[英]Is there any way to declare that an inner class has the same generic type as the outer?
有什么方法可以通过内部类重用外部类的通用参数吗?
我有以下课程
public class TaggedUnionBuilder<L,R>{
private final Class<L> leftClass;
private final Class<R> rightClass;
public TaggedUnionBuilder( Class< L > leftClass, Class< R > rightClass ) {
this.leftClass = leftClass;
this.rightClass = rightClass;
}
TaggedUnion<L,R> left( L aLeft ){
return new TaggedUnion<>( true, aLeft );
}
TaggedUnion<L,R> right( R aRight ){
return new TaggedUnion<>( false, aRight );
}
public class TaggedUnion<L,R>{
private final boolean isLeftClass;
private final Object value;
private TaggedUnion( boolean isLeftClass, Object value ) {
this.isLeftClass = isLeftClass;
this.value = value;
}
L left(){
//vvv compiler error vvv
return leftClass.cast( value );
//^^^ compiler error ^^^
}
R right(){
//vvv compiler error vvv
return rightClass.cast( value );
//^^^ compiler error ^^^
}
boolean isLeft(){
return isLeftClass;
}
boolean isRight(){
return !isLeftClass;
}
}
}
但是,我有一个错误:
java:不兼容的类型:L不能转换为L
java:不兼容的类型:R不能转换为R
在left()
和right()
方法中。
这似乎是宣告L
和R
在TaggedUnion
被遮蔽在声明TaggedUnionBuilder
。 如果删除TaggedUnion
的通用参数声明,则无法将其作为通用类型返回。
如果我从TaggedUnion
删除通用参数, TaggedUnion
收到错误消息
java:类型为TaggedUnionBuilder.TaggedUnion不带参数
解决该问题的方法是使内部类TaggedUnion
成为static class
并显式传递TaggedUnionBuilder
的实例。 这样可以解决问题。
public class TaggedUnionBuilder<L,R>{
private final Class<L> leftClass;
private final Class<R> rightClass;
public TaggedUnionBuilder( Class< L > leftClass, Class< R > rightClass ) {
this.leftClass = leftClass;
this.rightClass = rightClass;
}
public TaggedUnion<L,R> left( L aLeft ){
return new TaggedUnion<>( this, true, aLeft );
}
public TaggedUnion<L,R> right( R aRight ){
return new TaggedUnion<>( this, false, aRight );
}
public static class TaggedUnion<L,R>{
private final boolean isLeftClass;
private final Object value;
private final TaggedUnionBuilder<L,R> parent;
private TaggedUnion( TaggedUnionBuilder<L,R> aParent, boolean isLeftClass, Object aValue ) {
this.parent = aParent;
this.isLeftClass = isLeftClass;
this.value = aValue;
}
public L left(){
return parent.leftClass.cast( value );
}
public R right(){
return parent.rightClass.cast( value );
}
public boolean isLeft(){
return isLeftClass;
}
public boolean isRight(){
return !isLeftClass;
}
}
}
但实际上使TaggedUnion
成为一个单独的类(只需为TaggedUnionBuilder
上的类提供TaggedUnionBuilder
)。
由于您有一个嵌套类,因此泛型类型也被“传播”到嵌套类中。
public class Outer<A> {
Inner in;
Outer( A a ) {
in = new Inner( a );
}
Inner get() {
return in;
}
class Inner {
A value;
Inner( A value ) {
this.value = value;
}
}
public static void main( String[] args ) {
String s = new Outer<>( "test" ).get().value;
//And to declare an variable Inner
Outer<String>.Inner i = new Outer<>( "test" ).get();
}
}
声明一个Outer<String>
然后将给出一个Outer<String>.Inner
,该value
将是一个String
。
如果声明了Inner
,则需要使用完整的类名来指定泛型类型,这虽然冗长但又是正确的解决方案。
所述问题的真正答案(在评论中由@lexicore提供)是使用父名称来限定返回的类型,例如:
public class TaggedUnionBuilder<A,B>{
private final Class<A> classA;
private final Class<B> classB;
public TaggedUnionBuilder( Class< A > classA, Class< B > classB ) {
this.classA = classA;
this.classB = classB;
}
public TaggedUnionBuilder<A,B>.TaggedUnion left( A aA ){
return new TaggedUnion( true, aA );
}
public TaggedUnionBuilder<A,B>.TaggedUnion right( B aB ){
return new TaggedUnion( false, aB );
}
public class TaggedUnion{
private final boolean isClassA;
private final Object value;
private TaggedUnion( boolean isClassA, Object aValue ) {
this.isClassA = isClassA;
this.value = aValue;
}
A left(){
return classA.cast( value );
}
B right(){
return classB.cast( value );
}
boolean isA(){
return isClassA;
}
boolean isB(){
return !isClassA;
}
}
}
但是,这意味着不能指TaggedUnion
genericly 而不包括在类型包含类(即总是TaggedUnionBuilder<A,B>.TaggedUnion
代替TaggedUnion
),其是符合人体工程学的残酷但回答了说明。
前言
首先,让我怀疑您所展示的一门课程的用处。 如果一个能够将一种类型转换为另一种类型,则至少一个类型是接口,或者两种类型都处于继承关系中。 从我的角度来看,您可以使用Class#isAssignableForm(Object obj)
, Class#isInstance(Object obj)
和Class#cast(Object obj)
来完成所有这些工作。
在部署构建器模式时 ,通常会将构建器写为实际类型的内部静态类。 这有助于提高可读性(重要的类是POJO,而不是生成器)。 此外,内部(非静态)类始终对创建它的周围类的实例具有隐式引用。
有什么方法可以通过内部类重用外部分类的通用参数吗?
就在这里。 让我们看一下您的代码的简化版本。
public class TaggedUnionBuilder<A, B> {
// ...
public class TaggedUnion {
// ...
}
}
众所周知,我们先实例化外部类的实例,然后在该实例上调用new <InnerClass>()
来实例化内部类,如下所示:
TaggedUnionBuilder<String, Object> builder = new TaggedUnionBuilder<String, Object>();
TaggedUnionBuilder<String, Object>.TaggedUnion union = builder.new TaggedUnion();
通过编写此代码,可以看到union
的完整类型确实是TaggedUnionBuilder<String, Object>.TaggedUnion
。
这对实施意味着什么?
我们可以使用TaggedUnion
已经存在的通用参数A
和B
因此,我们可以将代码重构为:
public class TaggedUnionBuilder<A, B> {
private final Class<A> classA;
private final Class<B> classB;
public TaggedUnionBuilder(Class<A> classA, Class<B> classB) {
this.classA = classA;
this.classB = classB;
}
TaggedUnion left(A a) {
return new TaggedUnion(true, a);
}
TaggedUnion right(B b) {
return new TaggedUnion(false, b);
}
public class TaggedUnion {
private final boolean isClassA;
private final Object value;
private TaggedUnion(boolean isClassA, Object value) {
this.isClassA = isClassA;
this.value = value;
}
A left() {
return classA.cast(value);
}
B right() {
return classB.cast(value);
}
boolean isA() {
return isClassA;
}
boolean isB() {
return !isClassA;
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.