Java基础之反射详解

前言

反射是我们框架的灵魂,反射也是我们框架的一个底层基石,没有反射也就没有框架,如果我们学好了反射,对我们阅读框架底层是有很大班助的——阿俊。有些文章上来就讲反射,就会很懵逼,不知道是干啥的,所以我们就引出一些问题来看看为什么需要反射

一、一个需求引出反射

看下面的问题
根据配置文件reflection.properties指定信息,创建People对象并调用方法hi

classullpath= com.reflection.People
method=hi

思考:使用现有技术,能做吗?
我们可以来试一试
我们根据要求创建出两个类和一个配置文件

People 类

public class People {
    private String name="zlj";
    public void hi(){
        System.out.println("hi"+name);
    }
}
classullpath= com.reflection.People
method=hi

在QuestionReflectionQuestion类中进行测试,我们学Java的时候可知,可以通过如下的方法创建People对象并调用方法hi

public class QuestionReflectionQuestion {
    public static void main(String[] args) {
            //传统方式
        People people = new People();
        people.hi();
    }
}

那我们如何通过配置文件reflection.properties指定信息,创建People对象并调用方法hi呢?

注意:这样的需求在学习框架时特别多,即通过外部文件配置,在不修改源码情况下,来控制程序,也符合设计模式的ocp原则(开闭原则:不修改源码来扩展功能)

尝试1:Java中有一个Properties类,可以读写配置文件,我们可以用它进行尝试

public class QuestionReflectionQuestion {
    public static void main(String[] args) throws IOException {
        //我们尝试做一下-》明白反射
        //Java中有一个Properties类,可以读写配置文件,我们可以用它进行尝试
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\reflection.properties"));
        String classullpath = properties.get("classullpath").toString();//classullpath:com.reflection.People
        String method = properties.get("method").toString();//method:hi
        System.out.println("classullpath:"+classullpath);
        System.out.println("method:"+method);
        //那我们可以不可以直接使用new classullpath();来创建呢?这样显然不行的
    }
}

结论:尝试失败,我们就可以使用反射机制来解决上述:通过配置文件reflection.properties指定信息,创建People对象并调用方法hi,下一节进行代码演示

二、反射入门

解决第一节问题的代码演示

分四个步骤:

1:加载类,返回class类型对象:cls
2:通过cls得到你的加载类com.reflection.People的对象实例
3.通过cls得到你加载的类com.reflection.People的method=hi的方法对象(即:在反射中,可以把方法视为对象(即:万物皆对象))
4.通过method调用方法:即通过方法对象来实现调用方法

public class QuestionReflectionQuestion {
    public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\reflection.properties"));
        String classullpath = properties.get("classullpath").toString();//classullpath:com.reflection.People
        String methodName = properties.get("method").toString();//method:hi
        System.out.println("====使用反射机制解决=====");
        //1:加载类,返回class类型对象:cls
        Class cls = Class.forName(classullpath);
        //2:通过cls得到你的加载类com.reflection.People的对象实例
        Object o = cls.newInstance();
        System.out.println("o的运行类型="+o.getClass());//运行类型
        //3.通过cls得到你加载的类com.reflection.People的method=hi的方法对象
        //即:在反射中,可以把方法视为对象(即:万物皆对象)
        Method method = cls.getMethod(methodName);
        //4.通过method调用方法:即通过方法对象来实现调用方法
        method.invoke(o);//传统方法:对象.方法()    反射机制 方法.invoke(对象)
    }
}
====使用反射机制解决=====
o的运行类型=class com.reflection.People
hizlj

我们先知道一下反射实现方式的步骤即可,一些类的介绍,我们后续会进行介绍

如果Java没有反射机制,Java就不是一种动态语言,而且我们所说的spring mybatis 框架就都不存在了,反射机制是框架的灵魂,也是底层机制的基石

反射机制的牛逼之处就在于:可以通过外部文件配置,在不修改源码的情况下,来控制程序(这就是开闭原则)
比如,我们在People类中新增cry方法,我们就不需要在QuestionReflectionQuestion类中新增 people.cry();这个方法,只需要在配置文件中reflection.properties进行如下修改method=cry即可。

====使用反射机制解决=====
o的运行类型=class com.reflection.People
cryzlj

三、反射原理图

前面我们对反射进行了一个快速入门,接下来,我们来介绍一下它的原理

反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到

加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象) ,这个对象包含了类的完整结构信息。通过这个Class对象得到类的结构。这个对象就像一面镜子, 透过这个镜子看到类的结构,所以,形象的称之为反射。

我们可以拿第一节的例子,画图来说明

四、反射相关类

接下来讲完反射机制原理,我们就来看一下反射机制可以做那些事情

