java 泛型

在我看来,java的泛型一直就是语法糖,就是帮助我们在写代码的时候不会抛出java.lang.ClassCastException异常,看代码

 1 public class GenericTest {
 2 
 3     public static void main(String[] args) {
 4         List list = new ArrayList();
 5         list.add("a");
 6         list.add("b");
 7         list.add(100);
 8 
 9         for (int i = 0; i < list.size(); i++) {
10             //下面代码编译时肯定 没错,运行就会报错
11             String name = (String) list.get(i); 
12             System.out.println("name:" + name);
13         }
14     }
15 }

你创建List的时候没有指定它的类型,那就是默认的Object,添加任何类型都没问题,遍历的时候要打印转换时,全部转String肯定报错,因为之前添加有int,所以这时候如果我们一开始加泛型,那添加的时候就会告诉我们,List里存储的是同一种类型

泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。再看代码

public class GenericTest {

    public static void main(String[] args) {
      
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        //  提示编译错误
        //list.add(100);   

        for (int i = 0; i < list.size(); i++) {
            String name = list.get(i); // 这边就不需要转换,因为里面的类型都是String
            System.out.println("name:" + name);
        }
    }
}    

查看集合类的源码都是加泛型的,这样我们再执行一些操作的时候能确保集合里都是同一种“类型”

在泛型接口、泛型类和泛型方法的定义过程中,我们常见的如T、E、K、V等形式的参数常用于表示泛型形参,由于接收来自外部使用时候传入的类型实参。

知道这些后我们自己来实现一下泛型

 1 public class Test {
 2 
 3     public static void main(String[] args) {
 4 
 5         //创建一个实体类,调用带参构造函数函数传个值  
 6         Container<String> name = new Container<String>("abc");
 7         //上面已经定义了Container里只能放String类型
 8         System.out.println("name:" + name.getData());
 9     }
10 
11 }
12 
13 //自定义一个类,当作容器,里面可以放任何类型的实体
14 class Container<T> {
15 
16     private T data;
17 
18     public Container(T data) {
19         this.data = data;
20     }
21 
22     public T getData() {
23         return data;
24     }
25 
26 }

再看下面代码输出

1     Container<String> container1 = new Container<String>("a");
2         Container<Integer> container2 = new Container<Integer>(100);
3         System.out.println(container1.getClass());
4         System.out.println(container2.getClass());
5         Boolean bl = container1.getClass() == container2.getClass();
6         System.out.println(bl);

输出:

class Container
class Container
true

不管他们规定的是String类型还是Integer,编译过后的container1 和container2都是Container类型的,所以一开始说泛型只是语法糖~压根没有变

最后来看这段代码

class Test {

    public static void main(String[] args) {

        Container<String> name = new Container<String>("abc");
        Container<Integer> age = new Container<Integer>(100);
        Container<Number> number = new Container<Number>(200);
        Container<Float> ft = new Container<Float>(200F);


        getData(name);
        getData(age);
        getData(number);

        // 报错
        //getUpperNumberData(name);
        getUpperNumberData(age);
        getUpperNumberData(number);

        getUpperNumberData(age);
        //报错
        //getDownNumberData(ft);

    }

    public static void getData(Container<?> data) {
        System.out.println("data :" + data.getData());
    }

    public static void getUpperNumberData(Container<? extends Number> data) {
        System.out.println("data :" + data.getData());
    }

    public static void getDownNumberData(Container<? super Integer> data) {
        System.out.println("data :" + data.getData());
    }

}

类型通配符一般是使用 “?”代替具体的类型实参。此处是类型实参,而不是类型形参。有时候类型通配符还分上限和类型通配符下限

类型通配符上限通过形如Container<? extends Number>形式定义,相对应的,类型通配符下限为Container<? super Number>形式,其含义与类型通配符上限正好相反

原文地址:https://www.cnblogs.com/hzzjj/p/7275058.html