- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我有一个解析数据流的类。每个数据 block 称为一个 Box
。 Box
有很多种。我想为每种类型的框设置不同的 Parser
。所以基本上我需要一个 Registry
或类似的东西,让我为每个 Box
提取正确的解析器。这是我的问题的简化版本:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class GenericsTest {
class Box {
private String data;
public String getData() {
return data;
}
}
class BoxA extends Box {
private String adata;
BoxA( String adata ) {
this.adata = adata;
}
public String getAData() {
return adata;
}
}
class BoxB extends Box {
private String bdata;
BoxB( String bdata ) {
this.bdata = bdata;
}
public String getBData() {
return bdata;
}
}
interface Parser<T> {
public void parse( T box );
}
class ParserA implements Parser<BoxA> {
@Override
public void parse( BoxA box ) {
System.out.print( "BoxA: " + box.getAData() );
}
}
class ParserB implements Parser<BoxB> {
@Override
public void parse( BoxB box ) {
System.out.print( "BoxB: " + box.getBData() );
}
}
class Registry {
Map<Class<?>, Parser<?>> unsafeMap = new HashMap<>();
<T extends Box, S extends Parser<T>> void add( Class<T> clazz, S parser ) {
unsafeMap.put( clazz, parser );
}
<T extends Box> boolean containsKey( Class<T> clazz ) {
return unsafeMap.containsKey( clazz );
}
@SuppressWarnings( "unchecked" )
<T extends Box, S extends Parser<T>> S get( Class<T> clazz ) {
return (S) unsafeMap.get( clazz );
}
}
public void runTest() {
Registry registry = new Registry();
registry.add( BoxA.class, new ParserA() );
registry.add( BoxB.class, new ParserB() );
List<Box> boxes = new ArrayList<>();
boxes.add( new BoxA( "Silly" ) );
boxes.add( new BoxB( "Funny" ) );
boxes.add( new BoxB( "Foo" ) );
boxes.add( new BoxA( "Bar" ) );
for ( Box box : boxes ) {
Class<? extends Box> clazz = box.getClass();
registry.get( clazz ).parse( clazz.cast( box ) );
}
}
public static void main( String[] args ) {
new GenericsTest().runTest();
}
}
如果您获取该代码并尝试对其进行编译,您会看到此错误:
The method parse(capture#4-of ? extends GenericsTest.Box) in the type GenericsTest.Parser is not applicable for the arguments (capture#5-of ? extends GenericsTest.Box)
那么问题来了,
(capture#4-of ? extends GenericsTest.Box)
不同于
(capture#5-of ? extends GenericsTest.Box)
?
而且,有没有比我的 Registry
方法更好的方法,不需要使用 @SuppressWarnings( "unchecked")
?
最佳答案
首先,让我们回答 OP 的问题。 (capture#4-of ? extends GenericsTest.Box)
之间有什么区别?和 (capture#5-of ? extends GenericsTest.Box)
?
编译器计算出传递给 registry.get()
的类对象类型为 Class<x>
对于一些未知的 x
扩展 Box
.因此类型推断实例化类型 T
的 get()
与 x
, 并得出结论,它返回的解析器的类型为 Parser<x>
同样的 x
扩展 Box
. (不幸的是,编译器使用像“capture#4-of ?”这样的术语来表示“对于某些 x4,这样的 x4”。)到目前为止,一切顺利。
通常发生的情况是,只要您有两个单独的表达式(即使是语法相同的表达式),其类型被推断为通配符类型,就会独立捕获存在变量。如果表达式出现在非通配符上下文中,您可以“统一”这些变量,通常是单独的泛型方法。
检查一下:
public class WildcardTest {
private < T > void two( Class< T > t1, Class< T > t2 ) {}
private < T > void one( Class< T > t1 ) {
two( t1, t1 ); // compiles; no wildcards involved
}
private void blah() {
two( WildcardTest.class, WildcardTest.class ); // compiles
one( WildcardTest.class ); // compiles
Class< ? extends WildcardTest > wc = this.getClass();
two( wc, wc ); // won't compile! (capture#2 and capture#3)
one( wc ); // compiles
}
}
还有这个:
public class WildcardTest {
interface Thing< T > {
void consume( T t );
}
private < T > Thing< T > make( Class< T > c ) {
return new Thing< T >() {
@Override public void consume(T t) {}
};
}
private < T > void makeAndConsume( Object t, Class< T > c ) {
make( c ).consume( c.cast( t ) );
}
private void blah() {
Class< ? extends WildcardTest > wc = this.getClass();
make( wc ).consume( wc.cast( this ) ); // won't compile! (capture#2 and capture#3)
makeAndConsume( this, wc ); // compiles
}
}
第二个例子是这里的相关例子。以下转换消除了除您已在注册表中抑制的警告之外的所有警告:
private < T extends Box > void getParserAndParse(
Registry registry, Class< T > clazz, Object box
) {
registry.get( clazz ).parse( clazz.cast( box ) );
}
public void runTest() {
Registry registry = new Registry();
registry.add( BoxA.class, new ParserA() );
registry.add( BoxB.class, new ParserB() );
List<Box> boxes = new ArrayList< Box >();
boxes.add( new BoxA( "Silly" ) );
boxes.add( new BoxB( "Funny" ) );
boxes.add( new BoxB( "Foo" ) );
boxes.add( new BoxA( "Bar" ) );
for ( Box box : boxes ) {
Class< ? extends Box > clazz = box.getClass();
getParserAndParse( registry, clazz, box ); // compiles
}
}
关于您的第二个问题,您正试图通过相当于变体类型 (Box) 的内容来执行临时多态性。有两种方法可以在没有类型警告的情况下实现这样的事情:
parseSelf
方法添加到 Box
),我从问题中收集到的方法不适合您,并且会使 Box
困惑。应用程序接口(interface)Box
的所有类型添加一个访问者接受器,这似乎是一个问题,原因与经典的 OO 分解相同Box
的所有可能种类在定义您的访客界面时提前 es关于Class<T> 到 Parser<T> 的 Java 泛型映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11488524/
可以用这种方式转换字符串吗?我们有相同的参数,Java 做出了正确的选择。如果值是整数 - 我们调用 parseInt(value),否则如果值是 double 型 - 我们调用 parseDoubl
如果这段代码中有一个愚蠢的错误,我提前道歉,但我似乎无法解决它。我的问题是这样的,我用GCC-8(通过home-brew安装在Mac上)编译,然后在终端中执行。当使用 int do 定义变量 s &
我用 a-videosphere 制作了一个 a-scene。我尝试使用按钮启用/禁用声音,但有些想法不起作用?这是我的代码: var gargamel = 0; function
我正在使用 ISAAC 实现来生成随机整数。我需要用这些整数创建一个高斯值。首先,我需要将它们从 0 更改为 1 的 double 值。我怎样才能在Java中做到这一点?这是到目前为止我将整数转换为
我将 0x0000 到 0x01c2 范围内的十六进制值从 BLE 获取到我的手机 a 作为字符串。为了将其绘制在图表中,我必须将其转换为 double,我已经尝试过 this method但遗憾的是
我有一个父类(super class) Animal和一个子类 Dog 。在第三节课中,我有一个 List它同时接受子类型和父类(super class)型对象。 public class foo{
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 6 年前。 Improve this ques
我正在尝试查询我的用户的距离。我可以用这段代码做到这一点 PFGeoPoint.geoPointForCurrentLocationInBackground { (geoPoint: PFGe
考虑示例:http://jsfiddle.net/KWLu7/16/ 我正在尝试将总体重要性值计算为每个选定选择重要性的总和乘以其父标准重要性: var watch = $scope.$watch("
这个问题在这里已经有了答案: Bounding generics with 'super' keyword (6 个答案) 关闭 2 年前。 我有一个列表装饰器,它应该允许从一个列表转换到另一个列表
为什么下面的代码没有选择最近父类(super class)型的隐式 val? class A class B extends A trait TC[-T] { def show(t: T): Stri
这是我想要做的 def merge[A, B, C](eithers: Either[A,B]*)(implicit ev1: A x, x => x)) 关于scala - 推断常见的父类(s
我正在尝试从具有 double 类型列的Cassandra表中获取 double 值。我已经使用CQL3语法创建了表: CREATE TABLE data_double ( datetime
是否应该在不需要显式类型定义的情况下编译以下 this ? def prepList[B >: A](prefix: PlayList[B]) : PlayList[B] = prefix.fol
我正在查看某人的代码,并且在创建结构时使用了 abstract type AbstractFoo end julia> struct Foo1 struct Foo2 foo_op(x::Abst
一些示例代码: public class Main { class SomeType { } class A { protected T createSome
是否可以只接受类的泛型类型的父类(super class)型? 我正在寻找的是这样的: class MyClass { public void myMethod(TS someObject
在我的代码中,我有许多 ArrayList 被传递到排序方法中。每个 ArrayList 都有不同的泛型类型,但所有这些类型都是 Sorter 的实现。排序方法旨在接受 Sorter 类型的 Arra
如果已经有人问过这个问题,请链接并关闭这个问题。 我目前正在为另一个使用起来复杂得多(并且有潜在危险)的 API 的简化 API 设计原型(prototype)。 考虑到相关的有点复杂的对象创建,我决
我正在尝试构建一个具有某些依赖项的 android 应用程序,但是其中一个导致了此错误: Illegal class file: Class module-info is missing a supe
我是一名优秀的程序员,十分优秀!