2017-02-05 13 views
3

У меня есть следующий код:Java наследование и разрешение метод заказа

class p { 
    public void druckauftrag() { 
     // ... 
     drucke(); 
    } 

    public void drucke() { 
     System.out.println("B/W-Printer"); 
    } 
} 

class cp extends p { 
    public void drucke() { 
     System.out.println("Color-Printer"); 
    } 
} 

Вызов следующие строки:

cp colorprinter = new cp(); 
    cp.druckauftrag(); 

Там нет никаких проблем понять, почему «cp.druckauftrag(); " приводит к выпуску консоли «Цветной принтер».

Но когда я называю:

p drucker = (p)colorprinter; 
    drucker.druckauftrag(); 

я получаю тот же результат - почему? Переписывает ли типпередача метод «drucker» объекта «drucke» с помощью «drucke» от colorprinter?

Заранее благодарим за каждое объяснение.

+1

Немного nitpick: назовите свои классы прописными буквами для большей ясности. –

+1

Никогда не используйте свой неанглийский родной язык, когда классы именования, mehtods и т. Д. Используйте английский camelCase. –

+0

Тип класса - это определение того, как объект просматривается «внешними пользователями» (другими классами). Реализация метода привязана к экземпляру, и тип определяет только внешний cotract. – topr

ответ

3

colorprinter является примером cp. Даже когда вы повышаете его до p, это drucke() метод будет по-прежнему один от cp.

Разница в том, что после того, как вы настроите colorprinter, вы не сможете использовать методы, которые cp определяет самостоятельно.

4

colorprinter не перестает быть экземпляром cp при использовании оператора, наложенные на него, так его реализация public void drucke() не меняет

Что вы выражаете с (p)colorprinter кастинге вид контракт (интерфейс) вы ожидаете, что объект colorprinter удовлетворит, что включает открытый метод с подписями public void drucke(), но не какой-либо конкретной реализации.

И, кстати, эта отливка уже выполняется неявно при объявлении drucker типа p, так (p) избыточна в p drucker = (p)colorprinter;. p drucker = colorprinter; хватит.

Here you can learn more about typecasting.

Имейте в виду, что лучше всего отказаться от абстрактных классов или интерфейсов и только @Override (реализовать) абстрактные методы. Лучший дизайн вашего кода будет:

abstract class BasePrinter { 

    public void druckauftrag() { 
     // ... 
     drucke(); 
    } 

    public void drucke(); 

} 

class p extends BasePrinter {  
    public void drucke() { 
     System.out.println("B/W-Printer"); 
    } 
} 

class cp extends BasePrinter { 
    public void drucke() { 
     System.out.println("Color-Printer"); 
    } 
} 

Но, конечно, ограничения не всегда позволяют такого рода редизайн.Переходя базовые требования в качестве параметров конструктору (dependency injection) вместо расширения базового класса также может быть хорошей альтернативой:

interface Druckable { 
    void drucke(); 
} 

class Druckauftrager { 

    Druckable dk; 
    Druckauftrager(Drukable dk){ 
     this.dk = dk; 
    } 
    public void druckauftrag() { 
     // ... 
     dk.drucke(); 
    } 

} 

class p implements Druckable {  
    public void drucke() { 
     System.out.println("B/W-Printer"); 
    } 
} 

class cp implements Druckable { 
    public void drucke() { 
     System.out.println("Color-Printer"); 
    } 
} 

Теперь, если вы хотите, чтобы выразить, что принтер требует или может иметь несколько возможностей печати (как и в цвете и ч/б), вы просто пишете класс с как много дополнительных Drukable свойств и параметров конструктора, как вы хотите, например:

class BlackAndWhiteOrColorPrinter { 

    p blackAndWhitePrintService; 
    cp colorPrintService; 

    Druckable selectedPrintService; 

    BlackAndWhiteOrColorPrinter (p blackAndWhitePrintService, cp colorPrintService){ 
     this.blackAndWhitePrintService = blackAndWhitePrintService; 
     this.colorPrintService = colorPrintService; 
     this.selectedPrintService = blackAndWhitePrintService; 
    } 

    public void druckauftrag() { 
     // ... 
     selectedPrintService.drucke(); 
    } 

} 

Таким образом, вы можете даже написать class MultiPrinter с MultiPrinter(List<Druckable> printServices) конструктора и добавить любое количество режимов печати в свой список служб печати : p, cp, и любая другая реализация Druckable с ее public void drucke() появится в будущем. Это также весьма практично, если вы хотите ввести модульное тестирование, поэтому вы можете предоставить объекты макета, которые вынуждают конкретные условия, которые вы хотите протестировать, например, druke(), например, бросать PaperJamException.

Для получения дополнительной информации о том, как интерфейсы, переопределение и наследование работы, см https://docs.oracle.com/javase/tutorial/java/IandI/usinginterface.html

BTW, acording к последней версии официального java code conventions guide, а также де-факто стандартом, классы в Java должны использовать CamelCase именования. Вы также можете значительно выиграть от использования семантичного именования во всех своих определениях, таких как BlackAndWhitePrinter blackAndWhitePrinter и ColorPrinter colorPrinter.

0

При создании объекта с использованием оператора new память выделяется в heap. Методы и поля на самом деле существуют в зависимости от конкретного фактического класса объекта. Изменение подкласса переопределяет и изменяет поведение из его суперкласса, вызывая переопределенный метод, всегда будет приводить к измененному поведению. Кастинг будет означать только то, что объект подкласс теперь представлен супер-типом, поскольку объект имеет модифицированное поведение для метода, всегда будет приводить к измененному поведению.

Предположим, у вас есть ниже классов

public class Fruit{ 
    public void taste(){ 
    System.out.println("depends upon the actual fruit"); 
    } 
} 

public class Mango extends Fruit{ 
    @Override 
    public void taste(){ 
    System.out.println("sweet"); 
    } 
    public void wayToExposeSuperMethod(){ 
    super.taste(); 
    } 
} 

Другими словами его как вызов mango как fruit, но до сих пор остается mangomango. Для вышеуказанного кода

Fruit fruit = new Mango(); 

fruit.taste(); // <-- this will output : sweet 

((Mango)fruit).taste();// <-- this will output : sweet 

fruit.wayToExposeSuperMethod(); // <-- this will not compile 

((Mango)fruit).wayToExposeSuperMethod(); // <-- this will output : depends upon the actual fruit