1. 概述
反射:将类的各个组成部分封装为其他对象,可以在程序运行过程中操作这些对象,还可以解耦,提高程序的可扩展性。Java反射技术应用广泛,它能配置类的全限定名、方法和参数,完成对象的初始化,甚至反射某些方法。
2.获取Class对象的方式
* Class.forName(“全限定名”);将字节码文件加载进内存,返回Class对象。多用于配置文件,将类名定义在配置文件中。读取文件,加载类
* 类名.class:通过类名的属性class获取。多用于参数传递
* 对象.getClass():getClass()在Object类中定义着的。多用于对象获取字节码格式
代码演示:
package com.wanfei.domain;
/**
* 创建一个Student类:
*/
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
获取Class对象的三种方式的演示及物理地址比较:
public static void main(String[] args) throws ClassNotFoundException{
//使用Class.forName()
Class class_01 = Class.forName( "com.wanfei.domain.Student" );
System.out.println(class_01);
//使用 类名.Class
Class class_02 = Student.class;
System.out.println(class_02);
//使用对象名.getClass()
Class class_03 = new Student().getClass();
System.out.println(class_03);
//比较
System.out.println(class_01 == class_02); //true
System.out.println(class_01 == class_03); //true
/**
* 结论:同一个字节码文件(*.class)在一次程序运行过程中,
* 只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
*/
}
打印结果:
3.字节码对象Class的功能
1)获取成员变量们
- Field[] getFields() :获取所有public修饰的成员变量
- Field getField(String name) : 获取指定名称的成员变量
- Field[] getDeclaredFields() : 获取所有成员变量,不考虑修饰符
- Field getDeclaredField(String name)
2)获取构造方法们
- Constructor<?>[] getConstructors()
- Constructor getConstructor(类<?>… parameterTypes)
- Constructor getDeclaredConstructor(类<?>… parameterTypes)
- Constructor<?>[] getDeclaredConstructors()
3)获取成员方法们
- Method[] getMethods()
- Method getMethod(String name, 类<?>… parameterTypes)
- Method[] getDeclaredMethods()
- Method getDeclaredMethod(String name, 类<?>… parameterTypes)
4)获取全类名
String getName()
4.Field成员变量的使用:
修改Student.java文件中的内容
private String name;
private int age;
public String a;
public String b;
String c;
测试获取和设置成员变量:
public static void main(String[] args) throws Exception {
Class studentClass = Student.class;
System.out.println("------------- 获取public修饰的成员变量-----------------");
Field[] fields = studentClass.getFields();
for (Field f: fields) {
System.out.println(f);
}
System.out.println("------------- 获取所有成员变量-,不考录修饰符----------------");
Field[] fields2 = studentClass.getDeclaredFields();
for (Field f2: fields2) {
System.out.println(f2);
}
//获取指定的成员变量并设置值
Student student = new Student();
Field fieldName = studentClass.getDeclaredField( "a" );
fieldName.set(student,"Pink Floyd" );
//输出打设置后的值
Object value = fieldName.get( student );
System.out.println(student.toString());
//不能直接访问私有变量,若需要访问。需忽略访问权限修饰符的安全检查
Field fieldName2 = studentClass.getDeclaredField( "c" );
fieldName2.setAccessible( true );//暴力反射
System.out.println(fieldName2.get( student ));
}
运行结果截图如下:
D:\Java\jdk1.8.0_221\bin\java.exe "-javaagent:D:\IntelliJ IDEA2018\lib\idea_rt.jar=59928:D:\IntelliJ IDEA2018\bin" -Dfile.encoding=UTF-8 -classpath D:\Java\jdk1.8.0_221\jre\lib\charsets.jar;D:\Java\jdk1.8.0_221\jre\lib\deploy.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\access-bridge-64.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\cldrdata.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\dnsns.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\jaccess.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\jfxrt.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\localedata.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\nashorn.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\sunec.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\sunjce_provider.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\sunmscapi.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\sunpkcs11.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\zipfs.jar;D:\Java\jdk1.8.0_221\jre\lib\javaws.jar;D:\Java\jdk1.8.0_221\jre\lib\jce.jar;D:\Java\jdk1.8.0_221\jre\lib\jfr.jar;D:\Java\jdk1.8.0_221\jre\lib\jfxswt.jar;D:\Java\jdk1.8.0_221\jre\lib\jsse.jar;D:\Java\jdk1.8.0_221\jre\lib\management-agent.jar;D:\Java\jdk1.8.0_221\jre\lib\plugin.jar;D:\Java\jdk1.8.0_221\jre\lib\resources.jar;D:\Java\jdk1.8.0_221\jre\lib\rt.jar;D:\IdeaProjects\SSM实战\day05_mybatis06_useful\day06_ssm01_java设计模式\target\classes;C:\Users\16565\.m2\repository\junit\junit\4.12\junit-4.12.jar;C:\Users\16565\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;C:\Users\16565\.m2\repository\org\mybatis\mybatis\3.4.5\mybatis-3.4.5.jar;C:\Users\16565\.m2\repository\mysql\mysql-connector-java\5.1.6\mysql-connector-java-5.1.6.jar;C:\Users\16565\.m2\repository\log4j\log4j\1.2.12\log4j-1.2.12.jar;C:\Users\16565\.m2\repository\dom4j\dom4j\1.6.1\dom4j-1.6.1.jar;C:\Users\16565\.m2\repository\xml-apis\xml-apis\1.0.b2\xml-apis-1.0.b2.jar;C:\Users\16565\.m2\repository\jaxen\jaxen\1.1.6\jaxen-1.1.6.jar com.wanfei.test.Main
------------- 获取public修饰的成员变量-----------------
public java.lang.String com.wanfei.domain.Student.a
public java.lang.String com.wanfei.domain.Student.b
------------- 获取所有成员变量-,不考录修饰符----------------
private java.lang.String com.wanfei.domain.Student.name
private int com.wanfei.domain.Student.age
public java.lang.String com.wanfei.domain.Student.a
public java.lang.String com.wanfei.domain.Student.b
java.lang.String com.wanfei.domain.Student.c
Student{name='null', age=0, a='Pink Floyd', b='null', c='null'}
null
Process finished with exit code 0
5.Constructor 构造方法的使用
Constructor 可以用来创建对象,在使用不带参数的构造器创建对象时,可直接使用Class类提供的newInstance()方法.
public static void main(String[] args) throws Exception {
Class studentClass = Student.class;
//获取构造器,用来创建对象
Constructor constructor = studentClass.getConstructor( String.class,int.class );
System.out.println(constructor);
//使用带参数的构造器创建对象
Object object = constructor.newInstance( "King Crimson",100 );
System.out.println(object.toString());
//使用不带参数的构造器创建对象
Constructor constructor2 = studentClass.getConstructor( );
Object object2 = constructor2.newInstance( );
System.out.println(object2.toString());
//使用不带参数的构造器创建对象简化版
Object object3 = studentClass.newInstance();
System.out.println(object3.toString());
}
运行结果:
public com.wanfei.domain.Student(java.lang.String,int)
Student{name='King Crimson', age=100, a='null', b='null', c='null'}
Student{name='null', age=0, a='null', b='null', c='null'}
Student{name='null', age=0, a='null', b='null', c='null'}
6.Method方法的使用
在Student.java文件中添加eat()和info(String name,int age)两个方法.
public void eat(){
System.out.println("eat--------");
}
public void info(String name,int age){
System.out.println(name+"-----> "+age);
}
调用方法是用到Method类的invoke(Object object,…)方法
public static void main(String[] args) throws Exception {
//不带参的方法
Class studentClass = Student.class;
Method eat_method = studentClass.getMethod( "eat");
Student student = new Student( );
eat_method.invoke( student );
//带参的方法
Method info_method = studentClass.getMethod("info", String.class, int.class);
Student student1 = new Student( );
info_method.invoke( student1,"camel",99 );
}
执行后的结果
eat--------
camel-----> 99
7.案例
写一个小框架,要求在不改变代码的前提下,可以创建任意的对象,执行任意的方法,实现思路如下:
这里是引用
- 将要生成的对象的全类名和要执行的方法写入配置文件中
- 在框架中读取配置文件
- 使用反射技术加载类文件进内存
- 创建对象
- 执行方法
步骤:
- 编写Person类和Student类并编写方法
public class Person {
public void eat(){
System.out.println("吃东西");
}
}
public class Student {
public void sleep(){
System.out.println("在寝室睡大觉");
}
}
2)编写配置文件pro.properties,只需要修改该文件里的内容便可以创建各种类
className=com.wanfei.re.domain.Person
methodName=eat
3)编写框架程序
public class ReflectTest {
public static void main(String[] args) throws Exception {
//1.加载配置文件
Properties properties = new Properties( );
//2.读取class目录下的文件
ClassLoader classLoader = ReflectTest.class.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream( "pro.properties" );
properties.load( inputStream);
String className = properties.getProperty( "className" );
String methodName = properties.getProperty( "methodName" );
//使用反射机制
Class cls = Class.forName( className);
Object object = cls.newInstance();
Method method = cls.getMethod( methodName );
method.invoke( object );
}
}
执行上面代码的结果
D:\Java\jdk1.8.0_221\bin\java.exe "-javaagent:D:\IntelliJ IDEA2018\lib\idea_rt.jar=52872:D:\IntelliJ IDEA2018\bin" -Dfile.encoding=UTF-8 -classpath D:\Java\jdk1.8.0_221\jre\lib\charsets.jar;D:\Java\jdk1.8.0_221\jre\lib\deploy.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\access-bridge-64.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\cldrdata.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\dnsns.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\jaccess.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\jfxrt.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\localedata.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\nashorn.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\sunec.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\sunjce_provider.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\sunmscapi.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\sunpkcs11.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\zipfs.jar;D:\Java\jdk1.8.0_221\jre\lib\javaws.jar;D:\Java\jdk1.8.0_221\jre\lib\jce.jar;D:\Java\jdk1.8.0_221\jre\lib\jfr.jar;D:\Java\jdk1.8.0_221\jre\lib\jfxswt.jar;D:\Java\jdk1.8.0_221\jre\lib\jsse.jar;D:\Java\jdk1.8.0_221\jre\lib\management-agent.jar;D:\Java\jdk1.8.0_221\jre\lib\plugin.jar;D:\Java\jdk1.8.0_221\jre\lib\resources.jar;D:\Java\jdk1.8.0_221\jre\lib\rt.jar;D:\IdeaProjects\SSM实战\ssm\target\classes ReflectTest
吃东西
Process finished with exit code 0
然后修改pro.properties里面的内容
className=com.wanfei.re.domain.Student
methodName=sleep
再次执行ReflectTest.java文件
D:\Java\jdk1.8.0_221\bin\java.exe "-javaagent:D:\IntelliJ IDEA2018\lib\idea_rt.jar=52922:D:\IntelliJ IDEA2018\bin" -Dfile.encoding=UTF-8 -classpath D:\Java\jdk1.8.0_221\jre\lib\charsets.jar;D:\Java\jdk1.8.0_221\jre\lib\deploy.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\access-bridge-64.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\cldrdata.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\dnsns.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\jaccess.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\jfxrt.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\localedata.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\nashorn.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\sunec.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\sunjce_provider.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\sunmscapi.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\sunpkcs11.jar;D:\Java\jdk1.8.0_221\jre\lib\ext\zipfs.jar;D:\Java\jdk1.8.0_221\jre\lib\javaws.jar;D:\Java\jdk1.8.0_221\jre\lib\jce.jar;D:\Java\jdk1.8.0_221\jre\lib\jfr.jar;D:\Java\jdk1.8.0_221\jre\lib\jfxswt.jar;D:\Java\jdk1.8.0_221\jre\lib\jsse.jar;D:\Java\jdk1.8.0_221\jre\lib\management-agent.jar;D:\Java\jdk1.8.0_221\jre\lib\plugin.jar;D:\Java\jdk1.8.0_221\jre\lib\resources.jar;D:\Java\jdk1.8.0_221\jre\lib\rt.jar;D:\IdeaProjects\SSM实战\ssm\target\classes ReflectTest
在寝室睡大觉
Process finished with exit code 0
总结
没啥好说的,到此结束
来源:CSDN
作者:房东的拉布拉多
链接:https://blog.csdn.net/qq_40610435/article/details/103631154