JavaFX的世界中, Properties API允许UI开发人员将值绑定到UI控件。 这种功能非常容易,但是当对象模型经常使用属性时,应用程序可能会很快耗尽内存。 我通常会编写两个单独的对象,例如pojo类和表示模型对象。 此技术通常在基于Swing的应用程序中使用。 从JavaFX角度来看,您可以只创建一个具有属性的对象,以允许观察者(侦听器)更新值。 听起来不错吧? 不完全是因为主要问题是当所有对象的(pojo)属性(字段)都是还包装实际值的属性时,程序员(api的用户)可能根本不想绑定或使用属性,而只想访问实际值。 那么,JavaFX开发人员该做什么?

一个TreeTable控件持有雇员。

我经常访问Dirk Lemmermann的博客Pixel Perfect ,该博客经常发布非常有用的JavaFX技巧。 最近,Dirk在博客上发表了一篇关于如何使用一种有趣的模式“ Shadow Fields ”来节省内存的博客。 要查看他的帖子,请访问他的博客条目JavaFX Tip 23:节省内存! 属性的阴影字段。 。 Dirk的JavaFX技巧确实有助于解决上述问题(减少堆),但是我注意到必须存在样板代码才能( 聪明地 确定 )为调用者提供返回值是实际对象还是属性包装器对象。 例如,该代码将返回intInteger值,而不是在调用getset方法时返回IntegerProperty对象,从而节省了内存。 此外,代码声明了两个变量来保存两种值类型之一。 例如:

private String _title = "Untitled"; // shadow field
private StringProperty title;

我觉得我可以使事情更简洁,并可能节省更多的内存。 并减少样板代码。 我决定使用Java 8的默认方法创建一个接口,该接口将处理管理实际值和属性。 API的用户将只创建一个实现以下接口的域类:

界面属性访问器

一个提供访问器方法的接口,以提供对实际对象值或JavaFX属性包装器对象的智能确定。 API的用户必须实现一种称为getModelProperties()的方法,该方法返回属性名(字符串)和值(对象)的映射。 该值可以是实际对象或属性类型对象。 下面的代码也将支持可观察列表。

