简体   繁体   中英

Type-safe retrieval from collection of generic class

I have a generic Container which holds objects of type E:

public class Container<E> {

    private final E e;

    public Container(E e) {
        this.e = e;
    }

    public E get() {
        return e;
    }
}

I have a bucket which holds various containers:

public class Bucket {
    private final Map<String, Container<?>> containers = new HashMap<>();

    public void put(String name, Container<?> container) {
        containers.put(name, container);
    }

    public Container<?> get(String name) {
        Container<?> container = containers.get(name);
        return container;
    }
}

I want to be able to put containers (of various types) into the bucket and retrieve them back in a type-safe way.

    Container<Long> longs = new Container<>(100L);
    Container<String> strings = new Container<>("Hello");

    Bucket bucket = new Bucket();
    bucket.put("longs", longs);
    bucket.put("strings", strings);

But as you can I lost type-safety:

   Container<?> longs1 = bucket.get("longs");
   Container<?> strings1 = bucket.get("strings");

I can't seem to figure out what it'd take that would allow me achieve the following:

   Container<Long> longs1 = bucket.get("longs");
   Container<String> strings1 = bucket.get("strings");

My solution. I guess it serves my need pretty good:

public class Container<E> {

    private final E e;

    public Container(E e) {
        this.e = e;
    }

    public <T> T get(Class<T> target) {
        if (target.isAssignableFrom(e.getClass())) {
            return (T) e;
        }
        throw new ClassCastException(e.getClass().getName() + " '" + e + "' cannot be converted to " + target.getName());
    }
}
public class Bucket {
    private final Map<String, Container<?>> containers = new HashMap<>();

    public void put(String name, Container<?> container) {
        containers.put(name, container);
    }

    public Container<?> getContainer(String name) {
        return containers.get(name);
    }
}

Putting it to test:

Container<Long> longs = new Container<>(100L);
Container<String> strings = new Container<>("Hello");

Bucket bucket = new Bucket();
bucket.put("longs", longs);
bucket.put("strings", strings);

Container<?> longContainer = bucket.getContainer("longs");
Long aLong = longContainer.get(Long.class);
log.debug("{}", aLong); // Prints 100

Container<?> stringContainer = bucket.getContainer("strings");
String aString = stringContainer.get(String.class);
log.debug("{}", aString); // Prints Hello

log.debug("{}", stringContainer.get(Long.class)); // Throws java.lang.ClassCastException: java.lang.String 'Hello' cannot be converted to java.lang.Long

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM