Java的反射机制

目录

一.反射机制讲解

 1.反射机制的概念

 2.反射机制的优缺点

优点

缺点

二.反射的使用 

 1.获取Class的三种方法

Class.forName(完整类名)

 类名.class

对象.getClass

2.通过反射实例化

getConstructor() 获取公开构造方法

getDeclaredConstructor() 获取私有的构造方法

setAccessible() 是否启动和禁用安全检查

三.反射动态方法调用 

getMethod() 调用公开的方法

 invoke()

 getDeclaredMethod() 调用私有的方法 

四.通过反射获取成员变量

getField()  获取公开的成员变量

getDeclaredField() 获取私有的成员变量


一.反射机制讲解

 1.反射机制的概念

  反射是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法

  并且对于任意一个对象,都能够调用它的任意一个方法

  这种动态获取信息以及动态调用对象方法的功能称为反射机制。

 

  简单来说

  动态获取类中的信息,就是反射机制。

 

 ps:反射机制是框架设计的灵魂


 2.反射机制的优缺点

优点

  • 反射机制极大的提高了程序的灵活性和扩展性,降低模块的耦合性,提高自身的适应能力。
  • 通过反射机制可以让程序创建和控制任何类的对象,无需提前硬编码目标类
  • 使用反射机制能够在运行时构造一个类的对象、判断一个类所具有的成员变量和方法、调用一个对象的方法。
  • 反射机制是构建框架技术的基础所在,使用反射可以避免将代码写死在框架中。

缺点

  • 使用反射通常需要程序的运行没有安全方面的限制。如果一个程序对安全性提出要求,则最好不要使用反射。
  • 使用反射性能较低,需要解析字节码(.class文件),将内存中的对象进行解析(避免在对性能要求很高的程序或经常被执行的代码中使用反射)

二.反射的使用 

 1.获取Class的三种方法

用一个学生类(Student)来做示范

 

  • Class.forName(完整类名)

   这个我们在连接数据库驱动时使用过,下面大家看下示例代码:

 //通过该类的完整名字获取Class对象
 Class<Student> clazz01=(Class<Student>)Class.forName("com.yjx.test.Student");
  •  类名.class

   直接通过类名.class获得Class对象,代码如下:

 //通过类名.class获取到Class对象
Class<Student> clazz02=(Class<Student>)Student.class;
  • 对象.getClass

     这种情况一般都是当构造函数没有被私有化,可以直接将该类实例得到对象,进行操作,如果类被私有化构造函数,那么还是使用上面两种。代码如下:

 //通过对象.getClass获取Class对象
 Student stu=new Student();
 Class<Student> clazz03=(Class<Student>)stu.getClass();

 注:运行期间,一个类只产生一个Class对象产生,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。

 大家可以将这三个代码同时运用,然后打印,都是一样的


2.通过反射实例化

我们通过反射获取到构造函数,将该类实例化。

学生类代码如下:

package com.yjx.test;

public class Student {
	
	private Integer id;
    private String name;
    private Integer age;
    
    
    //get和set方法
	
    public Integer getId() {
		return id;
	}
 
	public void setId(Integer id) {
		this.id = id;
	}


	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}


	public Integer getAge() {
		return age;
	}


	public void setAge(Integer age) {
		this.age = age;
	}



	/**
     * 无参构造
     */
     public Student() {
		
		System.out.println("调用无参构造方法创建了一个学生对象");	
	}
	
     private Student(Integer id, String name) {
 		super();
 		this.id = id;
 		this.name = name;
 		
 	}
     

	public Student(Integer id, String name, Integer age) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
	}
	
	
	public void hello() {
		System.out.println("你好!我是" + this.name);
	}

	public void hello(String name) {
		System.out.println(name + "你好!我是" + this.name);
	}

	@SuppressWarnings("unused")
	private Integer add(Integer a, Integer b) {
		return new Integer(a.intValue() + b.intValue());
	}

	 
	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
	}


	
	
 
 
    
}
  • getConstructor() 获取公开构造方法

      获取公开的构造方法我们就是使用到该方法,如果需要调用无参构造,我们就里面什么都不填,如果是其他的构造方法,那么那个构造方法中参数有几个以及什么属性,都要在该方法中依次输入。

