Чаму не Java дазваляе мне выканаць гэты тып палімарфізму/спадчыну?

Я рэфактарынг вялізнага, калі заява ў мяне ёсць. Адзін са спосабаў, якія я знайшоў, каб палепшыць яго было выкарыстанне палімарфізму і атрымання ў спадчыну. У вельмі спрошчаным выглядзе, гэта тое, што ў мяне ёсць у маім кодзе:

public abstract class Animal {  
    public abstract void doAction();  
}

public class Dog extends Animal {  
    public void doAction() {System.out.println("run");} 
}

public class Cat extends Animal {  
    public void doAction() {System.out.println("sleep");}
}

public class RunActions {  
    public void runAction(Dog d) {
        d.doAction();
    }

    public void runAction(Cat c) {
        c.doAction();
    }
}

public class Start {
    public static void main(String args[]) {
        Animal animal = new Dog();
        new RunActions().runAction(animal);//Problem!
    }
}

Я ведаю, я ведаю. Я мог бы проста патэлефанаваць animal.doAction ();. Або дадаць метад у RunActions, які атрымлівае жывёла ў якасці параметру.

Але чаму не кампілятар дазвольце мне назваць гэта апошняе «(жывёла) runAction» лінію? Ці не вынікае віртуальная машына фігура з жывёльнага з'яўляецца асобнікам сабакі падчас выканання?

Ці ёсць канкрэтная прычына, чаму яна не дазваляе мне зрабіць гэта?

EDIT: Forgot to make Dog and Cat extend Animal. Fixed.

2
дададзена аўтар NINCOMPOOP, крыніца

6 адказы

Кампілятар не можа гарантаваць, што ёсць адпаведны метад падчас выканання.

У вас ёсць метад, які прымае Cat і ў вас ёсць метад, які прымае Dog . Вы спрабуеце перадаць Animal зменная, якая спасылаецца на Dog . Што рабіць, калі б спасылацца на Слон ? Тады не будзе прыдатным метадам падчас выканання. Вось чаму гэта не дазволіць вам кампіляваць.

Animal animal = new Elephant();
new RunActions().runAction(animal);//real problem now!
5
дададзена
@LucasTulio: Не, няма. Кампілятар глядзіць і бачыць, калі ён знаходзіць дастасавальныя метад для выкліку. Калі так, то добра, калі няма, то ваша памылка.
дададзена аўтар jlordo, крыніца
вы захавалі мае націску клавіш. +1
дададзена аўтар Arpit, крыніца
Гэта было вельмі лёгка зразумець. Дзякуй. Паколькі мы па гэтым пытанні: ці існуюць спосабы «падмануць» кампілятар, думаючы, што выклік нармальна? Напрыклад ... нейкая GetClass() (або іншага адлюстравання матэрыялу), каб падмануць кампілятар думаць, выклік будзе працаваць? Я не буду гэтага рабіць. Я абяцаю. Гэта проста з цікаўнасці.
дададзена аўтар Lucas Tulio, крыніца

Асноўная асноватворная канцэпцыя, якая робіць тое, што вы хочаце немагчыма, што Java з'яўляецца <�эм> Стабілізатары дыспетчарскай мовы, гэтак жа як і амаль ва ўсіх іншых мовах, званых «ААП». Што гэта азначае, што рашэнне падчас выканання які метад выклікаць ўлічвае толькі першы аргумент метаду, які сінтаксічна змяшчаецца перад кропкай , то адзін, значэнне якога будзе прывязаны да гэта спецыяльная пераменная.

Вы можаце таксама задацца пытаннем, чаму адзінкавая дыспетчарызацыя выкарыстоўваецца ў большасці моў ... гэта звязана з асноўнай ідэяй инкапсулирования і аб'ектаў, якія з'яўляюцца ўладальнікамі сваіх метадаў. Разгледзім ваш выпадак: калі runAction належаць RunActions або Animal ? Гэта ставіцца да абодвух аднолькава; лепш сказаць: гэта не належаць небудзь. Гэта прыводзіць да зусім іншай мадэлі праграмавання, адзін без інкапсуляцыі.

3
дададзена

Праблема заключаецца ў тым, не ўсе жывёлы могуць быць кошкі або сабакі. разгледзім:

