1. 反射的概念

反射 机制指的是,程序在运行时能够获取自身的信息。在 java 中只要给定类的名字,就能够获取类的所有属性和方法

反射是 Java 中很多高级特性的基础,比如 注解、动态代理 以及 Spring Ioc、AOP 等技术都需要借助反射来实现。

2. Class 对象的创建

java 中 java.lang.Class 是反射机制的基础,当我们想要在运行期获取一个类中的相关信息的时候,必须先获取其 Class 类。Jvm 会自动将已加载类的 Class 对像载入。

获取 Class 对象的三种方式:

  • 对象实例.getClass()

    MyObject obj = new MyObject();

    Class clazz = obj.getClass();

  • 类名.Class

    Class clazz = MyObject.Class;
  • Class.forName()

    Class clazz = Class.forName("MyObject");

3. 通过反射创建实例

java 中,最常使用的创建实例方法是通过 new 关键字来实现的。使用反射,也有两种可以 创建实例 的方式。

使用 Class 对象的 newInstance() 方法

Class clazz = MyObject.class;
MyObject myObject = clazz.newInstance();

使用 java.lang.reflet.Constructor 中的 newInstance() 方法

Constructor<MyObject> constructor = MyObject.class.getConstructor();
MyObject myObject = constructor.newInstance();

说明:其实 clazz.newInstance() 创建实例的内部也是通过 Constructor 创建实例的方式来实现的

4. 通过反射获取类的属性、方法、注解、构造器

Class 类中有获取类的所有 属性、方法、注解、构造器的相关方法。如下:

获取 非私有的 属性、方法、注解、构造器

Field[] getFields();    // 获取属性
Method[] getMethods(); // 获取方法
Annotation[] getAnnotations(); // 获取注解
Constructor<?>[] getConstructors(); // 获取构造器

获取** 私有的** 属性、方法、注解、构造器

Field[] getDeclaredFields();    // 获取私有属性
Method[] getDeclaredMethods(); // 获取私有方法
Annotation[] getDeclaredAnnotations(); // 获取私有注解
Constructor<?>[] getDeclaredConstructors(); // 获取私有构造器

使用示例:

Class clazz = MyObject.class;
Methods[] methodList = clazz.getFields();

5. 反射机制的一些缺点

  • 反射会破坏封装性:由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用--代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。

  • 反射的性能问题:反射包括了一些动态类型,所以 JVM 无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被 执行的代码或对性能要求很高的程序中使用反射。

  • 安全性问题:使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如 Applet,那么这就是个问题了。

6. 反射对单例的破坏

单例是为了控制 类示例 在内存中只存在一个的机制。他本身的构造方法是 private 的,对外提供 getSingleton() 方法,统一管理实例的获取。

而反射可以通过获取到类中的私有构造方法, 并将其变为可用,通过构造方法生成新的实例,这样就造成了单例的破坏。

双重校验锁的单例模式:

public class Singleton {
private static volatile Singleton singleton(); private Singleton() {
} public static Singleton getSingleton() {
if(singleton == null) {
synchronized (Singleton.class) {
if(singleton == null) {
singleton = new Singleton();
}
}
} return singleton;
}
}

通过反射破坏单例:

Singleton singleton1 = Singleton.getSingleton();
// 通过反射获取构造函数
Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
// 将构造方法设置为可访问
constructor.setAccessible(true);
// 通过构造方法创建一个新的实例
Singleton singleton2 = constructor.newInstance(); System.out.print(singleton1 == singleton2); // false

解决方案:在单例类的构造方法中加判断,当实例已存在的时候,不再创建新的实例

private Singleton() {
if(singleton != null) {
throw new RuntimeException("单例对象只能创建一次...");
}
}

最新文章

  1. About_PHP读写文件
  2. 获取设备的mac地址和IP地址(android6.0以上专用)
  3. 收集C#常用类:自己写的一个DBHelper类
  4. HSV与RGB颜色空间的转换
  5. HRS(CRLF Injection)
  6. tomcat7登录账户配置
  7. HTML 空格的表示符号 nbsp / ensp / emsp 的区别?
  8. 【USACO 3.1.6】邮票
  9. ASP.NET MVC:Razor 引入命名空间
  10. H5的新应用-指定视频的播放进度
  11. 定时任务之crontab命令
  12. android studio添加project libs库步骤
  13. ASP.NET Aries 开发框架(已支持.NET Core)
  14. MySQL视图 索引 存储过程 触发器 函数
  15. 查看和指定SpringBoot内嵌Tomcat的版本
  16. MySQL变量变更小记
  17. linq to sql 项目移植后,数据库实体类需要重新创建?
  18. 开发小技巧1——Logger
  19. BZOJ4921 互质序列
  20. python接口自动化9-https请求(SSL)

热门文章

  1. Docker 数据共享与持久化
  2. ELK Stack 日志平台性能优化
  3. windows系统下使用bat脚本文件设置MySQL系统环境变量
  4. 为什么ArrayList的subList结果不能转换为ArrayList????
  5. Oracle导出和导入
  6. Tableau Server注册安装及配置详细教程
  7. Hudi 数据湖的插入,更新,查询,分析操作示例
  8. java集合框架复习----(2)List
  9. C语言基础--数组
  10. NLP之TextRNN(预测下一个单词)