Java开发笔记(七十八)面向对象的后门——反射

作为一门面向对象的编程语言,Java认为一切皆是对象,每个对象都能归属于某个类,甚至每个类均可提取出一种特殊的类型,即Class类型。早在前面介绍多态的时候,就提到每个类都存在独一无二的基因,通过比较实例的类基因与具体类名的类基因,即可分辨某个实例是否属于目标类。例如,若想获取公鸡类的类型,则可通过“类名.class”得到该类的Class对象,详细的获取代码如下所示:

		// 第一种方式:通过“类名.class”获取
		Class clsFromClass = Cock.class;
		System.out.println("clsFromClass name = " + clsFromClass.getName());

 

相对应的,若想获取公鸡实例的类型,则可通过“实例名.getClass()”得到该实例的Class对象,详细的获取代码如下所示:

		// 第二种方式:通过“实例名.getClass()”获取
		Cock cock = new Cock();
		Class clsFromInstance = cock.getClass();
		System.out.println("clsFromInstance name = " + clsFromInstance.getName());

 

既然Class也是一种数据类型,那么Class对象也能调用该类型的实例方法,比如上面两段例子代码都调用了Class的getName方法,该方法返回的是Class对象蕴含着的目标类类名,而且是包含完整包路径的类名。假如分别运行前面的两段示例代码,就会依次观察到如下的日志信息,从中可见getName方法确实返回了完整的类名:
clsFromClass name = com.addition.reflect.Cock
clsFromInstance name = com.addition.reflect.Cock
除了通过“类名.class”或者“实例名.getClass()”获得Class对象,甚至还能反向操作,只要提供一个保存完整类名的字符串,即可由该字符串生成目标类的Class对象,具体的获取代码格式形如“Class.forName("完整类名")”。通过类名字符串获取Class对象的代码示例如下,注意需要捕捉forName方法可能扔出的“类型未找到异常”ClassNotFoundException:

		// 第三种方式:通过该类的完整路径字符串获取
		try {
			Class clsFromString = Class.forName("com.addition.reflect.Cock");
			System.out.println("clsFromString name = " + clsFromString.getName());
		} catch (ClassNotFoundException e) { // 捕捉到类型未找到异常
			e.printStackTrace();
		}

 

上述这种通过字符串反向获得Class对象的操作被称为“反射”,仿佛光线照到镜子表面反射回来那样,看起来像是一种逆向操作。只是反射远非逆向操作这么简单,它还洞悉面向对象不为人知的各种奥秘,因此经常出现于一些高级的应用场合。
构成反射技术的基石主要有类型Class、字段Field、方法Method这三个好汉,其中尤以Class最为重要,它既是从其它类中提取出来的基因类型,又是一种可以直接访问的普通类型。之所以说Class普通,是因为它拥有若干可以被开发者访问的方法,使用体验与其它类型相比并没有什么差异。下面是Class常见的方法说明:
equals:判断当前类型是否与目标类型相等。
getDeclaredFields:获得当前类型已声明的所有字段(字段即属性)。
getDeclaredField:根据指定的字段名称获得对应的字段(字段即属性)。
getDeclaredMethods:获得当前类型已声明的所有方法。
getDeclaredMethod:根据指定的方法名称以及参数类型列表获得对应的方法。
getName:获取当前类型包括包名在内的完整类名。
getPackage:获取当前类型所在的包名。
getSimpleName:获取当前类型的类名(不包括包名)。
getSuperclass:获取当前类型的父类类型。
以上的说明文字中,字段指的是Field类型,方法指的是Method类型,有关它们的详细用法将在后面的文章中加以阐述。



更多Java技术文章参见《Java开发笔记(序)章节目录

posted @ 2019-03-30 09:11  pinlantu  阅读(314)  评论(0编辑  收藏  举报