通用对象的集合。自动铸造?隐藏铸造?

时间:2015-04-06 22:48:17

标签: java generics

我试图以下列方式保存节点属性(这可能本质上是错误的):

public class Property<T> {
    protected String key;
    protected T value;

    public Property(String key, T value) {
        this.key = key;
        this.value = value;
    }
}


public class Node {
    protected HashMap<String,Property> properties;

    public Node() {
        properties = new HashMap<>();
    }

然而,这有一个令人遗憾的副作用,让我成为一个巨大的铸造混乱。我一直在阅读可能相关的所有内容,但似乎没有解决问题。这是我目前的想法:

    public void add(String key, Object value) {
        if ( ! (value instanceof Property)) {
            value = new Property<>(key, value);
        }
        properties.put(key, (Property)value);
    }

    public long get(String key, long x) {
        return (long)properties.get(key).value;
    }
    public long[] get(String key, long[] x) {
        return (long[])properties.get(key).value;
    }
    public String get(String key, String x) {
        return (String)properties.get(key).value;
    }
    // etc

现在这显然是令人难以置信的愚蠢,但我正在试图简单地通过键获取节点属性,并确保它是基于密钥的类型。

就这么简单。 给定密钥必须与给定类型相对应,包括添加和获取

老实说,我觉得我误解了Java的本质。

6 个答案:

答案 0 :(得分:3)

试试这个

// a node representing things of type T
public class Node<T> {
    protected HashMap<String,Property<T>> properties;

    public Node() {
        properties = new HashMap<>();
    }

    // add a T to the map
    public void add(String key, T value) {
        properties.put(key, new Property<T>(string, value));
    }
}

到目前为止,我对你的例子感到担忧的是一个节点&#34;看起来很像hashmap Entry。一个更好的问题是&#34;你真正想做什么&#34;?

答案 1 :(得分:2)

  

给定的密钥必须对应于给定的类型,包括添加和获取。

假设你的意思是String key是元素及其类型的标识符,那么你运气不好,用泛型来说根本不可能。一种选择是为每个已知属性定义一个具有适当类型字段/ getter的自定义类。

如果您的意思是x参数,那么您可以使用泛型来执行类似

的操作
public <T> T get(String key, T x) {
    return (T) properties.get(key).value;
}

但是这可以为各种ClassCastException设置。您的编译器应该警告这一点。 (另请注意,您将无法直接使用基本类型。)

答案 2 :(得分:0)

可以编写一个外部类型安全的实现,虽然它需要一些编译器无法证明是正确的内部转换。

class TypeSafeMap {
  public static final class Key<T> {
    // deliberately empty; we're knowingly using reference equality
  }

  private final Map<Key<?>, Object> map;

  TypeSafeMap() {
    this.map = new HashMap<>();
  }

  public <T> T get(Key<T> key) {
    return (T) map.get(key); // cast is safe, but the compiler can't prove it
  }

  public <T> void put(Key<T> key, T value) {
    map.put(key, value);
  }
}

class SomewhereElse {
  static final Key<Integer> myIntKey = new Key<Integer>();
  static final Key<String> myStringKey = new Key<String>();

  public void doWhatever(TypeSafeMap myMap) {
    int myInt = myMap.get(myIntKey);
    String myString = myMap.get(myStringKey);
  }
}

...也就是说,如果你事先知道了整个键组,你可以(并且应该)用适当类型的字段创建一个自定义类,而不是试图将整个事物压缩成类似地图的结构。

答案 3 :(得分:0)

由于节点类可以包含任何值类型的属性,因此无论如何都需要进行未选中的强制转换。没有必要重载get函数,你可以强制转换为预期的返回类型

@SuppressWarnings("unchecked")
public <T> T get(String key) {
    return (T) properties.get(key).value;
}

示例:

Node node = new Node();
node.add("x", 123);
node.add("y", "ABC");
node.add("z", new Date());

int    valueX = node.get("x"); // cast to integer and autobox to int
String valueY = node.get("y"); // cast to String
Date   valueZ = node.get("z"); // cast to Date

String valueFail = node.get("z"); // this will throw a ClassCastException

答案 4 :(得分:0)

public class Node
{
    public static void main (String[] args)
    {
        Node node = new Node();
        node.addProperty("a", 12L);
        node.addProperty("b", "i'm a string");

        long number = node.getProperty("a");
        String string = node.getProperty("b");
    }

    private Map<String, Object> properties = new HashMap<>();

    public void addProperty(String key, Object value){
        this.properties.put(key, value);
    }

    public <T> T getProperty(String key){
        return (T) this.properties.get(key);
    }
}

答案 5 :(得分:0)

OP正在尝试处理不同对象的集合,因此泛型不是前进的方法。他要做的是对集合中的每个特定对象进行类型安全处理。以下是使用访客模式的方法。

// Implement this interface in something which needs to process
// an item from the collection in a way specific to the type of that item
interface Visitor {
    void visit(Circle c);
    void visit(Square s);
}

class Collection {
    Map<String, Shape> shapes = new HashMap<>();

    void add(String key, Shape shape) {
        shapes.put(key, shape);
    }


    // when you want to process what's behind a key, send in a visitor
    void visit(String key, Visitor visitor) {
        // ask the shape to be visited by the visitor
        shapes.get(key).visit(visitor);
    }
 }


 interface Shape { 
     void visit(Visitor visitor);
 }


 class Circle implements Shape {
     void visit(Visitor visitor) {
         // tells the visitor to treat this object as a circle
         visitor.visit(this);
     }
 }

假设您想要从集合中绘制特定形状的东西。

 class DrawingVisitor implements Visitor {
     void visit(Circle c) {
         // use properties only a circle has to draw it
         graphics2d.ellipse(c.getRadius(), c.getCenterPoint()); 
     }

     void visit(Square s) {
         graphics2d.rectangle(s.getTopLeft(), s.getBottomRight());
     }
 }

有意义吗?