3

I'm currently working with the following types:

// A Field whose values are of type V.
interface Field<V> {
    public V getValue();
}

// A Field whose values are of type V and that has a LabelProvider for those values.
interface LabelField<V> extends Field<V> {
    public LabelProvider<V> getLabelProvider();
}

These come from a library and I cannot change them. This is probably not relevant, but a LabelProvider is basically a class that converts values of type V to Strings.

Now I want to create a class that provides an interface similar to this:

// A Wrapper class for Fields of values V
interface IWrapper<V, F extends Field<V>> {
    public F getField();
    public V getValue();
    public String getLabel();
}

The class will wrap a Field, and let its users retrieve the value from the field, but also provide other functionalities, including retrieving the label. Here's what I have:

public class Wrapper<V, F extends Field<V>> {

    private F field;
    private LabelProvider<V> labelProvider; // Converts from V to String

    // Since we have no guarantee that F has a LabelProvider, one is explicitely supplied.
    public Wrapper(F field, LabelProvider<V> labelProvider) {
        this.field = field;
        this.labelProvider = labelProvider;
    }

    private String getLabel() {
        return labelProvider.getLabel(field.getValue());
    }

    public F getField() {
        return field;
    }

    public V getValue() {
        return field.getValue();
    }
}
  1. No problem until this point, although I'm not sure whether I need these two generic types. Ideally I would have prefered to just have Wrapper> and be able to access both F and V. I think that this is not possible, and that the above is the correct way to do this ?

  2. Now here's the real issue.

I want to have a more specific constructor for the LabelField type, which would look like this:

public Wrapper(LabelField<V> labelField) {
    // Use the field's own label provider
    this(labelField, labelField.getLabelProvider());
}

In this case the labelprovider can be extracted from the field. But the compiler doesn't like this and I get the following error:

The constructor Wrapper<V,F>(LabelField<V>, LabelProvider<V>) is undefined

Even though this method, which uses the same types, compiles :

public static <X> void test(LabelField<X> lf) {
    LabelProvider<X> lp = lf.getLabelProvider();
    new Wrapper<X, LabelField<X>>(lf, lp);
}

Why doesn't the second constructor compile ?

Here's a SSCE : http://pastebin.com/UqLJhJA7

4

2 回答 2

1

F可以是任何扩展的类型Field<V>,并且该类型不一定是LabelField.

例如,如果您创建一个FooField实现Field<Object>和使用的类Wrapper<Object, FooField>,则LabelField构造函数将不匹配。

您可以通过这种方式简化包装器(这也回答了您的第一点):

public class Wrapper<V> {

    private Field<V> field;

    private LabelProvider<V> labelProvider; // Converts from V to String

    // Since we have no guarantee that F has a LabelProvider, one is explicitely
    // supplied.
    public Wrapper(Field<V> field, LabelProvider<V> labelProvider) {
        this.field = field;
        this.labelProvider = labelProvider;
    }

    public Wrapper(LabelField<V> labelField) {
        // Use the field's own label provider
        this(labelField, labelField.getLabelProvider());
    }

    private String getLabel() {
        return this.labelProvider.getLabel(this.field.getValue());
    }

    public Field<V> getField() {
        return this.field;
    }

    public V getValue() {
        return this.field.getValue();
    }
}

这使用“常规”多态性而不是field.

于 2012-12-18T13:44:59.920 回答
0

你混合了泛型和继承。

您应该仅使用以下参数进行参数化V

public class Wrapper<V>

并写在下面

Field<V>

在所有你会写的地方

F
于 2012-12-18T14:09:42.873 回答