Подтвердить что ты не робот

Есть ли способ сделать метод, который не является абстрактным, но должен быть переопределен?

Есть ли способ заставить дочерние классы переопределить не абстрактный метод суперкласса?

Мне нужно иметь возможность создавать экземпляры родительского класса, но если класс расширяет этот класс, он должен дать свое определение некоторых методов.

4b9b3361

Ответ 1

В этом нет, как я знаю, прямого метода, способного выполнять компилятор.

Вы можете обойти это, не создавая родительский класс, но вместо этого предоставляя метод factory, который создает экземпляр некоторого (возможного частного) подкласса, который имеет реализацию по умолчанию:

public abstract class Base {
  public static Base create() {
    return new DefaultBase();
  }

  public abstract void frobnicate();

  static class DefaultBase extends Base {
    public void frobnicate() {
      // default frobnication implementation
    }
  }
}

Теперь вы не можете написать new Base(), но вы можете сделать Base.create(), чтобы получить реализацию по умолчанию.

Ответ 2

Как указывали другие, вы не можете сделать это напрямую.

Но один из способов сделать это - использовать шаблон Стратегия, например:

public class Base {
    private final Strategy impl;

    // Public factory method uses DefaultStrategy
    // You could also use a public constructor here, but then subclasses would
    // be able to use that public constructor instead of the protected one
    public static Base newInstance() {
        return new Base(new DefaultStrategy());
    }

    // Subclasses must provide a Strategy implementation
    protected Base(Strategy impl) {
        this.impl = impl;
    }

    // Method is final: subclasses can "override" by providing a different
    // implementation of the Strategy interface
    public final void foo() {
        impl.foo();
    }

    // A subclass must provide an object that implements this interface
    public interface Strategy {
        void foo();
    }

    // This implementation is private, so subclasses cannot access it
    // It could also be made protected if you prefer
    private static DefaultStrategy implements Strategy {
        @Override
        public void foo() {
            // Default foo() implementation goes here
        }
    }
}

Ответ 3

Рассмотрим возможность создания интерфейса с этим методом. Потомкам класса придется реализовать его.

Ответ 4

Я думаю, что самый простой способ - создать абстрактный класс, который наследуется от базового класса:


public class Base {
    public void foo() {
        // original method
    }
}

abstract class BaseToInheritFrom extends Base {
    @Override
    public abstract void foo();
}

class RealBaseImpl extends BaseToInheritFrom {
    @Override
    public void foo() {
        // real impl
    }
}

Ответ 5

Нет, что вся точка абстрактного метода. Каков ваш прецедент? Возможно, мы сможем подумать об этом, основываясь на основной потребности.

Ответ 6

Как об этом: внутри реализации метода по умолчанию используйте отражение, чтобы получить точный класс объекта. Если класс не соответствует вашему базовому классу, бросьте исключение RuntimeException или его эквивалент.

public class Parent {

    public void defaultImpl(){
        if(this.getClass() != Parent.class){
            throw new RuntimeException();
        }
    }

}

Ответ 7

Там причина не возможна!

Производный класс может просто вызвать реализацию базового класса при переопределении метода.

Итак, что же заставляет класс переопределять ваш метод? Я не думаю, что есть какая-то польза.

Ответ 8

Ответ будет нет. Вы можете перепроектировать шаблон шаблона шаблона. Это может вам помочь.

В качестве альтернативы вы можете сделать свои дочерние классы реализованным интерфейсом. Интерфейс может или не может быть реализован суперклассом.

Ответ 9

Вы всегда можете сделать базовый класс методом, который генерирует исключение.

Технически базовый класс определил этот метод, но он не может использоваться без переопределения метода. В таком случае я предпочитаю исключение во время выполнения, поскольку для него не требуется явно выраженная команда throw. Пример следует

public class Parent {

  public void doStuff() {
    throw new RuntimeException("doStuff() must be overridden");
  }

}

public class Child extends Parent {

  @Override
  public void doStuff() {
    ... all is well here ...
  }

}

Недостатком является то, что это не мешает созданию объектов Base; однако каждый, кто пытается использовать один из методов "должен быть переопределен", скоро обнаружит, что они должны были переопределить класс.

В то время как это решение удовлетворяет описанию запроса, ваше приложение, вероятно, выиграет от не требующего решения, подобного этому. Это намного лучше, чтобы избежать сбоев во время выполнения с проверками компилятора, что и предоставляет абстрактное ключевое слово.

Ответ 10

