【问题标题】:Method Local Inner classes program方法本地内部类程序
【发布时间】:2018-12-07 12:08:20
【问题描述】:

我只是在学习 Java 概念。 谁能告诉我为什么我不能运行这个程序?

package innerClasses;

public class Test {
    int i=10;
    static int j=20;
    public void m1() {
        int k=30;
        final int m=40;

        class Inner {
            public void m2() {
                System.out.println(i);
            }
        }
    }

    public static void main(String[] args) {
        Test t = new Test();
        Test.Inner in = t.new Inner();
        t.m1();
    }

}

谁能告诉我为什么我不能运行这个程序?

【问题讨论】:

  • 你为什么不告诉我们?你收到错误信息吗?它是在编译/运行时出现的吗?它说什么?
  • 你不能在方法中声明一个类,更不用说假设'将是一个有效的内部类
  • Getting Compile time error say-Multiple marker at this line, Test.Inner cannot be resolve to a type"
  • 原因在我的第二条评论中
  • 我建议通读这个。问题是您正在尝试创建一个本地类,并尝试将其用作内部类:docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html

标签: java inner-classes


【解决方案1】:

编译时错误的最基本原因是“Scope”。
根据您的代码,类 Inner 在方法 m1 内定义(此类称为 Local class/method local class),因此如果您观察方法变量的范围,它仅在声明的方法内,我们无法访问该方法之外的任何方法变量这就是原因,class Inner 的范围仅限于 m1 方法 所以如果你想实例化class Inner 并调用它的方法,那么你必须在m1 方法中执行它(在代码中,你试图在方法m1 之外创建类内部对象,这是不可能的)因此代码将是

public class Test {
int i = 10;
    static int j = 20;
    public void m1() {
        int k = 30;
        final int m = 40;
        class Inner {
            public void m2() {
                System.out.println(i);
            }
        }
        Inner in = new Inner();
        in.m2();
    }
    public static void main(String[] args) {
        Test t = new Test();
        t.m1();
    }
}

更多信息,当方法内部需要任何重复的功能时,可以使用本地类(因为在 java 中不允许嵌套方法,所以我们可以创建内部类)当然如果我们不想创建类以水平方法为例

class Outer {
    public void cal() { 
        class Inner {
            public void sum(int x, int y) {
                System.out.println("sum : "+(x+y));
            }
        }
        Inner i= new Inner();
        i.sum(10, 20); //sum is repeatdly needed in between code
        i.sum(100, 200);
        i.sum(1000, 2000);
        i.sum(10000, 20000);
    }
}
public class TestClass {
    public static void main(String[] args) {
        new Outer().cal();
    }
}

