一文带你深入理解【Java基础】· 泛型

news2024/9/23 9:24:11

写在前面


        Hello大家好, 我是【麟-小白】,一位软件工程专业的学生,喜好计算机知识。希望大家能够一起学习进步呀!本人是一名在读大学生,专业水平有限,如发现错误不足之处,请多多指正!谢谢大家!!!

        如果小哥哥小姐姐们对我的文章感兴趣,请不要吝啬你们的小手,多多点赞加关注呀!❤❤❤ 爱你们!!!


目录

写在前面

1. 为什么要有泛型

1.1 为什么要有泛型

1.2 泛型的概念

1.3 在集合中使用泛型

1.4 泛型代码演示

 2. 自定义泛型结构

2.1 泛型结构

2.2 泛型类、泛型接口

2.3 泛型方法

2.4 自定义泛型类型代码演示

2.5 泛型在继承上的体现

3. 通配符的使用

3.1 使用通配符

3.2 注意点

3.3 有限制的通配符

3.4 通配符代码演示

4. 泛型应用举例

4.1 泛型嵌套

4.2 实际案例

结语


【往期回顾】

一文带你深入理解【Java基础】· Java集合(上)

一文带你深入理解【Java基础】· 注解

一文带你深入理解【Java基础】· 枚举类

一文带你深入理解【Java基础】· 常用类(上)

一文带你深入理解【Java基础】· 多线程(上)

一文带你深入理解【Java基础】· 异常处理


1. 为什么要有泛型


1.1 为什么要有泛型

  • 泛型:标签
  • 举例:
    • 中药店,每个抽屉外面贴着标签
    • 超市购物架上很多瓶子,每个瓶子装的是什么,有标签
  • 泛型的设计背景
  • 集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的对象,所以JDK1.5之前只能把元素类型设计为ObjectJDK1.5之后使用泛型来解决。因为这个时候除了元素的类型不确定,其他的部分是确定的,例如关于这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计成一个参数,这个类型参数叫做泛型。Collection<E>List<E>ArrayList<E> 这个<E>就是类型参数,即泛型。

1.2 泛型的概念

  • 所谓泛型,就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时(例如,继承或实现这个接口,用这个类型声明变量、创建对象时)确定(即传入实际的类型参数,也称为类型实参)。
  • JDK1.5以后,Java引入了“参数化类型(Parameterized type)”的概念,允许我们在创建集合时再指定集合元素的类型,正如:List<String>,这表明该List只能保存字符串类型的对象。
  • JDK1.5改写了集合框架中的全部接口和类,为这些接口、类增加了泛型支持,从而可以在声明集合变量、创建集合对象时传入类型实参。

那么为什么要有泛型呢,直接Object不是也可以存储数据吗?

1. 解决元素存储的安全性问题,好比商品、药品标签,不会弄错。
2. 解决获取数据元素时,需要类型强制转换的问题,好比不用每回拿商品、药品都要辨别。

 

Java 泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮。

1.3 在集合中使用泛型

ArrayList<Integer> list = new ArrayList<>();//类型推断
list.add(78);
list.add(88);
list.add(77);
list.add(66);
//遍历方式一:
//for(Integer i : list) {
    //不需要强转
    //System.out.println(i);
//}
//遍历方式二:
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()) {
    System.out.println(iterator.next());
}
Map<String,Integer> map = new HashMap<String,Integer>();
map.put("Tom1",34);
map.put("Tom2",44);
map.put("Tom3",33);
map.put("Tom4",32);
//添加失败
//map.put(33, "Tom");
Set<Entry<String,Integer>> entrySet = map.entrySet();
Iterator<Entry<String,Integer>> iterator = entrySet.iterator();
while(iterator.hasNext()) {
    Entry<String,Integer> entry = iterator.next();
    System.out.println(entry.getKey() + "--->" + entry.getValue());
}

1.4 泛型代码演示

