c++ 嵌套私有类_嵌套类和私有方法

c++ 嵌套私有类

当您在另一个类中有一个类时,他们可以看到彼此的private方法。 在Java开发人员中并不为人所知。 面试过程中的许多候选人说, private是一种可见性,它使代码可以查看成员是否属于同一班级。 这实际上是对的,但更准确地说,代码和成员都在一个类中。当我们嵌套了内部类时, private成员和使用它的代码可能会出现在同一班级,同时他们也处于不同的班级。

例如,如果我在一个顶级类中有两个嵌套类,则其中一个嵌套类中的代码可以看到另一个嵌套类的private成员。

当我们查看生成的代码时,它开始变得很有趣。 JVM不在乎其他类中的类。 它处理JVM“顶级”类。 当您在类A有一个名为B的类时,编译器将创建.class文件,其名称将类似于A$B.classB有一个可从A调用的private方法,然后JVM看到A.class中的代码调用A$B.class的方法。 JVM检查访问控制。 当我们与初级用户讨论此问题时,有人建议JVM可能不在乎修饰符。 那是不对的。 尝试编译A.javaB.java ,两个顶级班,在一些代码A调用一个public的方法B 。 当你拥有A.classB.class修改方法B.javapublicprivate ,并重新编译Bた新B.class 。 启动应用程序,您将看到JVM非常关心访问修饰符。 不过,您仍可以在上面的示例中从A.class调用A$B.class的方法。

为了解决此冲突,Java生成了一些固有的公共合成方法,请在同一类中调用原始的私有方法,并且在考虑JVM访问控制的情况下可以调用该方法。 另一方面,如果您找出生成的方法的名称并尝试直接从Java源代码中调用,则Java编译器将不会编译代码。 我在4年前就写了详细的文章。

如果您是一位经验丰富的开发人员,那么您可能会认为这是一个奇怪而令人反感的技巧。 除了此hack之外,Java如此干净,优雅,简洁,纯净。 还有可能是Integer高速缓存的破解,它使用==使小的Integer对象(典型的测试值)相等,而较大的值只是equals()而不是== (典型的生产值)。 但是除了合成类和Integer缓存hack之外,Java都是干净,优雅,简洁和纯净的。 (您可能会发现我是Monty Python的粉丝。)

这样做的原因是嵌套类不是原始Java的一部分,而是仅添加到1.1版中。解决方案是一个hack,但是那时还有很多重要的事情要做,例如引入JIT编译器,JDBC,RMI,反思和其他一些我们今天认为理所当然的事情。 那时的问题不是解决方案是否干净。 相反,问题是Java是否将完全存活下来并成为主流编程语言或死掉,并且仍然是一个不错的尝试。 那个时候我还担任销售代表,而编码只是一种爱好,因为东欧的编码工作很少,它们主要是无聊的簿记应用程序,而且薪水低。 那段时间有些不同,搜索引擎名为AltaVista,我们从水龙头里喝水,而Java具有不同的优先级。

结果是20多年来,我们的JAR文件略大,Java执行速度稍慢(除非JIT优化了调用链)以及IDE中令人讨厌的警告提示我们最好在嵌套类中使用包保护的方法,而不是private当我们从顶级或其他嵌套类中使用它时。

巢主机

现在看来,这20年的技术债务将得到解决。 http://openjdk.java.net/jeps/181进入Java 11,它将通过引入一个新概念嵌套来解决此问题。 当前,Java字节码包含一些有关类之间关系的信息。 JVM知道某个类是另一个类的嵌套类,而不仅仅是名称。 该信息可以帮助JVM决定一个类中的一段代码是允许还是不允许访问另一类的private成员,但是JEP-181开发有一些更通用的方法。 随着时间的推移,JVM不再是Java虚拟机。 好吧,是的,至少是它的名字,但是,它是一个虚拟机,恰好执行从Java编译的字节码。 或其他语言的问题。 有许多针对JVM的语言,请记住,JEP-181不想将JVM的新访问控制功能与Java语言的特定功能联系在一起。

