Thinking in java学习笔记—泛型(擦除)
来源:互联网 发布:数据库isnull 编辑:程序博客网 时间:2024/06/06 17:45
一、泛型擦除
在泛型代码内部,无法获得任何有关泛型参数类型的消息。
import java.util.Arrays;class AA<T>{}class CC<Q>{}class B{}public class Generic {public static void main(String[] args){AA<B> a = new AA<B>();CC<B> c = new CC<B>(); System.out.println(Arrays.asList(a.getClass().getTypeParameters())); System.out.println(Arrays.asList(c.getClass().getTypeParameters()));}}/*Output:[T][Q]*///:~上面这段代码,通过反射我们查看在泛型类对象的参数类型,最后输出的结果只是用作参数占位符的标识符,这不是有用的信息。
Java泛型是使用擦除来实现的,这意味着当我们使用泛型时,任何具体的类型信息都将被擦除,唯一知道的就是我们在使用一个对象。
List<String>和List<Integer>在运行时实际上都是相同的类型。
二、应对擦除
在基于擦除性的实现中,泛型类被当做第二类型处理,即不能再某些重要的上下文环境中使用的类型。泛型类型只有在静态类型检查期间才出现。
任何在运行时需要知道确切类型信息的操作都将无法工作:
public class Erased<T> {private final int SIZE = 100;public static void f(Object arg){if(arg instanceof T){} //ErrorT var = new T(); //ErrorT[] array = new T[SIZE]; //ErrorT[] array = (T)new Object[SIZE]; //Unchecked warning}}
可以通过引入类型标签来对擦除进行补偿。这意味着需要显式地传递类型的Class对象。
import java.lang.reflect.Array;import java.util.Arrays;public class ArrayMaker<T>{private Class<T> kind; //在泛型类内部,我们用一个class域来保存类型class对象。public ArrayMaker(Class<T> kind){this.kind = kind;}@SuppressWarnings("unchecked")public T[] creat(int size){return (T[])Array.newInstance(kind,size); //反射机制 ,当我们想要创建一个泛型数组时, //可以通过reflect里面的Array.newInstance(Class<?> component,int length) //来达成目的}public static void main(String[] args){ArrayMaker<String> make = new ArrayMaker<String>(String.class);String[] str = (String[])make.creat(10); System.out.println(Arrays.toString(str));}}接下来我们来看一下面对擦除,我们有哪些解决方法
1、创建类型示例
(1)传递一个工厂对象,并使用它来创建新的实例
最便利的工厂方法就是就是Class对象
class TestClass{public TestClass(){System.out.println("I am TestClass constructor");}}public class ClassAsFactory<T>{private T t;public ClassAsFactory(Class<T> cla){try{t = cla.newInstance();}catch(InstantiationException e){e.printStackTrace();}catch(IllegalAccessException e){ e.printStackTrace();}}public static void main(String[] args){ClassAsFactory newclass = new ClassAsFactory(TestClass.class);}}/*OutputI am TestClass constructor*///~
import java.util.Random;interface Factory<T>{ //这是工厂方法的工厂接口T creat();}class IntegerFactory implements Factory<Integer>{ //实现了Factory接口的类public Integer creat(){return new Integer(new Random(47).nextInt());}}class InnerFactory{public static class innerFactory implements Factory<InnerFactory>{ //内部类实现Factorypublic InnerFactory creat(){return new InnerFactory();}}}public class FactoryCreatTest<T> {private T t;public <F extends Factory<T>> FactoryCreatTest(F f){ //将参数类型限制为Factory<T>t = f.creat(); //通过工厂方法,我们实现了泛型实例的创建}public static void main(String args){new FactoryCreatTest(new IntegerFactory());new FactoryCreatTest(new InnerFactory.innerFactory());}}2、泛型数组
前面说过,可以利用反射机制里面的Array.newInstance(CLass<?> component,int lenght)来在泛型类内部创建泛型数组,但是这种方法要求传递类型标签,
即类型的Class对象。
数组将跟踪它们的实际类型,而这个类型是在数组被创建时确定的。
因此下面通过创建Object数组然后将其转型为某个类型会产生ClassCaseException
class AFGone<T>{}public class ArrayOfGeneric {static int SIZE = 100;static AFGone<Integer>[] afg;public static void main(String[] args){@SuppressWarnings("unchecked")//Compiles:produces ClassCastException: //!afg = (AFGone<Integer>[])new Object[SIZE];}}
public class GenericArray<T> { private T[] array; @SuppressWarnings("unchecked") //如果将SupressWarnings去掉,在这里就会产生警告。 public GenericArray(int sz) { array = (T[])new Object[sz]; } public void put(int index, T item) { array[index] = item; } public T get(int index) { return array[index]; } // Method that exposes the underlying representation: public T[] rep() { return array; }<span style="white-space:pre"></span> public static void main(String[] args) { GenericArray<Integer> gai = new GenericArray<Integer>(10); // This causes a ClassCastException: //因为运行时的实际类型是Object[] //! Integer[] ia = gai.rep(); // This is OK: Object[] oa = gai.rep(); }} ///:~
下面是几种解决方法:
(1)使用ArrayList
(2)通过创建有一个被擦除类型的数组,然后对其进行转型
class AFGone<T>{}public class ArrayOfGeneric {static int SIZE = 100;static AFGone<Integer>[] afg;public static void main(String[] args){afg = (AFGone<Integer>[])new AFGone[SIZE]; //创建泛型数组的方式是创建一个被擦除类型的新数组,然后对其进行转型。System.out.println(afg.getClass().getSimpleName());}}上面这段代码,类型AFGone<Integer>在运行时将被擦除到AFGone。
(3)最后,我们可以在内部将数组贮存为Object[],当我们要返回具体类型时,再将他进行转型。
public class ArrayOfGeneric<T> {static int SIZE = 100;static Object[] afg;@SuppressWarnings("unchecked")public T[] get(){return (T[])afg; //在使用时再将其进行转型}}
0 0
- Thinking in java学习笔记—泛型(擦除)
- Thinking In Java 学习笔记(序)
- thinking in java 学习笔记(1)
- Thinking in java 学习笔记(2)
- Thinking In Java学习笔记(1)
- Thinking In Java学习笔记(2)
- Thinking In Java 学习笔记(一)
- Thinking In Java 学习笔记(二)
- Thinking In Java 学习笔记(三)
- Thinking In Java 学习笔记(四)
- thinking in java 学习笔记(一)
- thinking in java学习笔记(二)
- Thinking in java 学习笔记(一)
- (Thinking in Java学习笔记)初始化
- (Thinking in Java学习笔记)字符串
- Thinking in java 学习笔记(三)
- 《Thinking in Java》学习笔记(1)
- Thinking In Java学习笔记
- jQuery选择器
- 欢迎使用CSDN-markdown编辑器
- CAS 单点登录实战 (3) Client端
- Vbs脚本经典教材
- 注*TP 3.2 使用 官方 WeChat 类. 获取用户信息(授权页面) ---纯手工打造!
- Thinking in java学习笔记—泛型(擦除)
- HDU 1232 畅通工程(并查集)
- 读 程序猿之华丽转身,菜鸟4步曲有感!
- Educational Codeforces Round 5(A,B,C,D)
- 浅谈 SOAP
- Python -- Control Flow Tools
- 2016.1.20 html5之html第一天
- Angular-seed 入门
- awesomeplayer_openmax 初始化分析