Java(13):反射(2)

关于 Class 类、Method 类以及 Field 类的使用方式解析:

1. 要想使用反射,首先需要获得待处理类或对象所对应的 Class 对象。

2. 获取某个类或某个对象所对应的 Class 对象的常用 3 种方式:

    a. 使用 Class 类的静态方法 forName();

// 参数为要获取的 Class 类的包名,eg: Class<?> classType = Class.forName("java.lang.String");
public static Class<?> forName(String className)
            throws ClassNotFoundException {
    ...
}

    b. 使用类的 .class 语法;

eg: String.calss

    c. 使用对象的 geyClass() 方法;

eg:
String s = "ym";
Class<?> clazz = s.getClass();

3. 若想通过类的不带参数的构造方法来生成对象,我们有两种方式:

    a. 先获取 Class 对象,然后通过该 Class 对象的 newInstance() 方法直接生成即可(已废弃):

Class<?> classType = String.class;
Object obj = classType.newInstance();

    b. 先获取 Class 对象,然后通过该对象获得对应的 Constructor 对象,再通过该 Constructor 对象的 newInstance() 方法生成:

Class<?> classType = String.class;
Constructor cons = classType.getConstructor(new Class[]{});
Object obj = cons.newInstance(new Object[]{});

4. 若想通过类的带参构造方法来生成对象,只能通过 3 中的 b 方法。

eg1:通过反射实现一个对象的 copy,并返回和原对象属性一样的新对象。

public class ReflectionTest {

    // 该方法实现对 Customer 对象的拷贝操作
    public Object copy(Object object) throws Exception {
        // 1. 获取 Customer 类的 Class 对象
        // 方法 3 :
        Class<?> classType = object.getClass();

        // 2. 获取 Customer 对象的一个实例,这个就是最后返回的新对象
        // 通过无参构造方法创建
        Constructor cons = classType.getConstructor();
        Object newObj = cons.newInstance();

        // 通过有参构造方法创建
//        Constructor cons = classType.getConstructor(new Class[]{String.class, int.class});
//        Object newObj = cons.newInstance(new Object[]{"ym", 20});

        // 3. 获取 Customer 对象的所有成员变量
        Field[] fields = classType.getDeclaredFields();

        for(Field field : fields){

            // 获取 属性 的名称
            String name = field.getName();

            // 获取字符的首字母,并将其转换成大写
            String firstLetter = name.substring(0, 1).toUpperCase();
            // name.substring(1) 等价于 name.substring(1, name.length)
            String getMethodName = "get" + firstLetter + name.substring(1);
            String setMethodName = "set" + firstLetter + name.substring(1);
            Method getMethod = classType.getMethod(getMethodName, new Class[]{});
            Method setMethod = classType.getMethod(setMethodName, new Class[]{field.getType()});
            Object value = getMethod.invoke(object, new Object[]{});
            setMethod.invoke(newObj, new Object[]{value});
        }
        return newObj;
    }

    public static void main(String[] args) throws Exception {

        Customer customer = new Customer("ym", 18);
        customer.setId(1L);
        ReflectionTest reflectionTest = new ReflectionTest();
        Customer newCustomer = (Customer) reflectionTest.copy(customer);
        System.out.println(newCustomer.getId()+", " + newCustomer.getName() + ", " + newCustomer.getAge());

    }
}

class Customer{
    private Long id;
    private String name;
    private int age;

    public Customer() {
    }

    public Customer(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

// output
1, ym, 18

5. java.lang.Array 类提供了动态创建和访问数组元素的各种静态方法。

eg1: 先创建一个长度为 10 的字符串数组,接着把索引位置为 5 的元素设置为 “ym”,然后再读取该位置元素的值。

public class ArrayTest {

    public static void main(String[] args) throws Exception{
        Class<?> classType = Class.forName("java.lang.String");

        // 生成一个数组对象
        Object array = Array.newInstance(classType, 10);
        Array.set(array, 5, "ym");
        System.out.println(Array.get(array, 5));
    }
}

// output
ym

6. Integer.TYPE 返回的是 int,而 Integer.class 返回的是 Integer 类所对应的 Class 对象。

public class ArrayTest {

    public static void main(String[] args) throws Exception{
        System.out.println(Integer.TYPE);
        System.out.println(Integer.class);
    }
}

// output
int
class java.lang.Integer

eg2: 对多维数组的操作

public class ArrayTest {

    public static void main(String[] args) throws Exception{
        int[] dims = new int[]{ 5, 10, 15 };
        // 这里第二个参数类型是维度,也就是生成了一个 3 维数组。array[5][10][15]。
        Object array = Array.newInstance(Integer.TYPE, dims);

        // 获取 第一维 索引为 3 个数组,也就是 array[3][][],所以 arrayObj 其实就是一个二维数组。
        Object arrayObj = Array.get(array, 3);
        Class<?> classType = arrayObj.getClass().getComponentType();

        arrayObj = Array.get(arrayObj, 5);
        Array.setInt(arrayObj, 10, 37);
        int[][][] arratCast = (int[][][]) array;
        System.out.println(arratCast[3][5][10]);
    }
}

// output
37

7. 通过反射调用外部类中的私有方法、访问对象的私有成员变量

eg1: 通过反射调用外部类私有方法

public class PrivateTest {
    // 私有方法
    private String testOne(String s){
        return "ym: " + s;
    }
}

// 通过反射调用 PrivateTest 的私有方法
public class Test {

    public static void main(String[] args) throws Exception {
        PrivateTest privateTest = new PrivateTest();

        // 获取 PrivateTest 的 Class 对象
        Class<?> classType = privateTest.getClass();

        // 获取 Method 对象
        Method method = classType.getDeclaredMethod("testOne", new Class[]{ String.class });

        // 压制 Java 的访问控制检查
        method.setAccessible(true);

        String str = (String) method.invoke(privateTest, new Object[]{ "test" });
        System.out.println(str);
    }
}

// output
ym: test

eg2:通过反射修改外部类私有属性值

public class PrivateTest {

    // 私有属性
    private String name = "cfm";

    public String getName() {
        return name;
    }
}

public class Test {

    public static void main(String[] args) throws Exception {
        PrivateTest privateTest = new PrivateTest();

        // 获取 PrivateTest 的 Class 对象
        Class<?> classType = privateTest.getClass();

        // 获取 Field 对象
        Field field = classType.getDeclaredField("name");
        field.setAccessible(true);
        field.set(privateTest, "ym");

        System.out.println(privateTest.getName());
    }
}

// output
ym

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值