当前位置:首页 > Java技术 > 【Java编程思想笔记】反射

【Java编程思想笔记】反射

2022年08月04日 21:07:39Java技术4

文章参考:学习网站 how2java.cn

                           参考博客:(敬业的小码哥)https://blog.csdn.net/sinat_38259539/article/details/71799078

                                             (青色的画轴)https://www.cnblogs.com/yrstudy/p/6500982.html

                                             (chris.wu)https://www.cnblogs.com/buoge/p/9285142.html

1.反射的概述

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

       Java反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public、static等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。

 

2.为什么要用反射

        Java中编译类型有两种:

          (1)静态编译:在编译时确定类型,绑定对象,即通过

                                     在你敲代码的时候,就已经确定你要用的是哪个类的对象,new一个出来,使用

          (2)动态编译:运行时确定类型,绑定对象。动态编译最大限度地发挥了Java的灵活性,体现了多态的应用,可以减低类之间的耦合性。

                                      在你运行之前,你只知道你要用的类的名称,而不知道其具体有哪些属性,哪些方法,却可以在运行后操作它

         因此,Reflection可以在运行时加载、探知、使用编译期间完全未知的classes。即Java程序可以加载一个运行时才得知名称的class,获取其完整构造,并生成其对象实体、或对其fields设值、或唤起其methods。

 

       例如:  我们要创造两个类似的类的对象

        传统方法:

interface fruit{
    public abstract void eat();
}

class Apple implements fruit{

    @Override
    public void eat() {
        System.out.println("eat Apple");
    }
}

class Orange implements fruit{

    @Override
    public void eat() {
        System.out.println("eat Orange");
    }
}

class Factory{
    public static fruit getInstance(String fname){
        fruit f = null;
        if(fname.equals("Apple"))
            f = new Apple();
        
        if(fname.equals("Orange"))
            f = new Orange();
        
        return f;
    }
}

因此,当我们有了更多水果时,就需要重写工厂类,来添加更多选择,这不仅是个重复的工作,且代码的耦合度很高。

 

           反射机制:

class Factory{
    public static fruit getInstance(String fname){
        fruit f = null;
        try{
            f=(fruit)Class.forName(fname).newInstance();
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }
        return f;
    }
}

 而使用了反射机制的工厂类,则可以无需修改代码,只要你实现了一个类,应用了fruit接口,就可以用这个工厂类创造水果(实例)。

 

实际上,反射可以做的还有很多,这只是冰山一角。例如在Spring框架中的依赖注入,反转控制等。反射有着十分强大的功能。熟练的使用可以实现非常丰富的功能。

 

3.怎么用反射   

实现Java反射机制的类都位于java.lang.reflect包中:

1、Class类:代表一个类

2、Field类:代表类的成员变量(类的属性)

3、Method类:代表类的方法

4、Constructor类:代表类的构造方法

5、Array类:提供了动态创建数组,以及访问数组的元素的静态方法

 

   (1)Class类: 类对象,当获取到一个类对象后,你就能够进一步获取这个类的更多信息

             获取类对象的三种方法:forName() , ClassName.class  , instance.getClass()   (ClassName指类名称,instance是指一个对象实例)

        String className = "Hero";

        //获取类对象的三种方法
        try{
            Class hClass1 = Class.forName(className);
            Class hClass2 = Hero.class;
            Class hClass3 = new Hero().getClass();
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }

             当我们获取到类对象时,会导致类中的属性被初始化,例如在类中加一个静态代码块,看在获取类时会不会初始化

public class Person {

    private String name;
    private int id;

    static {
        System.out.println("初始化Person类");
    }
}

 

       (2)Constructor类:代表类的构造方法  我们可以用它来获取类的对象

        String className = "ReflectTest.Person";

        //通过Constructor获取一个对象
        try{
            Class hClass1 = Class.forName(className);
            Constructor c = hClass1.getConstructor();
            Person p = (Person)c.newInstance();
            p.setName("bilibili");
            System.out.println(p);
        }catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e){
            e.printStackTrace();
        }

         

        (3)Field类:代表类的成员变量(类的属性)   通过它获取类的变量

try{
            Person p = new Person();
            p.setName("lala");
            p.setId(15);
            p.age=15;

            Class pClass = p.getClass();
            Field f1 = pClass.getDeclaredField("age");

            f1.set(p,15);

            System.out.println(p);

        }catch (NoSuchFieldException | IllegalAccessException e){
            e.printStackTrace();
        }

           这里的age是public的,因此可以直接修改,而对于private修饰的属性,应该如下操作:

            Class pClass = p.getClass();
            
            //获取Person类的所有属性
            Field[] fields = pClass.getDeclaredFields();
            
            //对所有属性设置访问权限
            AccessibleObject.setAccessible(fields,true);

            //对单个属性设置访问权限
            Field f1 = pClass.getDeclaredField("name");
            f1.setAccessible(true);
            
            f1.set(p,"Baolan");

 

        (4)Method类:代表类的方法   通过它可以调用类中的方法

           为此我先在Person类中添加了两个方法

    public void run(){
        System.out.println(name+" is Running");
    }
    private void feel(String f){
System.out.println(name+" is Felling "+f);
}
 
  

          然后我们来通过反射调用

            Class pClass = p.getClass();

            //获取类中叫做run的方法
            Method mrun = pClass.getMethod("run");

            mrun.invoke(p);

         同样的,对于私有的方法,要设置访问权限,同时要注意feel是一个有参数的方法,需要在调用时导入参数

            Class pClass = p.getClass();

            //获取类中叫做feel的方法,并导入其参数的类型
            Method mfeel = pClass.getDeclaredMethod("feel",String.class);
            mfeel.setAccessible(true);
 
            //在使用feel方法时,加入feel方法需要的参数"Good"
            mfeel.invoke(p,"Good");

 

