《Java技术及应用》笔记(五)

1.收集

Java设计了收集系列,提供了更复杂的方式保存对象。

收集又叫容器,它把多个元素放进一个单元里,形成一个对象。收集用于存储、读取、处理和交流聚集的数据。

Java的收集形成了收集框架的体系结构,包括接口、实现、算法三部分。

1.核心的收集接口有Collection、Set、List、Queue、Map等,标红的都是Collection的后继,所有的核心接口都是泛型的。

2.实现是指存储收集所用的数据对象,有通用目的实现、专用目的实现等。

3.收集的算法是一些静态方法,对收集执行有用的功能。常用的算法有排序、搅乱、常规数据处理、搜索、组合、寻找极值等。

1.1.Collection接口

这是收集系列的根,具有最大的通用性允许重复元素存在,不要求元素排序等。通用目的的各种收集在实现时都用Collection作构造方法的参数,方便转换收集的类型。

Collection只有接口,没有实现。接口结构如下:

public interface Collection<E> extends Iterator<E>{
 //基本操作
 int size(); //返回收集的元素个数
 boolean isEmpty(); //收集有无元素
 boolean contains(Object element); //是否包含element元素
 boolean add(E element); //加入element元素到收集
 boolean remove(Object element); //删除element元素
 Iterator<E> iterator(); //列举收集元素

 //成批操作
 boolean containsAll(Collection<?> c); //目标收集是否有指定收集c的所有元素
 boolean addAll(Collection<?extends E> c); //加入指定收集元素到目标收集
 boolean removeAll(Collection<?> c); //目标收集删除指定收集全部元素
 boolean retainAll(Collection<?> c); //目标收集保留指定收集全部元素
 void clear(); //清空收集

 //数组操作
 Object[] toArray(); //收集元素放进Object数组
 <T> T[] toArray(T[] a); //收集元素放进T类型数组
} 

1.1.1.遍历收集

把收集中的对象列举出来称为遍历收集。可以用for-each结构遍历,如:

for(Object o:collection)System.out.println(o);

1.1.2.Iterator接口

//Iterator接口的结构

public interface Iterator<E>{
 boolean hasNext(); //收集若还有元素返回true
 E next(); //取下一个元素
 void remove(); //删除next()返回的最后一个元素
}

调用Collection接口的iterator()方法就可以得到Iterator对象。Iterator对象可以遍历收集,如果遍历收集时希望删除其元素,可以在调用next()后调用一次remove(),这是for-each结构遍历无法做到的。过滤任意Collection的多态代码如下:

Static void filter(Collection<?> c){
 for(Iterator<?> it=c.iterator();it.hasNext;)
   if(!cond(it.next()))
     it.remove();
}

1.1.3.成批操作

成批操作是对整个Collection进行的,但这些操作也是用Collection接口的基本操作实现的。

1.1.4.数组操作

数组操作让Collection的内容转换到数组中。例如:Object[] a=c.toArray();  将Collection对象c的内容导入Object数组中,数组长度与c的元素个数相同。

1.2.Set 

Set是不能包含重复元素的Collection,它继承了Collection的方法。

Java平台有3种通用目的的Set实现:HashSetTreeSetLinkedHashSet

1.HashSet用哈希表存放元素,实现性能最好,但不保证列举顺序。

2.TreeSet用红-黑树存放元素,按元素值排次序,比HashSet慢。

3.LinkedHashSet是链表实现的哈希表,按元素插入集合的顺序排次序,次序不混乱,但代价高一些,介于HashSet和TreeSet之间。由于HashSet速度快,除了要排序的情况下必须用TreeSet外,一般都用HashSet

Set还有两个专用目的的实现,EnumSet和CopyOnWriteArraySet,暂不理会。

创建Set对象时总是用接口类Set做引用,如:

Set<String> s=new HashSet<String>();

或:Set<String> s=new HashSet<String>(32);

为HashSet设置32容量。其默认容量为16,若输入的容量不是2的幂,将会自动变成比这容量大的2的幂,例如设置15,实际容量为16。当元素个数大于容量,将会扩容。

补充:

若有一个已被创建的Set对象<String>a,可以:

