gpt4 book ai didi

Java 8 问题尝试在使用继承和泛型时添加 Function FunctionalInterface 调用

转载 作者:行者123 更新时间:2023-11-30 10:42:50 25 4
gpt4 key购买 nike

我一直在学习 Java 8 的特性,到目前为止已经成功实现了它们,但我最新的代码引发了两个问题。

第一个问题可以通过强制转换来解决,但是这里不应该发生这种情况,因为类型继承应该是健全的;这是在接受单参数构造函数参数时,其中构造函数是 Function FunctionalInterface 方法引用。

相关问题是,如果在调用方法引用时将此类型用作构造函数参数的类型,则在使用方法引用填充映射时,Java 无法将泛型参数的具体声明子类型解析为有效。

下面的代码使用分离的接口(interface)继承树、接口(interface)规范和接口(interface)实现,用于两种类型的对象 Node 和 Edge。

边有通用参数来定义创建方法引用时指定的开始节点和结束节点。

节点和边都可以有自定义子类型,它们有一个由实现子类型实现的派生接口(interface)(子类型)。

节点包含作为集合的关系,可以是具体节点引用或具体边引用。 (startNode 应该匹配持有边集的父对象,但作为边的成员是必需的,这是我无法控制的)

为避免大量重复代码,通过操作界面进行访问

Operations 接口(interface)也有一个单独的接口(interface)和具体实现,并且有两种类型(Node 和 Edge)来支持 Edge 所需的泛型,一种是为每个具有关系的 ImplExtendedNode 中的每个关系集创建的。

这个修改是将创建者方法引用的存储移回知道使用哪些具体类型并有权访问Sets的类,而不是将自定义方法引用传递给每个Operations构造函数,然后传递它返回调用。

该问题与 Edge(构造函数)方法引用非常相关,无法正确解析类型是否有效并满足泛型类型约束的要求。

该系统是批处理过程的一部分。我已经去掉了所有不重要的东西,我真的很感激帮助我了解更多关于泛型和 Java 8 的新特性的信息,以帮助任何理解我出错的人。

//Node Interfaces

public interface Node {
...
}

public interface DefaultNode extends Node {
...
public <S extends Object & DefaultNode> Optional<S> createRelationship(NodeOperations nodeOps);
public <R extends Object & DefaultEdge, T extends Object & DefaultNode> Optional<R> createRelationship(EdgeOperations edgeOps);
...
}

//Edge Interfaces

public interface Edge<S extends Object & Node, T extends Object & Node> {
...
}

public interface DefaultEdge<S extends Object & Node, T extends Object & Node> extends Edge<S, T> {
...
}

//Implementation Classes

//(base objects)
public abstract class ImplNode implements Node {
...
}

public abstract class ImplEdge<S extends Object & Node, T extends Object & Node> implements Edge<S, T> {
...
//constructor(s)
public ImplEdge(S s) {
...
}
...
}

//(provide basic functions)
public abstract class ImplDefaultNode extends ImplNode implements DefaultNode {

//holds method reference to custom node/edge constructors in child implementation class definitions (multiple per class)
protected Map<NodeOperations, Supplier> nodeSuppliers;
protected Map<EdgeOperations, Function> edgeSuppliers;

//this works fine
@Override
public <S extends Object & DefaultNode> Optional<S> createRelationship(NodeOperations nodeOps) {
...
Supplier<S> f = this.nodeSuppliers.get(nodeOps);
S relationship = f.get();
...
}

//issue one, cannot automatically cast type of "this" to expected type of T in f.apply(this) - I know this should be possible in most cases and usually points to an issue with the code
@Override
public <R extends Object & DefaultEdge, T extends Object & DefaultNode> Optional<R> createRelationship(EdgeOperations edgeOps) {
...
Function<T, R> f = this.edgeSuppliers.get(edgeOps);
R relationship = f.apply(this);
...
}
}

public abstract class ImplDefaultEdge<S extends Object & Node, T extends Object & Node> extends ImplEdge<S, T> implements DefaultEdge<S, T> {
private S startNode;
private T endNode;
...
}

//(provides custom extensions which rely on ImplDefaultNode)

