java学习笔记----反射



一、什么是反射?


Java的反射是指程序在运行期间可以拿到一个对象的所有信息。

1、反射的原理


了解反射之前,我们需要先大致了解一下java程序的编译运行过程。 程序员写下代码之后,这些源代码由javac (java编译器)编译成字节码(class)文件,字节码文件再由jvm(java虚拟机)加载进内存,然后运行程序。


在jvm第一次读取到一种class类型文件并将其加载进堆内存时,就会为其创建一个 Class类型的对象,并关联起来。

注意:这里的Class和class(类)不同,Class是一个名为Class的class(类),就像我们自己创建的类:Person类、Student类…只不过Class类只能由jvm才能创建,我们无法手动创建)。
比如加载一个String类:

Class cls=new Class(String);

而这个Class对象中保存了class的所有信息,包括类名、包名、父类、实现的接口、所有的方法、字段等。因此,如果获取了Class对象,就可以通过这个Class对象获取到该对象对应的class的所有信息。这种通过Class实例获取class信息的方法称为反射。

2、反射的好处

(1)可以在程序运行过程中,操作对象
(2)可以解耦,提高程序的灵活性和可扩展性

3、反射的缺点

(1)性能问题:使用反射,基本上是一种解释性操作,用于字段和方法的接入时要远慢于直接代码。因此反射主要用于对灵活性和扩展性的要求较高的系统框架上,普通程序不建议使用。

(2)使用反射会模糊程序的逻辑:程序员希望在源代码中看到程序的逻辑,而反射绕过了源代码,因而带来了维护问题,反射比相应的直接代码更复杂。



二、获取Class对象的三种方式

1、Class.forName(“全类名”)

Class cls1 = Class.forName("cn._16_reflect.Person");

2、类名.Class

Class cls2 = Person.class;

3、对象.getClass( )

Class cls3 = p.getClass();

注意:同一个字节码文件在一次程序运行过程中,字节码文件只会被加载一次,不论用那种获取方式得到的字节码文件都是同一个。
论证如下:

public static void main(String[] args) throws ClassNotFoundException {
        //1.Class.forName("全类名")
        Class cls1 = Class.forName("cn._16_reflect.Person");
        System.out.println(cls1);
        //2.类名.Class
        Class cls2 = Person.class;
        System.out.println(cls2);
        //3.对象.getClass()
        Person p=new Person();
        Class cls3 = p.getClass();
        System.out.println(cls3);
        
        System.out.println(cls1==cls2);//true
        System.out.println(cls2==cls3);//true
    }



三、Class对象的功能

1、获取成员字段

//1.Field[] getField(String name);获取成员变量指定Field
        Field a = cls.getField("a");
//2.Field[] getFields();获取所有public修饰的成员变量
        Field[] fields = cls.getFields();
//3.Field getDeclaeredField(String name);获取成员变量指定Field,不考虑修饰符
        Field a = cls.getDeclaredField("a");
//4.Field[] getDeclaredFields();获取所有成员变量,不考虑修饰符
		Field[] fields = cls.getDeclareFields();

注意:使用不考虑修饰符的方法时,访问私有成员时需要忽略访问修饰符的安全检查,具体怎么做呢?如下:
Class对象 .setAccessible(boolean flag);//称为暴力反射

cls.setAccessible(true);

2、获取构造方法

//1.Constructor<T> getConstructors(类<?>... parameterTypes);获取指定的构造方法
	Constructor<Person> constructor = cls.getConstructor(String.class, int.class);//括号里是不同类型的参数的class对象
//2.Constructor<?>[] getConstructors();获取public修饰的所有构造方法
	Constructor[] c=cls.getConstructors();
//3.Constructor<T> getDeclaredConstructors(类<?>... parameterTypes);获取指定的构造方法,并且不考虑修饰符

//4.Constructor<?>[] getDeclaredConstructors();获取所有构造方法,并且不考虑修饰符

//注意:使用空参构造有一个创建对象的方法,class对象的newInstance方法
	Object person1 = constructor1.newInstance();

3、获取成员方法

//1.Method getMethod(String name);获取指定名称的空参方法
        Method eat1 = cls.getMethod("eat");
//2.Method getMethod(String name,类<?>... parameterTypes);获取指定名称的带参方法
        Method eat2 = cls.getMethod("eat", String.class);
//3.Method[] getMethods();获取所有方法	
	Method[] methods = cls.getMethods();
/*会连同父类的public修饰的方法都打印出来,Person类直接继承自Object,所以会打印Object的方法*/
    
//4.Method getDeclaredMethod(String name);
	//如果想获取私有方法,就用method.setAccessible(true)暴力反射
//5.Method getDeclaredMethod(String name,类<?>... parameterTypes);

//6.Method[] getDeclaredMethods();

/*获取成员方法之后可以创建类的对象,用获取到的方法对象调用invoke()方法,
并传入类对象和参数,可以实现获取到的成员方法
Object invoke(Object obj,Object...args)*/
	Person p=new Person();//创建对象
	//执行方法
    eat1.invoke(p);
	eat2.invoke(p,"rice");//传进对象p、参数rice

4、获取全类名

//获取全类名String getName();用Class对象调用
        String name = cls.getName();
        System.out.println(name);//cn._16_reflect.Person

5、获取方法名

//获取方法名String getName();用方法对象调用
	String name = method.getName();
    System.out.println(name);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值