CSC8014: Software Development – Advanced Techniques 第二周

2.3 Introduction to the Collections Framework

The Collections Framework

• A unified, generic framework for the representation and manipulation of groups of objects
–Manipulation is independent of representation
• Includes:
–Interfaces that define types of collection
–Abstract implementations for customisation
–General-purpose implementations
–Other implementations for legacy (Vector and Hashtable), or to constrain behaviour (wrappers), etc.
–Utilities to operate on collections and arrays and provide algorithms(sorting, searching etc.)
• Is an exemplar for other module material
·用于表示和操纵对象组的统一通用框架

  • 操纵独立于表示
    ·包括:
  • 定义集合类型的接口
  • 用于定制的抽象实现
  • 通用实施
  • 用于遗留(Vector和Hashtable)或约束行为(包装器)等的其他实现。
  • 对集合和数组进行操作并提供算法(排序,搜索等)的实用程序
    ·是其他模块材料的范例
    在这里插入图片描述• Map does not extend Collection.
    – It defines collection-view methods to access keys, values and entries of a mapping

interface Collection extends Iterable {
int size();
boolean isEmpty();
boolean contains(Object element);
boolean add(E element); // optional
boolean remove(Object element); // optional
// iterator from Iterable interface. Returns an iterator over
elements of type E.
Iterator iterator();
// Bulk and array operations
boolean containsAll(Collection<?> c); boolean addAll(Collection<? extends E> c); // optional boolean removeAll(Collection<?> c); // optional
boolean retainAll(Collection<?> c); // optional
void clear(); // optional
Object[] toArray();
E[] toArray(E[] a);
}

What is an Iterator?

• Can be used to cycle through elements of a collection. It has the following methods:
• hasNext(): Returns true if the iteration has more elements
• next(): Returns the next element in the iteration.
• remove(): Removes from the underlying collection the last element returned by this iterator (optional operation).
• How to use it?
–Create an Iterator object using iterator() method
–Use loop and hasNext()to loop through elements
–Obtain the element using next()
·可用于循环遍历集合的元素。它有以下几种方法:
hasNext():如果迭代有更多元素,则返回true
next():返回迭代中的下一个元素。
remove():从底层集合中删除迭代器返回的最后一个元素(可选操作)。
·如何使用它?

  • 使用iterator()方法创建Iterator对象
  • 使用loop和hasNext()循环遍历元素
  • 使用next()获取元素

Iteration over a collection

• Using a “foreach” statement:
void doSomethingToDates(Collection dates){
for (final Date d : dates) doSomethingToDate(d);
}
• Using the collection’s Iterator:
void forgetThePast(Collection dates) {
final Date today = new Date();
Iterator i = dates.iterator();
while (i.hasNext()) {
final Date date = i.next();
if (date.before(today))
i.remove(); // remove date
}
}

Sets

• A Set is an interface that inherits from Collection interface. It cannot contain duplicate elements
– There are no two elements e1 and e2 such that: e1.equals(e2)
– There is at most one null element
• Based on Set Theory
s1.containsAll(s2) // is s2 a subset of s1
s1.addAll(s2) // s1 = s1 union s2
s1.retainAll(s2) // s1 = s1 intersection s2
s1.removeAll(s2) // s1 = s1 difference s2

• There are no additional Set operations, just additional constraints on some operations. For example:
– The Collection add operation returns true if the Collection is modified as a result
– The Set add operation returns false if the Set already contains the element
»Maintains the semantics of the Collection operation and adds a reason for the operation to fail
·没有额外的Set操作,只是对某些操作的额外约束。举例来说:

  • 如果集合被修改,则集合添加操作返回true
  • 如果Set已包含元素,则Set add操作返回false
    »维护Collection操作的语义并添加操作失败的原因

HashSet

• HashSet is the most commonly used implementation of Set (for unsorted set) – There is TreeSet as well (for sorted set)
• Remember, always program to interfaces
Set uniques = new HashSet<>();
Set duplicates = new HashSet<>();

• Set constructors enforce set semantics
Collection removeDups(Collection c) {
// constructing a set from a collection
// removes any duplicate entries
return new HashSet©;
}
–There will be no duplicate elements in the returned collection

Lists

