Java 在验证和返回接口的特定实现时对通用方法进行未经检查的强制转换

问题描述 投票:0回答:1

问题:

我正在开发一个系统,在该系统中管理由键(

Connector<RQ, RS>
)标识的连接器(
ChannelKey<RQ, RS>
)。每个 ChannelKey 映射到特定的 Connector 实现,我想使用该密钥检索连接器,同时确保类型安全。

相关代码如下:

public <RQ, RS> Optional<Class<? extends Connector<RQ, RS>>> get(final ChannelKey<RQ, RS> key) {
    final Optional<Connector<?, ?>> connector = findConnector(key.getChannelName());
    return connector.flatMap(prev -> validateToGet(prev, key));
}


private <RQ, RS> Optional<Class<? extends Connector<RQ, RS>>> validateToGet(Connector<?, ?> prev, ChannelKey<RQ, RS> key) {

    Class<? extends Connector<RQ, RS>> targetClass = moduleProvider
            .getConnectorFactory(key.getChannelName())
            .flatMap(factory -> Optional.ofNullable(factory.getConnectorClass()))
            .orElseThrow(() -> new IllegalStateException("Connector class not found for channel: " + key.getChannelName()));

    Class<?> receivedClass = prev.getClass();

    if (targetClass.isAssignableFrom(receivedClass)) {
        Class<? extends Connector<RQ, RS>> castedClass = (Class<? extends Connector<RQ, RS>>) receivedClass;
        return Optional.of(castedClass);
    }

    return Optional.empty();
}


public Optional<Connector<?, ?>> findConnector(String name) {
    return Optional.ofNullable(runningChannels.get(name));
}


public static final ChannelKey<Request, Response> BLUE = new BaseChannelKey<>("Blue", BlueRequest.class, BlueResponse.class);

问题: 当我尝试在 validateToGet 方法中将 receiveClass 强制转换为

(Class<? extends Connector<RQ, RS>>)
时,我收到未经检查的强制转换警告。我的目标功能是当调用 get
(ChannelKey.BLUE)
时,我希望结果是
Optional<BlueConnector<BlueRequest, BlueResponse>
,其中 BlueConnector 是
Connector<Request, Response>
的具体实现。

但是,此转换会生成警告,我想确保实现既是类型安全的又是无警告的。对于上下文:

  • Connector<RQ, RS>
    是一个具有多种实现的接口。
  • 我需要验证接收到的连接器是否与 ChannelKey 定义的预期类型匹配,然后将其转换为适当的类型。

替代尝试:

我也尝试了以下方法,但它在方法调用期间需要显式泛型类型,我想避免:

public <RQ, RS> Connector<RQ, RS> find(ChannelKey<RQ, RS> key) {
    return (Connector<RQ, RS>) runningChannels.get(key.getChannelName());
}

例如:

Connector<Request, Response> blueConnector = channelManager.find(ChannelKeys.BLUE);

这可行,但这不是我想要的行为。相反,我想仅使用密钥来推断预期的连接器类别。

问题:

  1. 如何在确保类型安全的同时解决 validateToGet 中未经检查的强制转换警告?
  2. 是否有更好的设计模式或方法来实现此功能,其中键确定连接器类型,并将结果作为正确的泛型类型返回?
java generics inheritance
1个回答
0
投票
  1. 如何在确保类型安全的同时解决 validateToGet 中未经检查的强制转换警告?

您无法使用当前使用的数据结构。 您的类型参数化不足以让 Java 在编译时验证类型安全。

您的连接器存储显然是

runningChannels
Map<String, Connector<?, ?>>
或类似的。 当您从那里检索连接器时,Java 没有基础来验证比
Connector<?, ?>
更窄的类型。 任何实现此类转换的强制转换都必然是未经检查的。

请注意,问题中提出的替代方案也不例外。 它的演员阵容仍未检查。

  1. 是否有更好的设计模式或方法来实现此功能,其中键确定连接器类型,并将结果作为正确的泛型类型返回?

有时,最好的选择是接受未经检查的演员阵容。 这可能是其中之一。

您描述的这种问题时常出现,其中类似映射的数据结构的整体键和值类型很广泛,但键的特定类型传达了有关其对应值的特定类型的信息。 问题在于,这些键/值类型对应关系只是这种数据结构的“使用”的特征。它们不是由其类型捕获的,因此无法对它们进行静态检查或验证。 如果您无法遵守未经检查的强制转换,那么您需要避免其自身类型无法提供有关其中项目类型所需的所有信息的数据结构。 一种可能性可能是简单地省去

<RQ, RS>

Connector
参数化。 从您的示例代码中不清楚这是否真的为您做任何事情。 或者以类似的方式,您可以简单地将检索到的
Connector
用作
Connector<?, ?>
。 如果这些都不适合你,那么你可能只需要硬着头皮接受未经检查的演员阵容。
    

© www.soinside.com 2019 - 2024. All rights reserved.