关键词搜索

源码搜索 ×
×

一篇文章带你搞懂 Java 反射机制的深入应用

发布2020-02-21浏览561次

详情内容

反射除了可以取得一个类的完整结构外,还可以调用类中的指定方法或指定属性,并且可以通过反射完成对数组的操作

一、通过反射调用类中的方法

如果要使用反射调用类中的方法可以通过 Method 类完成:
(1)通过 Class 类的 getMethod(String name,Class...parameterTypes) 方法取得一个 Method 的对象,并设置此方法操作时所需要的参数类型

(2)之后可以使用 invoke 进行调用,并向方法中传递要设置的参数

  1. 调用 Person 类中的 sayChina() 方法:
import java.lang.reflect.Method;

public class Test{
    public static void main(String[] args) {
        Class<?> c1 = null;
        try {
            c1 = Class.forName("Person");
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }
        try{
            Method met = c1.getMethod("sayChina");//此方法没有参数
            met.invoke(c1.newInstance());//调用方法,必须传递对象实例
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

    程序中通过 Class 类的 getMethod() 方法根据一个类中的方法取得 Method 对象,并通过 invoke 调用指定的方法。但是在使用 invoke() 方法时必须传入一个类的实例化对象,因为在 sayChina() 方法上没有任何的参数,所以此处没有设置参数类型和参数内容,程序操作如下:
    在这里插入图片描述

    1. 调用Person 类中的 sayHello() 方法
    import java.lang.reflect.Method;
    
    public class Test{
        public static void main(String[] args) {
            Class<?> c1 = null;
            try {
                c1 = Class.forName("Person");
            }catch (ClassNotFoundException e){
                e.printStackTrace();
            }
            try{
                Method met = c1.getMethod("sayHello",
                        String.class,int.class);//此方法需要两个参数
                String rv = null;//接收方法的返回值
                rv = (String)met.invoke(c1.newInstance(),"Java",20);
                System.out.println(rv);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
    
      19
    • 20
    • 21

    程序中在使用 getMethod() 方法调用时除了要指定调用的方法名称,也同样指定了参数的类型,因为 sayHello() 方法调用完后存在返回值,所以用来一个字符串接收返回的内容。

    二、调用 setter 及 getter 方法

    面向对象部分已经知道,类中的属性必须封装,封装之后的属性要通过 setter 及 getter 方法设置和取得,同样在使用反射的调用方法操作中,最重要的也是调用类中的 setter 及 getter 方法。

    import java.lang.reflect.Method;
    
    public class Test{
        public static void main(String[] args) {
            Class<?> c1 = null;//声明 Class 对象
            Object obj = null;//声明一个对象
            try {
                c1 = Class.forName("Person");
            }catch (ClassNotFoundException e){
                e.printStackTrace();
            }
            try{
                obj = c1.newInstance();//实例化操作对象
            }catch (InstantiationException e){
                e.printStackTrace();
            }catch (IllegalAccessException e){
                e.printStackTrace();
            }
            setter(obj,"name","Java",String.class);
            setter(obj,"age",30,int.class);
            System.out.print("姓名:");
            getter(obj,"name");
            System.out.print("年龄:");
            getter(obj,"age");
        }
        /*
        @param obj 操作的对象
        @param att 操作的属性
        @param obj value 设置的值
        @param obj type 参数的类型
         */
        public static void setter(Object obj,String att,Object value, Class<?> type){
            try{
                Method met = obj.getClass().getMethod(
                        "set" + initStr(att),type);//设置方法参数类型
                met.invoke(obj,value);//调用方法
            }catch(Exception e){
                e.printStackTrace();
            }
        }
        public static void getter(Object obj,String att){//调用 getter 方法
            try{
                Method met = obj.getClass().getMethod(
                        "get" + initStr(att));//此方法不需要参数
                System.out.println(met.invoke(obj));//接收方法的返回值
            }catch(Exception e){
                e.printStackTrace();
            }
        }
        public static String initStr(String old){//单词首字母大写
            String str = old.substring(0,1).toUpperCase() + old.substring(1);
            return str;
        }
    }
    
      19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    三、通过反射操作属性

    反射操作中虽然可以使用 Method 调用类中的 setter 及 getter 方法设置和取得属性,但是这样操作很麻烦,所以在反射机制中也可以直接通过 Field 类操作类中的属性,通过 Field 类提供的 set()get() 方法就可以完成设置和取得属性内容的操作。

    但是操作之前,类中的属性已经都设置成私有的访问权限,所以在使用 set() 或 get() 方法时首先要使用 Field 类中的 setAccessible(true) 方法将需要操作的属性设置成可以被外部访问

    import java.lang.reflect.Field;
    
    public class Test{
        public static void main(String[] args)throws Exception {
            Class<?> c1 = null;//声明 Class 对象
            Object obj = null;//声明一个对象
            c1 = Class.forName("Person");
            obj = c1.newInstance();//实例化操作对象
            Field nameField = null;//表示 name 属性
            Field ageField = null;//表示 age 属性
            nameField = c1.getDeclaredField("name");//取得name属性
            ageField = c1.getDeclaredField("age");
            nameField.setAccessible(true);//将 name 属性设置成可被外部访问
            nameField.set(obj,"Java");//设置 name 属性内容
            ageField.setAccessible(true);
            ageField.set(obj,30);//设置 age 属性
            System.out.println("姓名:" + nameField.get(obj));
            System.out.println("年龄:" + ageField.get(obj));
        }
    }
    
      19
    • 20

    使用反射操作属性时最好通过 setter 及 getter 方法
    在这里插入图片描述

    四、通过反射操作数组

    反射机制不仅能用在类上,还可以用在任意的引用数据类型的数据上,当然这本身就包含了数组,既可以使用反射操作数组。可以通过 Class 类的以下方法取得一个数组的 Class 对象:

    public Class<?> getComponentType()
    
    • 1

    在反射操作包 java.lang.reflect 中使用 Array 类表示一个数组,可以通过此类取得数组长度,取得数组内容的操作
    在这里插入图片描述

    1. 取得数组信息并修改数组内容
    import java.lang.reflect.Array;
    
    public class Test{
        public static void main(String[] args)throws Exception {
            int temp[] = {1,2,3};
            Class<?> c = temp.getClass().getComponentType();//取得数组的 Class 对象
            System.out.println("类型:" + c.getName());//得到数组类型名称
            System.out.println("长度:" + Array.getLength(temp));//得到数组长度
            System.out.println("第一个内容:" + Array.get(temp,0));//得到第一个内容
            Array.set(temp,0,6);//修改第一个内容
            System.out.println("第一个内容:" + Array.get(temp,0));//得到第一个内容
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    1. 修改数组的大小
    import java.lang.reflect.Array;
    
    public class Test{
        public static void main(String[] args)throws Exception {
            int temp[] = {1,2,3};
            int newTemp[] = (int[])arrayInc(temp,5);//扩大数组长度
            print(newTemp);
            System.out.println("\n-------------------------");
            String t[] = {"J1","J2","J3"};//声明一个字符串数组
            String nt[] = (String[])arrayInc(t,8);//扩大数组长度
            print(nt);
        }
        public static Object arrayInc(Object obj,int len){//修改数组大小
            Class<?> c = obj.getClass();//通过数组得到 Class 对象
            Class<?> arr = c.getComponentType();//得到数组的 Class 对象
            Object newO = Array.newInstance(arr,len);//重新开辟新的数组大小
            int co = Array.getLength(obj);//取得数组长度
            System.arraycopy(obj,0,newO,0,co);//复制数组内容
            return newO;
        }
        public static void print(Object obj){
            Class<?> c = obj.getClass();//通过数组得到 Class 对象
            if (!c.isArray()){//判断是否是数组,不是则返回
                return;
            }
            Class<?> arr = c.getComponentType();//取得数组的 Class
            System.out.println(arr.getName() + 
                    "数组的长度是:" + Array.getLength(obj));
            for (int i=0;i<Array.getLength(obj);i++){
                System.out.print(Array.get(obj,i) + "、");
            }
        }
    }
    
      19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    五、程序中用到的Person 类

    interface China{
        public static final String NATIONAL = "China";
        public static final String AUTHOR = "Java";
        public void sayChina();//定义无参的抽象方法
        public String sayHello(String name,int age);//定义有参的抽象方法
    }
    class Person implements China{
        private String name;
        private int age;
        public Person(){
        }
        public Person(String name){//声明有一个参数的构造方法
            this.name = name;
        }
        public Person(String name,int age){
            this(name);
            this.setAge(age);
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public int getAge() {
            return age;
        }
    
        @Override
        public void sayChina() {
            System.out.println("作者:" + AUTHOR + ",国籍:" + NATIONAL);
        }
    
        @Override
        public String sayHello(String name, int age) {
            return name + "你好!我今年" + age + "岁了!";
        }
    }
    
      19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    相关技术文章

    点击QQ咨询
    开通会员
    返回顶部
    ×
    微信扫码支付
    微信扫码支付
    确定支付下载
    请使用微信描二维码支付
    ×

    提示信息

    ×

    选择支付方式

    • 微信支付
    • 支付宝付款
    确定支付下载