• A list is an ordered sequence of objects that may contain duplicates
• The user has control over where elements are inserted and can access elements through their index (or position)
• The List interface extends Collection and defines additional operations to work with indexed elements etc.
·列表是可能包含重复项的对象的有序序列
·用户可以控制元素插入的位置,并可以通过元素的索引(或位置)访问元素
List接口扩展了Collection,并定义了额外的操作来处理索引元素等。

interface List extends Collection{
E get(int index);
E set(int index, E element);
void add(int index, E element);
E remove(int index);
boolean addAll(int index, Collection<? extends E> c);
int indexOf(Object obj);
int lastIndexOf(Object obj);
// Iteration
ListIterator listIterator();
ListIterator listIterator(int index);
}

Iteration over a List

• See iteration over a collection
• Or use the ListIterator returned by a List.listIerator() or List.listIterator(int) for iteration from a given position
• ListIterator supports:
– Forward and backward traversal
– The ability to obtain list indexes relative to an iterator position
– Element insertion, removal and setting relative to an iterator position
·查看集合上的迭代
·或者使用List. listIterator()或List.listIterator(int)返回的ListIterator从给定位置进行迭代
· ListIterator支持:

  • 向前和向后遍历
  • 获取相对于迭代器位置的列表索引的能力
  • 相对于迭代器位置的元素插入、移除和设置

• It is possible to convert to and from List and arrays as follows:
–List list = Arrays.asList(array);
–String array[] = list.toArray();
• Arrays is a Utility class that allows manipulation of arrays

Maps

在这里插入图片描述• A Map maps keys to values
• A Map cannot contain duplicate keys (keys are unique)
– The collection of keys is a Set
– Map.put(key, value) replaces any existing entry in the map that has the same key
• One or more keys may map to the same value
• Use HashMap unless require guaranteed key order, in which case use TreeMap
·Map将键映射到值
·Map不能包含重复的键(键是唯一的)

  • 键的集合是一个Set
  • Map.put(key,value)替换map中任何具有相同键的现有条目
    ·一个或多个键可以映射到相同的值
    ·使用HashMap,除非需要保证密钥顺序,在这种情况下使用TreeMap

interface Map<K, V> {
V put(K key, V val); // optional
V get(Object key);
V remove(Object key); // optional
boolean containsKey(Object key);
boolean containsValue(Object value);
int size();
boolean isEmpty();
void putAll(Map<? extends K, ? extends V> t);
// optional
void clear(); // optional
Set keySet();
Collection values();
Set<Map.Entry<K, V>> entrySet();
}
• Nested Map.Entry<K, V> interface represents a {key, value} pair

Map Collection views

• The collection view methods provide three different views of the objects in a mapping:
– keySet returns the Set of keys
– values returns the Collection of values
– entrySet returns the Set of Map.Entry {key, value} pairs
• Each returned Collection is backed by the Map and is Iterable (by definition)
• A Collection returned from a modifiable Map supports element removal operations:
– Collection remove, removeAll, retainAll and clear and Iterator remove
• Returned collections do not support element addition operations (neither add nor addAll). Why?
·集合视图方法提供映射中对象的三种不同视图:

  • keySet返回键集
  • values返回值的集合
  • entrySet返回Map.Entry {key,value}对的集合
    ·每个返回的Collection都由Map支持,并且是Iterable的(根据定义)
    ·从可修改的Map返回的Collection支持元素删除操作:
  • 集合remove、removeAll、retainAll和clear以及Iterator remove
    返回的集合不支持元素添加操作(既不支持add也不支持addAll)。为什么?为什么?

Core Collection implementation hierarchy

在这里插入图片描述在这里插入图片描述• The recommended primary implementations are:
– HashSet for sets
– ArrayList for lists
– HashMap for maps
• LinkedList also implements List (and Queue)
• TreeSet implements SortedSet
• TreeMap implements SortedMap
• Do not use Vector or Hashtable because they always incur a synchronization overhead
• Remember: always program to the interfaces
·建议的主要实现是:

  • HashSet用于集合
  • 用于列表的ArrayList
  • HashMap用于map
    LinkedList也实现了List(和Queue)
    · TreeSet实现了SortedSet
    · TreeMap实现了SortedMap
    ·不要使用Vector或Hashtable,因为它们总是会产生同步开销
    ·记住:始终按照接口编程

Arrays and Collections Utilities