package com.jfxbe;import javafx.beans.property.Property;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;/*** Provide default methods to support the similar* capability of the shadow fields pattern.* To save memory object values don't have to be* wrapped into a Property object when using getters* and setters, however when calling property type methods* values will be wrapped into a property object.** Default methods for Observable lists are provided too.** Created by cpdea on 4/3/16.*/
public interface PropertyAccessors {Map<String, Object> getModelProperties();default <T> T getValue(String name, Object defaultVal) {Object p = getModelProperties().get(name);p = p==null ? defaultVal : p;return (T) ((p instanceof Property) ? ((Property) p).getValue(): p);}default void setValue(String name, Object value) {Object p = getModelProperties().get(name);if (p instanceof Property) {((Property)p).setValue(value);} else {getModelProperties().put(name, value);}}default <T> T refProperty(String name, Class propClass, Class rawValType) {Object p = getModelProperties().get(name);Property prop = null;try {if (p == null) {Class[] constructorTypes =new Class[]{Object.class, String.class};Constructor<Property> propConstr =propClass.getDeclaredConstructor(constructorTypes);prop = propConstr.newInstance(this, name);} else if (rawValType.isInstance(p)) {Class[] constructorTypes = new Class[]{Object.class,String.class, rawValType};Constructor<Property> propConstr =propClass.getDeclaredConstructor(constructorTypes);prop = propConstr.newInstance(this, name, p);} else {prop = (Property) p;}getModelProperties().put(name, prop);} catch (Exception e) {e.printStackTrace();}return (T) prop;}default <T> List<T> getValues(String name, List<T> defaultValue) {Object p, o = getModelProperties().get(name);p = o;o = o==null ? defaultValue : o;if (!o.equals(p)) {getModelProperties().put(name, o);}return  (List<T>) o;}default <T> void setValues(String name, List<T> newList) {Object list = getModelProperties().get(name);if (list == null || !(list instanceof ObservableList)) {getModelProperties().put(name, newList);} else {// Should the list be totally replaced? below clears and adds all itemsObservableList<T> observableList = (ObservableList<T>) list;observableList.clear();observableList.addAll(newList);}}default <T> ObservableList<T> refObservables(String name) {List list = (List) getModelProperties().get(name);if (list == null) {list = FXCollections.observableArrayList(getValues(name, new ArrayList<>()));getModelProperties().put(name, list);}if (! (list instanceof ObservableList)) {list = FXCollections.observableArrayList(list);getModelProperties().put(name, list);}return (ObservableList<T>) list;}
}

员工阶层

一个名为Employee的类,它实现PropertyAccessor接口。 在下面,您会注意到每个字段的属性名称都是使用public static final String声明的 。 例如,员工的名字是:

public static final String NAME_PROPERTY = “name”;

对于诸如getter,setter和xyzProperty()之类的访问器方法,您会在PropertyAccessor接口中注意到对默认方法的调用。

package com.jfxbe;import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** A hybrid domain and model object using the shadow field pattern to save memory.* Created by cpdea*/
public class Employee implements PropertyAccessors{/** This is a map to hold properties and observables */private Map<String, Object> modelProperties;public static final String NAME_PROPERTY = "name";public static final String POWERS_PROPERTY = "powers";public static final String SUPERVISOR_PROPERTY = "supervisor";public static final String MINIONS_PROPERTY = "minions";public Employee(String name, String powers) {setName(name);setPowers(powers);}@Overridepublic Map<String, Object> getModelProperties() {if (modelProperties == null) {modelProperties = new HashMap<>();}return modelProperties;}public final String getName() {return getValue(NAME_PROPERTY, "");}public final void setName(String name) {setValue(NAME_PROPERTY, name);}public final StringProperty nameProperty() {return refProperty(NAME_PROPERTY, SimpleStringProperty.class, String.class);}public String getPowers() {return getValue(POWERS_PROPERTY, "");}public final StringProperty powersProperty() {return refProperty(POWERS_PROPERTY, StringProperty.class, String.class);}public final void setPowers(String powers) {setValue(POWERS_PROPERTY, powers);}public final Employee getSupervisor() {return getValue(SUPERVISOR_PROPERTY, null);}public final ObjectProperty<Employee> supervisorProperty() {return refProperty(SUPERVISOR_PROPERTY, ObjectProperty.class, Employee.class);}public final void setSupervisor(Employee supervisor) {setValue(SUPERVISOR_PROPERTY, supervisor);}public final List<Employee> getMinions() {return getValues(MINIONS_PROPERTY, new ArrayList<>());}public final ObservableList<Employee> minionsObservables() {return refObservables(MINIONS_PROPERTY);}public final void setMinions(List<Employee> minions) {setValues(MINIONS_PROPERTY, minions);}}

结论

因此,您已找到解决方案,尝试消除两个变量和其他样板代码。 我实际上并没有使用大量数据来测试代码,因此也许在另一篇文章中或某个幸运的读者会创建一个测试,将所有三个(对象具有所有属性,Dirk和mine的)实现进行比较。

与RMI服务器一起使用时,此方法的可能缺点可能是序列化对象。 我敢肯定还有其他可能的缺点,但是对于大多数用例而言,这可能更容易处理和更简洁。

请随意发表评论!

参考文献

  • https://dlemmermann.wordpress.com
  • https://docs.oracle.com/javase/8/javafx/api/javafx/beans/property/Property.html
  • http://blog.netopyr.com/2011/05/13/javafx-properties/
  • https://projectlombok.org
  • http://www.jgoodies.com/freeware/libraries/binding

翻译自: https://www.javacodegeeks.com/2016/04/javafx-tips-save-memory-shadow-fields-properties-observables.html

JavaFX技巧来节省内存! 属性和可观察物的阴影场相关推荐

  1. javafx阴影_JavaFX技巧来节省内存! 属性和可观察对象的阴影场

    javafx阴影 在 JavaFX的世界中, Properties API允许UI开发人员将值绑定到UI控件. 这种功能出奇的简单,但是当对象模型经常使用属性时,应用程序可能会很快耗尽内存. 我通常会 ...

  2. JavaFX技巧5:可观察

    即使在整个NSA监视的这段时间,实现JavaFX控件时也要牢记可观察性,这仍然是一个好主意. 与Swing相比,这在JavaFX中很容易实现. 旧时光 来自Swing,我习惯于花费大量精力和时间来使自 ...

