泛型

​ 泛型是Java SE5.0中新增内容,泛型很好的解决了杂乱的使用Object类型然后在强制类型转换的操作,提高代码的可读性(比如如果没有泛型,使用集合类时内部只能维护一个Object类数组,在获取值时还需强制转换为指定的类型),指定泛型后,可以在编译时期对类型进行检查(编译出错的类无法运行),避免使用错误类型的对象

// Java7 及以后省略构造后的泛型声明
ArrayList<String> objects = new ArrayList<>();

定义泛型

​ 类型变量使用大写形式(小写也可用不推荐),且比较短,这是很常见的。在Java库中,使用变量E表示集合的元素类型,K和V分别表示表的关键字与值的类型。T(需要时还可以用临近的字母U和S)表示“任意类型”

public class Person<T,U> {
    private T name;
    private U age;

    public T getName() {
        return name;
    }

    public void setName(T name) {
        this.name = name;
    }

    public U getAge() {
        return age;
    }

    public void setAge(U age) {
        this.age = age;
    }
}
Person<String, Integer> per = new Person<>();
per.setName("taoqz");
per.setAge(10);
String name = per.getName();
System.out.println(name);

​ 一个类上可以声明多个多个泛型变量多个泛型变量使用逗号分隔,也可以限定泛型变量的类型,使用extends,多个限定使用&分隔,要注意类要在接口之前,并且限定类型中只能写一个类,因为只有java中只有单继承...,如果没有限定默认上限为Object

interface Demo1{
}

class Demo2 {
}

interface Demo3 {
}

// 编译出错,类的声明要在接口前
//class Demo<T1, T2 extends Integer, T3 extends Demo1 & Demo2> {
class Demo<T1, T2 extends Integer, T3 extends Demo2 & Demo1 & Demo3> {

}

方法

方法的泛型变量需要在方法的返回值之前定义使用<>包围,声明后的泛型变量可以在参数或返回值使用

//    没有返回值的写法
//    public static <T> void getMiddle(T... a) {
public static <T> T getMiddle(T... a) {
    return a[a.length / 2];
}
//        String middle = MyTest.<String>getMiddle(arr);
//        可省略
String middle = getMiddle(arr);
System.out.println(middle);

类型变量的限定

有时需要对类,方法中的类型变量加以约束

// 泛型类需要继承或实现指定的类和接口,多个类或者接口时使用 & 分隔
public static <T extends Person & Comparable> T max(T[] a) {
    //    public static <T extends Person > T max(T[] a) {
    // 使用该方法需要实现comparable接口
    Arrays.sort(a);
    return a[a.length-1];
}
@NoArgsConstructor
@AllArgsConstructor
public class Person<T,U> implements Comparable{
    // 不能定义泛型静态域
    // private static T name;
    private T name;
    private U age;

    public T getName() {
        return name;
    }

    public void setName(T name) {
        this.name = name;
    }

    public U getAge() {
        return age;
    }

    public void setAge(U age) {
        this.age = age;
    }

    @Override
    public int compareTo(Object o) {
        return (int)((Person)o).getAge();
    }

    @Override
    public String toString() {
        return "Person{" +
            "name=" + name +
            ", age=" + age +
            '}';
    }
}
@Test
public void demo2() {
    Person<String, Integer> p1 = new Person<>("zs", 20);
    Person<String, Integer> p2 = new Person<>("lisi", 18);
    // 不能创建参数化类型的数组
    // Person<String,Integer> pers = new Person<>[]; // 编译错误
    Person[] people = {p1, p2};
    Person max = max(people);
    System.out.println(max);
}

注意事项

泛型擦除

泛型只在编译时期有效,在运行时期会被擦除(替换为Object或者有多个类型时使用第一个类型)

// 方法冲突,泛型擦除后,和Object中的equals无异
public boolean equals(T value){
    return value.equals("123");
}
ArrayList<String> strings = new ArrayList<>();
strings.add("name");
//        strings.add(123); // 编译错误
// 使用反射后可以添加任意类型
Method add = ArrayList.class.getMethod("add",Object.class);
Object invoke = add.invoke(strings, new Person<String,Integer>("zs",10));
System.out.println(invoke);
System.out.println(strings);

不能抛出或捕获泛型类的实例

// 不能继承异常相关类
//public class Emp<T> extends Exception {
//public class Emp<T> extends Throwable {
public class Emp<T> {
    public <T extends Throwable> void fun(T t) {
        try {

        } catch (T e) { // 编译出错

        }
    }

    public <T extends Throwable> void fun2(T t) throws Throwable {
        try {

            // 可以编译通过,合法
        } catch (Throwable e) { // 编译出错
            throw t;
        }
    }
}

不同泛型参数的泛型类

Person<String, Integer> p1 = new Person<>("zs",19);
//        Person<Integer,String> p2 = p1; // 不同的泛型参数之前的类 没有关系
Person pp  = p1;
Person<Integer,String> p2 = pp; // 可以正常运行
System.out.println(p2);

通配符

有时候我们需要限定泛型的类型在一个范围内,通配符可以解决这个问题

通配符无法在类上声明,主要在方法的参数或返回值上使用

public static void main(String[] args) {
    //        Pair<Emp> empPair = new Pair<>();
    //        Emp emp = new Emp();
    //        empPair.t = emp;
    //        emp.name = "taoqz";
    //      这种情况是不能当参数的,因为Manager虽然是Emp的子类,但加泛型后便是两种没有任何关系的类型
    Pair<Manager> empPair = new Pair<>();
    fun(empPair);
}

public static void fun(Pair<Emp> empPair){
    System.out.println(empPair.t.name);
}
public static void main(String[] args) {
    //        Pair<Manager> empPair = new Pair<>();
    //        Manager manager = new Manager();
    // 也可写成多态的方式
    Pair<Emp> empPair = new Pair<>();
    Emp manager = new Manager();
    manager.name = "zz";
    empPair.t = manager;
    fun(empPair);
}

// 此时可以借助通配符来限定类型 表示传入的类型必须是继承自Emp或者是Emp类 也就是限定了类型的最大范围
public static void fun(Pair<? extends Emp> empPair){
    System.out.println(empPair.t.name);
}

// 表示必须是Emp类型 或者是Emp的父类,限定了类型的最小范围
public static void fun2(Pair<? super Emp> empPair){
    System.out.println(empPair.t);
}

泛型与反射

待做....

Copyright © TaoQZ 2019 all right reserved,powered by Gitbook作者联系方式:taoqingzhou@gmail.com 修订时间: 2024-11-19 17:25:43

results matching ""

    No results matching ""

    results matching ""

      No results matching ""