这本身不是一个“陷阱”,而是一个值得了解的实现细节。 假设我有一个带有字段的内部类。 这样的字段对于封闭的类是可见的,但是以下哪种方法是访问它的最快方法? 注意! 我只在这里查看生成的字节码,而不考虑任何JIT优化,因此这种“性能分析”非常幼稚

public class Test {public void testAlternatives() {// Alternative 1System.out.println(new Inner().field);// Alternative 2System.out.println(new Inner().getField());// Alternative 3System.out.println(new Inner2().field);// Alternative 4System.out.println(new Inner2().getField());}class Inner {private int field;public int getField() {return field;}}class Inner2 {int field;public int getField() {return field;}}}

一个直观的答案是,替代方案1和3的速度相当快,因为​​该字段始终对封闭的类可见,并且两者都使用字段访问,总体而言,该字段的访问速度比替代方案2和4中使用的方法访问快一点。但是,有一个实现细节导致这是不正确的。 JVM本身没有称为“内部类”的概念。 整个概念由Java编译器实现,并且在字节码级别,所有内容均由普通类组成。

这里的问题是,如果内部类具有私有字段,则编译器最终会将内部类编译为普通类。 普通类中的私有字段不能被其他类访问,因此,封闭的Test类如果没有技巧,就无法“看到”该字段。 这是上面的代码“拒绝”了编译器实际编译为字节码的内容:

public class Test {public void testAlternatives() {// Alternative 1System.out.println(Test$Inner.access$000(new Test$Inner(this)));// Alternative 2System.out.println(new Test$Inner(this).getField());// Alternative 3System.out.println(new Test$Inner2(this).field);// Alternative 4System.out.println(new Test$Inner2(this).getField());}
}class Test$Inner {final Test this$0;private int field;Test$Inner(Test test) {this$0 = test;}public int getField() {return field;}static int access$000(Test$Inner inner) {return inner.field;}}class Test$Inner2 {final Test this$0;int field;Test$Inner2(Test test) {this$0 = test;}public int getField() {return field;}}

如您所见,为了授予对私有字段的访问权限,将生成一个名为access $ 000的程序包级静态访问器方法。 现在,更容易看到替代方法3最有可能成为最快的替代方法,因为它是唯一使用直接字段访问的方法。 在字段中使用程序包访问是一个微优化,但是这绝对是Java开发人员应该知道的一个细节。 在对性能至关重要的代码部分中,这实际上可能很重要,而Android性能指南实际上提到了此实现细节。

当尝试对内部类的空引用进行字段访问时,此实现的详细信息也可能会引起一些混乱。 考虑以下代码:

public class NullTest {class Inner {private int field;}public void test() {Inner inner = null;System.out.println(inner.field);}public static void main(String[] args) {new NullTest().test();}
}

变量“ inner”为空,因此显然会引发NullPointerException。 但是,从原始代码中看不出来的是,异常是在编译器生成的静态访问器方法内引发的!

$ java NullTest
Exception in thread 'main' java.lang.NullPointerExceptionat NullTest$Inner.access$000(NullTest.java:2)at NullTest.test(NullTest.java:8)at NullTest.main(NullTest.java:12)

堆栈跟踪包含直观的异常源(第8行),但是实际源会使不了解编译器生成的访问器方法的开发人员感到困惑。

参考: Java陷阱:来自Jawsy Solutions技术博客博客的JCG合作伙伴 Joonas Javanainen, 内部类中的字段访问 。

翻译自: https://www.javacodegeeks.com/2012/05/java-pitfalls-field-access-in-inner.html

Java陷阱:内部类中的字段访问相关推荐

  1. java jolt tuxedo_Java中使用Jolt访问Tuxedo服务 – Tomcat环境部署测试

    Java中使用Jolt访问Tuxedo服务 – Tomcat环境部署测试 Java中使用Jolt访问Tuxedo服务 – Tomcat环境部署测试 最近在学习基于Tuxedo的系统架构,网上讨论最多的 ...