Set<String> b=new Set<>(a); 创建一个元素与a相同的Set对象b。

1.2.1.Set接口示例 

import java.util.*;

public class Test{

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
     String[] str={"Java技术及应用","qwq","awa"};
	 Set<String> s=new HashSet<>();
	 for(String str1:str)
		 s.add(str1);
	 System.out.println(s);
	}
}

1.3.List

List是有序的Collection,又称为序列,基本上是按插入顺序排列的,可以包含重复元素。List接口继承了Collection的方法,删除操作总是删除列表中第一个出现的指定元素,加入操作总是加在列表的末尾。(有点像c的队列)

另外,List根据序列特性增加了一些方法,其结构如下:

public interface List<E> extends Collection<E>{
 //按位置访问
 E get(int index);  //去指定下标的元素
 E set(int index,E element); //设置指定下标的元素,返回原元素
 boolean add(E element);
 void add(int index,E element); //加入到指定位置
 E remove(int index); //删除指定位置的元素,返回该元素
 boolean addAll(int index,Collection<? extends E> c);

 //搜索
 int indexOf(Object o); //返回列表中第一次出现的指定元素的下标,或-1(无)
 int lastIndexOf(Object o); //返回列表中最后一次出现的指定元素的下标,或-1
 
 //列举
 ListIterator<E> listIterator(); //从表头开始列举
 ListIterator<E> listIterator(int index); //从指定位置开始列举

 //范围视图,即显示一段范围的元素
 List<E> subList(int from,in to);
}

Java平台有两种通用目的的List实现:ArrayListLinkedList。前者提供固定时间的按位置访问,插入删除是线性时间,通常性能比较好;后者的插入删除是固定时间,在经常需要插入删除时性能稍好。

1.3.1.基本操作

创建ArrayList对象格式:List<Type> list=new ArrayList<Type>();

1.3.2.列举操作 

List使用的ListIterator扩充了Collection接口的iterator,可以从两个方向遍历列表,可在列表期间修改列表,而且获得iterator的当前位置。 创建ListIterator对象的格式为:

List<Integer> list=new ArrayList<>();
ListIterator it=list.listIterator();
//也可以指定位置开始列举
//ListIterator it=list.lisIterator(2);
//从第三个元素开始列举

由于书上对ListIterator接口的方法讲解的太笼统,测试方法时感觉不太对,所以根据网上注解和具体运行修改了对ListIterator接口方法的注释,其结构如下:

public interface ListIterator<E> extends Iterator<E>{
 boolean hasNext();  //是否存在下一个元素
 boolean hasPrevious(); //前一个元素是否存在

 E next(); //先取出当前指针指向的元素,再将指针向下移动
 E previous();  //先将指针向前移动,再取出当前指针指向的元素

 int nextIndex();   //测试:返回指针指向的下标
 int previousIndex(); //测试:返回指针指向的前一个元素下标

 void remove(); //删除next()或previous()返回的元素
 void set(E e); //用指定元素设置next()或previous()返回的元素
 void add(E e); //在当前指针指向的下标加入指定元素
 
 //如果当前下标指向列表开头,调用previousIndex将返回-1
 //如果当前下标指向列表的最后一个元素,调用nextIndex将返回list.size()
}

参考自:

1. ListIterator类_请叫我木丁西的博客-CSDN博客

2.有关ListIterator接口的add与remove方法探究_goodbaby728的博客-CSDN博客

ListIterator接口方法测试:

import java.util.*;

public class Test{

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
     List<String> list=new ArrayList<String>();
     list.add("A");
     list.add("B");
     list.add("C");
     System.out.println(list);
     
     ListIterator<String> it=list.listIterator();
     System.out.println(it.next());  //返回A,指针移动指向B
     System.out.println(it.next());  //返回B,指针移动指向C
     it.remove(); //删除next()返回的元素,故删除B
     System.out.println(it.previous());  //指针移动指向A,返回A
     System.out.println(it.nextIndex()); //指针现在指向A,返回下标0
     System.out.println(it.previousIndex()); //指针现在指向A,返回-1
     it.set("E");  //替换previous()返回的元素A
     it.add("D");  //指针现在指向E,在下标0处添加元素D
     System.out.println(list);
	}
}
//输出结果
[A, B, C]
A
B
A
0
-1
[D, E, C]

