集合

Java中的集合主要由两个接口派生,即CollectionMap。其中Collection接口派生出了List和Set集合,各个接口还提供了不同的实现类。如下图所示



Collection接口

     此接口是集合类的基本接口,它位于集合的顶层。Collection接口的定义如下

public interface Collection<E> extends Iterable<E>

我们可以发现Collection使用泛型技术,所以在操作时必须制定具体的操作类型,有利于集合的安全性。Collection是List和Set接口的父接口。它声明了多个集合类的核心方法,让我们看一下API


虽然Collection是集合类的基本接口,但是一般不会直接使用Collection接口进行操作,而是使用其子接口。常用的Collection主要子接口如下:

  1. List<E>:集合中的元素按照索引值来排序,允许存放重复的元素。List集合与数组相似
  2. Set<E>:集合中的元素不按特定方式排列,不能存在重复的对象,但它的有些实现类能对集合中的元素按照特定方式排序
  3. Sorted<E>:可以对集合中的元素进行排序
  4. Queue<E>:队列接口,通常以现金先出的方式排序各个元素


List接口

   List是一个有序集合,其元素以线性方式储存,集合中允许存放重复的元素,有两个主要的实现类ArrayList和LinkedList

使用List接口可以精确的控制每个元素插入的位置。也可以通过索引访问List中的元素。它不但继承了Collection接口,还进行了扩展增加了更多方法

voidadd(String item, int index)
向滚动列表中索引指示的位置添加指定的项。
booleanaddAll(int index, Collection<? extends E> c)
将指定 collection 中的所有元素都插入到列表中的指定位置(可选操作)。
Eget(int index)
返回列表中指定位置的元
intindexOf(Object o)
返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。
intlastIndexOf(Object o)
返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。
ListIterator<E>listIterator()
返回此列表元素的列表迭代器(按适当顺序)。
Eremove(int index)
移除列表中指定位置的元素(可选操作)。
Eset(int index, E element)
用指定元素替换列表中指定位置的元素(可选操作)。
List<E>subList(int fromIndex, int toIndex)
返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。  区间是左闭右开的【)
ListIterator<E>listIterator(int index)
返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。

数组列表类:ArrayList

public class ArrayList<E>extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, Serializable

通过定义我们可以发现,ArrayList实现了List接口,可以直接通过ArrayList为List接口实例化。ArrayList类是数组列表类,实现了可变长度的数组,允许对集合中的元素进行快速的访问,但是插入和删除速度比较慢

ArrayList集合中,插入一个元素时,列表需要将插入点后面的所有元素向后移动,而在删除一个元素时,需要将被删除元素后面的所有元素向前移动


 向集合中添加元素

        在Collection接口中就已经定义了向集合添加元素的两个方法  add()和addAll()方法

import java.util.Collection;
import java.util.List;
import java.util.ArrayList;
public class ArrayListDemo01 {
	public static void main(String[] args) {
		Collection<String> collection = new ArrayList<String>(); //通过ArrayList实例化Collection
		List<String> list = new ArrayList<String>(); 	//通过ArrayList实例化List
		collection.add("1");			//添加元素			
		collection.add("2");			//添加元素	
		collection.add("3");			//添加元素	
		System.out.println("collection集合:"+collection);//打印集合中的元素
		list.add("A");			//添加元素	
		list.add("C");			//添加元素	
		list.add(1,"B");			//向指定位置添加元素	
		list.addAll(0,collection);	//向指定位置添加一个集合的所有元素
		System.out.println("list集合:"+list); //打印集合中的元素
	}
}
collection集合:[1, 2, 3]
list集合:[1, 2, 3, A, B, C]


删除集合中的元素

ArrayList集合提供了专门用于删除元素的方法,Collection接口提供了remove()和removeAll()方法。在List接口中还提供了可以删除指定位置元素的方法remove(int index)。

import java.util.Collection;
import java.util.List;
import java.util.ArrayList;
public class Demo {
	public static void main(String[] args) {
		Collection<String> collection = new ArrayList<String>(); //通过ArrayList实例化Collection
		List<String> list = new ArrayList<String>(); 	//通过ArrayList实例化List
		collection.add("1");			//添加元素			
		collection.add("2");			//添加元素	
		collection.add("3");			//添加元素	
		System.out.println("collection集合:"+collection);//打印集合中的元素
		list.add("A");			//添加元素	
		list.add("C");			//添加元素	
		list.add(1,"B");			//向指定位置添加元素	
		list.addAll(0,collection);	//向指定位置添加一个集合的所有元素
		System.out.println("list集合删除前:"+list); //打印集合中的元素
		list.remove("B");    //删除元素B
		list.remove(3);     //删除指定位置的元素
		list.removeAll(collection);  //删除指定集合的元素
		System.out.println("list集合删除后:"+list); //打印集合中的元素
		
	}
}
collection集合:[1, 2, 3]
list集合删除前:[1, 2, 3, A, B, C]
list集合删除后:[C]

