Java 无法在映射中设置泛型属性的值
我试图在映射中设置属性的值,但出现以下错误:Java 无法在映射中设置泛型属性的值,java,javafx,Java,Javafx,我试图在映射中设置属性的值,但出现以下错误: The method setValue(capture#7-of ?) in the type WritableValue<capture#7-of ?> is not applicable for the arguments (capture#8-of ?) 我可以在没有地图的情况下进一步简化: Property<?> p1 = new SimpleIntegerProperty(5); Property<?>
The method setValue(capture#7-of ?) in the type WritableValue<capture#7-of ?> is not applicable for the arguments (capture#8-of ?)
我可以在没有地图的情况下进一步简化:
Property<?> p1 = new SimpleIntegerProperty(5);
Property<?> p2 = new SimpleIntegerProperty(10);
p1.setValue(p2.getValue());//Same (basic) error
p1.setValue(new Object());//Same (basic) error
Property p1=新的SimpleIntegerProperty(5);
属性p2=新的SimpleIntegerProperty(10);
p1.setValue(p2.getValue())//相同(基本)错误
p1.设置值(新对象())//相同(基本)错误
我正在使用Java 1.8 JDK如果您希望继续使用以下类型,请尝试以下操作:
IntegerProperty p1 = new SimpleIntegerProperty(5);
IntegerProperty p2 = new SimpleIntegerProperty(10);
p1.setValue(p2.getValue());
或该类型没有安全性:
Property p1 = new SimpleIntegerProperty(5);
Property p2 = new SimpleIntegerProperty(10);
p1.setValue(p2.getValue());
一,。E删除通配符。这不是JavaFX问题,这是泛型问题。一旦有了通配符类型,
setValue
方法就有了类型T
。。。您还没有指定。换句话说,这是不好的:
Property<?> p1 = new SimpleIntegerProperty(5);
Property<?> p2 = new SimpleIntegerProperty(10);
p1.setValue(p2.getValue());
使
Property
成为一个接口,并具有SimpleIntegerProperty
和SimpleStringProperty
实现Property
。然后您将有一个HashMap
问题是您尝试执行的操作本质上是不安全的。从编程逻辑中,您可能知道与map1
中的“key1”
关联的属性类型与map2
中的“key1”
关联的属性类型相同,但编译器不可能保证这一事实。因此,对于当前的结构,您唯一的选择就是放弃编译时安全性
这里的根本问题是Map
为您的需求提供了错误的API(即使它的基本功能是您所需要的)Map
是一个同质容器,这意味着给定Map中的所有值都是同一类型的。这是由API强制执行的:public V get(K键)代码>和<代码>公开作废(K键,V值)代码>始终使用相同的类型V
,这对于任何单个Map
实例都是固定的。您真正想要的是一个异构容器,其中的值根据键的不同而变化。因此,您需要一个API,其中容器实例的V
不是固定的,而是根据键的值对方法get
和put
的每次调用进行更改。因此,您需要一些get
和put
方法是通用方法的东西:
public interface Container<K> { // K is the type of the key...
public <V> V get(K key) ;
public <V> void put(K key, V value);
}
现在定义一个容器类作为映射。这里的基本思想是有两种方法:
public <T> void put(TypedKey<T, K> key, Property<T> property)
public <T> Property<T> get(TypedKey<T, K> key)
请注意,很难将其变成ObservableMap
,原因与引言中概述的相同:ObservableMap
接口定义了同质方法(实际上是从Map
接口继承的),而您无法以满足需求的方式实现这些方法。但是,您可以轻松地使此实现javafx.beans.Observable
,这将允许您使用它注册invalizationlistener
s,并在绑定中使用它:
public class TypedPropertyMap<K> implements Observable {
private final ObservableMap<TypedKey<?, K>, Property<?>> map = FXCollections.observableHashMap();
@Override
public void addListener(InvalidationListener listener) {
map.addListener(listener);
}
@Override
public void removeListener(InvalidationListener listener) {
map.removeListener(listener);
}
// remaining code as before...
}
公共类TypedPropertyMap实现了可观察的{
私有最终ObservaleMap>map=FXCollections.Observalehashmap();
@凌驾
public void addListener(invalizationListener侦听器){
addListener(监听器);
}
@凌驾
公共void RemovelListener(InvalizationListener侦听器){
map.removeListener(监听器);
}
//剩下的代码和以前一样。。。
}
您使用的是什么版本的Java?您试图实现什么样的功能?你为什么混血?地图的数据来自哪里?我需要能够在地图中包含多个属性类型。不幸的是,这在我的情况下不起作用。然后Eclipse黄色在它下面加下划线,说我需要一个类型。我知道我可以做@SuppressWarnings,但我希望有更好的方法,我从来没有使用过这些,现在不想开始。你在没有类型安全的情况下工作,你期望什么?这是我不想做的,我希望它是类型安全的。然后你需要指定一个类型。地图的键是什么类型的,值是什么类型的?您不能像示例中那样混合整数和字符串,并且必须是类型安全的。这是不可能的。我不确定这是否有效,因为Property
、SimpleIntegerProperty
和SimpleStringProperty
都是内置类。哦,我以前没有使用过JavaFX,所以我没有意识到。然后,要么使用一个HashMap
并使用强制类型转换,要么使用单独的HashMap
s。我还必须指出,我正在使用JavaFX的FXCollections
生成我的一个映射,所以我认为我无法生成TypedPropertyMap
。也许在声明observeMap
时,我仍然可以使用TypedKey
而不是String
?我需要考虑一下。制作TypedPropertyMap
实现javafx.beans.Observable
,非常容易,但是我看不出有什么办法可以让它实现javafx.collections.ObservableMap
。你的实际需求是什么?如果它实现了Observable
并另外定义了addListener(mapchangeStener)
和removeListener(mapchangeStener)
方法,但没有实现ObservableMap
,那会起作用吗?即使这样,您也可能无法在Change
事件上获得完整的类型安全性代码>。我不知道为什么要使用FXCollections
。我不认为它被用在任何视图或任何东西中。我想我可以在这种情况下使用TypedPropertyMap
。我想问题是:您是将侦听器附加到它还是绑定到它,代码中的任何位置?查看我的代码,我想我不需要侦听映射中的更改,只需侦听映射中的属性。我想TypedPropertyMap
可以正常工作。TypedPropertyMap
是否应包含内部Map
或扩展Map
?沃
Property<?> mapProperty = map2.get("key1");
if(mapProperty instanceof IntegerProperty) {
((IntegerProperty) mapProperty).setValue((Integer) map1.get("key1").getValue());
} else {
// handle the error
}
public interface Container<K> { // K is the type of the key...
public <V> V get(K key) ;
public <V> void put(K key, V value);
}
/**
* @param <T> The type associated with this key
* @param <K> The actual type of the key itself
*/
public class TypedKey<T, K> {
private final Class<T> type ;
private final K key ;
public TypedKey(Class<T> type, K key) {
if (type == null || key == null) {
throw new NullPointerException("type and key must be non-null");
}
this.type = type ;
this.key = key ;
}
@Override
public boolean equals(Object o) {
if (o == null) return false ;
if (! (o instanceof TypedKey)) {
return false ;
}
TypedKey<?, ?> other = (TypedKey<?, ?>) o ;
return other.type.equals(type) && other.key.equals(key);
}
@Override
public int hashCode() {
return Objects.hash(type, key);
}
}
// String key to map to Property<Number>:
TypedKey<Number, String> key1 = new TypedKey<>(Number.class, "key1");
// String key to map to Property<String>:
TypedKey<String, String> key2 = new TypedKey<>(String.class, "key2");
public <T> void put(TypedKey<T, K> key, Property<T> property)
public <T> Property<T> get(TypedKey<T, K> key)
/**
* @param <K> The type of the key in the TypedKey
*/
public class TypedPropertyMap<K> {
private final Map<TypedKey<?, K>, Property<?>> map = new HashMap<>();
public <T> void put(TypedKey<T, K> key, Property<T> property) {
map.put(key, property);
}
@SuppressWarnings("unchecked")
public <T> Property<T> get(TypedKey<T, K> key) {
// by virtue of the API we defined, the property associated with
// key must be a Property<T> (even though the underlying map does not know it):
return (Property<T>) map.get(key);
}
}
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
public class TypedPropertyMapTest {
public static void main(String[] args) {
TypedPropertyMap<String> map1 = new TypedPropertyMap<>();
TypedPropertyMap<String> map2 = new TypedPropertyMap<>();
TypedKey<Number, String> key1 = new TypedKey<>(Number.class, "key1");
TypedKey<String, String> key2 = new TypedKey<>(String.class, "key2");
map1.put(key1, new SimpleIntegerProperty(5));
map1.put(key2, new SimpleStringProperty("hi"));
map2.put(key1, new SimpleIntegerProperty());
map2.put(key2, new SimpleStringProperty());
map2.get(key1).setValue(map1.get(key1).getValue());
map2.get(key2).setValue(map1.get(key2).getValue());
System.out.println(map2.get(key1).getValue());
System.out.println(map2.get(key2).getValue());
}
/**
* @param <T> The type associated with this key
* @param <K> The actual type of the key itself
*/
public static class TypedKey<T, K> {
private final Class<T> type ;
private final K key ;
public TypedKey(Class<T> type, K key) {
if (type == null || key == null) {
throw new NullPointerException("type and key must be non-null");
}
this.type = type ;
this.key = key ;
}
@Override
public boolean equals(Object o) {
if (o == null) return false ;
if (! (o instanceof TypedKey)) {
return false ;
}
TypedKey<?, ?> other = (TypedKey<?, ?>) o ;
return other.type.equals(type) && other.key.equals(key);
}
@Override
public int hashCode() {
return Objects.hash(type, key);
}
}
/**
* @param <K> The type of the key in the TypedKey
*/
public static class TypedPropertyMap<K> {
private final Map<TypedKey<?, K>, Property<?>> map = new HashMap<>();
public <T> void put(TypedKey<T, K> key, Property<T> property) {
map.put(key, property);
}
@SuppressWarnings("unchecked")
public <T> Property<T> get(TypedKey<T, K> key) {
// by virtue of the API we defined, the property associated with
// key must be a Property<T> (even though the underlying map does not know it):
return (Property<T>) map.get(key);
}
}
}
public class TypedPropertyMap<K> implements Observable {
private final ObservableMap<TypedKey<?, K>, Property<?>> map = FXCollections.observableHashMap();
@Override
public void addListener(InvalidationListener listener) {
map.addListener(listener);
}
@Override
public void removeListener(InvalidationListener listener) {
map.removeListener(listener);
}
// remaining code as before...
}