1.概念 反射reflection
反射机制就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
用一句话总结就是反射可以实现在运行时可以知道任意一个类的属性和方法。
主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
反射机制就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
对于任意一个对象,都能够调用它的任意方法和属性,通俗的讲就是反射可以在运行时根据指定的类名获得类的信息。
2.为什么要使用反射,它的作用是什么,它在实际的编程中有什么应用。
静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。
优点
可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中它的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。
缺点
对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。
Eg package reflection
可以发现,每当我们要添加一种新的水果的时候,我们将不得不改变Factory中的源码,而往往改变原有正确代码是一种十分危险的行为。而且随着水果种类的增加,你会发现你的factory类会越来越臃肿
不得不说这是一种十分--的做法。(初学者可能会问,我们为什么不直接在main方法中new水果那,我们可能会需要getInstance方法做一些别的事情。。。所以不直接new);
而反射无疑是一种聪明的办法,看代码。
Eg Factory1 demo2
在出现新品种水果的时候,你完全不用去修改原有代码。
从上面的案例中,我们可以清楚的体会到反射的优越性
三、怎么用
Class相当于抽象了类,它的实例对象是一个个的类,这一个个的类都有类名,属性
方法等等,所以就抽象出了一个Class类来管理
Class没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。
虽然我们不能new一个Class对象,但是却可以通过已有的类得到一个Class对象,共有三种方式,如下:
EgDemo test
前面我们知道了怎么获取Class,那么我们可以通过这个Class干什么呢?
总结如下:
获取成员方法Method
获取成员变量Field
获取构造函数Constructor
1.获取成员方法Method
publicMethod getDeclaredMethod(String name, Class<?>... parameterTypes) // 得到该类所有的方法,不包括父类的
publicMethod getMethod(String name, Class<?>... parameterTypes) // 得到该类所有的public方法,包括父类的
Eg demo2
获取所有方法
Method[] methods =c.getDeclaredMethods(); // 得到该类所有的方法,不包括父类的
或者:
Method[] methods =c.getMethods();// 得到该类所有的public方法,包括父类的
Eg demo3
2.获取成员变量Field
public FieldgetDeclaredField(String name) // 获得该类自身声明的所有变量,不包括其父类的变量
public FieldgetField(String name) // 获得该类自所有的public成员变量,包括其父类变量
Eg demo4
如果想要获取所有成员变量的信息,可以通过以下几步
1.获取所有成员变量的数组:
Field[] fields =c.getDeclaredFields();
2.遍历变量数组,获得某个成员变量field
for (Field field :fields)
Eg demo5
3.获取构造函数Constructor
publicConstructor<T> getDeclaredConstructor(Class<?>... parameterTypes)// 获得该类所有的构造器,不包括其父类的构造器
publicConstructor<T> getConstructor(Class<?>... parameterTypes) // 获得该类所以public构造器,包括父类
Egdemo6
获取所有的构造函数,可以通过以下步骤实现:
1.获取该类的所有构造函数,放在一个数组中:
Constructor[]constructors = c.getDeclaredConstructors();
2.遍历构造函数数组,获得某个构造函数constructor:
for(Constructor constructor : constructors)
Egdemo7
当我们把Person中的默认的无参构造函数取消的时候,比如自己定义只定义一个有参数的构造函数之后,会出现错误,所以大家以后再编写使用Class实例化其他类的对象的时候,一定要自己定义无参的构造函数
其他方法
注解需要用到的
Annotation[]annotations = (Annotation[]) class1.getAnnotations();//获取class对象的所有注解
Annotationannotation = (Annotation) class1.getAnnotation(Deprecated.class);//获取class对象指定注解
TypegenericSuperclass = class1.getGenericSuperclass();//获取class对象的直接超类的
TypeType[] interfaceTypes = class1.getGenericInterfaces();//获取class对象的所有接口的type集合
获取class对象的信息
booleanisPrimitive = class1.isPrimitive();//判断是否是基础类型
booleanisArray = class1.isArray();//判断是否是集合类
boolean isAnnotation =class1.isAnnotation();//判断是否是注解类
booleanisInterface = class1.isInterface();//判断是否是接口类
booleanisEnum = class1.isEnum();//判断是否是枚举类
booleanisAnonymousClass = class1.isAnonymousClass();//判断是否是匿名内部类
booleanisAnnotationPresent = class1.isAnnotationPresent(Deprecated.class);//判断是否被某个注解类修饰
StringclassName = class1.getName();//获取class名字包含包名路径
PackageaPackage = class1.getPackage();//获取class的包信息
StringsimpleName = class1.getSimpleName();//获取class类名
intmodifiers = class1.getModifiers();//获取class访问权限
Class<?>[]declaredClasses = class1.getDeclaredClasses();//内部类
Class<?>declaringClass = class1.getDeclaringClass();//外部类
getSuperclass():获取某类的父类
getInterfaces():获取某类实现的接口