1

我正在尝试创建一个通用转换器接口,它将使用相同的方法名称将T对象转换为对象,即:Uconvert

public interface GenericConverter<T, U> {
  T convert(U fromObject);
  U convert(T fromObject);
}

当然,泛型擦除会在编译期间将这两种方法转换为以下内容:

convert(object fromObject);

所以这两种方法都有相同的擦除,这会导致编译时出错。

在我的示例中,我将始终为 和 使用不同的对象类型是合乎逻辑TU。有没有办法保持相同的方法名称(转换),能够封装不同类型的事实并T确保在每种情况下都会调用正确的方法U

4

3 回答 3

1

除非这两种类型TU基于两个独立的类型层次结构(即每个类型总是有一些不同的超类),否则没有办法让这两种方法具有相同的名称。在这种情况下,它甚至在语义上都没有意义——如果你不能在任何合理的事情上区分这两种类型,这两种方法之间的语义差异应该是什么?

除了建议的方法重命名之外,还可以考虑在接口中只使用一个这样的方法,而不是在需要转换两种方式的地方使用GenericConverter<T, U>and 。GenericConverter<U, T>

于 2017-01-10T13:30:59.477 回答
1

由于类型擦除,这不是直接可能的。其他答案中已经列出了几个选项。其中之一隐含地旨在分离转换。因此,您可以拥有两个不同的转换器,而不是拥有一个转换器:

public interface GenericConverter<T, U> {
  U convert(T fromObject);
}

GenericConverter<Integer, String> forward = Converters.integerString();
GenericConverter<String, Integer> backward = Converters.stringInteger();

但请注意,GenericConverter这种情况下的接口在结构上与Function接口相同——因此可能没有理由创建新接口。

相反,如果您想将此“正向和反向转换器”作为某种命名实体(两个转换函数不可分割地链接在一起),您可以为此定义一个接口:

public interface GenericConverter<T, U> {
  Function<T, U> forward();
  Function<U, T> backward();
}

这可以按如下方式使用:

GenericConverter<Integer, String> converter = Converters.integerString();

String string = converter.forward().apply(someInteger);
Integer integer = converter.backward().apply(someString);

这是否是这里的“最佳”解决方案取决于预期的使用模式。一个优点可能是,使用像这样的通用(!)实用程序函数......

private static GenericConverter<T, U> create(
    Function<T, U> forward, Function<U, T> backward) {
    return new GenericConverter() {
        @Override
        public Function<T, U> forward() {
            return forward;
        }
        @Override
        public Function<U, T> backward() {
            return backward;
        }
    }
}

创建一个新的转换器很容易:

public static GenericConverter<Integer, String> integerString() {
    return create(
        integer -> String.valueOf(integer), 
        string -> Integer.parseInt(string)
    );
}
于 2017-01-10T18:23:21.393 回答
0

问题

当你说,

我将始终使用不同的对象类型是合乎逻辑TU

编译器不知道。类型可以强制相同,但不能不同(没有约束)。


方法一

class ConversionSource {}

class ConversionTarget {}

interface GenericConverter<T extends ConversionSource, U extends ConversionTarget> {
    T convert(U obj);
    U convert(T obj);
}

现在,擦除是不同的。您可以使用所需的来源获得所需的行为,但由于限制,使用受到严格限制。


方法二

interface InvertibleConverter<T, U> {
    U convert(T obj);
    InvertibleConverter<U, T> inverse();
}

class Tokenizer implements InvertibleConverter<String, Stream<String>> {

    @Override
    Stream<String> convert(String obj) {
        return Arrays.stream(obj.split(" "));
    }

    @Override
    InvertibleConverter<Stream<String>, String> inverse() {
        return new InvertibleConverter<Stream<String>, String>() {
            @Override
            public String convert(Stream<String> obj) {
                return obj.collect(Collectors.joining(" "));
            }

            @Override
            public InvertibleConverter<String, Stream<String>> inverse() {
                return Tokenizer.this;
            }
        };
    }
}

用法可以如下

InvertibleConverter<String, Stream<String>> splitter = new Tokenizer();
String sentence = "This is a sentence";
Stream<String> words = splitter.convert(sentence);
String sameSentence = splitter.inverse().convert(words);

这种方法即使在TU相同时也有效。

希望这可以帮助。
祝你好运

于 2017-01-10T18:04:19.137 回答