上一篇 <<<设计模式总览
下一篇 >>>代理模式(Proxy Pattern)
1.反射机制获取类的三种方法
//第一种方式:
Classc1 = Class.forName("Employee");
//第二种方式:
//java中每个类型都有class 属性.
Classc2 = Employee.class;
//第三种方式:
//java语言中任何一个java对象都有getClass 方法
Employee e = new Employee();
Classc3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)
三种方式取得的结果都是一样,就像Spring容器通过名字、bean的class等获取结果一样,都存放在堆中的唯一空间。
反射操作就是利用堆中的class信息进行实例化及相关操作。
优点:能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
缺点:
1.反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;
2.反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。
2.利用反射机制创建对象
Class<?> forName = Class.forName("com.jarye.entity.User");
// 实例化无参构造函数
Object newInstance = forName.newInstance();
// 实例化有参构造函数
Class<?> forName = Class.forName("com.jarye.entity.User");
Constructor<?> constructor = forName.getConstructor(String.class, String.class);
User newInstance = (User) constructor.newInstance("123", "123");
3.反射常用方法
反射获取构造方法
(1)批量获取的方法:
public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
(2)单个获取的方法,并调用:
public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
(3) 调用构造方法:
Constructor-->newInstance(Object... initargs)
newInstance是 Constructor类的方法(管理构造函数的类)
api的解释为:newInstance(Object... initargs) ,使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
它的返回值是T类型,所以newInstance是创建了一个构造方法的声明类的新实例对象,并为之调用。
获取成员变量并调用:
1.批量的
1.1.Field[] getFields():获取所有的"公有字段"
1.2.Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
2.获取单个的:
2.1.public Field getField(String fieldName):获取某个"公有的"字段;
2.2.public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
3.设置字段的值 需要注意权限问题:
3.1.Field --> public void set(Object obj,Object value):
3.2.参数说明:
3.3.obj:要设置的字段所在的对象;
获取成员方法并调用:
1.所有的方法:
1.1.public Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类)
1.2.public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的)
2.获取单个的方法:
2.1.public Method getMethod(String name,Class<?>... parameterTypes):
参数:
name : 方法名;
Class ... : 形参的Class类型对象
public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
调用方法:
Method --> public Object invoke(Object obj,Object... args):
参数说明:
obj : 要调用方法的对象;
4.反射底层原理
反射机制底层其实走的是MethodAccessor,分为2步:
a、访问控制检查(判断该方法的修饰符modifiers是否为public)
b、调用MethodAccessor.invoke()实现方法执行,创建MethodAccessor有两种选择
- sun.reflect.noInflation的设置为true,则ReflectionFactory利用MethodAccessor的字节码生成类MethodAccessorGenerator直接创建一个代理类,通过间接调用原方法完成invoke()任务【使用Java代码生成】
- sun.reflect.noInflation的设置为false或未达到设置值(默认15次)时,创建DelegatingMethodAccessorImpl委托类,并将执行invoke()方法的具体内容交由NativeMethodAccessorImpl实现【使用Native代码生成】
参数 | 说明 |
---|---|
sun.reflect.noInflation | 是控制是否立即进行类膨胀 |
sun.reflect.inflationThreshol | 类膨胀阈值 |
可以通过启动参数-Dsun.reflect.noInflation=false -Dsun.reflect.inflationThreshold=15
5.反射应用
<dependencies>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.10</version>
</dependency>
</dependencies>
public class ReflexUtils {
public static Set<Class> getInterfaceImpls(Class c) {
Reflections reflections = new Reflections("cn.jarye");
//Filter是个接口,获取在指定包扫描的目录所有的实现类
Set<Class> classes = reflections.getSubTypesOf(c);
return classes;
}
public static void main(String[] args) {
// ReflexUtils.getInterfaceImpls(MsgObServer.class)
// interfaceImpls.forEach((t) -> {
// System.out.println("name:" + t.getSimpleName());
// });
}
}
相关文章链接:
<<<Java基础-字节码技术
<<<Java基础-创建对象的方式汇总
<<<Java基础-对象布局
<<<Java基础-对象的引用类型
<<<Class文件分析一个类为啥最多支持65535个接口
<<<为什么重写equals还要重写hashcode方法
<<<如何自定义注解
<<<十大经典排序算法汇总-动画演示
<<<JDK8十大新特性