java必须精通第六课

java类集

在使用各类接口时,如果没有指定泛型,则肯定会出现警告信息,此时泛型将被擦除,而全部使用Object接收。
如果现在要保存一组对象,按照之前的做法则只能使用对象数组,但是使用对象数组操作本身有一个限制,就是数组长度有限制,而通过一些数据结构的操作,如链表,则可以完成动态对象数组的操作,但是这些如果全部由开发人员来做,则肯定也是比较麻烦的。
类集框架恰好解决了这一问题,所谓的类集就是一个动态的对象数组,是对一些实现好的数据结构进行了包装,这样在使用时,就回非常的方便。而且最重要的就是类集框架本身不受对象数组长度的限制。
类集框架被设计拥有以下几个特性:
1.这种框架是高性能的,对基本类集(动态数组、链接表、树和散列表)的实现是高效率的,所以一般很少需要人工对这些“数据引擎”编写代码
2.框架必须允许不同类型的类集以相同的方式和高度互操作方式工作。
3.类集必须容易拓展和修改、为了实现这一目标,类集框架被设计成包含了一组标准接口。
类集框架主要接口
java类集最常使用的类集接口是:Collection、List、Set、Map、Iterator、ListIterator、Enumeration、SortedSet、SortedMap、Queue、Map.Entry
主要类集接口
主要类集接口
继承关系如下:
继承关系
SortedXxx定义的接口都属于排序接口。

Collection接口

定义:public interface Collection extends Iterable
从接口的定义可以看出,此接口使用了泛型定义,在操作时必须指定具体的操作类型,这样可以保证操作类集的安全性,避免发生ClassCastException异常。
Collection接口方法定义
Collection接口方法定义
在一般开发中,往往很少直接使用Collection接口开发,基本上都是使用其子接口。子接口主要有List,Set,Queue和SortedSet
Collection子类接口定义:
Collection接口虽然是集合的最大接口,但如果直接使用Collection接口进行操作,则表示的操作意义不明确 ,所以在java开发中不提倡直接使用Collection接口,主要的子接口介绍下:
List:可以存放重复的内容
Set:不能存放重复的内容,所有的重复内容靠hashCode和equals两个方法区分。
Queue:队列接口
SortedSet:可以对集合中的数据进行排序。

List接口:

List接口的定义:List是Collection的子接口,其中可以保存各个重复的内容。
public interface List extends Collection
List接口大量的扩充Collection接口
List接口拓展方法
List接口的常用子类:
1.ArrayList
ArrayList是List子类,可以直接通过对象的多态性为List接口实例化。
public class ArrayList extends AbstractList implements List,RandomAccess,Cloneable,Serializable
从定义可以看出来ArrayList继承自AbstractList
public abstract class AbstractList extends AbstractCollection implements List
此类实现了List接口,所以可以直接使用ArrayList为List接口实例化。

List添加元素实例
public class Test3{
public static void main(String[] args){
	List list=new ArrayList<>();
	list.add("111");
	list.add(1, "222");
	list.add(0,"000");
	list.add(1,"101");
	System.out.print(list);
  }
}
结果:
[000, 101, 111, 222]
使用List中的add(int index,E element)可以在集合中的指定位置增加元素(如果向之前已存在的元素
下标添加内容,那么之前的内容和下标会后移),其他两个add()和addAll()方法在集合的最后进行内容追加。

List删除
public class Test3{
public static void main(String[] args){
	List list=new ArrayList<>();
	list.add(0,"000");
	list.add("111");
	list.add(2, "222");
	System.out.println(list);
	list.remove(0);
	System.out.println(list);
	list.remove("111");
	System.out.print(list);
	list.removeAll(list);
	System.out.print(list);
  }
}
结果:
[000, 111, 222]
[111, 222]
[222]
[]

使用remove(Object o)方法删除对象说明:
在集合中可以插入任意类型的对象,在实例中是以插入String类的对象,所以在使用remove()方法删除时,
可以直接删除;而对于自定义的类如果要通过此种方式删除,则必须在类中覆写Object类中equals和
hashCode两个方法

输出List内容:
1.从前向后输出
public class Test3{
public static void main(String[] args){
	List list=new ArrayList<>();
	list.add(0,"000");
	list.add("111");
	list.add(2,"222");
	list.add("333");
	for(int i=0;i<list.size();i++) {
		System.out.print(list.get(i)+",");
	}
  }
}
结果:000,111,222,333,

2.从后向前输出
public class Test3{
public static void main(String[] args){
	List list=new ArrayList<>();
	list.add(0,"000");
	list.add("111");
	list.add(2,"222");
	list.add("333");
	for(int i=list.size()-1;i>=0;i--) {
		System.out.print(list.get(i)+",");
	}
  }
}
结果:333,222,111,000,
从运行结果来看,List集合中数据增加的顺序就是输出后的顺序,本身顺序不会发生改变。
这就是List的特点:数据有序可以重复

