创建new ArrayList()时初始化为一个Object[]空数组,而aClass和aClass1相等说明他们使用的是同一个空Object[],类型参数对ArrayList的初始化没有影响。
在泛型代码内部,无法获取任何有关泛型参数类型的信息.因此无法获取用来创建某个特定实例的实际的类型参数。
public class DemoA { public static void main(String[] args) { ArrayList<String> strings = new ArrayList<>(); System.out.println(Arrays.toString(strings.getClass().getTypeParameters()));//[E] } }Java泛型是用擦除来实现的,这意味着在使用泛型的时候,任何具体的类型信息都会被擦除。
使用泛型和不使用泛型的比较
public class DemoE<T extends DemoA> {//定义类的时候使用了泛型,并且给泛型加了一个边界 private T obj; public T get(){return obj;}//可以返回DemoA,也可以动态返回DemoA的导出类。 public void operator(T t){ t.getName(); }//可以使用t操作DemoA中的方法 } public class DemoF {//定义类的时候没有使用泛型 private DemoA obj; public DemoA get(){ return obj;}//不能动态的返回DemoA的导出类 }使用泛型时,虽然编译器无法知道泛型T的任何信息,但是编译器仍然可以确保在方法和类中使用的T的类型的一致性。
1,创建一个工厂对象
//这种方法只能创建有默认构造器的类的对象,无法对传入的泛型类进行编译器检查 public class ClassAsFactory<T> { T x; public ClassAsFactory(Class<T> kind){ try { x=kind.newInstance(); }catch (Exception e){ throw new RuntimeException(e); } } }2,显示工厂 会对传入的泛型进行编译期检查
public interface FactoryI<T> { T create();} public class Foo<T> { private T x; public T getX() { return x; } public void setX(T x) { this.x = x; } public <F extends FactoryI<T>> Foo(F factory){ x=factory.create(); } } public class IntegerFactory implements FactoryI<Integer> { @Override public Integer create() { return new Integer(0); } } public class FactoryConstraint { public static void main(String[] args) { Foo<Integer> foo = new Foo<>(new IntegerFactory()); Integer x = foo.getX(); System.out.println(x.hashCode()); } }因为有擦除,数组在运行时的类型只能为Object[],不能转型(不能创建确切类型的数组)。但是数组的元素可以在使用的时候进行转型。
public class GenericArray<T> { private T[] array; public GenericArray(int sz){ array=(T[])new Object[sz]; System.out.println(array.getClass().getSimpleName());//转型失败,已经为Object[] } public void put(int index,T item){ array[index]=item; } public T get(int index){ try { return array[index]; }finally { System.out.println(array[index].getClass().getSimpleName());//Integer, } } public T[] rep(){ try { return (T[])array; }finally { System.out.println(array.getClass().getSimpleName());//转型失败,已经为Object[] } } public static void main(String[] args) { GenericArray<Integer> gai = new GenericArray<>(10); gai.put(0,1); gai.get(0); gai.rep(); } }因为有擦除,数组在运行时的类型只能为Object[],最好在集合内部使用Object[],当使用数组元素时,再添加一个T的转换
public class GenericArray2<T> { private Object[] array; public GenericArray2(int sz){ array=new Object[sz]; } public void put(int index,T item){ array[index]=item; } public T get(int index){ return (T)array[index]; } public T[] rep(){ return (T[])array; } public static void main(String[] args) { GenericArray2<Integer> gia = new GenericArray2<>(10); for(int i=0;i<10;i++){ gia.put(i,i); } for (int i=0;i<10;i++){ System.out.print(gia.get(i)+" ");//数组元素转换成Integer类型成功 } System.out.println(); try { Integer[] rep = gia.rep(); System.out.println(rep.getClass().getSimpleName());//数组转换成Integer[]失败 }catch (Exception e){ System.out.println(e); } } }3,使用类型标记在泛型中创建一个特定类型的数组
public class GenericArrayTypeToken<T> { private T[] array; public GenericArrayTypeToken(Class<T> type,int sz){ array=(T[]) Array.newInstance(type,sz);//成功创建一个特定类型的数组 } public void put(int index,T item){ array[index]=item; } public T get(int index){return array[index];} public T[] rep(){return array; } public static void main(String[] args) { GenericArrayTypeToken<Integer> gatt = new GenericArrayTypeToken<>(Integer.class, 10); Integer[] rep = gatt.rep(); } }