当前位置:文档之家› Java反射访问私有变量和私有方法

Java反射访问私有变量和私有方法

Java反射访问私有变量和私有方法
Java反射访问私有变量和私有方法

Java反射访问私有变量和私有方法

引言

对于软件开发人员来说,单元测试是一项必不可少的工作。它既可以验证程序的有效性,又可以在程序出现BUG 的时候,帮助开发人员快速的定位问题所在。但是,在写单元测试的过程中,开发人员经常要访问类的一些非公有的成员变量或方法,这给测试工作带来了很大的困扰。本文总结了访问类的非公有成员变量或方法的四种途径,以方便测试人员在需要访问类非公有成员变量或方法时进行选择。

尽管有很多经验丰富的程序员认为不应该提倡访问类的私有成员变量或方法,因为这样做违反了Java 语言封装性的基本规则。然而,在实际测试中被测试的对象千奇百怪,为了有效快速的进行单元测试,有时我们不得不违反一些这样或那样的规则。本文只讨论如何访问类的非公有成员变量或方法,至于是否应该在开发测试中这样做,则留给读者自己根据实际情况去判断和选择。

方法一:修改访问权限修饰符

先介绍最简单也是最直接的方法,就是利用Java 语言自身的特性,达到访问非公有成员的目的。说白了就是直接将private 和protected 关键字改为public 或者直接删除。我们建议直接删除,因为在Java 语言定义中,缺省访问修饰符是包可见的。这样做之后,我们可以另建一个源码目录——test 目录(多数IDE 支持这么做,如Eclipse 和JBuilder),然后将测试类放到test 目录相同包下,从而达到访问待测类的成员变量和方法的目的。此时,在其它包的代码依然不能访问这些变量或方法,在一定程度上保障了程序的封装性。

下面的代码示例展示了这一方法。

清单1. 原始待测类 A 代码

public class A {

private String name = null;

private void calculate() {

}

}

清单2. 针对单元测试修改后的待测类 A 的代码

public class A {

String name = null;

private void calculate() {

}

}

这种方法虽然看起来简单粗暴,但经验告诉我们这个方法在测试过程中是非常有效的。当然,由于改变了源代码,虽然只是包可见,也已经破坏了对象的封装性,对于多数对代码安全性要求严格的系统此方法并不可取。

方法二:利用安全管理器

安全性管理器与反射机制相结合,也可以达到我们的目的。Java 运行时依靠一种安全性管理器来检验调用代码对某一特定的访问而言是否有足够的权限。具体来说,安全性管理器是https://www.doczj.com/doc/9e6352029.html,ng.SecurityManager 类或扩展自该类的一个类,且它在运行时检查某些应用程序操作的权限。换句话说,所有的对象访问在执行自身逻辑之前都必须委派给安全管理器,当访问受到安全性管理器的控制,应用程序就只能执行那些由相关安全策略特别准许的操作。因此安全管理器一旦启动可以为代码提供足够的保护。默认情况下,安全性管理器是没有被设置的,除非代码明确地安装一个默认的或定制的安全管理器,否则运行时的访问控制检查并不起作用。我们可以通过这一点在运行时避开Java 的访问控制检查,达到我们访问非公有成员变量或方法的目的。为能访问我们需要的非公有成员,我们还需要使用Java 反射技术。Java 反射是一种强大的工具,它使我们可以在运行时装配代码,而无需在对象之间进行源代码链接,从而使代码更具灵活性。在编译时,Java 编译程序保证了私有成员的私有特性,从而一个类的私有方法和私有成员变量不能被其他类静态引用。然而,通过Java 反射机制使得我们可以在运行时查询以及访问变量和方法。由于反射是动态的,因此编译时的检查就不再起作用了。

下面的代码演示了如何利用安全性管理器与反射机制访问私有变量。

清单3. 利用反射机制访问类的成员变量

//获得指定变量的值

public static Object getValue(Object instance, String fieldName)

throws IllegalAccessException, NoSuchFieldException {

Field field = getField(instance.getClass(), fieldName);

// 参数值为true,禁用访问控制检查

field.setAccessible(true);

return field.get(instance);

}

//该方法实现根据变量名获得该变量的值

public static Field getField(Class thisClass, String fieldName)

throws NoSuchFieldException {

if (thisClass == null) {

throw new NoSuchFieldException("Error field !");

}

}

其中getField(instance.getClass(), fieldName) 通过反射机制获得对象属性,如果存在安全管理器,方法首先使用this 和Member.DECLARED 作为参数调用安全管理器的checkMemberAccess 方法,这里的this 是this 类或者成员被确定的父类。如果该类在包中,那么方法还使用包名作为参数调用安全管理器的checkPackageAccess 方法。每一次调用都可能导致SecurityException。当访问被拒绝时,这两种调用方式都会产生securityexception 异常。

setAccessible(true) 方法通过指定参数值为true 来禁用访问控制检查,从而使得该变量可以被其他类调用。我们可以在我们所写的类中,扩展一个普通的基本类https://www.doczj.com/doc/9e6352029.html,ng.reflect.AccessibleObject 类。这个类定义了一种setAccessible 方法,使我们能够启动或关闭对这些类中其中一个类的实例的接入检测。这种方法的问题在于如果使用了安全性管理器,它将检测正在关闭接入检测的代码是否允许这样做。如果未经允许,安全性管理器抛出一个例外。

除访问私有变量,我们也可以通过这个方法访问私有方法。

清单4. 利用反射机制访问类的成员方法

public static Method getMethod(Object instance, String methodName, Class[] classTypes)

throws NoSuchMethodException {

Method accessMethod = getMethod(instance.getClass(), methodName, classTypes);

//参数值为true,禁用访问控制检查

accessMethod.setAccessible(true);

return accessMethod;

}

private static Method getMethod(Class thisClass, String methodName, Class[] classTypes)

throws NoSuchMethodException {

if (thisClass == null) {

throw new NoSuchMethodException("Error method !");

} try {

return thisClass.getDeclaredMethod(methodName, classTypes);

} catch (NoSuchMethodException e) {

return getMethod(thisClass.getSuperclass(), methodName, classTypes);

}

}

