java反射机制解析

第1章 反射
1.1 类的加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
 加载
就是指将class文件读入内存,并为之创建一个Class对象。
任何类被使用时系统都会建立一个Class对象
 连接
验证 是否有正确的内部结构,并和其他类协调一致
准备 负责为类的静态成员分配内存,并设置默认初始化值
解析 将类的二进制数据中的符号引用替换为直接引用
 初始化
就是我们以前讲过的初始化步骤
1.2 类的初始化
Java类只要满足以下任意一条,都讲完成类的初始化。

  1. 创建类的实例
  2. 类的静态变量,或者为静态变量赋值
  3. 类的静态方法
  4. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
  5. 初始化某个类的子类
  6. 直接使用java.exe命令来运行某个主类

到目前为止我们已经知道把class文件加载到内存做了哪些事情了,那么, 如果我们仅仅站在这些class文件的角度,我们如何来使用这些class文件中的内容呢?那就是我们反射将要学习的内容了。

1.3 反射概述
Java反射机制是在运行状态中,对指定的类,任意的方法或任意的字段进行操作,这种动态获取的信息以及动态调用对象方法的功能称为java语言的反射机制。
简而言之,反射就是:在运行时通过代码操作类。
想要操作类,就必须先获得该类的字节码对象Class。通过Class提供的方法对类进行进一步的解剖,从而实现各种操作。
在进行具体操作之前,大家需要先掌握类各个组成的专业描述
 Class类
 Constructor 构造
 Method 方法
 Field 字段
 instance 实例
 invoke 执行

1.4 准备数据

	添加字段
public class Bean {
   private String id;
   private String className;

	Bean类提供getter和setter方法
public String getId() {
   System.out.println("getId方法执行");
   return id;
}
public void setId(String id) {
   System.out.println("setId方法执行:" + id);
   this.id = id;
}

1.5 Class获得方式

//1 通过类型获得
// 语法:类名.class
// 应用场景:确定类型 等
Class clazz1 = Bean.class;

//2 通过实例对象获得
// 语法:变量.getClass()
// 应用场景:在方法内部通过参数获得类型 等
Bean bean = new Bean();
Class clazz2 = bean.getClass();

//3 通过字符串获得
// 语法:Class.forName(“全限定类名”)
// 应用场景:通过配置获得字符串 等
Class clazz3 = Class.forName(“com.itheima_00_Bean.Bean”);
1.6 构造方法与实例

1.6.1 添加构造

	修改Bean ,添加构造方法
public Bean() {
   System.out.println("无参构造");
}

public Bean(String id, String className) {
   this.id = id;
   this.className = className;
   System.out.print("有参构造:" + id);
   System.out.println(" ," + className);
}

1.6.2 无参构造

	无参构造,并获得实例

@Test
public void testDefaultCons() throws Exception{
   //无参构造 , 并实例化
   
   //1获得Class
   Class beanClass = Bean.class;
   
   //2获得构造 -- 没有形参
   Constructor constructor = beanClass.getConstructor();
   
   //3 实例对象,没有实参
   Object bean = constructor.newInstance();
   System.out.println(bean);
   
   /* 结果:
    * 无参构造
    * com.itheima_00_Bean.Bean@8c5488
    */
}

1.6.3 有参构造
 有参构造,并获得实例

@Test
public void testParamCons() throws Exception{
   //有参构造 , 并实例化
   
   //1获得Class
   Class beanClass = Bean.class;
   
   //2获得构造 -- 两个字符串形参 -- Bean(String id, String className)
   Constructor constructor = beanClass.getConstructor(String.class,String.class);
   
   //3 实例对象,两个字符串实参
   Object bean = constructor.newInstance("ArrayListId","java.util.ArrayList");
   System.out.println(bean);
   
   /* 结果:
    * 有参构造:ArrayListId ,java.util.ArrayList
    * com.itheima_00_Bean.Bean@101acff
    */
}

1.6.4 无参构造,简化版获得实例
 无参构造,简化版获得实例

@Test
public void testDefaultSimple() throws Exception{
   //无参构造 , 简化版
   
   //1获得Class
   Class beanClass = Bean.class;
   
   //2 直接获得实例对象,两个字符串实参
   Object bean = beanClass.newInstance();
   System.out.println(bean);
   
   /* 结果:
    * 无参构造
    * com.itheima_00_Bean.Bean@101acff
    */
}

1.6.5 扩展:私有构造(暴力反射)
 修改Bean添加私有构造

private Bean(String id) {
   this.id = id;
   System.out.println("有参构造:" + id);
}
	getConstructor() 使用该方法将无法获得私有方法,程序运行抛异常

