JAVA-反射机制

预备知识

OK,言归正传,首先我们先了解下什么是JAVA的反射机制,更多的概念性东西请前往百度百科,的确土了点: http://baike.baidu.com/view/1865203.htm?fr=aladdin

接下来我从这些繁杂的文字当中自己小小地总结一些要点:

  •  如何理解反射?

JAVA之所以引入一个reflect的概念,尤其强调的是reflect这个单词的象征性含义,简单说就是JAVA的程序在运行的过程中同样提供了一个自己的镜像一般的“影子”–计算机领域把这种特点称之为self-representation(自省或自表达),在这个过程中,开发人员从“影子”中便可获得JAVA实体运行程序的全部属性,并且允许开发再去修改这些属性。

  • 为什么JAVA会引入反射机制?

其实说到这个问题,不得不说JAVA引入这个机制的目的其实是为了顺应潮流,弥补自己的软肋,平时大家可能听说过静态语言与动态语言的划分问题,这又是一个很蛋疼的概念性问题,还是给个链接,感兴趣的话各位测友自己去翻阅看看:http://baike.baidu.com/view/1458275.htm  ,那么其实你会发现,JAVA(C#也一样)其实是介于这种静态与动态之间的语言,然而其实现在的系统或者框架以至于模块都趋向对外开放的可拓展性,这是动态语言的优势(测友的最爱python还有笔者曾经用过的ruby就是典型的动态语言),所以JAVA选择反射机制来让自己“显得”很像动态语言,请注意我这里的措辞。这种可能性的确是一种进步,但是反射机制不是一个性能很高的行为特点,因此要巧妙而冷静地去应用。

  • 我们利用JAVA反射都干些什么事情呢?

一般情况下,我们会利用这一个特性,获取一个JAVA Class下的全部属性信息(类信息,类变量,所有的方法信息,所有的注解信息等,并且我们还能修改他们),可能这样解释还不直观,说几个利用反射机制你能干的事情吧,比如你想列出来一个类下所有的方法,就如同你在一些IDE中能够看到一个Class下的树状结构一样,那么利用JAVA反射机制便可以实现这个功能;如果您使用过JDBC去和数据库打交道的话,不知道您是否还记得如何加载实例化DB驱动的环节(如:Class.forName(“com.mysql.jdbc.Driver.class”).newInstance();),其实我现在才知道,这就是一个典型的JAVA反射机制的应用,以后可以装下B了,呵呵;JAVA反射机制的经典应用还出现在著名的JAVA web类明星企业级应用开发框架组合SSH中,以Hibernate为例,该框架大量的使用了JAVA的反射机制来动态的加载并执行不同的函数,让JAVA的接口和抽象类的定义在实践中发挥到了极致,利用JAVA反射机制完成的基础代码架构的部分几乎不需要过多的修改便可以满足新增的需求(打断一下,这里说一个现实,其实JAVA的反射机制的确是在框架类代码中才被广泛使用,如果只是应用级别的人,比如几个做APP的小开发人员,我想他们也许只是知道这个东西,是否在应用我可以画一个大大的问号,作为测试人员的我们,能真正实践的可能更是少数),当然这也是我们测试框架一直追求的–高可复用性,高可拓展性,高可维护性,现实中其实我自己却很少应用,以后如果在做小的测试工具和所谓的测试框架时,我也要强迫自己应用这些特点,至少也能跟的上那些学院派大牛的步伐。

  • JAVA反射机制应用的一般设计步骤
  1. 先获取Class(可利用Class.forName;Object.class;Object.TYPE)
  2. 实例化Class对象(利用newInstance())
  3. 这时就厉害了,你将可以获得此类下的各种信息(包括:Constructor(构造函数),Method (所有已定义的方法),Field (所有类的属性,包括类中的变量))
  4. 接下来你便可以无法无天了
  • JAVA反射机制应用过程中的不安全因素

