关于泛型

来源:互联网 发布:js 触发事件 编辑:程序博客网 时间:2024/05/29 16:14

Java泛型的局限性:基本类型无法作为类型参数,不过Java SE5具备了自动打包和自动拆包的功能。

是否拥有泛型方法,与其所在的类是否是泛型没有关系。

对于一个static的方法而言,无法访问泛型类的类型参数,所以,如果static方法需要使用泛型能力,就必须使其成为泛型方法。

定义泛型方法,只需要将泛型参数列表置于返回值之前。

  public <T> void f(T x)    {    }

当使用泛型类时,必须在创建对象的时候指定类型参数的值,而使用泛型方法的时候,通常不必指明参数类型,因为编译器会为我们找出具体的类型,这称为”类型参数推断”。因此,我们可以向调用普通方法一样调用泛型方法。

类型推断只对赋值操作有效,其他时候并不起作用,如果你将一个泛型方法调用的结果作为参数,传递给另一个方法,这时编译器并不会执行类型推断,在这种情况下,编译器认为,调用泛型方法后,其返回值被赋给一个Object类型的变量。

"ABCDEFGHIJKLMN".split("")可以将A-N的字符串分开。

注意泛型的类型比较

Class c1 = new ArrayList<String>().getClass()Class c2 = new ArrayList<Integer>().getClass()c1 == c2 //true

Java泛型是使用擦除来实现的,这意味着当你在使用泛型时,任何具体的类型信息都会被擦除,唯一知道的就是你在使用一个对象,因此List<String>List<Integer>在运行上事实上是相同的类型,这两种形式都被擦除成他们的“原生”类型,即List。因此在泛型代码内部,无法获得任何有关泛型参数类型的信息。正式有了擦除这一特性,在运行时无法知道该参数变量可以调用哪些方法,因此就出现了extends关键字,来确定边界。例如:

class Manipulator<T>{private K obj;public Manipulator(T x) {obj = x;}//调用方法出错,Error: cannot find symbol : method f():public void manipulate(){  obj.f() }}

解决这一问题可以用extents关键字:

Class Manipulator<T extends HasF>private T obj;public Manipulator(T x) { obj = x;}public void manipulate() { obj.f()}

边界<T extends HasF>声明T必须具有类型HasF或从HasF导出的类型。像上例:T擦除到HasF,就好像在类的声明中用HasF替换了T一样。

即使擦除在方法或类内部移除了有关实际类型的信息,编译器仍旧可以确保在方法或类中使用的类型的内部一致性.在传递进来的值进行额外的编译器检查,并插入对传递出去的值得转型,因此:”边界就是发生动作的地方”

擦除丢失了在泛型代码中执行某些操作的能力,任何在运行时需要知道确切类型信息的操作都将无法工作.例如:

public class Erased<T>{    private final int SIZE = 100;    public static void f(Object arg){       if(arg instanceof T){} // Error       T var = new T();       // Error       T[] array = new T[SIZE];// error       T[] array = (T)new Object[SIZE] // Unchecked warning    }}

看一下这段代码

List<Fruit> flist = new ArrayList<Apple>();//Apple继承Fruit

在看这类问题的时候,真正的问题是应该谈论容器的类型,而不是容器持有的类型,flist的类型是List<Fruit>apple的类型是List<Apple>这在类型上就不等价,因此在编译时就会出错,与数组不同,泛型没有内建的协变类型,这是因为数组在语言中是完全定义的,因此可以内建了编译期和运行时的检查,但是在使用泛型时,编译器和运行时系统都不知道你想要的类型做些什么,以及采用什么样的规则.

对比上面的代码

//OKList<? extends Fruit> flist = new ArrayList<Apple>();//Compile Errorflist.add(new Apple());flist.add(new Fruit());flist.add(new Object());

List<? extends Fruit>
可以理解为”任何具有从Fruit继承的类型的列表”,但正是这样的特性导致了add不能添加任何对象,究其原因是应为add的参数类型也是? extends Fruit,这是一系列的Fruit或其子类,add并不知道是哪一类型的Fruit,这意味着他可以是任何事物,而编译器无法验证”任何事物”的类型安全性.

超类型通配符

写法是<? super MyClass>,
该句的意思是主要是MyClass或MyClass的子类型都是可以添加的,关于

<? extends MyClass> <? super MyClass> <MyClass>的区别可以看

区别与理解

0 0
原创粉丝点击