Java内部类继承外部类

12

在Java中,有一些情况下内部类会继承外部类。

例如,java.awt.geom.Arc2D.Float是java.awt.geom.Arc2D的一个内部类,并且也继承了Arc2D。 (参见http://download.oracle.com/javase/6/docs/api/java/awt/geom/Arc2D.Float.html

此外,sun.org.mozilla.javascript.internal.FunctionNode.Jump继承自sun.org.mozilla.javascript.internal.Node,而Node是FunctionNode的超类。 (抱歉...找不到javadoc的链接)

对我来说,这似乎很奇怪。那么你能创建这些吗?

new Arc2D.Float.Float() //n.b. I couldn't get this to compile in Intellij IDEA;

new FunctionNode.Jump.Jump.Jump(1); // I could get this to compile

将子类嵌套为父类的内部类有何用途?

我想知道这是否是为了访问父类中的某些内容,但如果您想要访问父类中的任何变量/方法,则可以使用

super.variable;

或者

super.method();

编辑1: jjnguy建议将逻辑放在同一位置。那么,为什么不编写一个名为com.mypackage.AbstractTest的文件:

abstract class AbstractTest {
  abstract String getString();
}

class ExtensionTest extends AbstractTest {
  @Override
  String getString() {
    return "hello world";
  }
}

...而不是:

abstract class AbstractTest {
  abstract String getString();

  class ExtensionTest extends AbstractTest {
    @Override
    String getString() {
      return "hello world";
    }
  }
}

编辑2: 正确指出了我之前编辑中的建议存在缺陷,因为无法在包外构建ExtensionTest。然而,经过周末的进一步思考,以下是我的新想法:

abstract class Test {
  public class ExtensionTest extends AbstractTest {
    @Override
    String getString() {
      return "hello world";
    }
  }

  private abstract class AbstractTest {
    abstract String getString();
  }
} 

从本质上讲,到目前为止我看到的最好的答案是:内部类继承其外部类可以将逻辑分组在一起。然而,我认为这可以在不使用继承的情况下完成。

在我看来,拥有一个类可以具有无限数量的相同子类嵌套在其中似乎是一种糟糕的设计。(背景:这是在尝试为代码补全实用程序生成字典时出现的问题,并引发了StackOverflowException。我找到了一个解决方法,但我只是无法理解为什么要以这种方式进行设计。)


@jinguy已经为为“why”问题提供了一个很好的答案。至于你的例子,javac会愉快地编译这一行代码:Object obj3 = new java.awt.geom.Arc2D.Float.Float.Float(); - 101100
3个回答

16

看一下Java的Point2D (链接)。它有两个内部类,它们是它的子类。

需要注意的重要事情是,它们是static内部类。这与常规内部类完全不同。就像静态方法一样,静态类是在类级别而不是对象级别定义的。

Point2D的情况下,这样做是为了逻辑上耦合类和它们的逻辑。它帮助抽象类型Point2D的用户找到他们可以使用的实现。

针对您的编辑,我想指出一个重要的事实。单个Java文件只能包含一个公共类,除了公共内部类。虽然您提供的两个示例都可以编译,但它们不允许公共访问那些类。如果您想向某人以单个文件呈现多个公共类,则必须使用公共静态内部类。


1
@amaid,请看我添加的最后一段。 - jjnguy
1
如果你想在单个文件中展示多个公共类,那就是我有时会这样做的原因。顺便说一下,“某人”可能是我自己——只是为了方便将类“打包”在单个文件中。 - gnat
1
@amaidment 目前你的内部类没有声明为_static_(注意 Arc2D.Float 是静态的)。对我来说,这会产生很大的影响,基本上破坏了我能想象到的所有好处。如果你要讨论未声明为“static”的命名内部类,那么我的唯一建议就是像避开瘟疫一样避免它。在我看来,静态命名内部类没问题,非静态的则是彻头彻尾的灾难。 - gnat
2
@amaid,“为什么你想让内部类继承它的外部类” - 你不会这样做。这就是我在其他评论中试图传达的意思。 - jjnguy
我认为Java不支持静态内部类。但是它支持静态嵌套类。 - akhil_mittal
显示剩余7条评论

10

内部类有两种情况:

  • 静态内部类。内部类不保留对外部类的引用。

  • 非静态内部类。内部类保留对外部类的引用。

静态内部类继承外部类的情况不像非静态内部类继承外部类那么有趣。

后者发生的情况是:为了创建内部类,需要一个对外部类的引用。然而,由于内部类是外部类的一个实例,它也接受一个对另一个内部类实例的引用,作为外部类使用。

让我们看一些代码:

Outer a = new Outer();
Outer.Inner b = a.new Inner();

// Only possible when Inner extends Outer:
Outer.Inner c = a.new Inner().new Inner();

如果您了解构建器模式,这可以用于具有面向对象的版本:

public abstract class Command {

    // Not possible to create the command, else than from this file!
    private Command() {
    }

    public abstract void perform();

    public static class StartComputer extends Command {
        public void perform() {
            System.out.println("Starting Computer");
        }
    }

    public class OpenNotepad extends Command {
        public void perform() {
            Command.this.perform();
            System.out.println("Opening Notepad");
        }
    }

    public class ShutdownComputer extends Command {
        public void perform() {
            Command.this.perform();
            System.out.println("Shutting Computer");
        }
    }

}

这段代码用于开启电脑、打开记事本并关闭电脑:new Command.StartComputer().new OpenNotepad().new ShutdownComputer().perform();


4
你认为这个例子的风格好吗?看起来很糟糕。 - jjnguy
我同意!它看起来很糟糕,需要一些适应时间。 - Pindatjuh
我以前从未见过这种用法。在某些地方这是常见做法吗? - jjnguy
1
哇,这看起来很奇怪,但我喜欢它。你也可以使用装饰器模式,这样你的代码看起来就像是new Command.StartComputer(new Command.OpenNotepad(new Command.ShutdownComputer()))).perform()。但是在你的代码中,你必须从StartComputer开始。你是如何找到这个解决方案的? - user1944408
2
或者按照正常的方式,让您的方法返回它们所在的类型,这样您就可以获得语法而无需使用new关键字和更少的实例化。 - Austin_Anderson

2

第一个在我的IntelliJ上编译得很好。

严格来说,静态成员类不是内部类。它们被称为嵌套类。


1
静态嵌套类更加准确。根据https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html,声明为静态的嵌套类被称为静态嵌套类。非静态嵌套类被称为内部类。 - Ahmed Rezk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接