聪明的测友也许会感受到一个问题,那就是你会发现因为有了JAVA的反射机制,那些所谓的public,private可见性限制及作用域问题都变的形同虚设一样,当然sun公司不可能无视这些东西,因此伟大的sun公司创建了一个类AccessibleObject,提供了一个方法setAccessible来避免滥用反射带来的安全隐患。其实这个应用是很难的一件事情,非技术细节狂人还是不要去触碰为好,我只是轻轻地了解了一下这个东西(这几周由于测试执行性能方面的限制,我把一个单线程的测试工具的代码改为多线程都各种坑需要填,对于这个反射安全性的应用,鄙人还是飘过为妙)。

反射实践

如果上面的废话很多很讨厌的话,那么“show me your code”更务实一些,所有的实践和理解都写在这里。。。
接上次的工厂类设计模式,这里当是复习一下:

Demo Code:

  • 创建接口
1
2
3
4
5
6
public interface TestingListener {
//一个伪测试状态监视器的接口定义    
    public void startListener();    
    public void stopListener();    
    public int getTestingStatusCode(String status);
}
  • 实现接口

GUI层测试状态监视器

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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
public class GuiFunctiontestingListener implements TestingListener{
//这是一个GUI层的QA验证程序的状态监听器
        boolean isStarted = false;
        boolean isEnded = false;
        @Override
        public void startListener() {
            // TODO Auto-generated method stub
            long startTime = System.currentTimeMillis();
            if(isStarted == false){
                System.out.println(">>>Start listener=>GuiFunctiontestingListener");
                isStarted = true;
                isEnded = false;
            }
            if(this.isStarted){
                try {
//假启动时间
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            long endTime = System.currentTimeMillis() - startTime;    
                System.out.println(">>>listener=>GuiFunctiontestingListener started!Time costing:"+endTime+" ms");
            }else{
                System.err.println(">>>listener=>GuiFunctiontestingListener starting meet trouble!");
            }
        }
 
        @Override
        public void stopListener() {
            // TODO Auto-generated method stub
            long startTime = System.currentTimeMillis();
            if(isEnded == false){
                System.out.println(">>>Stop listener=>GuiFunctiontestingListener");
                isStarted = false;
                isEnded = true;
            }
            if(this.isEnded){
                try {
//假关闭时间
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            long endTime = System.currentTimeMillis() - startTime;    
                System.out.println(">>>listener=>GuiFunctiontestingListener stopped!Time costing:"+endTime+" ms");
            }else{
                System.err.println(">>>listener=>GuiFunctiontestingListener ending meet trouble!");
            }
        }
 
        @Override
        public int getTestingStatusCode(String status) {
            // TODO Auto-generated method stub
            int statusCode = 0;
            switch(status){
            case "Success":
                statusCode = 200;
                break;
            case "Fail":
                statusCode = 300;
                break;
            case "Unknown":
                statusCode = 400;
                default:
                    break;
            }
            return statusCode;
        }
}
 
接口层测试状态监视器
 
public class InterfaceFunctiontestingListenner implements TestingListener{
//这是一个Interface层的QA验证程序的状态监听器
        boolean isStarted = false;
        boolean isEnded = false;
        @Override
        public void startListener() {
            // TODO Auto-generated method stub
            long startTime = System.currentTimeMillis();
            if(isStarted == false){
                System.out.println(">>>Start listener=>InterfaceFunctiontestingListenner");
                isStarted = true;
                isEnded = false;
            }
            if(this.isStarted){
                try {
//假启动时间
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            long endTime = System.currentTimeMillis() - startTime;    
                System.out.println(">>>listener=>InterfaceFunctiontestingListenner started!Time costing:"+endTime+" ms");
            }else{
                System.err.println(">>>listener=>InterfaceFunctiontestingListenner starting meet trouble!");
            }
        }
 
        @Override
        public void stopListener() {
            // TODO Auto-generated method stub
            long startTime = System.currentTimeMillis();
            if(isEnded == false){
                System.out.println(">>>Stop listener=>InterfaceFunctiontestingListenner");
                isStarted = false;
                isEnded = true;
            }
            if(this.isEnded){
                try {
//假关闭时间
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            long endTime = System.currentTimeMillis() - startTime;    
                System.out.println(">>>listener=>InterfaceFunctiontestingListenner stopped!Time costing:"+endTime+" ms");
            }else{
                System.err.println(">>>listener=>InterfaceFunctiontestingListenner ending meet trouble!");
            }
        }
 
        @Override
        public int getTestingStatusCode(String status) {
            // TODO Auto-generated method stub
            int statusCode = 0;
            switch(status){
            case "Success":
                statusCode = 200;
                break;
            case "Fail":
                statusCode = 300;
                break;
            case "Unknown":
                statusCode = 400;
                break;
                default:
                    break;
            }
            return statusCode;
        }
}
 
数据库数据验证测试状态监视器
 
public class DBlevelDataValidationListener implements TestingListener{
//这是一个DB层的QA验证程序的状态监听器
    boolean isStarted = false;
    boolean isEnded = false;
    @Override
    public void startListener() {
        // TODO Auto-generated method stub
        long startTime = System.currentTimeMillis();
        if(isStarted == false){
            System.out.println(">>>Start listener=>DBlevelDataValidationListener");
            isStarted = true;
            isEnded = false;
        }
        if(this.isStarted){
            try {
//假启动时间
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        long endTime = System.currentTimeMillis() - startTime;    
            System.out.println(">>>listener=>DBlevelDataValidationListener started!Time costing:"+endTime+" ms");
        }else{
            System.err.println(">>>listener=>DBlevelDataValidationListener starting meet trouble!");
        }
    }
 
    @Override
    public void stopListener() {
        // TODO Auto-generated method stub
        long startTime = System.currentTimeMillis();
        if(isEnded == false){
            System.out.println(">>>Stop listener=>DBlevelDataValidationListener");
            isStarted = false;
            isEnded = true;
        }
        if(this.isEnded){
            try {
//假关闭时间
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        long endTime = System.currentTimeMillis() - startTime;    
            System.out.println(">>>listener=>DBlevelDataValidationListener stopped!Time costing:"+endTime+" ms");
        }else{
            System.err.println(">>>listener=>DBlevelDataValidationListener ending meet trouble!");
        }
    }
 
    @Override
    public int getTestingStatusCode(String status) {
        // TODO Auto-generated method stub
        int statusCode = 0;
        switch(status){
        case "Success":
            statusCode = 200;
            break;
        case "Fail":
            statusCode = 300;
            break;
        case "Unknown":
            statusCode = 400;
            break;
            default:
                break;
        }
        return statusCode;
    }
}
  • 创建工厂类
1
2
3
4
5
6
7
8
9
10
11
12
13
public class FactoryClass {
  public static TestingListener instanceGUIListener(){
       return new GuiFunctiontestingListener();
  }
 
  public static TestingListener instanceInterfaceListener(){
       return new InterfaceFunctiontestingListener();
  }
 
  public static TestingListener instanceDBListener(){
       return new DBlevelDataValidationListener();
  }
}

以上步骤全部类似于之前设计模式中工厂模式的定义。

  • 下面写一个利用JAVA反射机制来获取工厂类的函数信息的测试类(重点)

Demo code

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
import java.lang.reflect.Method;
public class ShowFunctions {
//获取指定类的所有函数信息
String className;
//简单的JAVA POJO模式,这种Getter,Setter经常被应用在JAVA的代码中,用于对类变量进行变量的交换和传递
  private String getClassName() {
    return className;
  }
  private void setClassName(String className) {
    this.className = className;
  }
 
  ShowFunctions(String className){
    setClassName(className);
  try {
    Class<?> cluzz = Class.forName(getClassName());
    if(cluzz != null){
//此种方法会获取public及非public的任何已定义的函数
      Method methods[] = cluzz.getDeclaredMethods();
      System.out.println("[INFO]Totally got "+methods.length+" methods in CLASS named "+ getClassName());
      for(Method realMethod:methods){
        System.out.println("[INFO]Method info: "+realMethod.toString());
      }
  }
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    }
  }
}
  • 测试一下

Test Code

1
2
3
4
5
6
7
public class TestShowFunctions {
    public static void main(String[] args) {
        String className = "FactoryClass";
//获取类名为FactoryClass下定义的全部方法信息        
        new ShowFunctions(className);
    }
}
  • 运行结果

[INFO]Totally got 3 methods in CLASS named FactoryClass
[INFO]Method info: public static TestingListener FactoryClass.instanceGUIListener()
[INFO]Method info: public static TestingListener FactoryClass.instanceInterfaceListener()
[INFO]Method info: public static TestingListener FactoryClass.instanceDBListener()

  • 接下来通过JAVA反射机制实现一个动态执行测试Lisener的执行器,简单的一个例子,当然大多数网上的实例都是通过invoke()方法来实现的,这里没有这么实现,只是利用反射机制获取了方法名,再调用工厂模式的工厂类中实例化的对象,进而完成进一步的方法执行。

Demo Code
伪监听器执行器

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
import java.lang.reflect.Method;
 
public class ListenerExecutor {
  ListenerExecutor(String instanceName,String status){
  try {
    TestingListener listener = null;
    Class<?> cluzz = Class.forName("FactoryClass");
    try {
      Method executedMethod = cluzz.getDeclaredMethod(instanceName);
      String methodName = executedMethod.getName();
      if(listener == null){
        if(methodName.equals("instanceGUIListener")){
        listener = FactoryClass.instanceGUIListener();
        listener.startListener();
        int statusCode = listener.getTestingStatusCode(status);
        System.out.println("Status Code: "+statusCode);
        listener.stopListener();
    }
    if(methodName.equals("instanceInterfaceListener")){
      listener = FactoryClass.instanceInterfaceListener();
      listener.startListener();
      int statusCode = listener.getTestingStatusCode(status);
      System.out.println("Status Code: "+statusCode);
      listener.stopListener();
    }
    if(methodName.equals("instanceDBListener")){
      listener = FactoryClass.instanceInterfaceListener();
      listener.startListener();
      int statusCode = listener.getTestingStatusCode(status);
      System.out.println("Status Code: "+statusCode);
      listener.stopListener();
    }
  }
} catch (NoSuchMethodException e) {
   e.printStackTrace();
} catch (SecurityException e) {
   e.printStackTrace();
}} catch (ClassNotFoundException e) {
   e.printStackTrace();
 }
}
}
  • 测试一下

Demo Code

1
2
3
4
5
6
7
8
9
10
11
12
public class TestListenerExecutor {
private static String s_SUCCESS = "Success";
private static String s_FAIL = "Fail";
private static String s_UNKNOWN = "Unknown";
 
public static void main(String[] args) {
new ListenerExecutor("instanceGUIListener",s_SUCCESS);
new ListenerExecutor("instanceInterfaceListener",s_FAIL);
new ListenerExecutor("instanceDBListener",s_UNKNOWN);
}
 
}
  • 运行结果

>>>Start listener=>GuiFunctiontestingListener
>>>listener=>GuiFunctiontestingListener started!Time costing:2999 ms
Status Code: 200
>>>Stop listener=>GuiFunctiontestingListener
>>>listener=>GuiFunctiontestingListener stopped!Time costing:2003 ms
>>>Start listener=>InterfaceFunctiontestingListenner
>>>listener=>InterfaceFunctiontestingListenner started!Time costing:3001 ms
Status Code: 300
>>>Stop listener=>InterfaceFunctiontestingListenner
>>>listener=>InterfaceFunctiontestingListenner stopped!Time costing:2001 ms
>>>Start listener=>InterfaceFunctiontestingListenner
>>>listener=>InterfaceFunctiontestingListenner started!Time costing:3001 ms
Status Code: 400
>>>Stop listener=>InterfaceFunctiontestingListenner
>>>listener=>InterfaceFunctiontestingListenner stopped!Time costing:2001 ms

好了,今天就先给各位测友介绍到这里,例子的应用很简单,实现了一个假的测试状态监听器,使用一个独立的Executor去执行,实例化方法的选择完全通过JAVA的反射机制来动态获取方法名,这样做的好处大家应该能感受的到,那就是少了很多的HardCode而多了一些灵活与开放,实际上绝大多数的JAVA框架都或多或少的采取了JAVA的这个特点,来使得他们的框架的开放性更强,更容易被拓展,下次如果笔者还是在面试中被问到了这个话题,相信便不会捉襟见肘了,但是我最后还是不得不强调一下,知道这些东西也许是一个附加值,但绝对不是一个测试工程师的核心竞争力,事实上我们不需要去说一堆别人听不懂的东西来彰显自己的能力,能解决问题吗?这才是重点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值