進程:是一個正在執行中的程序 沒一個進程執行都有一個執行順序,該順序就是一個執行路徑 或者叫一個控制單元 進程用於給程序分配內存空間 線程就是:進程中的獨立的控制單元,線程控制着進程的執行。 一個進程中至少有一個線程 main方法所執行的線程稱為主線程 創建線程方法2種: 類實現 步驟 1:繼承Tread類 2,重寫run方法 目的:將自定義代碼存儲在run方法中讓線程運行 3,調用start方法 該方法有兩個作用,啟動線程,調用run方法 接口實現 步驟: 1,繼承Runable接口 2,重寫Runable接口中的run 方法 3,調用new Thread(SubRunable類).start方法開啟線程 區別: 1,接口可以對繼承,而類只有單繼承 2,共享資源(同一個對象)、 3,線程代碼存放正在Thread子類run方法中,Runtime接口的run方法中 若在main方法中調用run方法,相當於在主線程中調用了run方法 若調用start方法,則表示另外開啟線程執行run方法中代碼 為什么覆蓋run方法? Thead用於描述線程,該類就定義了一個運行代碼的功能, 該功能存儲在run方法中 thread類中的run方法,用於存儲線程要運行的代碼 線程狀態: start:運行線程 sleep(time):暫停線程,指定time后繼續執行 wait():暫停線程,notify()方法喚醒該方法的停止 stop():消亡線程。當run方法結束后也處於消亡狀態 線程都有自己的名稱通過getName()獲取,Thread-0,Thread-1.。。。。 Thread.currentThread()獲取當前進程對象 =this.getName();獲取線程名稱 設置線程名稱:setName或者構造函數 線程創建時內存會給特定的線程創建 class thread1 extends Thread { public void run() { System.out.println(); } } class thread2 extends Thread { public void run() { System.out.println(); } } class Demo { public static void main(String args[]) { //創建兩個進程 thread1 t1=new thread1(); thread2 t2=new thread2(); //執行兩個進程 t1.start(); t2.start(); } } //賣票 class Tickets extends Thread { public static int ticket=`100; //共享內存資源,不會重復買多種票 public void run () { while(true) { if(ticket>0) System.out.println(Tread.currentTread().getName+":"+ticket--); else break; } } } class SealDemo { public static void main(String args[]) { Tickets t1=new Tickets(); Tickets t2=new Tickets(); Tickets t3=new Tickets(); Tickets t4=new Tickets(); t1.start(); t2.start(); t3.start(); t4.start(); } } 用Runable接口實現 class Tickets implements Runable { public int ticket=`100; //共享內存資源,不會重復買多種票 Object obj=new Object(); public void run () { while(true) { synchronized(obj) { if(ticket>0) try(Thread.sleep())catch(Exception e){}; System.out.println(Tread.currentTread().getName+":"+ticket--); else break; } } } } class SealDemo { public static void main(String args[]) { Tickets t=new Tickets(); new Thread(t).start();//調用Thead類的構造函數,然后開啟 new Thread(t).start(); 另開啟線程 } } 多線程安全問題 以上案例中就可能出現線程錯誤 問題的原因: 當多條語句在操作同一個線程共享數據時,一個線程對多條語句只執行了一部分,還沒有執行完 另一個線程參與進來執行,導致共享數據的錯誤 解決辦法: 對多條操作共享數據的語句,只能讓一個線程執行完,在執行過程中, 其他線程不可以參與執行 java對於多線程的安全問題提供了專業的解決方式 同步代碼塊: Object obj=new Object(); 同步鎖----解決代碼的安全問題 synchronized(obj---對象) { 需要同步的代碼 } obj相當於鎖,持有鎖的線程可以再同步中執行。 沒有只有鎖的線程即使獲取了cpu的執行權,也進不去,因為沒有開鎖 同步得前提: 1,必須要有兩個以上的線程訪問同一個對象的共享屬性 2,必須是多個線程使用同一個鎖 必須保證同步中只有一個線程在運行 好處:解決多線程的安全問題; 弊端:多個線程每次都要判斷鎖,所以消耗資源,程序變慢; 同步函數: 找同步成員的方法: 1,明確哪些代碼是多線程運行代碼; 2,明確共享數據; 3,明確多線程運行代碼中哪些語句是操作共享數據的 語法: public synchronized void Add() { } 多線程中如果重寫Runable和Thread中的run方法時使用 同步函數, 那么程序將在一個線稱運行完后運行其他線程 同步函數的同步鎖是---this,同步函數的鎖將函數內容進行枷鎖 案例:同步代碼塊--使用obj鎖和同步函數使用的是this class Tickets implements Runable { privat int ticket=100; object obj =new object(); boolean flag=true; public void run() { if(flag==ture) { while(true) { sychronized(obj) { if(ticket>0) { try{Thread.sleep(10);}catch(Exception e){}; System.out.println(Thread.currentThread().getName()+"..."+ticket--) } } } } else { while(true) { show();//show 方法為同步方法 } } } public sychronized void show() { if(ticket>0) { try{Thread.sleep(10);}catch(Exception e){}; System.out.println(Thread.currentThread().getName()+"..."+ticket--) } } } class test { public static void main() { Tickets t=new Tickets (); Thread t1=new Thread(t); Thread t2=new Thread(t); t1.start(); t2.start(); } } 如果同步函數加上static,那么同步靜態方法的鎖就不再是this,這時候的鎖是 類名.Class 靜態進內存時,沒有本類對象,但是一定有類對象字節碼對象 類名.class,該對象的類型是Class 靜態函數中的同步代碼塊的鎖也是類名.class 單類設計模式 class Single { private static final Single s=new Single(); private Single(){}; public static Single getInstance() { return s; } } class Single { private static Single=null; private Single(){}; public static Single getInstance() { if(s==null) //用雙重判斷減少判斷鎖的狀態,從而增加效率 { sychronized(Single.class) //使用同步代碼塊進行加鎖 { if(s==null) { s=new Single(); } } } return s; } } 死鎖: 同步中嵌套同步,而鎖卻不同。這時程序會停止 死鎖案例:下面案例中會出現死鎖 class Test { private boolean flag; Test(boolean flag) { this.flag=flag; } public void run() { if(flag) { synchronized(Mylock.locka) { System.out.println("if locka"); synchronized(Mylock.lockb) { System.out.println("if lockb"); } } } else { synchronized(Mylock.lockb) { System.out.println("else lockb"); synchronized(Mylock.locka) { System.out.println("else locka"); } } } } } class Mylock { static object lockA=new object(); static object lockB=new object(); } class DeadLockDemo { public static void main(String args[]) { Test t= Thread t1=new Thread(new Test(true)); Thread t2=new Thread(new Test(false)); } } 線程間通信:其實就是多個線程在操作同一個資源,操作的動作不同 class Resourc { string name; string sex; boolean flag=false; } class input implement Runable { private Resource r; input(Resource r) { this.r=r; } public void run() { int x=0; while(ture) { sychronized(r)//枷鎖 該資源是唯一的,所以選擇該資源 { if(flag=true) r.wait(); if(x==0) { r.name="張三"; r.sex="男"; } else { r.name="李四"; r.sex="女"; } x=(x+1)%2; //循環輸出 張三,李四 r.flag=true; r.notify(); //喚醒r對象所在的線程 } } } } class output implement Runable { private Resource r; input(Resource r) { this.r=r; } public void run() { while(ture) { sychronized(r)//枷鎖,該資源是唯一的,所以選擇該資源 if(r.flag) r.wait(); System.out.println(r.name+".."+r.sex); r.flag=false; r.notify(); } } } class Main { public static void main(String args[]) { Resource r=new Resource(); input in=new input(r); output out=new output(r); in.start(); out.start(); //錯誤原因:當輸入的時候只賦值了姓名,性別還沒有賦值就被另一個線程輸出 //解決方法:同步代碼塊 } } notifyAll()喚醒所有線程 喚醒開發機制: wait notify notifyAll 都使用在同步中,因為要對持有監視器(鎖的線程操作)的線程操作。 所以要使用在同步中,因為同步才具有鎖 為什么這些操作線程的方法要定義在Object類中呢? 因為這些方法在操作同步中線程時,都必須要表示他們所操作線程只有的鎖 只有同一個鎖上的被等待線程,可以被同一個鎖上notify喚醒。 不可以對不同鎖中的線程進行喚醒; 也就是說,等待和喚醒必須是同一個鎖; 而鎖可以是任意對象,所以可以被任意對象調用的方法定義Object類中 代碼優化:用於單生產單消費 class Resourc { private string name; private string sex; private boolean flag=false; void sychronized set(String name,String sex) { if(flag==false) try{this.wait();}catch(Exception e){} this.name=name; this.sex=sex; r.flag=true; r.notify(); //喚醒r對象所在的線程 } void sychronized out() { if(!flag) try{this.wait();}catch(Exception e){} System.out.println(this.name+"..."+this.sex); r.flag=false; r.notify(); //喚醒r對象所在的線程 } } class input implement Runable { private Resource r; input(Resource r) { this.r=r; } public void run() { int x=0; while(ture) { if(x==0) r.set("張三","男"); else r.set("李四","女"); x=(x+1)%2; //循環輸出 張三,李四 } } } class output implement Runable { private Resource r; input(Resource r) { this.r=r; } public void run() { while(ture) { r.out(); } } } class Main { public static void main(String args[]) { Resource r=new Resource(); new Thread(new input(r)).start(); new Thread(new output(r)).start(); } } 代碼改進:用於多生產,多消費 notify()方法喚醒的是線程池中的第一個線程 class Resourc { private string name; private string sex; private boolean flag=false; void sychronized set(String name,String sex) { while(flag==false) try{this.wait();}catch(Exception e){} this.name=name; this.sex=sex; r.flag=true; r.notifyAll(); //喚醒r對象所在的線程 } void sychronized out() { while(!flag) try{this.wait();}catch(Exception e){} System.out.println(this.name+"..."+this.sex); r.flag=false; r.notifyAll(); //喚醒r對象所在的線程 } } class input implement Runable { private Resource r; input(Resource r) { this.r=r; } public void run() { int x=0; while(ture) { if(x==0) r.set("張三","男"); else r.set("李四","女"); x=(x+1)%2; //循環輸出 張三,李四 } } } class output implement Runable { private Resource r; input(Resource r) { this.r=r; } public void run() { while(ture) { r.out(); } } } class Main { public static void main(String args[]) { Resource r=new Resource(); new Thread(new input(r)).start(); new Thread(new input(r)).start(); new Thread(new output(r)).start(); new Thread(new output(r)).start(); } } JDK1.5中提供了多線程升級解決方案, 、將同步Synchronized替換成現實lock操作 將object中的wait,notify,notifyall,替換成Condition對象, 該對象可以Lock鎖,進行獲取 在該實例中,實現了本方只喚醒對方操作 一個lock對應多個Condition class Resourc { private string name; private string sex; private boolean flag=false; private Lock lock=new ReentrantLock(); private Condition condition_com=lock.newCondation(); private Condition condition_pro=lock.newCondation(); void set(String name,String sex)throws InterruptionException { try{ lock.lock(); while(flag==false) conditon_pro.await(); this.name=name; this.sex=sex; r.flag=true; } catch(InterruptionException e) { lock.unlock(); } conditon_con.signal(); //喚醒r對象所在的線程 } void out() { lock.lock(); while(!flag) condition_con.await(); System.out.println(this.name+"..."+this.sex); r.flag=false; lock.unlock(); conditon_pro.signal(); //喚醒r對象所在的線程 } } stop方法已經過時: 如果停止線程:只有一種,run方法結束 開啟多線程運行,運行代碼通常是循環結構 只要控制住循環,就能讓run方法結束,也就是線程結束 當線程處於凍結狀態; 就不會讀取到標記,那么線程就不會結束 當沒有指定的方式讓凍結的線程恢復到運行狀態時,這時需要對凍結狀態進行清除, 強制讓線程恢復到運行狀態中來,這樣就可以操作標記讓線程結束 使用Thread類的setDaemon(true)將線程標記為守護線程 當主線程結束之后,守護線程也將終止 join方法,表示加入到正在執行的線程中, 正在執行的線程等到調用join的線程運行完后開始繼續運行 join特點,當a線程執行到了b線程的join()方法時,a線程就會等待b線程執行完,a才會執行 join可以臨時加入線程執行 當b線程處於凍結狀態時,使用interrupt()方法中斷該線程返回到a線程中 Thread.tostring()重寫了object的tostring()方法, 打印:線程名,優先級,線程組 線程組:誰開啟了該線程,該線程就處於哪個組 ThreadGroup可以定義線程組 優先級:搶資源的頻率,誰的優先級高,被執行的頻率會多一點 setPriority ()設置線程的優先級,默認的所有線程的優先級為5, 最大為10 10:MAX_PRIORITY 5: 1:MIN_PRIORITY yield() 暫停正在執行的線程對象,執行其他線程、 什么時候用多線程 線程與線程之間無太大關聯,且都為循環體,為了提高運行效率,可以開多個線程進行數據的執行 class Thread { private static void main(String args[]) { new Thread() { public void run() { for(int i=0;i<1000;i++) { System.out.println(Thread.currentThread().getName()); } } }.start(); Runnable r=new Runnable() { public void run() { for(int i=0;i<10000;i++) { System.out.println(Thread.currentThread().getName()); } } }; new Thread(r).start(); } } class StopThread implement Runable { private boolean flag=ture; public void run() { while(flag) System.out.println(Thread.currentThread().getName()+".....run"); } public void changeFlag() { flag=false } } class DEMO { private static void main(String args[]) { StopThread st=new StopTread(); new Thread(st.start()); \ new Thread(st.start()); int num=0; while(true) { if(num++==60) { break; st.changeFlag(); } System.out.println(Thread.currentThread().getName()+"....."+num); } } } String 類 string s1="abc"; string s2=new String("abc"); string s3="abc" 區別:s1創建一個對象,s2創建兩個對象; s1==s2 為false,判斷的是對象; s1.equies(s2) 為true,判斷兩個字符串是否相同 s1==s3 為ture,為了節約內存,s1和s3指向同一個對象 int length(); 獲取長度 char charAt(int index)獲取指定位置的字符 int indexof(int ch) 返回ch在字符串中第一次出現的位置 int indexOf(int ch,int fromindex);獲取指定字符在指定位置index開始的位置,出現的位置 boolean isEmpty() 判斷長度是否為0 boolean contains(str) boolean startsWith(str) boolean endWith(str) boolean equals(str) 判斷內容是否相同復寫了object類的equals方法 boolean equalsIgnoreCase(str) 忽略大小寫判斷是否相同 if(str.indexof(str)!=-1) if(str.containt(str)) 構造函數:string(char[])將字符轉換為字符串 string (char[] ,offset,count)將字符串一部分轉換為字符串 string copyValueOf(char[],int offset ,int count)將字符串一部分轉換為字符串 char[] toCharArray();將字符串變成字符數組 string valueOf(int) 將整形轉換為string string valueOf(double) 將double轉換為string string replace(oldchar,newchar)替換指定字符串 string[] split(regex)字符串切割 string subString(begin) string subString(begin,end) 獲取子字符串 字符串大小寫轉換,toLowerCase(),toUpperCase() 去除空格:trim() 對兩個字符串自然順序比較:compareTo(string) string s="hello java" string s1=s.replace('a','n') s:hello java s1:hello jnvn string 為final,所以不能被賦值 stringBuffer 是字符串緩沖區, 一個容器,可以操作多種數據類型,長度可變, 數組長度是固定的,但是只能存儲一種類型 append(str)增加 insert(int index,string str) 在指定位置增加字符串 delete(int start,int end) 刪除字符串 包含start,不包含end sb.delete(0,sb.length())刪除緩沖區 deleteCharAt(index)產出指定位置的字符 stringbuffer replace(start,end,str) void setCharAt() API學習方法:先看累說明,思考類的功能, 推測應有方法,推測方法的參數和返回值,查找對應方法 StringBuilder StringBuilder是線程不同步,StringBuffer是線程同步的 若單線程時使用StringBuilder,多線程使用StringBuffer 多線程操作StringBuffer時只能有一個人來操作該對象,里面枷鎖 而StringBuilder沒有線程 線程安全的:表示多線程操作時同步 JDK升級3個因素: 1提高效率 2,簡化書寫 3,提高安全性 基本數據類型對象包裝類 byte Byte short short int Integer long Long boolean Boolean float Float double Double char Charactor 最常見作用: 就是用於基本數據類型和字符串類型之間做轉換, 基本數據類型轉為字符轉: 1,基本數據類型+"" 2,基本數據類型.toString(基本數據類型值)Integer.toString(34); 字符串轉成基本數據類型 1,基本數據類型包裝類.parseXXX(String); Integer.parseInt("123") 10進制轉其他進制 toBinaryString(); toHexString(); toOctalString(); 其他進制轉成10進制: Integer.parseInt("數值",進制);Integer.parseInt("110",2); 裝箱:值類型 轉換為引用類型 拆箱:引用類型轉換為值類型 引用類型比值類型 多了一個null值,拋出 空異常 Integer m=128; Integer n=128 m==n false Integer a=127; Integer b=127; a==b true; 因為a和b指向了同一個內存地址,當int型數值在byte范圍0-127內時,將不開辟內存空間 如果超出了空間,則開辟內存空間 Integer x=Integer("123"); Integer y=Integer(123); x==y false 比較的是對象 x.equals(y) true 比較的是數值 數據結構: Api學習,從頂層查看接口的共性方法 集合類:用於存儲對象 數組固定長度,集合可變長度 數組存儲的對象為同一種對象類型,集合可以存儲不同類型的對象 Collection ---接口 獲取長度 size(),add(),remove(),clear(),contains(),isEmpty();retainAll--交集 ,iterator(); |--List ---接口 ---元素是有序的,元素可以重復,該集合體系有索引 特有方法:add(idex,element),addAll(index,Collection), remove(index),set(index),set(index,element),get(index) subList(form,to),listIterator(); 默認長度為10; |--ArrayList --類 底層的結構是數組結構 (每個元素都有角標) 特點:查詢速度很快,插入刪除慢(角標需要后移)1.2JDK線程不同步 |--LinkedList --類 底層使用的是鏈表數據結構 (每個元素記錄前后關系)特點:插入刪除速度快,查詢速度慢 |--Vector --類 底層是數組數據結構 (被ArrayList替代) 1.0的jdk,特點:同線程同步ArrayList線程不同步 vector 和ArrayList 卻別:vector中有枚舉取出,ArrayList沒有 |--Set ---接口 ---元素是無序的,元素不可以重復 |--HashSet --類 底層數據結構是hash表,線程時非同步的,保證元素唯一性的原理是判斷元素的hashCode是否相同,如果相同,還會繼續判斷元素的equals方法是否為真 |--TreeSet --類 底層數據結構為二叉樹,可以對set集合中的元素進行排序,保證元素唯一性的依據是compareTo方法return 0 返回值為1,表示大於,返回值=0表示相同(不在存儲),返回值-1表示小 當compare恆等於一時,按存入順序迭代輸出 TreeSet排序的第一種方式:讓元素本身具備比較性; 勻速需要實現Comparable接口實現ComparTo方法 這種方式也成為元素的自然順序,或者叫做默認順序 treeset第二種排序方式:當元素自身不具備比較性時,或者具備的比較性不是所需要的 需要讓集合自身具有比較性,在集合初始化時就有了比較方式。 使用構造函數 當兩種排序都存在時,以比較器為主, 比較器:定義一個類,實現Comparator接口,覆蓋compare方法 TreeSet ts=new TreeSet(new MyComparator()); Iterator 迭代器接口 hasNext() 判斷是否有迭代的對象, next()取出迭代對象 ArrayList al=new ArrayList(); al.add("h1"); al.add("h2"); Iterator it=al.iterator(); while(it.hasNext()) { System.out.println(it.next(); } for(Iterator it=al.iterator();it.hasNext();) { System.out.println(it.Next()); } List集合特有的迭代器,ListIterator的子接口 在迭代時不可以通過集合對象的方法操作集合中的元素,因為會發生ConcurrentModificationException異常 所以在迭代器時,只能用迭代器的方法操作元素,可是Iterator的方法時有限的,只能對元素進行 判斷取出刪除,如果想要其他的操作,如增加,修改等,就需要使用其子接口:ListIterator方法獲取 ListIterator li=al.listIterator(); while(li.hasNext()) { Object obj=li.next(); if(obj.equals("java")) { li.set("java1"); li.remove(); li.add(java); } } while(li.hasPrevious()) { Object obj=li.next(); if(obj.equals("java")) { li.set("java1"); li.remove(); li.add(java); } } 枚舉和迭代時一樣的,枚舉的名稱以及方法的名稱過長,被迭代器取代 import java.util.*; class Vector { Vector v=new Vector(); v.add("123"); Enumeration en=v.elements(); while(en.hasMoreElement()) { en.nextElement(); } } LinkList 特有方法: addFirst();addLast() getFirst();getLast() 只取 removeFirst();removeLast();即取又刪 若LinkList中沒有元素,會拋出NosuchElement異常, 在Jdk1.6出現了替代方法: offerFirst();offerLast(); peekFirst();peekLast(); 獲取元素,但元素不被刪除,如果集合中沒有元素,會返回Null pollFirst(),pollLast(); 獲取元素,但是元素被刪除,如果集合中沒有元素,會返回Null class LinkListDemo { public static void main(String args[]) { LinkList link=new LinkList(); while(link.isEmpty()) { link.removeFirst(); } } } LinkListTest 使用LinkList模擬堆棧,或者隊列的數據結構 堆棧:先進后出 杯子 隊列:先進先出 水管 class duilie { private LinkedList link dulie() { link=new LinkedList(); } public void add(object obj) { link.addFirst(); } public object get() { link.removeLast(); } public boolean isNull() { return link.isEmpty(); } } class duizhan { private LinkedList link dulie() { link=new LinkedList(); } public void add(object obj) { link.addFirst(); } public object get() { link.removeFirst(); } public boolean isNull() { return link.isEmpty(); } } duilie d=new duilie(); duilie.add("h1") duilie.add("h2") duilie.add("h3") while(!d.isNull()) { d.get(); } 去除ArrayList中同名元素 在迭代時,循環中,next調用一次就要hasnext判斷一次 class GetNewArrayList { public static ArrayList singleElement(ArrayList al) { ArrayList newal=new ArrayList() Iterator it=al.iterator() while(it.hasNext()) { object obj=it.next(); if(!newal.contains(obj)) { newal.add(obj) } } return newal; } } 存人對象,同姓名,同年齡,視為一個人,為重復對象 class person { String name; int age; person(string name ,int age) { this.name=name; this.age=age; } public boolean equals(object obj) { if(obj instanceof person) { return false; } person p=(person)obj; return this.name.equals(p.name)&&this.age==p.age; } } List集合判斷元素是否相同(remove,contains()方法),依據的是元素的equals方法 HashSet對於判斷判斷,刪除HashSet集合,依據的是元素的hashCode()方法 hashSet:是如何保證元素唯一性 hashCode和equals來完成, 如果元素的HashCode值相同,才會判斷equals、是否為true。(true代表相同元素,所以不會存儲,否則存儲) 如果元素的hashcode值不同,不會調用equals 如果將對象存進HashSet,一般會復寫equals和hasCode方法 class hashSetDemo { public static void main(String args[]) { HashSet h=new HashSet(); h.add("java1"); //add返回boolean型數據,表示該數據是否存入HashSet中 h.add("java2"); h.add("java3"); h.add("java4"); Iterator it=h.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } } class hashSetTest { public static void main(String args[]) { HashSet hs=new HashSet(); hs.add(new person("a1",18)); hs.add(new person("a2",19)); hs.add(new person("a3",20)); hs.add(new person("a4",21)); Iterator it=hs.iterator(); while(it.hasNext()) { person p=(person)it.next(); System.out.println(p.name+"::"+p.age); } } } class person { String name; int age; person(string name ,int age) { this.name=name; this.age=age; } public int hashCode() { return name.hashCode()+age; } public boolean equals(object obj) { if(obj instanceof person) { return false; } person p=(person)obj; return this.name.equals(p.name)&&this.age==p.age; } } TreeSet:可以進行排序 對象如果要存入TreeSet中去,必須具備可比性,繼承Comparable接口實現compareTo方法 當主要條件相同時,要判斷次要條件是否相同 class TreeSetTest { public static void main(String args[]) { TreeSet ts=new TreeSet(); ts.add("abc"); ts.add("bcd"); ts.add("efd"); ts.add("fed"); Iterator it=ts.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } } class person implement Compareable 人本身不具備可比性,所以會出現異常,要繼承此接口 { String name; int age; person(string name ,int age) { this.name=name; this.age=age; } public int compareto(Object obj) { if(! obj instanceof person) { throw new Exception(); } person p=(person)obj; if(this.age>p.age) return 1; if(this.age==p.age) return this.name.compareto(p.name); return -1; } } class TreeSetTest { public static void main(String args[]) { TreeSet ts=new TreeSet(); ts.add(new person("a1",11)); ts.add(new person("a2",12)); ts.add(new person("a3",13)); ts.add(new person("a4",14)); Iterator it=ts.iterator(); while(it.hasNext()) { person p=(person)it.next() System.out.println(p.name+""+p.age); } } } classTreeSetDemo2 --當元素本身不具備比較性, 或者具備的比較性不是需要的,這時需要讓容器本身具備可比性 定義一個比較器,將比較器對象做為參數傳遞給TreeSet集合的構造函數 class TreeSetTest { public static void main(String args[]) { TreeSet ts=new TreeSet(new Mycompare()); //使用排序器進行排序,(比較器排序優先) ts.add(new person("a1",11)); ts.add(new person("a2",12)); ts.add(new person("a3",13)); ts.add(new person("a4",14)); Iterator it=ts.iterator(); while(it.hasNext()) { person p=(person)it.next() System.out.println(p.name+""+p.age); } } } class Mycompare implement Comparator { public int compare(object o1,object o2) { person p1=(person)o1; person p2=(person)o2; int num=p.name.compare(p2.name); if(num==0) { //return p1.age=p2.age; return new Integer(p1.age).compareTo(new Integer(p2.age)); } return num; } } 匿名內部類的實現 class TreeSetTest { public static void main(String args[]) { TreeSet ts=new TreeSet(new Comparator() { public int compare(object o1,object o2) { person p1=(person)o1; person p2=(person)o2; int num=p.name.compare(p2.name); if(num==0) { //return p1.age=p2.age; return new Integer(p1.age).compareTo(new Integer(p2.age)); } return num; } ); //使用排序器進行排序,(比較器排序優先) ts.add(new person("a1",11)); ts.add(new person("a2",12)); ts.add(new person("a3",13)); ts.add(new person("a4",14)); Iterator it=ts.iterator(); while(it.hasNext()) { person p=(person)it.next() System.out.println(p.name+""+p.age); } } } 泛型:JDK1.5版本以后出現新特性,用於解決安全問題,是一個安全機制 好處: 1,將運行時期出現的問題classCastexception,轉移到編譯時期; 方便程序員及時修改bug 2,避免了強制轉換的麻煩 3,提高了類型存儲的安全性 泛型格式: 通過<>來定義要操作的引用類型的數據類型 其實<>就是用來接收類型的 當使用集合時,將集合中要存儲的數據類型做為參數傳遞到<>中即可 什么時候使用泛型,通常在集合框架中很常見,只要見到<>就要定義泛型 class GenericDemo { public static void main(String args[]) { TreeSet<String> ts=new TreeSet<String>(new StringlengthComparator()); ts.add("abcd"); ts.add("abcd"); ts.add("abcd"); Iterator<String> it=ts.iterator(); while(ts.hasNext()) { String s=ts.next(); System.out.println(s); } } } class StringlengthComparator implement Comparator<String> { public int compare(String o1,String o2) { int num= new integer(o1.length()).compareTo(o2.length()); if(num==0) { return o1.compare(o2); } return num; } } 泛型的應用: 什么時候定義泛型類:當類中要操作的引用數據類型不確定的時候 早起定義object來完成擴展,現在定義泛型來完成擴展 泛型類定義的泛型,在整個類中有效,如果被方法是用, 那么泛型類的對象明確要操作的具體類型后,所有要操作的類型就已經固定了, 為了不同方法可以操作不同類型,而且類型還不確定。 那么可以將泛型定義在方法上 class worker { } class student { } class teacher { } class Tool<T> //泛型類 { private T type; public void setObject(T type) { this.type=type; } public T getObject(T type) { return this.type; } } class GenericApp { public static void main(String args[]) { Tool<worker> t=new Tool<worker>(); t.setObject(new worker()); t.getObject(); } } 泛型方法 public <T> void show(T t) { System.out.print(t); } 特殊之處:靜態方法不可以訪問類上定義的泛型,如果靜態方法操作的引用數據類型不確定 可以將泛型定義在方法上 class GenericClass<T> { public static void show(T t) //傳入的t的類型應類的類型一致 { System.out.println(t); } public static <M> void print(M m) //而靜態泛型方法不能與類上定義的類型一致,靜態方法只能使用靜態成員 { System.out.println(m); } } 泛型接口: interface Inter<T> { void show(T t); } class InterClass implements Inter<String> { public <String> void show(String t) { System.out.println(t); } } class InterClass<T> implements Inter<T> { public <T> void show(T t) { System.out.println(t); } } 泛型應用 ?占位符:泛型的限定 ? extends E;可以接收E類型或者E的子類型 上限定 ? super E;可以接收E類型或者E的父類型 下限定 class App { public static void main(String args[]) { ArrayList<String> a1=new ArrayList<String>(); ArrayList<Integer> a2=new ArrayList<Integer>(); Print(a1); Print(a2); } public <T> void Print(ArrayList<T> a) //傳入T類型時可以進行接收,然后操作(T為具體類型) { //遍歷兩個方法 Interator<T> it=a.interator(); while(it.hasNext()) { System.out.println(it.next()); } } public void Print(ArrayList<?> a) //傳入?時無法接收並操作該類型,(?為未知類型,占位符) { //遍歷兩個方法 Interator<?> it=a.interator(); while(it.hasNext()) { System.out.println(it.next()); } } public void Print(ArrayList<?extends Person> a) //類型限定符,只能傳入Person及其子類 { //遍歷兩個方法 Interator<? extends Person> it=a.interator(); while(it.hasNext()) { System.out.println(it.next()); } } } class Person { String name ; int age; Person(String name,int age) { this.name=name; this.age=age; } } class Student extends Person { Student(String name,int age) { super(name,age); } } class Worker extends Person { Worker(String name,int age) { super(name,age); } } public Demo { public static void main(String args[]) { //將student類和woker類存入TreeSet TreeSet ts1=new TreeSet(new comp<Student>()); //在使用比較器的時候使用到了泛型計較器,以Person為比較器的類型,然后傳入子類進行比較 ts1.add(new Student("a1",19)); ts1.add(new Student("a2",20)); ts1.add(new Student("a3",21)); Interator<Student> it=ts1.interator(); while(it.hasNext()) { System.out.println(it.next()); } TreeSet ts2=new TreeSet(new comp<Worker>()); //在使用比較器的時候使用到了泛型計較器,以Person為比較器的類型,然后傳入子類進行比較 ts2.add(new Worker("a1",19)); ts2.add(new Worker("a2",20)); ts2.add(new Worker("a3",21)); Interator<Student> it=ts2.interator(); while(it.hasNext()) { System.out.println(it.next()); } } } class comp implements Comparator<Person> { public int compareTo(Person p1,Person p2) { int num= p1.name.compareTo(p2.name) ; if(num==0) { return p1.age.compareTo(p2.age); } return num; } } 傳智播客畢向東Java基礎視頻教程-day16-01-集合(Map概述) Map:該集合存儲鍵值對,一對一的對應關系,而且保證建的唯一性 clear(); boolean containKey(object key) boolean containValue(Object value) isEmpty() put(K key,V value) putAll(Map()) get(Object key) size(); value(); entrySet(); keySet(); Map |--Hashtable 底層是hash表數據結構,不能存入null建null值的情況,該集合是線程同步的 |--Hashmap 底層是hash表數據結構,允許使用null建null值的情況,該集合是線程不同步的 |--TreeMap 底層是二叉樹結構,線程不同步,可以用於給map集合的健排序 和set很像:set底層使用的是Map集合 class MapDemo { public static void main(String args[]) { Map<String,String> map=new HashMap<String,String>(); map.put("zhangsan","001"); map.put("Lisi","002"); map.put("Wangwu","003") ; if(map.containKey("zhangsan")) System.out.println(map.remove("zhangsan")); if(map.get("Lisi")!=null)//可以通過get方法的返回值來判斷一個鍵是否存在 System.out.println(map.remove(“Lisi")); } } put會返回這個鍵原來的值,並覆蓋該值 增加元素,如果出現增加時相同的健,那么后增加的值會覆蓋原有鍵對應的值,並put方法會返回被覆蓋的值 map集合的兩種取出方式: 1,keySet()將map中所有的鍵存入到Set集合,因為Set集合具備迭代器,所以可以通過迭代方式取出所有的鍵,並通過get方法取出所有的值 先獲取map集合的所有鍵的set集合,keySet(); 有了set集合就可以取出鍵值了 map集合的取出原理:將map集合轉成set集合,在通過迭代器取出 2,Set<Map.Entry<k,v>> entrySet() 將map集合中的映射關系存入到了set中, 這個關系的類型為Map.Entry對象,該方法的getKey(),getValue(); 那么關系對象Map.Entry獲取到后,就可以通過getKey(),getValue()獲取鍵值 Map.Entry:其實Entry也是一個借口,它是Map接口中的一個內部接口 interface Map { public static interface Entry //接口在成員位置才能使用static 修飾符 { public abstract Object getKey(); public abstract Object getValue(); } } class HashMap implements Map { class hash implemetns Map.Entry { public abstract Object getKey(); public abstract Object getValue(); } } class MapDemo { public static void main(String args[]) { Map<String,String> map=new HashMap<String,String>(); map.put("zhangsan","001"); map.put("Lisi","002"); map.put("Wangwu","003") //兩種取出方法 ; Set<String> keySet=map.keySet(); Interator<String> it=keyset.iterator(); while(it.hasNext()) { Syste.out.println(map.get(it.next())); } Set<Map.Entry<String,String>> entrySet=map.entrySet(); Iterator<Map.Entry<String,String>> it=map.entrySet(); while(it.hasNext()) { Map.Entry<String,String> me = it.next(); String key=me.getKey(); String value=me.getValue(); } } } 什么時候使用map集合: 當數據之間存在映射關系時,可以使用map集合 class APPDemo { public static void main(String args[]) { String str="abcdeabcdefgaaaabbc"; char[] ch=str.toCharArray(); TreeMap<Charactor,Integer> tm=new TreeMap<Charactor,Integer>(); for(int i=0;i<ch.length;i++) { Integer value=tm.get(ch[i]); //獲取ch[i]對應的值,如果不存在返回null if(value==null) { tm.put(ch[i],1); //將ch[i]對應的值,存入到treeMap中,如果該值存在,則覆蓋原有數據 } else { value+=1; tm.put(ch[i],value); } } StringBuilder sb=new StringBuilder(); Set<Map.Entry<Charactor,Interger>> entrySet=tm.entrySet(); Iterator<Map.Entry<Charactor,Interger>> it=entrySet.iterator(); while(it.hasNext()) { Map.Entry<Charactor,Integer> me=it.next(); Charactor ch=me.getKey(); Integer value=me.getValue(); sb.append(ch+"("+value+")"); } System.out.println(sb); } } map擴展: map集合被使用是因為具備映射關系; map嵌套 1對多映射 class Demo { public static void main(String args[]) { HashMap<String,String> renliziyuan=new HashMap<String,String>(); bumen.put("01","a"); bumen.put("02","b"); HashMap<String,String> it=new HashMap<String,String>(); bumen.put("01","c"); bumen.put("02","d"); HashMap<String,HashMap<String,String>> Main=HashMap<String,HashMap<String,String>>(); Main.put("renliziyuan",renliziyuan); Main.put("it",it); //取數據 Iterator<String> it=Main.keySet().iterator(); while(it.hasNext()) { String name=it.next(); HashMap<String,String> part =Main.get(name); System.out.println(name); GetPartInfo( part); } } public void GetPartInfo(HashMap<String,String> part) { Iterator<String> it=part.keySet().iterator(); while(it.hasNext()) { String id=it.next(); String name=part.get(id); System.out.println(id+":"+name); } } } Collections: 工具類,靜態類,用於對集合進行操作 Collections.sort(List) 自然排序 Collections.sort(List l,Comparator c)按照比較器排序 Collections.binarySearch(List) 返回角標,如果為負,表示角標不存在,返回-號,加上插入點-1 Collections.fill(List l,String str) 將集合中的元素全部替換為str Collections.replaceAll(List l,String Old,String new) 將制定集合中的Old值全部替換成new Collections.reverse(List l) 反轉集合 Collections.swap(List l,int a,int b ) 交換List中角標為a和b的位置 Collections.shuffle(List); 隨機置換List Arrays 用於操作數據的工具類,靜態類 Arrays.equals(Object a1,object a2) 比較數組中元素是否相同 Arrays.toString(arr); Arrays.asList(arr); 將數組編程list集合,可以使用集合的思想和方法來操作數組中的元素 將數組編程集合,不可以使用集合的增刪方法,因為數組的長度是固定的 如果增刪,那么發生unsupporteException異常 如果數組中的元素都是對象,變成集合時,數組中的元素就直接轉換為集合中的元素 如果數組中的元素都是基本數據類型。,那么會將該數組作為集合中的元素存在 Collection接口中的toArray()方法:指定類型的數組要定義長度,當指定類型的數組的長度小於了集合的size,那么該方法內部會創建一個新的數組,長度為集合的size, 當指定的數組類型的長度,大於了集合的size就不會新創建數組,而是使用傳遞進來的數組 所以創建一個剛剛好的數組最優 toArray(new String[0]); 集合變數組的原因:為了限定對元素的操作,不需要對元素進行增刪 foreach迭代 ArrayList<String> a=new ArrayList<String>(); a1.add("123") a1.add("123") a1.add("123") for(String s:a) //只能對集合中元素進行取出,不能修改 { System.out.println(s); } 格式: for(數據類型 變量名:被遍歷的集合(Collection)或者數組) { } 對集合進行遍歷的時候,只能獲取元素,但是不能對集合進行操作 迭代器,除了遍歷,還可以進行remove集合中元素的操作 如果用ListIterator,還可以再遍歷過程中進行增刪改查操作 傳統的for循環高級for區別:高級for有一個局限性,必須有被遍歷的目標,(如打印指定次數的一條語句) 建議在遍歷數組的時候使用傳統for循環,因為傳統for循環可以定義角標 HashMap<Integer,String> hm=new HashMap<Integer,String>(); hm.put(1,"a"); hm.put(2,"b"); hm.put(3,"c"); Set<Integer> keySet=hm.keySet(); for(Integer i:keySet) { System.out.println(i+":"+hm.get(i)) } Set<Map.Entry<Integer,String>> entrySet=hm.entrySet(); for(Map.Entry<Integer,String> me: hm.entrySet()) { System.out.println(me.getKey()+":"+me.getValue()) } JDK1.5出現新特性 可變參數:上一種參數的簡寫形式 public static void show(String str,int... arr) 方法的可變參數,可變參數一定定義在參數最后面 靜態導入: import static java.util.Arrays.*;將類中所有“靜態成員”導入到該類中 當類名重名時,需要制定具體的包名, 當方法重名時,需要指定具體的對象或者類 創建圖形化界面: 1,創建Frame窗體 2,對Frame進行設計,大小,位置,布局 3,定義組建 4,將組建通過窗體的add方法增加到窗體中 5,將窗體現實,通過setVisible(true) 事件監聽機制特點: 1,事件源 2,事件 3,監聽器 4,事件處理 事件源:就是awt或者swing包中的那些圖形界面組建 事件:每一個事件源都有自己特有的對應事件和共性事件 監聽器:將可以出發某一個事件的動作(不止一個)都已經封裝到了監聽器中 以上三者在java中都已經定義好了,直接獲取其對象用就可以了 程序員要做的就是:事件處理 class AwtDemo { public static void main(String args[]) { Frame f=new Frame("Java Awt"); f.setSize(500,400); f.setLocation(300,200); f.setLayout(new FlowLayout()); Button btn=new Butten("btn按鈕"); f.add(btn); //f.addWindowLisener(new MyWin()); f.addWindowLisener(new MyWin(){ //匿名內部類來實現事件 public windowClosing(WindowEvent e) { System.exit(0); } }); f.setVisible(true); } } 因為WindowLisener的子類:windowAdapter已經實現了WindowListener接口 並覆蓋了其中的所有方法,那么我們只要繼承自windowAdapter覆蓋我們需要的方法即可; class MyWin extends WindowAdapter { public windowClosing(WindowEvent e) { System.exit(0); } } 需要導入以下兩個包 java.awt.*; java.awt.event.*;