获得私有方法的原理与获得私有变量的方法相同。当我们得到了函数后,需要对它进行调用,这时我们需要通过invoke() 方法来执行对该函数的调用,代码示例如下:

//调用含单个参数的方法

public static Object invokeMethod(Object instance, String methodName, Object arg)

throws NoSuchMethodException,

IllegalAccessException, InvocationTargetException {

Object[] args = new Object[1];

args[0] = arg;

return invokeMethod(instance, methodName, args);

}

//调用含多个参数的方法

public static Object invokeMethod(Object instance, String methodName, Object[] args)

throws NoSuchMethodException,

IllegalAccessException, InvocationTargetException {

Class[] classTypes = null;

if (args != null) {

classTypes = new Class[args.length];

for (int i = 0; i < args.length; i++) {

if (args[i] != null) {

classTypes[i] = args[i].getClass();

}

}

}

return getMethod(instance, methodName, classTypes).invoke(instance, args);

}

利用安全管理器及反射,可以在不修改源码的基础上访问私有成员,为测试带来了极大的方便。尤其是在编译期间,该方法可以顺利地通过编译。但同时该方法也有一些缺点。第一个是性能问题,用于字段和方法接入时反射要远慢于直接代码。第二个是权限问题,有些涉及Java 安全的程序代码并没有修改安全管理器的权限,此时本方法失效。

方法三:使用模仿(Mock)对象

在单元测试的过程中模仿对象被广泛使用。它从测试中分离了外部的不需要的因素,并且帮助开发人员专注于被测试的功能。模仿对象(Mock object)的核心是构造一个伪类,在测试中通常用这个构造的伪类替换原来的需要访问相关环境(如应用服务器,数据库等)的需要测试的待测类,这样单元测试便可以运行在本地环境下(这也是对单元测试的基本要求之一,不依赖于任何特定的环境),并可以正确的执行。此外, 由于Java 语言不能多继承的特性,使得该方法也可以被用来作为非公有成员变量及方法的访问方法(测试类不能同时继

承TestCase 和待测类),利用该方法,在模仿对象中改变类成员的访问控制权限,从而达到访问非公有类变量及方法的目的。

下面的代码示例演示了模仿对象方法。

本方法的应用场景在单元测试中非常常见,即在待测试的公有方法中,有一些受限制的成员变量是由其它私有方法来初始化的,在测试该方法的时候,需要给这个变量置初值才能完成测试。

清单5. 待测类A

public class A {

protected String s = null;

public A() {

}

private void method() {

s = "word";

System.out.println("this is mock test");

}

public void makeWord() {

String prefix = s;

System.out.println("prefix is:" + prefix);

}

}

在待测类A 中,增加工厂方法。

清单6. 包含工厂方法的待测类A

// 增加工厂方法的类A

public class A {

protected String s = null;

public A getA() {

return new A();

}

private void method() {

s = "word";

System.out.println("this is mock test");

}

public void makeWord() {

String prefix = s;

System.out.println("prefix is:" + prefix);

}

}

//伪类,在运行时替换类A

public class MockA extends A{

public String s = null;

public MockA(){

}

}

//测试类

public class TestA extends TestCase{

public void setup(){

}

public void teardown(){

}

public void makeWordTest(){

A a = new MockA();

a.s = "test";

a.makeWord();

}

}

此方法中有几个值得注意的地方,首先是将创建代码抽取到工厂方法中,在测试子类中覆盖该工厂方法,然后令被覆盖的方法返回模仿对象。如果可以的话,添加需要原始对象的工厂方法的单元测试,以返回正确类型的对象。模仿对象方法在处理许多对象依赖基础结构的其它对象或层时, 可以起到很好的效果。模仿对象符合实际对象的接口,但只要有足够的代码来“欺骗”测试对象并跟踪其行为。例如,在单元测试中需要测试一个使用数据库的对象,或者需要测试连接J2EE 应用服务器的对象,通常的测试用例需要安装、配置和发送本地数据库副本、运行测试然后再卸装本地数据库或者需要安装、配置应用服务器、运行测试然后再卸装应用服务器,操作可能很麻烦,。模仿对象提供了解决这一困难的途径。对于既需要访问相关环境又要访问非公有变量或方法的类来说,模仿对象非常适合,但是,如果只是访问非公有变量或方法,那么传统的模仿对象法显得有些笨重,可以对该法进行简化,不使用工厂方法,达到同样的效果。

下面的代码示例演示了经过简化的模仿对象方法:

清单7. 简化的待测类 A 的模仿对象

//伪类,在运行时替换类A

public class MockA extends A{

public MockA(){

super();

s = "test";

}

}

//测试类

public class TestA extends TestCase{

public void setup(){

}

public void teardown(){

}

public void makeWordTest(){

A a = new MockA();

a.makeWord();

}

}

模仿对象方法既能消除运行环境的影响,又能解决多继承的难题,但是由于该方法使用子类的实例来替代父类的实例,对于私有成员变量及方法来说,仍然不能进行访问。

方法四:利用字节码技术

Java 编译器把Java 源代码编译成字节码bytecode(字节码),既然在测试中尽量要避免改变原来的代码,那么最直接的改造Java 类的方法莫过于直接改写class 文件。通过修改字节码中的关键字,将私有的成员变量及方法改成公有的成员变量及方法,可以做到在不改变源码的情况下访问到需要的成员变量及方法。Java 规范有class 文件的格式的详细说明,直接编辑字节码确实可以改变Java 类的行为,但是这也要求使用者对Java class 文件有较深的理解。目前,比较流行的字节码处理工具有Javassist,BCEL 和ASM 等。这几种工具各有特点,适合于不同的应用场景,如果读者对字节码技术感兴趣,可以阅读后面的参考文献。本文选择利用字节码工具ASM。

ASM 能被用来动态生成类或者修改既有类的功能。它可以直接产生二进制class 文件,也可以在类被加载入Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class 文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及Java 字节码(指令)。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类(.class)。ASM 作为Java 字节码操控框架,是所有同类工具中效率最高的一个,并且由于其采用了基于Vistor 模式的框架设计,它也是同类工具中最轻巧灵活的,尽管它的学习台阶相对要高一些,它仍然是达到本文目的的首选。利用ASM 访问私有变量及方法,需要了解的比较重要的几个类:ClassReader、ClassVistor、MethodVisitor、FieldVisitor 和ClassAdaptor 等。ClassReader 类可以直接

