编写高质量代码 101-105之反射

注重Class类的特殊性

Class类的三个特殊性

1.无构造函数。Java中的类一般都有构造函数,用于创建实例对象,但是Class类却没有构造函数,不能实例化,Class对象是在加载类时由Java虚拟机通过调用类加载器中的defineClass方法自动构造的。

2.可以描述基本类型。虽然8个基本类型在JVM中并不是一个对象,它们一般存在于栈内存中,但是Class类仍然可以描述它们,例如可以使用int.class标识int类型的类对象。

3.其对象都是单例模式。一个Class的实例对象描述一个类,并且只描述一个类,反过来也成立,一个类只有一个Class实例对象,如下代码返回的结果都为true

4.Class类是Java反射的入口

获得一个Class对象有三种途径:

1.类属性方式,如String.class

2.对象的getClass()方法,如new String().getClass()

3.forName()方法加载,如Class.forName(“java.lang.String”);

适时选择getDeclaredXXX和getXXX

Class类中提供了很多getDeclaredXXXgetXXX的方法:

getXXX的方式是获取所有公共的(public)级别的,包括从父类继承的方法。

getDeclaredXXX的方式是获取所有的,包括公共的(public),私有的(private),不受限与访问权限。

public static void main(String[] args) {  
    Class<User> cls = User.class;  
    // 获取类方法  
    cls.getDeclaredMethods();  
    cls.getMethods();  

    // 获取类构造函数  
    cls.getDeclaredConstructors();  
    cls.getConstructors();  

    // 获取类属性  
    cls.getDeclaredFields();  
    cls.getFields();  
}


反射访问属性或方法时将Accesible设置为true

在调用构造函数或方法的invoke前检查accessible已经是公认的写法,例如以下代码

public static void main(String[] args) throws Exception {  
    Class<User> cls = User.class;  
    //创建对象  
    User user = cls.newInstance();  
      
    //获取test方法  
    Method method = cls.getDeclaredMethod("test");  
      
    //检查Accessible属性  
    if(!method.isAccessible()){  
        method.setAccessible(true);  
    }  
    method.invoke(user);  
}  

可以尝试获取ClassgetMethod,也就是公开的方法,再输出isAccessible,可以看到输出的其实也是false,其实因为accessible属性的语义并不是我们理解的访问权限,而是指是否进行安全检查,而安全监察是非常消耗资源的,所以反射提供了Accessible可选项,让开发者逃避安全检查。

使用forName动态加载类文件

在使用JDBC时要动态加载数据库驱动就是使用forName的方式进行加载,同时亦可以从外部配置文件中读取类的全路径字符串进行加载,在使用forName,被加载的类就会被加载到内存当中,只会加载类,并不会执行任何代码,而我们的数据库驱动就是利用static代码块来执行操作的,因为当类被加载到内存中时,会执行static代码块

动态加载不适合数组

如果forName要加载一个类,那它必须是一个类-——8中基本类型就排除在外.它们不是一个具体的类。

其次它必须具有可追溯的类路径。否则就会报ClassNotFoundException

数组是一个特殊类,在声明时可以定义为String[],但编译后会为不同的数组类型生成不同的类.

//加载一个String数组 
Class.forName("[Ljava.lang.String;"); 
//加载一个long数组 
Class.forName("[J"); 

以上代码只是把一个String类型的数组类和long类型的数组类加载到了内存中(如果内存中没有该类的话),并不能通过newInstance()方法生成一个实例对象,因为它没有定义数组的长度,Java中数组是定长的,没有长度的数组是不允许存在的.

Array数组反射类来动态加载:
// 动态创建数组
String[] strs = (String[]) Array.newInstance(String.class, 8); 
// 创建一个多维数组 
int[][] ints = (int[][]) Array.newInstance(int.class,2,3);

Class.forName()Java程序运行时加载类的默认方法

Class.forName(String className):使用调用Class.forName()方法的类的类加载器加载加载类

Class.forName(String name, boolean initialize,ClassLoader loader):使用指定的类加载器加载类

Class.forName()加载类的过程
查看类是否已经加载:以ClassLoader和类全名作为keySystemDictionary 查询类是否存在。
2. 若没有加载则调用loader.loadClass(name)进行类型加载;

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小 明

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值