反射
本文参考自:https://blog.csdn.net/sinat_38259539/article/details/71799078#commentBox
一、反射概述
- 能够分析类能力的程序称为反射
- JAVA反射机制是在运行状态中:
- 对于任意一个类,都能够知道这个类的所有属性和方法;
* 对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
* 要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
-
反射就是把java类中的各种成分映射成一个个的Java对象
- 例如:一个类有:成员变量、方法、构造方法、包等等信息
- 利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。
- (其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述)
- 如图是类的正常加载过程:反射的原理在与class对象。
- 熟悉一下加载的时候:Class对象的由来是将class文件读入内存,并为之创建一个Class对象。
image
-
若要学习反射,必须了解Class类
二、Class类
- Class 类的实例表示正在运行的 Java 应用程序中的类和接口。
* 也就是jvm中有N多的实例每个类都有该Class对象。(包括基本数据类型)
- Class 没有公共构造方法。
- Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。
返回Class类型实例
-
Object类中的getClass()方法
Employee e; Class c1 = e.getClass(); //获取到Employee类 /* 此时还有一个常用的方法getName() */ System.out.println(c1.getName());
-
T.class(),此时T为任意的java类型
Class c1 = Random.class; Class c2 = int.class; Class c3 = Double[].class;
-
通过Class类中的static方法forName()
String className = "java.util.Random"; try{ Class c1 = Class.forName(className); System.out.println(c1.getName()); } catch(ClassNotFoundException e){ e.getMessage(); } /* 1. forName()方法抛出ClassNotFoundException 2. className必须是类名或者接口 */
通过反射获取构造方法并使用
自定义Employee类
package reflect;
import java.time.LocalDate;
public class Employee{
//data field
private String name;
private double salary;
private LocalDate hireDay;
//constructor
public Employee() {
System.out.println("c1.getConstructor().newInstance()被执行,调用了无参构造器");
}
public Employee(String name,double salary,int year,int month,int day){
this.name = name;
this.salary = salary;
this.hireDay = LocalDate.of(year,month,day);
System.out.println("getConstructor(Class,Class....).newInstance(para,para....)被执行");
}
//method
public String getName(){
return name;
}
public double getSalary(){
return salary;
}
public LocalDate gethireDay(){
return hireDay;
}
public void raiseSalary(double byPercent){
salary += salary * byPercent/100;
}
public String toString() {
return "name : " + name + "salary : " + salary + " hireDay : " + hireDay;
}
}
获取构造方法并使用
-
获取public构造器
- Constructor constructors = c1.getConstructors();
-
获取所有构造器
- Constructor<Employee>[] constructors = className.getDeclaredConstructors();
-
newIntance()方法的使用
- 调用无参构造器
- Constructor<Employee> con = c1.getConstructor();
- con.newInstance();
- 调用含参构造器
-
Constructor<Employee> paraCons = c1.getConstructor(String.class,double.class,int.class,int.class,int.class);
-
paraCons.newInstance("调用有参构造器",600,2018,7,18));
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
-
返回值为Constructor泛型,参数个数与实际构造器一致,但参数类型为Class
-
- 调用无参构造器
获取构造方法并使用例子程序
public class TestConstructors {
public static void main(String[] args) {
Class c1 = null;
//获取Class对象
try {
c1 = Class.forName("d_1reflect.Employee");
}catch(ClassNotFoundException e) {
e.printStackTrace();
}
//获取构造方法
System.out.println("========获取所有构造方法========");
Constructor<Employee>[] constructors = c1.getDeclaredConstructors();
//输出构造方法
for(Constructor cons : constructors) {
System.out.println(cons);
}
System.out.println();
//使用构造方法中的无参构造器
System.out.println("======使用构造方法中的无参构造器======");
try {
Constructor<Employee> nonParaCons = c1.getConstructor();
System.out.println(nonParaCons.newInstance());
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println();
//使用构造方法中的含参构造器
System.out.println("======使用构造方法中的含参构造器======");
try {
Constructor<Employee> paraCons = c1.getConstructor(String.class,double.class,int.class,int.class,int.class);
System.out.println(paraCons.newInstance("调用有参构造器",600,2018,7,18));
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
通过反射获取普通方法并使用
-
获取所有普通方法
- Method[] method = c1.getDeclaredMethods();
-
获取单个普通方法
-
Method m = c1.getDeclaredMethod("getName");
public Method getDeclaredMethod(String name,Class<?>... parameterTypes) throws NoSuchMethodException,SecurityException
- 返回值为Method类型,两个参数,第一个参数为String类,即方法名称,第二个参数为Class类型
-
-
使用普通方法
public Object invoke(Object obj,Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
- 返回值为Object,一共两个参数:
- 第一个参数Object是指调用该方法的对象,第二个参数是实参
通过反射获取普通方法并使用例子程序
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TestMethod {
public static void main(String[] args) {
//获取Class对象
Class c1 = null;
try {
c1 = Class.forName("d_1reflect.Employee");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//获取所有普通方法并输出
Method[] method = c1.getDeclaredMethods();
System.out.println("===========获取所有普通方法===========");
for(Method m : method) {
System.out.println(m);
}
///获取单个普通方法
System.out.println("===========获取单个普通方法===========");
Method m = null;
try {
m = c1.getDeclaredMethod("getName");
System.out.println(m);
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
//使用普通方法
System.out.println("===========使用普通方法===========");
Employee emp;
try {
emp = (Employee)c1.getDeclaredConstructor(String.class,double.class,int.class,int.class,int.class).newInstance("hahaha",200,2018,7,18);
System.out.println("调用Method类中invoke(Object,para)方法后 : " + m.invoke(emp, null));
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
}
}
/*
* 在JDK1.8中输出结果为:
* -----------------------------------------------------------------------
* ===========获取所有普通方法===========
public java.lang.String d_1reflect.Employee.toString()
public java.lang.String d_1reflect.Employee.getName()
public void d_1reflect.Employee.setName(java.lang.String)
public double d_1reflect.Employee.getSalary()
public java.time.LocalDate d_1reflect.Employee.gethireDay()
public void d_1reflect.Employee.raiseSalary(double)
public java.lang.String d_1reflect.Employee.testMethod(java.lang.String)
===========获取单个普通方法===========
public java.lang.String d_1reflect.Employee.getName()
===========使用普通方法===========
调用Method类中invoke(Object,para)方法后 : hahaha
-----------------------------------------------------------------------
* */
通过反射获取成员变量
-
获取所有成员变量信息
- Field[] fields = c1.getDeclaredFields();
-
获取public成员变量信息
- Field[] fields = c1.getFields();
-
获取单个成员变量信息
-
Field f = c1.getDeclaredField("name");
public Field getDeclaredField(String name) throws NoSuchFieldException,SecurityException
-
返回值为Field,有一个参数,为成员变量名字
-
-
使用成员变量
Employee emp = (Employee)c1.getConstructor().newInstance(); f.setAccessible(true);//暴力反射,解除私有设定 f.set(emp, "xixixi"); public void set(Object obj,Object value) throws IllegalArgumentException, IllegalAccessException
- 无返回值,共两个参数,第一个参数是:要设置的对象,第二个参数是要设置的值
- 此时注意private的成员变量不可直接访问,但是
- setAccessible()方法可解除私有设定
通过反射获取成员变量例子程序
public class TestField {
public static void main(String[] args) {
Class c1 = null;
//获取Class对象
try {
c1 = Class.forName("d_1reflect.Employee");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//获取成员变量信息
Field[] fields = c1.getDeclaredFields();
System.out.println("=========获取成员变量信息=========");
for(Field field : fields) {
System.out.println(field);
}
//获取单个成员变量信息
System.out.println("=========获取单个成员信息=========");
Field f = null;
try {
f = c1.getDeclaredField("name");
System.out.println(f);
} catch (NoSuchFieldException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//使用成员变量
Employee emp;
try {
emp = (Employee)c1.getConstructor().newInstance();
f.setAccessible(true);//暴力反射,解除私有设定
f.set(emp, "xixixi");
System.out.println("使用了set方法修改成员变量 name: " + emp.getName());
} catch (IllegalArgumentException | IllegalAccessException | InstantiationException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/*
* 在JDK1.8中输出结果为:
* ---------------------------------------------------------
* =========获取成员变量信息=========
private java.lang.String d_1reflect.Employee.name
private double d_1reflect.Employee.salary
private java.time.LocalDate d_1reflect.Employee.hireDay
=========获取单个成员信息=========
private java.lang.String d_1reflect.Employee.name
c1.getConstructor().newInstance()被执行,调用了无参构造器
使用了set方法修改成员变量 name: xixixi
---------------------------------------------------------
* */
反射与配置文件结合使用
-
配置文件pro.txt,注意是要放在工程下面
className = d_1reflect.Employee methodName = testMethod
-
主程序:从配置文件中获取ClassName生成Class对象,并调用方法
public static void main(String[] args) { Class c1 = null; //获取创建的Class对象 try { c1 = Class.forName(getValue("className")); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } Method m; try { m = c1.getDeclaredMethod(getValue("methodName")); m.invoke((Employee)c1.getConstructor().newInstance()); } catch (NoSuchMethodException | 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 str) { Properties pro = new Properties(); //获取配置文件对象 FileReader in; try { in = new FileReader("pro.txt"); pro.load(in); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return pro.getProperty(str); } /* * 在JDK1.8中输出结果为: * -------------------------------------------------- * c1.getConstructor().newInstance()被执行,调用了无参构造器 testMeod()方法被执行 -------------------------------------------------- * */
网友评论