- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
假设我有这个界面:
interface Foo<T extends Foo<T>> { // ... }
以及以下三个实现它的类:
class TrueFoo implements Foo<TrueFoo > { // ... }
class FalseFoo implements Foo<FalseFoo> { // ... }
class WrongFoo implements Foo<FalseFoo> { // ... }
// ^^^^^^^^ this here is wrong, only
// Foo<WrongFoo> should be allowed
以下方法的方法签名需要是什么来强制我可以返回类型为 TrueFoo 或 FalseFoo 的对象,但不能返回 WrongFoo...
public ???? getFoo(boolean which) {
return which ? new TrueFoo() : new FalseFoo();
}
以下不起作用:
这让我也可以返回一个新的 WrongFoo():
public Foo<?> getFoo(boolean which) {
return which ? new TrueFoo() : new FalseFoo();
}
这不允许我返回任何东西(解释如下):
public <FooType extends Foo<FooType>> FooType getFoo(boolean which) {
return which ? new TrueFoo() : new FalseFoo();
}
问题是 FooType 的类型是由我调用函数 getFoo()
的上下文决定的而不是我实际要返回的对象。
顺便说一句,调用方法时强制执行此签名很容易:
public <FooType extends Foo<FooType>> void test(FooType foo) {
// Do something with foo
}
如果您尝试使用 WrongFoo 的实例调用它,这将给您一个绑定(bind)不匹配错误。
让我觉得应该有一种方法可以对方法返回类型执行此操作。
或者有没有办法在 Foo 的接口(interface)定义中强制执行此签名?
编辑:
为了帮助形象化这个界面应该做什么,你可以想象它的这个版本:
interface CanCopy<Type extends CanCopy<Type>> {
public Type copy();
}
很明显像Foo implements CanCopy<Bar>
这样的类没有任何意义,只有Foo implements CanCopy<Foo>
或 Bar implements CanCopy<Bar>
.
编辑 2:
正如存在解决方案的概念验证一样,我可以为自己定义以下辅助类:
class FooResult {
private final Foo<?> foo;
public <FooType extends Foo<FooType>> FooResult(FooType foo) {
this.foo = foo;
}
@SuppressWarnings("unchecked")
public <FooType extends Foo<FooType>> FooType getFoo() {
return (FooType) foo;
}
}
然后我可以要求我的 getFoo 方法是这种类型:
public FooResult getFoo(boolean which) {
return which ? new FooResult(new TrueFoo()) : new FooResult(new WrongFoo());
}
那样的话,我将无法从我的 get 方法返回 WrongFoo。
但是,很明显,这有点过于复杂,无法像 Java 泛型通常倾向于编写代码那样优雅(根据我的经验)...那么,可以以某种方式缩短它吗?
编辑 3:
我找到了另一种方法来为实现接口(interface)的人提供检查,方法如下:
interface Foo<FooType extends Foo<FooType>> {
// Other interface definitions
/**
* Please implement with just this line in it:<br/><br/>
* <code>return this;</code>
* @return <code>this</code>
*/
public FooType returnThis();
}
现在,如果有人试图实现上面描述的 WrongFoo 类,他将不得不提供方法 FalseFoo returnThis()
如果他只是将其实现为 return this
按照 doctype 中的要求,该行将引发错误。
这不是保证,但它是一个很好的虚拟检查,可以防止因粗心复制类而导致的错误……并且在无论如何都需要具有此签名的消息的情况下,这将是一个很好的解决方案。
还有什么想法吗?
最佳答案
您遇到的泛型问题是症状,而不是问题所在:您要求您的界面依赖于您的具体实现。如果您希望 getFoo 接口(interface)方法返回不是 WrongFoo 的内容,则必须返回 TrueFoo 或 FalseFoo 但不是 WrongFoo 的内容。您的类层次结构没有这种特定的间接寻址。
要添加它,您需要执行以下操作:
class TrueFoo extends SpecialFoo {...}
class FalseFoo extends SpecialFoo {...}
class WrongFoo implements Foo<WrongFoo> {...}
class SpecialFoo implements Foo<SpecialFoo> {
SpecialFoo getFoo() {...}
}
请记住,Java 支持协变返回类型,因此通过返回 SpecialFoo,我们可以实现在 Foo 接口(interface)中创建的契约:Foo getFoo() {...}
如果您需要特定于 TrueFoo 和 FalseFoo 的行为,您可以进一步参数化 SpecialFoo,等等,turtles all the way down .
编辑:
阅读您的编辑后,我认为该语言不支持您要实现的目标。似乎您想根据具体实现来约束接口(interface),根据定义,这将使其不是接口(interface)。我认为以下示例非常接近您要查找的内容:
interface CanCopy<T extends CanCopy<T>> {
T copy();
}
interface FooCanCopy extends CanCopy<Foo> {
}
interface BarCanCopy extends CanCopy<Bar> {
}
class Foo implements FooCanCopy {
public Foo copy() {
return null;
}
}
class Bar implements BarCanCopy {
public Bar copy() {
return null;
}
}
我希望它现在清楚为什么该方法不起作用,即使在这里你仍然不能阻止某人做类似 class Baz implements FooCanCopy
的事情。我更想知道你为什么要这样做?如果是为了保护开发人员不犯错误,可能还有其他选择,即内省(introspection)单元测试或打包更改。
关于java - 强制 Java 方法返回类型以适应特定的通用签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13637882/
我得到了这个printHashKey函数,它运行良好。 fun printHashKey() { try { val info : PackageInfo = packageM
如何使用正确的签名 key 为我的 Android 应用包签名? 最佳答案 我尝试在此处和 this question 中使用多个答案, 但不知何故我收到了这个错误,因为我的 android/app/
我的 gradle 文件中有这个: android { signingConfigs { mySigningConfig { keyAlias 'the
请至少选择一个签名版本以在 Android Studio 2.3 中使用 现在在 Android Studio 中生成一个签名的 APK 时,它显示了两个选项(复选框),即 1. V1(Jar 签名)
我想表示一些标量值(例如整数或字符串)通过它的实际值或一些 NA 值,然后存储它们在集合中(例如列表)。目的是处理缺失值。 为此,我实现了一个签名 module type Scalar = sig
为什么这不完全有效? sum :: (Num a, Num b) => a -> b -> c sum a b = a + b 当然,错误消息与签名有关,但我仍然不明白原因。 Couldn't mat
谢谢帮助,我的问题是关于从下面的代码中收到的 ax 值? mov al,22h mov cl,0fdh imul cl 真机结果:ff9a 我的预期:00:9a(通过二进制相乘) 第一个数字是 22h
我有一个注释: import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.
我从对物体的思考中得出了一个术语。当我们扩展一个类时,扩展类将具有与父类相同的签名,因此术语 IS-A 来自...示例 class Foo{ } class Foo2 extends Foo{ } c
我需要在有符号整数和它们作为字节序列的内部表示之间进行转换。在 C 中,我使用的函数如下: unsigned char hibyte(unsigned short i) {return i>>8;}
我正在尝试使用给定的 RSA 参数对一些数据进行签名。 我给出了模数、指数、D、DP、DQ、P、Q 和 InverseQ。什么库或方法最容易使用来计算此签名。在 C# 中,一旦您提供参数,它们就会有一
这些签名之间有什么区别? T * f(T & identifier); T & f(T & identifier); T f(T & identifier); void f(T * identifie
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: Where and why do I have to put the “template” and “typ
我有一个签名,我需要在签名旁边添加图片。但我不确定 css 的确切程度和内容。目前它显示在文字下方,我应该把图片放在哪里?在相同的 tr 或 td 中?
查看 LinkedHashMap 的 JDK 源代码,我注意到这个类被声明为: public class LinkedHashMap extends HashMap im
背景:我继承了一个基于 linux 的嵌入式系统,其中包含一个 SMTP 代理和一些我不得不忍受的古怪限制。它位于 SMTP 客户端和服务器之间。当 SMTP 客户端连接时,代理会打开与服务器的连接,
这是 C++17 形式的规则 ([basic.lval]/8),但它在其他标准中看起来很相似(在 C++98 中是“lvalue”而不是“glvalue”): 8 If a program attem
我有一个注释: import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.
我即将开展一个项目,希望使用电子签名板使用 C# 捕获客户的签名、在设备上显示文本等。 现在,在我开始做进一步的研究之前,我想向你们征求一些意见/建议,我应该使用哪些设备.. 我现在的要求非常笼统:我
呢喃自己在心中开始扩张地盘,仿佛制式地广播了三次。 漾起的涟绮,用谈不上精腻的手段。 拒绝天亮,却又贪恋着贪恋多情的日光。 川流不息的画面是他们,而我的落幕停在右脚,它渴望着下台,而我只剩自言
我是一名优秀的程序员,十分优秀!