4.测试用例

         这里我们用配置文件来进行两种方法的切换调用

首先我们定义两个类,实现两个不同的方法

public class DoSomething {
    public void doSome1(){
        System.out.println("Do Great");
    }
}
public class DoSomething2 {
    public void doSome2(){
        System.out.println("Do Bad");
    }
}

然后将其中一个的信息保存到一个txt文件中

class=ReflectTest.DoSomething
method=doSome1

然后通过配置文件获取其内容,调用文件中保存的方法

        try{
            //从保存类名称和方法名称的文件中获取信息
            File configfile = new File("D:\\IDEAworkspace\\JavaBasick\\methodtxt.txt");
            Properties config = new Properties();
            config.load(new FileInputStream(configfile));
            String className = (String)config.get("class");
            String methodName = (String)config.get("method");

            //根据类名称获取类对象
            Class dclass = Class.forName(className);
            //根据方法名称获取方法
            Method method = dclass.getMethod(methodName);
            //获取构造器
            Constructor c = dclass.getConstructor();
            //实例化
            Object dosomething = c.newInstance();
            //调用指定方法
            method.invoke(dosomething);
        }catch (Exception e){
            e.printStackTrace();
        }

可以看到,在上面的代码中,我们并没有指出要用什么类,以及什么方法,这些都是只保存在methodtxt文件中的

因此只要我们修改文件中的内容,就可以调用不同类的不同方法了,如

class=ReflectTest.DoSomething2
method=doSome2

 

作者:胡叁安
来源链接:https://www.cnblogs.com/wqq-blog/p/10561956.html

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。


本文链接:https://www.javaclub.cn/java/17447.html

分享给朋友:

“【Java编程思想笔记】反射” 的相关文章

读Java编程思想随笔の数组

  数组与其他种类的容器之间区别有三:效率、类型和保存基本类型的能力。在Java中,数组是一种最高的存储和随机访问对象引用序列的方式。数组就是一个简单的线性序列,这使得元素访问非常快速。但是为这种速度所付出的代价是数组对象的大小被固定,并且在其生命周期中不可改变。你可以能会建议使用Ar...

Java编程思想 4th 第2章 一切都是对象

Java编程思想 4th 第2章 一切都是对象

Java是基于C++的,但Java是一种更纯粹的面向对象程序设计语言,和C++不同的是,Java只支持面向对象编程,因此Java的编程风格也是纯OOP风格的,即一切都是类,所有事情通过类对象协作来完成。 在Java中,使用引用来操纵对象,在Java编程思想的第四版中,使用的术语是...

Java编程思想学习(五)----第5章:初始化与清理

随着计算机革命的发展,“不安全”的编程方式已逐渐成为编程代价高昂的主因之一。 C++引入了构造嚣(constructor)的概念,这是一个在创建对象时被自动调用的特殊方法。Java中也采用了构造器,并额外提供了“垃圾回收器”。对于不再使用的内存资源,垃圾回收器能自动将其释放。...

回顾Java编程思想篇(一)

本文主要介绍Java中对象的理解。 很久以前看过Java编程思想这本书,当时看得不是很懂,重新拿起这本书,感觉非常陌生,于是产生了重新研究的念头,并做一些读书笔记。   一、一切都是对象 1、Java与...

【Java编程思想】8.多态

【Java编程思想】8.多态

在面向对象的程序设计语言中,多态是继数据抽象和继承之后的第三种基本特征。 多态分离了“做什么”和“怎么做”,让接口和实现分离开,改善了代码的可读性和组织结构,创建了可拓展的程序。 封装,通过合并特征和行为来创建新的数据类型。 实现隐藏,通过将细节“私有化”把接口...

Java编程思想读书笔记之内部类

         现在是够懒得了,放假的时候就想把这篇笔记写出来,一直拖到现在,最近在读《Java编程思想》,我想会做不止这一篇笔记,因为之前面试的时候总会问道一些内部类的问题,那这本书的笔记就从内部类开始...

[JAVA]java编程思想-第一章-对象入门

第1章 对象入门 “为什么面向对象的编程会在软件开发领域造成如此震憾的影响?” 面向对象编程(OOP)具有多方面的吸引力。对管理人员,它实现了更快和更廉价的开发与维护过程。对分析与设计人员,建模处理变得更加简单,能生成清晰、易于维护的设计方案。对程序员,对象模...

Java编程思想第四版勘误

  坊间传说这本书翻译得很烂,我倒觉得还好。虽然看原文更准确,但是如果在具备一定编程思维和基础、能够看出来疑问的情况下,还是看中文更快一些,而且这本书本身也不适合初学者看。当然,错误和不通顺还是有的,而且官方和网上居然没有一份公开的勘误表,至少我没有搜到,搜索“Java编程思想第四版勘...

Java编程思想学习(十五) 注解

注解Annotation又叫元数据,是JDK5中引入的一种以通用格式为程序提供配置信息的方式。使用注解Annotation可以使元数据写在程序源码中,使得代码看起来简洁,同时编译器也提供了对注解Annotation的类型检查,使得在编译期间就可以排除语法错误。 1JDK内置的3中...

java异常捕获案例,此题的出处是《Java编程思想》一书

转自:https://blog.csdn.net/jackfrued/article/details/44921941   class Annoyance extends Exception {} class Sneeze extends Annoyan...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。