由字节数组或由class 文件间接的获得字节码数据,它能正确的分析字节码,通过调用accept 方法接受一个ClassVisitor 接口的实现类实例作为参数,然后依次调用ClassVisitor 接口的各个方法;ClassVisitor 接口中定义了对应Java 类各个成员的访问函数,比如visitMethod 会返回一个实现MethordVisitor 接口的实例,visitField 会返回一个实现FieldVisitor 接口的实例。不同Visitor 的组合,可以非常简单的封装对字节码的各种修改;ClassAdaptor 类为ClassVisitor 接口提供了一个默认实现。创建一个ClassAdaptor 对象实例时,需要传入一个ClassVisitor 接口的实现类实例来访问字节吗。因此当我们需要对字节码进行调整时,只需从ClassAdaptor 类派生出一个子类,覆写需要修改的方法,完成相应功能后再把调用传递到下一个需要修改的visitor 即可。

本例的应用场景为,要对公有方法method() 进行单元测试,但是,该方法中有一个私有变量number 是由另一个私有方法makePaper() 付值,所以,需要在测试中为该私有变量置初值。

清单8. 待测类A

class A{

private String number = “”;

public void method() {

if(number.eaquals(“prefix”))

System.out.println("method..."+number);

else

System.out.println(number +”is null”);

}

private void makePaper() {

number=”prefix”;

System.out.println("makePaper...");

}

}

清单9. 使用字节码访问类A

//修改变量的修饰符