import org.junit.Test;

import java.util.*;

/**
 * 泛型的使用
 * 1.jdk 5.0新增的特性
 *
 * 2.在集合中使用泛型:
 *  总结:
 *  ① 集合接口或集合类在jdk5.0时都修改为带泛型的结构。
 *  ② 在实例化集合类时,可以指明具体的泛型类型
 *  ③ 指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性等)使用到类的泛型的位置,都指定为实例化的泛型类型。
 *    比如:add(E e)  --->实例化以后:add(Integer e)
 *  ④ 注意点:泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换
 *  ⑤ 如果实例化时,没有指明泛型的类型。默认类型为java.lang.Object类型。
 *
 * 3.如何自定义泛型结构:泛型类、泛型接口;泛型方法。见 GenericTest1.java
 */
public class GenericTest {

    //在集合中使用泛型之前的情况:
    @Test
    public void test1() {
        ArrayList list = new ArrayList();
        //需求:存放学生的成绩
        list.add(78);
        list.add(76);
        list.add(89);
        list.add(88);
        //问题一:类型不安全
        //list.add("Tom");

        for (Object score : list) {
            //问题二:强转时,可能出现ClassCastException
            int stuScore = (Integer) score;
            System.out.println(stuScore);
        }
    }

    //在集合中使用泛型的情况:以ArrayList为例
    @Test
    public void test2() {
        ArrayList<Integer> list = new ArrayList<Integer>();

        list.add(78);
        list.add(87);
        list.add(99);
        list.add(65);
        //编译时,就会进行类型检查,保证数据的安全
//        list.add("Tom");

        //方式一:
//        for(Integer score : list) {
//            //避免了强转操作
//            int stuScore = score;
//            System.out.println(stuScore);
//        }
        //方式二:
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()) {
            int stuScore = iterator.next();
            System.out.println(stuScore);
        }
    }

    //在集合中使用泛型的情况:以HashMap为例
    @Test
    public void test3() {
        //Map<String,Integer> map = new HashMap<String,Integer>();
        //jdk7新特性:类型推断
        Map<String, Integer> map = new HashMap<>();

        map.put("Tom", 87);
        map.put("Jerry", 87);
        map.put("Jack", 67);

//      map.put(123,"ABC");
        //泛型的嵌套
        Set<Map.Entry<String, Integer>> entry = map.entrySet();
        Iterator<Map.Entry<String, Integer>> iterator = entry.iterator();

        while (iterator.hasNext()) {
            Map.Entry<String, Integer> e = iterator.next();
            String key = e.getKey();
            Integer value = e.getValue();
            System.out.println(key + "----" + value);
        }
    }
}

 2. 自定义泛型结构


2.1 泛型结构

1. 泛型的声明
  • interface List<T> class GenTest<K,V>
  • 其中,T,K,V不代表值,而是表示类型。这里使用任意字母都可以。
  • 常用T表示,是Type的缩写。
2. 泛型的实例化:
  • 一定要在类名后面指定类型参数的值(类型)。如:
    • List<String> strList = new ArrayList<String>();
    • Iterator<Customer> iterator = customers.iterator();
  • T只能是类,不能用基本数据类型填充。但可以使用包装类填充
  • 把一个集合中的内容限制为一个特定的数据类型,这就是generics背后的核心思想
  •  体会:使用泛型的主要优点是能够在编译时而不是在运行时检测错误。

2.2 泛型类、泛型接口

1. 泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如:<E1,E2,E3>
2. 泛型类的构造器如下: public GenericClass(){}
    而下面是错误的: public GenericClass<E>(){}
