完全折衷了对纯java中方法的受限访问,使用了为什么这是可能的

  • 本文关键字:受限访问 java 方法 java reflection
  • 更新时间 :
  • 英文 :


我完全困惑了——我用Java8SE写了一个类(不到10行代码),它完全折衷了使用反射的受限(私有)方法。我发现这是非常危险的,并质疑允许这样做的反思意识。

package reflection;
import java.lang.reflect.Method;
import java.util.Arrays;
public class Reflection {
    //  Throw 'Throwable' because this method must be totally transparent, doing exactly what the actually called method does:
    static public Object call(Object target, String methodName, Object... args) throws Throwable {
        // Get the arguments' classes:
        Class<?>[] argumentClasses =
                Arrays.asList(args)
                    .stream()
                    .map(object -> object.getClass())
                    .toArray(Class[]::new);
        Method method = target.getClass().getDeclaredMethod(methodName, argumentClasses);
        method.setAccessible(true);
        return method.invoke(target, args);
    }
}

您可以运行这个测试,它调用另一个类Action:的私有方法,包括静态和非静态方法

package reflection;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class ReflectionUnitTest {
    @Test
    public void testCall() throws Throwable {
        Action target = new Action();
        assertEquals("Something static done!", Reflection.call(target, "doSomethingStatic"));
        assertEquals("Something static done with something else!", Reflection.call(target, "doSomethingStatic", "something else"));
        assertEquals("Something static done 3 times with something else!", Reflection.call(target, "doSomethingStatic", 3, "something else"));
        assertEquals("Something static done 5 times with something else!", Reflection.call(target, "doSomethingStatic", "something else", 5));
        assertEquals("Something done!", Reflection.call(target, "doSomething"));
        assertEquals("Something done with something else!", Reflection.call(target, "doSomething", "something else"));
        assertEquals("Something done 3 times with something else!", Reflection.call(target, "doSomething", 3, "something else"));
        assertEquals("Something done 5 times with something else!", Reflection.call(target, "doSomething", "something else", 5));
    }
}

package reflection;
public class Action {
    static private String doSomethingStatic(){
        return "Something static done!";
    }
    private String doSomethingStatic(String argument) {
        return "Something static done with " + argument + "!";
    }
    private String doSomethingStatic(Integer count, String argument) {
        return "Something static done " + count + " times with " + argument + "!";
    }
    private String doSomethingStatic(String argument, Integer count) {
        return "Something static done " + count + " times with " + argument + "!";
    }

    private String doSomething() {
        return "Something done!";
    }
    private String doSomething(String argument) {
        return "Something done with " + argument + "!";
    }
    private String doSomething(Integer count, String argument) {
        return "Something done " + count + " times with " + argument + "!";
    }
    private String doSomething(String argument, Integer count) {
        return "Something done " + count + " times with " + argument + "!";
    }
}

我的问题:

  1. 与您分享这些知识
  2. 询问是否有人能解释为什么这是可能的

问题不是反射。

问题在于你的假设/期望。

让我解释一下:除非你的应用程序在你自己的物理硬件上运行,否则其他人也无法访问;除非您控制运行应用程序的系统上代码加载的所有方面。。。无论如何,控制是一种幻觉

如果你的类运行在一个不属于你的JVM上。。。人们可以(几乎)做任何他们想做的事。这只是一个努力的问题。

含义:Java语言之父在某种程度上实现了反思;不管好坏,他们决定允许你覆盖这种保护(如果没有SecurityManager的话)。但这并不是什么新鲜事,从一开始就是这样。

你说你觉得它很危险。。。为什么?如果你调用了一个私有代码,它就变成了BOOM,那么你的程序就会崩溃。调用方代码是必须处理异常的代码。。。那么,如果不是为了安全,为什么private存在呢?

它们的存在是为了表达意图。它们的存在是为了告诉代码的用户他们应该使用哪些方法,哪些方法只有在子类化时才应该使用,哪些方法根本不应该使用,因为这样做会导致问题。

原始代码的开发人员不希望另一个开发人员直接调用私有方法,因为这样做可能会跳过一些验证,并给出错误的结果。

或者你不能直接改变一个变量,因为它也必须改变另一个。。。但如果另一个变量正是给你带来麻烦的变量,那么直接通过反射设置它将跳过问题。。。

因此,通过反射调用private并不是为了破坏安全措施,而是为了解决糟糕的设计决策(可能在private部分,设计应该允许直接调用,也可能在反射部分,你不应该调用private方法,因为这会使你的代码行为不正确)。

相关内容

  • 没有找到相关文章

最新更新