приведение к абстрактному классу ... как это возможно? - PullRequest
4 голосов
/ 02 января 2012

Я на самом деле читаю книгу о шаблонах проектирования в Java, и я новичок:)

http://www.amazon.com/Design-Patterns-Java-TM-Software/dp/0321333020/ в главе о композитных шаблонах я наткнулся на код, который озадачивает меня, бросокЧто касается абстрактного класса, я также не очень хорошо понял, что происходит, когда в подклассе вызывается конструктор абстрактного суперкласса.

приведение, о котором я говорю, находится в isTree (набор посещений)

        MachineComponent c = (MachineComponent) i.next();
        if (visited.contains(c) || !c.isTree(visited)) 

Как мы можем вызвать метод isTree подкласса после преобразования в его абстрактный суперкласс, покаметод isTree суперкласса является абстрактным?

Вот фрагменты двух классов:

package com.oozinoz.machine;
/*
 * Copyright (c) 2001, 2005. Steven J. Metsker.
 */

import java.util.*;
import com.oozinoz.iterator.ComponentIterator;

/**
 * Objects of this class represent either individual machines or composites of
 * machines.
 */

public abstract class MachineComponent {

    /*
     * Subclasses implement this to support the isTree() algorithm.
     */

    protected abstract boolean isTree(Set s);

    // rest of class omitted
}

2:

package com.oozinoz.machine;    
/*
 * Copyright (c) 2001, 2005. Steven J. Metsker.
 */

import java.util.*;
import com.oozinoz.iterator.ComponentIterator;
import com.oozinoz.iterator.CompositeIterator;

 /**
 * Represent a collection of machines: a manufacturing line, a bay, or a
 * factory.
 */

public class MachineComposite extends MachineComponent {
    protected List components = new ArrayList();

    /**
     * @param visited a set of visited nodes
     * @return true if this composite is a tree
     * @see MachineComponent#isTree()
     */

    protected boolean isTree(Set visited) {
        visited.add(this);
        Iterator i = components.iterator();
        while (i.hasNext()) {
            MachineComponent c = (MachineComponent) i.next();
            if (visited.contains(c) || !c.isTree(visited)) 
                return false;
        }
        return true;
    }

    // rest of class omitted
}

Ответы [ 5 ]

9 голосов
/ 02 января 2012

Это различие между типом времени выполнения (фактическим типом) и типом времени компиляции.

Тип-тип для абстрактного класса MachineComponent в порядке, потому что фактический экземпляр объекта на самом деле будет неабстрактным.подкласс MachineComponent, который реализует все абстрактные методы.

Абстрактный класс MachineComponent является типом времени компиляции присвоенной переменной.Но фактический экземпляр не создается (или не может быть) с этим абстрактным классом.

4 голосов
/ 02 января 2012

isTree является абстрактным только для абстрактного класса. Как только класс был инициализирован как неабстрактный, приведение его к абстрактному не изменит его память. Следовательно, вызов метода в абстрактном классе эффективно вызывает его в конкретной реализации.

Причина, по которой это полезно, заключается в передаче подклассов через абстрактную реализацию.

Допустим, у класса String есть метод length. Нет необходимости иметь функцию для каждого возможного подкласса типа String. Вместо этого вы приводите базовую (абстрактную) строку, имеющую реализацию length, и передаете ее.

3 голосов
/ 02 января 2012

ОК - давайте попробуем еще раз:

В: Можете ли вы привести к абстрактному классу?

A: Конечно - конечно, вы можете

Например:

public class UseAbstract
{
  public static void main (String[] args)
  {
    // Instantiate an abstract class
    AbstractPet myDog = new Dog ();
    myDog.sound ();

    // Instantiate a concrete class
    Cat myCat = new Cat ();
    myCat.sound ();

    // Cast a concrete class to an abstract class
    AbstractPet somePet = (AbstractPet)myCat;
    somePet.sound ();
  }
}

abstract class AbstractPet
{
  void sound ()
  {
    System.out.println ("eek");
  }
}

class Dog extends AbstractPet
{
  void sound ()
  {
    System.out.println ("Woof");
  }
}

class Cat extends AbstractPet
{
  void sound ()
  {
    System.out.println ("meow");
  }
}
2 голосов
/ 02 января 2012

Хорошо, давайте возьмем Cat, который является подклассом абстрактного класса Animal.

Вы можете разыграть Cat до Animal, потому что кошка - это животное . Он делает все, что делает нормальное животное, поскольку у него есть функции животного.

Подклассы абстрактного класса одинаковы. Вы можете просто использовать "is" , потому что это подкласс.

Вы можете определить список животных как зоопарк, но в нем могут быть собаки и кошки - в конце концов, они оба животные.

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

Редактировать
Если вам не нравятся кошки (я тоже не люблю), позвольте мне перенаправить вас на статью Википедии о наследовании . Абстрактные классы были бы бесполезны, если вы не можете их разыграть.

1 голос
/ 02 января 2012

Q: Можете ли вы привести к абстрактному классу?

A: Конечно, конечно, вы можете.

То, что вы не можете сделать, это назвать абстрактнымметод абстрактного класса.(вставка из раздела комментариев - Эндрю Барбер - ниже) - Вы фактически называете конкретную реализацию этого в подклассе.

...