简单介绍下反射机制[中高]?

反射是框架设计的灵魂.
(使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))

什么是反射?
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

Class是反射的基石。
1、Class是一个类,一个描述类的类(也就是描述类本身),封装了描述方法的Method,描述字段的Filed,描述构造器的Constructor等属性,通过反射可以得到类的各种成分。
2、对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个类的有关信息。
3、Class 对象只能由jvm建立
4、一个类在 JVM 中只会有一个Class实例
5、反射相关的类这个包下:java.lang.reflect

获取Class对象的三种方式要知道。

  1. Object ——> getClass();
  2. 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
  3. 通过Class类的静态方法:Class.forName(String className)(常用,一般都是使用这个)
    参考代码: GetClassTest
// 获取Class对象的三种方式测试
public class GetClassTest {

	public static void main(String[] args) {
		// 第一种方式获取Class对象
		Student stu1 = new Student();
		// 获取Class对象
		Class stuClass = stu1.getClass();
		System.out.println(stuClass.getName());

		// 第二种方式获取Class对象
		Class stuClass2 = Student.class;
		// 判断第一种方式获取的Class对象和第二种方式获取的是否是同一个
		System.out.println("第一种和第二种方式的class是否相等:" + (stuClass == stuClass2));

		// 第三种方式获取Class对象,一般都是用这种方式,强烈推荐这种方式
		try {
			// 注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
			Class stuClass3 = Class.forName("com.cto.edu.basic.Student");
			// 判断三种方式是否获取的是同一个Class对象
			System.out.println("第二种和第三种方式的class是否相等:" + (stuClass3 == stuClass2));
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

	}

}

项目中使用的很多的例子:
使用jdbc链接数据库的时,都用的反射,一般都是通过配置文件书写链接哪个数据库,比如mysql、orcle等,以及对应的关键信息。

简单总结说:
反射就是把java类中的各种成分映射成一个个的Java对象。
例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。
核心的几个类:
Class类:代表一个类
Constructor类:代表类的构造方法
Filed类:代表类的成员变量
Method类:代表类的方法

参考代码: ConstructorsTest FieldsTest

/* 
 * 利用反射获取构造方法测试
 * 通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员; 
 *  
 * 1.获取构造方法: 
 *      1).批量的方法: 
 *          public Constructor[] getConstructors():所有"公有的"构造方法 
            public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有) 
      
 *      2).获取单个的方法,并调用: 
 *          public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法: 
 *          public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有; 
 *       
 *          调用构造方法: 
 *          Constructor-->newInstance(Object... initargs) 
 */  
public class ConstructorsTest {  
    public static void main(String[] args) throws Exception {  
        //加载Class对象  
        Class cla = Class.forName("com.cto.edu.basic.Student");  
          
        System.out.println("**********************所有公有构造方法*********************************");  
        Constructor[] conArray = cla.getConstructors();  
        for(Constructor c : conArray){  
            System.out.println(c);  
        }  
        System.out.println();
          
          
        System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");  
        conArray = cla.getDeclaredConstructors();  
        for(Constructor c : conArray){  
            System.out.println(c);  
        }  
        System.out.println();
        System.out.println("*****************获取公有、无参的构造方法*******************************");  
//      Constructor con = cla.getConstructor();  
        Constructor con = cla.getConstructor(null);  
        //1>、因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型  
        //2>、返回的是描述这个无参构造函数的类对象。  
        System.out.println("con = " + con);  
        
        //调用构造方法  
        Object obj = con.newInstance();  
        
        System.out.println();
        System.out.println("******************获取私有构造方法,并调用*******************************");  
        con = cla.getDeclaredConstructor(int.class);  
        System.out.println(con);  
        //调用构造方法  
        con.setAccessible(true);//暴力访问(忽略掉访问修饰符)  
        obj = con.newInstance(20);  
    }  
      
}  
/* 
 * 利用反射获取成员变量并调用测试: 
 *  
 * 1.批量的 
 *      1).Field[] getFields():获取所有的"公有字段" 
 *      2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有; 
 * 2.获取单个的: 
 *      1).public Field getField(String fieldName):获取某个"公有的"字段; 
 *      2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的) 
 *  
 *   设置字段的值: 
 *      Field --> public void set(Object obj,Object value): 
 *                  参数说明: 
 *                  1.obj:要设置的字段所在的对象; 
 *                  2.value:要为字段设置的值; 
 *  
 */  
public class FieldsTest {  
  
        public static void main(String[] args) throws Exception {  
            //获取Class对象  
            Class stuClass = Class.forName("com.cto.edu.basic.Student");  
            
            System.out.println("************获取所有公有的字段********************");  
            Field[] fieldArray = stuClass.getFields();  
            for(Field f : fieldArray){  
                System.out.println(f);  
            }  
            System.out.println();
            System.out.println("************获取所有的字段(包括私有、受保护、默认的)********************");  
            fieldArray = stuClass.getDeclaredFields();  
            for(Field f : fieldArray){  
                System.out.println(f);  
            }  
            System.out.println();
            System.out.println("*************获取公有字段**并调用***********************************");  
            Field f = stuClass.getField("name");  
            System.out.println(f);  
            //获取一个对象 --》相当于Student stu = new Student();
            Object obj = stuClass.getConstructor().newInstance();  
            //为字段赋值  
            f.set(obj, "张三");//为Student对象中的name属性赋值--》stu.name = "张三"  
            //验证  
            Student stu = (Student)obj;  
            System.out.println("验证姓名:" + stu.name);  
              
            System.out.println(); 
            System.out.println("**************获取私有字段****并调用********************************");  
            f = stuClass.getDeclaredField("tellphone");  
            System.out.println(f);  
            f.setAccessible(true);//暴力反射,解除私有限定  
            f.set(obj, "13512345678");  
            System.out.println("验证电话:" + stu.getTellphone());  
              
        }  
    }

参考文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiangyuenacha

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值