将集合变为对象数组
在Collection中定义了toArray()方法,此方法可以将集合变为对象数组,但是由于在类集声明时已经
通过泛型指定了集合中元素类型,所以在接收时,要使用泛型指定的类型
public class Test3{
public static void main(String[] args){
	List<String> list=new ArrayList<>();
	list.add("111");
	list.add("222");
	list.add("333");
	String str[]=list.toArray(new String[]{});
	System.out.println(Arrays.toString(str));
	for(int i=0;i<str.length;i++) {
		System.out.println(str[i]);
	}
	Object ojb[]=list.toArray();
	for(int j=0;j<ojb.length;j++) {
		String temp=(String) ojb[j];
		System.out.println(temp);
		}
  }
}
结果:
[111, 222, 333]
111
222
333
111
222
333

集合的其他相关操作:
public class Test3{
public static void main(String[] args){
	List<String> list=new ArrayList<>();
	list.add("111");
	list.add("222");
	list.add("333");
	list.add("444");
	list.add("555");
	
	//判断集合是否为空?
	boolean flag=list.isEmpty();
	System.out.println(flag);
	//取出里面部分集合
	List<String> subList=list.subList(0, 2);
	System.out.println(subList);
	//判断元素所在位置
	int num1=list.indexOf("444");
	System.out.println(num1);
	int num2=list.lastIndexOf("222");
	System.out.println(num2);
  }
}
结果
false
[111, 222]
3
1

Vector:
Vector在使用上和List一样,都是集成abstractList,因为之前JDK的版本的用户一直使用,所以改动保留了这个类,在方法和使用和List的子类ArrayList没有什么区别。其它方面的区别如下
主要区别

LinkList子类与Queue接口

LinkList表示一个链表的操作类,即java已经为开发者提供好了一个链表程序,开发者直接使用即可,无须重新开发。
public class LinkedList
extends AbstractSequentialList
implements List, Deque, Cloneable, java.io.Serializable
从类的定义来看,此类虽然实现了List接口,但也同时实现了Deque接口。
public interface Deque extends Queue
Queue表示队列操作接口,采用FIFO(先进先出)的方式操作
Queue是Collection的子接口
public interface Queue extends Collection
Queue也可以增加元素并输出
Queue接口定义的方法
LinkedList部分方法

实例:链表的开头和结尾增加数据
public class Test3{
public static void main(String[] args){
	//因为List类没有addFirst和addLast方法
	//所以必须直接使用LinkedList类
	LinkedList<String> list=new LinkedList<String>();
	list.add("bbb");
	list.add("ccc");
	list.add("ddd");
	System.out.println(list);
	list.addFirst("aaaa");
	System.out.println(list);
	list.addLast("eeee");
	System.out.println(list);
  }
}
结果:
[bbb, ccc, ddd]
[aaaa, bbb, ccc, ddd]
[aaaa, bbb, ccc, ddd, eeee]

实例:找到链表头
在LinkedList中存在很多找到链表头的操作,最常用的有如下几种
找到表头:public E element()
找到不删除表头: public E peek()
找到并删除表头: public E poll()

public class Test3{
public static void main(String[] args){
	//因为List类没有addFirst和addLast方法
	//所以必须直接使用LinkedList类
	LinkedList<String> list=new LinkedList<String>();
	list.add("A");
	list.add("B");
	list.add("C");
	String head1=list.element();
	System.out.println(head1+"--"+list);
	String head2=list.peek();
	System.out.println(head2+"--"+list);
	String head3=list.poll();
	System.out.println(head3+"--"+list);
  }
}
结果:
A--[A, B, C]
A--[A, B, C]
A--[B, C]
都能找到表头,而poll方法直接删除了表头
Set接口

Set接口也是Collection接口的子接口,但是与Collection和List接口不同的是,Set接口中不能添加重复的元素
Set接口的特点是数据无序不可以重复。
public interface Set extends Collection
从定义可以知道,Set接口 与List接口的定义并没有太大的区别。但是Set接口的主要方法与Collection方法是一只的,也就是说Set接口并没有对,Collection方法进行扩充,只是比Collection的接口更加严格了,不能增加重复元素。
Set接口的实例无法像List接口那样可以进行双向输出,因为此接口没有提供像List接口定义的get(int index)方法。

Set接口常用子类
1.HashSet
HashSet是Set接口的一个子类,主要的特点是:里面不能存放重复的元素,而且采用散列的存储方式,所以
没有顺序。
public class Test3{
public static void main(String[] args){
	Set<String> set=new HashSet<String>();
	set.add("B");	
	set.add("A");
	set.add("B");
	set.add("C");
	set.add("D");
	set.add("E");
	set.add("F");
	set.add("G");
	set.add("H");
	set.add("D");
	System.out.println(set.toString());
  }
}
结果:[A, B, C, D, E, F, G, H]
从程序结果可以看出,对于重复的元素只会添加一次,集合中元素加入的顺序并不是集合中保存的顺序。
有序的存放TreeSet

