我试图以下列方式保存节点属性(这可能本质上是错误的):
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的本质。
答案 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());
}
}
等
有意义吗?