1

我同时有一个非常简单但令人困惑的问题。

在 Transformer 中,有没有办法指定被转换的类的类型是相同的类型?

为了清楚起见,我将分享代码:

Transformer<Set<?>, List<?>> transformer = new SetToListTransformer();

有没有办法让我指定 Set 和 List 是同一类型?

同样在编写变压器时我这样做了,我认为它没有任何作用:

private static class SetToListTransformer implements Transformer<Set<?>, List<?>> {

  @Override
  public List<?> transform(final Set<?> input) {
     return this.doTransform(input);
  }

  public <T> List<T> doTransform(final Set<T> input) {
      ...
  }
}

问题是,我不能输入 SetToListTransformer,因为我并不真正关心里面有什么类型,我只关心它们是相同的类型。

任何帮助,将不胜感激!

PS:我并没有真正将 Set 转换为 List,我使用的是其他类型,我只是用它们来澄清代码:)

4

4 回答 4

1

尝试将两个通配符绑定到相同的类型参数,如下所示:

class SetToListTransformer<E> implements Transformer<Set<E>, List<E>> { 
    @Override
    public List<E> transform(Set<E> from) {
        ...
    }
}
于 2013-02-18T21:28:27.567 回答
1

使您的类通用:

private static class SetToListTransformer <T> implements Transformer<Set<T>, List<T>> {

  @Override
  public List<T> transform(Set<T> input) {
     return this.doTransform(input);
  }

  public List<T> doTransform(Set<T> input) {
      ...
  }
}

但是请注意,此实现对类型非常严格。您将无法使用 SetToListTransformer<Number> 将 Set<Integer> 转换为 List<Number>,尽管 Integer 是一个数字。

于 2013-02-18T21:30:43.543 回答
0

transform由于无法在通用通配符之间施加任何关系,因此无法对您的实现实施所需的约束。?您声明中的两者SetToListTransformer都注定各自意味着某种未知类型,无法将它们相互绑定。

正如其他人指出的那样,最简单的解决方案是SetToListTransformer通用。例如:

class SetToListTransformer<T> implements Transformer<Set<? extends T>, List<T>> {

    @Override
    public List<T> transform(final Set<? extends T> input) {
        final List<T> output = new ArrayList<T>(input.size());
        output.addAll(input);
        return output;
    }
}

当然,这需要您使用特定类型参数来实例化转换器。只要SetToListTransformer便宜,这应该没问题。但是,您表示您只想使用一个实例。以下是如何做到这一点:

class MyTransformers {

    // There is no reason to expose SetToListTransformer now.
    // Keep it here as an anonymous class.
    private static final Transformer<Set<?>, List<?>> FROM_SET_TO_LIST =
            new Transformer<Set<?>, List<?>>() {
                @Override
                public List<?> transform(final Set<?> input) {
                    return doTransform(input);
                }
                private <T> List<T> doTransform(final Set<T> input) {
                    final List<T> output = new ArrayList<T>(input.size());
                    output.addAll(input);
                    return output;
                }
            };

    private MyTransformers() { }

    public static <T> Transformer<Set<? extends T>, List<T>> fromSetToList() {
        @SuppressWarnings("unchecked")//this is okay for any T because the impl is stateless 
        final Transformer<Set<? extends T>, List<T>> withNarrowedTypes =
                (Transformer<Set<? extends T>, List<T>>)(Transformer<?, ?>)FROM_SET_TO_LIST;
        return withNarrowedTypes;
    }
}

这是一个使用示例:

Set<Integer> intSet = new HashSet<Integer>();
intSet.add(42);
intSet.add(1337);
List<Number> numList = MyTransformers.<Number>fromSetToList().transform(intSet);
于 2013-02-18T21:45:39.303 回答
0

你不能用Transformer接口表达那个约束。您可以创建一个施加额外约束的子类型,并使用使用过的子类型Transformer

interface StricterTransformer extends Transformer<Set<?>, List<?>>

    public <T> List<T> transform2(Set<T> input) ;

    /** javadoc additional contract: must behave as transform2(input) */
    public List<?> transform(Set<?> input);
    // in java8 we can give a "default" impl for this interface method
    // that simply calls transform2(), so subclasses don't have to impl 
    // the transform() method, which is just boiler plate code.
于 2013-02-18T21:48:02.897 回答