如果想对输入的数据进行进行有序排列则要使用TreeSet子类
public class TreeSet extends AbstractSet
implements NavigableSet, Cloneable, java.io.Serializable
TreeSet继承了AbstractSet
public abstract class AbstractSet extends AbstractCollection implements Set

public class Test3{
public static void main(String[] args){
	Set<String> set=new TreeSet<String>();
	set.add("B");	
	set.add("A");
	set.add("G");
	set.add("C");
	set.add("D");
	set.add("E");
	set.add("F");
	set.add("H");
	set.add("D");
	Iterator<String> iterator=set.iterator();
	while(iterator.hasNext()) {
		System.out.println(iterator.next()+"-");
	}
  }
}
结果:
A-
B-
C-
D-
E-
F-
G-
H-
可以看出来,插入数据是没有顺序的,但输出之后数据是有序的。所以TreeSet是可以排序的子类。

利用TreeSet给对象排序
public class Person{
	private String name;
	private int age;
	
	public Person(String name,int age) {
		this.name=name;
		this.age=age;
	}

	@Override
	public String toString() {
		return "姓名:"+this.name+";"+"年龄:"+this.age;
		
	}
}
public class Test3{
public static void main(String[] args){
	Set<Person> set=new HashSet<>();
	set.add(new Person("李四", 40));
	set.add(new Person("王五", 50));
	set.add(new Person("张三", 30));
	set.add(new Person("李四", 40));
	System.out.print(set);
  }
}
结果:
[姓名:李四;年龄:40, 姓名:李四;年龄:40, 姓名:张三;年龄:30, 姓名:王五;年龄:50]
结果来看,我们还没有用TreeSet进行排序,但是发现一个问题,就是对象出现了重复,正常Set是不允许
重复的。
HashSet元素不重复的功能是通过HashMap的key唯一来实现的。再向HashSet中添加对象时,首先通过
hashCode值来判断对象是否相同,如果不同,则直接向set中添加,相同则通过比较equals来比较元素是否
相同。同时,hashSet通过hashCode的值来选择将添加的元素放到相应的“位置”。
因为是new Person的新对象所以hashCode值不会重复,所以数据会加入到hashSet中。解决方法:就是自己
手动覆写Object的hashCode和equals方法
public class Person{
	private String name;
	private int age;
	
	public Person(String name,int age) {
		this.name=name;
		this.age=age;
	}
	@Override
	public boolean equals(Object obj) {
		// TODO Auto-generated method stub
		if(this==obj) {
			return true;
		}
		if(!(obj instanceof Person)) {
			return false;	
		}
		Person p=(Person) obj;
		if(this.name.equals(p.name)&&this.age==p.age) {
			return true;
		}else {
			return false;
		}
	}
	@Override
	public int hashCode() {
		// TODO Auto-generated method stub
		return this.name.hashCode()*this.age;
	}

	@Override
	public String toString() {
		return "姓名:"+this.name+";"+"年龄:"+this.age;
		
	}
}
public class Test3{
public static void main(String[] args){
	Set<Person> set=new HashSet<>();
	set.add(new Person("李四", 40));
	set.add(new Person("王五", 50));
	set.add(new Person("张三", 30));
	set.add(new Person("李四", 40));
	System.out.print(set);
  }
}
结果:
[姓名:王五;年龄:50, 姓名:李四;年龄:40, 姓名:张三;年龄:30]
可以看出,数据没有重复。

接下来我们进行排序
要使用TreeSet进行排序,就要比较的类实现Comparable接口,并覆写ComparaTo方法
因为需要知道,根据什么去比较大小

实例:根据年龄从小到大排序
public class Person implements Comparable<Person>{
	private String name;
	private int age;
	
	public Person(String name,int age) {
		this.name=name;
		this.age=age;
	}
	@Override
	public boolean equals(Object obj) {
		if(this==obj) {
			return true;
		}
		if(!(obj instanceof Person)) {
			return false;	
		}
		Person p=(Person) obj;
		if(this.name.equals(p.name)&&this.age==p.age) {
			return true;
		}else {
			return false;
		}
	}
	@Override
	public int hashCode() {
		return this.name.hashCode()*this.age;
	}

	@Override
	public String toString() {
		return "姓名:"+this.name+";"+"年龄:"+this.age;
		
	}
	@Override
	public int compareTo(Person o) {
		if(this.age>o.age) {
			return 1;
		}else if(this.age<o.age) {
			return -1;
		}else {
			return this.name.compareTo(o.name);
		}
	}
}

public class Test3{
public static void main(String[] args){
	Set<Person> set=new TreeSet<Person>();
	set.add(new Person("李四", 40));
	set.add(new Person("王五", 50));
	set.add(new Person("张三", 30));
	set.add(new Person("李四", 40));
	System.out.print(set);
  }
}
结果:
[姓名:张三;年龄:30, 姓名:李四;年龄:40, 姓名:王五;年龄:50]
数据没有重复,并且按照年龄排序。
SortedSet

从TreeSet类的定义接口可以发现,TreeSet中实现了SortedSet接口,此接口主要用于排序操作,
即实现此接口的子类都属于排序的子类。
public interface SortedSet extends Set
SortedSet接口中定义的方法

