0
点赞
收藏
分享

微信扫一扫

编写高质量代码 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类中提供了很多getDeclaredXXX和getXXX的方法:

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);
}

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

使用forName动态加载类文件

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

动态加载不适合数组

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

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

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

编写高质量代码 101-105之反射_构造函数

//加载一个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和类全名作为key去SystemDictionary 查询类是否存在。
2. 若没有加载则调用loader.loadClass(name)进行类型加载;

编写高质量代码 101-105之反射_数组_02


举报

相关推荐

0 条评论