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

2018-03-01 11:07:08来源:oschina作者:二十岁以后人点击

分享
一、从问题入手

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


问:如下一个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.类加载器的分类


BootstrapClassLoader根类加载器


ExtensionClassLoader扩展类加载器


SysetmClassLoader 系统类加载器


5.类加载器的作用


(1)BootstrapClassLoader根类加载器


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


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


(2)ExtensionClassLoader扩展类加载器


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


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


(3)SysetmClassLoader系统类加载器


负责在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



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


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


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


//获取带指定参数的共有构造方法 *publicConstructorgetConstructor(Class...parameterTypes) *publicConstructorgetDeclaredConstructor(Class<?>...parameterTypes) */


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


Student类:



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



输出为



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



结果为:



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


一共四个方法可以获取


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


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


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


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



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


最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台