【问题标题】:Passing settings via interfaces in Java - possible?通过 Java 中的接口传递设置 - 可能吗?
【发布时间】:2019-03-22 23:11:00
【问题描述】:

假设我有两个班级。

public class Banana extends Fruit{    
    public Banana() {
        this.setTitle("Banana");
        this.setSize("Medium");
        this.setState("Rotten");
    }
}
public class Sausage extends Meat{    
    public Sausage() {
        this.setTitle("Sausage");
        this.setSize("Medium");
        this.setState("Rotten");
    }
}

有没有办法引入一个可以保存通用设置的接口(可能使用默认方法)?两个原始扩展都应保留。

我在谷歌上搜索了大约一个小时的接口和默认方法,并在 Java 聊天服务器上询问了这个问题,但我仍然感到困惑。

【问题讨论】:

  • 接口没有实例字段。他们不能保持状态。
  • 首先你需要有一个被其他人扩展的通用类。除非 Fruit 和 Meat 在某个共同的地方相遇,否则您无法保留共同的设置。
  • 如果我有一个共同的课程,这将不再是一个有趣的问题。为了科学起见,让我们假设他们没有。我还能用接口和默认情况完成任何事情吗?
  • 您不能直接执行此操作。 我认为您在这里基本上要求的是多重继承,而这个概念似乎给 Java 语言设计者带来了严重的轻率。你可以自己实现类似的东西。
  • @markspace 提供的类如何实现的任何示例?

标签: java java-8 interface


【解决方案1】:

您不能直接执行此操作。我认为您在这里基本上要求的是多重继承,而这个概念似乎给 Java 语言设计者带来了严重的轻率。不过你可以自己实现类似的东西。

假设你有一个接口Food

public interface Food {    
    void setTitle(String s);
    void setSize(String s);
    void setState(String s);
}

那么你可以这样做:

public class BaseFood implements Food {  
    private String title;  
    private String size;  
    private String state;  
    // setters and getters...
}

然后是这个:

public class Banana extends Fruit implements Food {    
    private BaseFood food = new Food();
    public Banana() {
        food.setTitle("Banana");
        food.setSize("Medium");
        food.setState("Rotten");
    }
}

为了完整,这里是Sausage,和Banana基本一样:

public class Sausage extends Meat implements Food {    
    private BaseFood food = new Food();
    public Sausage() {
        food.setTitle("Kielbasa");
        food.setSize("Medium");
        food.setState("Tasty");
    }
}

这称为“委托”,您将 Java 中某个接口的实现委托给另一个对象,只声明它实现了一个通用接口,然后只调用实际实现该接口的私有实例上的方法。它基本上是手动多重继承。

我的 IDE (NetBeans) 会为我完成大部分工作,这很常见。给定一个接口和一个实现该接口的私有实例成员,它将编写公开实现该接口所需的所有方法。它工作正常,但可以生成很多样板。我有点希望 Java 人员至少能在语言中为“多重继承问题”提供部分解决方案。

编辑:你说没有共同的基类,但是你说的是:

在这种情况下,您不能创建基类,因为它是具有单一继承性的 Java - 而且 Sausage 和 Banana 都已经在扩展某些东西。除非我遗漏了你能看到的东西......

如果你可以改变继承,你可以创建一个通用的基类:

class Food { ...
class Fruit extends Food {...
class Banana extends Fruit {...
class Meat extends Food {...
class Sausage extends Meat { ...

但我的回答假设您出于任何原因都不能这样做。

【讨论】:

  • 我想我明白了,但为了完整起见,答案不包括香肠,我猜有人饿了,所以香肠消失了。
  • 香肠基本上看起来就像香蕉(没有双关语的意思)。
  • 感谢您使用您提到的假设。否则,这个问题将是微不足道的,真的。很好的答案,很棒的解释!
  • 我已经运行了代码......我很伤心。不仅 Netbeans 需要实现 Banana 的抽象方法,而且它还说 Food 是抽象的,不能被实例化……有问题……
【解决方案2】:

接口用于定义一些常见的行为。如果你需要通用的state,你应该使用一个基类,如果它不被直接实例化,你也可以将它抽象化。

【讨论】:

  • 在这种情况下,您不能创建基类,因为它是具有单一继承的 Java - 而且 Sausage 和 Banana 都已经在扩展某些东西。除非我遗漏了你能看到的东西......
  • 您可以有一个名为 Product 的基类(在您的情况下似乎很合适),然后让 Fruit and Meat 先扩展它。
【解决方案3】:

接口只定义实现必须履行的契约,但通常不暴露任何实现细节本身。 (这里不考虑默认方法)

您的意思可能是abstract 类或将这些公共属性继承给子类的公共超类。这些类可以保持具体状态。

/**
 * The contract for each food.
 * You can get its title, size and its state. Also, the state can be changed.
 */
public interface Food {
    String getTitle();
    String getSize();
    String getState();
    void setState(String state);
}

现在,abstract 类可以定义常见行为:

public class AbstractFood implements Food {

    private String title;
    private String size;
    private String state;

    public AbstractFood(String title, String size, String state) {
        this.title = title;
        this.size = size;
        this.state = state;
    }

    @Override
    public String getTitle() {
        return null;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    @Override
    public String getSize() {
        return null;
    }

    public void setSize(String size) {
        this.size = size;
    }

    @Override
    public String getState() {
        return null;
    }

    @Override
    public void setState(String state) {
        this.state = state;
    }
}

这些类可以有任意子类,例如Fruit

public class Fruit extends AbstractFood {

    public Fruit(String title, String size, String state) {
        super(title, size, state);
    }
}

定义一个类Banana,即Fruit

public class Banana extends Fruit {

    public Banana(String size, String state) {
        super("Banana", size, state);
    }
}

回到Food 接口的用户,您现在可以对所有类型的食物应用通用行为,而无需了解任何实现细节。例如,您可以将所有香蕉的状态更改为 rotten:

for (Fruit fruit : fruits) {
    if (fruit.getTitle().equals("Banana")) {
        fruit.setState("Rotten");
    }
}

【讨论】:

    【解决方案4】:

    问题是:你想持有什么样的财产?

    您可以在接口中声明 public static final 字段,就像在任何类中一样:

    public interface MyInterface {
        String PROPERTY = "MyProperty";
    }
    

    如果这还不够,您可能不得不使用继承而不是接口,并将通用属性存储在抽象对象中。

    【讨论】:

    • 您能否举例说明如何为给定的课程完成这项工作?
    • @Governator 它不能。你想要实例字段。接口没有实例字段。只有静态最终字段。
    • @JBNizer,将它与 default 方法混淆了。更新答案,谢谢。
    猜你喜欢
    • 2020-11-12
    • 2010-12-17
    • 2020-12-19
    • 2023-03-28
    • 2019-01-03
    • 1970-01-01
    • 1970-01-01
    • 2015-05-29
    • 2018-02-14
    相关资源
    最近更新 更多