進程:是一個正在執行中的程序
沒一個進程執行都有一個執行順序,該順序就是一個執行路徑
或者叫一個控制單元
進程用於給程序分配內存空間
線程就是:進程中的獨立的控制單元,線程控制着進程的執行。
一個進程中至少有一個線程
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.*;