public class AccessClassAdapter extends ClassAdapter {

public AccessClassAdapter(ClassVisitor cv) {

super(cv);

}

public FieldVisitor visitField(final int access, String name,

final String desc, final String signature,

final Object value) {

int privateAccess = access;

//找到名字为number的变量

if (name.equals("number"))

privateAccess = Opcodes.ACC_PUBLIC;

//修字段的修饰符为public:在职责链传递过程中替换调用参数

return cv.visitField(privateAccess, name, desc,

signature, value);

}

public static void main(String[] args) throws Exception {

ClassReader cr = new ClassReader("A");

ClassWriter cw = new ClassWriter(https://www.doczj.com/doc/9e6352029.html,PUTE_MAXS);

ClassAdapter classAdapter = new AccessClassAdapter(cw);

cr.accept(classAdapter, ClassReader.SKIP_DEBUG);

byte[] data = cw.toByteArray();

//生成新的字节码文件

File file = new File("A.class");

FileOutputStream fout = new FileOutputStream(file);

fout.write(data);

fout.close();

}

}

执行完该类,将产生一个新的A.class 文件。

测试类测试method 方法,先对变量进行置初值,然后就可以像其他单元测试一样,对method 方法进行测试。

方法对比

方法修饰符

使用难度缺陷protec

ted 缺省private

方法

一:修

改访问

权限修

饰符是是是低,有

java编程

基础即

可。

由于需要修改源代码,

虽然是同包可见,也会

带来一些封闭性的问

题。

方法

二:利

用安全

性管理

器是是是中,需要

了解java

安全性管

理器及反

射机制。

一些对代码安全有要求

的程序,程序员并没有

修改security manager

的权限,此时,安全管

理器方法失效。

方法

三:使

用模仿

对象是是否较高,需

要了解设

计模式和

待测对象

的内部实

现细节。

由于模仿对象要求伪类

必需和待测类是继承与

被继承的关系,所以当

源码以private关键字

修饰时,此方法失效。

方法

四:利

用字节

码技术是是是高,需要

操作和改

写类部分

的字节

码。

学习成本高,需要了解

Java字节码技术

总结

在进行单元测试时,我们要尽可能的考虑代码的移植性和通用性,在不修改源程序的前提下达到测试的最佳效果。对于是否应该使用以及如何使用本文中提到的四种方法,需要开发人员根据具体场合谨慎选择。

参考资料

?Dennis Sosnoski 撰写的“Classworking 工具箱”系列。

?“Java 编程的动态性”系列:作者是Dennis Sosnoski,他将带您遍历Java 类结构、反射和classworking 等。

?阅读李夷磊等撰写的文章“AOP 的利器:ASM 3.0 介绍”(developerWorks,2007 年7 月)。

?Peter Haggar 撰写的文章“Java bytecode: Understanding bytecode makes you a better programmer”(developerWorks,2001 年7 月)。

?Alexander Day Chaffee撰写的文章“使用模仿对象进行单元测试”

(developerWorks,2003年3月)。

作者简介

侯晓强,IBM 中国软件开发中心高级软件工程师,2003 年加入IBM,拥有丰富的WebSphere Business Integration 相关的产品经验,包括WebSphere Process Server, WebSphere Message Broker,WebSphere Adapters 等,目前从事WebSphere Service Registry and Repository 相关的开发工作。

杜冰冰,IBM 中国软件开发实验室SOA 设计中心软件开发工程师,主要从事SOA 相关技术的研究和相关项目的实施。

实验4:静态变量、静态方法与包

实验4:静态变量、静态方法与包实验目的 1、熟练静态变量、静态方法、实例变量、实例方法的概念 2、掌握包的概念与应用。 实验内容 一、静态变量 1.阅读下列程序,并按照要求完成后续功能。 class Point { private int x,y; Point (int xValue, int yValue) { x=xValue; y=yValue; }; public int GetX() { return x; } public int GetY() { return y; } public void SetY(int value) { y=value; } public void SetX(int value) { x=value; } } class Managerpoint { static int count=0; Point createPoint(int x,int y)

{ 提示:在此处加入代码,完成程序的输出要求 } } public class one { public static void main(String[] args) { // TODO Auto-generated method stub Managerpoint mPoint =new Managerpoint(); for(int i=0;i<9;i++){ Point p=mPoint.createPoint(i,20); System.out.print("当前点的总数为:"+Managerpoint.count); System.out.println("当前点的x值为:"+p.GetX()); } } } 注意:本例中使用的“20”仅仅是作为一个测试数据。 在提示处加入代码,要求: ●除提示处代码,其他代码保持不变 ●Main方法的执行结果为: 当前点的总数为:1当前点的x值为:0 当前点的总数为:2当前点的x值为:1 当前点的总数为:3当前点的x值为:2 当前点的总数为:4当前点的x值为:3 当前点的总数为:5当前点的x值为:4 当前点的总数为:6当前点的x值为:5 当前点的总数为:7当前点的x值为:6 当前点的总数为:8当前点的x值为:7 当前点的总数为:9当前点的x值为:8 2.改错。 理解静态方法可访问静态变量,但在静态方法中不能直接访问实例变量。 提示: 阴影处为需要修改的代码。 public class one { int x=8; int y=9; final int i=10; static int getY(){ return y; } static int getI(){ return i;

Java中的static变量、方法、代码块

1、static变量 按照是否静态的对类成员变量进行分类可分两种:一种是被static修饰的变量,叫静态变量或类变量;另一种是没有被static修饰的变量,叫实例变量。两者的区别是: 对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(方便),当然也可以通过对象来访问(但是这是不推荐的)。 对于实例变量,每创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)。 2、static方法 静态方法可以直接通过类名调用,任何的实例也都可以调用,因此静态方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法(就是不带static的成员变量和成员成员方法),只能访问所属类的静态成员变量和成员方法。因为实例成员与特定的对象关联!这个需要去理解,想明白其中的道理,不是记忆!!! 因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract。 3、static代码块 static代码块也叫静态代码块,是在类中独立于类成员的static语句块,可以有多个,位置可以随便放,它不在任何的方法体内,JVM加载类时会执行这些静态的代码块,如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次。 例子: class A{ static{ System.out.println("A static block"); // (3)运行 } { System.out.print("Q"); // (5)运行 } public A (){ System.out.println("x"); // (6)运行 } } class B extends A{ static{ System.out.println("B static block"); // (4)运行 } { System.out.print("W"); // (7)运行 }

Java 中的 static 使用之静态方法

Java 中的static 使用之静态方法 与静态变量一样,我们也可以使用 static 修饰方法,称为静态方法或类方法。其实之前我们一直写的 main 方法就是静态方法。静态方法的使用如: 需要注意: 1、静态方法中可以直接调用同类中的静态成员,但不能直接调用非静态成员。如: 如果希望在静态方法中调用非静态变量,可以通过创建类的对象,然后通过对象来访问非静态变量。如: 、在普通成员方法中,则可以直接访问同类的非静态变量和静态变量,如下所示:

3、静态方法中不能直接调用非静态方法,需要通过对象来访问非静态方法。如: ava 中的static 使用之静态初始化块 Java 中可以通过初始化块进行数据赋值。如: 在类的声明中,可以包含多个初始化块,当创建类的实例时,就会依次执行这些代码块。如果使用 static 修饰初始化块,就称为静态初始化块。 需要特别注意:静态初始化块只在类加载时执行,且只会执行一次,同时静态初始化块只能给静态变量赋值,不能初始化普通的成员变量。 我们来看一段代码:

运行结果: 通过输出结果,我们可以看到,程序运行时静态初始化块最先被执行,然后执行普通初始化块,最后才执行构造方法。由于静态初始化块只在类加载时执行一次,所以当再次创建对象 hello2 时并未执行静态初始化块。 封装 1、概念: 将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问 2、好处 a:只能通过规定的方法访问数据 b:隐藏类的实例细节,方便修改和实现。 什么是Java 中的内部类 问:什么是内部类呢? 答:内部类( Inner Class )就是定义在另外一个类里面的类。与之对应,包含内部类的类被称为外部类。 问:那为什么要将一个类定义在另一个类里面呢?清清爽爽的独立的一个类多好啊!! 答:内部类的主要作用如下:

Java静态方法、静态变量,初始化顺序

Java静态方法、静态变量、初始化顺序 成员变量分为实例变量和静态变量。其中实例变量属于某一个具体的实例,必须在类实例化后才真正存在,不同的对象拥有不同的实例变量。而静态变量被该类所有的对象公有(相当于全局变量),不需要实例化就已经存在。南京Java软件培训机构 方法也可分为实例方法和静态方法。其中,实例方法必须在类实例化之后通过对象来调用,而静态方法可以在类实例化之前就使用。与成员变量不同的是:无论哪种方法,在内存中只有一份——无论该类有多少个实例,都共用同一个方法。南京Java软件培训机构 实例方法的调用: 1.ClassA a = new ClassA(); //必须经过实例化,用对象名访问 2. a.instanceMethod(); 静态方法的调用: 1. 1. a.staticMethod(); //无需经过实例化,用类名或者对象名访问 2. 静态方法的声明和定义 定义一个静态方法和定义一个实例方法,在形式上并没有什么区别,只是在声明的头部,需要加上一个关键字static。南京Java软件培训机构 3.静态方法和实例方法的区别 静态方法和实例方法的区别主要体现在两个方面: · 在外部调用静态方法时,可以使用“类名.方法名”的方式,也可以使用“对象名.方法名”的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。 · 静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制。 实例代码:静态方法访问成员变量示例: 1.class accessMember{ 2.private static int sa; //定义一个静态成员变量 3.private int ia; //定义一个实例成员变量 4.//下面定义一个静态方法 5.static void statMethod(){ 6.int i = 0; //正确,可以有自己的局部变量 7.sa = 10; //正确,静态方法可以使用静态变量 8.otherStat(); //正确,可以调用静态方法 9.ia = 20; //错误,不能使用实例变量 10.insMethod(); //错误,不能调用实例方法 11.}

JAVA反射机制(内含大量实例)

反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。其中LEAD/LEAD++ 、OpenC++ 、MetaXa和OpenJava等就是基于反射机制的语言。最近,反射机制也被应用到了视窗系统、操作系统和文件系统中。 反射本身并不是一个新概念,它可能会使我们联想到光学中的反射概念,尽管计算机科学赋予了反射概念新的含义,但是,从现象上来说,它们确实有某些相通之处,这些有助于我们的理解。在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。可以看出,同一般的反射概念相比,计算机科学领域的反射不单单指反射本身,还包括对反射结果所采取的措施。所有采用反射机制的系统(即反射系统)都希望使系统的实现更开放。可以说,实现了反射机制的系统都具有开放性,但具有开放性的系统并不一定采用了反射机制,开放性是反射系统的必要条件。一般来说,反射系统除了满足开放性条件外还必须满足原因连接(Causally-connected)。所谓原因连接是指对反射系统自描述的改变能够立即反映到系统底层的实

际状态和行为上的情况,反之亦然。开放性和原因连接是反射系统的两大基本要素。 Java中,反射是一种强大的工具。它使您能够创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代表链接。反射允许我们在编写与执行时,使我们的程序代码能够接入装载到JVM中的类的内部信息,而不是源代码中选定的类协作的代码。这使反射成为构建灵活的应用的主要工具。但需注意的是:如果使用不当,反射的成本很高。 二、Java中的类反射: Reflection 是 Java 程序开发语言的特征之一,它允许运行中的Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pascal、C 或者 C++ 中就没有办法在程序中获得函数定义相关的信息。 1.检测类: 1.1 reflection的工作机制 考虑下面这个简单的例子,让我们看看 reflection 是如何工作的。

Java中的静态变量_静态方法_静态块与静态类

Java中的静态变量、静态方法、静态块与静态类 在Java中,static是一个关键字,我们不能用它来作为类名或包名,static主要有四种用途,即作为静态变量、静态方法、静态块和静态类。 1、静态变量Java static variables 静态变量就是类变量,它并不属于类的实例,仅属于类本身。在所有能访问该类的地方,也就可能访问或修改该变量,它是非线程安全的,因此,静态变量通常是和final关键字结合在一起,用来标识该变量是一个公共资源和常量。 只要静态变量不是private私有的,那么我们可通过ClassName.variableName的方式进行访问。 2、静态方法Java static methods 静态方法与静态变量一样,也是属于类本身而不属于类的实例对象。在一个静态方法中,除了局部变量外,它能访问的外部变量也必须是静态的,能访问的外部方法也必须是静态的,实例变量和实例方法均不能访问。

3、静态块Java static Block 静态块是由一些语句组成的段落,它在类被加载进内存时执行,且无论类被使用多少次它都只会执行一次。一个类的静态块可以有多个,其执行顺序由它在代码中的顺序决定。 4、静态类Java static methods 静态类都是内部类,static不能用于修饰顶级的类。对于单例模式用静态类来实现就是一个很不错的选择。 5、完整示例

//static variable example private static int count; //kept private to control it's value through setter public static String str; public int getCount() { return count; } //static method example public static void setCount(int count) { if(count > 0) StaticExample.count = count; } //static util method public static int addInts(int i, int...js){ int sum=i; for(int x : js) sum+=x; return sum; } //static class example - used for packaging convenience only public static class MyStaticClass{ public int count; } }

static变量和static函数的各自的特点

static变量和static函数的各自的特点 static变量大致分为三种用法 一、用于局部变量中,成为静态局部变量. 静态局部变量有两个用法,记忆功能和全局生存期. 二、用于全局变量,主要作用是限制此全局变量被其他的文件调用. 三、用于类中的成员.表示这个成员是属于这个类但是不属于类中任意特定对象 static 声明的变量. 在C语言中有两方面的特征: 1、变量会被放在程序的全局存储区中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。 2、变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。 Tips: A.若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度; B.若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度; C.设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题; D.如果我们需要一个可重入的函数,那么,我们一定

要避免函数中使用static变量(这样的函数被称为:带“内部存储器”功能的的函数) E.函数中必须要使用static变量情况:比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。 函数前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)。使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名。 扩展分析:术语static有着不寻常的历史.起初,在C中引入关键字static是为了表示退出一个块后仍然存在的局部变量。随后,static在C中有了第二种含义:用来表示不能被其它文件访问的全局变量和函数。为了避免引入新的关键字,所以仍使用static关键字来表示这第二种含义。最后,C++重用了这个关键字,并赋予它与前面不同的第三种含义:表示属于一个类而不是属于此类的任何特定对象的变量和函数(与Java中此关键字的含义相同)。

静态变量用法

JAVA的静态变量相当于类字段,而不用理解为对象字段。 java类的成员变量有俩种:一种是被static关键字修饰的变量,叫类变量或者静态变量;另一种没有static修饰,为实例变量。 在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。 在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。 静态变量位于方法区,被类的所有实例共享。静态变量可以直接通过类名进行访问,其生命周期取决于类的生命周期。 而实例变量取决于类的实例。每创建一个实例,java虚拟机就会为实例变量分配一次内存,实例变量位于堆区中,其生命周期取决于实例的生命周期。 结果为: 1 0 (成员变量具有缺省值而局部变量则没有) 把代码改为: 结果则为 1

Java中的静态变量和静态函数 静态变量: 在JAVA中类在声明的时候,其实并没有申请和产生内存空间,就如同我们的一个切实可行的想法,但其实并没有去实施这个想法。而类只有在用这种数据类型创建一个类的对象的时候,才能在内存中申请和产生类大小的内存空间,这一块内存空间是用来存放成员变量和成员函数的备份。所以在类声明的时候,是不可以对成员变量进行初始化的,只有用类创建的对象时,才能通过对象对变量初始化,SO,便产生的静态变量!!!它对所有的类对象都是很公共的,对每一个类的对象都具有相同的值。静态变量的关键字是static,它的语法是: Static<数据类型><静态变量名>=<初始化静态变量>; 静态变量在声明的时候就同时初始化,并且只能初始化一次,它有自己的变量作用域,但具有全局的生命周期,可以随时被调用。它声明的时候内存中就从开始一直保留一份值。在类的对象没有被创建之前可以使用类名调静态成员变量,它的语法是: <类名>.<静态成员变量>; 静态函数: 既然有了静态变量那就会有静态函数,静态函数只有访问静态变量,其它非静态的函数是不被允许的,但在静态成员函数中可以声明它自身的变量,它也是一个函数也具有其它函数的特性!静态函数的声明和静态变量的声明所差无几: Static<数据类型><静态函数名>(变量表); 和静态变量一样,静态函数在声明的时候就在内存中存在(即使没有创建对象这和其它的非静态函数是不一样的),也具有全局的生命周期。 下面给出一个静态函数和静态变量的例子: import java.io.*; //导入io流 public class Text_Static { int iNum1; static int iNum2; Text_Static(int iNum1,int iNum2) { this.iNum1=iNum1; this.iNum2=iNum2; this.iNum1++; this.iNum2++; } public void Display1(String str)

一个例子让你了解Java反射机制

一个例子让你了解Java反射机制 JAVA反射机制: 通俗地说,反射机制就是可以把一个类,类的成员(函数,属性),当成一个对象来操作,希望读者能理解,也就是说,类,类的成员,我们在运行的时候还可以动态地去操作他们. 理论的东东太多也没用,下面我们看看实践 Demo ~ Demo: 1.package cn.lee.demo; 2. 3.import https://www.doczj.com/doc/9e6352029.html,ng.reflect.Constructor; 4.import https://www.doczj.com/doc/9e6352029.html,ng.reflect.Field; 5.import https://www.doczj.com/doc/9e6352029.html,ng.reflect.InvocationTargetException; 6.import https://www.doczj.com/doc/9e6352029.html,ng.reflect.Method; 7.import https://www.doczj.com/doc/9e6352029.html,ng.reflect.Modifier; 8.import https://www.doczj.com/doc/9e6352029.html,ng.reflect.TypeVariable; 9. 10.public class Main { 11. /** 12. * 为了看清楚Java反射部分代码,所有异常我都最后抛出来给虚拟机处 理! 13. * @param args 14. * @throws ClassNotFoundException 15. * @throws InstantiationException 16. * @throws IllegalAccessException 17. * @throws InvocationTargetException 18. * @throws IllegalArgumentException 19. * @throws NoSuchFieldException 20. * @throws SecurityException 21. * @throws NoSuchMethodException 22. */

C++静态成员变量和静态成员函数

数据成员可以分静态变量、非静态变量两种. 静态成员:静态类中的成员加入static修饰符,即是静态成员.可以直接使用类名+静态成员名访问此静态成员,因为静态成员存在于内存,非静态成员需要实例化才会分配内存,所以静态成员不能访问非静态的成员..因为静态成员存在于内存,所以非静态成员可以直接访问类中静态的成员. 非静态成员:所有没有加Static的成员都是非静态成员,当类被实例化之后,可以通过实例化的类名进行访问..非静态成员的生存期决定于该类的生存期..而静态成员则不存在生存期的概念,因为静态成员始终驻留在内存中.. 一个类中也可以包含静态成员和非静态成员,类中也包括静态构造函数和非静态构造函数.. 分两个方面来总结,第一方面主要是相对于面向过程而言,即在这方面不涉及到类,第二方面相对于面向对象而言,主要说明static在类中的作用。 一、在面向过程设计中的static关键字 1、静态全局变量 定义:在全局变量前,加上关键字static 该变量就被定义成为了一个静态全局变量。 特点: A、该变量在全局数据区分配内存。 B、初始化:如果不显式初始化,那么将被隐式初始化为0(自动变量是随机的,除非显式地初始化)。 C、访变量只在本源文件可见,严格的讲应该为定义之处开始到本文件结束。 例(摘于C++程序设计教程---钱能主编P103)://file1.cpp //Example 1 #include void fn(); static int n; //定义静态全局变量 void main() { n=20; cout <

深入理解Java反射机制汇总

深入理解Java反射机制 本文较为详细的分析了Java反射机制。分享给大家供大家参考,具体如下: 一、预先需要掌握的知识(java虚拟机) java虚拟机的方法区: java虚拟机有一个运行时数据区,这个数据区又被分为方法区,堆区和栈区,我们这里需要了解的主要是方法区。方法区的主要作用是存储被装载的类的类型信息,当java虚拟机装载某个类型的时候,需要类装载器定位相应的class文件,然后将其读入到java虚拟机中,紧接着虚拟机提取class 中的类型信息,将这些信息存储到方法区中。这些信息主要包括: 1、这个类型的全限定名 2、这个类型的直接超类的全限定名 3、这个类型是类类型还是接口类型 4、这个类型的访问修饰符 5、任何直接超接口的全限定名的有序列表 6、该类型的常量池 7、字段信息 8、方法信息 9、除了常量以外的所有类变量 10、一个到class类的引用 等等(读者可以参考《深入java虚拟机》这本书的叙述) Class类: Class类是一个非常重要的java基础类,每当装载一个新的类型的时候,java虚拟机都会在java堆中创建一个对应于新类型的Class实例,该实例就代表此类型,通过该Class实例我们就可以访问该类型的基本信息。上面说到在方法区中会存储某个被装载类的类型信息,我们就可以通过Class实例来访问这些信息。比如,对于上面说到的信息Class中都有对应的方法,如下:

1、getName();这个类型的全限定名 2、getSuperClass();这个类型的直接超类的全限定名 3、isInterface();这个类型是类类型还是接口类型 4、getTypeParamters();这个类型的访问修饰符 5、getInterfaces();任何直接超接口的全限定名的有序列表 6、getFields();字段信息 7、getMethods();方法信息 等等(读者可以自己参看jdk帮助文档,得到更多的信息) 二、java反射详解 反射的概念:所谓的反射就是java语言在运行时拥有一项自观的能力,反射使您的程序代码能够得到装载到JVM中的类的内部信息,允许您执行程序时才得到需要类的内部信息,而不是在编写代码的时候就必须要知道所需类的内部信息,这使反射成为构建灵活的应用的主要工具。 反射的常用类和函数:Java反射机制的实现要借助于4个类:Class,Constructor,Field,Method;其中class代表的是类对象,Constructor-类的构造器对象,Field-类的属性对象,Method -类的方法对象,通过这四个对象我们可以粗略的看到一个类的各个组成部分。其中最核心的就是Class类,它是实现反射的基础,它包含的方法我们在第一部分已经进行了基本的阐述。应用反射时我们最关心的一般是一个类的构造器、属性和方法,下面我们主要介绍Class 类中针对这三个元素的方法: 1、得到构造器的方法 Constructor getConstructor(Class[] params) -- 获得使用特殊的参数类型的公共构造函数,Constructor[] getConstructors() -- 获得类的所有公共构造函数 Constructor getDeclaredConstructor(Class[] params) -- 获得使用特定参数类型的构造函数(与接入级别无关) Constructor[] getDeclaredConstructors() -- 获得类的所有构造函数(与接入级别无关) 2、获得字段信息的方法

静态成员函数一般情况下只能访问静态成员变量

静态成员函数一般情况下只能访问静态成员变量,因为不接受隐含的this指针。另外作为类的静态成员函数,不用声明对象,便可直接调用,例如类A的静态成员函数fun(); A::fun(); 1、主要用于封装全局变量和全局函数。以避免在文件作用域内包含带外部连接的数据。 例如全局变量:int path;int para1; 解决办法:设计一个全局类,并将这些全局名称声明为静态变量,并编写静态函数来调用这些变量。 class Global{ static int s_path; static int s_para; private: Global();//不实现,避免无意中的实例化 public: //manipulators static void setPath(int path){s_path = path;} static void setPara(int para){s_para = para;} //accessors static int getPath(){return s_path;} static int getPara(){return s_para;} } 2、对自由函数的封装 在.h文件的文件作用域内避免使用自由函数(运算符函数除外);在.c文件中避免使用带有外部连接的自由函数,因此可以使用静态成员函数进行处理。 例如:int getPara();int getPath();我们可以通过声明一个结构的静态方法代替: struct SysUtil{ static int getPath(); static int getPara(); }这样,唯一有冲突危险的就是出现类名SysUtil了。

Java中类反射机制基本原理

Java中的类反射机制 一、反射的概念 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。其中LEAD/LEAD++ 、Open C++ 、Meta Xa和Open Java等就是基于反射机制的语言。最近,反射机制也被应用到了视窗系统、操作系统和文件系统中。 反射本身并不是一个新概念,它可能会使我们联想到光学中的反射概念,尽管计算机科学赋予了反射概念新的含义,但是,从现象上来说,它们确实有某些相通之处,这些有助于我们的理解。在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。可以看出,同一般的反射概念相比,计算机科学领域的反射不单单指反射本身,还包括对反射结果所采取的措施。所有采用反射机制的系统(即反射系统)都希望使系统的实现更开放。可以说,实现了反射机制的系统都具有开放性,但具有开放性的系统并不一定采用了反射机制,开放性是反射系统的必要条件。一般来说,反射系统除了满足开放性条件外还必须满足原因连接(Causally-connected)。所谓原因连接是指对反射系统自描述的改变能够立即反映到系统底层的实际状态和行为上的情况,反之亦然。开放性和原因连接是反射系统的两大基本要素。 Java中,反射是一种强大的工具。它使您能够创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代表链接。反射允许我们在编写与执行时,使我们的程序代码能够接入装载到JVM中的类的内部信息,而不是源代码中选定的类协作的代码。这使反射成为构建灵活的应用的主要工具。但需注意的是:如果使用不当,反射的成本很高。 二、Java类反射 Reflection 是Java 程序开发语言的特征之一,它允许运行中的Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pascal、C 或者C++ 中就没有办法在程序中获得函数定义相关的信息。 1.检测类 1.1 reflection的工作机制 考虑下面这个简单的例子,让我们看看reflection 是如何工作的。 import https://www.doczj.com/doc/9e6352029.html,ng.reflect.*; public class DumpMethods { public static void main(String args[]) { try { Class c = Class.forName(args[0]); Method m[] = c.getDeclaredMethods(); for (int i = 0; i < m.length; i++) System.out.println(m[i].toString()); } catch (Throwable e) { System.err.println(e); }

java反射机制详解与应用

java有着一个非常突出的动态相关机制:Reflection。这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods1。这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。Reflection和introspection是常被并提的两个术语。 这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等等)、superclass(例如Object)、实现之interfaces (例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。 目前好多框架都会用到java的反射机制。比如struts2,sping,hibernate。 如果我们不用struts2,自己写一个类似的功能也是可以实现的,比如浏览器通过HTTP发送数据,而这些数据都是字符串,我们接受到这些字符串时,可以通过反射去构造一个对象(通过拦截器做成框架的功能),这样就可以用对象的get和set方法了,而不用原始的getPeremter 方法。事实上,在struts2出来之前,我们又不想用struts1的ActionForm就做过这样项目。 一、Class object 的产生方式有以下几种。 1、运用getClass() 注:每个class 都有此函数 String str = "abc"; Class c1 = str.getClass(); 2、运用static method Class.forName()(最常被使用) Class c1 = Class.forName ("https://www.doczj.com/doc/9e6352029.html,ng.String"); Class c2 = Class.forName ("java.awt.Button"); 3、运用.class 语法 Class c1 = String.class; Class c2 = java.awt.Button.class; 4、运用primitive wrapper classes的TYPE 语法 Class c1 = Integer.TYPE; Class c2 = Long.TYPE; 二、Java类反射中的主要方法 对于以下三类组件中的任何一类来说-- 构造函数、字段和方法-- https://www.doczj.com/doc/9e6352029.html,ng.Class 提供四种

static静态变量的理解

C语言中,static的字面意思很容易把我们导入歧途,其实它的作用有三条。(1)先来介绍它的第一条也是最重要的一条:隐藏。 当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性。为理解这句话,我举例来说明。我们要同时编译两个源文件,一个是a.c,另一个是main.c。 下面是a.c的内容 char a = 'A'; // global variable void msg() { printf("Hello\n"); } 下面是main.c的内容 int main(void) { extern char a; // extern variable must be declared before use printf("%c ", a); (void)msg(); return 0; } 程序的运行结果是: A Hello 你可能会问:为什么在a.c中定义的全局变量a和函数msg能在main.c中使用?前面说过,所有未加static前缀的全局变量和函数都具有全局可见性,其它的源文件也能访问。此例中,a是全局变量,msg是函数,并且都没有加static 前缀,因此对于另外的源文件main.c是可见的。 如果加了static,就会对其它源文件隐藏。例如在a和msg的定义前加上static,main.c就看不到它们了。利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。Static可以用作函数和变量的前缀,对于函数来讲,static的作用仅限于隐藏,而对于变量,static还有下面两个作用。(2)static的第二个作用是保持变量内容的持久。存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。共有两种变量存储在静态存储区:全局变量和static变量,只不过和全局变量比起来,static可以控制变量的可见范围,说到底static还是用来隐藏的。虽然这种用法不常见,但我还是举一个例子。 #include int fun(void){ static int count = 10; // 事实上此赋值语句从来没有执行过 return count--; } int count = 1; int main(void) { printf("global\t\tlocal static\n"); for(; count <= 10; ++count)

C_静态方法与非静态方法的比较(精辟易懂)

C#静态方法与非静态方法的比较 C#的类中可以包含两种方法:C#静态方法与非静态方法。那么他们的定义有什么不同呢?他们在使用上会有什么不同呢?让我们来看看最直观的差别:使用了static 修饰符的方法为静态方法,反之则是非静态方法。 下面我们分四个方面来看看C#静态方法与非静态方法的差异: C#静态方法与非静态方法比较一、C#静态成员: ①静态成员属于类所有,非静态成员属于类的实例所有。 ②每创建一个类的实例,都会在内存中为非静态成员新分配一块存储; 非静态成员属于类所有,为各个类的实例所公用,无论类创建了多少实例, 类的静态成员在内存中只占同一块区域。 C#静态方法与非静态方法比较二、C#静态方法 1、C#静态方法属于类所有,类实例化前即可使用。 2、非静态方法可以访问类中的任何成员,静态方法只能访问类中的静态成员。 3、因为静态方法在类实例化前就可以使用,而类中的非静态变量必须在实例化之后才能分配内存, 这样,C#静态方法调用时无法判断非静态变量使用的内存地址,所以无法使用。而静态变量的地址对类来说是固定的,故可以使用。 C#静态方法与非静态方法比较三、C#静态方法是一种特殊的成员方法 它不属于类的某一个具体的实例,而是属于类本身。所以对静态方法不需要首先创建一个类的实例,而是采用类名.静态方法的格式。 1.static方法是类中的一个成员方法,属于整个类,即不用创建任何对象也可以直接调用!

static内部只能出现static变量和其他static方法!而且static方法中还不能使用this....等关键字..因为它是属于整个类! 2.静态方法效率上要比实例化高,静态方法的缺点是不自动进行销毁,而实例化的则可以做销毁。 3.静态方法和静态变量创建后始终使用同一块内存,而使用实例的方式会创建多个内存. 4.C#中的方法有两种:实例方法,静态方法. C#静态方法与非静态方法比较四、C#静态方法中获取类的名称 静态方法中用: string className = System.Reflection.MethodBase. GetCurrentMethod().ReflectedType.FullName; 非静态方法中还可以用: string className = this.GetType().FullName; C#静态方法与非静态方法的区别解析旨在诠释C#静态方法的含义,希望对你了解和学习C#静态方法与非静态方法有所帮助。

Java反射访问私有变量和私有方法

Java反射访问私有变量和私有方法 引言 对于软件开发人员来说,单元测试是一项必不可少的工作。它既可以验证程序的有效性,又可以在程序出现BUG 的时候,帮助开发人员快速的定位问题所在。但是,在写单元测试的过程中,开发人员经常要访问类的一些非公有的成员变量或方法,这给测试工作带来了很大的困扰。本文总结了访问类的非公有成员变量或方法的四种途径,以方便测试人员在需要访问类非公有成员变量或方法时进行选择。 尽管有很多经验丰富的程序员认为不应该提倡访问类的私有成员变量或方法,因为这样做违反了Java 语言封装性的基本规则。然而,在实际测试中被测试的对象千奇百怪,为了有效快速的进行单元测试,有时我们不得不违反一些这样或那样的规则。本文只讨论如何访问类的非公有成员变量或方法,至于是否应该在开发测试中这样做,则留给读者自己根据实际情况去判断和选择。 方法一:修改访问权限修饰符 先介绍最简单也是最直接的方法,就是利用Java 语言自身的特性,达到访问非公有成员的目的。说白了就是直接将private 和protected 关键字改为public 或者直接删除。我们建议直接删除,因为在Java 语言定义中,缺省访问修饰符是包可见的。这样做之后,我们可以另建一个源码目录——test 目录(多数IDE 支持这么做,如Eclipse 和JBuilder),然后将测试类放到test 目录相同包下,从而达到访问待测类的成员变量和方法的目的。此时,在其它包的代码依然不能访问这些变量或方法,在一定程度上保障了程序的封装性。 下面的代码示例展示了这一方法。 清单1. 原始待测类 A 代码 public class A { private String name = null; private void calculate() { } }

PHP类的静态(static)方法和静态(static)变量使用介绍

PHP类的静态(static)方法和静态(static)变量使用介绍 在php中,访问类的方法/变量有两种方法: 1. 创建对象$object = new Class(),然后使用”->”调用:$object->attribute/function,前提是该变量/方法可访问。 2. 直接调用类方法/变量:class::attribute/function,无论是静态/非静态都可以。但是有前提条件: A. 如果是变量,需要该变量可访问。 B. 如果是方法,除了该方法可访问外,还需要满足: b1) 如果是静态方法,没有特殊条件; b2) 如果是非静态方法,需要改方法中没有使用$this,即没有调用非静态的变量/方法,当然,调用静态的变量/方法没有问题。然后我们再看一下使用$object->…和使用class::…都有什么区别: 1. 使用$object->…,需要执行构造函数创建对象; 2. 使用class::…调用静态方法/变量,不需要执行构造函数创建对象; 3. 使用class::…调用非静态方法/变量,也不需要执行构造函数创建对象。然后奇怪的地方就出来了,既然2和3都一样,那静态方法/变量存在还有什么意义呢? 差异还是显然存在的,如下: 1. 静态变量

静态成员只保留一个变量值,而这个变量值对所有的实例都是有效,也就是说,所有的实例共享这个成员。 2. 静态方法 静态方法可以直接使用class::…来调用,而非静态方法需要满足一定限制条件才能使用class::.. 的方法调用,如之前所述 您可能感兴趣的文章:php静态文件生成类实例分析基于PHP 静态类的原罪详解PHP静态类PHP 面向对象程序设计(oop)学习笔记(二) - 静态变量的属性和方法及延迟绑定php中的静态变量的基本用法PHP static局部静态变量和全局静态变量总结php中static静态变量的使用方法详解php 静态变量的初始化php中静态类与静态变量用法的区别分析

相关主题
文本预览
相关文档 最新文档