1

私はJavaを初めて使用し、ジェネリックスの処理方法について誤解していることが明らかな状況に陥りましたが、チュートリアルを読んだり、stackoverflowを検索したりしても、(少なくともこれまでのところ)私が思う以上の明確さは得られませんでした。ワイルドカードを誤用しています。ヘッズアップとして、私はC ++のバックグラウンドを持っているので、それがテンプレートをどのように扱うかは、おそらく私がこれにアプローチした方法を彩っています。

代表的なクラスを使用した継承の基本構造は次のとおりです

abstract class PacketHeader{
   // some stuff
}

class TypeOfPacketHeader extends PacketHeader{
   // extended stuff
}

abstract class Packet<T extends PacketHeader>{
    T mHeader;
    // some methods treating T as a type of PacketHeader
    // some abstract methods
}

class TypeOfPacket extends Packet<TypeOfPacketHeader>{
    static TypeOfPacket obtain {
        return new TypeOfPacket();
    }
    // overriden abstract functions that call specific TypeOfPacketHeader methods on mHeader
}

interface PacketParser<T extends Packet<? extends PacketHeader>>{
T obtainPacket();
        void parse(T packet);
}

class ImplementedPacketParser implements PacketParser<TypeOfPacket>{
     TypeOfPacket obtainPacket(){
         return TypeOfPacket.obtain();
     }
     void parse(TypeOfPacket packet){
         // code that relies on TypeOfPacket specific functions
     }
}

それはすべて正しいようです(または少なくとも日食は不平を言っていません)、私がそれらを利用しようとすると問題が発生するようです。私の最初の試みは:

class User{
    PacketParser mParser;

    User(PacketParser parser){
        mParser = parser;
    }

    void DoSomething(){
         Packet packet = mParser.obtainPacket();
         // do some stuff with the packet
         mParser.parse(packet);
    }
}

そして、Rawタイプの警告につながりました。だから私は試しました...

class User{
    PacketParser<? extends Packet<? extends PacketHeader>> mParser;

    User(PacketParser<? extends Packet<? extends PacketHeader>> parser){
        mParser = parser;
    }

    void DoSomething(){
         Packet<? extends PacketHeader> packet = parser.obtainPacket();
         // do some stuff with the packet
         mParser.parse(packet);
    }
}

しかし、これはエラーにつながります

タイプPacketParser>のメソッドparse(capture#9-of?extends Packet)は、引数(Packet)には適用できません。

この時点で、ジェネリックがどのように機能しているかについて何か誤解していると判断したので、stackoverflowを使用して、間違っている場所を示し、正しい方向に向けることができればと思います。

4

2 に答える 2

0

コードにいくつか変更を加えました。今すぐコンパイルします。これを使用してみてください。

   abstract class PacketHeader {
    // some stuff
   } 
   class TypeOfPacketHeader extends PacketHeader {
        // extended stuff
    }

    abstract class Packet<T extends PacketHeader> {
        T mHeader;
        // some methods treating T as a type of PacketHeader
        // some abstract methods
    }

    class TypeOfPacket extends Packet<TypeOfPacketHeader> {
        static TypeOfPacket obtain() {
            return new TypeOfPacket();
        }
        // overriden abstract functions that call specific TypeOfPacketHeader
        // methods on mHeader
    }

    interface PacketParser<T extends Packet<? extends PacketHeader>> {
        T obtainPacket();

        void parse(T packet);
    }

    class ImplementedPacketParser implements PacketParser<TypeOfPacket> {
        public TypeOfPacket obtainPacket() {
            return TypeOfPacket().obtain();
        }

        private TypeOfPacket TypeOfPacket() {
            // TODO Auto-generated method stub
            return null;
        }

        public void parse(TypeOfPacket packet) {
            // code that relies on TypeOfPacket specific functions
        }
    }

ユーザークラス。

class User{
    private PacketParser mParser;

    User(PacketParser parser) {
        mParser = parser;
    }

    void DoSomething() {
        Packet packet = mParser.obtainPacket();
        // do some stuff with the packet
        mParser.parse(packet);
    }
}
于 2012-06-19T20:45:29.013 に答える
0

あなたのコードでは、コンパイラはフィールド上のがローカル変数と同じタイプであるUserことを認識していません。? extends Packet<? extends PacketHeader>mParserPacket<? extends PacketHeader> packet

Userジェネリックにすることで使用されるパケットのタイプをバインドする必要があります。

class User<T extends Packet<?>> {
    PacketParser<T> mParser;

    User(PacketParser<T> parser){
        mParser = parser;
    }

    void DoSomething(){
         T packet = parser.obtainPacket();
         // do some stuff with the packet
         mParser.parse(packet);
    }
}

// and then when instantiating your User, specify the packet type:
new User<TypeOfPacket>(new ImplementedPacketParser())

これで、コンパイラは、表示されるTsが同じタイプのを表すことを認識しますが、表示さPacket<?>れるたびに、? extends Packet<?>の異なるサブタイプになる可能性がありPacket<?>ます。

編集:追記:クラスはすでにそのサブタイプとそのサブタイプを制限しているため、インターフェイス宣言には「 ? extends PacketHeader」は必要ありません。PacketParserPacketTPacketHeader

// ? is implicitly constrained to "extends PacketHeader" because of
// the way Packet's generic is defined
interface PacketParser<T extends Packet<?>> {
于 2012-06-19T20:47:06.533 に答える