Java наследует от абстрактного класса

#java #inheritance #polymorphism #abstract-class

#java #наследование #полиморфизм #абстрактный класс

Вопрос:

Я создаю класс Node для использования в двух похожих, но принципиально разных алгоритмах. Имея некоторую общую функциональность между ними, моя идея заключалась в создании абстрактного класса node с общими методами и полями. Расширьте из этого абстрактного класса два конкретных подкласса WaveNode и EchoNode.

Некоторые методы в абстрактном классе имеют дело с экземплярами узла, но я хотел использовать этот общий код с экземпляром подкласса, то есть, если вы даете методу WaveNode или EchoNode, тогда методу не нужна другая реализация. Поэтому я подумал, что лучше всего реализовать его в абстрактном классе, и оба подкласса могут использовать реализацию, поэтому мне не нужно вводить ее дважды. Однако, когда я нахожусь в своем подклассе и имею дело с WaveNode или EchoNode, я получаю ошибки компиляции, потому что метод ожидает экземпляр абстрактного узла. Есть ли способ реализовать метод в суперклассе, и разные классы, расширяющие суперкласс, могут использовать его реализацию.

Пример приведен ниже.

 Set<Node> getNeighs(){
    Set<Node> nei = (Set<Node>) rec.keySet();       
    nei.remove(this);
    return nei;
}
  

Этот код принимает карту «rec» и помещает набор ключей (узла) в набор узлов. Удаляет текущий узел и возвращает все его соседние узлы. Таким образом, и WaveNode, и EchoNode используют один и тот же код. Единственное отличие заключается в том, что набор будет иметь WaveNode или EchoNode. Я хотел реализовать его с помощью Node в суперклассе, чтобы избавить меня от необходимости писать его дважды. Возможно ли это?

Редактировать

Публикуем еще немного кода:

 public abstract class Node {

   private final int id;
   Map<Node, Boolean> rec = new HashMap<Node, Boolean>();


   public Node(int id) {
       this.id = id;
   }


   int getId() {
        return id;
   }

   void addNeigh(Node neigh) {
       rec.put(neigh, false);
   }

   Set<Node> getNeighs() {
       Set<Node> nei = (Set<Node>) rec.keySet();        
       nei.remove(this);
       return nei;
   }

   void printNeighbours() { 
       Set<Node> nei = getNeighs();
       System.out.println(this  " neighbours are: "   nei);
   }

    Node getSilentNeigh() {
        for(Entry<Node, Boolean> entry : rec.entrySet())
        {
            if(!entry.getValue())
                return entry.getKey();
        }   
        return null;
    }



public final class TreeNode extends Node {


    boolean messageSent = false;


    public TreeNode(int id){
        super(id);
    }

    public void sendTok(TreeNode sender){
        rec.put(sender, true);
    }
  

Пожалуйста, имейте в виду, что сейчас у меня все работает так, как задумано, я сам виноват в том, что не привел возвращаемый тип узла к TreeNode. Однако любые комментарии к моему коду «делают слишком много» или аналогичные советы по очистке моего кода приветствуются. Спасибо

Комментарии:

1. Можете ли вы опубликовать весь свой фактический код (удалить несвязанные части) и сообщение об ошибке

2. Однако метод, который вы показали, не принимает параметры. Как он принимает rec ?

3. Я думаю, что вы хотите использовать какой-то тип в абстрактном классе (т. Е. EchoNode extends AbstractXXX<EchoNode> ), Но я не уверен

4. Извините, ребята, мне просто нужно было привести возвращаемый тип метода, возвращающего узел в TreeNode. Я думал, что это опасно, так как вы должны стараться избегать отбрасывания, но, похоже, это работает и не дает мне ошибок. В настоящее время я изучаю наследование, поэтому, возможно, ошибка новичка. Спасибо

Ответ №1:

Используйте generics для этого вместо того, чтобы вводить текст конкретно в Node. Измените возвращаемую сигнатуру с Set<Node> на Set<? extends Node> или попросите подкласс обрабатывать общий тип, а не его тип.

Ответ №2:

Set<WaveNode> or Set<EchoNode> не является подклассом Set<Node> и не может быть приведен к нему; и вы не можете вызывать remove(WaveNode ..) с аргументом типа суперкласса ( Node ) . Если бы у вас было keySet так, как Set<Node> это было бы нормально, или используйте необработанный тип: Set nei = rec.keySet();

Ответ №3:

пытаясь быть более полезным, я попытался интуитивно понять суть проблемы и найти работоспособное решение. есть много более сложных моментов, которые мог бы выполнить код (см., Nosretep выше), но слишком много деталей может отвлечь новичка от изучения основного момента; поэтому этот код только наводит на мысль о простом рабочем подходе.

 import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

/* this class does everything that EVERY Node does since it defines what that means; for
 * ANY behaviors that are common to subclasses, here is where they should be implemented.
 */
abstract class Node {
    private final int id;
    private boolean tokenSent = false;

    public Node(int id) {
        this.id = id;
    }

    int getId() {
        return id;
    }

    // common behavior: other things that a Node might wish to do in context of the problem
    public void sendTok() {
        if (!tokenSent) {
            // send token here
            tokenSent = true;
        }
    }

    /* common behavior: this is not really the ideal way to do this, but hopefully it makes
     * sense in the context of the problem being solved; better would be an iterator that
     * visits each node in the list and performs the printing, etc., but this is in the 
     * spirit of the problem
     */
    public void printNeighboursOf(List<Node> list) {
        if (list.size() > 1) {
            System.out.print(this   "["   getId()   "] has neighbors: ");
            Node node;
            Iterator<Node> iterator = list.iterator();
            while (iterator.hasNext()) {
                node = iterator.next();
                if (!node.equals(this))
                    System.out.print(node   "["   node.getId()   "] ");
            }
        } else {
            System.out.print(this   " has no neighbors");
        }
        System.out.println();
    }

    /* this method has no implementation in this class (hence its being abstract); each
     * subclass MUST implement it (or their subclasses!), allowing differing algorithms.
     * the signature (method name and parameter list) must be identical for every subclass
     */
    public abstract int doSomeNodeBehavior();
}

/* this class knows and does everything a Node knows and does, and adds a bit more; it
 * can do additional things differently or other than what EchoNode does
 */
class WaveNode extends Node {
    public WaveNode(int id) {
        super(id);
    }

    public void doWaveBehavior() {
        // do something wavy here
    }

    public int doSomeNodeBehavior() {
        // do the wave algorithm
        return 0;
    }
}

/* this class knows and does everything a Node knows and does, and adds a bit more
 * can do additional things differently or other than what WaveNode does
 */
class EchoNode extends Node {
    public EchoNode(int id) {
        super(id);
    }

    public void doEchoBehavior() {
        // do something echoy here
    }

    public int doSomeNodeBehavior() {
        // do the echo algorithm
        return 0;
    }
}

/* it is best to reduce the amount of behavior the Node container (ArrayList in this case)
 * does beyond what is typical for an Abstract Data Type (ADT) element; make the additional
 * behavior in other classes.  visit each node to perform specific behaviors and let the
 * polymorphic behavior determine exactly what to do.  Note: subclass specific behavior is
 * not possible without downcasting, and that MAY be a sign of poor design
 */
public class Nodes {
    public static void main(String[] args) {
        List<Node> list = new ArrayList<Node>();
        list.add(new WaveNode(1));
        list.add(new WaveNode(2));
        Node node = new EchoNode(1);
        list.add(node);
        list.add(new EchoNode(2));

        node.printNeighboursOf(list);
    }
}