0

私はJavaとジェネリックに比較的慣れていません。私は何か間違ったことをしているのか、ジェネリックメソッドを書いていないのかを理解しようとしています。次のコードがあります(大幅に簡略化されています):

public class ContentIniter {       
    public ContentType getContentType();
}

public interface Content {
}

public class Show implements Content {       
}

public class Movie implements Content {       
}

public enum ContentType {
    Movie, Show
}

public class Channel {

    public List<Show> getShows() {
        return getContentByType(ContentType.Show)
    }

    public List<Movie> getMovies() {
        return getContentByType(ContentType.Movie)
    }

    private <T> List<T> getContentByType(ContentType contentType) {
        List<T> typeContents = Lists.newArrayList();
        List<ContentIniter> allContentIniters = someMethod(); // Returns initers for both shows and movies
        for (Content contentIniter : allContentIniters) {
            if (contentIniter.getContentType().equals(contentType)) {
                switch (contentType) {
                case Movie:
                    typeContents.add((T) new Movie(contentIniter));
                    break;
                case Show:
                    typeContents.add((T) new Show(contentIniter));
                    break;
                }
            }
        }
        return typeContents;
    }

}

私の質問は、次の行に関連しています。

typeContents.add((T) new Movie(contentIniter));

コードをコンパイルする唯一の方法は、コンテンツ オブジェクトを T にキャストすることです。 )。さらに、コードは機能しますが、IntelliJ はチェックされていないキャストについて不平を言います。

ジェネリック メソッドを記述するより良い方法はありますか?

更新:コードを単純化しようとしたときに、コードを少し台無しにしました。への参照を修正しましたtypeContents。また、単にinstanceof.

更新 2 : さらに別のエラーが発生したことに気付きました...ContentIniterコンテンツを実装していません。また、注目に値するのContentIniterは、単なる作り物のオブジェクトです。奇妙に思える場合は、コンテンツ オブジェクトが特定の動作を委任するために使用するイベントまたはその他の戦略と考えてください。

4

4 に答える 4

1

ジェネリックを適切に使用していません。実際には必要ないときに、それらを列挙と混合しています。理想的には、呼び出してから、リフレクションを使用しgetContentByType<Show>()て正しいタイプのリストを決定します。allContents

同様の行に沿って何かを試してください(テストされていません):

private <T> List<T> getContents() {
    List<T> typeContents = Lists.newArrayList();
    List<Content> allContents = someMethod(); // Returns both shows and movies
    for (Content content : allContents) {
        if (content instanceof T) {
            typeContents.add((T) content);
        }
    }
    return typeContents;
}

そして呼び出します:

List<Show> shows = getContents<Show>();

次に、その上で呼び出される型を拡張する型のみに制限できますContent

private <T extends Content> List<T> getContents() {
    ...
}
于 2013-07-11T04:38:38.853 に答える
0

実際には、答えはあなたが考えるよりも簡単です。コンパイラを満足させるには、 Content のインスタンスが Show か Movie かを確認するだけです:

if (content instanceof Movie)
    contents.add((Movie) content);
if (content instanceof Show)
    contents.add((Show) content);

とにかく、ジェネリックメソッドを書いた方法は正しいと思います。しかし、インスタンス ( instanceof) のタイプをチェックするネイティブな方法があるため、それを使用する必要があります :)

EDIT:私はまだあなたが使用すべきだと思いますinstanceof

List<Content>さらに、 Content はよりグローバルなタイプであるため、 a の代わりに aを使用する必要がありますList<ContentIniter>。誰かが Content の別の実装を思いついた場合、コードを変更する必要はありません。実際には、たとえば ArrayList の代わりに Interface List を使用する場合も同じことを行っています。List は ArrayList ほど具体的ではないからです。

また、列挙型を使用することは間違いではありません。使用したい場合は使用できます。ただし、インスタンスのタイプを決定するために使用しないでください。インスタンスのタイプは、インスタンス自体、ピリオドに含まれています。それでも、Daniel Imms のソリューションは私のソリューションよりも洗練されており、Java 型の機能をよりうまく活用していると言えます。

public interface Content {
    public STContentType getContentType();
}

public class ContentIniter implements Content {       
}

// You can keep the enum, as long as it's not used 
// to check for the type of an instance of ContentIniter
public enum ContentType {
    Movie, Show
}

public class Show implements Content {       
}

public class Movie implements Content {       
}


public class Channel {

    public List<Show> getShows() {
        return getContentByType(ContentType.Show)
    }

    public List<Movie> getMovies() {
        return getContentByType(ContentType.Movie)
    }

    private <T> List<T> getContentByType(ContentType contentType) {
        List<T> typeContents = Lists.newArrayList();
        // Using more generic type Content
        List<Content> allContentIniters = someMethod(); // Returns initers for both shows and movies
        for (Content contentIniter : allContentIniters) {
            // If it's a Show and I asked for Shows
            if (contentIniter instanceof Show && contentType == ContentType.Show)) {
                typeContents.add(contentIniter);
            }
            // If it's a Movie and I asked for Movies
            if (contentIniter instanceof Movie && contentType == ContentType.Movie){
                typeContents.add(contentIniter);
            } 
        }
        return typeContents;
    }

}
于 2013-07-11T04:35:29.590 に答える