【讨论】:

    【解决方案2】:

    您的 class Inner 就是 JLS 所称的 Local Class (14.3. Local Class Declarations)

    scope of a Local Class is defined as (6.3. Scope of a Declaration):

    由块(第 14.2 节)直接包围的局部类声明的范围是直接封闭块的其余部分,包括它自己的类声明。

    由 switch 块语句组(第 14.11 节)直接包围的局部类声明的范围是直接封闭的 switch 块语句组的其余部分,包括它自己的类声明。

    在您的情况下,它是在一个块中声明的,这是您的方法的主体。所以你的类可见的范围是这个方法体的其余部分。

    由于Inner 类型在main() 中不可见,因此您不能在那里使用它。不过,您可以创建它的实例并在 m1() 中使用它们。

    【讨论】:

      【解决方案3】:

      你不能编译它,因为 Inner 类的范围是 m1 方法。 如果您希望能够创建 Inner 类的实例,您可以直接在 Test 中定义它:

      public class Test {
          int i=10;
          static int j=20;
      
          public void m1() {
              int k=30;
              final int m=40;
          }
      
          // On the Test class level 
          class Inner {
              public void m2() {
                  System.out.println(i);
              }
          }
      
          public static void main(String[] args) {
              Test t = new Test();
              Test.Inner in = t.new Inner();
              t.m1();
              in.m2(); // prints 10
          }
      }
      

      Java 提供的另一个特性是使用匿名类。它可以通过一些接口的实现来创建:

      // Define an interface to be able to implement it inside the method
      interface Inner {
          void m2();
      }
      
      public class Test {
          int i=10;
          static int j=20;
      
          public void m1() {
              int k=30;
              final int m=40;
      
              // Implement interface and call method on it
              // Functional style: 
              ((Inner) () -> System.out.println(i)).m2();
      
              // Legacy style:
              new Inner() {
                  @Override
                  public void m2() {
                      System.out.println(i);
                  }
              }.m2();
      
          }
      
          public static void main(String[] args) {
              Test t = new Test();
              t.m1(); // prints 10 twice
          }
      }
      

      或扩展一些类:

      // A class we going to extend
      class Inner {
          void m2() {
              System.out.println(11);
          }
      }
      
      public class Test {
          int i=10;
          static int j=20;
      
          public void m1() {
              int k=30;
              final int m=40;
      
              // Extend inner class and call method on it
              new Inner() {
                  void m2() {
                      System.out.println(i);
                  }
              }.m2();
      
          }
      
          public static void main(String[] args) {
              Test t = new Test();
              t.m1(); // prints 10, not 11
          }
      }
      

      所以对你来说最好的方法取决于你最终想要得到什么样的代码设计。

      【讨论】:

        【解决方案4】:

        方法内部类仅对该方法可见,因此您不能在任何其他位置使用它。

        为了使用这个类,你必须在方法之外声明它。

        【讨论】:

          【解决方案5】:

          Inner 类在方法m1() 内声明,导致它在此方法外不可用。

          您的代码必须如下所示才能运行,尽管它不会打印任何内容...

          public class Test {
          
              int i=10;
              static int j=20;
          
              public void m1() {
                  int k=30;
                  final int m=40;
              }
          
              class Inner {
                  public void m2() {
                      System.out.println(i);
                  }
              }
          
              public static void main(String[] args) {
                  Test t = new Test();
                  Test.Inner in = t.new Inner();
                  t.m1();
              }
          
          }
          

          t.m1(); 替换为in.m2(); 将输出10。

          编辑

          如果您必须在方法内创建内部类,请使其像

          public class Test {
          
              int i=10;
              static int j=20;
          
              public void m1() {
          
                  int k=30;
                  final int m=40;
          
                  class Inner {
                      public void m2() {
                          System.out.println(i);
                      }
                  }
          
                  // this is what makes it run
                  Inner myInner = new Inner();
                  myInner.m2();
              }
          
          
              public static void main(String[] args) {
                  Test t = new Test();
                  t.m1();
              }
          
          }
          

          编译并运行。

          恕我直言,这不是一个好方法......

          【讨论】:

          • 实际上我正在使用“方法本地内部类”的概念,据此我必须在 m1() 中定义内部类。
          • @AnkitJain 请查看我的编辑并回答我的问题为什么要在另一个类的方法中声明一个类?
          【解决方案6】:

          最基本的原因是范围。为了做到

          Test.Inner in = t.new Inner();
          

          Inner 必须在Test 中定义,但它是在m1 范围内定义的。

          【讨论】:

          • 但是按照“方法本地内部类”的概念,我们可以在方法中声明一个类。
          • 问题仍在范围内。您的主要声明正在尝试访问嵌套类,但您正在定义一个方法本地类。如果您的意图是实际访问方法本地类,那么您只能在m1 的上下文中进行。
          猜你喜欢
          • 2015-06-19
          • 1970-01-01
          • 1970-01-01
          • 2014-02-07
          • 2011-09-04
          • 2019-01-05
          • 1970-01-01
          • 2013-12-20
          • 2010-09-06
          相关资源
          最近更新 更多