反射是非常重要的知识
JAVA让我们运行时识别对象和类的信息,有俩个方式:一个是传统的RTTI,它假定我们在编译时已经知道了所有的类型信息。另一种是反射机制,它允许我们运行时发现和使用类的信息。
–编程思想
反射的描述
JAVA反射机制是运行状态中,对于任意一个类,能够知道这个类的所有属性和方法,对于任意一个对象,能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用方法的功能称为java语言的反射机制。
要想达到这样的效果,必须先要获取到该类的字节码文件对象,而达到这样效果使用的是Class类中的方法,所以先要获取到每个字节码文对应的Class类型对象。
每个类都会产生一个对应的Class对象,且每个类只有一个,也就是保存在.class文件。所有类都是在对其第一次使用时,动态加载到JVM
JAVA中反射的实现过程:
JAVA语言在编译之后会产生成一个.class文件,反射就是通过字节码文件找到某一个类,类中的方法以及属性等。
下图2中,就是找到Class文件并创建Class对象(摘自网上)
下面是jdk到解释,说明反射就是把类中的各个成分反映为一个个对象
Class类的类表示正在运行的Java应用程序中的类和接口。 枚举是一种类,一个注释是一种界面。 每个数组也属于一个反映为类对象的类,该对象由具有相同元素类型和维数的所有数组共享。 原始Java类型( boolean , byte , char , short , int , long , float和double ),和关键字void也表示为类对象。
类没有公共构造函数。 相反, 类对象由Java虚拟机自动构建,因为加载了类,并且通过调用类加载器中的defineClass方法。
我们不需要自己创建Class类,JVM自动帮我们创建好了。
反射的作用
JAVA反射的作用是什么:
反射机制指的是程序在运行时能够获取自身的信息。在JAVA中,只要给定类的名字,那么就可以通过反射机制来获取类的所有信息。
获取Class对象的三种方式
//1.java中每个类型都有class 属性**
Class cls1 = String.class;
Class cls2 = int.class;
Class cls3 = Employee.class; (Employee是一个类)
//2.通过class类的静态方法 Class.forName(ClassName)
Class cls1 = Class.forName("Employee");
Class cls2 = Class.forName("java.lang.String");
//3.通过类的getClass()方法(Object的方法,因为所以方法都继承Object)
Employee employee = new Employee();
Class cls = employee.getClass();
反射的实现主要借助以下四个类:class:类的对象,Constructor:类的构造方法,field:类中的属性对象,Method类中的方法对象。
通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问:
通过反射获取构造方法并使用
package fanshe;
public class Student {
//默认的构造方法
Student(String str){
System.out.println("默认的构造方法 s= "+str);
}
//无参数构造方法
public Student() {
System.out.println("调用了公有,无参数构造方法执行了。。。");
}
//有一个参数的构造方法
public Student(char name) {
System.out.println("姓名:"+name);
}
//有多个参数的构造方法
public Student(String name,int age) {
System.out.println("姓名:"+name+"年龄:"+age);
}
//受保护的构造方法
protected Student(boolean n) {
System.out.println("受保护的构造方法 n = "+n);
}
//私有构造方法
private Student(int age) {
System.out.println("私有的构造方法 年龄:"+age);
}
}
package fanshe;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Constructors {
//加载class对象
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//加载class对象
Class cls = Class.forName("fanshe.Student");
//Class cls = new Student().getClass();
//Class cls = Student.class;
//获取所有公有的构造方法
System.out.println("**********************所有公有构造方法*********************************");
Constructor[] conArray = cls.getConstructors();
for(Constructor c:conArray) {
System.out.println(c);
}
System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
conArray = cls.getDeclaredConstructors();
for(Constructor c : conArray){
System.out.println(c);
}
System.out.println("*****************获取公有、无参的构造方法*******************************");
Constructor con = cls.getConstructor(null);
System.out.println("con = " + con);
//创建此对象的一个新实例对象
Object obj = con.newInstance();
System.out.println("******************获取私有构造方法,并调用*******************************");
con = cls.getDeclaredConstructor(char.class);
System.out.println(con);
con.setAccessible(true);
//用新实例对象的方法设置参数
obj = con.newInstance('男');
}
}
输出
获取成员变量并调用
package fanshe;
public class Employee {
public Employee() {
}
//***********字段******************
public String name;
protected int age;
char sex;
private String phoneNum;
@Override
public String toString() {
return "Employee [name=" + name + ", age=" + age + ", sex=" + sex + ", phoneNum=" + phoneNum + "]";
}
}
package fanshe;
import java.lang.reflect.Field;
public class Fields {
public static void main(String[] args) throws Exception {
//1.获取class对象
Class cls = Class.forName("fanshe.Employee");
//2.获取字段
System.out.println("***********获取所有公有字段************************");
Field []fieldArray = cls.getFields();
for(Field f: fieldArray) {
System.out.println(f);
}
System.out.println("***********获取所有的字段(包括私有,受保护,默认的)*******");
fieldArray = cls.getDeclaredFields();
for(Field f: fieldArray) {
System.out.println(f);
}
System.out.println("************获取所有的字段(包括私有、受保护、默认的)********************");
fieldArray = cls.getDeclaredFields();
for(Field f : fieldArray){
System.out.println(f);
}
System.out.println("*************获取公有字段**并调用***********************************");
Field f = cls.getField("name");
System.out.println(f);
//获取一个对象
Object obj = cls.getConstructor().newInstance();//产生Student对象--> Employee emp = new Employee();
//为字段设置值
f.set(obj, "刘德华");
//验证
Employee emp = (Employee)obj;
System.out.println("验证姓名:" + emp.name);
System.out.println("**************获取私有字段****并调用********************************");
f = cls.getDeclaredField("phoneNum");
System.out.println(f);
f.setAccessible(true);//暴力反射,解除私有限定
f.set(obj, "18888889999");
System.out.println("验证电话:" + emp);
}
}
获取成员方法并调用
package fanshe;
public class School {
public void show1(String s){
System.out.println("调用了:公有的,String参数的show1(): s = " + s);
}
protected void show2(){
System.out.println("调用了:受保护的,无参的show2()");
}
void show3(){
System.out.println("调用了:默认的,无参的show3()");
}
private String show4(int age){
System.out.println("调用了,私有的,并且有返回值的,int参数的show4(): age = " + age);
return "abcd";
}
}
package fanshe;
import java.lang.reflect.Method;
public class MethodClass {
public static void main(String[] args) throws Exception {
//1.获取Class对象
Class cls = Class.forName("fanshe.School");
//2.获取所有公有方法
System.out.println("***************获取所有的”公有“方法*******************");
cls.getMethods();
Method[] methodArray = cls.getMethods();
for(Method m : methodArray){
System.out.println(m);
}
System.out.println("***************获取所有的方法,包括私有的*******************");
methodArray = cls.getDeclaredMethods();
for(Method m : methodArray){
System.out.println(m);
}
System.out.println("***************获取公有的show1()方法*******************");
Method m = cls.getMethod("show1", String.class);
System.out.println(m);
//实例化一个Student对象
Object obj = cls.getConstructor().newInstance();
m.invoke(obj, "刘德华");
System.out.println("***************获取私有的show4()方法******************");
m = cls.getDeclaredMethod("show4", int.class);
System.out.println(m);
m.setAccessible(true);//解除私有限定
Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(获取有反射),一个是实参
System.out.println("返回值:" + result);
}
}
利用反射运行配置文件
在src目录下建一个pro.txt配置文件,用来更新操作
pro.txt内容:
ClassName=fanshe.Student1
MethodName=show
package fanshe;
public class Student1 {
public void show() {
System.out.println("is show");
}
}
package fanshe;
import java.io.FileReader;
import java.lang.reflect.Method;
import java.util.Properties;
public class Demo {
public static void main(String[] args) throws Exception {
//通过反射获取class对象
Class cls = Class.forName(getValue("ClassName"));
//获取show方法
Method m = cls.getMethod(getValue("MethodName"));
//调用show方法
m.invoke(cls.getConstructor().newInstance());
}
private static String getValue(String key) throws Exception {
Properties pro = new Properties();//获取文件配置对象
FileReader in = new FileReader("pro.txt");
pro.load(in); //将流加载到配置文件对象中
in.close();
return pro.getProperty(key);
}
}
运行后
is show
当我们需要更改类时,创建一个新类Student2,然后只需要更改pro.txt的内容,就可以运行了。
ClassName=fanshe.Student2
MethodName=show
package fanshe;
public class Student2 {
public void show() {
System.out.println("is show2");
}
}
其他不用改
输出:
is show2
以前写过的一些方法,那时理解很浅
点我