反射

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

1. 基本概念

反射把Java类中的各种结构(方法、成员变量、构造器、类名)映射成为一个个Java对象(在运行期)

反射就像一面镜子,它可以在运行时获取一个类的所有信息,可以获取到任何定义的信息(包括成员变量,成员方法,构造器等),并且可以操纵类的字段、方法、构造器等部分

     Class c = Class.forName("cn.javareflection.Student")

此代码可以将Student类实时、动态地加载到程序中。加载完成后,在堆内存中就产生了一个Class类型的对象,这个对象就包含了完整的类的结构信息。

好处:

  • 可以在程序运行过程中操作这些对象

  • 可以解耦,提高程序的可扩展性

  • 使得java语言具有动态特性


2. Class类

  • java.lang.Class类十分特殊,用来表示java中的类型(class、interface、enum、annotation、primitive type、void)本身

  • Class类是Reflection的根源。想动态加载运行的类,必须先获得相应的Class对象


3. 获取Class类对象的方式

方式一:对象.getClass()

  • Object中方法:类<?> getClass():返回此 Object的运行时类

方式二:类名.class()

方式三:Class.forName("包名.类名")

  • 此方式使用最多,推荐

  • Class类中方法:static 类<?> forName(String className):返回与给定字符串名称的类或接口相关联的类对象

注意:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都一样

示例代码

public class ReflectTest {public static void main(String[] args) throws ClassNotFoundException {// 三种方式// 1、 对象.getClass()Iphone iphone = new Iphone();Class clz1 = iphone.getClass();// 2、 类.class()Class clz2 = Iphone.class;// 3、 Class.forName("包名.类名")Class clz3 = Class.forName("cn.sxt_01.Iphone");// 同一个类只会加载一个Class对象System.out.println(clz1 == clz2);System.out.println(clz2 == clz3);int[] arr01 = new int[10];int[] arr02 = new int[30];int[][] arr = new int[10][30];System.out.println(arr01.getClass().hashCode());System.out.println(arr02.getClass().hashCode());System.out.println(arr.getClass().hashCode());}
}
class Iphone {}

打印结果

true
true
2129789493
2129789493
668386784

打印结果说明:同一个类(同一维度)只会被加载一次,产生一个Class对象


4. Class类对象的功能

1、获取功能

应用反射的API,获取类的信息(类的名称、属性、方法、构造器)

获取类的名称 描述
Class.getName() 获取包名+类名
Classs.getSimpleName() 只获取类名
获取成员变量 描述
Field[] getFields() 获取所有public修饰的成员变量,包括继承变量
Field getField(String name) 获取指定名称的 public修饰的成员变量
Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符,可以获得私有
Field getDeclaredField(String name) 获取指定的成员变量,不考虑修饰符,可以获得私有
获取构造方法 描述
Constructor<?>[] getConstructors() 获得所有的公共构造方法
Constructor<T> getConstructor(类名,参数列表) 获得指定的公共构造方法
获取成员方法 描述
方法[] getMethods() 获取所有公共的方法,包括继承的方法
方法 getMethod(String name, 类<?>... parameterTypes) 获得指定的公共成员方法

示例代码

先自定义公共类User

public class User {private int id;private int age;private String uname;//必须要有无参的构造方法!public User() {}public User(int id, int age, String uname) {super();this.id = id;this.age = age;this.uname = uname;}public int getId() {return id;}public void setId(int id) {this.id = id;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getUname() {return uname;}public void setUname(String uname) {this.uname = uname;}public void setUname() {this.uname = "张三";}
}

测试类

/*** 应用反射的API,获取类的信息(类的名称、属性、方法、构造器)*/
public class ReflectionDemo {public static void main(String[] args) {try {Class clazz = Class.forName("cn.sxt_01.Reflection.User");// 1、获取类的名称System.out.println(clazz.getName());    // 获得包名 + 类名System.out.println(clazz.getSimpleName());  // 获得类名// 2、获取属性信息Field[] fields = clazz.getDeclaredFields(); // 获得所有的fieldSystem.out.println(fields.length);for (Field temp : fields) {System.out.println("属性:" + temp);}// 3、获取方法信息Method[] methods = clazz.getDeclaredMethods();Method method1 = clazz.getMethod("getUname", null);Method method2 = clazz.getMethod("setUname", String.class);// 若方法有参,则必须传入参数类型对应的class对象。以便于区分重载的方法。for (Method method : methods) {System.out.println("方法:" + method);}// 4、获得构造器信息Constructor[] constructors = clazz.getDeclaredConstructors();   // 获得所有构造器for (Constructor constructor : constructors) {System.out.println("构造器:" + constructor);}Constructor constructor = clazz.getConstructor(int.class,int.class, String.class);System.out.println("指定构造器:" + constructor);} catch (ClassNotFoundException | NoSuchMethodException e) {e.printStackTrace();}}
}

打印结果

cn.sxt_01.Reflection.User
User
3
属性:private int cn.sxt_01.Reflection.User.id
属性:private int cn.sxt_01.Reflection.User.age
属性:private java.lang.String cn.sxt_01.Reflection.User.uname
方法:public int cn.sxt_01.Reflection.User.getId()
方法:public void cn.sxt_01.Reflection.User.setAge(int)
方法:public void cn.sxt_01.Reflection.User.setUname()
方法:public void cn.sxt_01.Reflection.User.setUname(java.lang.String)
方法:public java.lang.String cn.sxt_01.Reflection.User.getUname()
方法:public void cn.sxt_01.Reflection.User.setId(int)
方法:public int cn.sxt_01.Reflection.User.getAge()
构造器:public cn.sxt_01.Reflection.User()
构造器:public cn.sxt_01.Reflection.User(int,int,java.lang.String)
指定构造器:public cn.sxt_01.Reflection.User(int,int,java.lang.String)

2、反射调用

Field:提供有关类或接口的单个字段的信息和动态访问, 可以理解成 成员变量

反射新建实例 描述
Class.newInstance() 创建由此类对象表示的类的新实例
反射调用成员变量 描述
Field.get(Object obj) 返回指定对象上由此Field表示的字段的值
Field.set(Object obj, Object value) 将指定对象变量上此 Field 对象表示的字段设置为指定的新值
Field.setAccessible(true) 忽略访问权限修饰符的安全检查,暴力反射,私有成员允许被访问
反射调用成员方法 描述
Field.setAccessible(true) 私有方法允许被访问
Object invoke(Object obj, Object... args) 在具有指定参数的方法对象上调用此方法对象表示的底层方法

示例代码

public class ReflectionDemo02 {public static void main(String[] args) {try {Class clazz = Class.forName("cn.sxt_01.Reflection.User");// 1、通过反射API动态调用构造方法,构造对象User user = (User) clazz.getDeclaredConstructor().newInstance();// 这里是调用了User的无参构造System.out.println(user);// 有参构造Constructor<User> c = clazz.getDeclaredConstructor(int.class, int.class, String.class);User user1 = c.newInstance(1001, 18, "张三");System.out.println(user1.getUname());// 2、通过反射API调用普通方法Method method = clazz.getDeclaredMethod("setUname", String.class);method.invoke(user1, "李四");System.out.println(user1.getUname());// 3、通过反射API操作属性Field f = clazz.getDeclaredField("uname");f.setAccessible(true);  // 暴力反射,使得可以操作私有属性f.set(user1, "王五");System.out.println(user1.getUname());} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchFieldException e) {e.printStackTrace();}}
}

打印结果

cn.sxt_01.Reflection.User@7ef20235
张三
李四
王五

5. 反射机制的性能问题

setAccessible

