1

我在玩弄实例控制流和静态控制流,注意下面的代码

class A {
    {
        m1();
    }
    A(){
        System.out.println("A constructor");
    }
    void m1(){
        System.out.println("A m1");
    }
}
public class Main extends A {
    public static void main(String[] args) throws Exception {
        Main m = new Main();
    }
    void m1(){
        System.out.println("Main m1");
    }
}

代码的输出是:
Main m1
A constructor

我知道这是因为:
首先,静态块和变量被识别为自上而下的父子,在这种情况下,只有一个main()是静态的。
其次,静态块和变量赋值被执行,所以main()开始执行,并且尝试创建一个新Main对象。
所以第三,将识别父类的实例块和变量。然后它们将自上而下执行。(之后父类的构造函数运行,然后识别子类的实例块和变量,然后自上而下执行,最后执行子类的构造函数)。


所以 A 中的实例块调用了 `m1()`。然后,A 的构造函数执行。最后,控制流返回到 `main()` 并且程序终止。
现在,从 A 调用 `m1()` 调用了 `Main` 的 `m1()`。但是,如果我将“m1()”方法都设为静态,其他一切都保持不变,那么从 A 的实例块调用“m1()”就会调用 A 的“m1()”。

我有两个问题(为什么?纯粹出于学术原因,我还在学习 Java):

  1. 当这两种m1()方法都是非静态的时,是否可以从 A 的实例块调用 A 的 m1()?我尝试做一个this.m1(),但仍然调用 Main 的 m1()。(为什么?)
  2. 当这两个m1()方法都是静态的时,是否可以从 A 的实例块调用 Main 的 m1()?(我猜不是,但我不确定)。

    我知道在第一种情况下,它正在发生,而在第二种情况下,它是方法隐藏。但是我仍然不确定如何根据这些知识回答我的问题。
4

2 回答 2

1

编译完成 java 8 编译器后,您的代码如下所示:

 class A {
           A() {
              this.m1();  // at runtime this refers to Main class instance
              System.out.println("A constructor");
           }
        
           void m1() {
              System.out.println("A m1");
           }
        }

public class Main extends A {
     public Main() { }

     public static void main(String[] args) throws Exception {
          Main m = new Main();
          m.m1();
       }
    
       void m1() {
          System.out.println("Main m1");
       }
    }

现在回答您的第一个问题:不。除非您正在创建 A 的实例(A 的实际对象),否则您不能。

对于您的第二个问题:在使两个 m1 的静态编译后看起来像这样:

class A {
   A() {
      m1(); // resolves to A's m1
      System.out.println("A constructor");
   }

   static void m1() {
      System.out.println("A m1");
   }
}
public class Main extends A {
   public Main() {
   }

   public static void main(String[] args) throws Exception {
      new Main();
   }

   static void m1() {
      System.out.println("Main m1");
   }
}

现在无论您创建哪个实例(A 或 Main),您都会看到 A 的 m1 被执行。

于 2020-10-03T10:47:54.213 回答
0

1.(当两个方法都是实例方法时)如果你在A(父)类里面,如果你调用m1();或者this.m1();您将调用该m1()方法的 A 版本,但如果您在主类(子类)中,如果您调用,m1();您将调用 m1 的主版本,尽管如果您调用super.m1();您将调用 m1 方法的 A 版本。

2.(如果方法是静态的)你可以在任何你想要的地方调用每个版本,没有类的对象,例如,你可以在 A 块内调用 main 的 m1 方法,使用以下行Main.m1(); // ClassName.StaticMethodName();

于 2020-07-01T09:18:41.863 回答