1 使用JavaFX集合
本教程描述了JavaFX集合API,它是Java集合框架的扩展,提供了可以编译和运行的代码示例。
本教程首先简要回顾了Java集合框架中相关的类和接口,然后解释了JavaFX集合API如何扩展它们以提供额外的功能。有关Java集合的深入教程,请参阅Java教程的集合部分。
回顾Java集合基础知识
本节概述了java.util.List
和java.util.Map
接口以及java.util.Collections
类。如果您已经熟悉Java集合,请跳到下一节学习JavaFX集合。
List
List
是一个有序的对象集合,由java.util.List
接口表示。一个List
中的对象称为其元素,相同的元素可以存在于同一个List
中。List
接口定义了许多有用的方法,可以添加元素,访问或更改特定索引处的元素,创建子列表,在列表中搜索元素,清除列表等。
示例1-1使用List
的String
对象演示了这些方法:
示例1-1 使用List
package collectionsdemo; import java.util.List; import java.util.ArrayList; public class CollectionsDemo { public static void main(String[] args) { // 创建一个List。 System.out.println("创建List..."); List<String> list = new ArrayList<String>(); list.add("字符串一"); list.add("字符串二"); list.add("字符串三"); // 打印内容。 printElements(list); // 在索引0处设置一个新元素。 System.out.println("设置一个元素..."); list.set(0, "一个新的字符串"); printElements(list); // 搜索新添加的字符串。 System.out.println("搜索内容..."); System.out.print("包含\"一个新的字符串\"吗? "); System.out.println(list.contains("一个新的字符串")); System.out.println(""); // 创建一个子列表。 System.out.println("创建一个子列表..."); list = list.subList(1,3); printElements(list); // 清除所有元素。 System.out.println("清除所有元素..."); list.clear(); printElements(list); } private static void printElements(List<String> list) { System.out.println("大小: "+list.size()); for (Object o : list) { System.out.println(o.toString()); } System.out.println(""); } }
示例1-1的输出如下:
创建List...
大小: 3
字符串一
字符串二
字符串三
设置一个元素...
大小:3
一个新的字符串
字符串二
字符串三
正在搜索内容...
包含 "一个新的字符串"? true
创建子列表...
大小:2
字符串二
字符串三
清除所有元素...
大小:0
该程序首先实例化一个ArrayList
(List
接口的具体实现),并将其赋值给list
变量。接下来,通过调用其add
方法将三个String
对象添加到列表中。(在执行过程中的各个点上,程序通过调用一个名为printElements
的自定义private static
方法打印出元素。)list.set(0,"一个新的字符串")
这一行用一个新的String
对象替换了第一个索引位置上的原始String
对象。contains
方法报告指定的元素是否存在于List
中,sublist
方法返回由给定索引值范围指定的新List
。最后,clear
方法从List
中删除所有元素。
映射
Map
是将键映射到值的对象。一个Map
不能包含重复的键;每个键只能映射到一个值。您可以将键和值放入Map
中,然后通过传入其键来检索值。例如,键apple可能返回fruit,而carrot可能返回vegetable。
示例1-2使用String
对象的Map
演示了这些方法:
示例 1-2 使用 Map
package collectionsdemo; import java.util.Map; import java.util.HashMap; public class CollectionsDemo { public static void main(String[] args) { // 创建一个 Map。 Map<String,String> map = new HashMap<String,String>(); map.put("apple", "fruit"); map.put("carrot","vegetable"); System.out.println("大小: "+map.size()); System.out.println("是否为空? "+map.isEmpty()); // 传入键; 打印出值。 System.out.println("传入键并打印出值..."); System.out.println("键是 apple,值是: "+map.get("apple")); System.out.println("键是 carrot,值是: "+map.get("carrot")); System.out.println(""); // 检查键和值。 System.out.println("检查键和值:"); System.out.println("包含键 \"apple\"? "+ map.containsKey("apple")); System.out.println("包含键 \"carrot\"? "+ map.containsKey("carrot")); System.out.println("包含键 \"fruit\"? "+ map.containsKey("fruit")); System.out.println("包含键 \"vegetable\"? "+ map.containsKey("vegetable")); System.out.println("包含值 \"apple\"? "+ map.containsValue("apple")); System.out.println("包含值 \"carrot\"? "+ map.containsValue("carrot")); System.out.println("包含值 \"fruit\"? "+ map.containsValue("fruit")); System.out.println("包含值 \"vegetable\"? "+ map.containsValue("vegetable")); System.out.println(""); // 从 Map 中移除对象。 System.out.println("从 Map 中移除 apple..."); map.remove("apple"); System.out.println("大小: "+map.size()); System.out.println("包含键 \"apple\"? "+ map.containsKey("apple")); System.out.println("调用 map.clear()..."); map.clear(); System.out.println("大小: "+map.size()); } }
示例 1-2 的输出如下:
大小: 2
是否为空? false
传入键并打印出值...
键是 apple,值是: fruit
键是 carrot,值是: vegetable
检查键和值:
包含键 "apple"? true
包含键 "carrot"? true
包含键 "fruit"? false
包含键 "vegetable"? false
包含值 "apple"? false
包含值 "carrot"? false
包含值 "fruit"? true
包含值"vegetable"? true
从映射中移除apple...
大小: 1
包含键"apple"? false
调用map.clear()...
大小: 0
该程序首先实例化一个HashMap
(Map
接口的具体实现),并将其赋值给map
变量。然后通过调用put
方法向map
添加键值对。程序接着通过调用size()
和isEmpty()
获取(并打印出)有关映射的一些信息。程序还演示了如何根据给定的键获取值(例如,map.get("apple")
返回值fruit)。containsKey
和containsValue
方法演示了如何测试特定的键或值是否存在,clear
方法则移除所有的键值映射。
集合
除了List
和Map
中的方法外,Collections
类还提供了一些静态实用方法,用于操作或返回集合。 示例 1-3通过创建一个List
,然后使用Collections
类来反转、交换和排序其元素来演示了一些这样的方法。
示例 1-3 使用 Collections 类
package collectionsdemo; import java.util.List; import java.util.ArrayList; import java.util.Collections; public class CollectionsDemo { public static void main(String[] args) { System.out.println("创建列表..."); List<String> list = new ArrayList<String>(); list.add("a"); list.add("b"); list.add("c"); list.add("d"); printElements(list); System.out.println("反转元素..."); Collections.reverse(list); printElements(list); System.out.println("交换元素位置..."); Collections.swap(list, 0, 3); Collections.swap(list, 2, 0); printElements(list); System.out.println("按字母顺序排序元素..."); Collections.sort(list); printElements(list); } private static void printElements(List<String> list) { for (Object o : list) { System.out.println(o.toString()); } } }
示例 1-3的输出如下:
创建列表...
a
b
c
d
反转元素...
d
c
b
a
交换元素...
b
c
a
d
按字母顺序排序元素...
a
b
c
d
该程序首先将字母a b c和d添加到一个List
中,再次使用ArrayList
作为具体实现。然后,通过调用Collections.reverse(list)
来反转列表的元素。要在List
中交换元素,程序调用Collections.swap
方法(例如,Collections.swap(list,0,3)
会交换索引位置0和3的元素。最后,Collections.sort()
方法按字母顺序对元素进行排序。
在回顾了Java Collections Framework的最相关部分后,现在可以学习JavaFX中如何表示集合。
在示例1-4中,首先创建了一个标准的List
,然后将其包装在一个ObservableList
中,通过将列表传递给FXCollections.observableList(list)
来获取。然后注册了一个ListChangeListener
,当ObservableList
发生变化时将收到通知。
您可以以类似的方式监听ObservableMap
的变化,如示例1-5所示。
示例1-5 使用ObservableMap
package collectionsdemo; import java.util.Map; import java.util.HashMap; import javafx.collections.ObservableMap; import javafx.collections.MapChangeListener; import javafx.collections.FXCollections; public class CollectionsDemo { public static void main(String[] args) { // 使用Java集合创建列表。 Map<String,String> map = new HashMap<String,String>(); // 通过将其包装在ObservableList中来添加可观察性。 ObservableMap<String,String> observableMap = FXCollections.observableMap(map); observableMap.addListener(new MapChangeListener() { @Override public void onChanged(MapChangeListener.Change change) { System.out.println("检测到变化! "); } }); // 对observableMap的更改将被报告。 observableMap.put("key 1","value 1"); System.out.println("大小: "+observableMap.size()); // 对底层map的更改将不会被报告。 map.put("key 2","value 2"); System.out.println("大小: "+observableMap.size()); } }
最后,您可以使用Collections
或FXCollections
的静态实用方法(例如,反转列表的元素)。但请记住,当调用其方法时,FXCollections
类将产生最少数量的更改通知(通常为一个)。另一方面,调用Collections
方法可能会导致多个更改通知,如示例1-6所示。
示例1-6 Collections Vs. FXCollections 更改通知
package collectionsdemo; import java.util.List; import java.util.ArrayList; import javafx.collections.ObservableList; import javafx.collections.ListChangeListener; import javafx.collections.FXCollections; public class CollectionsDemo { public static void main(String[] args) { // 使用Java集合创建列表 List<String> list = new ArrayList<String>(); list.add("d"); list.add("b"); list.add("a"); list.add("c"); // 通过将其包装在ObservableList中来添加可观察性 ObservableList<String> observableList = FXCollections.observableList(list); observableList.addListener(new ListChangeListener() { @Override public void onChanged(ListChangeListener.Change change) { System.out.println("检测到变化! "); } }); // 使用FXCollections进行排序 FXCollections.sort(observableList); } }
在示例1-6中,代码FXCollections.sort(obervableList)
按字母顺序对列表中的String
对象进行排序,并只向屏幕打印一次更改通知;但是如果使用Collections.sort(observableList)
,更改通知将打印四次。
当使用ListChangeListener
或MapChangeListener
时,onChanged
方法总是包含一个封装有关更改信息的对象。这是ListChangeListener.Change
(对于ObservableList
)或MapChangeListener.Change
(对于ObservableMap
)的实例。在使用ListChangeListener.Change
时,始终将对更改对象的任何调用包装在调用change.next()
的循环中。 示例1-7提供了一个演示。
示例1-7 查询ListChangeListener.Change对象
... // 这段代码适用于之前的任何ObservableList示例 observableList.addListener(new ListChangeListener() { @Override public void onChanged(ListChangeListener.Change change) { System.out.println("检测到更改! "); while (change.next()) { System.out.println("是否添加? " + change.wasAdded()); System.out.println("是否移除? " + change.wasRemoved()); System.out.println("是否替换? " + change.wasReplaced()); System.out.println("是否置换? " + change.wasPermutated()); } } }); ...
示例1-7在ListChangeListener.Change
对象上调用各种方法。最重要的是要记住,ListChangeListener.Change
对象可以包含多个更改,因此必须通过在while
循环中调用其next()
方法进行迭代。但是请注意,MapChangeListener.Change
对象只包含表示执行的put
或remove
操作的更改。
有关可用方法的信息,请参阅ListChangeListener.Change和MapChangeListener.Change
API文档。