ジェネリックのラッパークラスの継承構造に問題があります。これは、基本的な構造です:汎用スーパークラスを返す
public abstract class SuperWrapper<E extends Super>{
private E wrappedObject;
public E getWrappedObject(){
return wrappedObject;
}
}
public abstract class MiddleWrapper<E extends Middle> extends SuperWrapper<E>{}
public class SubAWrapper extends MiddleWrapper<SubA>{}
public class SubBWrapper extends MiddleWrapper<SubB>{}
包まれているクラスはとても基本的に、同じ継承構造に従います。
public class Super{}
public class Middle extends Super{}
public class SubA extends Middle{}
public class SubB extends Middle{}
これらのラップクラスは地雷ではないとの理由である(変更することはできませんラッパークラスの場合)。この構造体はほとんどの場合非常にうまく動作しますが、SubAWrapperまたはSubBWrapperのいずれかを返すメソッドが必要な場合にはいくつかの問題があります。
これは私がこれまで試したものです:
public static MiddleWrapper<?> findMiddle(String id){
SubAWrapper a = new SubAWrapper();
SubBWrapper b = new SubBWrapper();
if(returnSubA){
return a;
} else{
return b;
}
}
これは、コンパイルして動作しますが、SonarQubeは、戻り値の型でのワイルドカードの使用について警告し、私のグーグルから、それはそのはずのいずれかの警告ではありません無視される。
別の方法:
public static <E extends Middle> MiddleWrapper<E> findMiddle(String id){
SubAWrapper a = new SubAWrapper();
SubBWrapper b = new SubBWrapper();
if(returnSubA){
return (MiddleWrapper<E>) a;
} else{
return (MiddleWrapper<E>) b;
}
}
これは、コンパイルし、現在のコードで動作しますが、それは危険なようです。呼び出し元がMiddleWrapper<SubA> middle = findMiddle("1");
のようにこのメソッドを使用すると、コンパイルは正常に行われますが、findMiddleがSubBWrapperを返そうとすると実行時にClassCastExceptionが発生します。何でも、私は仕事だろうが、していなかった:
public static MiddleWrapper<Middle> findMiddle(String id){
SubAWrapper a = new SubAWrapper();
SubBWrapper b = new SubBWrapper();
if(returnSubA){
return (MiddleWrapper<Middle>) a; //Compile error here
} else{
return (MiddleWrapper<Middle>) b; //and here
}
}
だから私の質問は、基本的に、実行をコンパイルし、ベストプラクティスを、次の方法のfindMiddleを書き込むための正しい方法はありますか?
また、SubAとSubBの両方を含むリストを返すようにメソッドを書く方法がありますか?このようにワイルドカードなし:
public static List<MiddleWrapper<?>> getAllMiddle(){
List<MiddleWrapper<?>> ret = Lists.newArrayList();
ret.add(new SubAWrapper());
ret.add(new SubBWrapper());
return ret;
}
ps現時点ではまだJava 6を使用していますが、Java 8へのアップグレードは来年に予定されているため、Java 7-8の機能を使用するソリューションは引き続き有効です。
それは悪い習慣になる理由はここに少し説明しますhttps://sonarcloud.io/organizations/default/rules#q=wildcardをも様々にhttps://stackoverflow.com/questions/22815023/generic-wildcard-types-should-not-be-used-in-return-parametersなどのスタックオーバーフローに関する質問。 MiddleWrapper >またはMiddleWrapper <?を使用できますか?中間>を返すタイプでは解決しやすいですが、問題がなければそれが可能かどうかです。 – MatsT
これを実現するには、MiddleWrapperはジェネリックを指定せずにインスタンス化できる必要があります。ジェネリックのレイヤーを削除することで可能です。最後に、ジェネリック制約とAPIの使いやすさの間にトレードオフがあります。 – davidxxx