class building {}
class Maker<T> {
Class<T> kind;
Maker(Class<T> kind){
this.kind = kind;
}
T make() throws IllegalAccessException, InstantiationException {
return kind.newInstance();
}
}
public class test {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
/*第一种方式*/
Class<?> fromFroName = Class.forName("building");
// Class<? extends building> fromFroName2 = Class.forName("building"); //解开注释,编译报错
// Class<building> fromFroName3 = Class.forName("building"); //解开注释,编译报错
/*第二种方式*/
Class<? extends building> fromGetClass = new building().getClass();
// Class<building> fromGetClass2 = new building().getClass(); //解开注释,编译报错
/*第三种方式*/
Class<building> fromClass = building.class;
/*第四种方式*/
ClassLoader loader = new building().getClass().getClassLoader();
Class<?> fromLoadClass = loader.loadClass("building");
/*第五种方式*/
Maker<building> maker = new Maker<building>(fromClass);
Class<building> fromMakerKind = maker.kind;
building b = maker.make();
}
}
- 通过
Class.forName(类名)
获得。但这种方式获得的Class对象的泛型类型只能是通配符的,从下面的两行注释代码可知,要想获得更具体的泛型类型时,都会编译报错。 - 通过
对象.getClass()
获得。这种方式获得的Class对象的泛型类型,虽然比上一种更加具体,可以是Class<? extends building>
了,但不能具体到Class<building>
了。 - 通过
类名.class
获得。这种方式获得的Class对象的泛型类型,最具体,是Class<building>
。 - 通过
ClassLoader对象.loadClass("类名")
获得。但这种方式获得的Class对象,和第一种Class.forName(类名)
一样,只能是通配符的泛型类型。 - 通过成员变量
Class<T> kind
获得,注意Maker是一个自定义的泛型类(第五种其实和反射无关了)。因为泛型指定了new Maker<building>
,所以构造器实际上变成了Maker(Class<building> kind)
,而对于传入的fromClass而言,是符合构造器参数类型。不用担心泛型机制的类型擦除会擦除掉Class<T> kind
里的尖括号里的信息,因为在泛型代码的出口处(比如maker.kind
)会自动强转为Class
为Class<building>
。
关于第五种方式,还可以进行拓展,但需要理解泛型的相关知识:
Class<building> fromMakerKind1 = new Maker<building>(fromClass).kind;
// Class<building> fromMakerKind2 = new Maker<? extends building>(fromGetClass).kind;
Class<building> fromMakerKind2 = new Maker(fromGetClass).kind;
// Class<building> fromMakerKind3 = new Maker<?>(fromFroName).kind;
Class<building> fromMakerKind3 = new Maker(fromFroName).kind;
注释掉的两行代码,取消注释后,你会收获一个编译错误:Type parameter '? extends building' cannot be instantiated directly
或者Type parameter '?' cannot be instantiated directly
,这其实很简单,在实例化的时候,泛型类型不允许为带通配符的,当然,除外构造器的其他方法是可以的。
你还会收获两个警告:
第一个警告告诉你:Maker对象以原生类型实例化了。
第二个警告告诉你:等号两边的赋值,是从原生类型转型到了Class<building>
。