java 泛型详解
1.定义
泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?
顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),
然后在使用/调用时传入具体的类型(类型实参)。
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,
操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
1.1举个栗子
没有泛型时:
public static void main(String[] args) { ArrayList arrayList = new ArrayList(); arrayList.add("a"); arrayList.add("b"); arrayList.add(1); for (int i = 0; i < arrayList.size() ; i++) { System.out.println((String)arrayList.get(i)); } }
嗯嗯,相信你早就知道的真相,结果就是
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
这在没有泛型(jdk 1.5 才有泛型这个概念)时一致时一件非常苦逼的事情,这玩意编译时不报错。但是运行时报错。但我们的泛型来了会有什么改变呢?
从此麻麻再也不用担心我填错数据类型啦~~~因为在编译阶段IDE就会提示这错了。极大程度的防止了数据强转的异常发生
1.2只在编译期,运行期没有泛型的概念
List<String> stringArrayList = new ArrayList<String>(); List<Integer> integerArrayList = new ArrayList<>(); Class classStringArrayList = stringArrayList.getClass(); Class classIntegerArrayList = integerArrayList.getClass(); if(classStringArrayList.equals(classIntegerArrayList)){ System.out.println("泛型相同"); }
java中的泛型只在编译阶段有效,在编译过程中正确检验泛型结果后,会将泛型信息擦除。并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。
总结:在编译期检查类型,但运行去不会有泛型的概念存在。都是相同的基本类型
2.泛型应用
三种使用场景:泛型类、泛型接口、泛型方法
2.1泛型类
public class Dog<T> { public T name; public T get(T t){ return t; } public static void main(String[] args) { Dog<String> dog = new Dog<String>(); dog.get("1"); dog.get(1);//编译报错 } }
如果不传入泛型,那么泛型所定义的方法和属性即可位任意类型:
public T name; public T get(T t){ return t; } public static void main(String[] args) { Dog dog = new Dog(); dog.get("1"); dog.get(1);//编译通过 }
2.2泛型接口
和泛型类基本一样,泛型接口常被用于定义各种类的生产器中:
public interface Fy <T>{ public T show(); }
实现类不指定泛型参数
/** * 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中 * 如果这样 myFy implements Fy<T> 编译期会报错 */ class myFy<T> mplements Fy<T>{ @Override public T show() { return null; } }
实现类传入泛型参数
/** * 当实现类直接指定泛型参数时,那么改类实现的方法就变成了确切的数据类型 * 入下所示,变成了String */ class myFy implements Fy<String>{ @Override public String show() { return null; } }