  • 启用和禁用访问安全检查的开关,值为true,则表示反射的对象在使用时应该取消Java语言访问检查。值为false,则指示反射的对象应该实施Java语言访问检查。

  • 禁止安全检查,可以提高反射的运行速度

示例代码

@SuppressWarnings("all")
public class Demo {public static void main(String[] args) throws Exception {test1();test2();test3();}public static void test1() {User user = new User();long start = System.currentTimeMillis();for (int i = 0; i < 1000000000L; i++) {user.getUname();}long end = System.currentTimeMillis();System.out.println("普通调用,执行10亿次,耗时:" + (end - start) + "ms");}public static void test2() throws Exception {User user = new User();Class clazz = user.getClass();Method method = clazz.getDeclaredMethod("getUname");long start = System.currentTimeMillis();for (int i = 0; i < 1000000000L; i++) {method.invoke(user, null);}long end = System.currentTimeMillis();System.out.println("反射动态方法调用,通过安全检查,执行10亿次,耗时:" + (end - start) + "ms");}public static void test3() throws Exception {User user = new User();Class clazz = user.getClass();Method method = clazz.getDeclaredMethod("getUname");method.setAccessible(true);        // 跳过安全检查long start = System.currentTimeMillis();for (int i = 0; i < 1000000000L; i++) {method.invoke(user, null);}long end = System.currentTimeMillis();System.out.println("反射动态方法调用,不通过安全检查,执行10亿次,耗时:" + (end - start) + "ms");}
}

打印结果

普通调用,执行10亿次,耗时:920ms
反射动态方法调用,通过安全检查,执行10亿次,耗时:5332ms
反射动态方法调用,不通过安全检查,执行10亿次,耗时:2648ms

6. 反射操作泛型

Java采用泛型擦除机制来引入泛型。Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换的麻烦。但是,一旦编译完成,所有的和泛型有关的类型全部擦除。

和反射+泛型有关的接口类型

