有没有办法通过内部类重用外部类的泛型参数?
我有以下课程
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
删除通用参数,我会收到错误
java:type TaggedUnionBuilder.TaggedUnion不接受参数
答案 0 :(得分:2)
围绕它进行一项工作,使内部类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
上的类创建访问器。)
答案 1 :(得分:2)
由于你有一个嵌套类,所以通用类型是&#34;传播&#34;进入嵌套类。
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
,则需要使用完整的类名来指定泛型类型,这是一个更冗长但更正确的解决方案。
答案 2 :(得分:1)
所述问题的真实答案(由@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
通用包括类型中的包含类(即始终TaggedUnionBuilder<A,B>.TaggedUnion
而不是TaggedUnion
)这是残酷的符合人体工程学,但回答了所陈述的问题。
答案 3 :(得分:0)
<强>前言强>
让我首先怀疑像你所展示的那个类的有用性。如果能够将一种类型转换为另一种类型,则至少一种类型是接口,或者两种类型都处于继承关系中。从我的角度来看,您可以使用Class#isAssignableForm(Object obj)
,Class#isInstance(Object obj)
和Class#cast(Object obj)
完成所有这些操作。
部署Builder Pattern时,通常会将构建器写为实际类型的内部静态类。这有利于可读性(重要的类是POJO,而不是构建器)。此外,内部(非静态)类始终具有对其创建的周围类的实例的隐式引用。
有没有办法通过内部类重用外部clas的泛型参数?
是的。让我们看一下代码的简化版本。
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
。
这对实施意味着什么?
我们可以使用A
中已有的通用参数B
和TaggedUnion
。因此,我们可以将代码重构为:
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;
}
}
}