• The Arrays utility class provides static methods to search, sort, fill etc. an array plus the asList method that returns a list view of an array
– see java.util.Arrays Javadocs for details
• The Collections utility class provides static methods to search, sort,shuffle, find max and min values etc.
– see java.util.Collections Javadocs for details
• Collections also provides static factory methods to wrap collections to constrain their behaviour
– Wrappers include unmodifiable and thread safe (synchronized) versions of collections and maps

·Arrays实用程序类提供了用于搜索、排序、填充数组等的静态方法,以及返回数组列表视图的asList方法

  • 有关详细信息,请参见java.util.Arrays Javadocs
    ·Collections实用程序类提供静态方法来搜索,排序,洗牌,查找最大值和最小值等。
  • 有关详细信息,请参见java.util.Collections Javadocs
    · Collections还提供了静态工厂方法来包装集合以约束它们的行为
  • 包装器包括集合和映射的不可修改和线程安全(同步)版本

Sets, maps and immutability

• The behaviour of a Set is undefined if a change to the value of a set element affects the element’s equal comparison
– The Set cannot guarantee the no duplicates invariant
– A SortedSet cannot guarantee correct order
• Avoid holding mutable objects in a Set, including the Map key set
– Use immutable objects for Set elements and Map keys
– Or provide an immutable wrapper for mutable elements
– Or ensure that mutable objects do not change while they belong to a Set
(the most difficult option!)

2.4 Mixins and Strategies patterns (Ordering:Comparator and Comparable)

Ordering objects

• Sorting and comparison depend on a sort order
• In Java, the sort order is specified by implementations of the java.lang.Comparable or java.util.Comparator interfaces
• Classes that have a natural sort order, such as String, implement the mixin Comparable interface:
interface Comparable {
// returns:
// i < 0 if this is less than other
// 0 if this.equals(other)
// i > 0 if this is greater than other
int compareTo(T other);
}
• Sorting an array of objects a that implement Comparable is as simple as this:Arrays.sort(a);

public final class Module implements Comparable {
private final String prefix;
private final int number;
private final int semester;
// constructor, accessors, equals, hashCode
// order by prefix, number and semester
public int compareTo(Module m) {
final int pCmp = prefix.compareTo(m.prefix);
if (pCmp != 0) return pCmp ;
return number != m.number
? number – m.number
: semester – m.semester;
}
}

compareTo and equals

• Ideally, compareTo should be consistent with equals (see Bloch-EJ Item14)
• Classes that depend on compareTo include the sorted collections TreeSet and TreeMap and the utility classes Collections and Arrays, which contain searching and sorting algorithms.
• HashMap, ArrayList and HashSet add elements based on the equals method
• If compareTo is not consistent with equals, then it could produce strange results.
• Why?
·理想情况下,compareTo应该与equals一致(参见Bloch-EJ项目14)
·依赖于compare的类包括排序集合TreeSet和TreeMap以及包含搜索和排序算法的实用程序类Collections和Arrays。
· HashMap、ArrayList和HashSet基于equals方法添加元素
如果compareTo与equals不一致,那么它可能会产生奇怪的结果。
·为什么?

The mixin design pattern

• Mixins express optional or orthogonal behaviour
– Classes implement mixin types in addition to their primary type (or function)
• Example Java library mixins
– Instances of a class that implements Serializable can be serialized to a byte stream
– Instances of a class that implements Cloneable can be cloned
» and do not throw CloneNotSupportedException
– Instances of Comparable can be ordered
• Serializable and Cloneable are also markers
– Marker interfaces have no methods but declare a type (some capability)that implementations support
·混合表示可选或正交行为

  • 类除了实现它们的主类型(或函数)外,还实现了mixin类型
    ·Java库混合示例
  • 实现Serializable的类的对象可以被序列化为字节流
  • 可以克隆实现Cloneable的类的实例
    »并且不要抛出CloneNotSupportedException
  • 可订购可比较的产品
    ·可序列化和可克隆也是标记
  • 标记接口没有方法,但声明了实现支持的类型(某些功能)

A problem with mixins

• Mixins are a common and useful pattern but you have to modify a class to implement the mixin interface
• Only an implementation of Comparable can perform a comparison to order itself with respect to another object
– Good for new classes or for existing classes that you control and can retrofit with the Comparable interface
– Not so good for classes you do not control
• So the problem is:
– how do you get the desired behaviour provided by a mixin without modifying a class?
– How can you order instances of a class that does not implement
Comparable without modifying the class?