3. 实例化后,操作原来泛型位置的结构必须与指定的泛型类型一致。
4. 泛型不同的引用不能相互赋值。尽管在编译时ArrayList<String> ArrayList<Integer> 是两种类型,但是,在运行时只有一个ArrayList 被加载到 JVM 中。
5. 泛型如果不指定,将被擦除,泛型对应的类型均按照 Object 处理,但不等价于Object 经验: 泛型要使用一路都用。要不用,一路都不要用。
6. 如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。
7. jdk1.7 ,泛型的简化操作: ArrayList<Fruit> flist = new ArrayList<>();
8. 泛型的指定中不能使用基本数据类型,可以使用包装类替换。
9. 在类 / 接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态属性的类型、非静态方法的参数类型、非静态方法的返回值类型。但在 静态方法中不能使用类的泛型。
10. 异常类不能是泛型的
11. 不能使用 new E[] 。但是可以: E[] elements = (E[])new Object[capacity];
参考:ArrayList 源码中声明: Object[] elementData ,而非泛型参数类型数组。
12. 父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型:
  • 子类不保留父类的泛型:按需实现
    • 没有类型 擦除
    • 具体类型
  • 子类保留父类的泛型:泛型子类
    • 全部保留
    • 部分保留
结论:子类必须是“富二代”,子类除了指定或保留父类的泛型,还可以增加自己的泛型
class Father<T1, T2> {
}
// 子类不保留父类的泛型
// 1)没有类型 擦除
class Son<A, B> extends Father {//等价于class Son extends Father<Object,Object> {
}
// 2)具体类型
class Son2<A, B> extends Father<Integer, String> {
}
// 子类保留父类的泛型
// 1)全部保留
class Son3<T1, T2, A, B> extends Father<T1, T2> {
}
// 2)部分保留
class Son4<T2, A, B> extends Father<Integer, T2> {
}    
class Person<T> {
    // 使用T类型定义变量
    private T info;
    // 使用T类型定义一般方法
    public T getInfo() {
    return info;
}
public void setInfo(T info) {
    this.info = info;
}
// 使用T类型定义构造器
public Person() {
}
public Person(T info) {
    this.info = info;
}
// static的方法中不能声明泛型
//public static void show(T t) {
//
//}
// 不能在try-catch中使用泛型定义
//public void test() {
//try {
//
//} catch (MyException<T> ex) {
//
//}
//}
//}


2.3 泛型方法

  • 方法,也可以被泛型化,不管此时定义在其中的类是不是泛型类。在泛型方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型。
泛型方法的格式:
  • [访问权限] <泛型> 返回类型 方法名([泛型标识 参数名称]) 抛出的异常
  • 泛型方法声明泛型时也可以指定上限(12.5中讲)
public class DAO {
    public <E> E get(int id, E e) {
        E result = null;
        return result;
    }
}
public static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
    for (T o : a) {
        c.add(o);
    }
}
public static void main(String[] args) {
    Object[] ao = new Object[100];
    Collection<Object> co = new ArrayList<Object>();
    fromArrayToCollection(ao, co);
    String[] sa = new String[20];
    Collection<String> cs = new ArrayList<>();
    fromArrayToCollection(sa, cs);
    Collection<Double> cd = new ArrayList<>();
    // 下面代码中T是Double类,但sa是String类型,编译错误。
    // fromArrayToCollection(sa, cd);
    // 下面代码中T是Object类型,sa是String类型,可以赋值成功。
    fromArrayToCollection(sa, co);
}
class Creature{}
class Person extends Creature{}
class Man extends Person{}
class PersonTest {
    public static <T extends Person> void test(T t) {
        System.out.println(t);
    }
    public static void main(String[] args) {
        test(new Person());
        test(new Man());
        //The method test(T) in the type PersonTest is not 
        //applicable for the arguments (Creature)
        test(new Creature());
    }
}

2.4 自定义泛型类型代码演示

import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

/** 如何自定义泛型结构:泛型类、泛型接口;泛型方法。
 *
 * 1. 关于自定义泛型类、泛型接口:
 */
public class GenericTest1 {

