没有覆盖的 Subclass(别名 class)
Subclass with no overrides (alias class)
如果我有一个具体的 class Foo
,我想添加一个名为 Bar
的 "alias" 扩展 Foo
但不覆盖任何方法 - Java 让我这样做吗?
编辑:上下文 - 目标是最终将 Foo
重命名为 Bar
,因为 Foo
的命名很糟糕;但是,Foo
依赖于另一个项目,我无法在同一提交中同时更改 Foo
和 FooCaller
。为避免破坏 FooCaller
,我将进行三项更改:(1) 添加 Bar
,(2) 将 FooCaller
更改为 BarCaller
(相同行为),(3) 删除总共 Foo
(当没有更多 FooCaller
时)。
这里有什么陷阱吗,或者 Bar
的行为是否与 Foo
相同?
只要您使用适当的可见性,Bar 就会像 Foo 一样工作。 Foo 中的私有方法和属性将无法被 Bar 访问,受保护的方法和属性将被假定为 Bar 中的私有。
下面的示例将 "Foo" 输出到您的控制台。
class Example
{
public static void main (String[] args)
{
Bar b = new Bar();
System.out.println(b.getName());
}
}
class Foo {
protected String name; // Will be private in Bar
public Foo() {
this.name = "Foo";
}
public String getName() {
return this.name;
}
}
class Bar extends Foo {
}
是的,Java 可以让你子class 一个非final
具体的 class 只是为了给原来的 class 添加别名。
public class Foo { /* implementation */ }
public class Bar extends Foo {}
这将是最小的实现,假设 Foo
中只有一个默认构造函数。如果在 Foo
中有接受参数的构造函数,那么您必须在 Bar
中为您计划调用以创建 Bar
实例的每个构造函数提供一个构造函数,例如:
public class Foo {
public Foo(String baz) { /* constructor implementation */ }
}
public class Bar extends Foo {
public Bar(String baz) { super(baz); }
}
Foo
中的所有非 private
方法将被 Bar
继承。
唯一可能不起作用的地方是如果您打算使用 Bar
代替 Foo
作为泛型类型参数。
例如,如果您将 List<Foo>
替换为 List<Bar>
,那么您的 List
将无法再容纳任何 Foo
个实例,或任何其他 class 可能会扩展 Foo
.
此外,因为 Java 的泛型是不变的,所以 List<Bar>
不是 List<Foo>
的子类型,即使 List<Foo>
=15=] 是一个 Foo
。有关为什么会这样的详细信息,请参阅 Is List a subclass of List? Why aren't Java's generics implicitly polymorphic?。另外,如果你使用 List<? extends Foo>
可以绕过它,这样你就可以使用 List<Foo>
或 List<Bar>
,但是你将无法 add
除了 null
.
您声明您不会在泛型中使用它,但如果您的要求有所扩展,请记住这一点。
总而言之,是的,Java 编译器可以让您这样做,但优势有限——使用 Bar
而不是 Foo
作为别名——以及潜在的缺点,我认为没有理由使用这个别名过程。
如果我有一个具体的 class Foo
,我想添加一个名为 Bar
的 "alias" 扩展 Foo
但不覆盖任何方法 - Java 让我这样做吗?
编辑:上下文 - 目标是最终将 Foo
重命名为 Bar
,因为 Foo
的命名很糟糕;但是,Foo
依赖于另一个项目,我无法在同一提交中同时更改 Foo
和 FooCaller
。为避免破坏 FooCaller
,我将进行三项更改:(1) 添加 Bar
,(2) 将 FooCaller
更改为 BarCaller
(相同行为),(3) 删除总共 Foo
(当没有更多 FooCaller
时)。
这里有什么陷阱吗,或者 Bar
的行为是否与 Foo
相同?
只要您使用适当的可见性,Bar 就会像 Foo 一样工作。 Foo 中的私有方法和属性将无法被 Bar 访问,受保护的方法和属性将被假定为 Bar 中的私有。
下面的示例将 "Foo" 输出到您的控制台。
class Example
{
public static void main (String[] args)
{
Bar b = new Bar();
System.out.println(b.getName());
}
}
class Foo {
protected String name; // Will be private in Bar
public Foo() {
this.name = "Foo";
}
public String getName() {
return this.name;
}
}
class Bar extends Foo {
}
是的,Java 可以让你子class 一个非final
具体的 class 只是为了给原来的 class 添加别名。
public class Foo { /* implementation */ }
public class Bar extends Foo {}
这将是最小的实现,假设 Foo
中只有一个默认构造函数。如果在 Foo
中有接受参数的构造函数,那么您必须在 Bar
中为您计划调用以创建 Bar
实例的每个构造函数提供一个构造函数,例如:
public class Foo {
public Foo(String baz) { /* constructor implementation */ }
}
public class Bar extends Foo {
public Bar(String baz) { super(baz); }
}
Foo
中的所有非 private
方法将被 Bar
继承。
唯一可能不起作用的地方是如果您打算使用 Bar
代替 Foo
作为泛型类型参数。
例如,如果您将 List<Foo>
替换为 List<Bar>
,那么您的 List
将无法再容纳任何 Foo
个实例,或任何其他 class 可能会扩展 Foo
.
此外,因为 Java 的泛型是不变的,所以 List<Bar>
不是 List<Foo>
的子类型,即使 List<Foo>
=15=] 是一个 Foo
。有关为什么会这样的详细信息,请参阅 Is List a subclass of List? Why aren't Java's generics implicitly polymorphic?。另外,如果你使用 List<? extends Foo>
可以绕过它,这样你就可以使用 List<Foo>
或 List<Bar>
,但是你将无法 add
除了 null
.
您声明您不会在泛型中使用它,但如果您的要求有所扩展,请记住这一点。
总而言之,是的,Java 编译器可以让您这样做,但优势有限——使用 Bar
而不是 Foo
作为别名——以及潜在的缺点,我认为没有理由使用这个别名过程。