  3. 节省内存的嵌入式软件设计技巧

    现在新买的安卓千元机都是2G内存的了,我们还要绞尽脑汁地省内存?是的,那是高端处理器的特色,咱们这里讲的是资源紧缺型的嵌入式系统设计方法.一般主控是单片机控制器的电子产品的成本跟内存的关系可是成正比的 ...

  4. python类与对象-如何为创建大量实例节省内存

    如何为创建大量实例节省内存 问题举例 在网络游戏中,定义玩家类Player(id, name, level...), 每个玩家在线将创建一个Player实例,当在线人数很多时,将产生大量实例, 如何降 ...

  5. 2.6.29的一个节省内存的补丁

    今天看linux内核的maillist,发现了一个很有创意的补丁,叫做ksm,也就是kernel shared memory driver,读了之后感觉太有创意了,可是不知道到底有没有实际用处.这个补 ...

  6. 牺牲速度来节省内存,Redis是觉得自己太快了吗?

    来源:cnblogs.com/lonely-wolf/p/14281136.html 前言 正常情况下我们选择使用 Redis 就是为了提升查询速度,然而让人意外的是,Redis 当中却有一种比较有意 ...

  7. 【MCU】一种单片机节省内存的方法(补充)

    1.聊一聊 以前听这首曲子内心会变得格外平静,然而现在却五味陈杂! 今天主要跟大家分享一个MCU省内存的办法,同时也欢迎大家在文末问答留言讨论. 2.读前必备 对于MCU节省内存办法大合集bug菌在很 ...

  8. java 内存_java节省内存的几条建议

    java节省内存的几条建议 引导语:Java的主要工作是通过编程语言来制作互联网页面.制作动态效果以及网站等技术,以下是小编整理的java节省内存的几条建议,欢迎参考阅读! 1. 尽量在合适的场合使用 ...

  9. 2020-12-11 keras通过model.fit_generator训练模型(节省内存)

    keras通过model.fit_generator训练模型(节省内存) 前言 前段时间在训练模型的时候,发现当训练集的数量过大,并且输入的图片维度过大时,很容易就超内存了,举个简单例子,如果我们有2 ...

最新文章

  1. 2018-3-19科学网--贾琳老师《思维力量》笔记摘选(触动自己)
  2. BZOJ——1202: [HNOI2005]狡猾的商人
  3. 基于BCH的一些落地应用现状
  4. LINUX设备驱动之设备模型一--kobject
  5. boost::undirected_dfs用法的测试程序
  6. mysql strtok,strtok()和strtok_r()
  7. hadoop遇到的问题及处理
  8. mimo雷达信号处理_雷达学术入门脉冲雷达信号处理概述
  9. ORA-06502: PL/SQL: numeric or value error: character to number conversion error 错误的解决方法...
  10. JavaSE基础-02-接口
  11. 符号_液压图形符号识别之流量控制阀符号原理
  12. office设置保护色
  13. 【杂谈】MacPro 2015款拆机清灰换导热硅脂实录
  14. 【机器学习】网络表征学习、网络嵌入必读论文
  15. 燕东微通过注册:预计年营收超20亿 亦庄国投与京东方是股东
  16. 快手往事:得老铁者,失天下
  17. Android发展历程
  18. 微博内容导购平台,淘宝客的梦可以继续做了
  19. Logstash同步数据
  20. WinSCP登陆服务器提示收到了太大的SFTP包 支持的最大包大小1024000B

热门文章

  1. 关于人脸识别最近浏览器打不开摄像头的解决方案
  2. 使用ueditor实现多图片上传案例——Service层(IShoppingService)
  3. Tomacat乱码解决
  4. Springboot+MyBatis-plus+postgresSQL 的整合
  5. 小米miui系统已停止服务器,小米两款机型停止 MIUI 更新,明天发布最终体验版固件...
  6. python测试开发面试题_python测试开发面试之深浅拷贝
  7. 如何实现下拉框的绑定
  8. aws上负载均衡器标组端口_AWS CloudFormation:目标组没有关联的负载均衡器
  9. payara 创建 集群_在Payara Server和GlassFish中配置密码
  10. spring 导出csv_Spring批处理CSV处理