  • java.lang.reflect.Type:java语言中所有类型的公共父接口
  • ParameterizedType:表示一种参数化的类型,比如Collection< String >
  • GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型
  • TypeVariable:是各种类型变量的公共父接口
  • WildcardType:代表一种通配符类型表达式,比如?、? extends Number、? super Integer。(wildcard是一个单词:就是”通配符“)

此部分内容用到情况较少,用到时可自行百度


7. 反射操作注解

可通过反射API获得相关注解信息

常用的相关方法 说明
Class.getAnnotations() 获得类的所有有效注解
Class.getAnnotation(类<A> annotationClass) 获得指定注解信息

示例代码

public class AnnotationDemo {public static void main(String[] args) {try {Class clazz = Class.forName("cn.sxt.annotation_03.Student");// 获得类的所有有效注解Annotation[] annotations = clazz.getAnnotations();for (Annotation a : annotations) {System.out.println(a);}// 获得指定注解myTable st = (myTable) clazz.getAnnotation(myTable.class);System.out.println(st.value());// 获得类的所有属性的注解Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {myField  myfield = field.getAnnotation(myField.class);System.out.println(myfield.columnName()+" - "+myfield.type()+" - "+myfield.length());}} catch (ClassNotFoundException e) {e.printStackTrace();}}
}

Java反射机制(Reflection)相关推荐

  1. Java反射机制Reflection

    Java反射机制 1 .class文件 2 Class类 3 Class类与反射机制 4 Java反射机制的类库支持及简介 5 反射机制的定义与应用 6 反射机制Demo Java反射机制demo(一 ...

  2. java反射机制--reflection

    反射,reflection,听其名就像照镜子一样,可以看见自己也可以看见别人的每一部分.在java语言中这是一个很重要的特性.下面是来自sun公司官网关于反射的介绍:    Reflection is ...

  3. 12000+字Java反射,一起全面了解Java反射机制,为学习框架铺路

    文章目录 Java反射机制 理解Class类 获取Class类实例 类的加载过程 类加载器ClassLoader 创建运行时类的对象 获取运行时类的结构 调用运行时类的指定结构 动态代理 Java反射 ...

  4. Java反射机制的基本概念与使用_Java进阶之reflection(反射机制)——反射概念与基础...

    反射机制是Java动态性之一,而说到动态性首先得了解动态语言.那么何为动态语言? 一.动态语言 动态语言,是指程序在运行时可以改变其结构:新的函数可以引进,已有的函数可以被删除等结构上的变化.比如常见 ...

  5. 反射 字段_详解面试中常考的 Java 反射机制

    反射(Reflection) 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说"自审",并能直接操作程序的内部属性和方法. 反射是一项高级 ...

  6. java初反射_初始 java 反射机制 (一)

    反射机制详解 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为j ...

  7. 初识java反射机制

    这篇小博客有这么些内容~认识何使用java反射机制的心路历程 什么是java反射机制呢?什么时候会用到java反射机制呢?怎么使用java反射机制呢? 那我们开始吧~ (一)反射机制(Reflecti ...

  8. 浅谈Java反射机制 之 获取类的字节码文件 Class.forName(全路径名) 、getClass()、class...

    先贴上Java反射机制的概念: AVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法: 对于任意一个对象,都能够调用它的任意一个方法和属性: 这种动态获取的信息以及动态调用对 ...

  9. 工作中用到的java反射机制_(转)JAVA-反射机制的使用

    Java反射机制的实现原理 反射机制:所谓的反射机制就是java语言在运行时拥有一项自观的能力.通过这种能力可以彻底的了解自身的情况为下一步的动作做准备.下面具体介绍一下java的反射机制.这里你将颠 ...

最新文章

  1. 【ACM】CODE[VS] 1215 (DFS)
  2. linux过滤输出内容,Linux内容整理--过滤器、输入输出及管道
  3. 选择P2P平台的技巧和方法
  4. 130道ASP.NET面试题
  5. 【UOJ】67 新年的毒瘤 【BZOJ】1123 BLO
  6. 【Qt】modbus之串口模式读操作
  7. 教你怎么在vi和vim上查找字符串
  8. 跟我一起学.NetCore之选项(Options)核心类型简介
  9. 掌握了Docker Layer Caching才敢自称精通Dockerfile
  10. 开源SUP对接API卡盟程序卡信乐v2.0源码
  11. Salt-Syndic
  12. 服务器修改域,服务器修改域名
  13. java读文件指定行开始到文件的最后
  14. 创造型模式-生成器模式
  15. 加密、解密、openssl的基本应用以及CA的实现过程
  16. html amp css设计与构建网站,HTMLCSS设计与构建网站 笔记CSS
  17. Checker框架学习笔记
  18. SQL-SELECT 语句,From子句,where条件查询
  19. 如何将密切好友的微信聊天记录恢复到自己的微信中
  20. 20172328 2018-2019《Java软件结构与数据结构》第三周学习总结

热门文章

  1. 设计一个可以变换的c语言图案,关于图形和变换专题的数学试题
  2. 总结阐述Cocos2d-X与Cocos2d-iphone区别
  3. td里面字体大小怎么改_教你王者荣耀改战区
  4. 「NOIP 2013」 货车运输
  5. CentOS7.5 firefox Flash插件更新
  6. 微信小程序实现选项卡
  7. 数组巧去重new Set
  8. mysql 中常用的基本操作
  9. msp430入门编程21
  10. 求1e11以内的素数