通用对象的集合。自动铸造?隐藏铸造?
Collection of Generic Objects. Auto-Casting? Hidden Casting?
我正在尝试以下列方式保存节点属性(这可能本身就是错误的):
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 的本质有一些基本的误解。
试试这个
// 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));
}
}
到目前为止,我对您的示例感到担忧的是 "Node" 看起来很像散列图条目。更好的问题是 "what are you REALLY trying to do"?
A given key must correspond to a given type, both for adding and for getting.
假设您的意思是 String key
是元素 及其类型 的标识符,那么您就不走运了,这对泛型来说根本不可能。一种选择是为每个已知 属性.
定义一个具有适当类型 field/getters 的自定义 class
如果你的意思是 x
参数,那么你可以使用泛型来做类似
public <T> T get(String key, T x) {
return (T) properties.get(key).value;
}
但这会让你为各种 ClassCastException
做好准备。您的编译器应该对此发出警告。 (另请注意,您将无法直接使用原始类型。)
可以为此编写一个外部类型安全的实现,尽管它需要一些编译器无法证明正确的内部转换。
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);
}
}
...就是说,如果您事先知道整组键,您可以(并且应该)使用适当键入的字段进行自定义 class,而不是试图将整个内容压缩到类似地图的结构。
由于节点 class 可以保存任何值类型的属性,因此您无论如何都需要进行 unchecked cast。无需重载 get
函数,您可以 转换为任何预期的 return 类型 :
@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
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);
}
}
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());
}
}
等等
有道理吗?
我正在尝试以下列方式保存节点属性(这可能本身就是错误的):
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 的本质有一些基本的误解。
试试这个
// 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));
}
}
到目前为止,我对您的示例感到担忧的是 "Node" 看起来很像散列图条目。更好的问题是 "what are you REALLY trying to do"?
A given key must correspond to a given type, both for adding and for getting.
假设您的意思是 String key
是元素 及其类型 的标识符,那么您就不走运了,这对泛型来说根本不可能。一种选择是为每个已知 属性.
如果你的意思是 x
参数,那么你可以使用泛型来做类似
public <T> T get(String key, T x) {
return (T) properties.get(key).value;
}
但这会让你为各种 ClassCastException
做好准备。您的编译器应该对此发出警告。 (另请注意,您将无法直接使用原始类型。)
可以为此编写一个外部类型安全的实现,尽管它需要一些编译器无法证明正确的内部转换。
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);
}
}
...就是说,如果您事先知道整组键,您可以(并且应该)使用适当键入的字段进行自定义 class,而不是试图将整个内容压缩到类似地图的结构。
由于节点 class 可以保存任何值类型的属性,因此您无论如何都需要进行 unchecked cast。无需重载 get
函数,您可以 转换为任何预期的 return 类型 :
@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
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);
}
}
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());
}
}
等等
有道理吗?