1.在运行时判断任意一个对象所属的类

2.在运行时构造任意一个类的对象

3.在运行时得到任意一个类所具有的成员变量和方法

4.在运行时调用任意一个对象的成员变量和方法

5.生成动态代理

反射相关的主要类:

1.java.lang.Class:代表个类, Class对象表示某 个类加载后在堆中的对象

2.java.lang.reflect.Method:代表类的方法

3.java.lang.reflect.Field: 代表类的成员变量

4.java.lang.reflect.Constructor:代表类的构造方法

我们上面第二节介绍了Method演示,我们接下来进行Field和Constructor演示
People.java

public class People {
    public String name="zlj";
    public People(){
        this.name="zzg";
    }
    public People(String name){
        this.name=name;
    }
    public void hi(){
        System.out.println("hi"+name);
    }
    public void cry(){
        System.out.println("cry"+name);
    }
}

QuestionReflectionQuestion.java

public class QuestionReflectionQuestion {
    public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\reflection.properties"));
        String classullpath = properties.get("classullpath").toString();//classullpath:com.reflection.People
        String methodName = properties.get("method").toString();//method:hi
        String fieldName = properties.get("field").toString();
        String constructorName = properties.get("constructor").toString();
        System.out.println("====使用反射机制解决=====");
        //1:加载类,返回class类型对象:cls
        Class cls = Class.forName(classullpath);
        //2:通过cls得到你的加载类com.reflection.People的对象实例
        Object o = cls.newInstance();
        System.out.println("o的运行类型="+o.getClass());//运行类型
        //3.通过cls得到你加载的类com.reflection.Field 的field=name的字段
        //即:在反射中,可以把方法视为对象(即:万物皆对象)
        //getField不可以得到私有属性
        Field field = cls.getField(fieldName);
        //4.通过field 调用方法:即通过方法对象来实现调用方法
        //因为对象赋了初始值;所以就是zzg,而不是zlj
        System.out.println(field.get(o));
        System.out.println("People类的字段name是否为zlj:"+field.equals("zlj"));
        //构造器的3,4和Field 一样
        Constructor constructors = cls.getConstructor();//()中可以指定构造器参数类型。默认返回无参构造器
        System.out.println(constructors);
        Constructor constructor = cls.getConstructor(String.class);//传入构造参数的类型对象
        System.out.println(constructor);
    }
}

reflection.properties

classullpath= com.reflection.People
method=cry
field=name
constructor=People

演示

====使用反射机制解决=====
o的运行类型=class com.reflection.People
People类的字段name是否为zlj:false
public com.reflection.People()
public com.reflection.People(java.lang.String)

五、反射调用优化

前面我们说了反射的原理和反射的作用,接下来我们就说一下它的优缺点

反射优点和缺点

优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活没有反射机制,框架技术就失去底层支撑。

缺点:使用反射基本是解释执行,对执行速度有影响。

基于缺点,我们可以进行反射调用优化。
我们先看一下传统方法调用和反射机制调用的耗时

public class ReflectionOptimize {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        ReflectionOptimize.m1();
        ReflectionOptimize.m2();
    }
    //传统方法调用hi
    public static void m1(){
        People people = new People();
        long start = System.currentTimeMillis();
        for (int i=0;i<900000;i++){
            people.hi();
        }
        long end = System.currentTimeMillis();
        System.out.println("传统方法调用hi耗时:"+(end-start));
    }
    //反射机制调用hi
    public static void m2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class<?> cls = Class.forName("com.reflection.People");
        Object o = cls.newInstance();
       Method method = cls.getMethod("hi");
12
        long start = System.currentTimeMillis();
        for (int i=0;i<900000;i++){
           method.invoke(o);
        }
        long end = System.currentTimeMillis();
        System.out.println("反射机制调用hi耗时:"+(end-start));
    }
}
传统方法调用hi耗时:4
反射机制调用hi耗时:19

结论:使用反射机制调用方法耗时更长
我们可以进行如下优化

反射调用优化关闭访问检查

1.Method和Field、 Constructor对象都有setAccessible()方法

2.setAccessible作用是启动和禁用访问安全检查的开关

3.参数值为true表示 反射的对象在使用时取消访问检查,提高反射的效率。参数值为false则表示反射的对象执行访问检查

代码第12行加入method.setAccessible(true);//反射的对象在使用时取消访问检查,提高反射的效率
代码效果演示

传统方法调用hi耗时:3
反射机制调用hi耗时:16

