当前位置:首页 > 分类119 > 正文

Java基础反射反射的概述

摘要: Java基础反射反射的概述Java基础-反射-反射的概述Java工程师知识树/Java基础反射(Reflection)的概述反射...
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包和类路径,主要是我们开发者自己写的类

发表评论