我知道Java有这些serval关键字来识别开发过程中的变量范围,但是我想知道它在生产环境中是否有所不同,或仅仅是为了编码器的兴趣?感谢。
答案 0 :(得分:5)
不,JVM实际上会在运行时检查并强制执行可见性。
有很多方法可以使用反射来解决这个问题,但是SecurityManager也可以禁止它。
答案 1 :(得分:5)
可访问性也在运行时强制执行。如果某些代码尝试访问不应该访问的成员,则会抛出IllegalAccessException
或IllegalAccessError
。这是一个快速演示:
public class AccessTest {
public int publicNumber;
private int secretNumber;
}
public class Client {
public static void main(String[] args) throws Exception {
reflection();
noReflection();
}
private static void noReflection() throws IllegalAccessException, NoSuchFieldException {
int a = new AccessTest().publicNumber;
// ^^^^^^^^^^^^
// To be changed to secretNumber in bytecode editor after compilation
System.out.println("Number read: " + a);
}
private static void reflection() throws IllegalAccessException, NoSuchFieldException {
AccessTest instance = new AccessTest();
AccessTest.class.getDeclaredField("publicNumber").get(instance); // <-- Works
try {
AccessTest.class.getDeclaredField("secretNumber").get(instance); // <-- Throws IllegalAccessException
} catch (IllegalAccessException e) {
System.out.println("Caught IllegalAccessException");
}
}
}
实际上,上述程序输出:
Caught IllegalAccessException
Number read: 10
当我使用字节码编辑器更改
时getfield com/blah/access/AccessTest/publicNumber I
方法noReflection()
中的:
getfield com/blah/access/AccessTest/secretNumber I
输出是:
Caught IllegalAccessException
Exception in thread "main" java.lang.IllegalAccessError: tried to access field com.blah.access.AccessTest.secretNumber from class com.blah.access.Client
at com.blah.access.Client.noReflection(Client.java)
at com.blah.access.Client.main(Client.java:12)
正如迈克尔所说,这种行为可能与JVM有关。我在
上运行了这个java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02)
Java HotSpot(TM) 64-Bit Server VM (build 16.3-b01, mixed mode)
答案 2 :(得分:2)
检查在运行时完成,以及编译时。这种类型的异常可以在运行时抛出,例如IllegalAccessException:
当应用程序尝试时抛出IllegalAccessException 反射地创建一个实例(除了数组),设置或得到一个 字段,或调用方法,但当前正在执行的方法不会 可以访问指定类,字段,方法或的定义 构造
答案 3 :(得分:1)
检查是在运行时(以及编译时)执行的。然而,这些检查虽然相对昂贵,但通常每次调用执行一次,并没有太大的区别。
我能想到的两个例外是:
如果在同一文件中访问类的私有成员,则需要创建一个访问器方法(因为JVM不允许从另一个类访问私有成员,嵌套或其他类)尽可能多地影响性能,因为方法可以内联。它可以做的是在调用堆栈中添加一个令人困惑的access$100
方法
如果使用反射,则每次都会执行检查。如果您使用member.setAccessible(true)
,则会禁用安全检查,即使该成员是公开的,也可以更快地进行访问/调用。