package com.yjx.test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Test01 {
	public static void main(String[] args) throws Exception {
		
	  //通过该类的权限命名获取Class对象
	  Class<Student> clazz01=(Class<Student>)Class.forName("com.yjx.test.Student");
	  
	  //通过类名.class获取到Class对象
	  Class<Student> clazz02=(Class<Student>)Student.class;
	  
	  //通过对象.getClass获取Class对象
	  Student stu=new Student();
	  Class<Student> clazz03=(Class<Student>)stu.getClass();
		
	  
	   //通反射实例化,class对象获取到该构造方法,在里面传入值,根据相对应的值找到相对应的构造方法
	   //无参构造就不传值进去
	    Constructor<Student> c01=clazz01.getConstructor();
	   //获取到Student对象
	   Student stu01=c01.newInstance();
	   stu01.setName("hhh");
	   stu01.setId(1);
	   stu01.setAge(18);
	   System.out.println(stu01);
	   
	   //通过反射实例,通过class对象获取到该构造方法
	   //传入该构造方法相对应的值
	   Constructor<Student> 
       c02=clazz01.getConstructor(Integer.class,String.class,Integer.class);
	   //得到Student对象,newInstance()方法可以根传入的参数,调用该构造函数。
	   Student stu02=c02.newInstance(2,"小黄",18);
	   System.out.println(stu02);
	    
	   
	}

}
  • getDeclaredConstructor() 获取私有的构造方法

  • setAccessible() 是否启动和禁用安全检查

1.setAccessible()方法的作用是启动和禁用访问安全检查的开关。

2.setAccessible()方法默认是false,那么反射的对象需要进行安全检查,那么是无法调用该函数的。

3.将setAccessible()方法里的值为true,那么反射的对象不需要进行安全检查,因为禁用了安全检查。

 

  代码如下:

  

package com.yjx.test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Test01 {
	public static void main(String[] args) throws Exception {
		
	  //通过该类的权限命名获取Class对象
	  Class<Student> clazz01=(Class<Student>)Class.forName("com.yjx.test.Student");
	  
	  //通过类名.class获取到Class对象
	  Class<Student> clazz02=(Class<Student>)Student.class;
	  
	  //通过对象.getClass获取Class对象
	  Student stu=new Student();
	  Class<Student> clazz03=(Class<Student>)stu.getClass();
		
	  

	   //获取到私有的构造方法
	   Constructor<Student> c03=clazz01.getDeclaredConstructor(Integer.class,String.class);
	   //在我们访问私有的构造方法或者其他私有的方法时,就需要使用setAccessible()方法
	   //setAccessible作用是启动和禁用访问安全检查的开关
	    //当里面的值为true时则反射的对象在使用时,抑制Java语言访问检查
	    //默认是为false,那么反射的对象进行Java语言访问检查
	    c03.setAccessible(true);
	    //实例Student
	    Student stu03=c03.newInstance(3,"小黑");
	    System.out.println(stu03);
	    

	   
	}

}

三.反射动态方法调用 

  • getMethod() 调用公开的方法

1.getMethod()方法是调用类中的公开方法,往该getMethod()方法中传入方法的名字和该方法所需要传入的那种类型参数。

2.例如无参的方法getMethod("hello")

3.如果需要调用一个有参的方法,该方法需要传入一个String类型的参数,那么getMethod("hello",String.class) 

  

  •  invoke()

      调用Method类代表的方法,可以实现动态调用

代码如下:

package com.yjx.test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Test01 {
	public static void main(String[] args) throws Exception {
		
	  //通过该类的权限命名获取Class对象
	  Class<Student> clazz01=(Class<Student>)Class.forName("com.yjx.test.Student");
	  
	  //通过类名.class获取到Class对象
	  Class<Student> clazz02=(Class<Student>)Student.class;
	  
	  //通过对象.getClass获取Class对象
	  Student stu=new Student();
	  Class<Student> clazz03=(Class<Student>)stu.getClass();
		
	  
	   //通反射实例化,通过class对象获取到该构造方法,在里面传入值,根据相对应的值找到相对应的构造方法
	   //无参构造就不传值进去
	    Constructor<Student> c01=clazz01.getConstructor();
	   //获取到Student对象
	   Student stu01=c01.newInstance();
	   stu01.setName("hhh");
	   stu01.setId(1);
	   stu01.setAge(18);
	   System.out.println(stu01);

	    
	    //反射动态方法调用
	    //将方法的名字传进去
	     Method m01=clazz01.getMethod("hello");
	     m01.invoke(stu01);
	     
	     //将方法的名字,以及该方法所需要传的参数一一对应放入。
	     Method m02=clazz01.getMethod("hello",String.class);
	     //invoke()方法的作用:调用Method类代表的方法,可以实现动态调用
         //这串代码就是stu01.hello("小白")
          m02.invoke(stu01,"小白");
	   
	   
	}

}
  •  getDeclaredMethod() 调用私有的方法 

     

