Java之泛型深入理解及总结


泛型深入理解及总结

泛型值存在于java的编译期,编译后生成字节码文件泛型是被擦除的;

Java泛型是伪泛型

擦除后—>强制类型转换

泛型类

public class A<T>{
    
}

泛型方法

泛型方法,是在调用方法的时候指明泛型的具体类型

静态方法

public static <T> void out(T t) {
	System.out.println(t);
}

普通方法

public <T> void out(T t) {
	System.out.println(t);
}

误区

返回值类型是泛型的方法并不一定是泛型方法。

泛型接口

public interface Generator<T> {
    public T next();
}

通配符(Wildcards)

为了解决类型被限制死了不能动态根据实例来确定的缺点,引入了“通配符泛型”,针对上面的例子,使用通配泛型格式为<? extends Collection>,“?”代表未知类型,这个类型是实现Collection接口。

  • 如果只指定了<?>,而没有extends,则默认是允许Object及其下的任何Java类了。也就是任意类。
  • 通配符泛型不单可以向下限制,如<? extends Collection>,还可以向上限制,如<? super Double>,表示类型只能接受Double及其上层父类类型,如Number、Object类型的实例。
  • 泛型类定义可以有多个泛型参数,中间用逗号隔开,还可以定义泛型接口,泛型方法。这些都与泛型类中泛型的使用规则类似。

上界与下界

为泛型添加上边界,即传入的类型实参必须是指定类型的子类型

Generic<? extends Number> obj

类型必须为Number的子类

Generic<? super Number> obj

类型必须为Number的父类

autoboxing & unboxing

装箱就是自动将基本数据类型转换为包装器类型;

拆箱就是 自动将包装器类型转换为基本数据类型。

理解泛型擦除

Java中的泛型基本上都是在编译器层次来实现的。在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会在编译器在编译的时候去掉。这个过程就称为类型擦除。

Java是伪泛型!! c#是真的。原因:为了向下兼容且不用修改jvm,使用伪泛型我们只需要在编译器的层次解决就可以。

例子:

public static void main(String[] args) {
		ArrayList<String> arrayList1=new ArrayList<String>();
		arrayList1.add("abc");
		ArrayList<Integer> arrayList2=new ArrayList<Integer>();
		arrayList2.add(123);
		System.out.println(arrayList1.getClass()==arrayList2.getClass()); //true
}

明泛型类型String和Integer都被擦除掉了,只剩下了原始类型(primitive type)。


例子2:

使用反射调用参数类型为泛型的方法,可以运行!

注意

1.泛型只适用于引用数据类型,基本数据类型(primitive data type)不被允许。解决办法 使用基本数据类型的包装类型。

2.泛型类中的静态方法和静态变量不可以使用泛型类所声明的泛型类型参数,因为静态类型在类加载的时候便要初始化,而泛型只有在对象被实例化的时候才起作用,素以无法确定类型。

参考

https://docs.oracle.com/javase/tutorial/extra/generics/fineprint.html

https://blog.csdn.net/s10461/article/details/53941091

https://findingsea.github.io/2015/10/09/java-generic-type-erasure/


文章作者: Bxan
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Bxan !
  目录