百度优化排名,苏州网站搜索优化,新建的网站多长时间在百度搜到,小程序模板免费制作概述#xff1a; Java泛型在使用过程有诸多的问题#xff0c;如不存在ListString.class, ListInteger不能赋值给ListNumber#xff08;不可协变#xff09;#xff0c;奇怪的ClassCastException等。 正确的使用Java泛型需要深入的了解Java的一些概…概述 Java泛型在使用过程有诸多的问题如不存在ListString.class, ListInteger不能赋值给ListNumber不可协变奇怪的ClassCastException等。 正确的使用Java泛型需要深入的了解Java的一些概念如协变桥接方法以及这篇笔记记录的类型擦除。Java泛型的处理几乎都在编译器中进行编译器生成的bytecode是不包涵泛型信息的泛型类型信息将在编译处理是被擦除这个过程即类型擦除。 编译器如何处理泛型 通常情况下一个编译器处理泛型有两种方式 1.Code specialization。在实例化一个泛型类或泛型方法时都产生一份新的目标代码字节码or二进制代码。例如针对一个泛型list可能需要 针对stringintegerfloat产生三份目标代码。 2.Code sharing。对每个泛型类只生成唯一的一份目标代码该泛型类的所有实例都映射到这份目标代码上在需要的时候执行类型检查和类型转换。 C中的模板template是典型的Code specialization实现。C编译器会为每一个泛型类实例生成一份执行代码。执行代码中integer list和string list是两种不同的类型。这样会导致代码膨胀code bloat不过有经验的C程序员可以有技巧的避免代码膨胀。 Code specialization另外一个弊端是在引用类型系统中浪费空间因为引用类型集合中元素本质上都是一个指针。没必要为每个类型都产生一份执行代码。而这也是Java编译器中采用Code sharing方式处理泛型的主要原因。 Java编译器通过Code sharing方式为每个泛型类型创建唯一的字节码表示并且将该泛型类型的实例都映射到这个唯一的字节码表示上。将多种泛型类形实例映射到唯一的字节码表示是通过类型擦除type erasue实现的。 类型擦除指的是通过类型参数合并将泛型类型实例关联到同一份字节码上。编译器只为泛型类型生成一份字节码并将其实例关联到这份字节码上。类型擦除的关键在于从泛型类型中清除类型参数的相关信息并且再必要的时候添加类型检查和类型转换的方法。 类型擦除可以简单的理解为将泛型java代码转换为普通java代码只不过编译器更直接点将泛型java代码直接转换成普通java字节码。 类型擦除的主要过程如下 1.将所有的泛型参数用其最左边界最顶级的父类型类型替换。 2.移除所有的类型参数。 擦除使我们在泛型代码内部无法获得任何有关参数类型的信息。很蛋疼... 例如 C中我们可以这样写 templatetypename T T imax(T a, T b) {T copy; return copy;
}
class A{};但是在Java中我们是不能够生成copy的因为们压根就不知道T的类型信息。 那为什么Java要使用擦除呢 首先能够节省空间避免代码膨胀主要原因是为了“迁移兼容性”即允许泛型代码与非泛型代码共存因为泛型是Java后期才添加的为了兼容以前的代码所以采取了折中的办法。 那么擦除所带来的问题我们如何解决呢 1 通过引入类型标签来对擦除进行补偿 class Building{Overridepublic String toString() {return Building ...;}
}
class House extends Building{Overridepublic String toString() {return House ...;}
}class TestItemT{ClassT type; //通过添加类型标签来获得我要持有的类型的信息public TestItem(ClassT type) {this.type type;}public T getInstance() throws InstantiationException, IllegalAccessException {T copy type.newInstance(); //这样我就可以利用类型信息进行必要的处理了return copy;}
}public class Test {public static void main(String[] args) throws InstantiationException, IllegalAccessException {TestItemBuilding item new TestItem(Building.class);System.out.println(item.getInstance());System.out.println(------------------------);TestItemHouse item2 new TestItem(House.class);System.out.println(item2.getInstance());//出错因为我们是利用newInstance来创建对象的就必须保证我们的对象要有默认的构造方法才行但是Integer没有
// System.out.println(------------------------);
// TestItemInteger item3 new TestItem(Integer.class);
// System.out.println(item3.getInstance());}
} 上面的Integer的问题我们可以通过传入一个工厂来实现 interface FactoryT{T create();
}
class IntegerFactory implements FactoryInteger {Overridepublic Integer create() {return new Integer(0);}
}class TestItemT{ClassT type; //通过添加类型标签来获得我要持有的类型的信息T copy;FactoryT factory;public F extends FactoryTTestItem(F factory) {this.factory factory;}public TestItem(ClassT type) {this.type type;}public T getInstance() throws InstantiationException, IllegalAccessException {//copy type.newInstance(); //这样我就可以利用类型信息进行必要的处理了copy factory.create();return copy;}
}public class Test {public static void main(String[] args) throws InstantiationException, IllegalAccessException {
// TestItemBuilding item new TestItem(Building.class);
// System.out.println(item.getInstance());
// System.out.println(------------------------);
// TestItemHouse item2 new TestItem(House.class);
// System.out.println(item2.getInstance());//现在把工厂放进去就可以了。System.out.println(------------------------);TestItemInteger item3 new TestItem(new IntegerFactory()); System.out.println(item3.getInstance());}
}2 同样我们可以通过使用设置擦相互边界来补偿擦除 就像我们在前一篇的比较的时候我们将擦除边界设定成了Comparable保证了我们的类新信息是可比较的。 http://www.cnblogs.com/E-star/p/3438226.html 注意 1.虚拟机中没有泛型只有普通类和普通方法2.所有泛型类的类型参数在编译时都会被擦除3.创建泛型对象时请指明类型让编译器尽早的做参数检查Effective Java第23条请不要在新代码中使用原生态类型4.不要忽略编译器的警告信息那意味着潜在的ClassCastException等着你。 转载于:https://www.cnblogs.com/E-star/p/3438290.html