The strategy design pattern

• The answer is the strategy design pattern
– Use when cannot modify a class or when not implementing
normal/expected behaviour
• A strategy is a separate implementation of an interface that provides the
desired orthogonal behaviour
– E.g. Comparator compares two objects as opposed to an object doing
the comparison itself (by implementing Comparable)
– Implementations of Comparator often provide alternative orderings

Implementing Comparator

• An implementation of the strategy interface Comparator can be used to specify a sort order for objects of a given type.
interface Comparator {
// returns:
// i < 0 if obj1 is less than obj2
// 0 if obj1.equals(obj2)
// i > 0 if obj1 is greater than obj2
int compare(T obj1, T obj2);
}
• A Comparator can be passed to a sort method (Collection.sort(), Arrays.sort()) to sort lists and
arrays according to the order induced by the specified comparator.
• A Comparator instance should be passed to the constructor of SortedSet and
SortedMap implementations to order them according to the order induced by the specified comparator.
• Ideally, Comparator should be consistent with equals

public final class ModuleByStage
implements Comparator {
public ModuleByStage () { }
// order by module semester, prefix, number
public int compare(Module m1, Module m2) {
final int sCmp
= m1.getSemester() – m2.getSemester();
if (sCmp != 0) return sCmp;
final int pCmp
= m1.getPrefix().compareTo(m2.getPrefix());
return pCmp != 0
? pCmp
: m1.getNumber() - m2.getNumber();
}
}

import java.util.*;
class StringSort implements Comparator {
public int compare(String s1, String s2){
return s1.toLowerCase().compareTo(s2.toLowerCase());
}
public static void main(String args[]) {
List list = Arrays.asList(args);
Collections.sort(list); // default String sort
System.out.println(list);
Collections.sort(list, new StringSort()); //case independent String sort
System.out.println(list);
}
}

Mixins versus Strategies

• Mixins and strategies both have their place
– Not all classes can implement or be retrofitted with a mixin
– Not all classes will expose sufficient information to apply a strategy
» There may not be public methods that can be used to implement the strategy’s functionality

SortedSet and SortedMap

• A SortedSet maintains its elements in ascending order
– Additional operations are provided to take advantage of the ordering
– SortedSet is implemented by TreeSet
• SortedMap is the Map analog of SortedSet. The mappings are maintained in ascending key order (the key set is a sorted set)
– SortedMap is implemented by TreeMap
• For both, the sorted order is either determined by Comparable elements or by a Comparator provided at instantiation
·SortedSet按升序维护其元素

  • 提供额外的操作以利用排序
  • SortedSet由TreeSet实现
    · SortedMap是SortedSet的Map类似物。映射以键的升序进行维护(键集是一个排序集)
  • SortedMap由TreeMap实现
    ·对于两者,排序顺序由Comparable元素或在实例化时提供的Comparator确定

2.5 Factory methods and singleton

Factory Methods

• It creates objects of some type without the user necessarily specifying the concrete implementation of the type
• Users do not use the object’s constructor (The user does not use the new keyword)
• Access to constructors is often forbidden
• The factory pprovides static factory method(s) e.g. getInstance that can return an interface type
– “hiding” implementation detail
– The factory determines which implementation to use
– The choice of implementation can be deferred to run-time
• The factory can impose invariants such as uniqueness
• Polymorphism + interfaces + factories = implementation Independence
·它创建某种类型的对象,而无需用户指定该类型的具体实现
·用户不使用对象的构造函数(用户不使用new关键字)
·经常禁止构造器
·工厂提供静态工厂方法,例如可以返回接口类型的getInstance

  • “隐藏”实施细节
  • 工厂决定使用哪个实现
  • 实现的选择可以推迟到运行时
    ·工厂可以强加不变量,例如唯一性
    多态+接口+工厂=实现独立性
    在这里插入图片描述在这里插入图片描述在这里插入图片描述• AccountFactory instantiates an account
    – Determines which account type from the key passed to getInstance
    Account acc = AccountFactory.getInstance(“free”, 1234);
    – Could be FreeAccount, OverdraftAccount or another implementation
    – Potential to configure an application to use different concrete implementations at run-time
    · AccountFactory实例化帐户
  • 从传递给getInstance的键中确定哪个帐户类型
    account = accountFactory.getInstance(“free”,1234);
  • 可以是FreeAccount、OverdraftAccount或其他实现
  • 配置应用程序以在运行时使用不同具体实现的可能性

