博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java反射机制
阅读量:6332 次
发布时间:2019-06-22

本文共 6327 字,大约阅读时间需要 21 分钟。

一、什么是反射?

在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有),这种动态获取的信息,及调用对象的方法的功能就称为Java的反射机制。

二、获取类对象

1、什么是类对象?

  创建Dog类和Cat类

public class Dog {    private String name;    private int age;    public Dog() {    }    public Dog(String name, int age) {        this.name = name;        this.age = age;    }        /*getter and setter*/}
public class Cat {    private String name;    private String hobby;    /*getter and setter*/}

  实例化两个Dog类的对象

Dog dog1 = new Dog("大黄", 5);Dog dog2 = new Dog("小黑", 3);

在理解类对象之前,先说我们熟悉的对象之间的区别:

       dog1和dog2都是Dog对象,他们的区别在于,各自有不同的名称、年龄

然后说说类之间的区别

  Dog和Cat都是类,他们的区别在于有不同的方法,不同的属性

类对象,就是描述一个类都有什么属性,什么方法的。所有的类,都存在一个类对象,这个类对象用于提供类本身的信息.

2、获取类对象的三种方式

   1. Class.forName

   2. Dog.class
   3. new Dog().getClass()

try {            Class class1 = Class.forName("yingshe.Dog");            System.out.println(class1);            Class class2 = Dog.class;            System.out.println(class2);            Class class3 = new Dog().getClass();            System.out.println(class3);            System.out.println(class1 == class2);            System.out.println(class1 == class3);        } catch (ClassNotFoundException e) {            e.printStackTrace();        }

执行结果

  在一个JVM中,一种类,只会有一个类对象存在。所以以上三种方式取出来的类对象,都是一样的。

3、获取类对象的时候会导致类属性被初始化

  Dog类加上代码

static String msg;    static {        System.out.println("初始化msg");        msg="被初始化了";    }

  获取类对象

  无论什么途径获取类对象,都会导致静态属性被初始化,而且只会执行一次。(除了直接使用 Class c = Hero.class 这种方式,这种方式不会导致静态属性被初始化)

 

三、创建对象

  与传统的通过new 来获取对象的方式不同,反射机制,会先拿到Hero的“类对象”,然后通过类对象直接创建对象或获取“构造器对象” ,再通过构造器对象创建一个对象

   T newInstance()

    创建由此 类对象表示的类的新实例。

  Constructor getConstructor()

    返回一个 Constructor对象

