当前位置: 首页 > 面试题库 >

访问超类的私有字段

郑卜鹰
2023-03-14
问题内容

众所周知,私有字段不会在类之间继承。令我着迷的是它如何用于内部静态类。考虑以下代码:

public class Main {
    public static void main(String[] args) {
        new B();
    }

    private static class A {
        private int a = 10;

        private void foo() {
            System.out.println("A.foo");
        }
    }

    private static class B extends A {
        {
            // foo();    // compile-time error
            super.foo();    // ok

            // System.out.println(a);    // compile-time error
            System.out.println(super.a);    // ok
        }
    }
}

您能否解释一下如何访问其他内部类的私有字段?如果合法,为什么只能通过“ super.XXX”构造实现?


问题答案:

内部类是Java的较晚入门。添加它们时,它们仅作为编译器扩展添加,对JVM不变。

语言规范指出,内部类被允许访问在其内声明的类的私有成员。包括其他内部类。

为了使其工作,编译器会生成桥接方法。上面示例中的javap与Main $ A一起使用看起来像这样:

注意access $ 200和access $ 300的添加。它们分别提供对私有方法和字段的后门访问。

class Main$A {
  Main$A(Main$1);
    Code:
       0: aload_0       
       1: invokespecial #3                  // Method "<init>":()V
       4: return

  static void access$200(Main$A);
    Code:
       0: aload_0       
       1: invokespecial #2                  // Method foo:()V
       4: return

  static int access$300(Main$A);
    Code:
       0: aload_0       
       1: getfield      #1                  // Field a:I
       4: ireturn       
}

为了完整起见,这是Main $ B的生成代码。注意对access $
200和300的调用,它们出现在Java代码中super.a和super.foo()的位置。

class Main$B extends Main$A {
  public Main$B();
    Code:
       0: aload_0       
       1: aconst_null   
       2: invokespecial #1                  // Method Main$A."<init>":(LMain$1;)V
       5: aload_0       
       6: invokestatic  #2                  // Method Main$A.access$100:(LMain$A;)V
       9: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      12: aload_0       
      13: invokestatic  #4                  // Method Main$A.access$200:(LMain$A;)I
      16: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
      19: return        
}

如果合法,为什么只能通过“ super.XXX”构造实现?

私有字段通常不属于编译器用于字段的解析路径的一部分,通过迫使开发人员指定超级字段,编译器可以确定私有访问是什么意思,而不是错误。



 类似资料:
  • 我知道如何访问私有变量,但我正在尝试测试以下类: ProcessStatusResult: 在我的测试中,我需要在ProcessStatusBody中获取ProcessStatus来验证它,但我不知道如何做到这一点。 有没有一种方法可以使用反射(或其他方法)来访问它,而不必仅仅为了测试而在ProcessStatusResult中添加getter?

  • 我正在尝试获取对象的私有字段的名称。当我对包的公共字段使用相同的切点时,它正好工作。我的方面设置为特权。我想要更新类对象的字段。切入点: 建议: 我在我的切入点异常中得到这一行的异常:

  • 问题内容: 我有一个类,该类具有一个命名的字段(它与我的类具有相同的类型并具有修饰符): 在该类中,我定义了一个名为的方法,该方法具有一个类型为type的参数。我想知道为什么我可以直接访问实例字段?我的意思是该字段是,不是通过实例受害者无法访问的吗? 问题答案: 隐私不是针对每个实例的,而是针对每个班级的。 该类可以访问所有实例的私有字段。 例如,该方法可以将o(如果适用)转换为相同类型,并将其私

  • 如果我有课,说: ...我想使用Java代理拦截“某种方法”,所以我做了一些事情: 在截取方法中,如何使用ByteBuddy访问类Foo的“name”字段? ByteBuddy是否可以公开这个私有变量供我检查(或者修改,但对于我的用例,只读是可以的)?

  • 我试图找到一种很好的方法来迭代并打印出ArrayList中的对象。 问题是我似乎无法到达用户键入对象信息(例如颜色和品牌)的字段。 对象的新实例如下所示: 汽车(以及自行车、公共汽车等其他类别)是汽车的子类。 车辆等级: } 汽车等级: }尝试迭代对象时: 当迭代对象时,我希望达到I.color中的颜色和品牌字符串。但是我猜想,由于我是一个新的对象,它可能无法访问与汽车、公共汽车等相关的字段和方法

  • 假设一个抽象超类包含一个名为price of type double的私有变量。 现在假设变量已声明但未初始化。超类包含访问器方法,但是setter方法是抽象的,因此必须在子类中重写它,但是,由于超变量是私有的,有没有办法从子类初始化此变量? 考虑下面的例子:我有4节课;书籍(抽象超级)、非小说类(sub)、小说类(sub)、测试者(测试发生了什么的类)。 图书类: 小说课 非小说类 公共类非小说