在这里插入图片描述

Collections framework factory methods and wrappers

• Can use factory to create unmodifiable collections. Returns an unmodifiable collection for a given modifiable collection
• The Collections factory class gives you several static methods to create immutable wrappers for your collections or maps. All these methods starts with unmodifiable, followed by the name of the type of your structure
·可以使用工厂创建不可修改的集合。返回给定的可修改集合的不可修改集合
Collections工厂类为您提供了几个静态方法来为您的集合或映射创建不可变的包装器。所有这些方法都以unmodifiable开头,后跟结构类型的名称

public class Collections {
public static Collection unmodifiableCollection(Collection c) {…}
public static List unmodifiableList(List l) {…}
public static <K, V> Map<K, V> unmodifiableMap(Map<K, V> m) {…}
public static Set unmodifiableSet(Set s) {…}
public static SortedSet unmodifiableSortedSet(SortedSet s) {…}
public static <K, V> SortedMap<K,V> unmodifiableSortedMap(SortedMap <K, V>
s) {…}

}
在这里插入图片描述

Advantages of static factory methods

Advantages compared to constructors:

  1. Static factory methods can have more meaningful names
  2. Static factory methods are not required to create a new object each time they are invoked
    – Instances can be cached, can enforce other constraints
  3. Static factory methods can return an object of any subtype of their return type
    – The return type of an instantiated object can be restricted to its interface
    – Implementation can be hidden and changed at run-time
    – Service provider frameworks can be extended with new implementations (see Java Cryptography libraries)
    • See Bloch-EJ Item 1

Disadvantages of static factory methods

(Possible) disadvantages compared to constructors:

  1. Classes without public or protected constructors cannot be subclassed
    – A blessing? See composition versus inheritance (part 2.6)
  2. Static factory methods are not readily distinguishable from other static methods(they deviate from the norm)
    – The Collections static factories are an example
    » There is a tension between meaningful names and conveying the message that objects are being created
    – In contrast, constructors standout in the API
  3. There is a necessary level of indirection

Static factory methods: summary

• Do not automatically provide public constructors simply because they are the norm
• For a given class, consider whether the advantages of static factory methods are significant
– If they are, then do not provide constructors and provide factory methods instead
– If they are not, or the advantages are not compelling, then prefer constructors because they are
the norm

Singleton Pattern

• A singleton is a class that is instantiated exactly once

  • A typical use is to represent a system component e.g. OS, FileSystem or some class that controls other components (e.g. Bank issuing Accounts).
    Another example is the screen on a phone
    • Two ways to implement singleton
    – With public final field
    – With static factory

code demo

public class HashSetDuplicateWordsExample {
public static void main(String[] args) {
// array of words
String[] words = “What, my name is. What, my name is, What, my name
is…”.split(" ");
// create sets
Set uniques = new HashSet<>();
Set duplicates = new HashSet<>();
// populate sets
for (String s : words) {
if (!uniques.add(s)) {
duplicates.add(s);
}
}
// print sets
System.out.println("Unique Words: " + uniques);
System.out.println("Duplicate Words: " + duplicates);
// remove all words that are found in duplicates
uniques.removeAll(duplicates);
// print sets
System.out.println("Unique Words: " + uniques);
System.out.println("Duplicate Words: " + duplicates);
}
}

public class RemoveDuplicates {
public static void main(String[] args) {
final String[] colours = { “red”, “blue”, “orange”, “pink”, “purple”,
“red”, “green”, “blue”, “red” };
final List colourList = Arrays.asList(colours);
System.out.println("Colours: " + colourList);
System.out.println("Colours without duplicates: " +
removeDuplicates(colourList));
System.out.println("Sorted colours without duplicates: " +
sortAndremoveDuplicates(colourList));
}
public static Collection removeDuplicates(Collection c) {
return new HashSet©;
}
public static Collection sortAndremoveDuplicates(Collection
c) {
return new TreeSet©;
}
}