import java.lang.reflect.Constructor;public class Test2 {    public static void main(String[] args) {        //获取类对象        Class classDog = Dog.class;        try {            //用类对象直接创建            Dog dog1 = (Dog)classDog.newInstance();            dog1.setName("大黄");            dog1.setAge(5);            System.out.println(dog1);            //获取构造器再创建            //构造器            Constructor constructor = classDog.getConstructor();            //通过构造器实例化            Dog dog2 = (Dog) constructor.newInstance();            dog2.setName("小黑");            dog2.setAge(4);            System.out.println(dog2);        } catch (Exception e) {            e.printStackTrace();        }    }}

四、访问属性

 为了访问属性,将name修改为public属性

对于private修饰的成员,需要使用setAccessible(true)才能访问和修改。

通过反射修改属性值

import java.lang.reflect.Field;public class Test3 {    public static void main(String[] args){        Dog dog =new Dog();        //使用传统方式修改name的值为大黄        dog.name = "大黄";        System.out.println(dog.name);        try {            //获取类Dog的名字叫做name的字段            Field f1= dog.getClass().getDeclaredField("name");            //修改这个字段的值            f1.set(dog, "小黑");            //打印被修改后的值            System.out.println(dog.name);        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}

五、部分函数

1、Field[] getFields()

  返回包含一个数组 Field对象反射由此表示的类或接口的所有可访问的公共字段、类对象。
2、Field[] getDeclaredFields()
  动态的返回的数组 Field对象反映此表示的类或接口声明的所有字段 类对象

增加Dog属性

public class Dog {    public String name;  //public    private int age;  private    String health;   //默认    protected int weigth;  //protected    //其他函数}
import java.lang.reflect.Field;public class Test4 {    public static void main(String[] args){        Class classDog=Dog.class;        Field[] fields1 = classDog.getFields();        System.out.println("类的public属性");        for (Field f : fields1){            System.out.println(f.getName());        }        Field[] fields2 = classDog.getDeclaredFields();        System.out.println("类的所有属性");        for (Field f : fields2){            System.out.println(f.getName());        }    }}

执行结果

3、Method[] getMethods()

  返回包含一个数组 方法对象反射由此表示的类或接口的所有公共方法 类对象,包括那些由类或接口和那些从超类和超接口继承的声明。

4、Method[] getDeclaredMethods()
  返回包含一个数组 方法对象反射的类或接口的所有声明的方法,通过此表示 类对象,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法。

5、Object invoke(Object obj, Object… args)

  在具有指定参数的 方法对象上调用此 方法对象表示的底层方法

例如:取得setName方法映射给method,method调用invoke函数第一个对象为操作对象,第二个参数为参数(可以是数组)

import java.lang.reflect.Method;public class Test5 {    public static void main(String[] args) {        Class classDog = Dog.class;        try {            Dog dog = (Dog) classDog.newInstance();            Method method = classDog.getMethod("setName", String.class);            method.invoke(dog, "名字");            System.out.println(dog.name);        } catch (Exception e) {            e.printStackTrace();        }    }}

六、反射有什么用?

1、首先准备两个业务类,这两个业务类很简单,就是各自都有一个业务方法,分别打印不同的字符串

package reflection; public class Service1 {     public void doService1(){        System.out.println("业务方法1");    }}
package reflection; public class Service2 {     public void doService2(){        System.out.println("业务方法2");    }}

2、非反射方式

当需要从第一个业务方法切换到第二个业务方法的时候,使用非反射方式,必须修改代码,并且重新编译运行,才可以达到效果

package reflection; public class Test {     public static void main(String[] args) {//      new Service1().doService1();        new Service2().doService2();    }}

3、反射方式

使用反射方式,首先准备一个配置文件,就叫做spring.txt吧, 放在src目录下。 里面存放的是类的名称,和要调用的方法名。

在测试类Test中,首先取出类名称和方法名,然后通过反射去调用这个方法。
当需要从调用第一个业务方法,切换到调用第二个业务方法的时候,不需要修改一行代码,也不需要重新编译,只需要修改配置文件spring.txt,再运行即可。
这也是Spring框架的最基本的原理,只是它做的更丰富,安全,健壮。

spring.txt

class=yingshe.Service1method=doService1

TestF.java

import java.io.File;import java.io.FileInputStream;import java.lang.reflect.Constructor;import java.lang.reflect.Method;import java.util.Properties;public class TestF {    @SuppressWarnings({
"rawtypes", "unchecked"}) public static void main(String[] args) throws Exception { //从spring.txt中获取类名称和方法名称 File springConfigFile = new File("g:\\spring.txt"); Properties springConfig = new Properties(); springConfig.load(new FileInputStream(springConfigFile)); String className = (String) springConfig.get("class"); String methodName = (String) springConfig.get("method"); //根据类名称获取类对象 Class clazz = Class.forName(className); //根据方法名称,获取方法对象 Method m = clazz.getMethod(methodName); //获取构造器 Constructor c = clazz.getConstructor(); //根据构造器,实例化出对象 Object service = c.newInstance(); //调用对象的指定方法 m.invoke(service); }}

执行结果

 

转载于:https://www.cnblogs.com/GG-Bond/p/10644278.html

你可能感兴趣的文章
EXTJS学习系列提高篇:第二十四篇(转载)作者殷良胜,ext2.2打造全新功能grid系列--阅增删改篇...
查看>>
Hadoop MapReduce编程 API入门系列之分区和合并(十四)
查看>>
判断二叉树是否平衡、是否完全二叉树、是否二叉排序树
查看>>
并查集的应用之求解无向图中的连接分量个数
查看>>
7个神奇的jQuery 3D插件
查看>>
在线浏览PDF之PDF.JS (附demo)
查看>>
波形捕捉:(3)"捕捉设备"性能
查看>>
AliOS Things lorawanapp应用介绍
查看>>
美国人的网站推广方式千奇百怪
查看>>
java web学习-1
查看>>
用maven+springMVC创建一个项目
查看>>
linux设备驱动第四篇:以oops信息定位代码行为例谈驱动调试方法
查看>>
redis知识点整理
查看>>
Hello World
查看>>
Spring3全注解配置
查看>>
ThreadLocal真会内存泄露?
查看>>
IntelliJ IDEA
查看>>
低版本mybatis不能用PageHeper插件的时候用这个分页
查看>>
javaweb使用自定义id,快速编码与生成ID
查看>>
[leetcode] Add Two Numbers
查看>>