Java反射机制(Reflection)
反射
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)相关推荐
- Java反射机制Reflection
Java反射机制 1 .class文件 2 Class类 3 Class类与反射机制 4 Java反射机制的类库支持及简介 5 反射机制的定义与应用 6 反射机制Demo Java反射机制demo(一 ...
- java反射机制--reflection
反射,reflection,听其名就像照镜子一样,可以看见自己也可以看见别人的每一部分.在java语言中这是一个很重要的特性.下面是来自sun公司官网关于反射的介绍: Reflection is ...
- 12000+字Java反射,一起全面了解Java反射机制,为学习框架铺路
文章目录 Java反射机制 理解Class类 获取Class类实例 类的加载过程 类加载器ClassLoader 创建运行时类的对象 获取运行时类的结构 调用运行时类的指定结构 动态代理 Java反射 ...
- Java反射机制的基本概念与使用_Java进阶之reflection(反射机制)——反射概念与基础...
反射机制是Java动态性之一,而说到动态性首先得了解动态语言.那么何为动态语言? 一.动态语言 动态语言,是指程序在运行时可以改变其结构:新的函数可以引进,已有的函数可以被删除等结构上的变化.比如常见 ...
- 反射 字段_详解面试中常考的 Java 反射机制
反射(Reflection) 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说"自审",并能直接操作程序的内部属性和方法. 反射是一项高级 ...
- java初反射_初始 java 反射机制 (一)
反射机制详解 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为j ...
- 初识java反射机制
这篇小博客有这么些内容~认识何使用java反射机制的心路历程 什么是java反射机制呢?什么时候会用到java反射机制呢?怎么使用java反射机制呢? 那我们开始吧~ (一)反射机制(Reflecti ...
- 浅谈Java反射机制 之 获取类的字节码文件 Class.forName(全路径名) 、getClass()、class...
先贴上Java反射机制的概念: AVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法: 对于任意一个对象,都能够调用它的任意一个方法和属性: 这种动态获取的信息以及动态调用对 ...
- 工作中用到的java反射机制_(转)JAVA-反射机制的使用
Java反射机制的实现原理 反射机制:所谓的反射机制就是java语言在运行时拥有一项自观的能力.通过这种能力可以彻底的了解自身的情况为下一步的动作做准备.下面具体介绍一下java的反射机制.这里你将颠 ...
最新文章
- 【ACM】CODE[VS] 1215 (DFS)
- linux过滤输出内容,Linux内容整理--过滤器、输入输出及管道
- 选择P2P平台的技巧和方法
- 130道ASP.NET面试题
- 【UOJ】67 新年的毒瘤 【BZOJ】1123 BLO
- 【Qt】modbus之串口模式读操作
- 教你怎么在vi和vim上查找字符串
- 跟我一起学.NetCore之选项(Options)核心类型简介
- 掌握了Docker Layer Caching才敢自称精通Dockerfile
- 开源SUP对接API卡盟程序卡信乐v2.0源码
- Salt-Syndic
- 服务器修改域,服务器修改域名
- java读文件指定行开始到文件的最后
- 创造型模式-生成器模式
- 加密、解密、openssl的基本应用以及CA的实现过程
- html amp css设计与构建网站,HTMLCSS设计与构建网站 笔记CSS
- Checker框架学习笔记
- SQL-SELECT 语句,From子句,where条件查询
- 如何将密切好友的微信聊天记录恢复到自己的微信中
- 20172328 2018-2019《Java软件结构与数据结构》第三周学习总结