public class HashMapIterator {
public static void main(String[] args) {
// create and populate map
Map<String, String> foo = new HashMap<>();
foo.put(“s1”, “James”);
foo.put(“s2”, “Jane”);
foo.put(“s3”, “Rich”);
foo.put(“s4”, “Becky”);
// using for loop and keySet
for (String id : foo.keySet()){
System.out.println("Key: " + id);
}
// using for loop and values
// CAUTION, order is not guaranteed to match KeySet
for (String name : foo.values()){
System.out.println("Value: " + name);
}
// using for loop and entrySet
for (Map.Entry<String, String> entry : foo.entrySet()) {
System.out.println("Key: " + entry.getKey() + " Value: " +
entry.getValue());
}
}
}

public class FrequencyCount {
public static void main(String args[]) {
//array of Words
String[] words = “My name is What? My name is Who? My name
is …”.split(" “);
Integer freq;
Map<String, Integer> wordMap = new HashMap<String, Integer>();
// Keys:the words
// Vals:their frequency
for (String word : words) {
// get value associated with key
// if it does not exist, default value = 0
freq = wordMap.getOrDefault(word,0);
freq++;
wordMap.put(word, freq);
}
System.out.print(wordMap.size());
System.out.println(” distinct words detected");
System.out.println(wordMap);
Map<String, Integer> sortedMap = new TreeMap<String, Integer>(wordMap);
System.out.println(“In Sorted Order:”);
System.out.println(sortedMap);
}
}

public final class Module implements Comparable {
public static final int MIN_MODULE_NUMBER = 1000;
public static final int PREFIX_LENGTH = 3;
private final String prefix;
private final int number;
private final int semester;
public Module(String prefix, int number, int semester) {
if (prefix.length() != PREFIX_LENGTH)
throw new IllegalArgumentException("prefix: " + prefix);
if (number < MIN_MODULE_NUMBER)
throw new IllegalArgumentException("number: " + number);
if (semester != 1 && semester != 2)
throw new IllegalArgumentException("semester: " + semester);
this.prefix = prefix;
this.number = number;
this.semester = semester;
}
public String getPrefix() {
return prefix;
}
public int getNumber() {
return number;
}
public int getSemester() {
return semester;
}
public int compareTo(Module module) {
final int pCmp = prefix.compareTo(module.prefix);//call compareTo in
string class
if (pCmp != 0)
return pCmp;
return number != module.number
? number - module.number
: semester - module.semester;
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof Module))
return false;
final Module module = (Module) obj;
//NB this is not consistent with compareTo

return prefix.equals(module.prefix) && number == module.number;
//This is consistent with compareTo
//return prefix.equals(module.prefix) && number == module.number &&
semester == module.semester ;
}
@Override
public int hashCode() {
int hc = 17;
hc = 37 * hc + prefix.hashCode();
hc = 37 * hc + number;
return hc;
}
public String toString() {
final StringBuilder sb = new StringBuilder(prefix);
sb.append(number).append(“-”).append(semester);
return sb.toString();
}
}

public class UseModule {
public static void main(String[] args) {
final Module[] modulesArray
= new Module[] {
new Module(“CSC”, 8005, 2),
new Module(“CSC”, 8002, 2),
new Module(“MAS”, 1006, 2),
new Module(“JPN”, 1004, 1),
new Module(“CSC”, 8005, 1),
new Module(“CSC”, 1014, 2),
new Module(“JPN”, 1004, 1)
};
System.out.println("direct module comparison: "

  • modulesArray[1].compareTo(modulesArray[0]));
    // unordered (HashSet), no duplicates (Set interface uses equals)
    final Set unsortedModulesSet = new HashSet();
    // ordered (TreeSet), duplicates (SortedSet interface uses compareTo)
    final SortedSet sortedModulesSet = new TreeSet();
    for (final Module m : modulesArray) {
    sortedModulesSet.add(m);
    unsortedModulesSet.add(m);
    }
    System.out.println("array of modules: "
  • Arrays.toString(modulesArray));
    System.out.println("sorted set of modules: "
  • sortedModulesSet);
    System.out.println("unsorted set of modules: "
  • unsortedModulesSet);
    }
    }

public class InconsistencyEqualsCompareTo {
public static void main(String[] args) {
Module module1 = new Module(“CSC”,8014,1);
Module module2 = new Module(“CSC”,8014,2);
Set set = new HashSet();
set.add(module1);
set.add(module2);
System.out.println("HashSet "+set);
Set treeSet = new TreeSet();
treeSet.add(module1);
treeSet.add(module2);
System.out.println("TreeSet "+treeSet);
}
}

