由于技术有限,可能理解不到位,或者有错误,希望大家及时指出,共同成长
概述
-
反射:框架设计的灵魂,反射就是根据字节码文件, 反射类的信息,字段,方法,构造方法等类的内容, 根据字节码文件创建对象, 调用方法的技术
-
框架:半成品软件。可以在框架的基础上进行软件开发,简化编码
-
反射的好处:
- 可以在程序运行过程中,操作这些对象。
- 可以解耦,提高程序的可扩展性。
-
原理
- 首先需要将Java文件保存到本地硬盘 .java
- 编辑Java文件,生成字节码文件.class
- 使用jvm,将.class文件通过类加载,加载到内存中
- 万事万物皆对象,class文件在内存中使用Class类表示
- 当使用反射的时候,首先获取到Class类,得到这个类之后,就可以得到class文件里面所有内容
-
反射的基础 是Class对象
把一组小狗可以抽象为Dog类, 把一组小猪抽象类Pig类, 把一组人抽象为Person类, 把Dog/Pig/Person/String/System等所有的类抽象为Class类,Class类描述所有的类的共同特征
如何获得Class对象?
获取class对象方式 | 作用 | 应用场景 |
---|---|---|
Class.forName("完整类名") | 通过指定的字符串路径获取 | 多用于配置文件,将类名定义在配置文件中。读取文件,加载类 |
类名.class | 通过类名的属性class获取 | 多用于参数的传递 |
对象.getClass() | 通过对象的getClass()方法获取 | 多用于对象的获取字节码的方式 |
提示:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
反射类的信息
java.lang.reflect
包中有反射相关的类
方法 | 作用 |
---|---|
class1.getModifiers() | 返回类的修饰符(返回值为int,通过此方法转换String modifier = Modifier.toString(class1.getModifiers())😉 |
.getName() | 返回完整类名 |
class1.getSimpleName() | 获得简单类名,只是类名,没有包 |
class1.getSimpleName() | 简易类名 |
class1.getSuperClass() | 父类 |
class1.getInterfaces() | 接口 |
例
public class Test02 {
public static void main(String[] args) {
//1)创建Class对象
Class<?> class1 = String.class;
// Class<?> class1 = Integer.class;
StringBuilder sb = new StringBuilder();
//2)反射类的信息
//2.1 修饰符
int mod = class1.getModifiers(); //方法返回类的修饰符,是一个整数
String modifier = Modifier.toString(mod);
sb.append( modifier );
//2.2 类名
sb.append(" class ");
// sb.append( class1.getName() ) ; //getName()r返回完整类名
sb.append( class1.getSimpleName() ) ; //返回简易类名
//2.3 父类
Class<?> superclass = class1.getSuperclass();
//判断父类是否为Object
if ( Object.class != superclass ) {
sb.append(" extends ");
sb.append( superclass.getSimpleName() );
}
//2.4 接口,getInterfaces()返回接口数组, 如果类没有实现接口,返回的数组长度为0
Class<?>[] interfaces = class1.getInterfaces();
if( interfaces.length > 0 ){ //实现了接口
sb.append(" implements ");
//遍历接口数组
for( int i = 0 ; i<interfaces.length ; i++){
sb.append( interfaces[i].getSimpleName() );
//接口之间使用逗号分隔
if ( i < interfaces.length - 1) {
sb.append(",");
}
}
}
System.out.println( sb );
}
}
运行结果
访问字段
方法 | 作用 |
---|---|
class1.getField( 字段名 ) | 返回指定名称的公共字段 |
class1.getDeclaredField(字段名) | 返回指定名称的字段(公共字段或私有字段) |
class1.newInstance() | 创建此 Class 对象所表示的类的一个新实例。 要求:类必须有public的无参数构造方法 |
field.set( 实例名, 字段值) | 设置字段的值 |
field.get( 实例名 ) | 返回字段的值 |
field.setAccessible(true) | 设置调用该字段可访问(修改) |
例
依赖类
public class Person {
static{
System.out.println("静态代码块, 在类加载内存后执行");
}
public String name;
private int age;
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
public void show() {
System.out.println("name:" + name + ",age:" + age);
}
public void set(String name, int age) {
this.age = age;
this.name = name;
}
}
main类
public class Test03 {
public static void main(String[] args) throws NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
//1) 创建Class对象,
Class<?> class1 = Person.class;
//2) 反射name字段
Field nameF = class1.getField("name");
//3) 通过反射技术创建对象(实例), 默认调用类的无参构造
Object p1 = class1.newInstance(); //相当于new Person()
//4)设置字段的值
nameF.set(p1, "lisi"); //p1.setName("lisi")
//5)返回字段的值
System.out.println( p1 );
System.out.println( nameF.get(p1) ); //p1.getName()
//6)访问私有字段: age
//Field ageF = class1.getField("age"); //只能返回公共字段
Field ageF = class1.getDeclaredField("age"); //返回字段
ageF.setAccessible(true); //设置字段的可访问性
ageF.set(p1, 18);
System.out.println( ageF.get(p1));
System.out.println( p1 );
}
}
运行结果
调用方法
返回值 | 方法 | 作用 |
---|---|---|
Method | class1.getMethod( 方法名, 方法的参数类型.class列表) | 反射指定方法名的公共方法,第二个参数是变长参数,类型为Class |
Method | class1.getDeclaredMethod(“方法名”, 方法的参数类型… 类型) | 根据方法名和参数类型获得一个方法对象,包括private修饰的 |
Method[] | class1.getMethods() | 获取所有的public修饰的成员方法,包括父类中。 |
Method[] | class1.getDeclaredMethods() | 获取当前类中所有的方法,包含私有的,不包括父类中。 |
Object | method.invoke( 实例名, 方法的实参列表) | 根据参数args调用对象obj的该成员方法如果obj=null,则表示该方法是静态方法 |
void | setAccessible(boolean flag) | 暴力反射,flag = true,即设置为可以直接调用私有修饰的成员方法 |
例
依赖类
public class Person {
static{
System.out.println("静态代码块, 在类加载内存后执行");
}
public String name;
private int age;
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
public void show() {
System.out.println("name:" + name + ",age:" + age);
}
public void set(String name, int age) {
this.age = age;
this.name = name;
}
}
main类
public class Test04 {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//1) 创建Class对象
Class<?> class1 = Person.class;
//2) 反射show()方法
Method showM = class1.getMethod("show", null);
//3)通过反射技术创建实例
Object obj = class1.newInstance(); //new Person()
//4)调用方法
showM.invoke(obj, null); //obj.show()
//5)反射set(String, int)方法
Method setM = class1.getMethod("set", String.class , int.class );
setM.invoke(obj, "lisi", 66);
showM.invoke(obj);
System.out.println( obj );
}
}
运行结果
IO+Properties+Reflect
有时会把类名保存到配置文件中, 通过Properties读取配置文件的类名 , 通过反射创建对象
例
public class Test05 {
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException {
//读取配置文件的类名
Properties properties = new Properties();
InputStream inStream = Test.class.getResourceAsStream("/com/fanshe/config.properties");
properties.load(inStream);
String className = properties.getProperty("classname");
//通过反射技术,根据完整类名创建对象
Class<?> class1 = Class.forName(className);
Object p= class1.newInstance();
System.out.println( p );
Field field = class1.getField("name");
field.set(p, "张三");
System.out.println( p );
}
}
配置文件config.properties
内容为classname = com.fanshe.Person
运行结果