有很多面试的同学整天背那些官方并且浅薄的面试答案,而不知道其的原理,或则说根本就不知道具体的作用,所以呢,小子不才,就准备做一个课程系列,针对于各大面试题,来一个概括性的讲述,虽然不是特别具体,但是用来面试完全足够了。
今天我们首先来学习反射!
1,什么是反射?
官方回答:就是运行状态下,动态获取这个类的所有信息!
2,反射的作用?
1,反编译
2,通过反射机制访问java对象的属性,方法,构造方法
3,应用场景
1,JDBC的加载驱动(重点!)
2,SpringIOC (下一篇文章我会实际的讲一下,springIOC的源码)
3,框架
几乎所有框架都用到了反射。
4,反射的实现代码!
1,使用无参构造方法实现
1.创建实体类
package entity;
public class UserEntity {
private String uid;
private String uname;
public UserEntity(){
System.out.println("这是一个无参构造函数!");
}
public UserEntity(String name){
System.out.println("这是一个有参构造函数!参数:"+name);
}
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
}
2.使用反射创建实体类,并且对成员进行赋值
package test;
import entity.UserEntity;
/**
* 项目名称:WorkReflect
* 类描述:("反射")
* 创建人:莫参商
* 创建时间:2020-1-7 上午10:54:09
* 修改人:acer
* @version
*
*/
public class ReflectTest {
public static void main(String[] args) throws Exception {
//1,获取类的字节码文件,必须使用完整路径
Class<?> forName = Class.forName("entity.UserEntity");
//2, 创建对象,类似于new;newInstance是使用的无参构造;
Object obj = forName.newInstance();
//3,这个时候对象就被创建出来了,然后转化类型,让他显示出来
UserEntity user = (UserEntity) obj;
System.out.println(user);
user.setUname("莫参商");
System.out.println(user.getUname());
}
}
运行结果:
在这里补充一个知识,newInstance创建一个对象,会自动调用这个对象构造函数。
使用new创建对象的本质其实也是调用了 newInstance方法。
下面出一道理论面试题;
下面的对象创建方法中哪些会调用构造方法 ()?
A. new语句创建对象
B. 调用Java.io.ObjectInputStream的readObject方法
C. java反射机制使用java.lang.Class或java.lang.reflect.Constructor的newInstance()方法
D. 调用对象的clone()方法
解释一下;A:构造方法new
B:序列化对象
C:反射
D:克隆
在这里只有 A和C会调用构造方法
2,创建有参构造方法实现
- 创建实体类,同上
- 使用反射技术创建对象,并且赋值
package test;
import java.lang.reflect.Constructor;
import entity.UserEntity;
/**
* 项目名称:WorkReflect
* 类描述:("反射")
* 创建人:莫参商
* 创建时间:2020-1-7 上午10:54:09
* 修改人:acer
* @version
*
*/
public class ReflectTest {
public static void main(String[] args) throws Exception {
//1,获取类的字节码文件,必须使用完整路径
Class<?> forName = Class.forName("entity.UserEntity");
//使用有参构造
Constructor<?> constructor = forName.getConstructor(String.class);
//创建对象
Object newInstance = constructor.newInstance("莫参商");
UserEntity user = (UserEntity) newInstance;
System.out.println(user);
user.setUname("莫参商");
System.out.println(user.getUname());
}
}
结果
3,使用反射技术,调用类里面的方法
1.在类中添加方法,这次为了方便,我就在实体类中添加方法了。
//普通方法
public String test(String name){
System.out.println("这是一个普通有返回值,有参数的方法!参数是:"+name);
return name;
}
//私有方法
private String test01(String name){
System.out.println("这是一个普通有返回值,有参数的方法!参数是:"+name);
return name;
}
- 使用反射技术,调用方法
package test;
import java.lang.reflect.Constructor;
import entity.UserEntity;
/**
* 项目名称:WorkReflect
* 类描述:("反射")
* 创建人:莫参商
* 创建时间:2020-1-7 上午10:54:09
* 修改人:acer
* @version
*
*/
public class ReflectTest {
public static void main(String[] args) throws Exception {
//1,获取类的字节码文件,必须使用完整路径
Class<?> forName = Class.forName("entity.UserEntity");
Object obj = forName.newInstance();
UserEntity user = (UserEntity) obj;
user.test("莫参商");
}
}
结果:
我们在类中定义了两个方法,一个是普通的,一个是私有的。
我们知道私有方法不能被其他的类访问,用以往的方法肯定是不能访问的。
4.暴力反射,强行访问类中的私有方法
package test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import entity.UserEntity;
/**
* 项目名称:WorkReflect
* 类描述:("反射")
* 创建人:莫参商
* 创建时间:2020-1-7 上午10:54:09
* 修改人:acer
* @version
*
*/
public class ReflectTest {
public static void main(String[] args) throws Exception {
//1,获取类的字节码文件,必须使用完整路径
Class<?> forName = Class.forName("entity.UserEntity");
//2 实例化对象
Object obj = forName.newInstance();
//3 暴力获得私有方法
Method mt = forName.getDeclaredMethod("test01", String.class);
//4 暴力访问
mt.setAccessible(true);
//5 使用test01方法
Object invoke = mt.invoke(obj, "莫参商");
System.out.println(invoke);
}
}
结果: