反射

由于技术有限,可能理解不到位,或者有错误,希望大家及时指出,共同成长

概述

  • 反射:框架设计的灵魂,反射就是根据字节码文件, 反射类的信息,字段,方法,构造方法等类的内容, 根据字节码文件创建对象, 调用方法的技术

  • 框架:半成品软件。可以在框架的基础上进行软件开发,简化编码

  • 反射的好处:

    1. 可以在程序运行过程中,操作这些对象。
    2. 可以解耦,提高程序的可扩展性。
  • 原理

    1. 首先需要将Java文件保存到本地硬盘 .java
    2. 编辑Java文件,生成字节码文件.class
    3. 使用jvm,将.class文件通过类加载,加载到内存中
    4. 万事万物皆对象,class文件在内存中使用Class类表示
    5. 当使用反射的时候,首先获取到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 );
  }
}

运行结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ywbGwJwy-1572348721110)(images/fslxx.jpg)]

访问字段

方法作用
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 );
    }
}

运行结果
在这里插入图片描述

调用方法

返回值方法作用
Methodclass1.getMethod( 方法名, 方法的参数类型.class列表)反射指定方法名的公共方法,第二个参数是变长参数,类型为Class
Methodclass1.getDeclaredMethod(“方法名”, 方法的参数类型… 类型)根据方法名和参数类型获得一个方法对象,包括private修饰的
Method[]class1.getMethods()获取所有的public修饰的成员方法,包括父类中。
Method[]class1.getDeclaredMethods()获取当前类中所有的方法,包含私有的,不包括父类中。
Objectmethod.invoke( 实例名, 方法的实参列表)根据参数args调用对象obj的该成员方法如果obj=null,则表示该方法是静态方法
voidsetAccessible(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

运行结果
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值