自己的通用接口,在没有原始类型警告的情况下使用

Interface generic of self, use without rawtype warning

我将 class 重构为许多实现接口的东西。它工作正常,但我希望能够使用代码而不必在任何地方推断或抑制警告。

//Item is a raw type. References to generic type Item<T> should be parameterized.
public interface Item<T extends Item>
{
    // Item is a raw type. References to generic type Item<T> should be parameterized.
    public static final Item DEFAULT_ITEM = new FooItem(Color.RED);

    // Because using "something = new Item(Default_Item)" won't work.
    public T Copy();

    public void Foo();
    public void Bar();
}

public class RepairMan
{
    // Item is a raw type. References to generic type Item<T> should be parameterized.
    Item itemNeedingRepairs;

    // Item is a raw type. References to generic type Item<T> should be parameterized.
    public RepairMan(final Item item)
    {
        itemNeedingRepairs = item.Copy();
    }       
}

我希望能够在大部分代码中将 Item 用作常规 non-interface 版本。忽略警告的地方太多了,而且到处都是Item,看起来也不吸引人。

一些注意事项:

  1. 项目在我的申请中成为 class 没有意义。
  2. 在这种情况下,我可以使用 non-generic 接口,尽管它更适合它,但为了学习,我想探索这个问题。

如果有更好的方式来描述这个问题,请随时调整标题,我不确定。

每个警告都有不同的响应,因此也需要不同的补救措施。

1:界面:

public static interface Item<T extends Item> { public T Copy(); }

这是您的项目 class 的关键功能。您希望 Item 的每个参数化实例将其自身复制到具有 same 参数化的实例中。第一个警告表明您未能执行此操作。

您应该明确要求 T 是同一类型,如下所示:

public static interface Item<T extends Item<T>> {
     public T Copy();
}

2:默认项目:

public static final Item DEFAULT_ITEM = new FooItem(Color.RED);

界面中默认项目的问题在于,因为它是原始的,所以它不遵循该约束。它的 copy() 方法可能 return 一个带有 不同 参数的项目。如果你想在该项目上强制执行此操作,则需要将其声明为 FooItem,如下所示:

public static final FooItem DEFAULT_ITEM = new FooItem(Color.RED);

如果您不想公开可能提供 public 的完整签名或您认为默认项目用户不应该看到的保护方法,您可以将其隐藏在中间抽象类型下。


3:修理工

你需要问自己一些设计问题:

是否所有 RepairMen 都能修复任何项?在这种情况下,您需要通过在所有维修人员字段和方法上使用通配符 <?> 来表达这一点。

public static class RepairMan {
    Item<?> itemNeedingRepairs; // Any Item is acceptable
    public RepairMan(final Item<?> item) { // Any Item is acceptable
        itemNeedingRepairs = item.Copy();
    }       
}

是否有一些 RepairMen 是专门的,比如水管工和电工,他们应该限制他们可以修理的物品类型?在这种情况下,你必须让 RepairMen 设置一些界限Item 参数。

public static class RepairMan<T extends Item<T> {
    TitemNeedingRepairs;
    public RepairMan(final Titem) {
        itemNeedingRepairs = item.Copy();
    }       
}

使用边界的示例实现:

public static interface ElectricItem extends Item<ElectricItem>{}

public static class LightBulb implements ElectricItem{
    @Override
    public LightBulb Copy() {
        return new LightBulb();
    }
}

public static class Electrician extends RepairMan<ElectricItem>{
    ElectricItem itemNeedingRepairs; // Only electric Items acceptable
    public Electrician(ElectricItem item) {
        super(item);
    }
}

public static void main(String[] argc){
    LightBulb bulb = new LightBulb();
    new Electrician(bulb);
}

最后的话

在构造函数中工作是 considered bad practive,并且 RepairMan 不需要您提前知道它将处理哪个 Item 实例。相反,它应该提供一种修复方法:

public void repair(Item<?> item){...}