public class StringSort implements Comparator {
public int compare(String s1, String s2) {
return s1.toLowerCase().compareTo(s2.toLowerCase());
}
public static void main(String args[]) {
String[] arr = { “one”, “two”, “three”, “four”, “Five”, “one”, “Ten” };
List list = Arrays.asList(arr);
Collections.sort(list); // default String sort
System.out.println(list);
// case independent String sort
Collections.sort(list, new StringSort());
System.out.println(list);
//String length sort
Collections.sort(list, new AnotherStringSort());
System.out.println(list);
}
}

public class AnotherStringSort implements Comparator{
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
}

public final class Name {
private static final Map<String, Name> NAMES = new HashMap<String, Name>();
private final String firstName, lastName, strRep;
private Name (String firstName, String lastName, String strRep) {
this.firstName= firstName;
this.lastName = lastName;
this.strRep = strRep;
}
public static Name getInstance (String firstName, String lastName) {
String strRep = firstName + " " + lastName;
Name name = NAMES.get(strRep);
if (name==null) {
name= new Name(firstName, lastName, strRep);
NAMES.put(strRep, name);
}
return name;
}
public String getFirstName() {return firstName;}
public String getlasstName() {return lastName;}
public String toString() {return strRep;}
}

ublic class UseName {
public static void main(String[] args) {
String fn1 = “John”;
String fn2 = “Smith”;
Name name1 = Name.getInstance(fn1,fn2);
Name name2 = Name.getInstance(“Jen”,“Jones”);
Name name3 = Name.getInstance(“John”,“Smith”);
System.out.println(“name1 same object as name2?” +(name1 == name2));
System.out.println(“name1 same object as name3?” +(name1 == name3));
}
}

public class UseAccountFactory {
public static void main(String[] args) {
System.out.println(“Using account factory”);
/*
// cannot create a FreeAccount directly because we’ve limited access (is
pkg-private)
//FreeAccount f = new FreeAccount(); // won’t work
// get free account with number 1234
final Account freeAccount1 =
AccountFactory.getInstance(AccountFactory.FREE_ACCOUNT, 1234);
// try to get another free account with number 1234.
// If factory imposes uniqueness this will be the same instance
final Account freeAccount2 =
AccountFactory.getInstance(AccountFactory.FREE_ACCOUNT, 1234);
// check that freeAccount1 == freeAccount2 - same instance
System.out.println("Only have single instance of freeAccount "

  • freeAccount1.getAccountNumber() + ": "
  • (freeAccount1 == freeAccount2));
    // freeAccount1 and freeAccount2 are same
    printAccountInfo(AccountFactory.FREE_ACCOUNT, freeAccount1);
    printAccountInfo(AccountFactory.FREE_ACCOUNT, freeAccount2);
    */
    // now we demo an overdraftAccount
    final Account overdraftAccount1 =
    AccountFactory.getInstance(AccountFactory.OVERDRAFT_ACCOUNT, 4567);
    printAccountInfo(“”, overdraftAccount1);
    final Account overdraftAccount2 =
    AccountFactory.getInstance(AccountFactory.OVERDRAFT_ACCOUNT, 5678);
    printAccountInfo(“”, overdraftAccount2);
    final Account overdraftAccount3 =
    AccountFactory.getInstance(AccountFactory.OVERDRAFT_ACCOUNT, 6789);
    printAccountInfo(“”, overdraftAccount3);
    final Account overdraftAccount4 =
    AccountFactory.getInstance(AccountFactory.OVERDRAFT_ACCOUNT, 7890);
    printAccountInfo(“”, overdraftAccount4);
    final Account overdraftAccount5 =
    AccountFactory.getInstance(AccountFactory.OVERDRAFT_ACCOUNT, 8901);
    printAccountInfo(“”, overdraftAccount5);
    }
    private static void printAccountInfo(String accType, Account account) {
    System.out.println(accType + " " + account + " is implemented by: " +
    account.getClass());
    }
    }

public interface Account {
void deposit(int amount);
int getAccountNumber();
int getBalance();
void transferBalance(Account acc);
int withdraw(int amount);
}

