Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angularjs/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 内部类如何访问外部类中的元素?_Java_Inheritance_Anonymous_Anonymous Class - Fatal编程技术网

Java 内部类如何访问外部类中的元素?

Java 内部类如何访问外部类中的元素?,java,inheritance,anonymous,anonymous-class,Java,Inheritance,Anonymous,Anonymous Class,我应该提到的是,在我想问这个问题之后,我已经解决了具体的编程问题,所以这不是一个编程问题,而是一个关于问题背后原因的问题 在使用访问修饰符时,我一直在测试Java的局限性,并开始将这些测试应用于基本的继承概念 代码如下: package test.Inheritance; public class SuperClass { private static int x = 0; protected static int y = 1; public static void

我应该提到的是,在我想问这个问题之后,我已经解决了具体的编程问题,所以这不是一个编程问题,而是一个关于问题背后原因的问题

在使用访问修饰符时,我一直在测试Java的局限性,并开始将这些测试应用于基本的继承概念

代码如下:

package test.Inheritance;

public class SuperClass {

    private static int x = 0;
    protected static int y = 1;

    public static void main(String[] args){
        SupplementalClass2 child = new SupplementalClass2();
        NestedClass local = new NestedClass();
        InnerClass test;

        child.setObject(child.new InnerClass(){
            @Override public void display(){System.out.println("Hey!");}
        });
        test = child.getObject();

        System.out.println(test.equals(child.receiveObject));
        SuperClass.NestedClass.display();
        SuperClass.NestedClass2.display();
        test.display();
        child.display();
        local.message();
    }

    public static class NestedClass {
        public static void display()
        {
            System.out.println("x before first static context change: " + x);
            x = 25;
            System.out.println("x after first static context change: " + x);
        }
        public void message()
        {
            System.out.print("Nested Class Field Access Test: " + "before(" + y + ") | ");
            y = 20;
            System.out.println("after(" + y + ")");
        }
    }

    public static class NestedClass2 {
        public static void display()
        {
            System.out.println("x before second static context change: " + x);
            x = 30;
            System.out.println("x after second static context change: " + x);
        }
    }

    public class InnerClass {
        public void display(){}
    }
}

abstract class SupplementalClass extends SuperClass {
    protected String test = "Parent Class String";
    protected InnerClass receiveObject;
}

interface SupplementalInterface {
    public static final int test = 3;
    public abstract void display();
}

class SupplementalClass2 extends SupplementalClass implements SupplementalInterface {
    public void display()
    {
        System.out.println("Supplemental Interface Field Access Test: " + SupplementalInterface.test);
        System.out.println("Supplemental Parent Field Access Test: " + super.test);
    }
    public void setObject(InnerClass in){
        receiveObject = in;
    }

    public InnerClass getObject()
    {
        return receiveObject;
    }
}
这是固定版本:
InnerClass
提供了一个方法
display()
,用于覆盖
SupplementalClass2
中的方法

以前,
InnerClass
是空的,我尝试在匿名类实例中设置display方法,而不是类本身,因为我相信内部类将继承通过
SupplementalInterface
实现的抽象显示方法


所以我的问题是,如果不是通过继承,嵌套类和内部类如何访问其持有者中的数据?

内部类实例访问其外部类实例的字段和方法,就像任何对象访问另一个对象的字段和方法一样。唯一的区别是,为了能够访问私有成员,编译器生成由内部类调用的合成桥方法(非私有)来访问私有成员

例如,请参见课程:

public class Outer {
    private int privateField;
    public int publicField;

    private void privateFoo() {}
    public void publicFoo() {}

    private class Inner {
        void bar() {
            privateFoo();
            publicFoo();
            System.out.println("privateField = " + privateField);
            System.out.println("publicField = " + publicField);
        }
    }
}
如果编译它并调用
javap-c Outer.Inner
,您将得到以下输出:

Compiled from "Outer.java"
public class com.foo.Outer {
  public int publicField;

  public com.foo.Outer();
    Code:
       0: aload_0       
       1: invokespecial #3                  // Method java/lang/Object."<init>":()V
       4: return        

  public void publicFoo();
    Code:
       0: return        

  static void access$000(com.foo.Outer);
    Code:
       0: aload_0       
       1: invokespecial #2                  // Method privateFoo:()V
       4: return        

  static int access$100(com.foo.Outer);
    Code:
       0: aload_0       
       1: getfield      #1                  // Field privateField:I
       4: ireturn       
}
Compiled from "Outer.java"
class com.foo.Outer$Inner {
  final com.foo.Outer this$0;

  void bar();
    Code:
       0: aload_0       
       1: getfield      #1                  // Field this$0:Lcom/foo/Outer;
       4: invokestatic  #3                  // Method com/foo/Outer.access$000:(Lcom/foo/Outer;)V
       7: aload_0       
       8: getfield      #1                  // Field this$0:Lcom/foo/Outer;
      11: invokevirtual #4                  // Method com/foo/Outer.publicFoo:()V
      14: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      17: new           #6                  // class java/lang/StringBuilder
      20: dup           
      21: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
      24: ldc           #8                  // String privateField = 
      26: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      29: aload_0       
      30: getfield      #1                  // Field this$0:Lcom/foo/Outer;
      33: invokestatic  #10                 // Method com/foo/Outer.access$100:(Lcom/foo/Outer;)I
      36: invokevirtual #11                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      39: invokevirtual #12                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      42: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      45: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      48: new           #6                  // class java/lang/StringBuilder
      51: dup           
      52: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
      55: ldc           #14                 // String publicField = 
      57: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      60: aload_0       
      61: getfield      #1                  // Field this$0:Lcom/foo/Outer;
      64: getfield      #15                 // Field com/foo/Outer.publicField:I
      67: invokevirtual #11                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      70: invokevirtual #12                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      73: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      76: return        
}
从“Outer.java”编译而来
公共类com.foo.Outer{
公共领域;
public com.foo.Outer();
代码:
0:aload_0
1:invokespecial#3//方法java/lang/Object。“:()V
4:返回
public void publicFoo();
代码:
0:返回
静态无效访问$000(com.foo.Outer);
代码:
0:aload_0
1:invokespecial#2//方法privateFoo:()V
4:返回
静态int访问$100(com.foo.Outer);
代码:
0:aload_0
1:getfield#1//Field privateField:I
4:我轮到你了
}
从“Outer.java”编译而来
类com.foo.Outer$Inner{
最终com.foo.Outer此$0;
空心钢筋();
代码:
0:aload_0
1:getfield#1//此$0字段:Lcom/foo/Outer;
4:invokestatic#3//方法com/foo/Outer.access$000:(Lcom/foo/Outer;)V
7:aload_0
8:getfield#1//此$0字段:Lcom/foo/Outer;
11:invokevirtual#4//方法com/foo/Outer.publicFoo:()V
14:getstatic#5//fieldjava/lang/System.out:Ljava/io/PrintStream;
17:new#6//class java/lang/StringBuilder
20:dup
21:invokespecial#7//方法java/lang/StringBuilder。”“:()V
24:ldc#8//字符串私有字段=
26:invokevirtual#9//方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
29:aload_0
30:getfield#1//此$0字段:Lcom/foo/Outer;
33:invokestatic#10//方法com/foo/Outer.access$100:(Lcom/foo/Outer;)I
36:invokevirtual#11//方法java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
39:invokevirtual#12//方法java/lang/StringBuilder.toString:()Ljava/lang/String;
42:invokevirtual#13//方法java/io/PrintStream.println:(Ljava/lang/String;)V
45:getstatic#5//fieldjava/lang/System.out:Ljava/io/PrintStream;
48:new#6//class java/lang/StringBuilder
51:dup
52:invokespecial#7//方法java/lang/StringBuilder。”“:()V
55:ldc#14//字符串公共字段=
57:invokevirtual#9//方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
60:aload_0
61:getfield#1//此字段为$0:Lcom/foo/Outer;
64:getfield#15//Field com/foo/Outer.publicField:I
67:invokevirtual#11//方法java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
70:invokevirtual#12//方法java/lang/StringBuilder.toString:()Ljava/lang/String;
73:invokevirtual#13//方法java/io/PrintStream.println:(Ljava/lang/String;)V
76:返回
}
如您所见,外部类有两个附加的静态方法:
access$000()
access$100()
,它们分别调用private方法并返回private字段的值。内部类通过这些方法调用私有方法并访问私有字段

但是,公共方法和字段是以通常的方式访问的,因为没有什么可以阻止一个对象访问另一个对象的公共成员


我将让您在嵌套类和静态成员上做同样的实验,看看它是如何精确工作的。

@JB Nizet-Wow。这个答案让我难以理解。除了
Java
javac
之外,我没有使用任何Java提示可执行文件。我已经对此进行了测试,从您所说的内容来看,似乎编译器正在创建访问方法来将私有字段引用发送到内部类。所以它基本上是创建get方法,只要找到访问私有字段的请求,内部类就会自动调用这些方法。编译器将字段访问转换为对返回字段的合成桥方法的调用。