Java基础系列:(3)反射机制的简单总结

  1. 云栖社区>
  2. 博客>
  3. 正文

Java基础系列:(3)反射机制的简单总结

技术小阿哥 2017-11-27 14:40:00 浏览551
展开阅读全文

一 反射机制概念简介

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

       举个简单例子就是:正常情况下,对于一个存在的类我们可以通过类来创建对象,然后调用其中的属性或方法;但是要是想要通过一个对象来找到对应的类的名称,属性或者方法,这时候就需要用到反射机制了。

       如果想要简单了解反射操作,则首先应该认识的是Class类

二 认识Class类

(1)所有类的对象实际上都是Class类的实例

       在Java中,Object类是一切类的父类,那么所有类的对象实际上也就都是java.lang.Class类的实例,因此所有对象都可以转变成java.lang.Class类型表示。

(2)一个简单实例,获取完整的类名路径

1
2
3
4
5
6
7
8
9
package javase.reflex;
 
public class GetClassDemo01 {
    public static void main(String[] args) {
        GetClassDemo01 demo01 = new GetClassDemo01();
        System.out.println(demo01.getClass().getName()); // 输出:javase.reflex.GetClassDemo01
    }
 
}

(3)实例化Class类的三种方式

       由于在Class类中并没有定义任何的构造方法,因此一般通过forName(“”)静态方法来实例化对象。当然也可以使用“对象.getClass()“类.class”来实例化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package javase.reflex;
 
/**
 * 实例化Class对象
 * */
public class GetClassDemo02 {
    public static void main(String[] args) {
        Class<?> class1 = null;
        Class<?> class2 = null;
        Class<?> class3 = null;
        // 实例化方法一(常用)
        try {
            class1 = Class.forName("javase.reflex.GetClassDemo02");
        catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        // 实例化方法二
        class2 = new GetClassDemo02().getClass();
        // 实例化方法三
        class3 = GetClassDemo02.class;
 
        System.out.println("类名称:" + class1.getName());
        System.out.println("类名称:" + class2.getName());
        System.out.println("类名称:" + class3.getName());
    }
 
}

输出:

1
2
3
类名称:javase.reflex.GetClassDemo02
类名称:javase.reflex.GetClassDemo02
类名称:javase.reflex.GetClassDemo02

三 Class类初体验——通过newInstance()方法实例化对象

方法:public Object newInstance() throws InstantiationException,IllegalAccessException

描述:创建此Class对象所表示的类的一个新实例

(1)通过无参构造方法实例化对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
package javase.reflex;
 
class WebSite {
    private String name;
    private String domain;
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getDomain() {
        return domain;
    }
 
    public void setDomain(String domain) {
        this.domain = domain;
    }
 
    public String toString() {
        return "名称:" + name + "\n域名:" + domain;
    }
}
 
public class InstanceDemo01 {
 
