Java 反射
本文介绍 Java 语言中如何使用反射创建对象、访问属性、调用方法,以及反射的应用场景和基本使用示例等

# Java 反射

# 示例类

  1. User 类:
class User
{
    String name;
    int id;
   
    public User()
    {
    
    }
    
    public User(String name, int id)
    {
        this.name = name;
        this.id = id;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public int getId()
    {
        return id;
    }

    public void setId(int id)
    {
        this.id = id;
    }
}
  1. ReflectTest 类:
public Class ReflectTest
{
  pulic static void main(String[] args)
  {
    try
    {
      //测试
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
  }
}

# 类对象

  1. 不同的类区别在于有不同的方法,不同的属性。类对象,就是用于描述这种类,都有什么属性,什么方法的。
  2. 获取类对象的方法
    • Class.forName("mypackage.User")
    • User.class
    • new User().getClass()

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

# 反射创建对象

  1. 常规方法
//使用反射的方式创建对象
String className = "mypackage.User";
//类对象
Class uClass = Class.forName(className);
//构造器
Constructor con = uClass.getConstructor();
//通过构造器实例化
User u = (User) con.newInstance();
  1. Class.newInstance()Constructor.newInstance()

Class 对象调用 newInstance() 方法只能用于不带参数的构造方法;

Constructor 对象调用 newINstance() 方法可以指定参数

Constructor con =
      uClass.getConstructor(new Class[]{String.class, int.class});
User u = (User) con.newInstance(new Object[]{"haha", 123});
//也可以不传参数数组,直接写参数列表
Constructor con = uClass.getConstructor(String.class, int.class);
User u = (User) con.newInstance("haha", 123);

# 反射访问属性

  1. 示例类名 User,有成员属性 name
User u = new User();
//获取类User的name字段
Field f = u.getClass().getDeclaredField("name");
//修改这个字段的值
f.set(u, "haha");
//获取被修改后的值
System.out.println(f.get(u));

2.getDeclaredField()getField()

getField() 只能获取public的,包括从父类继承来的字段。
getDeclaredField() 可以获取本类所有的字段,包括private的,但是不能获取继承来的字段。
注:这里只能获取到private的字段,但并不能访问该private字段的值,除非加上f.setAccessible(true)

# 反射调用方法

  1. 常规方法

    User u = new User();
    Method m = u.getClass().getMethod("setName", String.class);
    //等同于
    Method m = 
          u.getClass().getMethod("setName", new Class[]{String.class});
    
    //对u对象,调用这个方法
    m.invoke(u, "Jack");
    //等同于
    m.invoke(u, new Object[]{"Jack"});
    
  2. getMethod()getDeclaredMethod()

    getMethod():获得类的public类型的方法 getDeclaredMethod():获得类的所有方法 gtMethod(String name, Class[] parameterTypes):获得类的特定方法,name 参数指定方法的名字,parameterTypes 参数指定方法的参数类型

  3. 获取方法上的注解

    User u = new User();
    Method m = u.getClass().getMethod("setName", String.class);
    // 类上的注解
    MyClassAnnotation myClassAnnotation = u.getAnnotation(MyClassAnnotation.class);
    // 方法上的注解
    MyMethodAnnotation myMethodAnnotation = m.getAnnotation(MyMethodAnnotation.class);
    // 获取注解上的信息,比如 value
    // MyMethodAnnotation.value();
    

# 反射的作用

反射可以访问私有属性,private 还有什么意义?

private 的作用是在面向对象的封装上 ,并不是为了解决安全问题。

  1. 作用: 在运行时构造一个类的对象;判断一个类所具有的成员变量和方法;调用一个对象的方法;生成动态代理

  2. 应用场景:反射最大的应用就是框架

    • spring 的 ioc/di
    • javaBean 和 jsp 之间调用
    • struts 的 FormBean 和页面之间
    • JDBC 的 classForName()
    • hibernate 的 find(Class clazz)
  3. 示例:通过配置文件,切换业务类和业务方法, 不需要修改一行代码,也不需要重新编译,只需要修改配置文件,再运行即可

    • 业务类
    package reflection;
     
    public class Service1 
    {
        public void doService1()
        {
            System.out.println("业务方法1");
        }
    }
    
    package reflection;
     
    public class Service2 
    {
        public void doService2()
        {
            System.out.println("业务方法2");
        }
    }
    
    • 配置文件 config.txt
    class=reflection.Service1
    method=doService1
    
    • 测试类
    public class Test 
    {
        public static void main(String[] args) throws Exception 
        {
            //从config.txt中获取类名称和方法名称
            File configFile = new File("config.txt");
            Properties config= new Properties();
            config.load(new FileInputStream(configFile));
            String className = (String) config.get("class");
            String methodName = (String) config.get("method");
             
            //根据类名称获取类对象
            Class clazz = Class.forName(className);
            //根据方法名称,获取方法对象
            Method m = clazz.getMethod(methodName);
            //获取构造器
            Constructor c = clazz.getConstructor();
            //根据构造器,实例化出对象
            Object service = c.newInstance();
            //调用对象的指定方法
            m.invoke(service);
        }
    }
    
Comment here, be cool~

Copyright © 2020 CadeCode

Theme 2zh powered by VuePress

本页访问次数 0

Loading