Java基础反射反射的概述
Java基础-反射-反射的概述
Java工程师知识树 / Java基础
反射(Reflection)的概述反射的由来:加载完类之后,在堆内存的方法区中就会产生一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。我们可以通过这个对象看到这个类的结构,这个对象就像一面镜子,透过这个镜子看到了类的结构,所以,通过这样获取类信息的方式形象的称之为,反射。
Java反射机制就是允许Java程序在运行期间借助Reflection API取得任何类的内部信息,并能直接操作对象的内部属性和方法。
使用反射获取对象以及之后操作的前提条件:必须先得到代表字节码的Class类,Class类用于表示.class文件(字节码)
反射在日常工作中用的倒不是很多,而被广泛应用于框架设计之中,反射是框架设计的灵魂。
反射的优缺点:优点:反射可以实现动态创建对象和编译,体现出很大的灵活性。缺点:使用反射对性能有一定影响。慢与直接创建对象调用方法。
反射使用实例:
public class Test { public static void main(String[] args) throws Exception { long start1 = System.currentTimeMillis(); User user = new User(); for (int i = 0; i < 1000000; i++) { user.getName(); } long end1 = System.currentTimeMillis(); System.out.println("普通方式执行:" + (end1 - start1) + "ms"); long start2 = System.currentTimeMillis(); Class userClass = user.getClass(); Method getName = userClass.getDeclaredMethod("getName", null); for (int i = 0; i < 10000000; i++) { getName.invoke(user, null); } long end2 = System.currentTimeMillis(); System.out.println("反射方式执行:" + (end2 - start2) + "ms"); long start3 = System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) { getName.invoke(user, null); } long end3 = System.currentTimeMillis(); System.out.println("反射方式关闭检测执行:" + (end3 - start3) + "ms"); }}class User { private String name; public void getName() { }}
获得Class类的方式如果已有具体的类,通过类的class属性获取,最为安全可靠且性能最高的方法。(Class xxx=XXX.class;)已知某个类的实例,调用此实例的getClass()方法获取Class对象。(Class xxx=xxx1.getClass();)已知一个类的全名且在类路径下,可以通过Class类的静态方法forName()获取,需要处理异常ClassNotFoundException(Class xxx=ClassforName(“yyy.XXX”);)内置基本数据类型可以直接使用类名.Type还可以用ClassLoader
public class TestReflection { public static void main(String[] args) throws ClassNotFoundException { //获取Class对象 Student student = new Student(); //Class xxx=XXX.class Class aClass = Student.class; //Class xxx=xxx1.getClass(); Class bClass = student.getClass(); //Class xxx=ClassforName(“yyy.XXX”); Class cClass = Class.forName("com.wechat.management.reflection.Student"); //.Type Class integerClass = Integer.TYPE; Class intClass = int.class; //ClassLoader ClassLoader loader = ClassLoader.getSystemClassLoader();//获取加载器对象 Class classString = loader.loadClass("java.lang.String"); Class dClass = loader.loadClass("com.wechat.management.reflection.Student"); System.out.println(aClass.hashCode()); System.out.println(bClass.hashCode()); System.out.println(cClass.hashCode()); System.out.println(dClass.hashCode()); }}class Student{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; }}
在运行期间,一个类,只有一个Class对象产生。
反射最常用的方式为
Class xxx=ClassforName(“yyy.XXX”)
。
Class xxx=XXX.class
对象都有了还要反射干什么。
Class xxx=xxx1.getClass()
需要导入类的包,依赖太强,不导包就抛编译错误。一般使用
Class xxx=ClassforName(“yyy.XXX”)
,参数可以传入也可写在配置文件中。
Class类的常用方法类的构造方法:Class类提供了用于获取某个类的构造方法。
Constructor getConstructor(Class<?>... parameterTypes) 根据构造函数的参数,返回一个具体的具有public属性的构造函数Constructor getConstructors() 返回所有具有public属性的构造函数数组Constructor getDeclaredConstructor(Class<?>... parameterTypes) 根据构造函数的参数,返回一个具体的构造函数(不分public和非public属性)Constructor getDeclaredConstructors() 返回该类中所有的构造函数数组(不分public和非public属性)
类的属性:Class类提供了获取成员属性的方法
Field getField(String name) 根据变量名,返回一个具体的具有public属性的成员变量Field[] getFields() 返回具有public属性的成员变量的数组Field getDeclaredField(String name) 根据变量名,返回一个成员变量(不分public和非public属性)Field[] getDelcaredFields() 返回所有成员变量组成的数组(不分public和非public属性)
类的方法:Class类提供了获取成员方法的方法
Method getMethod(String name, Class<?>... parameterTypes) 根据方法名和参数,返回一个具体的具有public属性的方法Method[] getMethods() 返回所有具有public属性的方法数组Method getDeclaredMethod(String name, Class<?>... parameterTypes) 根据方法名和参数,返回一个具体的方法(不分public和非public属性)Method[] getDeclaredMethods() 返回该类中的所有的方法数组(不分public和非public属性)
哪些类型可以有Class对象class:外部类、成员(成员内部类、静态内部类),局部内部类,匿名内部类。interface:接口[]:数组enum:枚举annotation:注解primitive type:基本数据类型void.....
public class Test5 { public static void main(String[] args) { Class c1= Object.class;//类 Class c2= Runnable.class;//接口 Class c3= String[].class;//一维二维数组 Class c4= int[][].class;//基本数据类型数组 Class c5= Override.class;//注解 Class c6= ElementType.class;//枚举 Class c7= Integer.class;//基本数据类型 Class c8= void.class;//void Class c9= Class.class;//Class }}
setAccessiblesetAccessible为启动和禁用安全检查的开关,为了安全默认为false (启动)
setAccessible启动与关闭测试:
package com.wechat.management.reflection;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class TestSetAccessible { /** * 测试方法 */ public String getName() { return "test"; } //普通方式调用 public static void test01() { TestSetAccessible user = new TestSetAccessible(); //开始时间 long starTime = System.currentTimeMillis(); //模拟10亿次不断获取名字所需要的时间 for (int i = 0; i < 1000000000; i++) { user.getName(); } //结束时间 long endTime = System.currentTimeMillis(); System.out.println("普通方式执行10亿次:" + (endTime - starTime) + "ms"); } //反射方式调用 public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { TestSetAccessible user = new TestSetAccessible(); Class c1 = user.getClass(); //获取指定方法 Method getName = c1.getDeclaredMethod("getName", null); getName.setAccessible(false);//false为开启检测 默认为也是false,为了安全 //开始时间 long starTime = System.currentTimeMillis(); //模拟10亿次不断获取名字所需要的时间 for (int i = 0; i < 1000000000; i++) { getName.invoke(user, null); } //结束时间 long endTime = System.currentTimeMillis(); System.out.println("反射方式执行10亿次:" + (endTime - starTime) + "ms"); } //反射方式调用 关闭检测 public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { TestSetAccessible user = new TestSetAccessible(); Class c1 = user.getClass(); //获取指定方法 Method getName = c1.getDeclaredMethod("getName", null); getName.setAccessible(true);//true为关闭检测 //开始时间 long starTime = System.currentTimeMillis(); //模拟10亿次不断获取名字所需要的时间 for (int i = 0; i < 1000000000; i++) { getName.invoke(user, null); } //结束时间 long endTime = System.currentTimeMillis(); System.out.println("关闭检测执行10亿次:" + (endTime - starTime) + "ms"); } public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { test01();//普通方式执行10亿次:3ms test02();//反射方式执行10亿次:3226ms test03();//关闭检测执行10亿次:2011ms //如果反射调用次数多的话,可以关闭这个检测 提高程序的一个效率 }}
Java学习教程:Java基础——反射
什么是反射?
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
例如:我们在开发的过程当中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法。
反射的常用类和函数
Java反射机制的实现要借助于4个类:Class,Constructor,Field,Method;其中class代表的是类对象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象,通过这四个对象我们可以粗略的看到一个类的各个组成部分。其中最核心的就是Class类,它是实现反射的基础,它包含的方法我们在第一部分已经进行了基本的阐述。
类的加载
说到反射就不得不说到类的加载
当程序主动使用某个类时,如果该类还没有被加载到内存中,则系统会通过加载、连接、初始化这三个步骤对该类进行初始化。有时会把这一整个流程统称为类加载或类初始化。类加载指的是将类的class文件读入内存中,并为之创建一个 java.lang.Class对象,也就是说程序使用任何类的时候,都会为其创建一个class对象。
类加载器
类加载器负责将.class文件加载到内存中,并为之生成对应的Class对象。类加载器负责加载所有的类,系统为所有加载到内存中的类生成一个java.lang.Class 的实例。
类加载器的组成:Bootstrap ClassLoader 根类加载器 : 也被称为引导类加载器,负责Java核心类的加载,比如System类,在JDK中JRE的lib目录下rt.jar文件中的类Extension ClassLoader 扩展类加载器 : 负责JRE的扩展目录中jar包的加载,在JDK中JRE的lib目录下ext目录System ClassLoader 系统类加载器 : 负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径,主要是我们开发者自己写的类
发表评论