美文网首页java干货Android技术知识Java学习笔记
花一杯茶的时间,学会Java反射(基础篇)

花一杯茶的时间,学会Java反射(基础篇)

作者: chenxuxu | 来源:发表于2016-08-26 15:45 被阅读413次

    什么是java反射

    JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制。

    其实就是指我们可以在运行时加载、探知、使用编译期间完全未知的 classes。

    java反射的作用

    1.反射可以更好的对代码进行自审。相当于程序员的一面镜子;
    2.反射可以解耦,提高代码的扩展性。如工厂模式。
    3.为满足需求,获取某代码进行部分修改或者破解;
    4.方便多人开发。
    假如有多个程序员开发同个项目,A程序员需要用到B程序员所写的类,若B程序员并没有完成他所写的类,那么A程序员是不能通过编译的。此时,反射就能很好的解决该问题;

    学习反射

    • 获得完整的包名和类名

    有三种方式。不过一般都是使用第一种,通过包名+类名获取需要的类,扩展性好很多:

        package com.demo;
    
        public class ReflectionDemo {
    
            public static void main(String[] args) {
                try {
                    //第一种(推荐使用)
                    Class<?> cls1 = Class.forName("com.demo.Person");
                    System.out.println(cls1.getName());
                    
                    // 第二种
                    Person per = new Person();
                    Class<?> cls2 = per.getClass();
                    System.out.println(cls2.getName());
                    
                    // 第三种
                    Class<?> cls3 = Person.class;
                    System.out.println(cls3.getName());
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    
        class Person {}
    

    打印结果
    com.demo.Person
    com.demo.Person
    com.demo.Person

    <br />

    • 反射进行类的实例化并获取构造方法

    根据构造方法是否有参数,参数的类型有关。

        package com.demo;
    
        import java.lang.reflect.Constructor;
        import java.lang.reflect.InvocationTargetException;
    
        public class ReflectionDemo {
    
            public static void main(String[] args) {
                try {
                    // 获取类
                    Class<?> cls1 = Class.forName("com.demo.Person");
    
                    // 直接获取实例(ps:需要获取的类中有无参构造方法,并且该构造方法不能是private的)
                    Person person = (Person) cls1.newInstance();
                    System.out.println("[ 直接获取实例 ]person.print() :" + person.print());
    
                    System.out.println("-----------------");
    
                    // 获取全部构造方法
                    Constructor<?>[] con = cls1.getConstructors();
                    for (int i = 0; i < con.length; i++) {
                        System.out.println("[ 获取全部构造方法 ]constructor[" + i + "] :" + con[i].toString());
                    }
                    
                    System.out.println("-----------------");
    
                    // 通过带参数的构造方法获取实例(对应上面显示的构造方法顺序)
                    Person per1 = (Person) con[1].newInstance("maxchan");
                    System.out.println("[ 获取带参数的构造方法实例 ] : name:" + per1.getName());
                    Person per2 = (Person) con[2].newInstance("maxchan", "男");
                    System.out.println("[ 获取带参数的构造方法实例 ] : name:" + per2.getName() + " sex:" + per2.getSex());
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (SecurityException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
    
        class Person {
            private String name; // 姓名
            private String sex; // 性别
    
            public Person() {
            }
    
            public Person(String name) {
                this.name = name;
            }
    
            public Person(String name, String sex) {
                this.name = name;
                this.sex = sex;
            }
    
            public String getName() {
                return name;
            }
    
            public String getSex() {
                return sex;
            }
    
            public String print() {
                return "print";
            }
        }
    

    运行结果:

        [ 直接获取实例 ]person.print() :print
        -----------------
        [ 获取全部构造方法 ]constructor[0] :public com.demo.Person()
        [ 获取全部构造方法 ]constructor[1] :public com.demo.Person(java.lang.String)
        [ 获取全部构造方法 ]constructor[2] :public com.demo.Person(java.lang.String,java.lang.String)
        -----------------
        [ 获取带参数的构造方法实例 ] : name:maxchan
        [ 获取带参数的构造方法实例 ] : name:maxchan sex:男
    

    <br />

    • 查看类的方法

    查看类有什么方法,可以使用getMethods()getDeclaredMethods()
    不同的是getMethods()只能获取该类以及父类使用public修饰的方法;getDeclaredMethods()获取的是此类的所有方法,没有获取父类的方法。
    若要查看某个父类中的所有方法,可以通过类cls1.getSuperclass()先获取该父类,再调用getDeclaredMethods()方法。

        package com.demo;
    
        import java.lang.reflect.Method;
    
        public class ReflectionDemo {
    
            public static void main(String[] args) {
                try {
                    // 获取类
                    Class<?> cls1 = Class.forName("com.demo.Person");
                    // 获取方法(只有使用public修饰符的方法)
                    Method[] method = cls1.getMethods();
                    for (int i = 0; i < method.length; i++) {
                        System.out.println("method[" + i + "] :" + method[i]);
                    }
                    
                    System.out.println("--------------------------");
                    
                    //获取全部方法(使用缺省、pulbic、private、protected修饰的方法)
                    Method[] method_all = cls1.getDeclaredMethods();
                    for (int i = 0; i < method_all.length; i++) {
                        System.out.println("method_all[" + i + "] :" + method_all[i]);
                    }
    
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    
        class Person {
            String defaultString() {
                return "defaultString";
            }
    
            private String privateString() {
                return "privateString";
            }
    
            protected String protectedString() {
                return "protectedString";
            }
    
            public String publicString() {
                return "person";
            }
        }
    

    打印结果

        method[0] :public java.lang.String com.demo.Person.publicString()
        method[1] :public final void java.lang.Object.wait() throws java.lang.InterruptedException
        method[2] :public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
        method[3] :public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
        method[4] :public boolean java.lang.Object.equals(java.lang.Object)
        method[5] :public java.lang.String java.lang.Object.toString()
        method[6] :public native int java.lang.Object.hashCode()
        method[7] :public final native java.lang.Class java.lang.Object.getClass()
        method[8] :public final native void java.lang.Object.notify()
        method[9] :public final native void java.lang.Object.notifyAll()
        --------------------------
        method_all[0] :java.lang.String com.demo.Person.defaultString()
        method_all[1] :private java.lang.String com.demo.Person.privateString()
        method_all[2] :protected java.lang.String com.demo.Person.protectedString()
        method_all[3] :public java.lang.String com.demo.Person.publicString()
    

    <br />

    • 获取类的某个具体方法

    和上面相同,若只需获取public方法,用getMethod([具体的方法名],[参数类型]);若需要获取使用其它修饰符的方法,则需使用getDeclaredMethod([具体的方法名],[参数类型])

        package com.demo;
    
        import java.lang.reflect.Method;
    
        public class ReflectionDemo {
    
            public static void main(String[] args) {
                try {
                    // 获取类
                    Class<?> cls1 = Class.forName("com.demo.Person");
    
                    // 获取类的某个具体的方法
                    Method method = cls1.getMethod("publicString");
                    System.out.println("method.getName() :" + method.getName());
                    
                    System.out.println("--------------------------");
    
                    // 获取类的某个具体的方法
                    Method declared_method = cls1.getDeclaredMethod("privateString");
                    System.out.println("declared_method.getName() :" + declared_method.getName());
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (SecurityException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                }
            }
        }
    
        class Person {
            String defaultString() {
                return "defaultString";
            }
    
            private String privateString() {
                return "privateString";
            }
    
            protected String protectedString() {
                return "protectedString";
            }
    
            public String publicString() {
                return "person";
            }
        }
    

    打印结果:
    method.getName() :publicString
    --------------------------
    declared_method.getName() :privateString
    <br />

    • 调用类的方法
        package com.demo;
    
        import java.lang.reflect.InvocationTargetException;
        import java.lang.reflect.Method;
    
        public class ReflectionDemo {
    
            public static void main(String[] args) {
                try {
                    // 获取类
                    Class<?> cls1 = Class.forName("com.demo.Person");
                    Person per = (Person) cls1.newInstance();
    
                    // 调用带参数的方法(第一个参数使用方法名,后面的参数是对应的参数类型,若有多个参数则显示多个参数类型,若无参数,则不显示)
                    //invoke方法的第一个参数是类的实例
                    Method param_method = cls1.getMethod("setContent", String.class);
                    param_method.invoke(per, "content");
    
                    // 调用不带参数的方法获取数据
                    Method method = cls1.getMethod("getContent");
                    String result = (String) method.invoke(per);
                    System.out.println("[ 调用不带参数的方法获取数据 ] :" + result);
    
                    // 调用不带参数的静态方法获取数据(只需将invoke方法的第一个参数改成null即可)
                    Method static_method = cls1.getMethod("getStaticContent");
                    String static_result = (String) static_method.invoke(null);
                    System.out.println("[ 调用不带参数的静态方法获取数据 ] :" + static_result);
    
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (SecurityException e) {
                    e.printStackTrace();
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                }
            }
        }
    
        class Person {
            public String content;
    
            public String getContent() {
                return content;
            }
    
            public void setContent(String content) {
                this.content = content;
            }
    
            public static String getStaticContent() {
                return "static content";
            }
    
        }
    

    运行结果:

        [ 调用不带参数的方法获取数据 ] :content
        [ 调用不带参数的静态方法获取数据 ] :static content
    

    <br />

    • 变量的获取和变量值的设置

    变量的获取使用Field,跟Method的用法很像。有getFields()以及getDeclaredFields()getDeclaredFields()可以获取全部变量,getFields()只能获取用public修饰的变量。

        package com.demo;
    
        import java.lang.reflect.Field;
    
        public class ReflectionDemo {
    
            public static void main(String[] args) {
                try {
                    // 获取类
                    Class<?> cls1 = Class.forName("com.demo.Person");
    
                    // 获取public修饰的变量
                    Field[] field = cls1.getFields();
                    for (Field f : field) {
                        System.out.println("[ 获取public修饰的变量 ] (getFields):" + f.getName());
                    }
    
                    System.out.println("-----------------------------");
    
                    // 获取全部的变量
                    Field[] declared_field = cls1.getDeclaredFields();
                    for (Field f : declared_field) {
                        System.out.println("[ 获取全部的变量 ] (declared_field):" + f.getName());
                    }
    
                    System.out.println("-----------------------------");
    
                    // 通过变量名,设置或获取变量值
                    Person person = (Person) cls1.newInstance();
                    Field field1 = cls1.getDeclaredField("sex");
                    System.out.println("[ 获取变量名 ] :" + field1.get(person));
    
                    // 设置变量值
                    field1.set(person, "女");
                    System.out.println("[ 设置变量名 ] :" + field1.get(person));
    
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (SecurityException e) {
                    e.printStackTrace();
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                }
            }
        }
    
        class Person {
            private String name; // 姓名
            public String sex = "男"; // 性别
        }
    

    运行结果:

        [ 获取public修饰的变量 ] (getFields):sex
        -----------------------------
        [ 获取全部的变量 ] (declared_field):name
        [ 获取全部的变量 ] (declared_field):sex
        -----------------------------
        [ 获取变量名 ] :男
        [ 设置变量名 ] :女
    

    这些是反射比较常用的方法。在花一杯茶的时间,学会Java反射(实用篇)中,我会写出一些用到反射的例子。大家若有什么疑问或意见,请在评论提出,谢谢。若有错误或者新的内容,我都会修改此贴。代码多了点,但是注释写的很清楚了。感谢大家的观看。

    相关文章

      网友评论

      • 英勇青铜5:前来学习 :smile:
      • e6e1569d11c4:Java反射一直没搞懂
        e6e1569d11c4:@chenxuxu 嗯嗯 好的:grin:
        chenxuxu:@十月二十四日 你先看这个基础篇,懂得基本使用,然后看看实用篇会容易懂。实用篇那里有两个例子。 :grin: 希望能帮到你
      • forip:话说。为何就最后一个例子不放输出结果 :joy:
        chenxuxu:@forip :scream: 漏了,谢谢提醒~
      • 2a926c539990:请问一下...没有第二篇了吗?
        2a926c539990: @chenxuxu 好哒,期待
        chenxuxu:@LostTrain 不好意思,最近工作和生活上很忙。我会尽快写第二篇的 0.0

      本文标题:花一杯茶的时间,学会Java反射(基础篇)

      本文链接:https://www.haomeiwen.com/subject/marwsttx.html