反射

反射概述

 

1 什么是反射

让我们从Class类开始了解反射!


每个加载到方法区中的class文件都对应一个Class类的对象,你可以把Class类的对象理解为硬盘上的class文件的对应体。

 

 

2 反射的作用

反射是Java中的高级特性,在各种Java框架中都需要使用反射。所以,就算你将来很长一段时间不使用反射,但你使用的框架都大量使用了反射,所以想深入学习框架,那么就一定要学习反射。

框架通常通过反射来识别一个对象的“类型信息”。当你传递给框架一个对象时,框架会通过反射来了解对象的真实类型(对象实体的类型,而不是引用的类型),这个类型有几个构造器,有什么样的属性,有什么样的方法。还可以通过反射调用构造器,调用方法,对属性进行读写操作。

你可能觉得这没有什么神奇的,那是你还没了解我说的是什么!你需要再想一想,写一个方法,参数是Object obj,然后你的方法需要创建一个与参数类型相同的对象出来,还要调用这个对象上的方法。需要注意,参数是Object类型,但用户调用这个方法时,可能传递的不是Object实体对象,它的真实类型有可能是任何类型。

public static void fun(Object obj) {

通过反射创建obj相同类型的对象;

调用obj的方法,调用的方法可以是obj真实类型独有的方法。而不一定非要Object中的方法。

}

3 Class类都有什么功能

通过面向对象的思想,猜测一个类中应该有什么样的方法了。

一个Student类用来表示学生类型,学生应该有名字,那么学生类就应该有getName()方法。学生也应该有学号,那么学生类就应该有getNumber()方法

一个Class类用来表示类类型,类应该有属性,那么Class类就应该有getField()方法,但一个类可以有多个属性,那么Class类有的就不是getField(),而是getFields()方法,返回值为Field[]类型。相同的道理,Class类也应该有getMethods()getConstructors()方法,用来返回这个类的所有方法和所有构造器的定义。其实今后我们去学习,很可能就只是想使用一个类的一个方法!然后才去查找这个类,再去学习我们需要的方法,对于这个类的其他就一无所知了!你很可能在编写某个项目时会有这样的想法:某某某方法应该是某某某类的!!!然后你就去查找API

描述学生的类型、描述老师的类型、描述计算机的类型,都是很好理解的,但描述类的类型总是让人感觉怪怪的,这也是初学者需要习惯的地方。还有,我们在学习过程中称呼这些类型时也需要注意一下,例如Field表示属性类,Field类有一个属性叫name,那么我们需要怎么说明这个name属性呢?“属性类的name属性”,这是一个不错的称呼!

Class:类的反射对象;

Field:属性反射对象;

Method:方法反射对象;

Constructor:构造器反射对象;

ClassFieldMethodConstrucator:统称为“反射对象”。

 

Class

 

1 反射从Class类开始

要想使用反射,首先你需要得到Class对象,然后才能通过Class对象获取ConstructorFieldMethod等对象。所有的反射对象都不可能自己来new,说白一点,这些反射对象对应的是class文件上的信息,你怎么可能自己去new呢?如果可以自己去new一个Class类的对象,那么是不是就不用我们再去编写.java文件,然后再通过编译器去编译成.class文件了呢?当然这是不可能的!

我们需要思考,Class除了可以返回当前对应类型的所有属性、方法、构造器的反射对象外,还有什么功能呢?例如对应类型的类名是什么?对应类型的父类是谁?对应类型是不是public类,是不是final类。对应类型有没有可能是个数组类型?有没有可能是接口类型?有没有可能是基本类型等等!如果你学会了这样思考,那么你今后学习新类是就方便多了!

 

2 得到Class对象

通过对象获取Class对象:obj.getClass()

你很清楚要使用的Class类型:String.classint.class,只需要在类型的后面添加.class就表示一个Class类型的实例了。

通过类名来获取Class对象:在只有一个字符串(类名)时使用Class.forName(String className)来获取Class对象。

Class c1 = “”.getClass();

Class c2 = String.class;

Class c3 = Class.forName(“java.lang.String”);

System.out.println(c1 == c2);

System.out.println(c2 == c3);

 

  上面代码输出的都是true,这是因为一个.class文件,在方法区中只对应一个Class对象。

 

3 加载类

我们已经知道,main()方法是程序的入口。那是不是在main()方法开始执行之前,所有的class文件都已经加载到方法区中了呢?答案是:NO!通常只有需要执行到使用某个类的代码时,才会去CLASSPATH中加载class文件,如果程序从头到尾都没有使用某个类,那么这个类对应的class文件就不会被加载到内存。

可以导致一个类被加载可能有:

l 使用一个类的静态方法;

l 使用一个类的静态属性;

l 创建这个类的对象;

l 使用Class.forName()方法加载类;

l 反序列化一个类的对象;

l 加载一个类的子类时,也会加载其父类;

l 加载一个类时,也会加载与该类相关的类。

