文章参考:学习网站 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

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

  1. Java编程思想 笔记

    date: 2019-09-06 15:10:00 updated: 2019-09-24 08:30:00 Java编程思想 笔记 1. 四类访问权限修饰词 \ 类内部 本包 子类 其他包 publ ...

  2. java编程思想笔记(1)

    java编程思想笔记(1) 一,对象的创建和生命周期 对象的数据位于何处?怎样控制对象的生命周期? 在堆(heap)的内存池中动态地创建对象. java完全采用了动态内存分配方式. 二,垃圾回收器 自 ...

  3. #Java编程思想笔记(一)——static

    Java编程思想笔记(一)--static 看<Java编程思想>已经有一段时间了,一直以来都把笔记做在印象笔记上,今天开始写博客来记录. 第一篇笔记来写static关键字. static ...

  4. 2.1(java编程思想笔记)位移操作

    java位移操作主要有两种: 有符号位移:有符号位移会保留原有数字正负性,即正数依然是正数,负数依然是负数. 有符号位左移时,低位补0. 有符号右移时:当数字为正数,高位补0.当数字为负时高位补1. ...

  5. 7.JAVA编程思想笔记隐藏实施过程

    欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/51040237 "进行面向对象的设计时,一项主要的考虑是:怎样将发生变 ...

  6. java编程思想笔记(第一章)

    Alan Kay 第一个定义了面向对象的语言 1.万物皆对象 2.程序是对象的集合,他们彼此通过发送消息来调用对方. 3.每个对象都拥有由其他对象所构成的存储 4.每个对象都拥有其类型(TYpe) 5 ...

  7. java编程思想笔记(一)——面向对象导论

    1.1 抽象过程 1.所有编程语言都提供抽象编程机制. 2.人们所能够解决的问题的复杂性直接取决于抽象的类型(所抽象的是什么)和质量. 3."命令式"语言(basic,c等)都是对 ...

  8. 【Java编程思想笔记】注解--元注解

    参考文章:(小白的小小白的白 )https://blog.csdn.net/weixin_42315600/article/details/80630669 https://www.cnblogs.c ...

  9. 【Java编程思想笔记】注解1-简单了解注解

    文章参考:https://www.cnblogs.com/xuningchuanblogs/p/7763225.html https://www.cnblogs.com/xdp-gacl/p/3622 ...

随机推荐

  1. JetBrains 全套激活 Pycharm Clion 高校学生老师免费用

    https://www.jetbrains.com/store/?fromMenu#edition=discounts https://www.jetbrains.com/zh/student/ 用高 ...

  2. SaaS服务和个性化需求,就不能鱼和熊掌兼得吗?

    随时随地.轻松高效,移动工作让人类的自由度最大化.但企业的移动化过程却不轻松:要综合考虑销售.产品.客服.市场销售.人力资源等错综复杂的流程和需求,以及原有IT系统.数据信息的对接. 千企千面,很难有 ...

  3. SkylineGlobe 7.0.1 & 7.0.2版本Web开发 如何实现对三维模型和地形的剖切展示

    现在很多三维项目中,不仅仅要用到三维地形,正射影像和矢量数据,还会融合到各种三维模型,包括传统的3DMax手工建模,BIM,倾斜摄影自动建模,激光点云模型,三维地质体模型等等. 三维平台首先要做的是把 ...

  4. Foundation框架 - 结构体

    一.基础知识 如果要想使用 Foundation 框架的数据类型,那么包含它的主头文件就可以了.即 #import <Foundation/Foundation.h> 补充: Core F ...

  5. 微信小程序:动画(Animation)

    简单总结一下微信动画的实现及执行步骤. 一.实现方式 官方文档是这样说的:①创建一个动画实例 animation.②调用实例的方法来描述动画.③最后通过动画实例的 export 方法导出动画数据传递给 ...

  6. hdu-1052(贪心)

    链接 [https://vjudge.net/contest/261555#problem/I] 题意 就是两个人都有n匹马,每只马都有战力 第二个人出马的顺序是战力大到小,请问第一个人采取怎样的策略 ...

  7. 解决Jenkins邮件配置问题

    最近要配置Jenkins邮箱,由于一直报如下错误,又没办法解决,所以想到了另外的办法发邮件. 我采用shell脚本执行python命令的方式来发邮件: #!/bin/bash cd /software ...

  8. 神经网路-SGD-1

    SGD神经网络以及python中实现 1.SGD(stochastic gradient descend):<1>数据抽取:<2>计算梯度;<3>参数更新:< ...

  9. centos7之sed和awk常用

    sed是一种流编辑器,它是文本处理中非常中的工具,能够完美的配合正则表达式使用,功能不同凡响.处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令 ...

  10. Python——设计模式——单例模式

    一个类始终只有一个实例 当你第一次实例化这个类的时候,就创建一个实例化得对象 当你之后再来实例化的时候,就用之前创建的对象 class A: __instance = False def __ini_ ...