JEP-181将NestHostNestMembers的概念定义为类的属性。 编译器将填充这些字段,并且当可以从其他类访问某个类的私有成员时,JVM访问控制可以检查:这两个类是否在同一嵌套中? 如果它们在同一巢中,则允许访问,否则不允许访问。 我们将在反射访问中添加方法,因此我们可以获得嵌套中的类的列表。

简单的嵌套示例

使用

$ java -version
java version "11-ea" 2018-09-25
Java(TM) SE Runtime Environment 18.9 (build 11-ea+25)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11-ea+25, mixed mode)

今天我们可以进行Java版本的实验。 我们可以创建一个简单的类:

package nesttest;
public class NestingHost {public static class NestedClass1 {private void privateMethod() {new NestedClass2().privateMethod();}}public static class NestedClass2 {private void privateMethod() {new NestedClass1().privateMethod();}}
}

很简单,它什么也不做。 私有方法互相调用。 没有这个,编译器就会发现它们只是什么也不做,不需要它们,而字节码只是不包含它们。
读取嵌套信息的类

package nesttest;import java.util.Arrays;
import java.util.stream.Collectors;public class TestNest {public static void main(String[] args) {Class host = NestingHost.class.getNestHost();Class[] nestlings = NestingHost.class.getNestMembers();System.out.println("Mother bird is: " + host);System.out.println("Nest dwellers are :\n" +Arrays.stream(nestlings).map(Class::getName).collect(Collectors.joining("\n")));}
}

打印输出符合预期:

Mother bird is: class nesttest.NestingHost
Nest dwellers are :
nesttest.NestingHost
nesttest.NestingHost$NestedClass2
nesttest.NestingHost$NestedClass1

请注意,嵌套主机也列在嵌套成员中,尽管此信息应该非常明显且多余。 但是,这样的使用可能允许某些语言从访问中公开嵌套主机本身的私有成员,并使访问仅允许嵌套。

字节码

使用JDK11编译器进行编译会生成文件

  • NestingHost$NestedClass1.class
  • NestingHost$NestedClass2.class
  • NestingHost.class
  • TestNest.class

没有变化。 另一方面,如果我们使用javap反编译器查看字节码,则将看到以下内容:

$ javap -v build/classes/java/main/nesttest/NestingHost\$NestedClass1.class
Classfile .../packt/Fundamentals-of-java-18.9/sources/ch08/bulkorders/build/classes/java/main/nesttest/NestingHost$NestedClass1.classLast modified Aug 6, 2018; size 557 bytesMD5 checksum 5ce1e0633850dd87bd2793844a102c52Compiled from "NestingHost.java"
public class nesttest.NestingHost$NestedClass1minor version: 0major version: 55flags: (0x0021) ACC_PUBLIC, ACC_SUPERthis_class: #5                          // nesttest/NestingHost$NestedClass1super_class: #6                         // java/lang/Objectinterfaces: 0, fields: 0, methods: 2, attributes: 3
Constant pool:*** CONSTANT POOL DELETED FROM THE PRINTOUT ***{public nesttest.NestingHost$NestedClass1();descriptor: ()Vflags: (0x0001) ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 6: 0LocalVariableTable:Start  Length  Slot  Name   Signature0       5     0  this   Lnesttest/NestingHost$NestedClass1;
}
SourceFile: "NestingHost.java"
NestHost: class nesttest/NestingHost
InnerClasses:public static #13= #5 of #20;           // NestedClass1=class nesttest/NestingHost$NestedClass1 of class nesttest/NestingHostpublic static #23= #2 of #20;           // NestedClass2=class nesttest/NestingHost$NestedClass2 of class nesttest/NestingHost

如果我们使用JDK10编译器编译相同的类,则反汇编行如下:

