java多線程處理與數據集合


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

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.*;

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM