一、Collection
資料多了用對象存,對象多了用集合存。
集合和數組一樣,存儲的都是位址。
集合類
為什麼出現集合類?
面向對象語言對事物的展現都是以對象的形式,是以為了友善對多個對象的操作,就對
對象進行存儲,集合就是存儲對象最常用的一種方式。
數組和集合類同是容器,有何不同?
數組雖然也可以存儲對象,但長度的固定的;集合長度是可變的。
數組中可以存儲基本資料類型,集合隻能存儲對象。
集合類的特點?
集合隻用于存儲對象,集合長度是可變的,集合可以存儲不同類型的對象。
為什麼會出現這麼多容器(集合)呢?
因為每個容器對資料的存儲方式都不同。這個存儲方式稱之為:資料結構。
集合内資料擷取:
把取出方式定義在集合的内部,這樣取出方式就可以直接通路集合内部的元素。
那麼取出方式就定義成内部類。而每一個容器的資料結構不同,是以取出的動作
細節也不一樣,但是都有共性内容:判斷和取出。那麼可以将共性抽取。
那麼這些内部類都符合一個規則,該規則是Iterator。如何擷取集合的取出對象呢:
通過一個對外提供的方法:interator();
什麼的類集架構?
1、類集架構是一組類和接口;
2、位于java.util包中;
3、主要用于使用者存儲和管理對象;
4、主要分為三大類:集合、清單和映射
什麼是集合(Set):集合中的對象不按特定的方式排序,并且沒有重複對象。
什麼是清單(List):集合中對象按照索引位置排序,可以有重複的對象。
什麼是映射(Map):集合中的每一個元素包含一個鍵對象和一個值對象,鍵不可以重複,值可以重複。
代碼:
package collection;
/*
1、add方法的參數類型是object,以便接收任意類型的對象。
2、集合中存儲的都是對象的引用(位址)
什麼是疊代器:
其實就是集合的取出元素的方式。
collection:
--List:元素是有序的,元素是可以重複的。因為該集合體系有索引。
--ArrayList:底層的資料結構使用的是數組結構。
特點:查詢、修改速度很快,但是增加、删除稍慢。
線程不同步。java1.2版本出現。
--LinkedList:底層使用的是連結清單資料結構。
特點:增加、删除速度很快,但是查詢、修改稍慢。
--Vector:底層使用的是數組資料結構。線程同步,增删改查速度慢。
java1.0版本出現。被ArrayList替代。
--Set:元素是無序的,元素是不可以重複的,集合中沒有索引。
*/
import java.util.ArrayList;
import java.util.Iterator;
class CollectionDemo{
public static void main(String[] args){
//method_1();
//method_2();
method_get();
}
public static void method_get(){
ArrayList<Object> al = new ArrayList<Object>();
al.add("java01");//add(obj);
al.add("java02");
al.add("java03");
al.add("java04");
//sop(al);
/*//擷取疊代器,用于取出集合中的元素
Iterator it = al.iterator();
while(it.hasNext()){
sop(it.next());
}
*/
for(Iterator<Object> it = al.iterator(); it.hasNext();){
sop(it.next());
}
}
public static void method_2(){
//建立一個集合容器,使用collection接口的子類。ArrayList
ArrayList<String> al1 = new ArrayList<String>();
al1.add("java01");//add(obj);
al1.add("java02");
al1.add("java03");
al1.add("java04");
ArrayList<String> al2 = new ArrayList<String>();
al2.add("java01");//add(obj);
al2.add("java02");
al2.add("java05");
al2.add("java06");
//取交集,al1中隻會保留和al2中相同的元素
al1.retainAll(al2);
sop("al1:" + al1);
sop("al2:" + al2);
//al1.removeAll(al2);
}
public static void method_1(){
//建立一個集合容器,使用collection接口的子類。ArrayList
ArrayList<String> al = new ArrayList<String>();
//1、添加元素
al.add("java01");//add(obj);
al.add("java02");
al.add("java03");
al.add("java04");
//列印原集合
sop(al);
//3、删除元素
al.remove("java02");
//2、擷取個數。集合長度
sop("size:" + al.size());
//列印移除後集合
sop(al);
//4、判斷元素
sop("java03是否存在:" + al.contains("java03"));
sop("集合是否為空:" + al.isEmpty());
//清空集合
al.clear();
}
//輸出對象
public static void sop(Object obj){
System.out.println(obj);
}
}
二、List
package collection.list;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/*
collection:
--List:元素是有序的,元素是可以重複的。因為該集合體系有索引。
--ArrayList:底層的資料結構使用的是數組結構。
特點:查詢、修改速度很快,但是增加、删除稍慢。
線程不同步。java1.2版本出現。
--LinkedList:底層使用的是連結清單資料結構。
特點:增加、删除速度很快,但是查詢、修改稍慢。
--Vector:底層使用的是數組資料結構。線程同步,增删改查速度慢。
java1.0版本出現。被ArrayList替代。
--Set:元素是無序的,元素是不可以重複的,集合中沒有索引。
List:
特有方法:凡是可以操作角标的方法都是改體系特有的方法。
增:add(index,element);
assAll(index,collection);
删:remove(index);
改:set(index,element);
查:get(index);
subList(from,to);
listItetator();
List集合特有的疊代器。ListIterator是Iterator的子接口。
在疊代時。不可以通過集合對象的方法操作集合中的元素。因為會發生
ConcurrentModificationException異常。
是以,在疊代器時,隻能用疊代器的放過操作元素,可是Iterator方法是有限的,
隻能對元素進行判斷、取出和删除操作,如果想要其他操作如添加、修改等,就需要
使用其子接口ListIterator
該接口隻能通過List集合的Iterator方法擷取。
*/
class ListDemo{
public static void main(String[] args){
//示範清單疊代器
ArrayList<String> al = new ArrayList<String>();
al.add("java01");
al.add("java02");
al.add("java03");
//在疊代過程中,準備添加後删除元素
ListIterator<String> li = al.listIterator();
while(li.hasNext()){
Object obj = li.next();
if(obj.equals("java02"))
//li.add("java009");//添加
li.set("java006");//替換
}
sop("hasNext:" + li.hasNext());//正向判斷
sop("hasPrevious:" + li.hasPrevious());//逆向判斷
sop(al);
}
public static void method_1(){
ArrayList<String> al = new ArrayList<String>();
//添加元素
al.add("java01");
al.add("java02");
al.add("java03");
sop("原集合是:" + al);
//在指定位置添加元素
al.add(1,"java09");
sop("添加元素後集合:" + al);
//删除指定位置的元素
al.remove(2);
sop("删除元素後集合:" + al);
//修改元素
al.set(2,"java007");
sop("修改元素後集合:" + al);
//通過角标擷取元素
sop("get(1):" + al.get(1));
//擷取所有元素
for(int x = 0; x < al.size(); x++){
System.out.println("al(" + x + ")=" + al.get(x) );
}
//用疊代器擷取元素
for(Iterator<String> it = al.iterator(); it.hasNext();){
sop("next:" + it.next());
}
//通過index擷取對象的位置
sop("index" + al.indexOf("java02"));
//擷取子串
List<String> sub = al.subList(1,3);
sop("sub=" + sub);
}
//封裝列印對象
public static void sop(Object obj){
System.out.println(obj);
}
}
====ArrayList===
練習一:
package collection.list;
import java.util.ArrayList;
import java.util.Iterator;
/*
練習:
去除ArrayList集合中的重複元素
*/
class ArrayListTest{
public static void main(String[] args){
ArrayList<Object> al = new ArrayList<Object>();
al.add("java01");
al.add("java02");
al.add("java01");
al.add("java03");
al.add("java02");
al.add("java04");
/*
在疊代時,循環中的next調用一次,就要hasNext判斷一次。
Iterator it = al.iterator();
while(it.hasNext()){// 判斷一次hasNext,使用兩次next,可能出現元素不存在異常。
sop(it.next() + "......." + it.next());
}
*/
sop(al);
al = singleElement(al);
sop(al);
}
public static ArrayList<Object> singleElement(ArrayList<Object> al){//去除重複元素
//定義一個臨時容器
ArrayList<Object> newAl = new ArrayList<Object>();
Iterator<Object> it = al.iterator();
while(it.hasNext()){
Object obj = it.next();
if(!newAl.contains(obj))//将元素添加到新容器中(重複的不存)
newAl.add(obj);
}
return newAl;
}
public static void sop(Object obj){
System.out.println(obj);
}
}
練習二:
package collection.list;
/*
練習:(重要)
将自定義對象作為元素存到ArrayList集合中,并去除重複元素
比如:存人對象。同姓名同年齡的視為同一個人,為重複對象。
思路:
1、對人描述,将資料封裝進人對象。
2、定義容器,将人存入。
3、取出。
4、去除重複對象。
*******List集合判斷元素是否相同,依據的是元素的equals方法。**********
*/
import java.util.*;
class ArrayListTest2{
public static void main(String[] args){
ArrayList<Object> al = new ArrayList<Object>();//建立一個集合
al.add(new Person("lisi01",30));//集合中添加對象
al.add(new Person("lisi02",30));
al.add(new Person("lisi03",30));
al.add(new Person("lisi01",30));
al.add(new Person("lisi02",35));
al.add(new Person("lisi04",30));
System.out.println("---------去除重複對象前--------------");
sopArrayList(al);
System.out.println("---------去除重複對象後--------------");
al = singleElement(al);
sopArrayList(al);
System.out.println("---------移除一個元素--------------");
//調用Person的equals方法,判斷移除元素是否與集合内元素相同
al.remove(new Person("lisi04",30));
sopArrayList(al);
}
//列印集合中對象的内容
public static void sopArrayList(ArrayList<Object> al){
Iterator<Object> it = al.iterator();
while(it.hasNext()){
Person p = (Person)it.next();//向下轉型
sop(p.getName() + "......" + p.getAge());
}
}
//列印對象
public static void sop(Object obj){
System.out.println(obj);
}
//去除集合内重複的對象元素
public static ArrayList<Object> singleElement(ArrayList<Object> al){
//定義一個臨時容器
ArrayList<Object> newAl = new ArrayList<Object>();
Iterator<Object> it = al.iterator();
while(it.hasNext()){//周遊集合中的對象。
Object obj = it.next();
if(!newAl.contains(obj))//依據對象的equals方法進行判斷
newAl.add(obj);
}
return newAl;
}
}
//建立一個Person類
class Person{
private String name;
private int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
//覆寫equals方法,判斷對象是否相同
public boolean equals(Object obj){
if(!(obj instanceof Person))//判斷對象是否是Person類對象
return false;
Person p = (Person)obj;//向下轉型
return this.name.equals(p.name) && this.age == p.age;
}
}
===LinkedList===
package collection.list;
import java.util.LinkedList;
/*
LinkedList特有方法:
addFirst();
addLast();
作為第一個(最後一個)元素,添加到集合中
getFirst();
getLast();
擷取元素,但不删除元素。會出現NoSuchElementException
removeFirst();
removeLast();
擷取元素,并删除元素。如果集合中沒有元素,會出現NoSuchElementException
在JDK1.6出現了替換方法:
offerFirst();
offerLast();
作為第一個(最後一個)元素,添加到集合中
peekFirst();
peekLast();
擷取元素,但不删除元素。如果集合中沒有元素,會傳回null
pollFirst();
pollLast();
擷取元素,并删除元素。如果集合中沒有元素,會傳回null
*/
class LinkedListDemo{
public static void main(String[] args){
LinkedList<Object> link = new LinkedList<Object>();
link.addFirst("java01");
link.addFirst("java02");
link.addFirst("java03");
link.addFirst("java04");
sop(link);
}
public static void sop(Object obj){
System.out.println(obj);
}
}
練習:
package collection.list;
import java.util.LinkedList;
/*
---------------------必須掌握(重要)-----------------------------
練習:使用LinkedList模拟一個堆棧或者隊列資料結構
堆棧:先進後出 如同一個杯子
隊列:先進先出 First in, First out FIFO如同一個水管
*/
class LinkedListTest{
public static void main(String[] args){
Queue dl = new Queue();
dl.myAdd("java01");//作為第一個元素添加到集合中
dl.myAdd("java02");
dl.myAdd("java03");
dl.myAdd("java04");
while(!dl.isNull())
System.out.println(dl.myGet());//擷取最後一個元素
}
}
class Queue{
private LinkedList<Object> link;
Queue(){//生成一個連結清單對象
link = new LinkedList<Object>();
}
public void myAdd(Object obj){//作為第一個元素添加
link.addFirst(obj);
}
public Object myGet(){//擷取最後一個元素,并移除
return link.removeLast();
}
public boolean isNull(){//判斷集合是否為空
return link.isEmpty();
}
}
===Vector===
package collection.list;
import java.util.Enumeration;
import java.util.Vector;
/*
枚舉就是vector特有的取出方式。
發現枚舉和疊代器很像。其實枚舉和疊代是一樣的。
因為枚舉的名稱以及方法的名稱都過長,是以枚舉被疊代器取代了。
枚舉就郁郁而終了。
*/
class VectorDemo{
public static void main(String[] args){
Vector<String> v = new Vector<String>();
v.add("java01");
v.add("java02");
v.add("java03");
v.add("java04");
Enumeration<String> en = v.elements();
while(en.hasMoreElements()){
System.out.println(en.nextElement());
}
}
}
三、Set
===HashSet===
package set;
import java.util.HashSet;
import java.util.Iterator;
/*
|--Set:元素是無序的(存入和取出的順序不一定一緻),元素不可以重複。
|-HashSet:底層資料結構是哈希表。
HashSet是如何保證元素唯一性的呢?
是通過元素的兩個方法,hashCode和equals來完成的。
如果元素的HashCode值相同,才會判斷equals是否為true。
如果元素的HashCode值不同,就不會調用equals方法。
注意:對于判斷元素是否存在,以及删除等操作,依賴的方法是元素
的hashCode和equals方法。先判斷hashCode方法,如果相同再判斷equals方法。
|-TreeSet:可以對set集合中的元素進行排序。
Set集合的功能和Collection是一緻的。
*/
public class HashSetDemo {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
HashSet<String> hs = new HashSet<String>();
hs.add("java04");//添加元素
hs.add("java05");
System.out.println(hs.add("java01"));//添加元素,并列印元素是否存在的值
hs.add("java02");
hs.add("java03");
hs.add("java03");
System.out.println(hs.add("java01"));//元素已經存在,列印出false
for(Iterator<String> it = hs.iterator(); it.hasNext();){//周遊集合
System.out.println(it.next());
}
}
}
練習:
package set;
import java.util.HashSet;
import java.util.Iterator;
/*
練習:
往HashSet集合中存入自定義對象(人對象)
姓名和年齡相同視為同一個人,為重複元素。
HashSet是如何保證元素唯一性的呢?
是通過元素的兩個方法,hashCode和equals來完成的。
如果元素的HashCode值相同,才會判斷equals是否為true。
如果元素的HashCode值不同,就不會調用equals方法。
*/
class HashSetTest{
public static void main(String[] args){
//建立HashSet集合
HashSet<PersonHashSet> hs = new HashSet<PersonHashSet>();
sop("\n---------添加元素-----------");
hs.add(new PersonHashSet("a1",11));
hs.add(new PersonHashSet("a2",12));
hs.add(new PersonHashSet("a3",13));
hs.add(new PersonHashSet("a4",14));
sop("\n---------重複添加一個元素-----------");
hs.add(new PersonHashSet("a2",12));
//判斷是否包含一個元素
sop("\n---------是否包含一個指定元素-----------");
sop(hs.contains(new PersonHashSet("a4",14)));
//移除一個元素
sop("\n---------移除一個元素-----------");
hs.remove(new PersonHashSet("a3",13));
sop("\n---------列印集合中的元素-----------");
for(Iterator<PersonHashSet> it = hs.iterator(); it.hasNext();){//周遊集合
PersonHashSet p = (PersonHashSet)it.next();
sop(p.getName() + "......" + p.getAge());
}
}
public static void sop(Object obj){//列印對象
System.out.println(obj);
}
}
//建立一個Person類
class PersonHashSet{
private String name;
private int age;
PersonHashSet(String name,int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
//覆寫HashCode方法,判斷對象是否相同,如果HashCode相同,再判斷equals方法
public int hashCode(){
System.out.println(this.name + "-------hashCode");//測試哪個對象調用hashCode方法
return name.hashCode() + age*39;
}
//覆寫equals方法,判斷對象是否相同
public boolean equals(Object obj){
if(!(obj instanceof PersonHashSet))//判斷對象是否是Person類對象
return false;
PersonHashSet p = (PersonHashSet)obj;//向下轉型
//測試哪個對象調用equals方法,并和哪個對象做比較
System.out.println(this.name + "----equals---" + p.name);
return this.name.equals(p.name) && this.age == p.age;
}
}
===TreeSet===
package set;
import java.util.Iterator;
import java.util.TreeSet;
/*
|--Set:元素是無序的(存入和取出的順序不一定一緻),元素不可以重複。
|-HashSet:底層資料結構是哈希表。
HashSet是如何保證元素唯一性的呢?
是通過元素的兩個方法,hashCode和equals來完成的。
如果元素的HashCode值相同,才會判斷equals是否為true。
如果元素的HashCode值不同,就不會調用equals方法。
注意:對于判斷元素是否存在,以及删除等操作,依賴的方法是元素
的hashCode和equals方法。先判斷hashCode方法,如果相同再判斷equals方法。
|-TreeSet:底層資料結構是二叉樹。可以對set集合中的元素進行排序。
二叉樹是保證元素唯一性的依據。
用compareTo方法的傳回值判斷大小。
TreeSet排序:
第一種方式:讓元素自身具備比較性。元素需要實作comparable接口,
覆寫compareTo方法。這種方式也成為元素的自然順序或預設順序。
第二種方式:當元素自身不具備比較性時,或者具備的比較性不是需要的時候,
需要讓集合自身具備比較性。
在集合一初始化時,就有了比較方式。
Set集合的功能和Collection是一緻的。
記住:排序時當主要條件相同時一定要判斷次要條件。
練習:
需求:(第一種排序方式)
往TreeSet集合中存儲自定義對象學生。
按照學生年齡進行排序。
*/
public class TreeSetDemo {
/**
* @param args
*/
public static void main(String[] args) {
TreeSet<Student> ts = new TreeSet<Student>();
ts.add(new Student("張三",26));
ts.add(new Student("李四01",23));
ts.add(new Student("王五",20));
ts.add(new Student("李四02",23));//年齡相同時,比較姓名
ts.add(new Student("小王",20));
ts.add(new Student("王五",20));//重複元素不會重新存儲
for(Iterator<Student> it = ts.iterator(); it.hasNext();){//周遊集合
Student s = (Student)it.next();
System.out.println(s.getName() + "-----" + s.getAge());
}
}
}
//實作compareable接口,該接口強制讓對象具備比較性
class Student implements Comparable<Object>{
private String name;
private int age;
Student(String name,int age){
this.setName(name);
this.setAge(age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//覆寫compareTo方法,定義按年齡排序的方法
public int compareTo(Object o) {
if(!(o instanceof Student))//判斷是否是相同類,不是相同類抛異常
throw new RuntimeException("輸入的類不是Student類");
Student s = (Student)o;
// System.out.println(this.name + "-----compareTo------" + s.name);
if(this.age > s.age)
return 1;
//如果年齡相同,按照姓名進行排序。字元串本身有自帶的compareTo方法。
if(this.age == s.age){
return this.name.compareTo(s.name);
}
return -1;
}
}
package set;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
/*
* 當元素自身不具備比較性,或者具備的比較性不是所需要的,這時就需要讓容器自身具備比較性。
*
* 思路:
* 1、定義一個類,實作comparator接口,并覆寫compare方法,做為比較器。
* 2、定義了比較器,将比較器對象作為參數傳遞給TreeSet集合的構造函數。
*
* 練習:(第二種排序方式)
* 需求:
* 1、往TreeSet集合中存儲自定義對象學生。
2、按照學生年齡進行排序。
3、現在需求改變,需要按照姓名來排序,但又不能修改原有的排序代碼
* 注意:當兩種排序都存在時,以比較器為主。
*
*
*/
public class TreeSetDemo2 {
/**
* @param args
*/
public static void main(String[] args) {
//将比較器作為參數傳遞給集合
TreeSet<Student> ts = new TreeSet<Student>(new MyCompare());
ts.add(new Student("李四01",26));
ts.add(new Student("李四04",23));
ts.add(new Student("李四02",20));
ts.add(new Student("李四02",23));//姓名相同,比較年齡
ts.add(new Student("李四03",20));
ts.add(new Student("李四04",23));//對象重複,不會添加
for(Iterator<Student> it = ts.iterator(); it.hasNext();){//周遊集合
Student s = (Student)it.next();
System.out.println(s.getName() + "-----" + s.getAge());
}
}
}
//自定義比較器
class MyCompare implements Comparator<Object>{
public int compare(Object o1, Object o2) {
Student s1 = (Student)o1;
Student s2 = (Student)o2;
int num = s1.getName().compareTo(s2.getName());
if(num == 0){
return s1.getAge()-s2.getAge();//這種方法也可行
//調用Integer類是compareTo方法
//return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
}
return num;
}
}
練習:
package set;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
/*
練習:
按照字元串長度排序
思路:字元串本身具備比較性,但是它的比較方式不是所需要的,這時就隻能使用比較器
*/
public class TreeSetTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
TreeSet<String> ts = new TreeSet<String>(new StringLengthComparator());
ts.add("abcd");
ts.add("abd");
ts.add("cd");
ts.add("d");
ts.add("adbcd");
ts.add("aacd");
for(Iterator<String> it = ts.iterator(); it.hasNext();){//周遊集合
System.out.println(it.next());
}
}
}
class StringLengthComparator implements Comparator<Object>{
public int compare(Object o1, Object o2) {
String s1 = (String)o1;
String s2 = (String)o2;
int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));
if(num == 0)
return s1.compareTo(s2);
return num;
}
}