$ javap -v build/classes/java/main/nesttest/NestingHost\$NestedClass1.class
Classfile /C:/Users/peter_verhas/Dropbox/packt/Fundamentals-of-java-18.9/sources/ch08/bulkorders/build/classes/java/main/nesttest/NestingHost$NestedClass1.classLast modified Aug 6, 2018; size 722 bytesMD5 checksum 8c46ede328a3f0ca265045a5241219e9Compiled from "NestingHost.java"
public class nesttest.NestingHost$NestedClass1minor version: 0major version: 54flags: (0x0021) ACC_PUBLIC, ACC_SUPERthis_class: #6                          // nesttest/NestingHost$NestedClass1super_class: #7                         // java/lang/Objectinterfaces: 0, fields: 0, methods: 3, attributes: 2
Constant pool:*** CONSTANT POOL DELETED FROM THE PRINTOUT ***{public nesttest.NestingHost$NestedClass1();descriptor: ()Vflags: (0x0001) ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #2                  // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 6: 0LocalVariableTable:Start  Length  Slot  Name   Signature0       5     0  this   Lnesttest/NestingHost$NestedClass1;static void access$100(nesttest.NestingHost$NestedClass1);descriptor: (Lnesttest/NestingHost$NestedClass1;)Vflags: (0x1008) ACC_STATIC, ACC_SYNTHETICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1                  // Method privateMethod:()V4: returnLineNumberTable:line 6: 0LocalVariableTable:Start  Length  Slot  Name   Signature0       5     0    x0   Lnesttest/NestingHost$NestedClass1;
}
SourceFile: "NestingHost.java"
InnerClasses:public static #14= #6 of #25;           // NestedClass1=class nesttest/NestingHost$NestedClass1 of class nesttest/NestingHostpublic static #27= #3 of #25;           // NestedClass2=class nesttest/NestingHost$NestedClass2 of class nesttest/NestingHost

Java 10编译器生成access$100方法。 Java 11编译器没有。 相反,它在类文件中具有嵌套主机字段。 我们终于摆脱了那些在某些反映框架的代码中列出所有方法时引起意外的综合方法。

窝窝

让我们玩一些布谷鸟。 我们可以稍微修改一下代码,以便现在可以执行以下操作:

package nesttest;
public class NestingHost {
//    public class NestedClass1 {
//        public void publicMethod() {
//            new NestedClass2().privateMethod(); /* <-- this is line 8 */
//        }
//    }public class NestedClass2 {private void privateMethod() {System.out.println("hallo");}}
}

我们还创建了一个简单的测试类