    @Test
    public void test1() {
        //如果定义了泛型类,实例化没有指明类的泛型,则认为此泛型类型为Object类型
        //要求:如果大家定义了类是带泛型的,建议在实例化时要指明类的泛型。
        Order order = new Order();
        order.setOrderT(123);
        order.setOrderT("ABC");

        //建议:实例化时指明类的泛型
        Order<String> order1 = new Order<String>("orderAA", 1001, "order:AA");
        order1.setOrderT("AA:hello");
    }

    @Test
    public void test2() {
        SubOrder sub1 = new SubOrder();
        //由于子类在继承带泛型的父类时,指明了泛型类型。则实例化子类对象时,不再需要指明泛型。
        sub1.setOrderT(1122);

        SubOrder1<String> sub2 = new SubOrder1<>();
        sub2.setOrderT("order2...");
    }

    @Test
    public void test3() {
        ArrayList<String> list1 = null;
        ArrayList<Integer> list2 = new ArrayList<Integer>();
        //泛型不同的引用不能相互赋值。
        //list1 = list2;

        Person p1 = null;
        Person p2 = null;
        p1 = p2;
    }

    //测试泛型方法
    @Test
    public void test4() {
        Order<String> order = new Order<>();
        Integer[] arr = new Integer[]{1, 2, 3, 4};
        //泛型方法在调用时,指明泛型参数的类型。
        List<Integer> list = order.copyFromArrayToList(arr);

        System.out.println(list);
    }
}
import java.util.ArrayList;
import java.util.List;

/**
 * 自定义泛型类
 */
public class Order<T> {
    String orderName;
    int orderId;
    //类的内部结构就可以使用类的泛型

    T orderT;

    public Order() {
        //编译不通过
        //T[] arr = new T[10];
        //编译通过
        T[] arr = (T[]) new Object[10];
    }

    public Order(String orderName, int orderId, T orderT) {
        this.orderName = orderName;
        this.orderId = orderId;
        this.orderT = orderT;
    }

    //如下的三个方法都不是泛型方法
    public T getOrderT() {
        return orderT;
    }

    public void setOrderT(T orderT) {
        this.orderT = orderT;
    }

    @Override
    public String toString() {
        return "Order{" +
                "orderName='" + orderName + '\'' +
                ", orderId=" + orderId +
                ", orderT=" + orderT +
                '}';
    }
//    静态方法中不能使用类的泛型。
//    public static void show(T orderT) {
//        System.out.println(orderT);
//    }

    public void show() {
        //编译不通过
//        try{
//
//        } catch(T t) {
//
//        }
    }

    //泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系。
    //换句话说,泛型方法所属的类是不是泛型类都没有关系。
    //泛型方法,可以声明为静态的。原因:泛型参数是在调用方法时确定的。并非在实例化类时确定。
    public static <E> List<E> copyFromArrayToList(E[] arr) {
        ArrayList<E> list = new ArrayList<>();
        for (E e : arr) {
            list.add(e);
        }
        return list;
    }
}
import java.util.ArrayList;
import java.util.List;

public class SubOrder extends Order<Integer> {//SubOrder:不是泛型类
    public static <E> List<E> copyFromArrayToList(E[] arr) {
        ArrayList<E> list = new ArrayList<>();
        for (E e : arr) {
            list.add(e);
        }
        return list;
    }
}
public class SubOrder1<T> extends Order<T> {//SubOrder1<T>:仍然是泛型类
}

2.5 泛型在继承上的体现

  • 如果BA的一个子类型(子类或者子接口),而G是具有泛型声明的类或接口,G<B>并不是G<A>的子类型!
  • 比如:StringObject的子类,但是List<String >并不是List<Object>的子类。
public void testGenericAndSubClass() {
    Person[] persons = null;
    Man[] mans = null;
    // 而 Person[] 是 Man[] 的父类.
    persons = mans;
    Person p = mans[0];
    // 在泛型的集合上
    List<Person> personList = null;
    List<Man> manList = null;
    // personList = manList;(报错)
}

