Javafx 将所有已注册的侦听器设置为ObservalEvalue

Javafx 将所有已注册的侦听器设置为ObservalEvalue,javafx,Javafx,如何使所有侦听器都达到一个可观察的值?我可以扩展这个类并重写addListener和removeListener方法来将它们存储在一个集合中。但集合应该已经以某种方式存储在可观察值中。我怎样才能得到这个集合呢?我找到了一种解决方法,你无法直接访问侦听器列表,但是如果你使用调试器(我使用IntelliJ),你可以看到它,如果你像下面这样查看你的ObservableProperty:(我希望这足够清楚) 另一种方式:(你是个聪明人,你会知道如何适应你的情况) 结果是: (注意1个或多个侦听器之间

如何使所有侦听器都达到一个可观察的值?我可以扩展这个类并重写
addListener
removeListener
方法来将它们存储在一个集合中。但集合应该已经以某种方式存储在可观察值中。我怎样才能得到这个集合呢?

我找到了一种解决方法,你无法直接访问侦听器列表,但是如果你使用调试器(我使用IntelliJ),你可以看到它,如果你像下面这样查看你的ObservableProperty:(我希望这足够清楚)

另一种方式:(你是个聪明人,你会知道如何适应你的情况)

结果是:

(注意1个或多个侦听器之间的差异)

我正在为几种类型的值添加示例

public static ChangeListener[] getChangeListeners(ObservableValue observableValue){

    Object value;
    ChangeListener[] list=null;
    ChangeListener changeListener=null;
    Field field = null;

    try {
        if(observableValue instanceof SimpleFloatProperty ){
            field = FloatPropertyBase.class.getDeclaredField("helper");
        }
        else if(observableValue instanceof SimpleBooleanProperty ){
            field = BooleanPropertyBase.class.getDeclaredField("helper");
        }
        else if(observableValue instanceof SimpleIntegerProperty ){
            field = IntegerPropertyBase.class.getDeclaredField("helper");
        }
        field.setAccessible(true);
        value = field.get(observableValue);
        try {
            field = value.getClass().getDeclaredField("listener");
            field.setAccessible(true);
            changeListener =(ChangeListener)field.get(value);
        }catch (NoSuchFieldException e) {
            //e.printStackTrace();
        }
        try {
            field = value.getClass().getDeclaredField("changeListeners");
            field.setAccessible(true);
            list =(ChangeListener[])field.get(value);
        }catch (NoSuchFieldException e) {
            //e.printStackTrace();
        }
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    if(list!=null){
        return list;
    }
    else {
        ChangeListener[] changeListeners = new  ChangeListener[1];
        changeListeners[0]=changeListener;
        return changeListeners;
    }
}
我称之为:

    SimpleBooleanProperty booleanProperty = new SimpleBooleanProperty(true);
    SimpleFloatProperty simpleFloatProperty = new SimpleFloatProperty(0);
    SimpleIntegerProperty simpleIntegerProperty = new SimpleIntegerProperty(1);
    booleanProperty.addListener(changeListener);
    simpleFloatProperty.addListener(changeListener);
    simpleIntegerProperty.addListener(changeListener);
    simpleIntegerProperty.addListener(changeListener);
    System.out.println(getChangeListeners(booleanProperty).length);
    System.out.println(getChangeListeners(simpleFloatProperty).length);
    System.out.println(getChangeListeners(simpleIntegerProperty).length);
结果是:


所以我确实收到了警告,但工作已经完成了

可观察值removeListener的文档说明:

如果给定的侦听器以前没有注册过(即从未添加过),则此方法调用是不可操作的

如果要避免反射,这就留下了一些选择

首先,在添加侦听器之前调用
removeListener
,例如:

final var property = someProperty();
final var listener = getListener();
property.removeListener( listener );
property.addListener( listener );
如果
getListener()
始终返回相同的对象引用,则此技术相当于使用
Set
。(如果同一类的不同对象引用重写
equals
以返回
true
,这也可能会起作用,但您必须仔细检查。)

缺点是必须保留对已添加侦听器的引用,这可能需要一个新类,但至少需要一个新实例变量

第二,保存一张注册听众的地图,大意是:

final HashMap<ObservableValue<?>, Object> map = new HashMap<>();
final var property = someProperty();
final var listener = getListener();
map.computeIfAbsent( property, p -> {
  property.addListener( listener );
  return property;
});

final hashmap这些方法是在
observeValue
接口中声明的,该接口不提供任何方法来查找添加的侦听器(它甚至不会返回一个布尔值来告诉您是否实际删除了某个观察者)。我很确定这是故意的(信息隐藏;如果你能得到所有侦听器的
集,你也可以删除它们…)。也许您很幸运,属性类扩展了
XYZPropertyBase
,您可以使用反射来强制访问侦听器,但这样您就做了API不想做的事情……期待已久的java 9发行版,它提供了对javafx内部构件problematicfield=value.getClass().getDeclaredField的拼图访问(“listener”);Is可以帮助解决这个问题:)我不能导入它,但我可以在获取它的对象后使用getClass(我使用java 9处理此代码)我编辑了我的答案以添加更多的ObservalEvalue,它不能直接与ObservalEvalue接口一起工作,但您可以根据需要添加值…@ayvango想知道为什么您要访问侦听器…您不应该关心它们;)对我来说,这有助于识别由于忘记指针或更糟糕的隐藏阶段而导致的非GC事件问题它的指针设置为null,但它的寄存器事件仍然发生(尽管我使用了弱侦听器),尽可能地保留添加的侦听器的存储(仅通过自定义应用程序的代码!-所有其他侦听器都不可访问)正在淘汰系统的每一次尝试,以使它们尽可能不受干扰(f.i.如果gc可省略,则删除它们——无可否认,有许多漏洞;)真正的问题是仔细研究不可访问方希望访问听众的原因……而不是这样做:)
final HashMap<ObservableValue<?>, Object> map = new HashMap<>();
final var property = someProperty();
final var listener = getListener();
map.computeIfAbsent( property, p -> {
  property.addListener( listener );
  return property;
});