    public static void main(String[] args) {
        try {
            Class<?> class1 = Class.forName("javase.reflex.WebSite");
            WebSite webSite = (WebSite) class1.newInstance(); // 实例化WebSite对象
            webSite.setName("zifangsky的个人博客");
            webSite.setDomain("http://www.zifangsky.cn");
 
            System.out.println(webSite);
        catch (ClassNotFoundException e) {
            e.printStackTrace();
        catch (InstantiationException e) {
            e.printStackTrace();
        catch (IllegalAccessException e) {
            e.printStackTrace();
        }
 
    }
 
}

输出:

1
2
名称:zifangsky的个人博客
域名:http://www.zifangsky.cn

要注意的是,这种实例化方式需要被实例化的对象的类中必须得存在无参的构造方法,不然程序会比如说这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
55
56
57
58
package javase.reflex;
 
class WebSite02 {
    private String name;
    private String domain;
 
    /**
     * 没有无参数构造方法,下面在进行实例化时会报错
     * */
    // public WebSite02() {
    //
    // }
    public WebSite02(String name, String domain) {
        this.name = name;
        this.domain = domain;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getDomain() {
        return domain;
    }
 
    public void setDomain(String domain) {
        this.domain = domain;
    }
 
    public String toString() {
        return "名称:" + name + "\n域名:" + domain;
    }
}
 
public class InstanceDemo02 {
    public static void main(String[] args) {
        try {
            Class<?> class2 = Class.forName("javase.reflex.WebSite02");
            WebSite02 webSite = (WebSite02) class2.newInstance(); // 实例化WebSite对象
            webSite.setName("zifangsky的个人博客");
            webSite.setDomain("http://www.zifangsky.cn");
 
            System.out.println(webSite);
        catch (ClassNotFoundException e) {
            e.printStackTrace();
        catch (InstantiationException e) {
            e.printStackTrace();
        catch (IllegalAccessException e) {
            e.printStackTrace();
        }
 
    }
 
}

运行时报错:

1
2
3
4
5
6
7
java.lang.InstantiationException: javase.reflex.WebSite02
    at java.lang.Class.newInstance(Class.java:427)
    at javase.reflex.InstanceDemo02.main(InstanceDemo02.java:43)
Caused by: java.lang.NoSuchMethodException: javase.reflex.WebSite02.<init>()
    at java.lang.Class.getConstructor0(Class.java:3082)
    at java.lang.Class.newInstance(Class.java:412)
    ... 1 more

(2)通过有参构造方法实例化对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
55
56
57
58
59
60
61
62
package javase.reflex;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
 
class WebSite03 {
    private String name;
    private String domain;
     
    /**
     * 只有有参数构造方法
     * */
    public WebSite03(String name, String domain) {
        this.name = name;
        this.domain = domain;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getDomain() {
        return domain;
    }
 
    public void setDomain(String domain) {
        this.domain = domain;
    }
 
    public String toString() {
        return "名称:" + name + "\n域名:" + domain;
    }
}
public class InstanceDemo03 {
    public static void main(String[] args) {
        try {
            Class<?> class3 = Class.forName("javase.reflex.WebSite03");
            Constructor<?>[] cons = class3.getConstructors();  //申明一个构造方法数组
             
            //取第一个构造方法,并且使用可变参数的形式向该构造方法传递参数
            WebSite03 webSite = (WebSite03) cons[0].newInstance("zifangsky的个人博客","http://www.zifangsky.cn");
         
            System.out.println(webSite);
        catch (ClassNotFoundException e) {
            e.printStackTrace();
        catch (InstantiationException e) {
            e.printStackTrace();
        catch (IllegalAccessException e) {
            e.printStackTrace();
        catch (IllegalArgumentException e) {
            e.printStackTrace();
        catch (InvocationTargetException e) {
            e.printStackTrace();
        }
 
    }
 
}

输出:

1
2
名称:zifangsky的个人博客
域名:http://www.zifangsky.cn

四 通过反射取得类的结构的常用操作示例

首先定义了一个接口和它的子类

接口:

1
2
3
4
5
6
7
8
package javase.reflex;
 
public interface Animal {
    public final String WATER = "水";
    public void drink();
    public void eat();
    public String introduce(String name,int age);
}

它的子类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
55
56
package javase.reflex;
 
public class Dog implements Animal{
    private String name;
    private int age;
    //三个构造方法
    public Dog() {
         
    }
     
    public Dog(String name) {
        this.name = name;
    }
     
    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    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;
    }
 
    /**
     * 喝水
     * */
    public void drink() {
        System.out.println("每天喝" + WATER);
         
    }
    /**
     * 吃东西
     * */
    public void eat() {
        System.out.println(name + ": 啃骨头 + 吃肉");
    }
    /**
     * 介绍
     * */
    public String introduce(String name, int age) {  
        return "我的名字是" + name + ",今年" + age + "岁了";
    }
 
}

一些常用操作示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package javase.reflex;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
 
public class Demo {
    /**
     * 获取实现的接口
     * */
    public void getInterfacesDemo() {
        try {
            Class<?> class1 = Class.forName("javase.reflex.Dog");
            Class<?>[] inter = class1.getInterfaces(); // 获取所有接口
 
            for (Class<?> c : inter)
                System.out.println("实现的接口: " + c.getName());
 
        catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 获取继承的父类
     * */
    public void getSuperDemo() {
        try {
            Class<?> class1 = Class.forName("javase.reflex.Dog");
            Class<?> superClass = class1.getSuperclass(); // 获取父类
 
            System.out.println("父类: " + superClass.getName());
 
        catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 获取所有构造方法
     * */
    public void getConstructorsDemo() {
        try {
            Class<?> class1 = Class.forName("javase.reflex.Dog");
            Constructor<?>[] cons = class1.getConstructors(); // 获取所有构造方法
 
            for (Constructor<?> con : cons) {
                Class<?>[] parameters = con.getParameterTypes(); // 获取一个构造方法的所有参数类型
                int mo = con.getModifiers(); // 取出权限
                System.out.print("构造方法: " + Modifier.toString(mo) + " "); // 输出权限名称
                System.out.print(con.getName() + "(");
 
                for (int i = 0; i < parameters.length; i++) {
                    System.out.print(parameters[i].getName() + " arg" + i);
                    if (i < (parameters.length - 1))
                        System.out.print(", ");
                }
                System.out.println(")");
            }
 
        catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 获取所有方法
     * */
    public void getMethodsDemo() {
        try {
            Class<?> class1 = Class.forName("javase.reflex.Dog");
            Method[] methods = class1.getMethods();
            for (Method method : methods) {
                System.out.print("方法: "
                        + Modifier.toString(method.getModifiers()) + " "); // 权限
                System.out.print(method.getReturnType().getName() + " "); // 返回值类型
                System.out.print(method.getName() + "("); // 方法名
                // 参数
                Class<?>[] parameters = method.getParameterTypes();
                for (int i = 0; i < parameters.length; i++) {
                    System.out.print(parameters[i].getName() + " arg" + i);
                    if (i < (parameters.length - 1))
                        System.out.print(", ");
                }
                System.out.print(")");
                // 抛出的异常
                Class<?>[] exceptions = method.getExceptionTypes();
                if (exceptions.length > 0)
                    System.out.print("throws ");
 
                for (int i = 0; i < exceptions.length; i++) {
                    System.out.print(exceptions[i].getName());
                    if (i < (exceptions.length - 1))
                        System.out.print(",");
                }
                System.out.println();
            }
        catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 获取所有属性
     * */
    public void getFieldsDemo() {
        try {
            Class<?> class1 = Class.forName("javase.reflex.Dog");
            // 1 取得本类中的全部属性,(PS:普通代码块)
            {
                Field[] field = class1.getDeclaredFields();
                for (Field f : field) {
                    System.out.print("本类属性: "
                            + Modifier.toString(f.getModifiers()) + " "); // 权限
                    System.out.print(f.getType().getName() + " "); // 类型
                    System.out.println(f.getName() + ";"); // 属性名称
                }
            }
            // 2 取得实现的接口或父类中的公共属性
            {
                Field[] field = class1.getFields();
                for (Field f : field) {
                    System.out.print("公共属性: "
                            + Modifier.toString(f.getModifiers()) + " "); // 权限
                    System.out.print(f.getType().getName() + " "); // 类型
                    System.out.println(f.getName() + ";"); // 属性名称
                }
            }
        catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
 
    public static void main(String[] args) {
        Demo demo = new Demo();
        demo.getInterfacesDemo();
        System.out
                .println("******************http://www.zifangsky.cn**********************\n");
 
        demo.getSuperDemo();
        System.out
                .println("******************http://www.zifangsky.cn**********************\n");
 
        demo.getConstructorsDemo();
        System.out
                .println("******************http://www.zifangsky.cn**********************\n");
 
        demo.getMethodsDemo();
        System.out
                .println("******************http://www.zifangsky.cn**********************\n");
 
        demo.getFieldsDemo();
        System.out
                .println("******************http://www.zifangsky.cn**********************\n");
    }
 
}

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
实现的接口: javase.reflex.Animal
******************http://www.zifangsky.cn**********************
 
父类: java.lang.Object
******************http://www.zifangsky.cn**********************
 
构造方法: public javase.reflex.Dog(java.lang.String arg0, int arg1)
构造方法: public javase.reflex.Dog(java.lang.String arg0)
构造方法: public javase.reflex.Dog()
******************http://www.zifangsky.cn**********************
 
方法: public java.lang.String getName()
方法: public void setName(java.lang.String arg0)
方法: public int getAge()
方法: public void setAge(int arg0)
方法: public void drink()
方法: public void eat()
方法: public java.lang.String introduce(java.lang.String arg0, int arg1)
方法: public final void wait()throws java.lang.InterruptedException
方法: public final void wait(long arg0, int arg1)throws java.lang.InterruptedException
方法: public final native void wait(long arg0)throws java.lang.InterruptedException
方法: public boolean equals(java.lang.Object arg0)
方法: public java.lang.String toString()
方法: public native int hashCode()
方法: public final native java.lang.Class getClass()
方法: public final native void notify()
方法: public final native void notifyAll()
******************http://www.zifangsky.cn**********************
 
本类属性: private java.lang.String name;
本类属性: private int age;
公共属性: public static final java.lang.String WATER;
******************http://www.zifangsky.cn**********************

五 通过反射调用类中的方法

注:下面的例子使用了前面定义过的javase.reflex.Dog类

(1)调用一般方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
package javase.reflex;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
 
public class InvokeDemo {
    public static void main(String[] args) {
        //1 调用的方法无参,而且不涉及类中属性
        {
            try {
                Class<?> class1 = Class.forName("javase.reflex.Dog");
                Method method = class1.getMethod("drink");
                method.invoke(class1.newInstance());
            catch (Exception e) {
                e.printStackTrace();
            
            System.out
            .println("******************http://www.zifangsky.cn**********************\n");
        }
         
        //2 调用的方法无参,但是涉及到类中的属性
        {
            try {
                Class<?> class1 = Class.forName("javase.reflex.Dog");
                Constructor<?>[] cons = class1.getConstructors();         
                Method method = class1.getMethod("eat");
                method.invoke(cons[1].newInstance("旺财"));  //通过第二个有参数的构造方法初始化name属性
            catch (Exception e) {
                e.printStackTrace();
            
            System.out
            .println("******************http://www.zifangsky.cn**********************\n");
        }
         
        //3 调用的方法有参数
        {
            try {
                Class<?> class1 = Class.forName("javase.reflex.Dog");
                Method method = class1.getMethod("introduce",String.class,int.class);
                String ret = (String) method.invoke(class1.newInstance(),"旺财",15);  //有返回值
                System.out.println(ret);
            catch (Exception e) {
                e.printStackTrace();
            
        }
         
    }
 
}

输出:

1
2
3
4
5
6
7
每天喝水
******************http://www.zifangsky.cn**********************
 
旺财: 啃骨头 + 吃肉
******************http://www.zifangsky.cn**********************
 
我的名字是旺财,今年15岁了

(2)调用setter和getter方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package javase.reflex;
 
import java.lang.reflect.Method;
 
public class InvokeGetSetDemo {
    /**
     * 通过反射调用Getter和Setter方法
     * */
    public void TestGetterSetter(){
        try {
            Class<?> class1 = Class.forName("javase.reflex.Dog");
            Object dog = class1.newInstance();  //实例化
            setter(dog, "name""大黄", String.class);
            setter(dog, "age"4int.class);
            //输出测试
            System.out.println("名字: " + getter(dog, "name"));
            System.out.println("年龄: " + getter(dog, "age"));
                 
        catch (ClassNotFoundException e) {
            e.printStackTrace();
        catch (InstantiationException e) {
            e.printStackTrace();
        catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    /**
     * setter方法
     * @param object 实例化的对象
     * @param str 要设置的属性名称
     * @param value 属性值
     * @param type 属性类型
     * */
    public void setter(Object object,String str,Object value,Class<?> type){
        try {
            //获取setter方法,如:setName。其中要将属性的首字母大写
            Method method = object.getClass().getMethod("set" + UpperString(str), type);
            method.invoke(object, value);  //setter方法无返回值
        catch (Exception e) {
            e.printStackTrace();
        }
    }
     
    /**
     * getter方法
     * @param object 实例化的对象
     * @param str 属性名称
     * @return 返回属性
     
     * */
    public Object getter(Object object,String str){
        try {
            //获取getter方法,如:getName。其中要将属性的首字母大写
            Method method = object.getClass().getMethod("get" + UpperString(str));
            return method.invoke(object);  //getter方法有返回值
        catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
     
    /**
     * 将字符串的首字母改成大写
     * */
    public String UpperString(String str){
        return String.valueOf(str.charAt(0)).toUpperCase() + str.substring(1);
    }
     
    public static void main(String[] args) {
        new InvokeGetSetDemo().TestGetterSetter();
 
    }
 
}

输出:

1
2
名字: 大黄
年龄: 4

附:

(1)我们在使用eclipse这类开发工具进行程序开发时,一般在我们输入一个“.”时,就可以提示出这个类的所有方法,这个功能实际上就是用了反射的原理 –> 通过反射获取一个类的所有方法

(2)将Java中的.class文件反编译成.java文件实际上也是应用了反射的原理




本文转自 pangfc 51CTO博客,原文链接:http://blog.51cto.com/983836259/1741355,如需转载请自行联系原作者

网友评论

登录后评论
0/500
评论
技术小阿哥
+ 关注