3. 通配符的使用


3.1 使用通配符

1.使用类型通配符:?

  • 比如:List<?> Map<?,?>
  • List<?>List<String>List<Object>等各种泛型List的父类。

2.读取List<?>的对象list中的元素时,永远是安全的,因为不管list的真实类型是什么,它包含的都是Object

3.写入list中的元素时,不行。因为我们不知道c的元素类型,我们不能向其中添加对象。

  • 唯一的例外是null,它是所有类型的成员。

将任意元素加入到其中不是类型安全的

  • Collection<?> c = new ArrayList<String>();
  • c.add(new Object()); // 编译时错误
  • 因为我们不知道c的元素类型,我们不能向其中添加对象。add方法有类型参数E作为集合的元素类型。我们传给add的任何参数都必须是一个未知类型的子类。因为我们不知道那是什么类型,所以我们无法传任何东西进去。

唯一的例外的是null,它是所有类型的成员。

另一方面,我们可以调用get()方法并使用其返回值。返回值是一个未知的类型,但是我们知道,它总是一个Object

public static void main(String[] args) {
    List<?> list = null;
    list = new ArrayList<String>();
    list = new ArrayList<Double>();
    // list.add(3);//编译不通过
    list.add(null);
    List<String> l1 = new ArrayList<String>();
    List<Integer> l2 = new ArrayList<Integer>();
    l1.add("尚硅谷");
    l2.add(15);
    read(l1);
    read(l2);
}
public static void read(List<?> list) {
    for (Object o : list) {
        System.out.println(o);
    }
}

3.2 注意点

注意点 1 :编译错误:不能用在泛型方法声明上,返回值类型前面 <> 不能使用 ?
public static <?> void test(ArrayList<?> list) {
}
注意点 2 :编译错误:不能用在泛型类的声明上
class GenericTypeClass<?> {
}
注意点 3 :编译错误:不能用在创建对象上,右边属于创建集合对象
ArrayList<?> list2 = new ArrayList<?>();

3.3 有限制的通配符

<?>
  • 允许所有泛型的引用调用
通配符指定上限
  • 上限extends:使用时指定的类型必须是继承某个类,或者实现某个接口,即<=
通配符指定下限
  • 下限super:使用时指定的类型不能小于操作的类,即>=
举例:
<? extends Number> ( 无穷小 , Number]
  • 只允许泛型为NumberNumber子类的引用调用
<? super Number> [Number , 无穷大 )
  • 只允许泛型为NumberNumber父类的引用调用
<? extends Comparable>
  • 只允许泛型为实现Comparable接口的实现类的引用调用
public static void printCollection3(Collection<? extends Person> coll) {
    //Iterator只能用Iterator<?>或Iterator<? extends Person>.why?
    Iterator<?> iterator = coll.iterator();
    while (iterator.hasNext()) {
        System.out.println(iterator.next());
    }
}
public static void printCollection4(Collection<? super Person> coll) {
    //Iterator只能用Iterator<?>或Iterator<? super Person>.why?
    Iterator<?> iterator = coll.iterator();
    while (iterator.hasNext()) {
        System.out.println(iterator.next());
    }
}

3.4 通配符代码演示

import org.junit.Test;

import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 1. 泛型在继承方面的体现
 * 2. 通配符的使用
 */
public class GenericTest {
    /*
    1. 泛型在继承方面的体现
       虽然类A是类B的父类,但是G<A> 和G<B>二者不具备子父类关系,二者是并列关系。
       补充:类A是类B的父类,A<G> 是 B<G> 的父类
     */
    @Test
    public void test1() {
        Object obj = null;
        String str = null;
        obj = str;

        Object[] arr1 = null;
        String[] arr2 = null;
        arr1 = arr2;
//      编译不通过
//      Date date = new Date();
//      str = date;
        List<Object> list1 = null;
        List<String> list2 = new ArrayList<String>();
        //此时的list1和list2的类型不具有子父类关系
        //编译不通过
        //list1 = list2;
        /*
        反证法:
        假设list1 = list2;
           list1.add(123);导致混入非String的数据。出错。
         */
        show(list1);
        show1(list2);
    }

