我试图理解Java为什么如此工作。
假设我有:
Mammal
实现IAnimal
,而Dog
扩展了Mammal
。
Mammal
声明并实现方法breastFeed()
(当然,Animal
没有此签名,因为并非每只动物都是哺乳动物)
现在,我想创建一个狗对象,接口将以这种方式引用该狗:
IAnimal dog = new Dog();
在运行时的某个地方,我可能想使用breastFeed
方法,但是dog对象无法识别该方法。
一种解决方案是在Dog
类中实现此方法
其他解决方案是从Abstract类引用Dog
,该类实现了接口,在这种情况下,我将所有内容都交给dog对象。
我发现这些解决方案是混乱而又怪异的。有什么想法吗?也许我错过了一些东西,并且有一些更好更清洁的解决方案?
谢谢你, 耶夫。
答案 0 :(得分:0)
这是有效的,因为您有继承链。但是这里的事情是dog被声明为IAnimal
,它只公开该接口具有的方法,而不公开实现中的方法。如果需要访问breastFeed()
方法,则应将值强制转换为子类。
答案 1 :(得分:0)
让我们假设您在名为{{的程序包]中拥有接口IAnimal
,两个抽象类Mammal
和Bird
以及两个具体类Dog
和Eagle
1}}。 animals
和Mammal
实现了接口Bird
,而IAnimal
扩展了Dog
,而Mammal
扩展了Eagle
。这种情况如下所示(感谢@BackSlash的评论):
接口:
Bird
抽象类:
哺乳动物:
package animals;
public interface IAnimal {
void feed();
}
鸟:
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 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
,输出将是狗的行为... (请原谅生物学上的错误,可能有些鸟没有给它们的幼崽喂食。这些例子是为爪哇而不是自然而生的。)
答案 2 :(得分:0)
您应该完全忘记方法breastFeed
,因为这只是一个规范。只需将方法feed()
添加到IAnimal
中,然后让实现决定它们的食用方式:
interface IAnimal{
void feed();
}
abstract class Mammal implements IAnimal{}
Dog
可能会吃一些肉:
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();
然后您可以致电anmial.feed()
。然后让其他实现来处理。
答案 3 :(得分:0)
我将介绍扩展IMammal
的接口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()");
}
}
然后可以在需要时测试instanceof IMammal
。
答案 4 :(得分:0)
我不会在这里使用接口,因为所有行为都是继承的。但是,使用IAnimal dog = new Dog();
狗只能访问IAnimal
方法。因此,如果要将dog存储到Mammal
变量中,则可以访问breastFeed()
方法。
例如:
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();
}
}
希望这会有所帮助。
答案 5 :(得分:-2)
您可能想将变量声明为Mammal
,例如EG:
Mammal dog = new Dog();
或者您可能希望将dog
投射为Mammal
甚至是Dog
:
if (dog instanceof Mammal)
((Mammal) dog).breastFeed();