public class Test3{
public static void main(String[] args){
	SortedSet<String> sortedSet=new TreeSet<String>();
	sortedSet.add("A");
	sortedSet.add("B");
	sortedSet.add("C");
	sortedSet.add("D");
	sortedSet.add("E");
	System.out.println(sortedSet);
	System.out.println(sortedSet.first());
	System.out.println(sortedSet.last());
	System.out.println(sortedSet.headSet("C"));
	System.out.println(sortedSet.tailSet("C"));
	System.out.println(sortedSet.subSet("C","E"));
  }

集合的输出

如果要输出Collection、Set集合中的内容,可以将其转换为对象数组输出,而使用List则可以直接通过get()方法输出,但是这些都不是集合的标准输出方式。在类集中提供了一下四种输出方式:
Iterator:迭代输出,是使用最多的输出方式
ListIterator:是Iterator的子接口,专门用于输出List中的内容。
foreach:可以输出数组或者集合
最常使用的就是Iterator迭代输出
只要碰到集合输出操作,就一定使用Iterator接口,因为这是标准的做法。所谓的迭代输出就是将元素一个一个进行判断,判断其是否有内容,如果有内容则把内容取出。
public interface Iterator
Iterator接口常用方法

Iterator
实例:输出内容
public class Test3{
public static void main(String[] args){
	List<String> list=new ArrayList<String>();
	list.add("I ");
	list.add("am ");
	list.add("beer!");
	Iterator<String> iterator=list.iterator();
	while(iterator.hasNext()) {
		System.out.print(iterator.next());
	  }
	}
}
结果:
I am beer!

实例:删除元素
public class Test3{
public static void main(String[] args){
	List<String> list=new ArrayList<String>();
	list.add("I");
	list.add("am");
	list.add("beer!");
	Iterator<String> iterator=list.iterator();
	while(iterator.hasNext()) {
		String str=iterator.next();
		if("am".equals(str)) {
			iterator.remove();
		}else {
			System.out.print(str+" ");
		}
	  }
	}
}
结果:
I beer! 
双向迭代ListIterator

Iterator接口主要是实现由前向后输出,而如果想实现从后向前和从前向后的双向输出,就要使用到Iterator的子接口ListIterator:
public interface ListIterator extends Iterator
ListIterator接口常用方法
与Iterator接口不同的是,ListIterator接口只能通过List接口实例化,即只能输出List接口中的内容。
在List接口中定义了可以为ListIterator接口实例化的方法。
public ListItetaror listIterator()

实例:进行双向迭代
public class Test3{
public static void main(String[] args){
	List<String> list=new ArrayList<String>();
	list.add("I");
	list.add("am");
	list.add("beer!");
	
	ListIterator<String> listIterator=list.listIterator();
	System.out.print("由前向后输出");
	while(listIterator.hasNext()) {
		System.out.print(listIterator.next()+"、");
	  }
	System.out.println();
	System.out.print("由后向前输出");
	while(listIterator.hasPrevious()) {
		System.out.print(listIterator.previous()+"、");
	  }
	}
}
结果:
由前向后输出I、am、beer!、
由后向前输出beer!、am、I、

注意:在使用ListListIterator进行双向输出时,如果想完成由后向前输出,则一定要进行由前向后输入
(本人已验证,直接右后向前输出,没有结果)

实例:增加和替换元素
public class Test3{
public static void main(String[] args){
	List<String> list=new ArrayList<String>();
	list.add("I");
	list.add("am");
	list.add("beer!");
	
	ListIterator<String> listIterator=list.listIterator();
	System.out.print("由前向后输出");
	while(listIterator.hasNext()) {
		String str=listIterator.next();
		System.out.print(str+"、");
		listIterator.set("M"+str);
	  }
	listIterator.add("Tail");
	System.out.println();
	System.out.print("由后向前输出");
	while(listIterator.hasPrevious()) {
		System.out.print(listIterator.previous()+"、");
	  }
	}
}
结果:
由前向后输出I、am、beer!、
由后向前输出Tail、Mbeer!、Mam、MI、

使用set方法修改每一个元素内容
使用add方法,向集合添加新元素,添加到尾端。
foreach
public class Test3{
public static void main(String[] args){
	List<String> list=new ArrayList<String>();
	list.add("I");
	list.add("am");
	list.add("beer!");
	
	for(String str:list){
		System.out.print(str+"、");
		}
	}
}
结果:
I、am、beer!、

Map接口

上面所说的Collection、Set、List接口都属于单值操作,即每次只能操作一个对象,而Map不同的是,每次可以操作一对对象,Map使用key-value的形式存储在集合中。
public interface Map<K,V>
Map接口常用方法
Map.Entry接口简介
Map.Entry是Map内部定义的一个接口,专门用来保存key-value的内容 。
public static interface Map.Entry<K,V>
Map.entry是使用static关键字声明的内部接口,此接口可以通过“外部类.内部类”的形式直接调用。
Map.Entry接口常用方法
对于Map集合来讲,实际上是将key-value的数据保存在了Map.Entry实例之后,再在Map集合中插入一个Map.Entry实例化对象。
Map实现原理
Map接口的常用子类
Map接口也必须依靠其子类实例化,常用子类如下:
HashMap:无序存放,key不允许重复
Hashtable:无序存放,key不允许重复
TreeMap:可以排序的Map集合,按集合中的key排序,key不允许重复。
WeakHashMap:弱引用的Map集合,当集合中的某些内容,不在使用时清楚掉无用的数据,使用GC进行回收。
IdentityHashMap:key可以重复的Map集合。

HashMap

HashMap本身是Map的子类,直接使用此类为Map接口实例化即可
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
HashMap是AbstractMap的子类:
public abstract class AbstractMap<K,V> implements Map<K,V>

实例:HashMap操作
public class Test3{
public static void main(String[] args){
	Map<String,String> map=new HashMap<String, String>();
	map.put("one", "I am one");
	map.put("two", "I am two");
	map.put("three", "I am three");
	String one=map.get("one");
	System.out.print(one);
	}
}
结果:
I am one

判断key是否存在
public class Test3{
public static void main(String[] args){
	Map<String,String> map=new HashMap<String, String>();
	map.put("one", "I am one");
	map.put("two", "I am two");
	map.put("three", "I am three");
	if(map.containsKey("two")) {
		System.out.print("搜索的key存在");
		}
	}
}
结果:
搜索的key存在

实例:输出全部的key
在Map中提供了一个叫KeySet方法,可以将一个Map中的全部Key变为一个Set集合,一旦有个Set实例,就
可以用Iterator迭代输出,但是在操作时一定要注意,接收Set集合中指定泛型和Map中key的泛型保持一致。
public class Test3{
public static void main(String[] args){
	Map<String,String> map=new HashMap<String, String>();
	map.put("one", "I am one");
	map.put("two", "I am two");
	map.put("three", "I am three");
	Set<String> set=map.keySet();
	Iterator<String> iterator=set.iterator();
	while(iterator.hasNext()) {
		System.out.println("key是"+iterator.next());
	  }
	}
}
结果:
key是one
key是two
key是three

输出全部的value值
要输出全部的value,则使用values()方法,此方法返回类型是Collection
public class Test3{
public static void main(String[] args){
	Map<String,String> map=new HashMap<String, String>();
	map.put("one", "I am one");
	map.put("two", "I am two");
	map.put("three", "I am three");
	Collection<String> collection=map.values();
	Iterator<String> iterator=collection.iterator();
	while(iterator.hasNext()) {
		System.out.println("map的value为:"+iterator.next());
	  }
	}
}
结果:
map的value为:I am one
map的value为:I am two
map的value为:I am three
Hashtable

Hashtable也是Map中的一个子类,与Vector退出时间一样都属于旧的操作类,其使用上也和之前没有什么太大区别(HashMap和Hashtable使用操作方法上一样的,例子同上)
系统上区别:
HashMap和Hashtable比较

TreeMap排序的子类

TreeMap主要功能是按照key进行排序

实例:按照key排序 TreeMap
public class Test3{
public static void main(String[] args){
	Map<String,String> map=new TreeMap<String,String>();
	map.put("C", "I am three");
	map.put("B", "I am two");
	map.put("A", "I am one");
	map.put("D", "I am four");
	Set<String> set=map.keySet();
	Iterator<String> iterator=set.iterator();
	while(iterator.hasNext()) {
		System.out.println(map.get(iterator.next()));
	}
  }
}
结果:
I am one
I am two
I am three
I am four
可以看出来,已经通过key进行排序了
**使用自定义类作为key时,需要实现Comparable接口**
TreeMap可以按照key排序,之前的代码使用的是String类作为key,因为String类本身已经实现了
Comparable接口,所以程序执行不会有任何问题,而如果使用自定义的一个类作为key,则此类必须
实现Comparable接口,否则将出现类型转换异常。
弱引用类WeakHashMap

HashMap和Hashtable以及TreeMap这些Map的子类都使用强引用保存的,即里面的内容不管是否使用,都始终留在集合中,如果希望集合自动清理暂时不用的数据就使用WeakHashMap类,这样,当进行垃圾收集时会释放掉集合的垃圾信息。
public class WeakHashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>

实例:强引用和弱引用Map子类对比
public class Test3{
public static void main(String[] args){
	Map<String, String> hashMap=new HashMap<String, String>();
	hashMap.put("A", "I am A");
	hashMap.put("B", "I am B");
	hashMap.put("C", "I am C");
	hashMap.put("D", "I am D");
	System.gc();
	System.out.println(hashMap);
	Map<String, String> weakMap=new WeakHashMap<String, String>();
	weakMap.put(new String("one"), "I am one");
	weakMap.put(new String("two"), "I am two");
	weakMap.put(new String("three"), "I am three");
	System.gc();
	System.gc();
	weakMap.put(new String("four"), "I am four");
	System.out.println(weakMap);
   }
}
结果:
{A=I am A, B=I am B, C=I am C, D=I am D}
{four=I am four}
注意这里weakMap.put(new String("one"), "I am one");必须使用new String的方式,因为这样
是弱引用,弱引用的key才会被垃圾回收机制回收。

Map接口使用注意事项

1.不能直接使用迭代输出Map中的全部内容
对于Map接口来说,其本身是不能使用迭代(Iterator、foreach)进行输出的,因为Map中的每一个位置存放的是一对值,(key-value),而Iterator每次只能找到一个值,所以如果非要使用迭代进行输出,则必须按照以下步骤进行输出
(1)将Map的实例通过entrySet()方法变为Set接口对象
(2)通过Set接口实例化为Iterator
(3)通过Iterator迭代输出,每个内容都是Map.Entry的对象
(4)通过Map.Entry进行key-value的分离

public class Test3{
public static void main(String[] args){
	Map<String, String> hashMap=new HashMap<String, String>();
	hashMap.put("A", "I am A");
	hashMap.put("B", "I am B");
	hashMap.put("C", "I am C");
	hashMap.put("D", "I am D");
	//方式一:Iterator迭代方式输出
	System.out.println("方式一:Iterator迭代方式输出");
	Set<Entry<String, String>> set=hashMap.entrySet();
	Iterator<Entry<String, String>> iterator=set.iterator();
	while(iterator.hasNext()) {
		Entry<String, String> entry=iterator.next();
		System.out.println(entry.getKey()+"--"+entry.getValue());
	}
	//方式二:foreach循环方式输出
	System.out.println("方式二:foreach循环方式输出");
	for(Map.Entry<String, String> map:hashMap.entrySet()) {
		System.out.println(map.getKey()+"--"+map.getValue());
	}
	
   }
}
结果:
方式一:Iterator迭代方式输出
A--I am A
B--I am B
C--I am C
D--I am D
方式二:foreach循环方式输出
A--I am A
B--I am B
C--I am C
D--I am D
foreach语法将集合中的每一个元素用Map.Entry类型对象接收,之后在进行key和value的分离

2.直接使用非系统类作为key
例如使用一个Person对象类作为Map的key,即这样的自定义对象表示Map的key,则对象所在的类中一定要覆写equalse和hashCode方法,否则无法找到对应的value(实例不举了,用法没什么区别)

可以重复key的Map集合IdentityHashMap
public class Test3{
public static void main(String[] args){
	Map<String, String> map=new IdentityHashMap<String,String>();
	 map.put(new String("A"), "I am three");
	 map.put(new String("A"), "I am two");
	 map.put(new String("C"), "I am one");
	 map.put(new String("C"), "I am four");
	 Set<Entry<String, String>> set=map.entrySet();
	 Iterator<Entry<String, String>> itetator=set.iterator();
	 while(itetator.hasNext()) {
		 Entry<String, String> entry=itetator.next();
		 System.out.println(entry.getKey()+"-"+entry.getValue());
	 }
  }
}
结果:
A-I am three
C-I am four
C-I am one
A-I am two
可以看出,允许重复,只要两个对象的key地址不同就可以。这就是IdentityHashMap的功能。
SortedMap接口

SortedMap是排序接口,只要实现了此类接口的子接口,都属于排序的子类,TreeMap也是此接口的一个子类
Sorted接口拓展方法

public class Test3{
public static void main(String[] args){
	 SortedMap<String, String> sort=new TreeMap<String, String>();
	 sort.put("A", "is A");
	 sort.put("B", "is B");
	 sort.put("C", "is C");
	 sort.put("D", "is D");
	 sort.put("E", "is E");
	 System.out.println("全部内容"+sort);
	 System.out.println("第一个key--"+ sort.firstKey());
	 System.out.println("最后一个key--"+ sort.lastKey());
	 
	 sort.headMap("B");//取key为B以上的元素组合
	 sort.subMap("B","C");//取key为B和key为C之间的元素组合
	 sort.tailMap("D");//取key为D一下的元素组合
  }
}
结果:
全部内容{A=is A, B=is B, C=is C, D=is D, E=is E}
第一个key--A
最后一个key--E

集合工具类Collections

在集合应用开发中,集合若干个接口和若干个子类是最常用的,但在JDK中提供了一种集合操作工具类–Collections,可以直接通过此类方便的操作集合。
public interface Collection extends Iterable
Collections类常用方法
Collections

实例一:返回不可变集合
Collections类中可以返回空的List、Set、Map集合,但是通过这种方式返回的对象是无法进行增加数据的
因为在这些操作中并没有实现add()方法
public class Test3{
public static void main(String[] args){
	List list=Collections.emptyList();
	list.add("I am list");
  }
}
结果:
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.util.AbstractList.add(AbstractList.java:148)
	at java.util.AbstractList.add(AbstractList.java:108)
	at myTest.Test3.main(Test3.java:9)
	报了异常,表示不支持方法异常,因为没有找到add()方法。

实例二:集合增加内容
使用addAll()方法可以为一个集合增加内容,此方法可以接收可变参数,所以可以传递任意多的参数作为集合
内容。
public class Test3{
public static void main(String[] args){
	List<String> list=new ArrayList<String>();
	Collections.addAll(list, "A","B","C");
	Iterator<String> iterator=list.iterator();
	while(iterator.hasNext()) {
		System.out.print(iterator.next()+"--");
	}
  }
}
结果:
A--B--C--

实例操作三:反转集合中的内容
直接使用Collections类中的reverse()方法即可以将集合中的内容反转保存
public class Test3{
public static void main(String[] args){
	List<String> list=new ArrayList<String>();
	Collections.addAll(list, "A","B","C");
	Collections.reverse(list);
	Iterator<String> iterator=list.iterator();
	while(iterator.hasNext()) {
		System.out.print(iterator.next()+"--");
	}
  }
}
结果:
C--B--A--

实例操作四:检索内容
直接通过Collections类中的binarySearch()方法即可完成内容的检索,检索之后会返回内容的位置。
public class Test3{
public static void main(String[] args){
	List<String> list=new ArrayList<String>();
	Collections.addAll(list, "A","B","C");
	int num=Collections.binarySearch(list, "B");
		System.out.print(num);
  }
}
结果:1

实例操作五:替换集合中的内容
直接通过Collections类中的replaceAll()方法,可以替换集合中的指定内容。
public class Test3{
public static void main(String[] args){
	List<String> list=new ArrayList<String>();
	Collections.addAll(list, "A","B","C");
	boolean sign=Collections.replaceAll(list, "B", "b");
	if(sign) {
		Iterator<String> iterator= list.iterator();
		while(iterator.hasNext()) {
			System.out.print(iterator.next()+":");
		}
	}
  }
}
结果:
A:b:C:

实例操作六:集合排序
直接通过Collections类中的sort()方法对一个集合进行排序操作,但是要求集合中的每一个对象必须实现
Comparable接口
public class Test3{
public static void main(String[] args){
	List<String> list=new ArrayList<String>();
	Collections.addAll(list, "D");
	Collections.addAll(list, "B");
	Collections.addAll(list, "A");
	Collections.addAll(list, "C");
	
		Iterator<String> iterator= list.iterator();
		System.out.print("排序之前");
		while(iterator.hasNext()) {
			System.out.print(iterator.next()+":");
		}
		System.out.println();
		Collections.sort(list);
		System.out.print("排序之后");
		Iterator<String> iterator2= list.iterator();
		while(iterator2.hasNext()) {
			System.out.print(iterator2.next()+":");
		}
  }
}
结果:
排序之前D:B:A:C:
排序之后A:B:C:D:
这里直接使用String类完成,String类本身已经实现好了Comparable接口,如果自定义类,则一定要实现
Comparable接口,否则会出现类型转换异常

实例七:交换指定位置内容
直接使用Collections类的swap()方法可以把集合中两个位置的内容进行交换
public class Test3{
public static void main(String[] args){
	List<String> list=new ArrayList<String>();
	Collections.addAll(list, "C");
	Collections.addAll(list, "B");
	Collections.addAll(list, "A");
	Collections.addAll(list, "D");
	
		Iterator<String> iterator= list.iterator();
		System.out.print("交换之前");
		while(iterator.hasNext()) {
			System.out.print(iterator.next()+":");
		}
		System.out.println();
		Collections.swap(list, 0, 2);
		System.out.print("交换之后");
		Iterator<String> iterator2= list.iterator();
		while(iterator2.hasNext()) {
			System.out.print(iterator2.next()+":");
		}
  }
}
结果:
交换之前C:B:A:D:
排序之后A:B:C:D:

其它集合类

Stack类

栈是采用先进后出的存储方式,每一个栈都包括栈顶,每次出栈是将栈顶的数据取出
栈的入栈和出栈操作
栈的应用:
在浏览器中存在一个后退的按钮,每次后退都后退到上一个步操作,那么实际上这就是一个栈的应用,采用的是先进后出的原则。
在java中使用Stack类对栈进行操作,Stack类是Vector的子类。
class Stack extends Vector
与之相反的是队列Queue,原则是先进先出
Stack类常用方法

实例:完成入栈和出栈
public class Test3{
public static void main(String[] args){
	Stack<String> stack=new Stack<String>();
	//入栈
	stack.push("A");
	stack.push("B");
	stack.push("C");
	int i=0;
	boolean flag=true;
	while(flag) {
		if(!stack.empty()) {
			i++;
			System.out.println("第"+i+"个出栈"+stack.pop());
		}else {
		System.out.println("栈已经空了");
		i=0;
		flag=false;
	  }
	}
  }
}
结果:
第1个出栈C
第2个出栈B
第3个出栈A
栈已经空了
属性类Properties

属性文件指的是xxx.properties,在一个属性文件保存多个属性,每一个属性是直接用字符串表示出来的“key=value”对的形式保存起来的,要轻松操作这些属性文件中的属性,可以使用Properties类完成。
Properties类本身Hashtable的子类,既然是其子类也是按照key和value的形式存储数据的
class Properties extends Hashtable<Object,Object>
Properties主要方法
Properties
虽然Properties是Hashtable的子类,也可以像Map那样使用put()方法保存任意类型数据,但一般属性都是由字符串组成的,所以在使用本类时本书只关心Properties类本事的方法。
XML(可拓展的标记语言)文件格式说明
XML是现在开发使用最广泛的一门语言,所有的属性内容可以通过storeToXML和LoadFromXML两个方法以XML文件格式进行保存和读取,但是使用XML保存时,将按照指定的文档格式进行存放,如果格式出错则无法读取。

实例:Properties设置和取得属性
可以使用setProperty()和getProperty()方法设置和取得属性,操作时要以String为操作类型
public class Test3{
public static void main(String[] args){
	Properties p=new Properties();
	p.setProperty("name", "zhangsan");
	p.setProperty("address", "BeiJing");
	System.out.println(p.getProperty("name"));
	System.out.println(p.getProperty("address"));
	//属性不存在时,提供默认的返回值
	System.out.println(p.getProperty("age","default"));
  }
}
结果:
zhangsan
BeiJing
default

实例:将属性保存在普通文件中
public class Test3{
public static void main(String[] args){
	Properties p=new Properties();
	p.setProperty("name", "zhangsan");
	p.setProperty("address", "BeiJing");
	
	String pathname="d:"+File.separator+"testDir"+File.separator+"cui.properties";
	File file=new File(pathname);
	try {
		p.store(new FileOutputStream(file), "人员属性");
	} catch (FileNotFoundException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
  }
}
结果:
文件成功保存了数据(文件夹是存在的,但是文件是程序自己创建的)文件内容如下:
#\u4EBA\u5458\u5C5E\u6027
#Thu Jul 25 15:15:04 CST 2019
address=BeiJing
name=zhangsan

实例:从属性文件中读取内容
public class Test3{
public static void main(String[] args){
	Properties p=new Properties();
	String pathname="d:"+File.separator+"testDir"+File.separator+"cui.properties";
	File file=new File(pathname);
		try {
			p.load(new FileInputStream(file));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.print("从文件读取属性为:"+p.getProperty("name"));
  }
}
结果:
从文件读取属性为:zhangsan

实例:将属性保存在XML中
在Properties类中也可以把全部内容以XML格式的内容通过输出流输出,如果要把属性保存在XML文件中,
则文件后缀最好为*.xml
public class Test3{
public static void main(String[] args){
	Properties p=new Properties();
	p.setProperty("name", "pencil");
	p.setProperty("color", "blue");
	String pathname="d:"+File.separator+"testDir"+File.separator+"cui.xml";
	File file=new File(pathname);
		try {
			p.storeToXML(new FileOutputStream(file), "XML to save");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
  }
}
结果:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>XML to save</comment>
<entry key="color">blue</entry>
<entry key="name">pencil</entry>
</properties>

实例:从XML文件取出数据
public class Test3{
public static void main(String[] args){
	Properties p=new Properties();
	String pathname="d:"+File.separator+"testDir"+File.separator+"cui.xml";
	File file=new File(pathname);
		try {
			p.loadFromXML(new FileInputStream(file));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	System.out.print("从xml文件取出的数据为"+p.getProperty("color"));
  }
}
结果:
从xml文件取出的数据为blue

要点总结
1.类集的目的是用来创建动态的对象数组操作。
2.Collection接口是类集中最大的单值操作的父接口,但是一般开发中不会直接使用此接口,而长使用List或者Set接口。
3.List拓展了Collection接口,里面的内容有序可以重复。
4.List接口常用的子类是ArrayList和Vector,在开发中ArrayList性能最高,属于异步处理。而Vector性能较低,属于同步处理。
5.Set接口与Collection接口定义一致,里面的内容是不允许重复的,依靠Object类中的equals和hashCode方法来区分是否是同一个对象。
6.Set接口的常用子类是HashSet和TreeSet,前者是散列存放,没有顺序,后者是顺序存放,使用Comparable进行排序操作。
7.集合的输出要使用Iterator接口完成,Iterator属于迭代输出接口,也可以使用foreach输出。
8.List操作集合可以使用ListIterator进行双向输出操作。
9.Map接口可以存放一对内容“key-value”形式保存,每一对“key-value”都是一个Map.Entry对象实例
10.Map中常用的子类是:HashMap、TreeMap、Hashtable。HashMap属于异步处理,性能较高。
TreeMap属于排序类,按照Comparable指定的顺序对key进行排序,Hashtable属于同步处理,性能较低。
11.类集中提供了Collections工具类完成类集的相关操作。
12.Properties类属于属性操作类,使用属性操作类可以直接操作属性文件,属性文件可以按普通文件*.properties或者XML文件进行保存
13.使用类集可以方便的表示出一对多和多对多的关系。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值