【问题标题】:Java Inner Class extends Outer ClassJava 内部类扩展了外部类
【发布时间】:2011-08-19 17:26:50
【问题描述】:

在 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,它是 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 为原因发布了一个很好的答案。至于您的示例,javac 将愉快地编译 Object obj3 = new java.awt.geom.Arc2D.Float.Float.Float (); 行。

标签: java inner-classes extends outer-classes


【解决方案1】:

看看 Java 的Point2D。它有两个内部类,它们是它的子类。

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

Point2D 的情况下,将类及其逻辑进行逻辑耦合。它可以帮助abstract 类型Point2D 的用户找到他们可以使用的实现。

针对您的编辑,我想指出 1 个重要事实。一个 Java 文件只能包含一个公共类,except 用于公共内部类。虽然您的两个示例都可以编译,但它们不允许公众访问这些类。如果您想在一个文件中向某人展示多个公共类,则必须使用公共静态内部类。

【讨论】:

  • 我可以看到你的推理,但我认为有更好的方法可以做到这一点......请参阅我对问题的编辑。
  • @amaid,请参阅我添加的最后一段。
  • 如果你想在一个文件中呈现多个公共类......这正是我有时会做类似事情的原因。顺便说一句,someone 可能是我自己——为了我自己的方便,只是将类“打包”在单个文件中。
  • @amaidment 目前你的内部类没有被声明为 static (注意Arc2D.Float 是静态的)。对我来说,这让世界变得与众不同,基本上毁掉了我能想象到的每一个好处。如果您要讨论未声明为static 的命名内部类,那么我对此的唯一建议就是像瘟疫一样避免它。静态命名的内部类在我的书中是可以的,非静态的只是彻底的灾难
  • @amaid,“你为什么想要一个内部类来扩展它的外部类” - 你不会。这就是我试图在其他 cmets 中传达的内容。
【解决方案2】:

内部类有两种情况:

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

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

静态内部类扩展外部类的情况不如非静态内部类扩展外部类有趣。

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

让我们看一些代码:

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

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

如果您知道 builder 模式,则可以使用它来获得它的 OOP 版本:

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();

【讨论】:

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

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

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

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2013-01-10
  • 2012-06-13
  • 1970-01-01
  • 1970-01-01
  • 2015-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多