还有一些需要注意的地方:remove()和set()操作都要跟随在next()或previous()方法后面,中间如果有add()操作,将会出错。

1.3.3.范围视图操作 

范围视图即显示一段范围的元素。其相关方法subList(int from,int to)返回从from下标到to下标前的子列表,即包括from位置元素,不包括to位置元素。subList().clear()将清空子列表。

如果产生子列表后又在原列表加入或删除元素,那么子列表的语义就没定义。

1.3.4.List的数据结构应用

Collections类有许多算法适用于List,比如合并排序sort、随机搅乱shuffle、序列反向reverse、循环rotate、元素交换swap、全部替换replaceAll、填充fill、复制copy等等。

排序示例如下:

import java.util.*;

public class Test{

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
     Random r=new Random();
     List<Integer> list=new ArrayList<>();
     for(int i=0;i<10;i++)
    	 list.add(r.nextInt(10));
     System.out.println(list);
     Collections.sort(list);
     System.out.println(list);
     Collections.reverse(list);
     System.out.println(list);
	}
}

1.4.Queue

Queue是保持元素重于处理元素的Collection,通常是按先进先出方式安排元素,在队尾插入元素,在队头删除元素;但优先队列是按值来安排的,不一定在队尾插入。

有些Queue实现时限制了所保持元素的数量,称为限界。

Queue接口增加了一些方法,如下:

public interface Queue<E> extends Collection<E>{
 E element(); //返回队头元素,空队则抛出异常
 boolean offer(E e); //在限界队列里加入元素
 E peek(); //返回队头元素,空队返回null
 E poll(); //删除并返回队头元素,空队则抛出异常
 E remove(); //删除并返回队头元素,空队返回null
}

Queue接口有个子接口叫Deque接口,是支持在队列两端都可以插入和删除元素的线性收集(双端队列),Deque接口方法比Queue接口多。 

1.4.1.Queue的实现

每种Queue实现必须说明它的安排性质:

LinkedList类实现了Queue接口,提供了先进先出队列的操作;

PriorityQueue类基于优先堆数据结构的优先队列,也实现了Queue接口;

BlockingQueue接口是并发Queue接口,定义了阻塞队列的方法,由SynchronousQueue类等几个并发队列实现。

创建Queue对象的格式是:Queue<Type> queue=new LinkedList<Type>();

创建PriorityQueue对象的格式是:Queue<Type> pq=new PriorityQueue<Type>(); 

LinkedList类和ArrayDeque类实现了Deque接口,这是可变长度的数组实现的双端队列,没有元素容量限制。

创建Deque对象的格式是:Deque<Type> pq=new ArrayDeque<Type>();

1.4.2.Queue的数据结构应用 

import java.util.*;

//用优先队列实现堆排列
//将随机列表放入PriorityQueue构造方法中形成堆,
//然后逐个元素出队到列表,最后返回列表
class MyheapSort{
	static<E> List<E> heapSort(Collection<E> c){  //形参也可以写成List<E> c
		Queue<E> queue=new PriorityQueue<E>(c);
		List<E> list=new ArrayList<E>();
		while(!queue.isEmpty()) {
			list.add(queue.remove());
		}
		return list;
	}
}

//生成随机列表,运行heapSort方法
public class Test{
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
     Random r=new Random();
     List<Integer> list=new ArrayList<>();
     for(int i=0;i<10;i++)
    	 list.add(r.nextInt(10));
     System.out.println(list);
     list=MyheapSort.heapSort(list);
     System.out.println(list);
     
	}
}

1.5.Map

Map是把键(Key)映射到值(Value)的对象。映射不能包含重复的键,一个键至少可以映射一个值,它是数学函数抽象的模型。

Map接口的结构是:

public interface Map<K,V>{
 //基本操作
 V put(K key,V value);  //输入
 V get(Object key);    //返回键映射的值
 V remove(Object key);  //删除键
 boolean containsKey(Object key); //是否包含key键
 boolean containsValue(Object value); 

 //成批操作
 void putAll(Map<? extends K,? extends V> m); //将m全部键和值加入目的Map
 void clear;

