java反射访问私有方法的的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java反射访问私有方法的的问题相关的知识,希望对你有一定的参考价值。

LeverageUtil lv =new LeverageUtil();
Class a = lv.getClass();
Method b = a.getDeclaredMethod("isPoXlfICE", new Class[]boolean.class);
b.setAccessible(true);
b.invoke(a.newInstance(),new Object[]null);
这是我写的反射机制访问另一个类的私有方法的代码,代码本身没问题,但在用的时候老是提示The method b is undefined for the type Class,method是private static boolean类型

java的反射可以绕过访问权限,访问到类的私有方法和成员。可能这点会引起安全性的讨论。反射的使用帮助解决很多复杂的问题,其运行时的类型检查,动态调用,代理的实现等,反射为我们写程序带来了很大的灵活性,很多功能都是基于反射。
利用反射还可以访问内部类、匿名内部类的私有属性。
用java自带的java -private 类名 反编译命令可以查看类的完整定义。(参考think in java)
下面举例子说明。首先定义一个接口
Java代码
public interface Ref
public void f();

public interface Ref
public void f();

接口的实现类
Java代码
public class RefImpl implements Ref
//实现接口方法
public void f()
System.out.println("public method f()");


void g(String args)
System.out.println("package method g():" + args);


private void w()
System.out.println("private method w()");


public class RefImpl implements Ref
//实现接口方法
public void f()
System.out.println("public method f()");


void g(String args)
System.out.println("package method g():" + args);


private void w()
System.out.println("private method w()");


测试类
Java代码
public class TestRef

public static void main(String[] args)
Ref ref = new RefImpl();
System.out.println(ref.getClass().getSimpleName()); //RefImpl类型
ref.f(); //调用接口方法
// ref.g(); //向上转型后实现类添加的方法不能调用
if(ref instanceof RefImpl)
RefImpl ref1 = (RefImpl)ref; //类型识别后转型
ref1.g("zhouyang");
// ref1.w(); //私有方法不能访问


//通过反射调用方法
try
Ref ref2 = new RefImpl();
Method m = ref2.getClass().getDeclaredMethod("f");
Method m1 = ref2.getClass().getDeclaredMethod("g", String.class);//有参的方法
Method m2 = ref2.getClass().getDeclaredMethod("w");
System.out.println("==============");
m.invoke(ref); //调用方法f()
m1.invoke(ref, "yangzhou");

m2.setAccessible(true);///调用private方法的关键一句话
m2.invoke(ref);
catch (Exception e)
e.printStackTrace();


//java的javap反编译能够查看类的信息,-private 开关能够打开所有信息
//javap -private 类名 类必须是编译成.calss 文件

//利用反射访问私有成员,改变私有成员值,但是final域可以访问不可改变
PrivateField pf = new PrivateField();
// ps.ss; //私有成员不能访问
//打印原来的成员值
pf.print();
try
//反射访问和改变原来值
Field[] f = pf.getClass().getDeclaredFields();
for(int i=0;i<f.length;i++)
f[i].setAccessible(true);
System.out.println(f[i].getType());//打印字段类型
System.out.println(f[i].get(pf)); //打印值
if("ss".equals(f[i].getName()))
f[i].set(pf, "hehe"); //修改成员值
else
f[i].setInt(pf, 55);



//重新打印修改后的成员值,final域值不变
pf.print();
catch (Exception e)
e.printStackTrace();

/*打印输出的结果
* RefImpl
public method f()
&nb
参考技术A Java反射之访问私有属性或方法

AccessibleObject类是Field、Method、和Constructor对象的基类。它提供了将反射的对象标记为在使用时取消默认Java语言访问控制检查的能力。对于公共成员、默认(打包)访问成员、受保护成员和私有成员,在分别使用Field、Method和Constructor对象来设置或获得字段、调用方法,或者创建和初始化类的新实例的时候,会执行访问检查。

当反射对象的accessible标志设为true时,则表示反射的对象在使用时应该取消Java语言访问检查。反之则检查。由于JDK的安全检查耗时较多,所以通过setAccessible(true)的方式关闭安全检查来提升反射速度。

举例代码:
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
* 用Java反射机制来调用private方法
* @author pieryon
*
*/

public class Reflect

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

//直接创建对象
Person person = new Person();

Class<?> personType = person.getClass();

//访问私有方法
//getDeclaredMethod可以获取到所有方法,而getMethod只能获取public
Method method = personType.getDeclaredMethod("say", String.class);

//抑制Java对访问修饰符的检查
method.setAccessible(true);

//调用方法;person为所在对象
method.invoke(person, "Hello World !");