	没有使用setAccessible(true),将抛异常
   		 

@Test
public void testPrivateCons() throws Exception{
   //私有构造 
   
   //1获得Class
   Class beanClass = Bean.class;
   
   //2获得构造 -- 两个字符串形参 -- Bean(String id, String className)
   // * getConstructor() 将抛异常  java.lang.NoSuchMethodException
   // * getDeclaredConstructor 可以获得私有构造
   Constructor constructor = beanClass.getDeclaredConstructor(String.class);
   
   //暴力访问
   constructor.setAccessible(true);
   
   //3 实例对象,两个字符串实参
   Object bean = constructor.newInstance("userId");
   System.out.println(bean);
   
   /* 结果:
    * 有参构造:userId 
    * com.itheima_00_Bean.Bean@8c5488
    */
}

1.7 方法与执行

1.7.1 public方法
 获得方法并设置

@Test
public void testMethod() throws Exception{
   
   //1 获得Class
   Class clazz = Class.forName("com.itheima_00_Bean.Bean");
   
   //2 获得实例 ,相当于  Object obj = new Bean();
   Object obj = clazz.newInstance(); 
   
   
   //3 操作setId方法
   //3.1 获得的方法,一个形参
   // * 格式:getMethod(方法名,形成列表)
   Method setMethod = clazz.getMethod("setId", String.class);
   //3.2 执行方法,一个实参
   Object setReturnObj = setMethod.invoke(obj, "我是参数");
   
   System.out.println("set方法返回值:" + setReturnObj);
   
   /* 运行结果:
    * 	无参构造
    * 	setId方法执行:我是参数
    * 	set方法返回值:null
    */
   
   System.out.println("---------------");
   
   //4 操作getId方法 (巩固)
   // 3.1 获得方法,没有形参
   Method getMethod = clazz.getMethod("getId");
   // 3.2 执行方法,没有实参
   Object getReturnObj = getMethod.invoke(obj);
   
   System.out.println("get方法返回值:" + getReturnObj);
   
   /* 运行结果:
    *	getId方法执行
    *	get方法返回值:我是参数
    */
}

1.7.2 扩展:私有方法(暴力反射)
 修改bean,添加方法:

//私有方法
private String show(){
   System.out.println("私有方法执行");
   return "Bean["+id+", "+ className +"]";
}
	getMethod() 使用该方法将无法获得私有方法,程序运行抛异常

	没有使用setAccessible(true),将抛异常



@Test
public void testPrivateMethod() throws Exception{
   //1 获得Class
   Class clazz = Class.forName("com.itheima_00_Bean.Bean");
   
   //2获得构造 -- 两个字符串形参 -- Bean(String id, String className)
   Constructor constructor = clazz.getConstructor(String.class,String.class);
   
   //3 实例对象,两个字符串实参
   Object bean = constructor.newInstance("ArrayListId","java.util.ArrayList");
   
   //3获得方法 -- 私有方法 -- private String show()
   // * getMethod(方法名,形成列表) 将抛异常  java.lang.NoSuchMethodException
   // * getDeclaredMethod(方法名,形成列表) 可以获得私有构造
   Method showMethod = clazz.getDeclaredMethod("show");
   
   //暴力访问
   showMethod.setAccessible(true);
   
   // 4 执行方法,没有实参
   Object getReturnObj = showMethod.invoke(bean);
   System.out.println("show方法返回值:" + getReturnObj);
   
   /* 运行结果:
    *	有参构造:ArrayListId ,java.util.ArrayList
    *	私有方法执行
    *	show方法返回值:Bean[ArrayListId, java.util.ArrayList]
    */
}

1.7.3 扩展:main方法与执行
 修改Bean,添加main方法

public static void main(String[] args) {
   for (int i = 0; i < args.length; i++) {
   	System.out.print(args[i] +", ");
   }
}

 通过反射,调用执行main方法

@Test
public void testMainMethod() throws Exception{
   //调用main方法
   
   //1 获得Class
   Class clazz = Class.forName("com.itheima_00_Bean.Bean");
   
   //2获得方法 -- main静态方法 -- public static void main(String[] args)
   Method mainMethod = clazz.getMethod("main", String[].class);
   Object getReturnObj = mainMethod.invoke(null, (Object)new String[]{"aaa","bbb"});
   
   System.out.println();
   System.out.println("main方法返回值:" + getReturnObj);
   
   /*
    * 运行结果:
    * 	aaa, bbb, 
    *	main方法返回值:null
    */
}

1.8 字段(成员变量)与数据操作(了解)
1.8.1 添加public字段
 Bean类提供成员变量 address

public class Bean {
   private String id;
   private String className;
   public String description;
1.8.2	public字段的操作
@Test
public void testField() throws Exception{
   /* 获得实例,为public字段赋值、获取值
    * public String description;
    */
   
   //1 获得Class
   Class clazz = Class.forName("com.itheima_00_Bean.Bean");
   
   //2 获得实例 ,相当于  Object obj = new Bean();
   Object bean = clazz.newInstance(); 
   
   //3 操作字段,进行赋值,public String description;
   //3.1 获得的字段,一个形参
   // * 格式:getField(字段名)
   Field descriptionField = clazz.getField("description");
   //3.2 为对象的字段赋值
   descriptionField.set(bean, "Bean的描述");
   
   //3.3 获取对象的字段值
   Object fieldReturnObj = descriptionField.get(bean);
   System.out.println("description字段返回值:"+fieldReturnObj);
}

1.8.3 扩展:私有字段(暴力反射)
 getField() 使用该方法将无法获得私有字段,程序运行抛异常

 没有使用setAccessible(true),将抛异常

@Test
public void testPrivateField() throws Exception{
   //私有字段 className
   
   //1获得Class
   Class clazz = Bean.class;
   
   //2 获得实例 ,相当于  Object obj = new Bean();
   Object bean = clazz.newInstance(); 
   
   //3获得字段 -- 私有字段 --  className
   // * getField() 将抛异常  java.lang.NoSuchMethodException
   // * getDeclaredField 可以获得私有字段
   Field classNameField = clazz.getDeclaredField("className");
   
   //暴力访问
   classNameField.setAccessible(true);
   
   //3.2 为对象的字段赋值
   classNameField.set(bean, "Bean的类名称");
   
   //3.3 获取对象的字段值
   Object fieldReturnObj = classNameField.get(bean);
   System.out.println("description字段返回值:"+fieldReturnObj);
   
   
   /* 结果:
    * 无参构造
    * description字段返回值:Bean的类名称
    */
}

猜你喜欢

转载自blog.csdn.net/ITzhongzi/article/details/84648808