// abstract class providing partial implementation of Account
public abstract class AccountFactory implements Account {
public static final String FREE_ACCOUNT = “free”;
public static final String OVERDRAFT_ACCOUNT = “overdraft”;
// map of account number to instantiated account
// note static, so per-class map
private static final Map<Integer, Account> accounts = new HashMap<Integer,
Account>();
private final int accountNumber;
private int balance;
private static int nbOverdraft = 0;
AccountFactory(int accountNumber) {
this.accountNumber = accountNumber;
}
/**

  • Return an account of the specified type with the specified
  • account number.
  • @param account the type of account to return
  • @param accountNumber the account number
  • @return an account of the specified type. An existing account
  • is returned if accountNumber is already known. Otherwise
  • a new account with the given number is returned.
  • @throws NullPointerException if accountType is null
  • @throws IllegalArgumentException if accountType is an
  • invalid accounttype
    */
    public static Account getInstance(String account, int accountNumber) {
    // enforce single instance per accountNumber
    Account acc = accounts.get(accountNumber);
    if (acc != null) // impose uniqueness
    return acc;
    if (account.equals(FREE_ACCOUNT)) {
    acc = new FreeAccount(accountNumber);
    } else if (account.equals(OVERDRAFT_ACCOUNT)) {
    if (nbOverdraft < 3) {
    acc = new OverdraftAccount(accountNumber);
    nbOverdraft=nbOverdraft+1;
    }else {
    acc = new FreeAccount(accountNumber);
    }
    } else {
    throw new IllegalArgumentException("invalid account type: " + account);
    }
    // put acc in accounts map
    accounts.put(accountNumber, acc);
    // return the instance
    return acc;
    }
    public void deposit(int amount) {
    if (amount < 0)
    throw new IllegalArgumentException("Negative deposit: " + amount);
    balance = balance + amount;
    }
    public int getAccountNumber() {
    return accountNumber;
    }
    public int getBalance() {
    return balance;
    }
    public void transferBalance(Account acc) {
    final int accBalance = acc.getBalance();
    if (accBalance < 0)
    throw new IllegalArgumentException("Transfer from overdrawn account not
    allowed: " + acc);
    deposit(acc.withdraw(accBalance));
    }
    public String toString() {
    return "account number: " + accountNumber + " (balance: " + balance + “)”;
    }
    // utility method to allow subclasses to set the account balance
    void setBalance(int balance) {
    this.balance = balance;
    }
    }

/**

  • OverdraftAccount - bank account that allows overdrafts that
  • incur a charge. This OverdraftAccount can only be instantiated
  • by classes in this same package.
  • Use AccountFactory.getInstance(“overdraft”) to get an instance.

/
// package-private class definition
// - cannot be imported to other packages
final class OverdraftAccount extends AccountFactory {
private final static int OVERDRAFT_CHARGE = 10;
// package-private constructor cannot be directly instantiated by
// clients outside this package.
// Use AccountFactory.getInstance(“overdraft”) instead.
OverdraftAccount(int accountNumber) {
super(accountNumber);
}
/
*

  • Withdraw allows accounts to go into to the red and imposes
  • a fixed charge for withdrawals from overdrawn accounts.
  • @see uk.ac.ncl.teach.ex.factory.acc.Account#withdraw(int)
    */
    public int withdraw(int amount) {
    if (amount < 0)
    throw new IllegalArgumentException("Negative withdrawal: " + amount);
    final int newBalance = getBalance() - amount;
    if (newBalance < 0) {
    setBalance(newBalance - OVERDRAFT_CHARGE);
    } else {
    setBalance(newBalance);
    }
    return amount;
    }
    }

/**

  • FreeAccount - bank account with no overdraft and no charges.
  • This FreeAccount can only be instantiated by classes in
  • this same package. Use the AccountFactory.getInstance(“free”)
  • to get an instance.

/
// package-private class definition
// - cannot be imported to other packages
final class FreeAccount extends AccountFactory {
// package-private constructor cannot be directly instantiated by
// clients outside this package.
// Use AccountFactory.getInstance(“free”) instead.
FreeAccount(int accountNumber) {
super(accountNumber);
}
/
*

  • A withdrawal that puts the account into the red will not
  • be permitted.
  • @see uk.ac.ncl.teach.ex.factory.acc.Account#withdraw(int)
    */
    public int withdraw(int amount) {
    if (amount < 0)
    throw new IllegalArgumentException("Negative withdrawal: " + amount);
    final int currentBalance = getBalance();
    if (currentBalance < amount)
    return 0;
    setBalance(currentBalance - amount);
    return amount;
    }
    }
  • 29
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值