工作奇谈——JAVA高级特性之反射

一、从问题入手

      最近又要面试新人,所以翻了翻以前的代码,突然发现了一个有意思的问题。

        问:如下一个Student类,请实例Student并对其成员变量赋值。

public class Student {
	
	private String NAME;
	
	private int AGE;

	@Override
	public String toString() {
		return "Student [name=" + NAME + ", age=" + AGE + "]";
	}

}

        如果是个入行没多久或者基础不太好的初学者来看,肯定一脸蒙逼。两个私有成员变量set,get方法也没有,有参构造器也不提供,怎么搞?

        其实也不难,首先看到这种只提供私有成员变量第一个想到的肯定是反射。代码如下:

	public static void main(String[] args) throws Exception {
		Class clazz = Student.class;
		
		Object obj = clazz.newInstance();
		
		Field fieldName = clazz.getDeclaredField("name");
		Field fieldAge = clazz.getDeclaredField("age");
		
		fieldName.setAccessible(true);
		fieldAge.setAccessible(true);
		
		fieldName.set(obj, "二十岁以后");
		fieldAge.set(obj,21);
		
		System.out.println(obj);
	}

那么什么是反射呢?

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

1.类的加载概述

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。

(1)加载 

就是指将class文件读入内存,并为之创建一个Class对象。

任何类被使用时系统都会建立一个Class对象。

(2)连接

1>验证 : 是否有正确的内部结构,并和其他类协调一致

2>准备 : 负责为类的静态成员分配内存,并设置默认初始化值

3>解析: 把类中的符号引用转换为直接引用

(3)初始化  就是类的初始化步骤 

2.类的加载时机

(1)创建类的实例

访问类的静态变量,或者为静态变量赋值

(2)调用类的静态方法

使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

(3)初始化某个类的子类

直接使用java.exe命令来运行某个主类

3.类加载器的概述

负责将.class文件加载到内在中,并为之生成对应的Class对象。

4.类加载器的分类

Bootstrap ClassLoader 根类加载器

Extension ClassLoader 扩展类加载器

Sysetm ClassLoader     系统类加载器

5.类加载器的作用

(1)Bootstrap ClassLoader 根类加载器

也被称为引导类加载器,负责Java核心类的加载

比如System,String等。在JDK中JRE的lib目录下rt.jar文件中

(2)Extension ClassLoader 扩展类加载器

负责JRE的扩展目录中jar包的加载。

在JDK中JRE的lib目录下ext目录

(3)Sysetm ClassLoader 系统类加载器

负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径

/**

  * 反射: 就是发生在运行状态下一种机制. 对于任意一个类我们可以获取到该类的字节码文件 对象 , 获取到

  * 字节码文件对象以后,我们就可以剖析找个类

  * java为我们的类中的每一种成员提供了对应的类对其进行描述:

  *

  * 成员变量 Field

  * 构造方法 Constructor

  * 成员方法 Method

  *

  * 获取一个类对应的字节码文件对象:

  *

  * (1): 通过调用getClass方法获取该类对应的字节码文件对象

  * (2): 通过静态的class属性获取

  * (3): 我们可以通过Class类中的一个静态方法叫做: forName(String className):

  * public static Class<?> forName(String className)

  *

  */

代码示例如下:通过三种方式去得的到Person类对应的字节码文件对象,以下输出结果都为True

/**  * 获取构造方法的方法

//获取所有公共的构造方法  * public Constructor<?>[] getConstructors()

// 获取所有的构造方法,包括私有的  * public Constructor<?>[] getDeclaredConstructors()

//获取带指定参数的共有构造方法  * public Constructor<T> getConstructor(Class... parameterTypes)  * public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)  */

代码示例为获取Student类的所有构造方法:

Student类:

测试代码,获取Student类的三个构造方法

输出为

测试代码,获取Student类参数为两个的公有构造器,并实例化对象

结果为:

通过反射获得类中的成员变量并使用

一共四个方法可以获取

getField(String name):获取单个成员变量,指定的成员变量对应的名称

getFields():获取的是所有公共的成员变量,包含从父类中继承过来的

getDeclaredFields():获取的是本类中所有的成员变量,包含私有的

getDeclaredField(String name):获取本类中指定成员变量

其中Student成员变量都为private提供Set、Get方法,且不通过两个参数的构造器实例化对象

猜你喜欢

转载自my.oschina.net/u/3637243/blog/1625955