public class Fish implements Animal{  
    public void doAction() {System.out.println("swim");  
}

Што б вы чакаеце, што ваш клас RunActions рабіць?

Вось чаму кампілятар скардзіцца.


Ёсць некалькі падыходаў, якія можна выкарыстоўваць, каб зрабіць вашу сітуацыю працу. Прасцей за ўсё мець адзін метад, які прымае жывёла і выкарыстоўваць серыю InstanceOf тэстаў, каб высветліць, што вы хочаце зрабіць з кожным канкрэтным падкласа жывёл.

1
дададзена

Па-першае, вы не распаўсюджваюць жывёла ў сабакі і каты. Так зрабіць гэта першым.

У спадчыну ISA асноўны атрымлівае было.

так, напрыклад,

public class Dog extends Animal

тут сабака праходзіць жывёл так, што <�моцны> DOG IS ANIMAL , але не наадварот ЖЫВЁЛАЎ НЕ МОЖА БЫЦЬ АБАВЯЗКОВА САБАКІ. ГЭТА МОЖА БЫЦЬ САТ ТАКСАМА У Вашым ВЫПАДКУ.

Таму, калі вы перадаеце спасылку на <�моцны> жывёла да метаду, які прымае DOG або прысваенне КПП будзе нешта накшталт

Dog d=animal;

які чытаецца як <�моцны> жывёла DOG і што гэта не так.

Таму кампілятар не дазволіць вам зрабіць гэта.

А наконт таго, чаму Java не дазваляе гэтага, што неабходна зрабіць, каб дасягнуць функцыі, якія яна здольная дасягнуць.

Скажам, напрыклад, Java дазваляе перадаць аб'ект жывёльнага да метаду і дазваляе выканаць метад.

так што ў гэтым выпадку

Animal animal=new Dog();
Dog d= animal;
d.doSomething();//let's say java allowed this no problem since animal is DOG.

АЛЕ,

Animal animal=new Horse();
Dog d= animal;
d.doSomething();//Can you imagine what will happen in this case?

Таму, каб пазбегнуць такіх situaltion Java досыць разумны, каб спыніць вас, калі вы робіце няправільна. Спадзяюся, што гэта ачышчае вашы сумневы і дапаможа вам зразумець гэта.

1
дададзена
Я думаю, што пытанне <�я> чаму , хоць. Напрыклад, CLOS робіць дыспетчарскія шляху ОП спрабуем зрабіць гэта ў Java.
дададзена аўтар Dave Newton, крыніца
Агульная сістэма Lisp Object; ён выкарыстоўвае множную дыспетчарызацыі.
дададзена аўтар Dave Newton, крыніца
@DaveNewton: абноўлены адказ. :)
дададзена аўтар ankurtr, крыніца
@DaveNewton: CLOS?
дададзена аўтар ankurtr, крыніца
@DaveNewton: ок. не ведаюць пра гэта.
дададзена аўтар ankurtr, крыніца

Перш за ўсё, Dog і Cat павінен распаўсюджвацца Animal :

public class Dog exttends Animal{  
    @Override
    public void doAction() {System.out.println("run");  
}

І выкарыстоўваць:

public class RunActions {  
    public void runAction(Animal a) {
        a.doAction();
    }
}

Паколькі і Dog і Cat з'яўляюцца Жывёлы , вы можаце выкарыстоўваць Animal аргумент.

1
дададзена
OP ведае, што ён мог бы зрабіць гэта. Яго пытанне было, чаму яго адправілі код не дапускаецца.
дададзена аўтар jlordo, крыніца

Лепш зрабіце наступнае

public interface Animal {  
    public void doAction();  
}

public class Dog implements Animal{  
    public void doAction() {System.out.println("run");  
}

public class Cat implements Animal{  
    public void doAction() {System.out.println("sleep");  
}

public class RunActions {  
    public void runAction(Animal d) {
        d.doAction();
    }
}

public class Start {
    public static void main(String args[]) {
        Animal animal = new Dog();
        new RunActions().runAction(animal);
    }
}
0
дададзена
Жывёла можа быць абстрактны клас, напрыклад, рэалізаваць некаторыя агульныя рысы, агульныя для ўсіх тыпаў Animal .
дададзена аўтар orique, крыніца