package com.yjx.test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Test01 {
	public static void main(String[] args) throws Exception {
		
	  //通过该类的权限命名获取Class对象
	  Class<Student> clazz01=(Class<Student>)Class.forName("com.yjx.test.Student");
	  
	  //通过类名.class获取到Class对象
	  Class<Student> clazz02=(Class<Student>)Student.class;
	  
	  //通过对象.getClass获取Class对象
	  Student stu=new Student();
	  Class<Student> clazz03=(Class<Student>)stu.getClass();
		
	  
	   //通反射实例化,通过class对象获取到该构造方法,在里面传入值,根据相对应的值找到相对应的构造方法
	   //无参构造就不传值进去
	    Constructor<Student> c01=clazz01.getConstructor();
	   //获取到Student对象
	   Student stu01=c01.newInstance();
	   stu01.setName("hhh");
	   stu01.setId(1);
	   stu01.setAge(18);
	   System.out.println(stu01);

	     
	     //调用私有的方法
	     Method m03=clazz01.getDeclaredMethod("add",Integer.class,Integer.class);
	     m03.setAccessible(true);
	     //因为原本得到的是一个object,而该方法中返回的值为int类型,所以需要进行一个强转
	     int i=(int)m03.invoke(stu01,3,4);
	     System.out.println(i);
	     

	   
	}

}

四.通过反射获取成员变量

  • getField()  获取公开的成员变量

  • getDeclaredField() 获取私有的成员变量

   在实体类中一定要有get和set方法,因为这串语句,在直观上通常以为是直接去找name属性,其实他是通过getName获取。

代码如下:

package com.yjx.test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Test01 {
	public static void main(String[] args) throws Exception {
		
	  //通过该类的权限命名获取Class对象
	  Class<Student> clazz01=(Class<Student>)Class.forName("com.yjx.test.Student");
	  
	  //通过类名.class获取到Class对象
	  Class<Student> clazz02=(Class<Student>)Student.class;
	  
	  //通过对象.getClass获取Class对象
	  Student stu=new Student();
	  Class<Student> clazz03=(Class<Student>)stu.getClass();
		
	  
	   //通反射实例化,通过class对象获取到该构造方法,在里面传入值,根据相对应的值找到相对应的构造方法
	   //无参构造就不传值进去
	    Constructor<Student> c01=clazz01.getConstructor();
	   //获取到Student对象
	   Student stu01=c01.newInstance();
	   stu01.setName("hhh");
	   stu01.setId(1);
	   stu01.setAge(18);
	   System.out.println(stu01);
	   

	     //反射读写属性
	     //在实体类中一定要有get和set方法,因为这串语句,我们通常以为是直接去找name属性,其实他是通过getName获取到该属性
	      Field f01=clazz01.getDeclaredField("name");
	      System.out.println(f01);
	      f01.setAccessible(true);
	      //这一串代码可以理解为Stundent.setName("哈哈哈")
	      f01.set(stu01,"哈哈哈22");
	      System.out.println(stu01);
	      
	      
	      //为什么我们要通过getName去获得属性,因为有可能我们在getName方法中做一些处理,如果直接通过name属性
	      //那么在getName中所定义的就没有意义,为了统一控制出口。
	
 
	   
	}

}

今天的学习到此结束啦!!! 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java反射机制是指在运行时动态地获取一个类的信息,并可以操作类的属性、方法和构造器等。Java反射机制可以使程序员在运行时动态地调用类的方法和属性,扩展类的功能,并可以实现注解、工厂模式以及框架开发等。 Java反射机制的原理如下:首先,Java编译器将Java源代码编译为字节码文件,字节码文件中包含着类的信息,这些信息包括类的名称、方法、属性和构造器等等。接着,Java虚拟机将字节码文件加载到内存中,然后通过类加载器将类加载到内存中形成一个类对象,这个类对象可以操作字节码文件中的信息。 使用Java反射机制的过程如下:首先获取类对象,通过类对象来获取类的构造器、属性、方法等信息,然后调用构造器来创建对象,通过属性获取和设置类的成员属性,通过方法调用类的方法等。 Java反射机制的优点是可以在运行时动态地得到类的信息,使得程序员在程序运行时能够对类进行更加灵活的操作,并可以使得程序更加通用化,同时也存在着一定的性能问题,因为Java反射机制需要Java虚拟机进行一定的额外处理,所以在程序运行时需要进行额外的时间和资源消耗。 总之,Java反射机制Java语言的一项重要特性,在Java开发中广泛应用,在代码编写、框架开发以及API开发中具有重要作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值