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

什么是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反射(实用篇)中,我会写出一些用到反射的例子。大家若有什么疑问或意见,请在评论提出,谢谢。若有错误或者新的内容,我都会修改此贴。代码多了点,但是注释写的很清楚了。感谢大家的观看。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 一:java概述:1,JDK:Java Development Kit,java的开发和运行环境,java的开发工...
    ZaneInTheSun阅读 2,627评论 0 11
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,398评论 25 707
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,169评论 11 349
  • “我为我狂妄负责的方式,就是我活的精致。” 疯子是一个狂妄的人,她炒老板鱿鱼,纹身,打耳洞,穿潮款衣服,83年的这...
    20a43a3c7a74阅读 5,589评论 103 196
  • 到深圳的第26天,没想到我已经到深圳快一个月了。 然而一直到今天为止,我才算真正的搬完家。将以前在贵阳呆了六年多的...
    明见苏Karen阅读 697评论 0 50