文档



JavaFX:使用JavaFX Collections
1 使用JavaFX集合(发布版8)

1 使用JavaFX集合

本教程描述了JavaFX集合API,它是Java集合框架的扩展,提供了可以编译和运行的代码示例。

本教程首先简要回顾了Java集合框架中相关的类和接口,然后解释了JavaFX集合API如何扩展它们以提供额外的功能。有关Java集合的深入教程,请参阅Java教程的集合部分

回顾Java集合基础知识

本节概述了java.util.Listjava.util.Map接口以及java.util.Collections类。如果您已经熟悉Java集合,请跳到下一节学习JavaFX集合

List

List是一个有序的对象集合,由java.util.List接口表示。一个List中的对象称为其元素,相同的元素可以存在于同一个List中。List接口定义了许多有用的方法,可以添加元素,访问或更改特定索引处的元素,创建子列表,在列表中搜索元素,清除列表等。

示例1-1使用ListString对象演示了这些方法:

示例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

该程序首先实例化一个ArrayListList接口的具体实现),并将其赋值给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

该程序首先实例化一个HashMapMap接口的具体实现),并将其赋值给map变量。然后通过调用put方法向map添加键值对。程序接着通过调用size()isEmpty()获取(并打印出)有关映射的一些信息。程序还演示了如何根据给定的键获取值(例如,map.get("apple")返回值fruit)。containsKeycontainsValue方法演示了如何测试特定的键或值是否存在,clear方法则移除所有的键值映射。

集合

除了ListMap中的方法外,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 cd添加到一个List中,再次使用ArrayList作为具体实现。然后,通过调用Collections.reverse(list)来反转列表的元素。要在List中交换元素,程序调用Collections.swap方法(例如,Collections.swap(list,0,3)会交换索引位置0和3的元素。最后,Collections.sort()方法按字母顺序对元素进行排序。

在回顾了Java Collections Framework的最相关部分后,现在可以学习JavaFX中如何表示集合。

1 使用JavaFX集合(发布版8)

示例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());
 
    }
}

最后,您可以使用CollectionsFXCollections的静态实用方法(例如,反转列表的元素)。但请记住,当调用其方法时,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),更改通知将打印四次。

当使用ListChangeListenerMapChangeListener时,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-7ListChangeListener.Change对象上调用各种方法。最重要的是要记住,ListChangeListener.Change对象可以包含多个更改,因此必须通过在while循环中调用其next()方法进行迭代。但是请注意,MapChangeListener.Change对象只包含表示执行的putremove操作的更改。

有关可用方法的信息,请参阅ListChangeListener.ChangeMapChangeListener.Change API文档。

关闭窗口

目录

JavaFX: 使用 JavaFX Collections

展开 | 折叠