Java中与C#泛型修饰符“out”相似的替代方式

3

我试图将以下C#代码和行为转换为Java,但我很难找到正确的语法或编程模式。

在C#中,我可以使用out,例如interface IProxy<out Target>,这使我可以将IProxy<DerivedElement1>隐式转换为IProxy<BaseElement>,但是对于Java,我不知道是否有类似的泛型修改符。

class BaseElement {
    public static readonly Property<BaseElement> P1 = new Property<BaseElement>();
}
class DerivedElement1 : BaseElement {
    public static readonly Property<DerivedElement1> P2 = new Property<DerivedElement1>();
}
class DerivedElement2 : BaseElement {
    public static readonly Property<DerivedElement2> P2 = new Property<DerivedElement2>();
}

class Property<Owner> {
}

interface IProxy<out Target> {
}
class Proxy<Target> : IProxy<Target> {
}

class Program {
    static void doSomething<Target>(IProxy<Target> proxy, Property<Target> property) {
        // ...
    }

    static void Main(string[] args) {
        Proxy<DerivedElement1> proxy1 = new Proxy<DerivedElement1>();

        doSomething(proxy1, DerivedElement1.P1);
        doSomething(proxy1, DerivedElement1.P2);

        // expected error
        doSomething(proxy1, DerivedElement2.P2);
    }
}

在编译时出现预期错误而不是运行时出现错误非常重要。

您是否知道任何适用的语法或模式,可以让我在不进行任何额外转换的情况下实现相同的行为?

希望您能指导我正确的方向,非常感谢您的帮助!


1
我猜这个链接可能对你有帮助:https://docs.oracle.com/javase/tutorial/java/generics/wildcards.html(这不是一个答案,因为它只是一个链接 - 尽管我真的认为这正是你在寻找的。) - Fildor
谢谢提供链接,但如果我使用通配符,则在使用不兼容的参数时(例如doSomething(proxy1, DerivedElement2.P2)),我将不会得到编译时错误。 - user667967
但是,您可以使用通用方法,例如public static <Target> void doSomething(IProxy<Target> proxy, Property<Target> property) {并像这样调用它Program.<DerivedElement1>doSomething(proxy1, DerivedElement2.P2)并获得所需的编译时错误。 - guido
这是正确的,但对于 doSomething(proxy1, DerivedElement1.P1); 将不起作用。 - user667967
是的,在这种情况下,您将不得不缩小范围到<BaseElement>doSomething() - guido
显示剩余2条评论
2个回答

0
我发现我可以使用Proxy<? extends Target>来声明我的代理参数。
这是完整的解决方案:
class BaseElement {
    public static final Property<BaseElement> P1 = new Property<BaseElement>();
}
class DerivedElement1 extends BaseElement {
    public static final Property<DerivedElement1> P2 = new Property<DerivedElement1>();
}
class DerivedElement2 extends BaseElement {
    public static final Property<DerivedElement2> P2 = new Property<DerivedElement2>();
}

class Property<Owner> {
}

class Proxy<Target> {
}

class App {
    static <Target>
    void doSomething(Proxy<? extends Target> proxy, Property<Target> property) {
        // ...
    }

    static void main(String[] args) {
        Proxy<DerivedElement1> proxy1 = new Proxy<DerivedElement1>();

        doSomething(proxy1, DerivedElement1.P1);
        doSomething(proxy1, DerivedElement1.P2);

        // expected error
        doSomething(proxy1, DerivedElement2.P2);
    }
}

-3

如果我理解正确,你应该看一下Java中的泛型类型

Java示例代码

public class IProxy<T>{
      ....
}

public class Property<T>{
    ....
}
public class Program {
    public static void doSomething(<IProxy<T> iProxy, Property<T> property){
       ......
    }
}

类型参数命名约定(不确定C#中的Target是指什么)

E - Element (used extensively by the Java Collections Framework)
K - Key
N - Number
T - Type
V - Value
S,U,V etc. - 2nd, 3rd, 4th types

3
感谢您的建议,但我不确定您的代码如何确保 doSomething(proxy, property) 只能使用正确的参数对调用。 - user667967
请查看我发送的链接。Java中的泛型适用于编译时测试而不是运行时测试。正如答案中所提到的,您可以通过E、K、N等来定义类型。 - Jack
对于 IProxy<Target> 代理和 Property<Target> 属性,您可以传递带有目标类型的 IProxy 接口等。 - Jack
@user667967的答案已更新,希望能有所帮助。正如所提到的,这只是一个示例代码。 - Jack

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接