------- android教育訓練、java教育訓練、期待與您交流! ----------
黑馬學習日志之十 集合(一)
1 集合
集合就是一種容器,用來存放對象。
集合類的出現:面向對象語言對事物的展現都是以對象的形式,是以為了友善對多個對象的 操作,就對對象進行存儲,集合就是存儲對象最常用的一種方式。
集合的特點:隻用于存儲對象,集合長度可變,可以存儲不同類型的對象。
集合和數組的差別:集合和數組都是容器。
數組雖然也可以存儲對象,但長度是固定的,可以存儲基本資料類型
集合長度是可變的,集合隻能存儲對象。
在實際使用中,如果長度固定,建議使用數組;如果長度不固定,建議使用集合。
2 集合架構
JDK為我們提供了一套完整的容器類庫,這些類統稱為集合類,它們都位于java.util包中。
整個集合類按照存儲結構被分為單列集合和雙列集合,單列集合的的根接口是Collection,雙列集合的根接口是Map集合。在Collection接口中主要有兩個子接口,分别是List和Set。Map接口的主要子接口有HashMap和TreeMap。
3 Collection
根接口: Collection
子接口: 丨—— List 可重複, 有存儲順序,有索引
丨—— Set 元素無序 不可重複
由于Collection是個接口,是以它沒有構造方法,示範它的基本方法,隻能通過其子類來驗證。如ArrayList
方法執行個體:
class CollectionDemo
{
public static void main(String[] args)
{
method_get();
}
public static void method_get()
{
ArrayList al = new ArrayList();
//1,添加元素。add(Object obj);
al.add("java01");
al.add("java03");
al.add("java04");
sop(al);
}
public static void method_2()
{
ArrayList al1 = new ArrayList();
al1.add("java01");
al1.add("java02");
al1.add("java03");
al1.add("java04");
ArrayList al2 = new ArrayList();
al2.add("java03");
al2.add("java04");
al2.add("java05");
al2.add("java06");
al1.retainAll(al2); //去交集,al1中隻會保留和al2中相同的元素。
al1.removeAll(al2);
sop("al1:"+al1);
sop("al2:"+al2);
}
public static void base_method()
{
//建立一個集合容器。使用Collection接口的子類。ArrayList
ArrayList al = new ArrayList();
//1,添加元素。
al.add("java01");//add(Object obj);
al.add("java02");
al.add("java03");
al.add("java04");
//列印原集合。
sop("原集合:"+al);
//3,删除元素。
al.remove("java02");
al.clear();//清空集合。
//4,判斷元素。
sop("java03是否存在:"+al.contains("java03"));
sop("集合是否為空?"+al.isEmpty());
//5,擷取個數。集合長度。
sop("size:"+al.size());
//列印改變後的集合。
sop(al);
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
注意:1,add方法的參數類型是Object。以便于接收任意類型對象。
2,集合中存儲的都是對象的引用(位址)
4 疊代器
什麼是疊代器呢?
疊代器就是集合取出元素的方式。取出方式定義在集合内部,這樣取出方式可以直接通路集合内容元素,那麼取出方式就被定義成了内部類。
每一個容器的資料結構不同,是以取出的動作細節也不一樣,但是都有共性内容判斷和取出,那麼可以将共性取出。
這些内部類都符合一個規則,就是Iterator.擷取集合的取出對象,通過一個對外提供的方法iterator。
疊代器是取出方式,會直接通路集合中的元素。是以将疊代器通過内部類的形式來進行描述。通過容器的iterator()方法擷取該内部類的對象。
如同抓娃娃遊戲機中的夾子,夾子是疊代器,取出方式被定義在容器内部,夾子的實作方式不同,但封裝在内部。
例子:
class CollectionDemo
{
public static void main(String[] args)
{
method_get();
}
public static void method_get()
{
ArrayList al = new ArrayList();
//添加元素。
al.add("java01");//add(Object obj);
al.add("java02");
al.add("java03");
al.add("java04");
Iterator it = al.iterator();//擷取疊代器,用于取出集合中的元素。
while(it.hasNext())
{
sop(it.next());
}
// 疊代的另一種用法
for(Iterator it = al.iterator(); it.hasNext() ; )
{
sop(it.next());
}
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
5 List集合
List集合是Collection的一個子接口,繼承了Collection中的方法。
List集合:元素有序,可重複,該集合體系有索引
List子類:Vector:底層是數組資料結構,線程同步,但增删查詢速度慢,被ArrayList替代。
ArrayList:底層是數組資料結構,線程不同步,查詢速度快。預設容量為10
LinkedList:底層使用連結清單資料結構,增删速度快
List集合的特有方法:凡是可以操作角标的方法,都是該體系特有方式。
add(int i,Object obj):在指定位置添加元素
addAll(int I,Collection):在指定位置添加一堆的元素
get 使用size和get方法可以周遊集合中的元素
int indexOf(Object o):傳回此清單中第一次出現的指定元素的索引,如果此清單中不包 含該元素,則傳回-1
int lastIndexOf(Object o):傳回此清單中最後出現的指定元素的索引:如果清單中不包 含此元素,則傳回-1;
List subList(int fromIndex, int toIndex):傳回清單中指定的fromIndex和toIndex之間的 部分的集合。
boolean add(E e):向list裡添加元素
void add(index,E e):在index索引位插入元素
boolean remove(E e):删除元素,有這個值就傳回真,沒有這個值就傳回假
Object remove(int index):根據索引位(角标)删除,會把删除的元素傳回
E set(int index, E element):對索引位置的元素進行修改。會傳回你傳入的元素.
E get(int index):通過索引位(角标)擷取到對應的元素
List subList(int fromIndex, int toIndex):根據指定的頭尾角标擷取子清單
例子:
import java.util.*;
class ListDemo
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void method()
{
ArrayList al = new ArrayList();
//添加元素
al.add("java01");
al.add("java02");
al.add("java03");
sop("原集合是:"+al);
//在指定位置添加元素。
al.add(1,"java09");
//删除指定位置的元素。
//al.remove(2);
//修改元素。
//al.set(2,"java007");
//通過角标擷取元素。
sop("get(1):"+al.get(1));
sop(al);
//擷取所有元素。
for(int x=0; x<al.size(); x++)
{
System.out.println("al("+x+")="+al.get(x));
}
Iterator it = al.iterator();
while(it.hasNext())
{
sop("next:"+it.next());
}
//通過indexOf擷取對象的位置。
sop("index="+al.indexOf("java02"));
List sub = al.subList(1,3);
sop("sub="+sub);
}
public static void main(String[] args)
{
method();
}
}
6 ListIterator
ListIterator是List集合特有的疊代器,ListIterator是Iterator的子接口。
在疊代時,不可以通過集合對象的方法操作集合中的元素,因為會發生并發修改異常(ConcurrentModificationException)。
是以,在疊代器時,隻能用疊代器的方法操作元素,可是Iterator方法是有限的,隻能對元素進行判斷,取出,删除的操作如果想要其他的操作 如添加,修改等,就需要使用其子接口,ListIterator。該接口隻能通過List集合的listIterator方法擷取。
例子:
public static void main(String [] args){
ArrayList al = new ArrayList();
//添加元素
al.add("java01");
al.add("java02");
al.add("java03");
al.add("java04");
sop(al);
//疊代器擷取所有元素
Iterator it = al.iterator();
while (it.hasNext())
{
Object obj = it.next();
if (obj.equals("java02"))
{
//al.add("java08");//并發同步異常。疊代器和集合操作不能同 時來執行
it.remove(); //iterator隻能對元素進行判斷取出删除操作
}
sop("obj"+obj);
}
sop(al);
}
Iterator例子:
public static void main(String[] args) {
List li = new ArrayList();
li.add("a");
li.add("A");
li.add("b");
li.add("c");
li.add("d");
ListIterator lit = list.listIterator();
while(li.hasNext())
{
Object obj =li.next();
if(obj.equals("A"))
{
li.add("e");//在java02後添加Java09
li.set("a2");//将java02改為Java006
}
}
System.out.println("----------------------------");
while(lit.hasPrevious()) { //倒序周遊
System.out.println(lit.previous());
}
7 vector
Vector是List集合的一個子類。底層是數組資料結構,線程同步,但增删查詢速度慢,被ArrayList替代。
Vector中提供了一個獨特的取出方式,就是枚舉Enumeration。此接口Enumeration的功能與 Iterator 接口的功能是重複的Enumeration的名稱和方法的名稱過程,書寫很麻煩。是以被Iterator所取代.
例子:
class VectorDemo{
public static void main(String[] args) {
Vector v = new Vector();
v.addElement("abc1");
v.addElement("abc2");
v.addElement("abc3");
Enumeration en = v.elements();
while(en.hasMoreElements()){
System.out.println(en.nextElement());
}
}
}
8 LinkedList
LinkedList是List的子類,底層是連結清單資料結構,增删快,查詢慢。
LinkedList的特有方法:
添加
void addFirst(Object o): 把元素添加到第一個位置
void addLast(Object o): 把元素添加到最末的位置
擷取
Object getFirst(): 擷取LinkedList中的第一個元素
Object getLast(): 擷取LinkedList中的最後一個元素
Peakfirst() peaklast() 也是擷取元素
對于get的方法,如果集合中沒有元素,就會抛出異常,
對于peak的方法,如果集合中沒有元素,就會出現null
删除(通過指針被删除的元素都會傳回被删除的元素)
removeLast() removeFirst(): 如果集合中沒有元素,傳回異常
pollLast() pollFirst():如果集合元素沒有,該方法不會抛異常,null
例子:
import java.util.*;
class Duilie
{
private LinkedList list;
Duilie()
{
list = new LinkedList();
}
public void myAdd(Object obj)
{
list.addFirst(obj);
}
public Object myGet()
{
return list.removeFirst();.//先進後出
//return list.removeLast(); //先進先出
}
public boolean isNull()
{
return list.isEmpty();
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
class LinkedListTest
{
public static void main(String[] args)
{
Duilie dl =new Duilie();
dl.myAdd("java01");
dl.myAdd("java02");
dl.myAdd("java03");
dl.myAdd("java04");
while(!dl.isNull())
{
Duilie.sop(dl.myGet());
}
}
}
9 Set集合
set是根接口collection的一個子接口,繼承了collection的方法。
set集合:元素無序(存入和取出順序不一緻),不可重複,沒有索引。
Set子類:
HashSet:底層是哈希表資料結構,線程非同步。
TreeSet:底層是二叉樹資料結構,可以對set集合中的元素進行排序
10 HashSet
HashSet是set集合的子類,底層是哈希表資料結構。其集合中沒有重複元素。
保證元素唯一:哈希表存儲結構,其實就是哈希值的存儲,每個對象都有一個哈希值通過equals方法和hashCode方法來保證元素的唯一性。hash算法時計算元素的位址值的,它在對對象的存儲的時候是先調用hashCode方法,然後再執行重寫equals方法。
HashSet集合保證元素唯一性,依賴的是元素的hashCode方法和euqals方法。
當元素的哈希值不同時,元素都有自己的獨立位置。不需要在判斷元素的equals方法,
當元素的哈希值相同時,這時元素在哈希表中位置相同,這時就需要在判斷一次元素的内容是否相同。就需要調用元素的equals方法進行一次比較。如果equals傳回是true。那麼視為兩個元素為重複元素。隻儲存一個。如果傳回是false,那麼這兩個元素不是重複元素,會存儲在同一個哈希值上。
HashSet原理
我們使用Set集合都是需要去掉重複元素的, 如果在存儲的時候逐個equals()比較, 效率較低。
雜湊演算法提高了去重複的效率, 降低了使用equals()方法的次數。當HashSet調用add()方法存儲對象的時候, 先調用對象的hashCode()方法得到一個哈希值, 然後在集合中查找是 否有哈希值相同的對象,如果沒有哈希值相同的對象就直接存入集合;如果有哈希值相同的對象, 就和哈希值相同的對象逐個進行equals()比較,比較結果為false就存入, true則不存。
注意:
類中必須重寫hashCode()和equals()方法
hashCode(): 屬性相同的對象傳回值必須相同, 屬性不同的傳回值盡量不同(提高效率)
equals(): 屬性相同傳回true, 屬性不同傳回false,傳回false的時候存儲
例子:
class HashSetTest
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
HashSet hs = new HashSet();
hs.add(new Person("a1",11));
hs.add(new Person("a2",12));
hs.add(new Person("a3",13));
hs.add(new Person("a2",12));
hs.add(new Person("a4",14));
Iterator it = hs.iterator();
while(it.hasNext())
{
Person p = (Person)it.next();
sop(p.getName()+"::"+p.getAge());
}
}
}
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
public int hashCode()
{
System.out.println(this.name+"....hashCode");
return name.hashCode()+age*37;
}
public boolean equals(Object obj)
{
if(!(obj instanceof Person))
return false;
Person p = (Person)obj;
System.out.println(this.name+"...equals.."+p.name);
return this.name.equals(p.name) && this.age == p.age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
11 TreeSet
TreeSet是set集合的子類,底層是二叉樹資料結構可以對set集合中的元素進行排序,預設自然排序。
保證資料唯一性:
compareTo方法return 0為同一個元素return 1 放元素二叉樹右邊 return -1放元素左邊
TreeSet排序方式:
TreeSet排序的第一種方式:讓元素自身具備比較性。元素需要實作Comparable接口,覆寫compareTo方法,這種方式也成為元素的自然順序 或者叫做預設排序。
例子:
import java.util.*;
class Student implements Comparable
{
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = age;
}
public int compareTo(Object obj)
{
if(!(obj instanceof Student))
throw new RuntimeException("對象類型錯誤");
Student stu = (Student)obj;
if(this.age > stu.age)
return 1;
if(this.age == stu.age) //主要特征比較不出來,用次要特征。
return this.name.compareTo(stu.name); //String類也有compareTo方法。
return -1;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
class TreeSetTest
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet();
ts.add(new Student("sun01",22));
ts.add(new Student("sun02",21));
ts.add(new Student("sun04",21));
ts.add(new Student("sun05",20));
Iterator it = ts.iterator();
while(it.hasNext())
{
Student s = (Student)it.next();
sop(s.getName()+"======"+s.getAge());
}
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
TreeSet排序的第二種方式:當元素自身不具備比較性時,或者具備的比較性不是所需要的,這時需要讓集合自身具備比較性(好比集合裡面有個刻度闆)。在集合的初始化時,就有了比較方式 此時要參閱集合的構造方法。
例子:
import java.util.*;
class Student
{
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
class TreeSetTest2
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet(new MyComparator());
ts.add(new Student("sun001",15));
ts.add(new Student("sun002",12));
ts.add(new Student("sun006",10));
ts.add(new Student("sun002",19));
ts.add(new Student("sun004",11));
Iterator it = ts.iterator();
while(it.hasNext())
{
Student stu = (Student)it.next();
sop(stu.getName()+"====="+stu.getAge());
}
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
//TreeSet的第二種排序方式。 集合自身具備比較性。
class MyComparator implements Comparator
{
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)
{
if(s1.getAge()>s2.getAge())
return 1;
if(s1.getAge()<s2.getAge())
return -1;
return 0;
}
return num;
}
}
12 泛型
集合在初始化時沒有定義資料類型,潛在安全隐患,出現了泛型。
泛型:jdk1.5版本後出現的新特性。用于解決安全問題,是一個安全機制。
泛型好處:(1)運作期間的classCastException轉移到編譯時期,友善程式員解決問題,讓 運作期問題減少,較安全。
(2)避免強制轉換麻煩。
泛型格式:通過< >來定義要操作的引用資料類型。其實< >就是來接收資料類型的。
例子:
import java.util.*;
class GenericDemo
{
public static void main(String[] args)
{
ArrayList<String> al1 = new ArrayList<String>();
al1.add("sss");
al1.add("sqq");
al1.add("saa");
sop(al1);
ArrayList<Integer> al2 = new ArrayList<Integer>();
al2.add(1);
al2.add(2);
al2.add(3);
sop(al2);
}
public static<T> void sop(ArrayList<T> al) //T代表一個明确類型
{
Iterator<T> it = al.iterator();
while(it.hasNext())
{
T t = it.next();
System.out.println(t.length());
}
}
}
泛型類
什麼時候定義泛型類:當類中要操作的引用資料類型不确定的時候。早期定義Object 來完成擴充,現在定義泛型來完成擴充。
例子:
class Worker
{
}
class Student
{
}
class Utils<QQ>
{
private QQ q;
public void setObject(QQ q){
this.q = q;
}
public QQ getObject(){
return q;
}
}
class GenerinDemo3
{
public static void main(String [] args){
Utils<Worker> u= new Utils<Worker>();
u.setObject(new Worder());
Worker w = u.getObject();
}
}
泛型方法:
泛型類定義的泛型,在整個類中有效。泛型類的對象明确要操作的具體類型後,所有要操做的類型就已經固定了。
為了讓不同方法可以操作不同類型,而且類型還不确定,那麼可以将泛型定義在方法上。
例子:
class Demo
{
public <T> void show(T t){
System.out.println("show:"+t);
}
public <Q> void print(Q q){//該泛型隻在這個方法中有效
System.out.println("print:"+t);
}
}
class GenericDemo4
{
public static void main(String [] args){
Demo d = new Demo();
d.show(new Integer(4));
d.print("hehe");
d.show("hahah");
}
}
靜态泛型方法:
靜态方法不可以通路類上定義的泛型
如果靜态方法操作的應用資料類型不确定,可以将泛型定義在方法上
例子:
class Demo1<T>
{
public void show(T t){
System.out.println("show:"+t);
}
public <Q> void print(Q q){
System.out.println("print:"+q);
}
public static <W> void method(W t){
System.out.println("method::"+t);
}
}
public class GenericDemo5
{
public static void main(String [] args){
Demo1<String> d1 = new Demo1<String>();
d1.print(5);
d1.show("hahah");
Demo1.method("hehehehe");
}
}
泛型限定
? 通配符,也可以了解為占位符。
?extends E:可以接受E類或者E的子類型 上限
?super E:可以接受E類型或者E的父類型 下限
例子:
import java.util.*;
class Person
{
private String name;
Person(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}
class Student extends Person
{
private String name;
Student(String name)
{
super(name);
}
}
class GenericTest
{
public static void main(String[] args)
{
ArrayList<Person> al = new ArrayList<Person>();
al.add(new Person("sun01"));
al.add(new Person("sun02"));
al.add(new Person("sun03"));
sop(al);
ArrayList<Student> al1 = new ArrayList<Student>();
al1.add(new Student("sss01"));
al1.add(new Student("sss02"));
al1.add(new Student("sss03"));
sop(al1);
}
public static void sop(ArrayList<? extends Person> al)
{
Iterator<? extends Person> it = al.iterator();
while(it.hasNext())
{
System.out.println(it.next().getName());
}
}
}
------- android教育訓練、java教育訓練、期待與您交流! ----------