簡體   English   中英

Java 中的抽象方法即使被覆蓋也可以具有默認行為嗎?

[英]Can an abstract method in Java have a default behavior even if it is overridden?

也許方法是錯誤的。 我的想法如下:

public abstract AbstractParser<T extends Value> {
  T value;

  //want to do something like
  public abstract void parseSomething(Model model) {
    value = (T) model.getValue()
  }
}

然后我希望每個子類都覆蓋 parseSomething 而不會丟失默認行為。 因此,當孩子覆蓋 parseSomething 時,它將具有正確實現它的價值

public ConcreteParser extends AbstractParser<ConcreteValue> {
  //now in Value I have a ConcreteValue to access

  @Override
  public void parseSomething(Model model) {
    //here I want to do stuff with value without having to do:
    value = (ConcreteValue) model.getValue();
    //in every implementation I create
  }
}

有任何想法嗎?

缺少的第一個,您需要一個Class<T>來轉換為T (類型擦除)。 (如果模型不可參數化。)

對於這個問題有一個很好的解決方案,與

  • 最終的、不可parseSomething 、公共 API服務方法 - parseSomething
  • 應該覆蓋的內部、受保護的請求實現方法 - onParseSomething。

可覆蓋的方法在最終的公共方法中被調用,並且可以有更多的參數,比如值。 該方法可以是abstract

所以:

public abstract AbstractParser<T extends Value> {
  private final Class<T> valueType;
  protected T value;

  protected AbstractParser(Class<T> valueType) {
    this.valueType = valueType;
  }

  // Class users will call this method
  public final void parseSomething(Model model) {
    value = valueType.cast(model.getValue());
    onParseSomething(model, value);
  }

  // Class implementors will override/implement this method
  protected void onParseSomething(Model model, T value) {
  }
}


public ConcreteParser extends AbstractParser<ConcreteValue> {

  public ConcreteParser() {
      super(ConcreteValue.class);
  }

  @Override
  public void onParseSomething(Model model, ConcreteValue value) {
  }
}

是的,這甚至擴展到 Java 8 的接口:

public interface IExample {

    default public String test() {
        return " world!";
    }

}

public class Example implements IExample {

    @Override
    public String test() {
        return "Hello " + IExample.super.test();
    }

}

要引用父接口的 super 方法,還必須在super之前包含類名。 最終結果:

System.out.println(new Example().test());
//Hello world!

從語義上講,如果您想保護特定父方法的功能,並且讓子類僅定義行為的一個子集,請考慮使用面向公眾的方法和用於定義該行為子集的受保護方法:

public abstract class AbstractParser<T extends Value> {

    protected T value;

    //final, cannot be overridden
    public final void parseSomething(Model model) {
        this.value = (T) model.getValue();
        this.continueParsing();
    }

    protected abstract void continueParsing();

}

public class ConcreteParser extends AbstractParser<ConcreteValue> {
    @Override
    protected void continueParsing() {
        //invoked after the value `T` is set by the public method
        //references to `this.value` will be of type `T` or in this case, `ConcreteValue`
    }
}

您正在尋找的內容只能通過泛型來完成。

Model類可以參數化:

class Model<T> {
   ...
   T getValue();
   ...
}

然后AbstractParser類可以重寫為:

abstract class AbstractParser<T> {
   T value;

   public abstract void parseSomething(final Model<T> model) {
      this.value = model.getValue();
   }
}

由於保證在使用之前初始化value ,因此可以使用構造函數注入將類重寫為不可變的。

abstract class AbstractParser<T> {
   final T value;

   AbstractParser(final Model<T> model) {
      this.value = model.getValue();
   }

   ...
}

這將為您做到:

public ConcreteParser extends AbstractParser<ConcreteValue> {

 @Override
 public void parseSomething(Model model) {
   if(!(model instanceOf ConcreteValue)) // to ensure safety
      return;
   //do what ever you like first, this.value is null by far if 
   //this method is getting called the 1st time

   super.parseSomething(model);

   // now you can use value as you like from here on. 
 }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM