Java反射使用总结

一、概述

反射:指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。也就是可以获取正在运行的Java对象。

反射作为Java中一个强大的工具,不仅可以很方便创建灵活的代码,而且对一些其他第三方代码可以进行增强。
其主要功能主要有:
1、可以判断运行时对象所属的类
2、可以判断运行时对象所拥有的成员属性和方法
3、生成动态代理

光看概念有些晦涩,我们先说一个简单的应用反射的例子:

public class Item {
    private String id;
    private String name;
    private double price;

    public Item(String id, String name, double price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    public String getId() {   return id; }
    public String getName() {  return name; }
    public double getPrice() { return price; }
}

上面这部分代码不管出于什么目的,其成员属性只在new对象时接收,其他情况一律修改不了。我们可以通过反射来修改类的私有属性。

public static void main(String[] args) throws Exception {
     Item item = new Item("1", "a", 1.0);
     Field field = item.getClass().getDeclaredField("id");
     field.setAccessible(true);
     field.set(item, "2");
     System.out.println(item.getId());  // 2
    }

运行可以发现,我们已经把其对象的id值更新到了2。

二、具体功能实现

1、获取类并创建其对象:反射中获取类通常有三种方法
Class clz1 = Class.forName("java.lang.String"); // 1.通过包和类名
Class clz2 = String.class;  // 2.直接通过类名

String str = new String();
Class clz3 = str.getClass(); // 3.根据对象(运行时类)

clz1.newInstance();
clz2.newInstance();
其他方法名含义
getEnclosingClass()返回底层类的立即封闭类
getDeclaredClasses()返回 Class 对象的一个数组,这些对象反映声明为此 Class 对象所表示的类的成员的所有类和接口
getDeclaringClass()如果此 Class 对象所表示的类或接口是另一个类的成员,则返回的 Class 对象表示该对象的声明类
2、获取类的属性
方法名含义
getFields()获取类的所有public属性,包括其父类
getField()获取某一个属性
getDeclaredFields()获取类的所有声明的字段,不包括父类
getDeclaredField()获取某一个属性
3、获取类的方法
方法名含义
getMethods()获取类的所有public方法,包括其父类
getMethod()获取某一个方法
getDeclaredMethods()获取类的所有声明的方法,不包括父类
getDeclaredMethod()获取某一个方法
getConstructors()获取访问权限是public的所有构造方法
getConstructor()获取某一个构造方法
getDeclaredConstructors()获取类的所有构造方法
getConstructors()获取某一个构造方法
4、总结
  • 反射里的Class, Field, Method, Constructor必须结合对象使用,除非是静态的。
  • 获取非public对象须用类似getDeclaredMethod()而不是getMethod()。
  • Field和Method都能设置accessible(true),之后能访问到私有权限。

三、一个简单的例子

下面是一个Person类,其中有两个私有属性id和name;拥有一个构造方法和一个私有方法print;
- 还有一个public内部类BaseInfo:含有两个私有属性nation和bloodType;拥有一个构造方法和一个私有方法print;
- 还有一个private内部类FamilyInfo:含有两个私有属性nativePlace和address,拥有一个构造方法和一个私有方法print。

由于FamilyInfo为私有的,因此为了可以初始化其属性,在Person中添加了一个私有属性,并在构造方法中对其进行了初始化。

public class Person {
    private String id;
    private String name;

    private FamilyInfo familyInfo;

    public Person(String id, String name) {
        this.id = id;
        this.name = name;
        this.familyInfo = this.new FamilyInfo("beijing", "beijing");
    }

    private void print() {
        System.out.println("Person{id=" + id + ", name=" + name + "}");
    }

    public class BaseInfo {
        private String nation;
        private String bloodType;

        public BaseInfo(String nation, String bloodType) {
            this.nation = nation;
            this.bloodType = bloodType;
        }

        private void print() {
            System.out.println("BaseInfo{nation=" + nation + ", bloodType=" + bloodType + "}");
        }
    }

    private class FamilyInfo {
        private String nativePlace; // 籍贯
        private String address;     // 住址

        private FamilyInfo(String nativePlace, String address) {
            this.nativePlace = nativePlace;
            this.address = address;
        }
        private void print() {
            System.out.println("FamilyInfo{nativePlace=" + nativePlace + ", address=" + address + "}");
        }
    }
}

下面的Main方法中,初始化了Person类,通过一个getFiledFromPerson()方法打印出其私有属性、私有方法、内部类私有属性及方法。

public class Main {

    private static void getFiledFromPerson(Person person, Person.BaseInfo baseInfo) {
        try {
            // 获取外部类的私有属性
            Field idField = person.getClass().getDeclaredField("id");
            idField.setAccessible(true);
            String id = (String) idField.get(person);
            System.out.println("id:" + id);

            Field familyInfoField = person.getClass().getDeclaredField("familyInfo");
            familyInfoField.setAccessible(true);
            Object familyInfo = familyInfoField.get(person);

            // 获取外部类的私有方法
            Method printPersonMethod = person.getClass().getDeclaredMethod("print");
            printPersonMethod.setAccessible(true);
            printPersonMethod.invoke(person);

            // 获取内部类的私有属性
            Class baseInfoClz = Class.forName("demo.Person$BaseInfo");
            Field nationField = baseInfoClz.getDeclaredField("nation");
            nationField.setAccessible(true);
            String nation = (String) nationField.get(baseInfo);
            System.out.println("nation:" + nation);

            Class familyInfoClz = Class.forName("demo.Person$FamilyInfo");
            Field field = familyInfoClz.getDeclaredField("address");
            field.setAccessible(true);
            String address = (String) field.get(familyInfo);
            System.out.println("address:" + address);

            // 获取内部类的私有方法
            Method printBaseInfoMethod = baseInfoClz.getDeclaredMethod("print");
            printBaseInfoMethod.setAccessible(true);
            printBaseInfoMethod.invoke(baseInfo);

            Method printFamilyInfoMethod = familyInfoClz.getDeclaredMethod("print");
            printFamilyInfoMethod.setAccessible(true);
            printFamilyInfoMethod.invoke(familyInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Person person = new Person("1001", "John"); // 初始化Person以及默认FamilyInfo
        Person.BaseInfo baseInfo = person.new BaseInfo("han", "A"); // 初始化BaseInfo
        getFiledFromPerson(person, baseInfo);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值