package nesttest;public class HackNest {public static void main(String[] args) {
//        var nestling =new NestingHost().new NestedClass1();
//        nestling.publicMethod();}
}

首先,从所有行的开头删除所有//并编译项目。 它像魅力一样工作并打印出hallo 。 之后,将生成的类复制到安全的位置,例如项目的根目录。

$ cp build/classes/java/main/nesttest/NestingHost\$NestedClass1.class .
$ cp build/classes/java/main/nesttest/HackNest.class .

让我们编译项目,这次添加注释,然后复制回上一次编译中的两个类文件:

$ cp HackNest.class build/classes/java/main/nesttest/
$ cp NestingHost\$NestedClass1.class build/classes/java/main/nesttest/

现在我们有了一个NestingHost ,它知道它只有一个NestedClass2NestedClass2 。 但是,测试代码认为还有另一个NestedClass1 ,并且它还具有可以调用的公共方法。 这样,我们尝试将额外的雏鸟潜入巢中。 如果执行代码,则会出现错误:

$ java -cp build/classes/java/main/ nesttest.HackNest
Exception in thread "main" java.lang.IncompatibleClassChangeError: Type nesttest.NestingHost$NestedClass1 is not a nest member of nesttest.NestingHost: current type is not listed as a nest memberat nesttest.NestingHost$NestedClass1.publicMethod(NestingHost.java:8)at nesttest.HackNest.main(HackNest.java:7)

从代码中识别出导致错误的行是我们要调用私有方法的那一行,这一点很重要。 Java运行时仅在那时而不是更早执行检查。

我们喜欢还是不喜欢? 快速失败原则在哪里? 为什么Java运行时仅在非常需要时才开始执行类并检查嵌套结构? 在Java中,原因很多:向后兼容。 加载所有类后,JVM可以检查嵌套结构的一致性。 这些类仅在使用时加载。 可以更改Java 11中的类加载,并与嵌套主机一起加载所有嵌套类,但是这样做会破坏向后兼容性。 如果没有别的,懒惰的单例模式会崩溃,我们不希望那样。 我们爱单身,但只有单麦芽(是)。

结论

JEP-181是Java的一个小改动。 大多数开发人员甚至不会注意到。 它消除了技术债务,如果核心Java项目没有消除技术债务,那么我们对普通开发人员有什么期望?

就像古老的拉丁语所说:“技术需要借记卡。”

翻译自: https://www.javacodegeeks.com/2018/08/nested-classes-private-methods.html

c++ 嵌套私有类

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/333068.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mybatis多参数封装到一个类中模糊查询

1.创建QueryValueObject实体类 package com.william.domain;import org.omg.PortableInterceptor.USER_EXCEPTION;/*** author &#xff1a;lijunxuan* date &#xff1a;Created in 2019/7/12 12:09* description &#xff1a;* version: 1.0*/ public class QueryValueObje…

MySQL数据库的权限表

文章目录user 表db 表tables_priv 表columns_priv表MySQL 数据库中与权限相关的表&#xff1a;user、db、tables_priv、columns_priv。 user 表 mysql> select * from mysql.user\G *************************** 1. row ***************************Host: localhostUser: …

jakarta ee_MicroProfile在Jakarta EE时代的作用

jakarta ee自创建以来&#xff0c;MicroProfile赢得了广泛的关注&#xff0c;并制定了各种规格。 最初&#xff0c;它的创建是为了在多个供应商的推动下&#xff0c;以更快的速度推进微服务世界的企业Java。 现在&#xff0c;随着在Eclipse Foundation下将Java EE转换为Jakarta…

Linux系统下MySQL数据库的超级管理员root的密码忘记/忘记密码怎么办?

文章目录方法一方法二方法三方法一 1.添加登录跳过权限检查配置 修改 /etc/my.cnf 文件&#xff0c;在 [mysqld] 配置节点添加 skip-grant-tables 配置 [mysqld] skip-grant-tables2.重新启动mysql服务 service mysqld restart3.修改密码 添加登录跳过权限检查配置后&#x…

Mybatis多参数封装到map中,多条件查询

1.UserMapper接口 package com.william.dao;import com.william.domain.QueryValueObject; import com.william.domain.User;import java.util.List;public interface UserMapper {/*** 多参数封装到map中&#xff0c;多条件查询* param map* return*/List<User> findBy…

jax-rs配置_具有MicroProfile配置的可配置JAX-RS ExceptionMapper

jax-rs配置当使用JAX-RS创建REST服务时&#xff0c;通常不返回任何内容&#xff08;例如HTTP 201/2/4等&#xff09;或某些数据&#xff08;可能采用JSON格式&#xff08;因此HTTP 200&#xff09;&#xff0c;或者返回某些异常/错误&#xff08;因此HTTP 4xx或5xx&#xff09;…

MySQL数据库修改用户登录密码的三种方式

文章目录一、更新 mysql.user 表二、用 set password 命令三、使用 mysqladmin 命令提醒&#xff1a;MYSQL5.7 版本后不再支持password()函数和password字段。 一、更新 mysql.user 表 mysql> use mysql; mysql> update user set passwordpassword(123456) where userr…

Mybatis多条件直接查询

1.UserMapper接口 package com.william.dao;import com.william.domain.QueryValueObject; import com.william.domain.User;import java.util.List;public interface UserMapper {/*** 根据多条件直接查询* param username* param sex* param startIndex* param pageSize* re…

java 正在验证应用程序_Java应用程序中的验证

java 正在验证应用程序我经常看到的项目几乎没有任何有意识的数据验证策略。 他们的团队在截止日期&#xff0c;明确要求的巨大压力下工作&#xff0c;只是没有足够的时间以适当且一致的方式进行验证。 因此&#xff0c;数据验证代码随处可见&#xff1a;JavaScript片段&#x…

Mybatis多条件直接查询Param注解版

1.UserMapper接口 package com.william.dao;import com.william.domain.QueryValueObject; import com.william.domain.User;import java.util.List;public interface UserMapper {/*** 多条件直接查询Param注解版* param username* param sex* param startIndex* param pageS…

WPS for MacOS如何设置自动句首字母大写

在顶部菜单栏&#xff0c;点击【文件】–>【文字偏好设置】或者点击左上角的【文件】–>【文字偏好设置】&#xff1a;

java 和javafx_Java,JavaFX的流利设计风格文本字段和密码字段

java 和javafx我刚刚发布了Java版本4.5 &#xff0c;JavaFX主题JMetro 。 此版本为“文本字段”和“密码字段”添加了新样式。 和往常一样&#xff0c;受到Fluent Design的启发。 在这篇文章中&#xff0c;我将详细介绍这个新版本。 JMetro版本4.5 就像我在简介中所说的那样&…

WPS for MacOS如何设置自动编号

在顶部菜单栏&#xff0c;点击【文件】–>【文字偏好设置】或者点击左上角的【文件】–>【文字偏好设置】&#xff1a;

Mybatis结果集映射

一、使用场景 当数据库里的列名和实体类的属性名不一致&#xff0c;就需要进行结果映射 二、UserMapper接口 package com.william.dao;import com.william.domain.QueryValueObject; import com.william.domain.User; import org.apache.ibatis.annotations.Param;import …

activemq 性能测试_ActiveMQ性能测试

activemq 性能测试我们使用ActiveMQ作为消息传递层–发送大量需要低延迟的消息。 通常它可以正常工作&#xff0c;但是在某些情况下我们已经看到性能问题。 在花了太多时间测试我们的基础结构之后&#xff0c;我想我已经学到了有关ActiveMQ的一些有趣的东西&#xff1a;它可能真…

WPS for MacOS如何设置自动拼写检查

在顶部菜单栏&#xff0c;点击【文件】–>【文字偏好设置】或者点击左上角的【文件】–>【文字偏好设置】&#xff1a;

jdk8 bug_JDK Bug系统浪费时间

jdk8 bug当我在OpenJDK jdk-dev邮件列表中看到Jesper Wilhelmsson的消息标题“ Introducing time浪费者 ”时&#xff0c;我想到了该消息的可能内容的几种可能性。 在阅读该链接与单击链接后出现消息之间的第二个左右时间内 &#xff0c;我想知道消息是否与以下主题之一有关&am…

角度和弧度的计算关系

一、角的两种单位 “ 弧度”和“度”是度量角大小的两种不同的单位。就像“米”和“市尺”是度量长度大小的两种不同的单位一样。 二、弧度的定义 角&#xff08;弧度&#xff09;&#xff1d;弧长/半径 圆的周长是半径的 2π倍&#xff0c;所以一个周角&#xff08;360度&a…

关键字搜索

1.1.1 需求分析 在首页或搜索页输入关键字&#xff0c;点击搜索 显示列表搜索结果&#xff1a; 1.1.2实现思路 &#xff08;1&#xff09;后端使用匹配查询和布尔查询 &#xff08;2&#xff09;前端向后端传递map&#xff08;因为提交的不仅仅是关键字&#xff0c;还有品牌…