上面给出的几个可能也只是可能而已,如果当前类没有被加载过,才会去加载,如果已经加载到方法区中了,那么就不可能再去加载。

 

4.Class类方法

方法1

l String getName():返回类名;

l String getSimpleName():返回简单类名,不包含包名,但数组类型使用它比较方便;

l Class getSuperClass():获取父类,Object.class.getSupperClass()返回null

l int getModifiers():获取类的所有修饰符信息;

 

方法2

l Constructor getConstructor(Class… parameterTypes):通过指定的参数类型获取公有构造器反射对象;

l Constructor[] getConstructors():获取所有公有构造器对象;

l Constructor getDeclaredConstructor(Class… parameterTypes):通过指定参数类型获取构造器反射对象。包含私有构造器对象;

l Constructor[] getDeclaredConstructors():获取所有构造器对象。包含私有构造器;

l Field getField(String name):通过名字获取公有属性反射对象,包含父类中声明的公有属性;

l Field[] getFields():获取所有公有属性反射对象,包含父类中声明的公有属性;

l Field getDeclaredField(String name):通过名字获取本类中某个属性,包含本类的private属性,但父类中声明的任何属性都不包含;

l Field[] getDeclaredFields():获取本类中声明的所有属性,包含private属性,但不包含父类中声明的任何属性;

l Method getMethod(String name, Class… parameterTypes):通过方法名和方法参数类型获取方法反射对象,包含父类中声明的公有方法,但不包含所有私有方法;

l Method[] getMethods():获取所有公有方法,包含父类中的公有方法,但不包含任何私有方法;

l Method getDeclaredMethod(String name, Class… parameterTypes):通过方法名和方法参数类型获取本类中声明的方法的反射对象,包含本类中的私有方法,但不包含父类中的任何方法;

l Method[] getDeclaredMethods():获取本类中所有方法,包含本类中的私有方法,但不包含父类中的任何方法。

 

方法3

l boolean isArray():是否为数组类型;

l boolean isAnnotation():是否为注解类型;

l boolean isAnnotationPresent(Class annotationClass):当前类是否被annotationClass注解了;

l boolean isEnum():是否为枚举类型;

l boolean isInterface():是否为接口类型;

l boolean isPrimitive():是否为基本类型;

l boolean isSynthetic():是否为引用类型;

 

方法4

l T newInstance():使用本类无参构造器来创建本类对象;

 

其他反射类

  其他反射类都在java.lang.reflect包下

1.AccessibleObject

AccessibleObject类是ConstructorMethodField三个类的父类。

l Annotation getAnnotation(Class annotationClass):获取作用在当前成员上的annotationClass类型的注解对象;

l Annotation[] getAnnotations():获取作用在当前成员上的所有注解对象;

l boolean isAccessible():判断当前成员是否可访问;

l void setAccessible(boolean flag):设置当前成员是否可访问。

 

2.Construcator

String getName():获取构造器名;

int getModifiers():获取构造器上的所有修饰符信息;

Class getDeclaringClass():获取构造器所属的类型;

Class[] getParameterTypes():获取构造器的所有参数的类型;

Class[] getExceptionTypes():获取构造器上声明的所有异常类型;

T newInstance(Object… initargs):通过构造器反射对象调用构造器。

 

3.Method

l String getName():获取方法名;

l int getModifiers():获取方法上的所有修饰符信息;

l Class getDeclaringClass():获取方法所属的类型;

l Class[] getParameterTypes():获取方法的所有参数的类型;

l Class[] getExceptionTypes():获取方法上声明的所有异常类型;

l Class getReturnType():获取方法的返回值类型;

l Object invode(Object obj, Object… args):通过方法反射对象调用方法,如果当前方法是实例方法,那么当前对象就是obj,如果当前方法是static方法,那么可以给obj传递nullargs表示是方法的参数;

 

4.Field

l String getName():获取属性名;

l int getModifiers():获取属性上的所有修饰符信息;

l Class getDeclaringClass():获取属性所属的类型;

l Class getType():获取当前属性的类型;

l Object get(Object obj):获取obj对象的当前属性值;

l void set(Object obj, Object value):设置obj对象的当前属性值为value

l XXX getXXX(Object obj):如果当前属性为基本类型,可以使用getXXX()系列方法获取基本类型属性值。假如当前属性为int类型,那么可以使用getInt(Object obj)方法获取obj对象的当前属性值;

l void setXXX(Object obj, XXX value):如果当前属性为基本类型,可以使用setXXX()系统方法基本类型属性值。假如当前属性为int类型,那么可以使用setInt(Object obj, int value)方法设置obj对象的当前属性值为value

 

5.Modifier

Modifier类有一系列的static方法用来解析其他getModifiers()方法返回的int值。

Method m = …

int m = m.getModifiers();

boolean b1 = Modifier.isAbstract(m);//解析m中是否包含abstract修饰

boolean b2 = Modifier.isStatic(m);//解析m中是否包含static修饰

String s = Modifiers.toString(m);//把所有修饰都转换成字符串

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值