31

是否可以对接受 ClassA 或 InterfaceB 的方法进行一般参数化?

由于 | 无法编译 伪代码

public <T extends Number | CharSequence> void orDoer(T someData){ // ... }

即,而不是编写多个方法签名,我希望这个方法接受 Number 或 CharSequence 作为参数

应该使用 Number OR CharSequence 参数传递

orDoer(new Integer(6));
int somePrimitive = 4;
orDoer(somePrimitive);
orDoer("a string of chars");
4

3 回答 3

20

如果你真的想这样做,你需要将你接受的类包装在你自己的自定义类中。在您的示例中,可能类似于:

public class OrDoerElement {
    private final Number numberValue;
    private final CharSequence charSequenceValue;

    private OrDoerElement(Number number, CharSequence charSequence) {
        this.numberValue = number;
        this.charSequenceValue = charSequence;
    }

    public static OrDoerElement fromCharSequence(CharSequence value) {
        return new OrDoerElement(null, value);
    }

    public static OrDoerElement fromNumber(Number value) {
        return new OrDoerElement(value, null);
    }
}

你的orDoer方法变成:

public void orDoer(OrDoerElement someData) { .... }

然后,您可以构建其中一个并在您的方法中使用:

orDoer(OrDoerElement.fromCharSequence("a string of chars"));
orDoer(OrDoerElement.fromNumber(new Integer(6)));

但老实说,这听起来有点太复杂,而且工作量太大,只是为了能够调用具有不同参数类型的方法。你确定你不能用两种方法达到同样的效果,第三种方法是通用逻辑吗?

于 2011-11-30T17:49:26.863 回答
1

使用匿名抽象类是否适合您?当我需要类型安全参数或返回类型时,我使用下面代码的一些变体。话虽如此,我同意这里的其他评论,并且很好奇当您为一组没有那么多共同点的对象实施类型安全时,您真正获得了什么好处。

public abstract class Doer<T> {

  public void do(T obj) {
    // do some stuff. 
  }

}

// calling method

new Doer<Number>(){}.do(new Integer(5));
于 2011-11-30T19:20:16.997 回答
0

对于原始问题:

public void orDoer(Object someData){
    assert someData instanceof Number || someData instanceof CharSequence;

    // ...
}

在您更具体的情况下,该assert语句应该只使用自省来澄清对象是否具有您想要的细节,即检查来自 String 的构造函数,探测以从toString()传入对象的结果创建对象的新实例,并进行比较两者都是为了平等:

public void orDoer(Object someData) {
    assert isUniconstructable(someData);
}

public static boolean isUniconstructable(Object object) {
    try {
        return object.equals(object.getClass().getConstructor(String.class)
            .newInstance(object.toString()));
    } catch (InstantiationException | IllegalAccessException | InvocationTargetException
            | NoSuchMethodException| RuntimeException e) {
        return false;
    }
}

(由于可能会抛出异常,我们需要将 assert 测试包装到它自己的函数中。)

请注意,由于 Android 的 ProGuard 代码压缩可能会破坏自省,它会重写类名,而YourClass不仅仅是一个类,即Q存储在数据库中,当您想要使用具有更多功能的更高版本的应用程序来恢复它时类,类Q是不同的东西。有关这方面的更多信息,请参阅 ProGuard 网站;我只是想通知您在 Android 上使用自省时应该注意这一点。

于 2018-08-09T07:09:56.080 回答