链表类:LinkedList类

   LinkedList是链表类,采用链表结构保存元素。链表结构的优点是便于向集合插入和删除元素,因为在插入或删除元素时,不需要移动任何元素。在程序中,若经常需要想集合插入或删除元素时,使用LinkedList实例化List接口是较好的选择。但若需要随机访问集合中的元素时,LinkedList集合就显得相对较慢了。

public class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, Serializable
从定义我们可以发现LinkedList实现了List接口,可以存放null元素,LinkedList类还提供了更对的方法,这些方法可以使LinkedList作为堆栈,队列或双向队列


Set接口

  Set是一个不包含重复元素的Collection,Set允许包含null元素,但只允许同一个Set集合只含有一个null元素,也就是说Set集合不能包含重复的元素。

 


下面通过两个例子比较一下HashSet类

  • 没有重写equals()和hashCode()方法的HashSet集合
import java.util.*;
class Person {
	private String name;										//定义name属性
	private int age;											//定义age属性
	public Person(){
		
	}									//无参构造方法
	public Person(String name,int age){							//有参构造方法,初始化成员属性
		this.name=name;
		this.age=age;
	}
	public String toString(){									//重写toString()方法
		return ("姓名:"+name+",年龄:"+age+"\n");
	}
}
public class Demo {
	public static void main(String[] args) {
		Set<Person> set = new HashSet<Person>();			//通过HashSet实例化Set
		set.add(new Person("张三",21));						//添加元素
		set.add(new Person("李四",23));						//添加元素
		set.add(new Person("张三",21));						//添加重复元素
		set.add(new Person("张三",21));						//添加重复元素
		set.add(new Person("王五",20));						//添加元素
		set.add(new Person("赵六",20));						//添加元素
		System.out.println(set);							//输出集合中所有的元素
	}
}
[姓名:张三,年龄:21
, 姓名:赵六,年龄:20
, 姓名:张三,年龄:21
, 姓名:李四,年龄:23
, 姓名:张三,年龄:21
, 姓名:王五,年龄:20
]

    从程序的运行结果来看,HashSet集合中存在3个张三,这与上面所说的Set集合不允许存在两个相同的元素明显矛盾。原因是这三个"张三"是不再同一内存地址的对象!使用Person类中默认的equals()方法比较结果是flase,所以HashSet集合认为他们是不同的元素。

   在Person类中并没有重写equals()方法,所以调用的是Object类的equals()方法。为了更好的比较两个元素是否相等,最好是重写equals()和hashCode()方法

  • 重写equals()和hashCode()方法的HashSet集合
import java.util.*;
class Person {
	private String name;										//定义name属性
	private int age;											//定义age属性
	public Person(){
		
	}									//无参构造方法
	public Person(String name,int age){							//有参构造方法,初始化成员属性
		this.name=name;
		this.age=age;
	}
	
	public String toString(){									//重写toString()方法
		return ("姓名:"+name+",年龄:"+age+"\n");
	}
	public boolean equals(Object o){							//重写equals()方法
		if (this==o) {										//判断当前对象与指定对象是否相等
			return true;}
		if (o==null) {										//判断指定对象是否为空
			return false;}
		if (!(o instanceof Person)) {							//判断指定对象是否为Person的实例
			return false;}
		Person per=(Person)o;								//将指定对象转为Person实例
		if (this.name.equals(per.name)&&this.age==per.age) {		//比较对象的属性是否相等
			return true;
		}else{
			return false;
		}
	}
	public int hashCode(){									//重写hashCode()方法
		final int prime=13;
		int result=13;
		result=prime*result+((name==null)?0:name.hashCode());
		result=prime*result+age;
		return result;
	}

}
public class Demo {
	public static void main(String[] args) {
		Set<Person> set = new HashSet<Person>();			//通过HashSet实例化Set
		set.add(new Person("张三",21));						//添加元素
		set.add(new Person("李四",23));						//添加元素
		set.add(new Person("张三",21));						//添加重复元素
		set.add(new Person("张三",21));						//添加重复元素
		set.add(new Person("王五",20));						//添加元素
		set.add(new Person("赵六",20));						//添加元素
		System.out.println(set);							//输出集合中所有的元素
	}
}
[姓名:李四,年龄:23
, 姓名:赵六,年龄:20
, 姓名:张三,年龄:21
, 姓名:王五,年龄:20
]

重写equals()和hashCode()方法后,集合中的重复元素就没有了,说明 重写equals()和hashCode()方法后可以防止元素的重复。 当我们在程序设计中,需要将某个类的对象保存到HashSet集合中时,该类最好重写equals()和hashCode()方法


TreeSet

public class TreeSet<E>extends AbstractSet<E>implements NavigableSet<E>, Cloneable, Serializable
     TreeSet类实现了java.util包中的Set接口和SortedSet接口。 TreeSet集合中的元素在默认情况下是升序排序(自然排序)。若想自定义自己的排序方式,可以使用TreeSet类的构造方法TreeSet(Comparator comparator)


  • 验证下TreeSet集合的默认排序
