抽象类中的具体方法可以返回子类中定义的变量吗?

时间:2012-12-14 21:25:18

标签: java polymorphism abstract-class

正当我开始熟悉界面时,我遇到了一个带抽象类的绊脚石。根据我的理解,它们可用于为子类提供一些功能,但强制子类指定未定义的函数(如果有任何剩余的)。

我遇到的所有示例只涉及可能是静态的功能 - 没有引用实例变量。

我试图在抽象类中隐藏一些常见函数,例如getName(),但是能够在子类中定义所述名称。

public interface Application {
    public String getName();
}

/**
 * Specify some default behaviour to keep leaf classes free of common code
 */
public abstract class DefaultApplication implements Application {
    public static final String NAME = "DefApp";

    @Override
    public String getName() {
        return NAME;
    }
}

public class MyApp extends DefaultApplication {
    public static final String NAME = "My App";
}

// Main class
Application myApp = new MyApp();
System.out.println(myApp.getName()); // Prints "DefApp"

我认为protected String name可能有效,但这也会在抽象类中返回实例变量。唯一的解决方案是在每个子类中重新定义getName()吗?我不会那么想,但这不是我试图将方法吸收到抽象类中的唯一情况。

谢谢!

编辑:
如果它是相关的(建议我可以考虑的其他方法),Application是一个插件api,MyApp是一个提供的示例应用程序。 DefaultApplication是基础项目的一部分。

2 个答案:

答案 0 :(得分:3)

你不能覆盖任何静态的东西。静态方法不属于特定对象,而是属于类本身;当您编写return NAME时,编译器会将其读为return DefaultApplication.NAME

在这种情况下,你可以像你已经提出的那样覆盖每个子类中的getName(),或者你可以使该字段非静态,并执行以下操作:

abstract class DefaultApplication implements Application {
  private final String name;

  protected DefaultApplication(String name) {
    this.name = name;
  }

  protected DefaultApplication() {
    this("DefApp");
  }

  public String getName() {
    return name;
  }
}

class MyApp extends DefaultApplication {

  public MyApp() {
    super("My App");
  }

}

这将为DefaultApplication的每个实例添加一个额外的字段,但只要你没有数百万个,这应该不重要。

答案 1 :(得分:2)

注释想法让我感兴趣,所以我想我会把它扔出去。这是一个非常复杂且不完全推荐的打印“我的应用程序”的方式:

import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

interface Application {
    public String getName();
}

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface ApplicationName {
  String value();
}

@ApplicationName("DefApp")
abstract class DefaultApplication implements Application {
    @Override
    public String getName() {
        return getClass().getAnnotation(ApplicationName.class).value();
    }
}

@ApplicationName("My App")
class MyApp extends DefaultApplication {
}

public class Main {
  public static void main(String[] args) {
    Application myApp = new MyApp();
    System.out.println(myApp.getName());
  }
}