//访问私有属性
Field field = personType.getDeclaredField("name");

field.setAccessible(true);

//为属性设置值;person为所在对象
field.set(person, "WalkingDog");

System.out.println("The Value Of The Field is : " + person.getName());




//JavaBean
class Person
private String name;

//每个JavaBean都应该实现无参构造方法
public Person()

public String getName()
return name;


private void say(String message)
System.out.println("You want to say : " + message);

参考技术B 静态,用另一个取反射的方法



Class c;
Method m = c.getMethod("method name", new Class[] int.class, int.class, int.class,int.class);
m.invoke(c, new Object[] 1,2, 3, 4);追问

为什么会提示b没有定义呢?

追答

LeverageUtil lv =new LeverageUtil();
Class a = lv.getClass();
Method b = a.getDeclaredMethod("isPoXlfICE", new Class[]boolean.class);
b.setAccessible(true);
b.invoke(a, new Object[]false); //boolean 不支持null。Boolean则可以

追问

如果a方法有三个参数的话invoke只加一个false可以吗? 多谢了

追答

不可以的,一定要对应(个数、类型都相等)。

本回答被提问者采纳

如何限制开发人员使用反射访问Java中的私有方法和构造函数?

【中文标题】如何限制开发人员使用反射访问Java中的私有方法和构造函数?【英文标题】:How to restrict developers to use reflection to access private methods and constructors in Java? 【发布时间】:2011-11-25 20:50:00 【问题描述】:

如何限制开发者使用反射访问Java中的私有方法和构造函数?

使用普通的 Java 代码,我们无法访问类之外的私有构造函数或私有方法。但是通过使用反射,我们可以访问 Java 类中的任何私有方法和构造函数。

那么我们怎样才能为我们的 Java 代码提供安全性呢?

【问题讨论】:

这对于签名的 jar 来说是一个不错的选择。 “在任何情况下,都不允许对此 jar 文件中的类进行反射”。但我认为,没有这样的功能。 【参考方案1】:

使用SecurityManager 和足够严格的security policy 运行您的应用程序。

short summary in the tutorial 有一个the security documentation 和大量信息。

【讨论】:

【参考方案2】:

在所有私有方法/构造函数中添加 checkPermission() 方法。 通过断言callerClass=selfClass 使用sun.reflect.Reflection.getCallerClass(int n) 检查权限。

getCallerClass 返回方法 realFramesToSkip 的类在堆栈中向上帧(从零开始),忽略与 java.lang.reflect.Method.invoke() 及其实现相关的帧。第一帧是与此方法关联的帧,因此getCallerClass(0) 返回sun.reflect.Reflection 的Class 对象。

public class PrivateConstructorClass 

    private PrivateConstructorClass() 
        checkPerMission();
              //you own code go below
    

    void checkPerMission() 
        Class self = sun.reflect.Reflection.getCallerClass(1);
        Class caller = sun.reflect.Reflection.getCallerClass(3);
        if (self != caller) 
            throw new java.lang.IllegalAccessError();
        
    

你可以试试reflect,会失败:

public class TestPrivateMain 

    Object newInstance() throws Exception 

        final Class<?> c = Class.forName("package.TestPrivate");

        final Constructor<?> constructor = c.getDeclaredConstructor();
        constructor.setAccessible(true);
        return constructor.newInstance();

    

    public static void main(String[] args) throws Exception 
        Object t = new TestPrivateMain().newInstance();
    
 

【讨论】:

嗯...但在我看来确实是一个很好的尝试。不稳定的 API 一开始就不应该存在【参考方案3】:

您(作为相关代码的开发者)不能这样做。

运行应用程序的最终用户可以安装一个禁止反射的 SecurityManager。

【讨论】:

他当然可以。他在应用程序启动期间安装了安全管理器。 除非他是应用程序的开发者,否则这不是一个选项。我更多地考虑了他“希望限制开发人员 [可能是应用程序的] 使用反射”来反对他希望保持私有的方法的情况。 是什么阻止他在他的类中使用静态初始化程序来安装安全管理器?并且ofc会抛出一个异常,防止class laoding,如果他不能安装呢?

以上是关于java反射访问私有方法的的问题的主要内容,如果未能解决你的问题,请参考以下文章

Java-利用反射访问类的私有(private)属性及方法&private的意义

Java-利用反射访问类的私有(private)属性及方法&private的意义

为啥 Java 反射 API 允许我们访问私有和受保护的字段和方法?这不会破坏访问修饰符的目的吗? [复制]

Java中是不是可以通过反射访问私有字段[重复]

java反射基础知识

java反射机制可以调用到私有方法,是否就破坏了JAVA的卦装性呢。