Java进阶-简单了解反射

Java进阶-简单了解反射

一、了解反射

反射(Reflect):反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。其实就是调用JDK提供的API。
/**
 * 实例化对象的标准用法:使用new实例化对象,也就所谓的正。
 * 一般情况下,我们使用某个类时必定知道它是什么类,是用来做什么的。
 * 于是我们直接对这个类进行实例化,之后使用这个类对象进行操作。
 */
Servant servant = new Servant();
servant.service("Hello");

/**
 * 反射则是一开始并不知道要初始化的类对象是什么,自然也无法使用 new 关键字来创建对象了。
 * 这时候,使用 JDK 提供的反射 API 进行反射调用。
 */
//获取Class的方式一
Class servantClass = Servant.class;
//获取Class的方式二
Class servantClass2 = servant.getClass();
//获取Class的方式三(框架常用方式)
Class servantClass3 = Class.forName("com.tiddler.enjoy1.basic.reflect.Servant");

//通过Class实例化对象
Servant servant3 = (Servant)servantClass3.newInstance();
servant3.service("OK");

二、获取类加载器

//1. 获取一个系统的类加载器(可以获取,AppClassLoader)
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
System.out.println("1. " + classLoader);

//2. 获取系统类加载器的父类加载器(扩展类加载器,可以获取,ExtClassLoader)
classLoader = classLoader.getParent();
System.out.println("2. " + classLoader);

//3. 获取扩展类加载器的父类加载器(引导类加载器,不可获取).
classLoader = classLoader.getParent();
System.out.println("3. " + classLoader);

//4. 测试当前类由哪个类加载器进行加载(系统类加载器AppClassLoader):
classLoader = Class.forName("com.tiddler.enjoy1.basic.reflect.TestClassLoader")
        .getClassLoader();
System.out.println("4. " + classLoader);

//5. 测试 JDK 提供的 Object 类由哪个类加载器负责加载(引导类)
classLoader = Class.forName("java.lang.Object").getClassLoader();
System.out.println("5. " + classLoader);

三、获取构造器

反射–示例类

public class Person {

    String name;
    private int age;

    public Person() {
        super();
    }

    //包含一个带参的构造器和一个不带参的构造器
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    //私有方法
    private void privateMethod() {
        System.out.println("this is private method!");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        System.out.println("this is setName()!");
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
        System.out.println("this is setAge()!");
    }
}

构造器相关

//获取Class
String className = "com.tiddler.enjoy1.basic.reflect.Person";
Class<Person> clazz = (Class<Person>) Class.forName(className);

System.out.println("获取全部Constructor对象:");
Constructor<Person>[] constructors = (Constructor<Person>[]) clazz.getConstructors();
for (Constructor<Person> constructor : constructors) {
    System.out.println(constructor);
}

System.out.println("获取某一个Constructor 对象,需要参数列表:");
//不能传入Integer.class,必须传入int.class。否则会java.lang.NoSuchMethodException
//Constructor<Person> constructor0 = clazz.getConstructor(String.class, Integer.class);
Constructor<Person> constructor = clazz.getConstructor(String.class, int.class);
System.out.println(constructor);

//2. 调用构造器的 newInstance() 方法创建对象
System.out.println("调用构造器的 newInstance() 方法创建对象:");
Person obj = constructor.newInstance("刘小鱼", 25);
System.out.println(obj.getName() + "," + obj.getAge());

四、获取方法

//获取Class
Class clazz = Class.forName("com.tiddler.enjoy1.basic.reflect.Person");

//获取clazz对应类中的所有方法,能获取从父类继承来的所有方法,但不能获取私有方法。
System.out.println("获取类中的方法,但不包含私有方法:");
Method[] methods = clazz.getMethods();
for (Method method : methods) {
    System.out.print(" " + method.getName() + "()");
}
System.out.println();

//获取所有方法,包括私有方法。所有声明的方法,都可以获取到,但只获取当前类的方法。
System.out.println("取类中的方法,且包含私有方法:");
methods = clazz.getDeclaredMethods();
for (Method method : methods) {
    System.out.print(" " + method.getName() + "()");
}
System.out.println();

//获取指定的方法。需要传入方法名称和参数列表,无参则不需要写参数列表。
System.out.println("获取指定的方法:");
//获取方法public void setName(String name) {  }
Method setNameMethod = clazz.getDeclaredMethod("setName", String.class);
System.out.println(setNameMethod);
//获取方法public String getName() {}
Method getNameMethod = clazz.getDeclaredMethod("getName");
System.out.println(getNameMethod);
//获取方法public void setAge(int age) {  }
Method setAgeMethod = clazz.getDeclaredMethod("setAge", int.class);
System.out.println(setAgeMethod);

//执行方法,第一个参数表示执行哪个对象的方法,剩下的参数是执行方法时需要传入的参数。
System.out.println("执行方法:");
Object obj = clazz.newInstance();
setNameMethod.invoke(obj,"刘小鱼");
setAgeMethod.invoke(obj, 25);
System.out.println("name = "+ getNameMethod.invoke(obj));

//私有方法的执行,必须在调用invoke之前加上一句method.setAccessible(true);
System.out.println("执行私有方法:");
Method method = clazz.getDeclaredMethod("privateMethod");
System.out.println(method);
method.setAccessible(true);
method.invoke(obj);

五、获取成员属性

//获取Class
Class clazz = Class.forName("com.tiddler.enjoy1.basic.reflect.Person");

//获取该类所有成员属性。包含私有属性,但不能获取从父类继承的属性。
System.out.println("获取所有字段,但不能获取父类字段:");
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
    System.out.print(" " + field.getName());
}
System.out.println();
System.out.println("------------------------------");

//获取指定字段,传入字段名称。
Field field = clazz.getDeclaredField("name");
System.out.println("获取指定字段:" + field.getName());

Person person = new Person("ABC", 12);
Object val = field.get(person);
System.out.println("获取person的指定字段:" + field.getName() + "=" + val);

field.set(person, "DEF");
System.out.println("设置指定对象指定字段的值:" + field.getName() + "=" + person.getName());

//如果字段是私有的,不管是读值还是写值,都必须先调用setAccessible(true)方法。
//比如Person类中,字段name字段是非私有的,age是私有的。
field = clazz.getDeclaredField("age");
field.setAccessible(true);
System.out.println("操作私有字段:" + field.get(person));
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值