4

さまざまなタイプのオブジェクトを格納するためのデータ構造が必要です。たとえばStringBoolean他のクラス。
キーを使用すると、それをキャストする方法を知っていることを前提とした、それに応じたオブジェクトを取得するMap<String, Object>場所を使用していますか?
より良い解決策はありますか?

4

2 に答える 2

5

PropretyHolderこれは、私が少し前に書いたのに最適なユースケースです。あなたは私のブログでそれについて詳しく読むことができます。私は不変性を念頭に置いて開発しました。ニーズに合わせて自由に調整してください。

一般に、Javaの型安全性から利益を得たい場合は、キーを知っている必要があります。つまり、キーが外部ソースから取得されるタイプセーフソリューションを開発することはほとんど不可能です。


その値のタイプを知っている特別なキーは次のとおりです(完全ではありません。完全なバージョンのソースをダウンロードしてください)。

public class PropertyKey<T> {
    private final Class<T> clazz;
    private final String name;

    public PropertyKey(Class<T> valueType, String name) {
        this.clazz = valueType;
        this.name = name;
    }

    public boolean checkType(Object value) {
        if (null == value) {
            return true;
        }
        return this.clazz.isAssignableFrom(value.getClass());
    }

    ... rest of the class

}

次に、それを利用するデータ構造を開発します。

public class PropertyHolder {

    private final ImmutableMap<PropertyKey<?>, ?> storage;

    /**
     * Returns value for the key of the type extending-the-one-declared-in-the {@link PropertyKey}.
     * 
     * @param key {@link PropertyKey} instance.
     * @return Value of the type declared in the key.
     */
    @SuppressWarnings("unchecked")
    public <T extends Serializable> T get(PropertyKey<T> key) {
        return (T) storage.get(key);
    }

    /**
     * Adds key/value pair to the state and returns new 
     * {@link PropertyHolder} with this state.
     * 
     * @param key {@link PropertyKey} instance.
     * @param value Value of type specified in {@link PropertyKey}.
     * @return New {@link PropertyHolder} with updated state.
     */
    public <T> PropertyHolder put(PropertyKey<T> key, T value) {
        Preconditions.checkNotNull(key, "PropertyKey cannot be null");
        Preconditions.checkNotNull(value, "Value for key %s is null", 
                key);
        Preconditions.checkArgument(key.checkType(value), 
                "Property \"%s\" was given " 
                + "value of a wrong type \"%s\"", key, value);
        // Creates ImmutableMap.Builder with new key/value pair.
        return new PropertyHolder(filterOutKey(key)
                .put(key, value).build());
    }

    /**
     * Returns {@link Builder} with all the elements from the state except for the given ket.
     * 
     * @param key The key to remove.
     * @return {@link Builder} for further processing.
     */
    private <T> Builder<PropertyKey<? extends Serializable>, Serializable> filterOutKey(PropertyKey<T> key) {
        Builder<PropertyKey<? extends Serializable>, Serializable> builder = ImmutableMap
                .<PropertyKey<? extends Serializable>, Serializable> builder();
        for (Entry<PropertyKey<? extends Serializable>, Serializable> entry : this.storage.entrySet()) {
            if (!entry.getKey().equals(key)) {
                builder.put(entry);
            }
        }
        return builder;
    }

    ... rest of the class

}

ここでは不要な詳細を省略していますが、不明な点がありましたらお知らせください。

于 2012-09-14T09:07:44.197 に答える
2

Atypesafe heterogeneous containerはこの目的に使用できます。

import java.util.HashMap;
import java.util.Map;

public class Container {

    private Map<Class<?>, Object> container = new HashMap<Class<?>, Object>();

    public <T> void putElement(Class<T> type, T instance) {
        if (type == null) {
            throw new NullPointerException("Type is null");
        }
        //container.put(type, instance); // 'v1'
        container.put(type, type.cast(instance)); // 'v2' runtime type safety!
    }

    public <T> T getElement(Class<T> type) {
        return type.cast(container.get(type));
    }

    public static void main(String[] args) {

        Container myCont = new Container();
        myCont.putElement(String.class, "aaa");
        myCont.putElement(Boolean.class, true);
        myCont.putElement(String[].class, new String[] {"one", "two"});

        System.out.println(myCont.getElement(String.class));
        System.out.println(myCont.getElement(String[].class)[1]);

    }

}

制限:このフォームのコンテナーは、 1つのインスタンス/オブジェクトタイプのみを格納できます。

では、動的キャストを使用してランタイムタイプの安全性putElement()を実現できます。ただし、これによりオーバーヘッドが追加されます。

例:生のクラスオブジェクトをコンテナに渡してみてください。例外が発生する場所に注意してください。

Class raw = Class.forName("MyClass");
myCont.putElement(raw, "aaa"); //ClassCastException if using 'v2'
System.out.println(myCont.getElement(raw)); //ClassCastException if using 'v1'
于 2012-09-14T09:34:45.130 に答える