前言:
在学习反射机制之前,我熟悉的操作是:
1、程序的运行过程
编译器,将.java文件编译成.class(二进制)文件。
运行期,jvm加载并运行.class文件。
2、对象创建的过程
编写类–>创建对象–>调用成员。
所有的上面操作都是发生在编译期。
注:这里放一个Student类,文章根据这个类来进行演示
package day10;
//学生类
public class Student {
public String name;
protected String address;
private Integer id;
public Student(String address, Integer id, Integer score) {
System.out.println("三个参数的构造器");
this.address = address;
this.id = id;
this.score = score;
}
public Student() {
System.out.println("Student无参构造函数");
}
//使用成员生成构造函数
public Student(Integer id, Integer score) {
this.id = id;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getScore() {
return score;
}
public void setScore(Integer score) {
this.score = score;
}
private Integer score;
//在这个类中,还可以自定义方法
public void study(String name) {
System.out.println("学生在学习");
}
private void song() {
System.out.println("学生在唱歌");
}
}
在之前的情况下,我们进行对象的方法调用等都是运用以下方式:
package day10;
public class Test01 {
public static void main(String[] args) {
//创建对象
Student s=new Student();
//对象调用成员(属性和方法)
s.name="李四";
//s.study();
Student ss=new Student("江苏",10,20);
}
}
有了对比才体现出反射的优势,好的,进入正题。
一、什么是JAVA反射机制
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性。这种动态获取信息以及动态调用对象方法的功能称为JAVA语言的反射机制。
简单来说,在JAVA中,只要知道类的名字,就可以在运行时通过反射机制获取该类的所有信息。
二、反射机制的作用
1、在运行时判断任意一个对象所属的类。
2、在运行时构造任意一个类的对象。
3、在运行时判断任意一个类所具有的成员变量和方法。
4、在运行时调用任意一个对象的方法。
三、反射机制使用场景
1、反编译(.class变为.java)
2、开发框架(反射是框架设计的灵魂),比如Spring框架。为了保证框架的通用性,框架需要根据配置文件加载不同的类或者对象(运行期间,动态加载所需的对象)SSM SSH
四、反射机制的实现
JAVA中,使用一个类需要把该类加载到虚拟机中,并生成一个Class对象,这个对象保存了该类的所有信息。反射机制的实现,就是获取这个Class对象。
4.1、Class对象获取方式
1、使用已知对象.getClass()返回Class类对象
2、使用一个已知的类的类名.class返回Class对象。
3、使用Class类的静态方法forName(),返回Class对象。
package day10;
/*
* 演示Class对象获取方式
* 当虚拟机加载.class文件以后,就会生成一个Class对象
* Class对象封装一个类的所有信息
*/
public class Test02 {
public static void main(String[] args) throws ClassNotFoundException {
//1对象.getClass
Student s=new Student();
Class class1=s.getClass();
//2类名.class
Class class2=Student.class;
//3Class今天方法获取Class对象
Class class3=Class.forName("day10.Student");//括号写包名或类名,表示要用的
}
}
测试结果:
(讲真这里的Class如果加个<?>会不会更好,如果有小伙伴知道的话还请指点我下)
4.2、使用反射机制创建对象的两种方式
1、调用newInstance()方法。
2、使用Constructor对象。
package day10;
import java.lang.reflect.Constructor;
/*
* 演示Class对象获取方式
* 当虚拟机加载.class文件以后,就会生成一个Class对象
* Class对象封装一个类的所有信息
*
* 使用Class对象,创建Student对象
*/
public class Test03 {
public static void main(String[] args) throws Exception {
//3Class今天方法获取Class对象
Class class3 = Class.forName("day10.Student");//括号写包名或类名,表示要用的
//因为不知道加载对象的类型,所以统一使用Object接收
//创建Student对象的第一种方式
Object obj1=class3.newInstance();
System.out.println(obj1);
System.out.println("----------");
// //Constructor对象
// //创建Student对象的第二种方式,获取构造器
// Constructor constructor = class3.getConstructor();
// Object obj2=constructor.newInstance();
// System.out.println(obj2);
// //如果把之前的无参构造函数注释,则报错原因是Student类中没有无参构造
//Constructor对象
//创建Student对象的第二种方式,获取构造器
Constructor constructor = class3.getConstructor(String.class,Integer.class,Integer.class);
Object obj2=constructor.newInstance("江苏",10,20);
System.out.println(obj2);
}
}
测试结果:
五、常用方法
5.1、获取构造方法
1、//获取所有的“公有的(public)”构造方法
public Constructor[] getConstructors()
2、//获取所有的构造方法(包括私有、受保护、默认、共有)
public Constructor[] getDeclaredConstructors()
3、//获取单个的“公有的(public)”构造方法
public Constructor getConstructor(Class…parameterTypes)
4、//获取“某个构造方法”可以是私有的、或者受保护、默认、共有的
public Constructor[] getDeclaredConstructors(Class…parameterTypes)
package day10;
import java.lang.reflect.Constructor;
/*
* 演示Class对象获取方式
* 当虚拟机加载.class文件以后,就会生成一个Class对象
* Class对象封装一个类的所有信息
*
* 使用Class对象,创建Student对象
*/
public class Test04 {
public static void main(String[] args) throws Exception {
//3Class今天方法获取Class对象
Class class3 = Class.forName("day10.Student");//括号写包名或类名,表示要用的
//获取Class对象中的构造函数
Constructor[] constructors = class3.getConstructors();
for(Constructor c:constructors) {
System.out.println(c);
}
System.out.println("----------------");
Constructor[] arr = class3.getDeclaredConstructors();
for(Constructor cc:arr) {
System.out.println(cc);
}
System.out.println("-------");
//获取单个构造器
Constructor constructor=class3.getConstructor();
System.out.println(constructor);
System.out.println("-------");
//获取单个私有构造器
Constructor constructor1=class3.getDeclaredConstructor(Integer.class,Integer.class);
System.out.println(constructor);
}
}
测试结果:
5.2、获取成员变量并调用
1、//获取所有属性,包括所有的公有属性
Field getFields()
2、//获取所有字段,包括:私有、受保护、默认、公有
Field[] getDeclaredFields()
3、//获取某个“公有的属性”
public Field getField(String fieldName)
4、//获取某个字段(可以是私有的)
public Field getDeclaredFields(String fieldName)
package day10;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
/*
* 演示Class对象获取方式
* 当虚拟机加载.class文件以后,就会生成一个Class对象
* Class对象封装一个类的所有信息
*
* 使用Class对象,创建Student对象
*/
public class Test05 {
public static void main(String[] args) throws Exception {
//3Class今天方法获取Class对象
Class class3 = Class.forName("day10.Student");//括号写包名或类名,表示要用的
//成员变量(只能获取共有)
Field[] fields = class3.getFields();
for(Field f:fields) {
System.out.println(f);
}
System.out.println("--------------");
//公有私有均可获取
Field[] declaredFields = class3.getDeclaredFields();
for(Field ff:declaredFields) {
System.out.println(ff);
}
Field fff=class3.getDeclaredField("score");
System.out.println(fff);
//动态的给对象赋值
//第一步:得到对象
Object obj1 = class3.newInstance();
//指定给哪个属性赋值
Field field=class3.getField("name");
field.set(obj1, "lisi");
Student student=(Student)obj1;
System.out.println(student.name);
}
}
测试结果:
5.3、获取成员方法并调用
5.3.1、批量获取
1、//获取所有公有方法,包含父类的方法也包含Object类
public Method[] getMethods();
2、//获取所有的成员方法,包括私有的(不包括继承的)
public Method[] getDeclaredMethods();
5.3.2、单个获取
1、//获取单个公有方法
public Method getMethod(String name,Class<?>…parameterTypes)
2、//获取单个可以是任何类的方法
public Method getDeclaredMethod(String name,Class<?>…parameterTypes)
5.4、invoke方法
public Object invoke(Object obj,Object,args)
注:obj要调用的方法,args调用方法时所传递的参数。
package day10;
import java.lang.reflect.Method;
/*
* 演示Class对象获取方式
* 当虚拟机加载.class文件以后,就会生成一个Class对象
* Class对象封装一个类的所有信息
*
* 使用Class对象,创建Student对象
*/
public class Test06 {
public static void main(String[] args) throws Exception {
//3Class今天方法获取Class对象
Class class3 = Class.forName("day10.Student");//括号写包名或类名,表示要用的
//获取Class对象中的方法
Method[] methods = class3.getMethods();
for(Method m:methods) {
System.out.println(m);
}
//获取单个方法name(方法名), parameterTypes(方法的参数类型)
Method mm=class3.getMethod("study",String.class);//没有参数则后面就不用写
System.out.println(mm);
Object obj3=class3.newInstance();
//方法的调用
mm.invoke(obj3, "李思");
//mm.invoke(class3.getDeclaredConstructor().newInstance(),"李思" );
}
}
测试结果:
六、反射实现的案例
package reflect;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
public class Test02 {
public static void main(String[] args) {
try {
Class clzz=Class.forName(getValue("className"));
Method method=clzz.getMethod(getValue("method"));
method.invoke(clzz.getConstructor().newInstance());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static String getValue(String key) throws IOException {
//获取Properties 对象
Properties p=new Properties();
FileReader r=new FileReader("user.txt");
p.load(r);
r.close();
return p.getProperty(key);
}
}
七、附加案例
package day10;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties;
//使用反射机制动态加载配置文件实现动态创建对象
public class TestReflect {
public static void main(String[] args) throws Exception {
Class clazz=Class.forName(getvalue("className"));
//通过反射机制,创建User对象
Object obj1=clazz.newInstance();
//获取login方法
Method method=clazz.getMethod("login", String.class);
//调用方法
method.invoke(obj1, "小明");
}
//封装一个方法,加载配置文件,根据key读取配置文件
public static String getvalue(String key) throws FileNotFoundException{
//Properties可以将配置文件的数据以key-value的形式读取
Properties p=new Properties();
String value;
try {
//读取文件
FileReader reader=new FileReader("user.txt");
p.load(reader);
value=p.getProperty(key);
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return p.getProperty(key);
}
}
package day10;
//User类
public class User {
private String name;
private Integer id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
//自定义方法
public void login(String name) {
System.out.println(name+"正在登录");
}
}
className=day10.User
method=login;
(这两行是写在user.txt)
测试结果: