Java接口对扩展抽象类的具体类的引用
我试图理解为什么Java是这样工作的 假设我有:Java接口对扩展抽象类的具体类的引用,java,class,interface,abstract,Java,Class,Interface,Abstract,我试图理解为什么Java是这样工作的 假设我有: 界面-IAnimal 抽象类-哺乳动物 混凝土类-狗 哺乳动物实现了IAnimal和狗扩展了哺乳动物 interface IAnimal { public void feed(); } interface IMammal extends IAnimal { public void breastFeed(); } abstract class Mammal implements IMammal { @Override
哺乳动物
实现了IAnimal
和狗
扩展了哺乳动物
interface IAnimal {
public void feed();
}
interface IMammal extends IAnimal {
public void breastFeed();
}
abstract class Mammal implements IMammal {
@Override
public void feed() {
breastFeed();
}
}
class Dog extends Mammal {
@Override
public void breastFeed() {
System.out.println("Dog breastFeed()");
}
}
哺乳动物
声明并实施方法母乳喂养()
(当然动物
没有此签名,因为并非所有动物都是哺乳动物)
现在我想创建一个dog对象,接口将引用此dog,方法如下:
IAnimal dog = new Dog();
在运行时的某个地方,我可能想使用母乳喂养
方法,但dog对象无法识别此方法
一种解决方案是在Dog
类中实现此方法
另一个解决方案是从实现接口的抽象类中引用Dog
,在本例中,我将所有内容都提供给Dog对象
我觉得这些解决方案既混乱又怪异。有什么想法吗?也许我错过了什么,还有更好更干净的解决方案
谢谢你,
Yoav.这是有效的,因为您的继承链。但是这里的问题是dog被声明为
IAnimal
,它只公开该接口拥有的方法,而不公开实现中的方法。如果需要访问母乳喂养()
Mammal dog = new Dog();
或者你可能想把你的狗
扔给哺乳动物
,甚至是狗
:
if (dog instanceof Mammal)
((Mammal) dog).breastFeed();
让我们假设在名为动物的包中有接口IAnimal
、两个抽象类哺乳动物和鸟、两个具体类狗和鹰<代码>哺乳动物
和鸟
实现接口IAnimal
,而狗
扩展哺乳动物
和鹰
扩展鸟
。这种情况如下所示(感谢@backslax的评论):
界面:
package animals;
public interface IAnimal {
void feed();
}
package animals;
public class Dog extends Mammal {
/*
* This is how dogs feed, the implementation of how mammals feed
*/
@Override
protected void breastFeed() {
System.out.println("currently breastfeeding... do not disturb!");
}
}
抽象类:
package animals;
public interface IAnimal {
void feed();
}
package animals;
public class Dog extends Mammal {
/*
* This is how dogs feed, the implementation of how mammals feed
*/
@Override
protected void breastFeed() {
System.out.println("currently breastfeeding... do not disturb!");
}
}
哺乳动物:
package animals;
abstract class Mammal implements IAnimal {
/*
* This is the feeding method that every animal has to implement.
* The trick here is to force the inconcrete method feed() to use the
* mammal specific one that has to be implemented by concrete mammals
*/
@Override
public void feed() {
breastFeed();
}
/*
* This is how mammals feed,
* so every concrete mammal has to implement this method (even humans...)
*/
protected abstract void breastFeed();
}
鸟类:
package animals;
public abstract class Bird implements IAnimal {
/*
* This time, force the inconcrete method feed() to use the
* bird specific one that has to be implemented by concrete birds
*/
@Override
public void feed() {
feedPrey();
}
/*
* Birds feed prey to their young, most likely due to a lack of breasts
*/
protected abstract void feedPrey();
}
具体类别:
package animals;
public interface IAnimal {
void feed();
}
package animals;
public class Dog extends Mammal {
/*
* This is how dogs feed, the implementation of how mammals feed
*/
@Override
protected void breastFeed() {
System.out.println("currently breastfeeding... do not disturb!");
}
}
您可以使用main
方法检查某个类的输出,如下所示:
import animals.Dog;
import animals.Eagle;
import animals.IAnimal;
public class Test {
public static void main(String[] args) {
IAnimal dog = new Dog();
IAnimal eagle = new Eagle();
dog.feed();
eagle.feed();
}
}
输出结果就是狗的行为。。。
(请原谅生物学上的错误,可能有鸟类不给幼鸟喂食。这些例子是为java而做的,不是为大自然而做的…你应该完全忘记母乳喂养的方法,因为这只是一个规范。只需将一个方法feed()
添加到IAnimal
中,然后让实现决定它们的进食方式:
interface IAnimal{
void feed();
}
abstract class Mammal implements IAnimal{}
狗可能会吃一些肉:
class Dog extends Mammal{
public void feed(){
System.out.println("Eating meat!");
}
}
而BabyCat
可能会喝一些牛奶:
class BabyCat extends Mammal{
public void feed(){
System.out.println("Drinking milk!");
}
}
这是一条路要走,所以当宣布一只狗如下:
IAnimal animal = new Dog();
然后,您只需调用anemial.feed()
。然后让实现来处理其余的部分。我将介绍一个扩展IAnimal
的接口imal
interface IAnimal {
public void feed();
}
interface IMammal extends IAnimal {
public void breastFeed();
}
abstract class Mammal implements IMammal {
@Override
public void feed() {
breastFeed();
}
}
class Dog extends Mammal {
@Override
public void breastFeed() {
System.out.println("Dog breastFeed()");
}
}
然后,您可以在需要时测试IMammal的实例。我不会在这里使用接口,因为所有行为都是继承的。但是,使用IAnimal dog=new dog()
dog只能访问IAnimal
方法。因此,如果要将dog存储到哺乳动物
变量中,则可以访问母乳喂养()
方法
例如:
public abstract class Animal {
public abstract void feed();
}
public abstract class Mammal extends Animal {
public abstract void breastFeed();
}
public class Dog extends Mammal{
@Override
public void breastFeed() {
System.out.println("Drinking milk!");
}
@Override
public void feed() {
System.out.println("Eating meating");
}
}
public class TryingAnimal {
public static void main(String[] args) {
Dog dog = new Dog();
dog.breastFeed();
dog.feed();
Animal animal = dog;
animal.feed();
Mammal mammal = dog;
mammal.breastFeed();
}
}
希望这能有所帮助。您可以简单地使用((Dog)Dog)来调用它。母乳喂养()。然后你只需在你的IAnimal
对象上调用feed()
,而母乳喂养()
将自动在你的哺乳动物
对象上调用。@Lino这只是一个例子,当然Dog
类需要管理如何喂养狗。多态性的主要优点是,您不需要真正了解对象的行为,只需定义一个公共接口,每个类都有自己的实现。动物应该喂食
:它如何喂食以及吃什么取决于特定的动物。这并没有增加任何内容,OP已经知道第一个“解决方案”,第二个“解决方案”已经由其他人提出。请完全删除哺乳动物类。并使母乳喂养()。如果可以,最好使用适当的继承。@Lino-还有可能哺乳动物
会扩展一个抽象类动物
。引入另一个中间类,对于当前的示例来说没有意义。但我同意你的观点,当哺乳动物有其他哺乳动物之间的共同状态,而不是动物之间的共同状态时