  2. java遍历类中所有字段

    代码: //遍历类中所有字段信息 https://blog.csdn.net/weixin_34346099/article/details/94036015public static void re ...

  3. java中声明内部类变量,java – 从内部类中访问变量(dialogView),需要声明final

    我正在尝试创建一个带有布局"是"或"否"的警告对话框.我想通过单击"否"按钮但是对话框View.dismiss()来关闭对话框;有错误. 这 ...

  4. java mysql tinyint_Msq 中tinyint字段对应 java中哪个类型?

    展开全部 MySql 中的tinyint(1)的使用 在MySql中如何定义像Java中类型的Boolean类型数据..其实,mysql中 是没有直接定义成Boolean这种数据类型. 它只能定义成 ...

  5. java获取json中某个字段

    import com.alibaba.fastjson.JSONObject; public class JsonTest {public static void main(String[] args ...

  6. java Clob转CLOB_Java获取Oracle中CLOB字段转换成String

    Java获取Oracle中CLOB字段转换成String : try {PreparedStatement stmt = session.connection().prepareStatement(s ...

  7. java继承a mya new c,“内部类” 大总结(Java),内部类总结java

    "内部类" 大总结(Java),内部类总结java (本文整理自很久以前收集的资料(我只是做了排版修改),作者小明,链接地址没有找到,总之感谢,小明) 内部类的位置: 内部类可以作 ...

  8. mysql clob转string_Java获取Oracle中CLOB字段转换成String

    Java获取Oracle中CLOB字段转换成String : try {PreparedStatement stmt = session.connection().prepareStatement(s ...

  9. JAVA基础——内部类(成员内部类、静态内部类、局部内部类、匿名内部类)

    成员内部类 静态内部类 局部内部类 匿名内部类 1.成员内部类(实例内部类.非静态内部类) 成员内部类中不能写静态属性和方法 实例化内部类,首先需要实例化外部类,通过外部类去调用内部类   作用 要想 ...

最新文章

  1. X5本地应用打包服务器环境搭建
  2. wsl ubuntu拒绝访问_一起聊聊WSL的那些事儿(下)
  3. Javascript深入浅出
  4. springboot创建多个对象
  5. Site24x7 为Teams提供可智能 DevOps
  6. Ingress-nginx工作原理和实践
  7. 移位 c语言一个变量存储两个值,【杭州C  培训】C语言中基础小问题总结
  8. 快速设置 Docker 的三种网络代理配置
  9. java中最大最小值
  10. 电子商务网络购物平台实例运营分析+电子商务概述及阿里巴巴集团模式五大核心内容[连载之电子商务网络营销]...
  11. 内存卡数据恢复,如何从内存卡恢复数据
  12. 在Excel中批量生成条形码
  13. 冰汽时代机器人不用热_如何评价游戏《冰汽时代》?
  14. 云计算采用的各种虚拟化技术比较
  15. SSH端口转发(port forwarding)基础知识
  16. 千兆12光12电工业级环网交换机24口全千兆二层网管型机架式工业以太网交换机
  17. python unpacking_使用Python将数组的元素导出到变量中(unpacking)
  18. PCDATA和CDATA区别
  19. FTP传输大文件丢包损坏严重,怎么解决?
  20. MATLAB与C++的接口问题

热门文章

  1. 包+类导入+静态导入+类放入包中+包作用域
  2. 求三个数的最大最小值
  3. java设计模式适配器模式_Java中的适配器设计模式
  4. monolith_将Java EE Monolith雕刻成微服务
  5. java8 streams_当Java 8 Streams API不够用时
  6. Apache CXF 3.0:CDI 1.1支持替代Spring
  7. 使用JDK 13查看TLS配置
  8. 使用OpenJDK 11运行JAXB xjc编译器
  9. 首选System.lineSeparator()以用Java编写系统相关的行分隔符字符串
  10. lucene使用3.0.3_使用Apache Lucene 4.3轻松进行搜索