    public void show1(List<String> list) {

    }

    public void show(List<Object> list) {

    }

    @Test
    public void test2() {
        AbstractList<String> list1 = null;
        List<String> list2 = null;
        ArrayList<String> list3 = null;

        list1 = list3;
        list2 = list3;

        List<String> list4 = new ArrayList<>();
    }

    /*
    2. 通配符的使用
       通配符:?
       类A是类B的父类,G<A>和G<B>是没有关系的,二者共同的父类是:G<?>
     */

    @Test
    public void test3() {
        List<Object> list1 = null;
        List<String> list2 = null;

        List<?> list = null;

        list = list1;
        list = list2;
        //编译通过
        //print(list1);
        //print(list2);

        List<String> list3 = new ArrayList<>();
        list3.add("AA");
        list3.add("BB");
        list3.add("CC");
        list = list3;
        //添加(写入):对于List<?>就不能向其内部添加数据。
        //除了添加null之外。
        //list.add("DD");
        //list.add('?');

        list.add(null);

        //获取(读取):允许读取数据,读取的数据类型为Object。
        Object o = list.get(0);
        System.out.println(o);
    }

    public void print(List<?> list) {
        Iterator<?> iterator = list.iterator();
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println(obj);
        }
    }

    /*
    3.有限制条件的通配符的使用。
        ? extends A:
                G<? extends A> 可以作为G<A>和G<B>的父类,其中B是A的子类

        ? super A:
                G<? super A> 可以作为G<A>和G<B>的父类,其中B是A的父类
     */
    @Test
    public void test4() {
        List<? extends Person> list1 = null;
        List<? super Person> list2 = null;

        List<Student> list3 = new ArrayList<Student>();
        List<Person> list4 = new ArrayList<Person>();
        List<Object> list5 = new ArrayList<Object>();

        list1 = list3;
        list1 = list4;
        //list1 = list5;

        //list2 = list3;
        list2 = list4;
        list2 = list5;

        //读取数据:
        list1 = list3;
        Person p = list1.get(0);
        //编译不通过
        //Student s = list1.get(0);

        list2 = list4;
        Object obj = list2.get(0);
        //编译不通过
        //Person obj = list2.get(0);

        //写入数据:
        //编译不通过
        //list1.add(new Student());

        //编译通过
        list2.add(new Person());
        list2.add(new Student());
    }
}

4. 泛型应用举例


4.1 泛型嵌套

public static void main(String[] args) {
    HashMap<String, ArrayList<Citizen>> map = new HashMap<String, ArrayList<Citizen>>();
    ArrayList<Citizen> list = new ArrayList<Citizen>();
    list.add(new Citizen("刘恺威"));
    list.add(new Citizen("杨幂"));
    list.add(new Citizen("小糯米"));
    map.put("刘恺威", list);
    Set<Entry<String, ArrayList<Citizen>>> entrySet = map.entrySet();
    Iterator<Entry<String, ArrayList<Citizen>>> iterator = entrySet.iterator();
    while (iterator.hasNext()) {
        Entry<String, ArrayList<Citizen>> entry = iterator.next();
        String key = entry.getKey();
        ArrayList<Citizen> value = entry.getValue();
        System.out.println("户主:" + key);
        System.out.println("家庭成员:" + value);
    }
}

4.2 实际案例

用户在设计类的时候往往会使用类的关联关系,例如,一个人中可以定义一个信息的属性,但是一个人可能有各种各样的信息(如联系方式、基本信息等),所以此信息属性的类型就可以通过泛型进行声明,然后只要设计相应的信息类即可。


结语


