java访问私有元素

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

引言

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

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

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

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

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

清单 原始待测类 A 代码

public class A {    private String name = null;    private void calculate() {    }}

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

public class A {    String name = null;    private void calculate() {    }}

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

方法二 利用安全管理器

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

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

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

//获得指定变量的值

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 来禁用访问控制检查 从而使得该变量可以被其他类调用 我们可以在我们所写的类中 扩展一个普通的基本类 java lang reflect AccessibleObject 类 这个类定义了一种 setAccessible 方法 使我们能够启动或关闭对这些类中其中一个类的实例的接入检测 这种方法的问题在于如果使用了安全性管理器 它将检测正在关闭接入检测的代码是否允许这样做 如果未经允许 安全性管理器抛出一个例外

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

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

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[ ];

args[ ] = 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 = ; i args length; i++) {

if (args[i] != null) {

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

}

}

}

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

}

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

另一种方法

package test;

import java lang reflect Field;

import model Dept;

public class TypeTest {

public static void main(String args[])

{

Dept d=new Dept();

d setDeptNo( );

d setDName( v );

d setLoc( mopish );

delete(d Dept class);

}

public static void delete(Object obj Class? clazz)

{

try

{

System out println( ? +(obj instanceof Dept));

System out println(clazz getName());

System out println(clazz getDeclaredFields() length);

for(Field f: clazz getDeclaredFields())

{

f setAccessible(true);

System out println(f getName());

System out println( +f get(obj));

}

}catch(Exception e)

{

e printStackTrace();

}

}

}

package model;

public class Dept {

private long deptNo;

private String DName;

private String Loc;

public long getDeptNo() {

return deptNo;

}

public void setDeptNo(long deptNo) {

this deptNo = deptNo;

}

public String getDName() {

return DName;

}

public void setDName(String dName) {

DName = dName;

}

public String getLoc() {

return Loc;

}

public void setLoc(String loc) {

Loc = loc;

}

lishixinzhi/Article/program/Java/hx/201311/26190

java private私有属性怎么在子类中访问

private属性是私有的,在子类是无法访问的。如果必须要访问,可以采用反射的方法,获取父类的class,然后拿到field,再然后setAccessible=true来进行访问。

java里一个私有的属性如何在其他类里面进行访问?

既然是私有属性就不建议直接访问的,一般会提供方法来访问私有属性,这样可以在方法中对属性的访问做一些控制。

当然也可以通过反射来直接访问。

我们准备一个包含私有属性的类

然后通过反射来访问属性,记得一定要加aField.setAccessible(true);这句代码,不然就不能访问私有属性。

不加aField.setAccessible(true);

加了aField.setAccessible(true);

java访问私有元素

java 如何访问类中的私有变量

不能,私有就是只能本类对象及方法访问。

当然,父类里面定义了set

get方法,子类必须通过这些方法可以间接访问到它们。

java 可以访问父类的私有属性吗

不可以。

私有属性(private)只能当前类才能调用,子类无法访问。

本文来自投稿,不代表【】观点,发布者:【

本文地址: ,如若转载,请注明出处!

举报投诉邮箱:253000106@qq.com

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2024年3月25日 07:27:16
下一篇 2024年3月25日 07:33:52

相关推荐

  • laravel调用java服务,laravel use

    amh不支持部署laravel框架么 它由两个主要部分组成:WEB服务器允许从一个原则的JavaScript跟着AJAX的Servlet(小应用程序)来获得,另一方面数据的JavaScript库,可以帮助Web开发人员能够轻松地采取收购优势。数据,以动态地改变网页的内容。 Composer安装完成后,下载最新版Laravel框架,把它解压缩到你服务器上的一个…

    2024年5月18日
    2900
  • java访问控制修饰符,java中访问控制修饰符

    java中类成员的访问修饰符有哪些 1、成员变量修饰符:(1)public(公共访问控制符),指定该变量为公共的,他可以被任何对象的方法访问。(2)private(私有访问控制符)指定该变量只允许自己的类的方法访问,其他任何类(包括子类)中的方法均不能访问。 2、一:访问修饰符:省略访问修饰符 具有默认的访问特性,即具有包访问特性,只能被同一个包中的类使用。…