Я отражу другие ответы и скажу, что не существует принудительного способа, с помощью которого производные классы могут переопределять не абстрактный метод. Весь смысл создания абстрактного метода состоит в том, чтобы определить, что метод с этой сигнатурой должен существовать, но не может быть указан на базовом уровне и поэтому должен быть указан на производном уровне. Если есть работающая, нетривиальная реализация (так как она не пустая и не просто генерирует исключение или показывает сообщение) метода на базовом уровне, то это не является строго необходимым для того, чтобы вызвать метод от потребителя производного класса для успеха. Таким образом, компилятору не требуется принудительно отменять метод, который может успешно выполняться на базовом или производном уровнях.

В ситуациях, когда вы хотите, чтобы производный класс переопределял вашу рабочую реализацию, должно быть довольно очевидно, что базовая реализация не делает то, что захотят потребители производного класса; базовый класс либо не имеет достаточной реализации, либо неправильный. В таких случаях вы должны доверять тому, что программист, получающий ваш класс, будет знать, что он делает, и тем самым знать, что метод нужно переопределить, потому что он не дает правильного ответа в контексте использования его нового объекта.

Я могу думать о одной вещи, которую вы могли бы сделать. Для этого потребуется абстрактная база с запечатанной (финальной для Javaheads) реализацией по умолчанию. Таким образом, существует базовая реализация метода, который легко доступен для использования, как если бы он был "базовым" классом, но для того, чтобы определить другой класс для нового сценария, вы должны вернуться к абстрактному классу и поэтому вынуждены переопределять метод. Этот метод может быть единственной абстрактной вещью в классе, тем самым позволяя использовать основные реализации других методов:

public abstract class BaseClass
{
   public abstract void MethodYouMustAlwaysOverride();

   public virtual void MethodWithBasicImplementation() { ... }
}

public final class DefaultClass:BaseClass
{
   public override void MethodYouMustAlwaysOverride() { ... }

   //the base implementation of MethodWithBasicImplementation 
   //doesn't have to be overridden
}

...

public class DerivedClass:BaseClass
{
   //Because DefaultClass is final, we must go back to BaseClass,
   //which means we must reimplement the abstract method
   public override void MethodYouMustAlwaysOverride() { ... }

   //again, we can still use MethodWithBasicImplementation, 
   //or we can extend/override it
   public override void MethodWithBasicImplementation() { ... }
}

Однако это имеет два недостатка. Во-первых, поскольку у вас нет доступа к реализации DefaultClass через наследование, вы не можете расширять реализацию DefaultClass, а это значит, что для выполнения того, что делает DefaultClass, плюс немного больше, вы должны переписать код из DefaultClass, нарушив DRY. Во-вторых, это работает только для одного уровня наследования, потому что вы не можете заставить переопределить, если вы разрешаете наследование из DerivedClass.

Ответ 11

возможно, это помогает:

class SuperClass {

    void doStuff(){

        if(!this.getClass().equals(SuperClass.class)){

            throw new RuntimeException("Child class must implement doStuff Method");
        }else{
            //ok
            //default implementation
        }
    }
}

class Child extends SuperClass{

    @Override
    void doStuff() {
        //ok
    }
}

class Child2 extends SuperClass{

}


 new SuperClass().doStuff(); //ok
 new Child().doStuff();         //ok
 new Child2().doStuff();        //error

Ответ 12

ОК, давайте учиться этому так. Я придерживаюсь правил стиля java и использую синтаксис Java. Таким образом, предполагается, что множественные наследования и шаблоны С++ недоступны.

создание абстрактного метода метода родительского класса не является обязательным, в ООП вы используете концепцию полиморфизма. вы можете использовать один и тот же метод двумя или несколькими способами. Это называется переопределением метода.

возьмем пример.

    public class Animal{
       public void makeSound(){
          System.out.println("Animal doesn't know how to make sound");
       }

    }

    public class PussyCat extends Animal{
        public void makeSound(){

           System.out.println("meowwww !!!");
        }

        public static void main(String args[]){
           PussyCat aCat=new PussyCat();
           aCat.makeSound(); 
        }
    }

это напечатает "meowww!!!" на экране.

но это не означает, что метод makeSound должен быть переопределен в дочернем классе.

Если вам нужно, чтобы дочерний класс был вынужден переопределить методы, лучше реализовать интерфейс по этому классу.

      public Interface audible{
         public void makeSound();

      }

      public class pussyCat implements audible{
          // now you must implement the body of makeSound method here
          public void makeSound(){
            System.out.println("meowwww !!!"); 
          }

          public static void main(String args[]){
           PussyCat aCat=new PussyCat();
           aCat.makeSound(); 
        }
      }

это также напечатает "meowwww!!!" на экране