本人会持续更新文章的哦!希望大家一键三连,你们的鼓励就是作者不断更新的动力

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/59605.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Arduino开发实例-DIY风速测量及显示

DIY风速测量及显示 1、应用介绍 本次实例将使用一款具有 NPN 脉冲输出的数字风速计传感器。 NPN脉冲输出风速计效果好,性价比高。另外它仅在 5V 电源下工作。 在本次实例中,将此风速计传感器与 Arduino 板和 0.96 英寸 OLED 显示屏连接。 OLED显示屏将以米/秒为单位显示风速…

[附源码]计算机毕业设计基于SpringBoot的酒店预订系统设计与实现

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

​AAAI 2023 | 基于历史对比学习的时序知识图谱推理

©PaperWeekly 原创 作者 | 徐奕单位 | 上海交通大学Acemap研究方向 | 数据挖掘论文标题&#xff1a;Temporal Knowledge Graph Reasoning with Historical Contrastive Learning论文链接&#xff1a;https://arxiv.org/abs/2211.10904代码链接&#xff1a;https://github…

Elasticsearch好用查询插件分享

以前我常用的ES查询工具是Head&#xff0c;作为插件形式在浏览器中运行&#xff0c;挺方便的&#xff0c;后来发现head不太好用&#xff0c;比如在数据浏览的时候&#xff0c;不小心就点击了两个索引&#xff0c;背景色设置的还不够明显&#xff0c;比较容易看错数据的。于是想…

git中rebase和merge的区别

介绍 Merge和Rebase是合并两个分支的操作。都是checkout到某个分支上&#xff0c;然后将别的分支合并&#xff08;变基&#xff09;到本分支上。 注意&#xff1a;本分支&#xff08;head指向的分支&#xff0c;或者经过checkout后的分支&#xff09;会变化&#xff0c;而别的…

在Linux上部署Servlet程序

目录 一、部署环境 1、安装JDK 2、安装Tomcat 3、安装MySQL 二、部署程序 1、构造云服务器上的数据库 2、打包程序 3、部署程序 一、部署环境 为了部署我们自己的web程序&#xff0c;首先需要在Linux上安装程序所依赖的环境~ 1、安装JDK 直接使用yum安装openjdk&…

小程序云开发笔记二

小程序云开发笔记二一、读取数据库播放列表将数据显示到界面二、上拉加载三、上拉刷新四、云函数路由优化tcb-router案例&#xff1a;点击两个按钮调用同一个云函数将music中写成koa风格的云函数五、事件冒泡组件参数properties和data一、读取数据库播放列表将数据显示到界面 …

java同步方法

观看此文 首先 你要了解 java的同步锁 如果不了解 可以观看我的文章 java 同步锁synchronized 解决线程共享数据重复操作问题 那么 从下图 我们可以看到 逻辑代码上被绑了一个同步锁 但这个其实大可以写成一个函数 看起来会美观便捷很多 同步方法的格式如下 修饰符 synchro…

git switch 命令详解

1. 前言 2. switch 创建分支 3. switch 切换分支 1. 前言 checkout 命令具有 分支的管理 和 文件的恢复 两个核心功能&#xff0c;功能较多、不够准确。在 git 2.23 版本中新增了 switch 和 restore命令&#xff0c;用于替代 checkout 命令&#xff0c;进而分化 checkout 命…

(附源码)springboot大学生竞赛管理平台 毕业设计

题 目 springboot大学生竞赛管理平台 目 录 摘要 1 1 绪论 1 1.1选题意义 1 1.2国内外研究现状 1 1.3系统开发技术的特色 4 1.4论文结构与章节安排 4 2 大学生竞赛管理平台分析 5 2.1 可行性分析 5 2.2 系统流程分析 6 2.2.1数据增加流程 7 2.3.2数据修改流程 7 2.3.3数据删…

java面向对象----封装 构造器