    2024年5月18日
    3600
  • ios推送java,IOS推送服务

    Java服务器端如何接收IOS远程推送传递来的devicetoken 只要可以接受到推送消息就可以获取到deviceToken,那么就需要推送证书打包,并且uexWidget.setPushState(1),还要在应用提示“**想给您发送推送通知”时,点“好”。 iOS开发怎么实现消息推送机制,操作的方法如下:首先应用程序要注册好消息推送。IOS跟服务器设备…

    2024年5月18日
    3000
  • java构造list,java构造领接表

    java中List的用法?尽量详细解释,包括例子。 1、采用循环的方法。通过循环第一个ArrayList,然后通过每循环一次的方式,将值赋值给另一个ArrayList。具体代码实现如下:采用ArrayList自带的addAll()方法。 2、LinkedListLei();这样list就只能add Lei 类型的对象,list.get(int i)获得的也是…

    2024年5月18日
    3200
  • java接口变量finall,JAVA变量

    java中Finally到底起的是什么作用??? 无论是否抛出异常,finally代码块总是会被执行。就算是没有catch语句同时又抛出异常的情况下,finally代码块仍然会被执行。最后要说的是,finally代码块主要用来释放资源,比如:I/O缓冲区,数据库连接。 Finally是一个副词,表示最终或最后。常用于描述某件事物经过长时间或多次努力之后得到实…

    2024年5月18日
    4200
  • java异常继承图,JAVA继承的好处

    请问这两个java类图怎么看,里面的箭头哪个表示继承,哪个表示关联,关联… https:// 如果你需要有偿辅导服务的话,也可以私信我。 泛化/继承(Generalization):实线+三角形空心 相当于类继承,父参与者可以是抽象的,即不能创建一个父参与者的直接实例,这就要求属于抽象父参与者的外部对象一定能够属于其子参与者之一。 在Java中继…

    2024年5月18日
    3800
  • 关于上海5年java的信息

    java工资一般多少 1、以北京为例:北京的Java程序员的月平均工资为一万元左右,应届毕业生的月平均工资为五千元左右,工作年限越长,经验越多,能力越强,职位越高,工资也会越多。 2、初级java工程师:待遇一般在4000以上,8000以下。工作两年以内。中级java工程师:待遇一般是在8000-10000左右,工作5年以内 高级java工程师:待遇1000…

    2024年5月18日
    3500
  • 查看java安装路径linux,查看java安装路径命令

    linux查看java进程命令? 1、jstack:Java提供的命令。可以查看某个进程的当前线程栈运行情况。根据这个命令的输出可以定位某个进程的所有线程的当前运行状态、运行代码,以及是否死锁等等。 pstack:Linux命令。 2、没有“应该显示几个”的规定,运行了几个就是几个。这一大堆内容是一个java进程,可执行文件是/jdk0_144/bin/ja…

    2024年5月18日
    3900
  • c语言打印数组,C语言打印数组每个元素

    C语言,指针数组:怎么把arr[1]以%d的格式打印出来? 1、而 int p={a,b} 的问题在于,它应该是指向整型指针,而不是整型指针数组。 2、格式说明符:规定了相应输出表列内容的输出格式,以%打头,如%d、%o等 转义字符:用来输出转义字符所代表的控制代码或者特殊字符,比如常用的‘\n、‘\t普通字符:需要原样输出的字符。 3、指针传递的实质就是传…

    2024年5月18日
    5300
  • java日历框包,用java编写日历添加窗口

    用java做一个日历显示数据功能,在页面上显示日期数据。 主要功能包括显示当月的日历表,当日特殊显示。一定要用JAVA语言写。谢谢了eryaruoshui@12com… 主要功能包括显示当月的日历表 ,当日特殊显示。 一定要用JAVA语言写。 一个就是用了java.awt和javax.swing的,应该是叫JAVA桌面应用程序吧。日历是能做出来,…

    2024年5月18日
    3600

发表回复

登录后才能评论



关注微信