ジェネリックコンテナの汎用ファクトリ

I have a generic abstract class Factory with a method createBoxedInstance() which returns instances of T created by implementations of createInstance() wrapped in the generic container Box.

abstract class Factory {
    abstract T createInstance();

    public final Box createBoxedInstance() {
        return new Box(createInstance());
    }

    public final class Box {
        public final T content;

        public Box(T content) {
            this.content = content;
        }
    }
}

At some points I need a container of type Box where S is an ancestor of T. Is it possible to make createBoxedInstance() itself generic so that it will return instances of Box where S is chosen by the caller? Sadly, defining the function as follows does not work as a type parameter cannot be declared using the super keyword, only used.

public final  Box createBoxedInstance() {
    return new Box(createInstance());
}

The only alternative I see, is to make all places that need an instance of Box accept Box<? extends S> which makes the container's content member assignable to S.

Is there some way around this without re-boxing the instances of T into containers of type Box? (I know I could just cast the Box to a Box but I would feel very, very guilty.)

4
@Luisその問題は、私がSのために使用したいタイプを前もって決めなければならないということです。そのアイデアは、私がTのファクトリを作成し、それを使ってSのさまざまなタイプパラメータを持つボックス化されたTを作成することができるということです。
追加された 著者 Feuermurmel,
@Peter Lawrey UがTを拡張するUを作成するファクトリは問題ありません。しかし、私の例では、TがSを拡張することを望みます。もし私がSを createBoxedInstance でTを拡張したいのであれば、宣言の前に を書くだけです。
追加された 著者 Feuermurmel,
@ルイス説明をありがとうございます。 S が間違っていても List List T があります。私は今、型を List <?>として宣言するという事実を受け入れ、受け入れました。 extends X> が可能です。
追加された 著者 Feuermurmel,
Box を使用しない理由は、SがTを拡張しても、 Factoy はboxed Sを作成します。boxed U(これはTも拡張します)
追加された 著者 Peter Lawrey,
あなたは抽象クラスFactory を試してみましたが、Tを使用するのはcreateInstance()だけですが、Sは他のどこでも使っていますか?または、抽象クラスFactory
追加された 著者 Luis,
私は、あなたが持っているものは、Javaでは共通の問題であり、クリーンな終了がないと考えています。たとえば、List aがあり、それをList に割り当てる場合は、b。 StringはCharSequenceを実装していても基本的に異なる型であるため、できません。それがうまくいき、文字列ではないbにCharSequenceを追加しようとすると、誰かがaからそれを取得しようとする可能性があり、タイプ違反が発生する可能性があります。
追加された 著者 Luis,

3 答え

Try rewriting your other code to not use Box but instead uses Box<? extends S>, so it will accept a Box, too. This way, you make it explicit that the Box may also contain subclasses of S.

Box static を作った場合は、以下もうまくいくはずです:

public static  Box createBoxedInstance(Factory factory) {
  return new Box(factory.createInstance());
}

ただし、 S の型推論を行うことができない場合があります。

public static  Box createBoxedInstance(Factory factory, S dummy) {
  return new Box(factory.createInstance());
}

非常に明白な別のバリエーション:

public static  Box<? extends S> createBoxedInstance(Test factory, S dummy) {
  return factory.createBoxedInstance();//Actually a Box
}
2
追加された
これらはすべてハックですが、このことからきれいなセマンティクスは得られません。 Box <?を使う方がはるかに賢明です。 S> を拡張して、ボックスがサブタイプ用であることを確認します。
追加された 著者 Anony-Mousse,
この答えには、私の元の質問に答えるほとんどの例が含まれていますが、実際には Box Box を内部的に使用します。 Box <? T> を拡張する方法があります。チェックされていないキャストを内部的に使用して、実際に私の元の質問に答えたい場合は、 Ben Schulzの答えをご覧ください。
追加された 著者 Feuermurmel,

あなたはあなたが望むものをある程度獲得することができます:

public final > S createBoxedInstance() {
   //sadly we can't capture the wildcard in the bound of S
   //this means we have to cast, but at least it's local..
   //*should* this cast ever break due to reification, we
   //can fix it here and be good to go
    @SuppressWarnings("unchecked")
    S box = (S) new Box(createInstance());
    return box;
}

Factory factory = getFactory();
Box box1 = factory.createBoxedInstance();
Box box2 = factory.createBoxedInstance();

I do think that your own Box<? extends S>-Alternative is the correct approach. However, if this will force client code to be littered with wildcards, the above might be preferable.

0
追加された
私はあなたの答えを受け入れられた答えのコメントにリンクしましたが、私はあなたのアドバイス(そして他者)に Box <? S> を拡張します。
追加された 著者 Feuermurmel,

あなたがそれをやり遂げることができない(またはあなたが奇妙な変換を使用しなければならない)理由は以下の通りです 最終的なものではなくボックスのコンテンツにもセッターがあったと想像してください。また、タイプSがRとTの両方のスーパータイプであるとします。次のコードは、キャストなしで有効です。

Box boxT = new Box(objectT);
Box boxS = boxT;
S objectR = new R();
boxS.set(objectR);

このコードは警告なしで有効ですが、R型のものを何かに割り当てることができないため、実行時にsetterが予期しない例外(予期しないキャスト例外がスローされるという意味では予期しない例外)タイプTの

詳細については、 http://www.angelikalanger.com/GenericsFAQ/FAQSections/を参照してください。 TechnicalDetails.html#Topic3 (ただし、アスピリンは近くにいると頭痛になる)

多くの人が言っているように、おそらく他のコードのボックスを使うのが最善の選択肢です。

0
追加された