Java 接口方法的泛型返回类型

Java 接口方法的泛型返回类型,java,generics,interface,java-8,return,Java,Generics,Interface,Java 8,Return,我有一个与方法parse(String value)的接口,它可能有不同的实现,返回或任何东西的映射。如何使其足够通用,以便扩展到不同的返回类型 目前,我有: public interface Parser <K,V> { Map<K,V> parse(String document); } 公共接口解析器{ 地图解析(字符串文档); } 但这将使其仅适用于地图。有人能告诉我,有没有一种方法可以让它对不同的退货类型通用 如果希望它返回任何类型,只需使用一个

我有一个与方法
parse(String value)
的接口,它可能有不同的实现,返回
或任何东西的映射。如何使其足够通用,以便扩展到不同的返回类型

目前,我有:

public interface Parser <K,V> { 

    Map<K,V> parse(String document);
}
公共接口解析器{
地图解析(字符串文档);
}

但这将使其仅适用于地图。有人能告诉我,有没有一种方法可以让它对不同的退货类型通用

如果希望它返回任何类型,只需使用一个泛型类型定义它,如T:

public interface Parser <T> { 

    <T> parse(String document);
}
公共接口解析器{
解析(字符串文档);
}
这是可能的,但我担心你以后会遇到新的挑战。Java现在可以从泛型类型实例化类,所以您还必须将该类类型作为参数传递:

public interface Parser <T> { 

    <T> parse(Class<T> clazz, String document);
}
公共接口解析器{
解析(类clazz,字符串文档);
}

您可以这样做,但我认为您应该进一步设计架构。如果文档的返回类型可以是任何类型,那么在大多数情况下,这是一种弱设计的味道,并将导致一个意大利面代码

如果您想使您的接口在返回类型中通用,我建议对JoeC的注释进行扩展

从Java8开始,就有了一个接口,为基本转换提供了接口。特别是,该界面可用于满足您的目的。我建议采取如下实施方式:

// file: Parser.java
import java.util.function.Function;

public abstract class Parser<R> implements Function<String, R> {

    @Override
    public final R apply(String document) {
        return (this.parse(document));
    }

    abstract public R parse(String document);
}
String document             = ...;
Parser<Map<K, V>> mapParser = ...; // instantiate a fitting Parser
Map<K, V> result            = mapParser.parse(document);
使用此(空)界面,您可以将上述代码重新编写为:

String document           = ...;
MapParser<K, V> mapParser = ...; // instantiate a fitting MapParser
Map<K, V> result          = mapParser.parse(document);

界面为用户提供了更大的灵活性,因为一个
可以实现多个
界面
s,但只能
扩展另一个
。然而,在缺点方面,接口
IParser
IMapParser
的开发人员无法强制执行该方法
apply(…)
不能被覆盖。因此,理论上,
Parser
的实现者可以以不同的方式实现
apply(…)
parse(…)
,这可能导致意外行为。当使用抽象类
Parser
MapParser
时,开发人员会强制执行
apply(…)
调用
parse(…)
,从而实现一致的行为。

注释已经给了您一个很好的提示,但我想您需要一个示例

// imports elided

interface Parser<T> {

    T parse(String document);

    Parser<Map<String, Integer>> static mapParser() {
        // replace with actual parsing code
        return document -> {
            Map<String, Integer> result = new Hashmap<>();
            result.put(document, document.length());
            return result;
         }

    Parser<List<String>> static listParser() {
        return document -> Collections.singletonList(document);
    }
}

Parser
也许?像
public interface Parser{E parse(String document);}
?@4castle我对interface不熟悉,你能给我解释一下它是如何工作的吗(你在这里提到的)“…有没有办法让它对不同的返回类型通用?”你是什么意思?是否有其他方法也需要返回与
parse
方法返回的类型无关的泛型值?还是别的什么。。。通读一遍。这将极大地帮助您理解接口/类的泛型“
Map…
”->这不会编译。有两个通用参数。感谢您的注意。我更正了示例。我删除了我的答案,因为它与您的答案相同-您更快:)。考虑用接口解析器代替抽象解析器。Java 8引入了
default
方法,这些方法与抽象类中的非抽象方法基本相同。@matoni是的,Java 8引入了。但对于abstrac类,可以强制执行
apply(…)
不会在其他地方被覆盖,并调用
parse(…)
,从而保证一致性行为,例如,如果
Parser
的实例用作流调用的一部分。当然,但在Java中,一切都是虚拟的,因此可以重写。Final关键字很少使用。拥有一个接口更加灵活,因为您可以实现多个接口,而使用抽象类,您只能扩展一个父类。“…在Java中,一切都是虚拟的…”您的意思是抽象的?只有当你将它声明为抽象时,它才是抽象的。这与动态绑定不同。“最后一个关键词很少使用。”我倾向于不同意。看看API。“拥有一个接口更灵活…”当然,但如果我能防止一些错误,我愿意牺牲灵活性来获得正确性。所谓“虚拟”我指的是可重写的。在C++中,只有标记为虚拟的方法可以被重写(同样适用于C语言),相反的java方法默认为虚的。如果您不是在设计库API,我会选择灵活性。
// file: IParser.java:
import java.util.function.Function;

public interface IParser<R> extends Function<String,R> {

    @Override
    default public R apply(String document) {
        return (this.parse(document));
    }

    public R parse(String document);
}

// file: IMapParser.java:
import java.util.Map;

public interface IMapParser<K, V> extends IParser<Map<K, V>> {}

// file: Parser.java:
public abstract class Parser<R> implements IParser<R> {

    @Override
    public final R apply(String document) {
        return (this.parse(document));
    }
}

// file: MapParser.java:
import java.util.Map;

public abstract class MapParser<K, V> extends Parser<Map<K, V>>
        implements IMapParser<K, V> {}
// imports elided

interface Parser<T> {

    T parse(String document);

    Parser<Map<String, Integer>> static mapParser() {
        // replace with actual parsing code
        return document -> {
            Map<String, Integer> result = new Hashmap<>();
            result.put(document, document.length());
            return result;
         }

    Parser<List<String>> static listParser() {
        return document -> Collections.singletonList(document);
    }
}
String document = "abc";
Map<String, Integer> lookup = Parser.mapParser().parse(document);
List<String> list = Parser.listParser().parse(document);