Java反射 获得Class对象的五种方法

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();
    }
}
  1. 通过Class.forName(类名)获得。但这种方式获得的Class对象的泛型类型只能是通配符的,从下面的两行注释代码可知,要想获得更具体的泛型类型时,都会编译报错。
  2. 通过对象.getClass()获得。这种方式获得的Class对象的泛型类型,虽然比上一种更加具体,可以是Class<? extends building>了,但不能具体到Class<building>了。
  3. 通过类名.class获得。这种方式获得的Class对象的泛型类型,最具体,是Class<building>
  4. 通过ClassLoader对象.loadClass("类名")获得。但这种方式获得的Class对象,和第一种Class.forName(类名)一样,只能是通配符的泛型类型。
  5. 通过成员变量Class<T> kind获得,注意Maker是一个自定义的泛型类(第五种其实和反射无关了)。因为泛型指定了new Maker<building>,所以构造器实际上变成了Maker(Class<building> kind),而对于传入的fromClass而言,是符合构造器参数类型。不用担心泛型机制的类型擦除会擦除掉Class<T> kind里的尖括号里的信息,因为在泛型代码的出口处(比如maker.kind)会自动强转为ClassClass<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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值