到此这篇关于Java基础之反射详解的文章就介绍到这了,更多相关Java反射内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java反射之Method的invoke方法实现教程详解

    前言 在框架中经常会会用到method.invoke()方法,用来执行某个的对象的目标方法.以前写代码用到反射时,总是获取先获取Method,然后传入对应的Class实例对象执行方法.然而前段时间研究invoke方法时,发现invoke方法居然包含多态的特性,这是以前没有考虑过的一个问题.那么Method.invoke()方法的执行过程是怎么实现的?它的多态又是如何实现的呢? 本文将从java和JVM的源码实现深入探讨invoke方法的实现过程. 首先给出invoke方法多态特性的演示代码: p

  • Java反射,泛型在Json中的运用

    最近项目中遇到了Json数据自动获取的功能,不然令人想起java的反射,已经很长时间没复习java了正好一块连java的这一块内容一起过一遍.java中的反射无疑就相当于java开发者的春天,在众多的框架中也能看到它的身影,可以在运行时检查类,接口.变量和方法等信息,可以实例化调用方法以及设置变量值等.本文主要以代码的形式直接将反射,泛型的运用展现出来. java中的反射 首先新建一个基础类Author. package bean; /** * * @author Super~me * Desc

  • Java 反射修改类的常量值、静态变量值、属性值实例详解

    前言 有的时候,我们需要修改一个变量的值,但变量也许存在于 Jar 包中或其他位置,导致我们不能从代码层面进行修改,于是我们就用到了下面的场景,通过反射来进行修改变量的值. 定义一个实体类 class Bean{ private static final Integer INT_VALUE = 100; } 利用反射修改私有静态常量方法 System.out.println(Bean.INT_VALUE); Field field = Bean.class.getField("INT_VALUE

  • java 利用反射获取内部类静态成员变量的值操作

    昨晚,一同事问到我,怎么利用java反射解析内部类静态成员变量的值,于是顺手写下了. 废话不多说,直接上代码! 待解析类结构如下: /** * @Author changle * @Time 17/6/13. * @Desc to do */ public class Goods { static class apple{ public static String version = "iphone6s[是手机不是吃的苹果]"; public static String date =

  • Java 使用反射调用jar包中的类方式

    下面讲展示的是从image.jar包中调用image.Buddy类的方法. public class Main { public static void main(String[] args) { try { // 两种方式都可以 URL url = new File("/Users/wuchen/Documents/IntelliJIDEA/Applet/out/production/Applet/image.jar").toURI().toURL(); // URL url = n

  • JAVA基础之注解与反射的使用方法和场景

    注解 注解定义 Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制. Java 语言中的类.方法.变量.参数和包等都可以被标注.和注释不同,Java 标注可以通过反射获取标注内容.在编译器生成类文件时,标注可以被嵌入到字节码中.Java 虚拟机可以保留标注内容,在运行 时可以获取到标注内容 . 当然它也支持自定义 Java 标注. 注解与注释的区别:注解是给机器看的注释,而注释是给程序员看的提示,编译时自动忽略注释. 使用场景 编译格式检查 反射中解

  • Java中反射机制和作用详解

    前言 很多刚学Java反射的同学可能对反射技术一头雾水,为什么要学习反射,学习反射有什么作用,不用反射,通过new也能创建用户对象. 那么接下来大师就带你们了解一下反射是什么,为什么要学习反射? 下面我们首先通过一个实例来说明反射的好处: 方法1.不用反射技术,创建用户对象,调用sayHello方法 1.1 我们首先创建一个User类 package com.dashi; /** * Author:Java大师 * User对象,包含用户的id和姓名以及sayHello方法 */ public

  • java反射机制的一些学习心得小结

    概述 之前在了解Spring的类加载机制的时候,了解了java的反射机制.但是,我对反射理解一直不深.也一直有点疑惑:Spring为什么利用反射创建对象?直接new对象和依靠反射创建对象有什么区别?什么是动态加载类? 什么是反射? 要想知道反射到底是什么,首先需要知道java的类加载和对象创建的机制. 当我们写完一个java文件的时候,后缀是.java.在我们利用IDE执行java文件的时候,其实IDE也帮我们运行了javac,即java编译器.编译器会将.java文件编译成.class文件.j

  • 如何用Java注解和反射实现依赖注入

    概述 在Spring中,我们可以通过 @Autowired注解的方式为一个方法中注入参数,那么这种方法背后到底发生了什么呢,这篇文章将讲述如何用Java的注解和反射实现一个"低配版"的依赖注入. 下面是我们要做的一些事情: 通过 @interface的方式定义一个注解 为某个希望杯被注入的方法添加这个注解 编写测试代码,通过反射获取添加了注解的方法对应的Method对象,将该方法对象设置为可访问的,通过反射创建对象并调用这个方法,同时注入依赖数据 如上所述,我们分为三个步骤, 去加工出

  • java反射方式创建代码详解

    在谈到实例的时候,很多人对这个概念还不能说出所以然.其实实例就是一个具体的对象,像我们之前学习的类.数组都可以创建实例.反射相对而言也是比较抽象的概念,所以我们是能够把它实例化的.下面简单对实例进行了解,然后分别带来无参和有参的反射实例实例化方法. 1.实例说明 new 一个对象是实例,可以把这个new出来的对象叫做实例,说白了就是这个new出来的"东西",叫它对象也可以,叫它实例也可以,对象和实例在这个角度上来讲是等价的. 2.创建空参的实例 使用Class对象的newInstanc

  • java高级用法之注解和反射讲义

    前言 反射和注解在java中偏高级用法,一般在各种框架中被广泛应用,文章简单介绍下反射和注解的用法,希望对你的工作学习有一定帮助 java注解 什么是注解 Java 注解也就是Annotation是从 Java5 开始引入的新技术 Annotation的作用: 不是程序本身,可以对程序作出解释 可以被其他程序(编译器等)读取 Annotation的格式: 注解以@注释名在代码中存在的,可以添加一些数值,例如SuppressWarnings(value="unchecked") Anno

  • java 非常好用的反射框架Reflections介绍

    Reflections通过扫描classpath,索引元数据,并且允许在运行时查询这些元数据. 使用Reflections可以很轻松的获取以下元数据信息: 1)获取某个类型的所有子类:比如,有一个父类是TestInterface,可以获取到TestInterface的所有子类. 2)获取某个注解的所有类型/字段变量,支持注解参数匹配. 3)使用正则表达式获取所有匹配的资源文件 4)获取特定签名方法. 通常的用法有: 引入依赖jar <dependency> <groupId>org

  • Java中的注解和反射实例详解

    一.注解 注解(Annotation): 从jdk5.0开始引进,可以对程序进行解释或被其他程序读取. 注解格式:"@注释名",并可以添加一些参数. 例:@MyAnnotation(value='value') 1.内置注解 @override: 用于修饰方法,表示该方法声明是重写或实现一个父类的方法 @Deprecated: 用于修饰方法.属性.类,表示已过时不建议使用的 @SuppressWarnings: 用于抑制编译时的警告信息 2.元注解 作用:用于注解其他注解 @Targe

  • Java利用反射实现文件的读取操作

    java反射 java从很早的版本开始就引入了反射机制,java如今的框架底层大部分也都是使用反射实现的. 这篇博客就去探索下java反射使用的方便之处. 要说java的反射机制,肯定离不开Class这个类,我们从jdk的源码可以看到这个类在jdk1.0的时候就存在了. 由于我这边需要用到文件读写的功能,同时又希望写的方法相对来说比较抽象,能在多出直接使用,于是我就想到了java的反射机制. 首先这边先把我的读取文件的方法展示出来 这个是用到的接口类 /** * 实现该接口中的方法,本来打算在F

  • java 实现反射 json动态转实体类--fastjson

    我就废话不多说了,大家还是直接看代码吧~ package test.refect; public class Student { // 姓名 private String name; // 年龄 private String age; // 住址 private String address; public String getName() { return name; } public void setName(String name) { this.name = name; } public

  • java反射获取包下所有类的操作

    我就废话不多说了,大家还是直接看代码吧~ public static void main(String[] args) { try { // 获取包名下所有类 Set<Class<?>> classes = getClasses("com"); for(Class c:classes){ // 打印有RestController 的类 if(c.isAnnotationPresent(RestController.class)){ System.out.prin

  • Java进阶知识之反射的概念与获取方法

    一.反射的基本概念 1.反射的概念 将类的各个组成部分封装成其他对象,这就是反射的机制. 通过上图,我们可以通过反射获得Person类的Class对象,通过获得Class对象来获得其中的成员变量,构造方法和成员方法,这个也是我们使用反射的目的. 2.使用反射的好处 可以在程序的运行过程中操作这些对象,获得类对象的属性,方法等. 可以解耦,以此来提高程序的可扩展性 3.补充 反射:框架设计的灵魂,反射是框架设计的关键点 那么知道了反射,框架又是什么呢 框架:半成品软件,我们在开发的过程中可以在框架

  • Java反射 Field类的使用全方位解析

    Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限.反射的字段可能是一个类(静态)字段或实例字段. Field 成员变量的介绍 每个成员变量有类型和值. java.lang.reflect.Field 为我们提供了获取当前对象的成员变量的类型,和重新设值的方法. 获取变量的类型 类中的变量分为两种类型:基本类型和引用类型: 基本类型( 8 种) 整数:byte, short, int, long 浮点数:float, double 字符:char 布尔值:boolean 引用类

随机推荐