//custom implementation of interface derived and defined from DefaultNode
public class ImplExtendedNode extends ImplDefaultNode implements ExtendedNode {
...
private Set<DifferentImplExtendedNode1> nodeRels1;
...
private Set<ImplExtendedEdge<ImplExtendedNode, DifferentImplExtendedNode2>> edgeRels1;

//this works when called via create function in superclass through generic map lookup
@Override
public NodeOperations morphNodeRels1() {
...
this.nodeSuppliers.put(i, DifferentImplExtendedNode1::new);
...
}

//this throws compiler error -
//Cannot convert java.lang.Object to ImplExtendedNode
//It only works if the first generic type is ImplNode, or ImplDefaultNode I think)
@Override
public EdgeOperations morphEdgeRels1() {
...
this.edgeSuppliers.put(i, ImplExtendedEdge<ImplExtendedNode, DifferentImplExtendedNode2>::new);
...
}
}

最佳答案

您的问题与 Java 8 无关,它们源于对某些泛型声明含义的根本误解。

如果您定义带有类型参数的类或方法,则意味着使用这些类或方法的代码可以使用它们和替换这些参数的任意类型,并且您的通用代码将独立于使用代码实际上已经选择了类型参数。

你定义一个接口(interface),如:

public interface DefaultNode extends Node {
...
public <S extends Object & DefaultNode> Optional<S>
createRelationship(NodeOperations nodeOps);
public <R extends Object & DefaultEdge, T extends Object & DefaultNode> Optional<R>
createRelationship(EdgeOperations edgeOps);
...
}

第一个方法 promise 返回 Optional<WhatEverTheCallerChooses>只要调用者选择的类型是 DefaultNode 的子类型.当然,那是行不通的。为了证明这一点,以下代码编译无误:

public static void demonstrating(DefaultNode n, NodeOperations o) {
abstract class FooBar implements DefaultNode {}
Optional<FooBar> opt = n.createRelationship(o);
if(opt.isPresent()) {
FooBar fb = opt.get();
}
}

createRelationship 的通用签名方法 promise 以某种方式返回 FooBar 的具体子类甚至不知道本地的类(class)。当然,在这种情况下,它总是可以返回一个空的可选值,但是唯一有效的实现是不返回任何内容的方法是没有意义的。

第二种方法甚至添加了另一个类型参数,T ,它没有出现在方法签名的其他地方,这使得它完全无用。您尝试在方法实现中使用它表明您不了解类型参数是调用者与方法实现之间契约的一部分:

@Override
public <R extends Object & DefaultEdge, T extends Object & DefaultNode> Optional<R>
createRelationship(EdgeOperations edgeOps) {
...
Function<T, R> f = this.edgeSuppliers.get(edgeOps);
R relationship = f.apply(this);
...
}

RT是方法的类型参数,调用者 决定用什么实际类型来代替它们。 edgeSuppliers.get返回原始类型 Function所以编译器接受对 Function<T, R> 的赋值尽管这是完全错误的。您不知道调用者为 T 选择了哪些实际类型和 R所以你无法知道函数是否满足契约,见上文,T可能是 FooBar .

然后调用 f.apply(this) ,但是你怎么能期望它被编译器接受呢?如上图,T可能是本地类型 FooBar和你的 this引用未指向 FooBar 的实例.当然,您的 map 不可能包含实际需要 FooBar 的函数。一个完全不同的上下文的实例,但这仅表明先前未经检查的操作已经是错误的。 T 可能是 FooBar所以这个函数不能Function<T,R> .

但如前所述,T根本不在方法声明中使用,因此在方法中使用它也没有任何意义。如果您断言所有函数都可以使用 this在这个地方,它们应该可以分配给 Function<? super ImplDefaultNode, …>并且你应该在你的类中使用适当的声明,包括 Map 的声明.但是,无法 promise 在调用时返回调用者希望的任何内容。你最好在这个地方没有任何类型参数并声明保证的最小值,例如一个Optional<Node> .

关于Java 8 问题尝试在使用继承和泛型时添加 Function FunctionalInterface 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37966294/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com