 //收集视图
 public Set<K> keySet(); //取Map中键的集合,返回一个Set对象
 public Collection<V> values(); //取Map中值的集合
 public Set<Map.Entry<K,V>> entrySet; //取Map中键-值对的集合

 //entrySet元素接口
 public interface Entry{
  K getKey();
  V getValue();
  V setValue(V value);
 }
}

1.5.1.Map的实现

Java平台有三种通用目的的Map实现:HashMapTreeMapLinkedListMap,它们性能与HashSet、TreeSet和LinkedHashSet类似。HashMap速度最快,TreeMap可以排序,LinkedHashMap性能接近HashMap并保持插入顺序,但LinkedHashMap可以根据键遍历,它还有removeEldestEntry()方法删除旧映射。

1.5.2.基本操作 

public class Test{
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
     Map<String,Integer> map=new HashMap<>();
     map.put("Math",68);
     map.put("Physics",82);
     map.put("English", 90);
     map.put("Chemistry", 75);
     System.out.println(map);
     System.out.println(map.get("Math"));
     System.out.println(map.remove("Math"));
     System.out.println(map);
     System.out.println(map.containsKey("English"));
	}
}
//输出
{English=90, Chemistry=75, Math=68, Physics=82}
68
68
{English=90, Chemistry=75, Physics=82}
true

1.如果用TreeMap构造Map对象,输出按字母顺序排列键。

2.如果用LinkedHashMap构造Map对象,输出按插入顺序排列键。

1.5.3.Map.Entry接口

Map有个嵌套的接口Map.Entry,可以实现按键-值对列举Map:

for(Map.Entry<KeyType,ValType> e:m.entrySet())
   System.out.println(e.getKey()+" "+e.getValue());

m.entrySet()方法会返回一个Set对象,接口Entry是存储的元素的类型,(接口也是一种数据类型)

收集视图操作示例:

import java.util.*;

public class Test{
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
     Map<String,Integer> map=new HashMap<>();
     Random r=new Random();
     map.put("Math",r.nextInt(100));
     map.put("Physics",r.nextInt(100));
     map.put("English", r.nextInt(100));
     map.put("Chemistry", r.nextInt(100));
     System.out.println(map);
     for(Map.Entry<String,Integer> e:map.entrySet())
    	 System.out.println(e.getKey()+" "+e.getValue());
	}
}
//输出
{English=26, Chemistry=18, Math=69, Physics=93}
English 26
Chemistry 18
Math 69
Physics 93

1.5.4.Map的数学应用

containsAll()、removeAll()、retainAll()等成批操作支持Map运算,例如:

//1.判断子集
if(m1.entrySet().containsAll(m2.entrySet())){
 ……
}

//2.判断两个Map有无共同的键集
//public Set<K> keySet();
System.out.println(m1.keySet().retainAll(m2.keySet()));

//3.删去共同键-值对
m1.entrySet().removeAll(m2.entrySet());

//4.实现多重Map,即一个键映射多个值,可以用List实例存放值
Map<String,List<String>> map=new HashMap<>();

1.6.SortedSet

SortedSet是按升序维护元素的Set,集合中的元素如果没有实现java.lang包的Comparable接口而无法比较,SortedSet就要提供java.util包的Comparable接口方法控制元素的次序。列举SortedSet元素时按其次序进行,转换成数组时元素仍是有序的。

SortedSet接口的核心结构是:

public interface SortedSet<E> extends Set<E>{
 //范围视图
 SortedSet<E> subSet(E fromElement,E toElement); //取[from,to)范围内的子集
 SortedSet<E> headSet(E toElement); //取[最小值,to)范围内的子集
 SortedSet<E> tailSet(E fromElement); //取[from,最大值]范围内的子集

 //端点
 E first(); //返回最小元素
 E last();  //返回最大元素

 //Comparator访问
 Comparator<? super E> comparator();
}

1.6.1.SortedSet的实现

TreeSet类实现了SortedSet接口,它有4个构造方法:

1.TreeSet()
2.TreeSet(Collection<? extends E> c)
3.TreeSet(Comparable<? super E> comparable)
4.TreeSet(SortedSet<E> s)

暂时寄了


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值