目录 封装和隐藏 为什么需要封装&#xff1f; 信息的封装和隐藏 四种访问权限修饰符 构造器(构造方法) 构造器的特征 语法格式&#xff1a; 构造器重载 构造器重载举例 属性赋值过程 JavaBean UML类图 关键字—this this是什么&#xff1f; 使用this&#xff0c;…

计算机网络笔记2 物理层

计算机网络系列笔记目录&#x1f447; 计算机网络笔记6 应用层计算机网络笔记5 运输层计算机网络笔记4 网络层计算机网络笔记3 数据链路层计算机网络笔记2 物理层计算机网络笔记1 概述 本文目录文章前言 &#x1f497;一、物理层概述&#x1f60a;二、物理层的传输媒体&#x…

Spring源码该如何阅读?十年架构师带来的Spring源码解析千万不要错过!

写在前面 最近学习了一句话&#xff0c;感觉自己的世界瞬间明朗&#xff0c;不再那么紧张焦虑恐慌&#xff0c;同样推荐给大家&#xff0c;希望我们都终有所得。 “如果一个人不是发自内心地想要做一件事情&#xff0c;那么&#xff0c;他是无法改变自己的人生的。” 同样这句…

4. 死信队列

二八佳人体似酥&#xff0c;腰间仗剑斩愚夫。虽然不见人头落&#xff0c;暗里教君骨髓枯。 死信 概念 先从概念解释上搞清楚这个定义&#xff0c;死信&#xff0c;顾名思义就是无法被消费的消息&#xff0c;字面意思可以这样理 解&#xff0c;一般来说&#xff0c;producer 将…

「Redis」05 Jedis操作Redis

笔记整理自【尚硅谷】Redis 6 入门到精通 超详细 教程 Redis——Jedis操作Redis 即通过 Java 操作 Redis。 1. Jedis基本操作 Ⅰ. 测试连接 连接Redis注意事项 禁用Linux的防火墙&#xff1a;Linux&#xff08;CentOS7&#xff09;里执行命令&#xff1a;systemctl stop/disab…

我的周刊(第068期)

我的信息周刊&#xff0c;记录这周我看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。&#x1f3af; 项目osquery[1]像操作 SQL 一样操作你的电脑&#xff0c…

康复训练的未来:VR和元宇宙如何帮助患者康复

欢迎来到Hubbleverse &#x1f30d; 关注我们 关注宇宙新鲜事 &#x1f4cc; 预计阅读时长&#xff1a;7分钟 本文仅代表作者个人观点&#xff0c;不代表平台意见&#xff0c;不构成投资建议。 一位有平衡问题的患者站在波速球上&#xff0c;同时在两只潇洒的企鹅之间击打着…

第十六章 品质保证:发布覆盖率测试报告

代码覆盖率才是评价一个项目品质的标准。在挑选一个项目的时候&#xff0c;有经验的使用者都会根据代码覆盖率来确定代码的可靠性。 虽然自动化测试工具可以自动验证代码的正确性&#xff0c;但是如果只有部分代码经过了测试&#xff0c;或者只是简单地跑通了代码&#xff0c;…

BlockingQueue二

接着上篇BlockingQueue没讲完的 LinkedTransferQueue LinkedTransferQueue是一个由链表结构组成的无界阻塞队列&#xff0c;相对于其它阻塞队列&#xff0c;LinkedBlockingQueue可以算是LinkedBlockingQueue与SynhronoousQueue结合&#xff0c;LinkedtransferQueue是一种无界…

Unity学习笔记--详细介绍CacheServer、部署方法、以及在Unity中的位置

目录前言CacheServer是什么&#xff1f;解决了什么问题&#xff1f;其他知识点在哪里找到Cache Server&#xff1f;怎么部署CacheServer&#xff1f;Unity什么时候需要生成内部文件&#xff1f;CacheServer缓存的是什么&#xff1f;随着越来越多的资源被导入和存储&#xff0c;…