public class Demo1 {
	public static <E> void main(String[] args) {
		TreeSet<Integer> treeSet = new TreeSet<Integer>();    //通过TreeSet实例化Set
		treeSet.add(4);
		treeSet.add(2);
		treeSet.add(3);
		treeSet.add(6);
		treeSet.add(3);    //添加重复元素
		treeSet.add(6);    //添加重复元素
		treeSet.add(9);
		System.out.println(treeSet);
	}
}
[2, 3, 4, 6, 9]
    从结果来看, TreeSet集合不允许添加重复元素,而且向TreeSet集合添加元素的顺序是无序的,但是输出却是有序的,默认为升序排序,也就是自然排序

  • 自定义的类排序
import java.util.*;

import com.sun.org.apache.regexp.internal.recompile;
class Person implements Comparable<Person>{   //创建对勾对象进行自定义排序必须实现Comparable接口
	private String name;										//定义name属性
	private int age;											//定义age属性
	public Person(){
		
	}									//无参构造方法
	public Person(String name,int age){							//有参构造方法,初始化成员属性
		this.name=name;
		this.age=age;
	}
	
	public String toString(){									//重写toString()方法
		return ("姓名:"+name+",年龄:"+age+"\n");
	}
	@Override
	public int compareTo(Person p) {   //重写Comparable接口的compareTo()方法
		if(this.age>p.age){
			return 1;
		}else if(this.age<p.age){
			return -1;
		}else{
			return this.name.compareTo(p.name);
		}
	}
}
public class Demo {
	public static void main(String[] args) {
		TreeSet<Person> set = new TreeSet<Person>();		//通过HashSet实例化Set
		set.add(new Person("张三",21));						//添加元素
		set.add(new Person("李四",23));						//添加元素
		set.add(new Person("张三",21));						//添加重复元素
		set.add(new Person("张三",21));						//添加重复元素
		set.add(new Person("王五",20));						//添加元素
		set.add(new Person("赵六",20));						//添加元素
		System.out.println(set);							//输出集合中所有的元素
	}
}
[姓名:王五,年龄:20
, 姓名:赵六,年龄:20
, 姓名:张三,年龄:21
, 姓名:李四,年龄:23
]
   如果想让自定义类创建的多个对象添加到TreeSet中,就必须让该自定义类实现Comparable接口。没有实现这个接口的类只能向TreeSet集合中添加一个对象。若强行添加多个对象,会抛出ClassCastException异常


集合的输出

    在Java中,主要提供了以下几种输出方式

  1. Iterator:迭代器输出
  2. foreach:增强for循环,这是JDK1.5后新增的输出。常用


迭代输出:Iterator接口

        Iterator接口是一个提供便利各种集合类型的迭代器。有的集合类没有提供get()方法,就可以用迭代器来获取集合元素的信息。所有的Collection接口的子接口,子类都支持Iterator迭代器,可调用集合类中的iterator()方法即可获得该集合的迭代器



输出集合中的所有元素

    Collection子类都提供iterator()为Iterator实例化,所以直接调用该方法就可以使用Iterator接口输出

import java.util.*;
public class Demo {
	public static void main(String[] args) {
		LinkedList <String> link = new LinkedList<String>();
		link.add("A");
		link.add("B");
		link.add("C");
		link.add("E");
		link.add("D");
		Iterator<String> iterator = link.iterator();
		while(iterator.hasNext()){
			System.out.print(iterator.next()+" ");
		}
	}
}
A B C E D 

删除集合中的部分元素

    使用Iterator接口还可以删除集合中的元素,可以选择删除全部(removeAll方法)或者部分删除

import java.util.*;
public class Demo {
	public static void main(String[] args) {
		LinkedList <String> link = new LinkedList<String>();
		link.add("A");
		link.add("B");
		link.add("C");
		link.add("E");
		link.add("D");
		Iterator<String> iterator = link.iterator();
		while(iterator.hasNext()){
			String str = iterator.next();  //获取元素
			if(str.equals("A")){
				iterator.remove(); //删除元素
			}else{
				System.out.print(str+" ");
			}
		}
	}
}
B C E D 


Java新支持:foreach()

   在JDK1.5以后,可以使用增强for循环foreach()循环

import java.util.*;
public class Demo {
	public static void main(String[] args) {
		LinkedList <String> link = new LinkedList<String>();
		link.add("A");
		link.add("B");
		link.add("C");
		link.add("E");
		link.add("D");
		for (String string : link) {
			System.out.print(string+" ");
		}
	}
}
A B C E D 
    虽然使用foreach可以很便捷的输出集合中的所有程序,但是在程序设计中尽量使用Iterator输出集合的元素。因为那是标准的方式

 我们在下一节把Map抽出来单独研究


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值