集合就是存放對象的,他比數(shù)組好的一點(diǎn)就是他一開始不清楚自己長度
容器一般是分為很多種的,很多的容器在一起然后進(jìn)過斷的抽象和抽取就成了一個(gè)體系,我們稱之為集合框架
我們看體系首先是看頂層的容器,他是底層的容器都有的特性,然后在逐步求精
最頂層的我們稱之為collection 在util包中的-
在collection中分為兩個(gè)比較常用的子接口分別是list和set宪拥。
list是類似于數(shù)組的那種,也就是集合元素可重復(fù)个唧,有序有腳標(biāo)江解。
set則為無序的,所以集合元素不可重復(fù)徙歼,不可腳標(biāo)查找
以下是List的通用方法:- 添加元素:
add(index,data) - 刪除元素:
remove(index) - 修改元素:
set(index,data) - 獲取元素:
get(index) 配合for循環(huán) - 迭代器
indexOf(data)
subList(start,end)
在list中有一個(gè)特殊的迭代器犁河,其他的集合都沒有只是list有叫做ListIterater
這個(gè)迭代器比一般的迭代器會多非常多的功能另外注意的一點(diǎn)就是在使用iterater進(jìn)行l(wèi)ist迭代的時(shí)候,不能夠使用集合的方法對集合進(jìn)行增刪改查的操作
否則就會出現(xiàn)一個(gè)運(yùn)行時(shí)異常魄梯,主要原因就是同時(shí)操作一個(gè)集合導(dǎo)致不合法桨螺,類似于同時(shí)IO同一塊數(shù)據(jù)塊
因此在迭代的過程中只能使用迭代器提供的操作集合的方法
或者不使用迭代器,直接使用原生的for循環(huán)酿秸,然后直接就可以使用迭代器的方法進(jìn)行對集合的操作 - 添加元素:
add方法接受的參數(shù)類型為object以便于接受任意類型的參數(shù)
集合中存放的是對象的地址而不是對象本身
對象可以直接被打印List可以分為三種灭翔,但是常用的只有兩種,他們之間的主要區(qū)別就是底層的數(shù)據(jù)及結(jié)構(gòu)不一樣辣苏。
- ArrayList 底層的實(shí)現(xiàn)使用的是數(shù)組肝箱,也就是說類似于數(shù)組構(gòu)成的線性表,查詢快增刪慢稀蟋,而且他是不同步的
- LinkedList 底層使用的是鏈表煌张,那么就會出現(xiàn)查詢慢,增刪快
- Vector 底層和ArrayList完全一樣退客,只不過vector就是jdk1.0出現(xiàn)的那時(shí)候還沒有集合框架骏融,后來有了集合框架被分到List里面,目前被ArrayList代替因?yàn)樗峭降乃俣嚷瓤瘢覀兌际怯肁rraylist然后自己寫鎖來手動同步
-
arraylist和vector之間區(qū)別還有就是他們們的迭代方式可以有不同档玻,由于vector是最先出來的,所以說他一開始用的并不是
iterator迭代器而是枚舉enumeration他和迭代器很相似茫藏,目前由于枚舉不好記就用iterator误趴。另外arraylist和vector使用的
是變長數(shù)組,也就是本來都是固定長度10個(gè)元素务傲,然后如果查過十個(gè)以后ArrayList使用的是50%的增長也就是會變成15個(gè)冤留,二vector則是
直接100%增長20個(gè)
枚舉的代碼如下:public class Enmu { public static void main(String[] args) { Vector v=new Vector(); v.add("1"); v.add("2"); v.add("3"); Enumeration e=v.elements(); //定義枚舉 while (e.hasMoreElements()){ //循環(huán)遍歷 System.out.println(e.nextElement()); } } }
-
LinkedList中除了一般的List的通用方法還有他自己特有的方法碧囊,而且比較重要
- addFirst
- addLast
- getFirst 獲取元素但是不刪除元素
- getLast
- removeFirst 獲取元素而且刪除元素,但是如果給的是一個(gè)空的鏈表列表使用此方法會產(chǎn)生異常因此有了以下替代方法
- removeLast
- offerFirst 添加
- offerLast
- peekFirst 獲取
- peekLast
- pollFirst 刪除
- pollLast 空鏈表列表也不會有異常而是直接返回null
代碼如下:
public class LinkedList_5 { public static void main(String[] args) { LinkedList list=new LinkedList(); list.addFirst("1"); list.addFirst("2"); list.addFirst("3"); System.out.println(list.getFirst()); System.out.println(list.removeFirst()); LinkedList list1=new LinkedList(); list1.offerFirst("1"); list1.offerFirst("2"); list1.offerFirst("3"); System.out.println(list1.peekFirst()); System.out.println(list1.pollFirst()); } }
7.使用LinkedList實(shí)現(xiàn)堆棧和隊(duì)列結(jié)構(gòu)也就是他所特有的addFirst addLast 以及remove方法的使用
只是要注意在LinkedList里面添加和刪除的元素都是object而不是一般的對象纤怒,應(yīng)該說
所有的集合框架里面的東西都是接受object對象的 所以在寫具體的函數(shù)的時(shí)候注意一下
8.使用ArrayList寫幾個(gè)小程序,第一個(gè)就是使用ArrayList去處重復(fù)元素天通,其中的元素就是字符串泊窘,而第二個(gè)則是
去除的某些自定義對象。第二個(gè)程序也揭示了對于List集合中的元素的比較的接口就是contains他底層是調(diào)用
的對象的equals方法像寒,對于remove也是底層調(diào)用了equals方法從而進(jìn)行比較和刪除烘豹。所以說重點(diǎn)在于重寫
equals方法。
另外在迭代器中每使用一次next方法必須要進(jìn)行一次hasNext的判斷否則很有可能出現(xiàn)找不到元素的情況
例如一個(gè)hasNext里面有兩個(gè)next方法诺祸,而元素又為奇數(shù)個(gè)時(shí)候會拋異常
class Person{
private String name;
private int age;
Person(String name,int age){
this.name=name;
this.age=age;
}
String getName(){
return this.name;
}
private int getAge(){
return this.age;
}
public boolean equals(Object object){
if (!(object instanceof Person)){
return false;
}
Person person=(Person)object; //注意這個(gè)地方必須要強(qiáng)轉(zhuǎn)否則會出現(xiàn)下面的person無法調(diào)用方法
return this.name.equals(person.getName()) && this.age==person.getAge();
}
}
public class ArrayList_7 {
private static ArrayList<Person> singleElement(List<Person> al){
ArrayList<Person> newAl=new ArrayList<Person>();
Iterator<Person> it=al.iterator();
while (it.hasNext()){
Person tmp= it.next(); //iterator返回的是object所以必須要強(qiáng)轉(zhuǎn)
if (!newAl.contains(tmp)){
newAl.add(tmp);
}
}
return newAl;
}
public static void main(String[] args) {
ArrayList<Person> al=new ArrayList<>();
al.add(new Person("zhang01",1));
al.add(new Person("zhang02",2));
al.add(new Person("zhang03",1));
al.add(new Person("zhang03",1));
al=singleElement(al);
for (Person per : al) { //可以使用這種更好的語言結(jié)構(gòu)來實(shí)現(xiàn)迭代省去了iterator迭代 也不用考慮向下類型轉(zhuǎn)換
System.out.println(per.getName());
}
}
}
9.Set中存放的元素都是無序的并且里面的元素都是不可重復(fù)的携悯,顯然如果只存放字符串的話很容易就知道是否重復(fù)
也就無序我們自己去判斷是否重復(fù)了。
set中的公共方法就是集合框架中共有的方法筷笨,重要的還是他的子類憔鬼,這里有兩個(gè)就是hashSet和TreeSet
而存放一般的自定義對象的時(shí)候我們發(fā)現(xiàn)如果想要某些屬性一致的對象作為重復(fù)對象
的話hashSet自身是做不到的,所以我們需要了解hashSet的底層層放原理胃夏,hashSet底層就是hash表轴或,在存放元素的時(shí)候
首先來判斷存放的元素的hashCode值是否一樣也就是調(diào)用他們的hashCode方法,注意hashCode是object對象的方法仰禀,所以
所有的對象都有此方法照雁,另外如果他們的hashCode是一樣的然后就調(diào)用他們的equals方法.不一樣則就存進(jìn)去一樣則被踢出去
那么說白了hashSet底層判斷是否為重復(fù)元素做了兩件事第一個(gè)就是判斷他們的hashCode第二個(gè)就是equals方法
如果要自定義對象如何存放就要重寫這兩個(gè)方法,但是重寫的時(shí)候一定要注意他們的參數(shù)列表否則肯定不會生效答恶,hashCode
一般來說也盡量不要讓不同的對象的hashCode一致造成多余的比較
對于元素判斷是否存在和刪除元素都是hashCode和equals方法
下面是hashSet的代碼示例:
class People{
private String name;
private int age;
People(String name,int age){
this.name=name;
this.age=age;
}
String getName(){
return this.name;
}
private int getAge(){
return this.age;
}
public int hashCode(){
return name.hashCode()+age;
}
public boolean equals(Object object){
if (!(object instanceof People)){
return false;
}
People person=(People)object; //注意這個(gè)地方必須要強(qiáng)轉(zhuǎn)否則會出現(xiàn)下面的person無法調(diào)用方法
return this.name.equals(person.getName()) && this.age==person.getAge();
}
}
public class HashSet_8 {
public static void main(String[] args) {
HashSet<People> hs=new HashSet<People>();
hs.add(new People("1",11));
hs.add(new People("2",11));
hs.add(new People("1",11));
for (People pe:hs){
System.out.println(pe.getName());
}
}
}
10.treeSet是在集合中的元素會自動排序饺蚊,如果是字符串什么的他們都可以自動比較,因?yàn)樽址且呀?jīng)實(shí)現(xiàn)了Compareable接口
但是如果要存放一般的元素對象的時(shí)候注意一定要讓改類實(shí)現(xiàn)compareable接口悬嗓,因?yàn)榇私涌跁岊悘?qiáng)制具有比較性
然后復(fù)寫此接口中的compareTo方法污呼,大于返回正數(shù)等于為零小于則為負(fù),這里要注意如果有多個(gè)排序元素的話然后在比較
的時(shí)候相等條件判斷要注意對其他排序元素的判斷烫扼,否則會造成某個(gè)條件相等但是并不是同一個(gè)元素而無法存入
class Student implements Comparable{
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;
}
@Override
public int compareTo(Object o) {
if (!(o instanceof Student)){
throw new RuntimeException("not same type");
}
if (this.age>((Student) o).age){
return 1;
}else if (this.age==((Student) o).age){
return this.name.compareTo(((Student) o).name);
//注意多重判斷曙求,要是age一樣的話他們就會被當(dāng)成相同元素而無法插入 string類已經(jīng)實(shí)現(xiàn)了comparable接口
//其實(shí)java中很多類都實(shí)現(xiàn)了comparable接口,讓類具有可比性
}
return -1;
}
}
public class TreeSet_9 {
public static void main(String[] args) {
TreeSet<Student> ts=new TreeSet<>();
ts.add(new Student("ab",1));
ts.add(new Student("kb",3));
ts.add(new Student("mb",3));
ts.add(new Student("am",7));
for (Student stu :
ts) {
System.out.println(stu.getName()+"--------"+stu.getAge());
}
}
}
11.TreeSet底層的數(shù)據(jù)結(jié)構(gòu)就是二叉樹映企,元素的排列方式就是第一個(gè)進(jìn)入的元素作為根節(jié)點(diǎn)然后按照compareTo方法
返回的值來判定是左孩子還是右孩子悟狱,這里就是如果說compareTo方法返回的正數(shù)則右孩子,負(fù)數(shù)為左孩子相等就說明
是同一個(gè)元素不用再比較。
所以說決定了TreeSet中的元素的重復(fù)與否就是compareTo函數(shù)的返回值
那么這樣的話我們也可以規(guī)定一個(gè)TreeSet按照放進(jìn)去的順序取出來 或者倒序取出來就是compareTo全部返回1
或者-1即可堰氓,當(dāng)然如果返回的始終為0那么最后集合中只有一個(gè)元素就是第一個(gè)元素
12.在TreeSet中除了實(shí)現(xiàn)comparable接口復(fù)寫compareTo方法以外還有一種排序方法就是比較器挤渐,前面的comparable
接口是讓元素具有了比較性而比較器則是讓集合具有了比較性這個(gè)優(yōu)先級跟高,具體的方法就是在集合實(shí)例化的時(shí)候傳入一個(gè)
自定義的比較器双絮,也就是構(gòu)造方法傳入一個(gè)比較器對象浴麻,這個(gè)比較器也是一個(gè)接口要實(shí)例化的話需要實(shí)現(xiàn)他的compare方法
比較器也是更加常用的
class MyComparator implements Comparator{
public int compare(Object o1,Object o2){
Student obj1=(Student)o1;
Student obj2=(Student)o2;
int num=obj1.getName().compareTo(obj2.getName());
if (num==0){
return new Integer(obj1.getAge()).compareTo(obj2.getAge());
}
return num;
}
}
public class TreeSet_10 {
public static void main(String[] args) {
TreeSet<Student> ts=new TreeSet<Student>(new MyComparator());
ts.add(new Student("dsf",11));
ts.add(new Student("dmf",12));
ts.add(new Student("ddf",13));
ts.add(new Student("jf",14));
for (Student stu :
ts) {
System.out.println(stu.getName()+"----------"+stu.getAge());
}
}
}