2

次のようにXMLツリーを表すクラスを実装しようとしています。

    public class XML<T extends XML<T>> {

        private final List<MarkupLanguage> nodeList = new ArrayList<>();

        private final Map<String, String> attributeList = new HashMap<>();

        public T attr(final String key, final String value) {
            if (value != null) {
                this.attributeList.put(key, value);
            } 
            return (T) this;
        }

        public T appendTo(final T node) {
            node.add(this);
            return (T) this;
        }
        ...
    } 

私の問題は、これらの句の入力です-「return(T)this;」のチェックされていないキャストが表示されます。

また、XMLクラスを単独で使用しようとすると、次のようになります。

    final XML url = new XML("url");
    new XML("loc")
        .add("http://goout.cz")
        .appendTo(url);

私は得ています:

    Unchecked cast to call appendTo(T) as a member of raw type XML.

コードを改善してタイピングを改善するにはどうすればよいですか?

4

2 に答える 2

5

入力するだけです:

final XML<T> url = new XML<T>("url");
new XML<T>("loc")
    .add("http://goout.cz")
    .appendTo(url);

XML<T>また、ではなく、メソッドに本当に使用したいように見えるTので、キャストを回避できます(ただし、間違っている可能性があります)。

public XML<T> attr(String key, String value) {
    if (value != null) {
        this.attributeList.put(key, value);
    } 
    return this;
}

public XML<T> appendTo(XML<T> node) {
    node.add(this);
    return this;
}
于 2012-10-13T00:37:59.757 に答える
0

以下のアプローチについてはどうですか(単純な継承とジェネリックメソッド):

import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

public class XmlTest {

    @Test
    public void test() {
        XMLFirstSubclass url = new XMLFirstSubclass("url");
        XMLSecondSubclass xmlSecondSubclassInstance = new XMLSecondSubclass(
                "loc").add("http://goout.cz").appendTo(url);
    }
}

abstract class XML {

    private final List<String> texts = new ArrayList<String>();

    private final List<XML> nodes = new ArrayList<XML>();

    private final String nodeName;

    protected XML(String nodeName) {
        this.nodeName = nodeName;
    }

    @SuppressWarnings("unchecked")
    public <R extends XML> R add(String text) {
        texts.add(text);
        return (R) this;
    }

    @SuppressWarnings("unchecked")
    public <R extends XML, T extends XML> R add(T node) {
        nodes.add(node);
        return (R) this;
    }

    @SuppressWarnings("unchecked")
    public <R extends XML, T extends XML> R appendTo(T node) {
        node.add(this);
        return (R) this;
    }
}

class XMLFirstSubclass extends XML {
    public XMLFirstSubclass(String nodeName) {
        super(nodeName);
    }
}

class XMLSecondSubclass extends XML {
    public XMLSecondSubclass(String nodeName) {
        super(nodeName);
    }
}

ジェネリック メソッドでは、1 つの型 T からノードを取得し、インスタンスの型 R を返すことができることに注意してください。これは、引数の型とは異なる場合があります。T は R とは異なる場合がありますが、どちらも XML を継承しています。

質問で提示されたアプローチに関するコメント

あなたが今まで使ってきたアプローチは、奇妙な状況につながる可能性があります. これを例で説明しましょう。

以下では、XML を特化した最初のクラスを作成してみます。

public class XMLFirstSubclass extends XML<OtherXMLSubclass> { ... }

最初の XML サブクラスを作成している場合、OtherXMLSubclass に可能な唯一の値は、XMLFirstSubclass であるか、ジェネリック型をまったく宣言しないことです。

最初のオプション:

public class XMLFirstSubclass extends XML<XMLFirstSubclass> { ... }

2番:

public class XMLFirstSubclass extends XML { ... }

クラスの設計でジェネリックを使用することを選択した場合、2 番目のオプションは不適切に思えます。
最初のオプションを詳しく見てみると、次のようなサブクラスを取得する可能性が開かれます。

class XMLSecondSubclass extends XML<XMLFirstSubclass> {
    ... 
}

これは完全にコンパイルされますが、実行時に XMLSecondSubclass メソッド呼び出しでクラス キャスト例外が発生することに注意してください。

于 2012-10-13T02:01:32.207 に答える