Java學習筆記(14)

需求:一個銀行帳戶5000塊,兩夫妻一個拿着存摺,一個拿着卡,開始取錢比賽,每次只能取1000,要求不許出現線程安全問題java

public class Demo10 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //建立了兩個線程對象
        BankThread thread1=new BankThread("老公");
        BankThread thread2=new BankThread("老婆");
        //調用start方法開啓線程取錢
        thread1.start();
        thread2.start();
    }

}
class BankThread extends Thread{
    static int count=5000;
    public BankThread() {}
    public BankThread(String name) {
        super(name);
    }
    
    @Override
    public void run() {
        // TODO Auto-generated method stub
        while (true) {
            synchronized ("鎖") {
                if (count>0) {
                    System.out.println(Thread.currentThread().getName()+"取走了1000塊,還剩餘"+(count-1000)+"元");
                    count-=1000;
                }
                else {
                    System.out.println("取光了...");
                    break;
                }
            }
        }
        //super.run();
    }
}


結果:
老公取走了1000塊,還剩餘4000元
老公取走了1000塊,還剩餘3000元
老公取走了1000塊,還剩餘2000元
老公取走了1000塊,還剩餘1000元
老公取走了1000塊,還剩餘0元
取光了...
取光了...

注意這個同步代碼塊不能把while也寫進去,這樣的話,一個線程進去,只有執行完while纔會出來,也就是取光了錢纔會出來,就不符合了數組

 

方式二:同步函數安全

同步函數就是使用synchronized修飾一個函數多線程

同步函數要注意的事項:ide

  1. 若是是一個非靜態的同步函數,鎖對象是this對象,若是是靜態的同步函數,鎖對象是當前函數所屬的類的字節碼文件(class對象)
  2. 同步函數的鎖對象是固定的,不能由你來指定的

推薦使用:同步代碼塊函數

緣由:this

  1. 同步代碼塊的鎖對象能夠由咱們隨意指定,方便控制。同步函數的鎖對象是固定的,不能由咱們來指定
  2. 同步代碼塊能夠很方便控制須要被同步的代碼的範圍,同步函數必須是整個函數的全部代碼都被同步了
@Override
    public void run() {
        // TODO Auto-generated method stub
        while (true) {
            synchronized ("鎖") {
                if (count>0) {
                    System.out.println(Thread.currentThread().getName()+"取走了1000塊,還剩餘"+(count-1000)+"元");
                    count-=1000;
                }
                else {
                    System.out.println("取光了...");
                    break;
                }
            }
        }
        //getMoney();
        //super.run();
    }
    /*public static synchronized void getMoney() {
        while (true) {
            if (count>0) {
                System.out.println(Thread.currentThread().getName()+"取走了1000塊,還剩餘"+(count-1000)+"元");
                count-=1000;
            }
            else {
                System.out.println("取光了...");
                break;
            }
        }
    }*/

註釋裏的即爲同步函數,這裏必須使用靜態的同步函數,由於若是是非靜態的話,兩個線程對象就有兩個各自的鎖對象,不知足鎖的條件spa

 

死鎖:java中同步機制解決了線程安全問題,可是同時也引起死鎖現象線程

 死鎖現象出現的根本緣由:code

  1. 存在兩個或者兩個以上的線程
  2. 存在兩個或者兩個以上的共享資源

死鎖現象的解決方案:沒有方案,只能儘可能避免發生而已

public class Demo1 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        DeadLock thread1=new DeadLock("張三");
        DeadLock thread2=new DeadLock("狗娃");
        //開啓線程
        thread1.start();
        thread2.start();
    }

}
class DeadLock extends Thread{
    public DeadLock() {}
    public DeadLock(String name) {
        super(name);
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        if ("張三".equals(Thread.currentThread().getName())) {
            synchronized ("遙控器") {//這個與下面的"遙控器"是一個對象,由於是字符串常量池中的
                System.out.println("張三拿到了遙控器,準備去拿電池!");
                synchronized ("電池") {
                    System.out.println("張三拿到了遙控器與電池,開着空調爽歪歪的吹着...");
                }
            }
        }
        else if ("狗娃".equals(Thread.currentThread().getName())) {
            synchronized ("電池") {
                System.out.println("狗娃拿到了電池,準備去拿遙控器!");
                synchronized ("遙控器") {
                    System.out.println("狗娃拿到了遙控器與電池,開着空調爽歪歪的吹着...");
                }
            }
        }
        //super.run();
    }
}

結果:
張三拿到了遙控器,準備去拿電池!
狗娃拿到了電池,準備去拿遙控器!

 

建立多線程方式二:

  1. 自定義一個類實現Runnable接口
  2. 實現Runnable的run方法,把自定義線程的任務定義在run方法上
  3. 建立Runnable實現類對象
  4. 建立Thread類的對象,而且把Runnable實現類的對象做爲實參傳遞
  5. 調用Thread對象的start方法開啓一個線程
public class Demo2 implements Runnable{

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Demo2 d=new Demo2();
        //建立Thread類的對象,把Runnable實現類對象做爲實參傳遞
        Thread thread=new Thread(d,"狗娃");
        //調用Thread對象的start方法開啓線程
        thread.start();
        
        for (int i=0;i<50;i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for (int i=0;i<50;i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

結果:
main:0
main:1
main:2
main:3
狗娃:0
狗娃:1
狗娃:2
狗娃:3
狗娃:4
main:4
main:5
main:6
狗娃:5
main:7
狗娃:6
main:8
main:9
main:10
main:11
狗娃:7
狗娃:8
main:12
main:13
main:14
main:15
main:16
main:17
main:18
main:19
main:20
main:21
main:22
main:23
main:24
main:25
main:26
main:27
main:28
狗娃:9
main:29
狗娃:10
狗娃:11
狗娃:12
狗娃:13
狗娃:14
狗娃:15
狗娃:16
狗娃:17
狗娃:18
狗娃:19
狗娃:20
狗娃:21
狗娃:22
main:30
狗娃:23
狗娃:24
狗娃:25
狗娃:26
main:31
狗娃:27
狗娃:28
狗娃:29
狗娃:30
狗娃:31
狗娃:32
狗娃:33
狗娃:34
狗娃:35
狗娃:36
狗娃:37
狗娃:38
狗娃:39
狗娃:40
狗娃:41
main:32
main:33
main:34
main:35
main:36
main:37
main:38
main:39
main:40
main:41
main:42
main:43
main:44
main:45
main:46
main:47
main:48
main:49
狗娃:42
狗娃:43
狗娃:44
狗娃:45
狗娃:46
狗娃:47
狗娃:48
狗娃:49

 問題一:Runnable實現類的對象是線程對象嗎?

Runnable實現類的對象並非一個線程對象,只不過是實現了Runnable接口的對象而已。只有是Thread或者是Thread的子類纔是線程對象(要有start方法)

問題二:爲何要把Runnable實現類的對象做爲實參傳遞給Thread對象呢,做用是什麼?

做用就是把Runnable實現類的對象的run方法做爲了線程的任務代碼去執行了

 @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

上面是Thread對象的run方法,能夠看出是調用了實現類對象的run方法

例題:售票問題(如上)

public class Demo3 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //建立了一個Runnable實現類的對象
        SaleTicket saleTicket=new SaleTicket();
        //建立三個線程對象模擬三個窗口
        Thread thread1=new Thread(saleTicket,"窗口1");
        Thread thread2=new Thread(saleTicket,"窗口2");
        Thread thread3=new Thread(saleTicket,"窗口3");
        //開啓線程售票
        thread1.start();
        thread2.start();
        thread3.start();
    }

}
class SaleTicket implements Runnable{
    int num=50;//票數 這裏不用加static修飾,是由於只建立了一個實現類對象saleTicket,因此不用靜態變量,其實加了也能夠,只不過這份數據的生命週期會變的很長
    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(true) {
            synchronized ("鎖") {
                if (num>0) {
                    System.out.println(Thread.currentThread().getName()+"售出了第"+num+"號票");
                    num--;
                }
                else {
                    System.out.println("售罄了...");
                    break;
                }
            }
        }
    }
}

結果:
窗口1售出了第50號票
窗口1售出了第49號票
窗口1售出了第48號票
窗口1售出了第47號票
窗口1售出了第46號票
窗口1售出了第45號票
窗口1售出了第44號票
窗口3售出了第43號票
窗口3售出了第42號票
窗口3售出了第41號票
窗口3售出了第40號票
窗口2售出了第39號票
窗口2售出了第38號票
窗口2售出了第37號票
窗口2售出了第36號票
窗口2售出了第35號票
窗口2售出了第34號票
窗口2售出了第33號票
窗口2售出了第32號票
窗口2售出了第31號票
窗口3售出了第30號票
窗口3售出了第29號票
窗口3售出了第28號票
窗口3售出了第27號票
窗口3售出了第26號票
窗口3售出了第25號票
窗口3售出了第24號票
窗口3售出了第23號票
窗口3售出了第22號票
窗口3售出了第21號票
窗口3售出了第20號票
窗口3售出了第19號票
窗口3售出了第18號票
窗口3售出了第17號票
窗口3售出了第16號票
窗口3售出了第15號票
窗口3售出了第14號票
窗口3售出了第13號票
窗口3售出了第12號票
窗口3售出了第11號票
窗口3售出了第10號票
窗口3售出了第9號票
窗口3售出了第8號票
窗口3售出了第7號票
窗口3售出了第6號票
窗口3售出了第5號票
窗口3售出了第4號票
窗口3售出了第3號票
窗口3售出了第2號票
窗口3售出了第1號票
售罄了...
售罄了...
售罄了...

以上兩種建立線程的方式,推薦使用第二種 實現Runnable接口的

緣由:由於java是單繼承,多實現的

 

線程的通信:一個線程完成了本身的任務時,要通知另一個線程去完成另一個任務。

wait(): 等待        若是線程執行了wait方法,那麼該線程會進入等待的狀態,等待狀態下的線程必需要被其餘線程調用notify方法才能喚醒
notify():喚醒      喚醒線程池中等待的線程其中一個

notifyAll():    喚醒線程池中全部等待的線程

wait與notify方法要注意的事項:

  1. wait與notify方法是屬於Object對象的(鎖對象能夠是任意對象,而若是將此方法定義在Thread類中,就不能由鎖對象調用了)
  2. wait與notify方法必需要在同步代碼塊或者是同步函數中才能使用(只有同步代碼塊或者是同步函數纔有鎖的概念)
  3. wait方法與notify方法必需要由鎖對象調用(必須是同一個鎖,不然沒用)
public class Demo4 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Product p=new Product();//產品
        //建立生產者對象
        Producter producter=new Producter(p);
        //建立消費者對象
        Customer customer=new Customer(p);
        //調用start方法開啓線程
        producter.start();
        customer.start();
    }

}
//產品類
class Product{
    String name;//價格
    double price;//價格
    boolean flag=false;//產品是否生產完畢的標識,默認狀況是沒有生產完成
    
}
//生產者類
class Producter extends Thread{
    Product p;//產品
    public Producter() {}
    public Producter(String name) {
        super(name);
    }
    public Producter(Product p) {
        this.p=p;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        int i=0;
        while (true) {
            synchronized (p) {
                if (p.flag==false) {
                    if (i%2==0) {
                        p.name="蘋果";
                        /*try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }*/
                        p.price=6.5;
                    }
                    else {
                        p.name="香蕉";
                        p.price=2.0;
                    }
                    System.out.println("生產者生產出了:"+p.name+" 價格是:"+p.price);
                    p.flag=true;
                    i++;
                    p.notify();//喚醒消費者去消費
                }
                else {
                    //已經生產完畢,等待消費者先去消費
                    try {
                        p.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }
        //super.run();
    }
}
//消費者類
class Customer extends Thread{
    public Customer() {}
    public Customer(String name) {
        super(name);
    }
    public Customer(Product p) {
        this.p=p;    }
    Product p;
    @Override
    public void run() {
        // TODO Auto-generated method stub
        while (true) {
            synchronized (p) {
                if (p.flag==true) {//產品已經生產完畢
                    System.out.println("消費者消費了"+p.name+" 價格:"+p.price);
                    p.flag=false;
                    p.notify();//喚醒生產者去生產
                }
                else {
                    //產品尚未生產,應該等待生產者先生產
                    try {
                        p.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }
        //super.run();
    }
}

結果:
生產者生產出了:香蕉 價格是:2.0
消費者消費了香蕉 價格:2.0
生產者生產出了:蘋果 價格是:6.5
消費者消費了蘋果 價格:6.5
生產者生產出了:香蕉 價格是:2.0
消費者消費了香蕉 價格:2.0
生產者生產出了:蘋果 價格是:6.5
消費者消費了蘋果 價格:6.5
生產者生產出了:香蕉 價格是:2.0
消費者消費了香蕉 價格:2.0
生產者生產出了:蘋果 價格是:6.5
消費者消費了蘋果 價格:6.5
生產者生產出了:香蕉 價格是:2.0
消費者消費了香蕉 價格:2.0
生產者生產出了:蘋果 價格是:6.5
消費者消費了蘋果 價格:6.5
生產者生產出了:香蕉 價格是:2.0
消費者消費了香蕉 價格:2.0
生產者生產出了:蘋果 價格是:6.5
消費者消費了蘋果 價格:6.5
生產者生產出了:香蕉 價格是:2.0
消費者消費了香蕉 價格:2.0
生產者生產出了:蘋果 價格是:6.5
消費者消費了蘋果 價格:6.5
生產者生產出了:香蕉 價格是:2.0
消費者消費了香蕉 價格:2.0
生產者生產出了:蘋果 價格是:6.5
消費者消費了蘋果 價格:6.5
生產者生產出了:香蕉 價格是:2.0
消費者消費了香蕉 價格:2.0
生產者生產出了:蘋果 價格是:6.5
消費者消費了蘋果 價格:6.5
生產者生產出了:香蕉 價格是:2.0
消費者消費了香蕉 價格:2.0
生產者生產出了:蘋果 價格是:6.5
消費者消費了蘋果 價格:6.5
生產者生產出了:香蕉 價格是:2.0
消費者消費了香蕉 價格:2.0
生產者生產出了:蘋果 價格是:6.5
消費者消費了蘋果 價格:6.5
生產者生產出了:香蕉 價格是:2.0
消費者消費了香蕉 價格:2.0
生產者生產出了:蘋果 價格是:6.5
消費者消費了蘋果 價格:6.5
生產者生產出了:香蕉 價格是:2.0
消費者消費了香蕉 價格:2.0
生產者生產出了:蘋果 價格是:6.5
消費者消費了蘋果 價格:6.5
生產者生產出了:香蕉 價格是:2.0
消費者消費了香蕉 價格:2.0
生產者生產出了:蘋果 價格是:6.5
消費者消費了蘋果 價格:6.5
生產者生產出了:香蕉 價格是:2.0
消費者消費了香蕉 價格:2.0
生產者生產出了:蘋果 價格是:6.5
消費者消費了蘋果 價格:6.5
生產者生產出了:蘋果 價格是:6.5
消費者消費了蘋果 價格:6.5
生產者生產出了:香蕉 價格是:2.0
消費者消費了香蕉 價格:2.0
生產者生產出了:蘋果 價格是:6.5
消費者消費了蘋果 價格:6.5
生產者生產出了:香蕉 價格是:2.0
消費者消費了香蕉 價格:2.0
生產者生產出了:蘋果 價格是:6.5
消費者消費了蘋果 價格:6.5
生產者生產出了:香蕉 價格是:2.0
消費者消費了香蕉 價格:2.0
生產者生產出了:香蕉 價格是:2.0
消費者消費了香蕉 價格:2.0
生產者生產出了:蘋果 價格是:6.5
消費者消費了蘋果 價格:6.5
生產者生產出了:香蕉 價格是:2.0
消費者消費了香蕉 價格:2.0
生產者生產出了:蘋果 價格是:6.5
消費者消費了蘋果 價格:6.5
...

 wait()方法:一個線程若是執行了wait方法,那麼該線程就會進去一個以鎖對象爲標識符的線程池中等待

notify()方法:若是一個線程執行notify方法,那麼就會喚醒以鎖對象爲標識符創建的線程池中的等待線程中的其中一個(若是有多個的話,會任意喚醒一個,但通常來講,先等待的會被先喚醒)

線程的中止:

  1. 中止一個線程,咱們通常都會經過一個變量去控制的。(線程執行完任務就中止了,因此可讓線程執行完任務或者是根本不能執行任務代碼)
  2. 若是須要中止一個處於等待狀態下的線程,咱們須要經過變量配合notify方法或者interrupt方法來使用
public class Demo5 extends Thread{

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Demo5 d=new Demo5("狗娃");
        d.start();
        
        for (int i=0;i<100;i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
            //當主線程的i是80的時候中止狗娃線程
            if (i==80) {
                d.flag=false;
                d.interrupt();//把線程的等待狀態強制清除,被清除狀態的線程會接收到一個InterruptedException
                /*synchronized (d) {
                    d.notify();
                }*/
            }
        }
    }
    boolean flag=true;
    public Demo5() {}
    public Demo5(String name) {
        super(name);
    }
    @Override
    public synchronized void run() {
        // TODO Auto-generated method stub
        int i=0;
        while (flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                System.out.println("接收到異常了...");
            }
            System.out.println(Thread.currentThread().getName()+":"+i);
            i++;
        }
        //super.run();
    }
}

結果:
main:0
main:1
main:2
main:3
main:4
main:5
main:6
main:7
main:8
main:9
main:10
main:11
main:12
main:13
main:14
main:15
main:16
main:17
main:18
main:19
main:20
main:21
main:22
main:23
main:24
main:25
main:26
main:27
main:28
main:29
main:30
main:31
main:32
main:33
main:34
main:35
main:36
main:37
main:38
main:39
main:40
main:41
main:42
main:43
main:44
main:45
main:46
main:47
main:48
main:49
main:50
main:51
main:52
main:53
main:54
main:55
main:56
main:57
main:58
main:59
main:60
main:61
main:62
main:63
main:64
main:65
main:66
main:67
main:68
main:69
main:70
main:71
main:72
main:73
main:74
main:75
main:76
main:77
main:78
main:79
main:80
main:81
main:82
main:83
main:84
main:85
main:86
main:87
main:88
main:89
main:90
main:91
main:92
main:93
main:94
main:95
main:96
main:97
main:98
main:99
java.lang.InterruptedException
    at java.base/java.lang.Object.wait(Native Method)
    at java.base/java.lang.Object.wait(Object.java:328)
    at test6.Demo5.run(Demo5.java:36)
接收到異常了...
狗娃:0

守護線程(後臺線程):若是一個進程中只剩下了守護線程,那麼守護線程也會死亡

isDaemon()    判斷線程是否爲守護線程

setDaemon()    設置線程是否爲守護線程,true爲守護線程,false爲非守護線程

一個線程默認都不是守護線程

public class Demo6 extends Thread{

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Demo6 d=new Demo6("後臺線程");
        System.out.println("是守護線程嗎?"+d.isDaemon());//判斷線程是否爲守護線程
        d.setDaemon(true);//setDaemon()  設置線程是否爲守護線程,true爲守護線程,false爲非守護線程
        System.out.println("是守護線程嗎?"+d.isDaemon());
        d.start();
        for (int i=1;i<=100;i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
    
    public Demo6() {}
    public Demo6(String name) {
        super(name);
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for (int i=1;i<=100;i++) {
            System.out.println("更新包目前下載"+i+"%");
            if (i==100) {
                System.out.println("更新包下載完畢!準備安裝...");
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        super.run();
    }
}

結果:
是守護線程嗎?false
是守護線程嗎?true
main:1
main:2
main:3
更新包目前下載1%
main:4
main:5
main:6
main:7
main:8
main:9
main:10
main:11
main:12
main:13
main:14
main:15
main:16
main:17
main:18
main:19
main:20
main:21
main:22
main:23
main:24
main:25
main:26
main:27
main:28
main:29
main:30
main:31
main:32
main:33
main:34
main:35
main:36
main:37
main:38
main:39
main:40
main:41
main:42
main:43
main:44
main:45
main:46
main:47
main:48
main:49
main:50
main:51
main:52
main:53
main:54
main:55
main:56
main:57
main:58
main:59
main:60
main:61
main:62
main:63
main:64
main:65
main:66
main:67
main:68
main:69
main:70
main:71
main:72
main:73
main:74
main:75
main:76
main:77
main:78
main:79
main:80
main:81
main:82
main:83
main:84
main:85
main:86
main:87
main:88
main:89
main:90
main:91
main:92
main:93
main:94
main:95
main:96
main:97
main:98
main:99
main:100

join方法:加入

一個線程若是執行了join語句,那麼就有新的線程加入,執行該語句的線程必需要讓步給新加入的線程先完成任務,而後才能繼續執行

public class Demo7 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Mon m=new Mon();
        m.start();
    }

}
//老媽
class Mon extends Thread{
    @Override
    public void run() {
        // TODO Auto-generated method stub
        System.out.println("媽媽洗菜");
        System.out.println("媽媽切菜");
        System.out.println("媽媽準備炒菜,發現沒有醬油了...");
        //叫兒子去打醬油
        Son s=new Son();
        s.start();
        try {
            s.join();//加入    一個線程若是執行了join語句,那麼就有新的線程加入,執行該語句的線程必需要讓步給新加入的線程先完成任務,而後才能繼續執行
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("媽媽繼續炒菜");
        System.out.println("全家一塊兒吃飯...");
        super.run();
    }
}
class Son extends Thread{
    @Override
    public void run() {
        // TODO Auto-generated method stub
        System.out.println("兒子下樓..");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("兒子一直往前走");
        System.out.println("兒子打完醬油了");
        System.out.println("上樓,把醬油給老媽");
        
        super.run();
    }
}

結果:
媽媽洗菜
媽媽切菜
媽媽準備炒菜,發現沒有醬油了...
兒子下樓..
兒子一直往前走
兒子打完醬油了
上樓,把醬油給老媽
媽媽繼續炒菜
全家一塊兒吃飯...

集合:

數組:存儲同一種數據類型的集合容器

數組的特色:

  1. 只能存儲同一種數據類型的數據
  2. 一旦初始化,長度固定
  3. 數組中的元素與元素之間的內存地址是連續的

注意:Object類型的數組能夠存儲任意類型的數據

public class Demo8 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Object[] arr=new Object[10];
        arr[0]="abc";
        arr[1]='a';
        arr[2]=true;
        arr[3]=12;
    }

}

集合:
集合是存儲對象數據的集合容器

集合比數組的優點:

  1. 集合能夠存儲任意類型的對象數據,數組只能存儲同一種數據類型的數據
  2. 集合的長度是會發生變化的,數組的長度是固定的

Collection 單例集合的根接口

----------|  List    若是是實現了List接口的集合類,具有的特色是:有序,可重複

----------|  Set    若是是Set接口的集合類,具有的特色是:無序,不可重複

Collection中的方法:

增長

add(E e)     添加成功返回true,添加失敗返回false
addAll(Collection<? extends E> c)      把一個集合的元素添加到另一個集合中去 

public static void main(String[] args) {
        // TODO Auto-generated method stub
        Collection c=new ArrayList();
        c.add("小龍女");
        c.add("孫笑川");
        System.out.println("添加成功嗎?"+c.add("楊過"));
        System.out.println("集合的元素:"+c);
        //建立一個集合
        Collection c2=new ArrayList();
        c2.add("虛竹");
        c2.add("段譽");
        c.addAll(c2);//把c2的元素添加到c集合中去
        System.out.println("集合的元素:"+c);
    }

結果:
添加成功嗎?true
集合的元素:[小龍女, 孫笑川, 楊過]
集合的元素:[小龍女, 孫笑川, 楊過, 虛竹, 段譽]

刪除

clear()     //清空集合中的元素
remove(Object o)     指定集合中的元素刪除,刪除成功返回true,刪除失敗返回false
removeAll(Collection<?> c)     刪除一個集合中與參數集合的交集元素,只是刪除前面集合中的元素,並不刪除參數集合的元素
retainAll(Collection<?> c)     保留這個集合與參數集合中的交集元素,其餘刪除

public static void main(String[] args) {
        // TODO Auto-generated method stub
        Collection c=new ArrayList();
        c.add("小龍女");
        c.add("孫笑川");
        System.out.println("添加成功嗎?"+c.add("楊過"));
        System.out.println("集合的元素:"+c);
        //建立一個集合
        Collection c2=new ArrayList();
        c2.add("虛竹");
        c2.add("段譽");
        c2.add("小龍女");
        c2.add("楊過");
        //c.addAll(c2);//把c2的元素添加到c集合中去
        //c.clear();
        //c.removeAll(c2);
        /*System.out.println("集合的元素:"+c);
        System.out.println("集合的元素:"+c2);
        System.out.println("刪除成功嗎?"+c.remove("孫笑川"));
        System.out.println("集合的元素:"+c);
        System.out.println("刪除成功嗎?"+c.remove("過兒"));
        System.out.println("集合的元素:"+c);
        */
        c.retainAll(c2);
        System.out.println("集合中的元素:"+c);
    }

結果:
添加成功嗎?true
集合的元素:[小龍女, 孫笑川, 楊過]
集合中的元素:[小龍女, 楊過]

查看

size()     查看元素個數

System.out.println("查看元素的個數:"+c.size());
        c.clear();
        System.out.println("查看元素的個數:"+c.size());
        System.out.println("集合中的元素:"+c);

結果:
查看元素的個數:3
查看元素的個數:0
集合中的元素:[]

判斷

isEmpty()     判斷集合是否爲空元素
contains(Object o)      判斷集合中是否存在指定的元素
containsAll(Collection<?> c)      該集合是否包含指定集合中的全部元素

import java.util.ArrayList;
import java.util.Collection;

/*
 判斷
         isEmpty()    判斷集合是否爲空元素
         contains(Object o)     判斷集合中是否存在指定的元素
         containsAll(Collection<?> c)     該集合是否包含指定集合中的全部元素
  
  
  */
public class Demo2 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        /*Collection c=new ArrayList();
        c.add("小龍女");
        c.add("孫笑川");
        c.add("楊過");
        //c.clear();
        System.out.println("判斷集合是否爲空元素:"+c.isEmpty());
        System.out.println("判斷集合中是否存在指定的元素:"+c.contains("段譽"));
        */
        //集合添加自定義的元素
        Collection c=new ArrayList();
        c.add(new Person(110,"狗娃"));
        c.add(new Person(119,"狗剩"));
        c.add(new Person(120,"鐵蛋"));
        //在現實生活中,只要身份證編號一致,那麼就爲一我的
        c.contains(new Dog());//這裏是調用了實參的equals方法,而不是調用了集合元素的equals方法,也就是這裏調用了狗的equals方法,而不是調用了人的方法
        System.out.println("存在該元素嗎?"+c.contains(new Person(120,"鐵蛋")));//其實contains方法內部是依賴於equals方法進行比較的
        System.out.println("集合的元素:"+c);
        
        Collection c2=new ArrayList();
        c2.add(new Person(110,"狗娃"));
        c2.add(new Person(119,"狗剩"));
        c2.add(new Person(104,"翠花"));
        System.out.println("c集合有包含c2集合的全部元素嗎?"+c.containsAll(c2));
    }

}
class Dog{}
class Person{
    int id;
    String name;
    public Person() {}
    public Person(int id,String name) {
        this.id=id;
        this.name=name;
    }
    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return "{編號:"+this.id+"姓名:"+this.name+"}";
    }
    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        Person p=(Person)obj;
        return this.id==p.id;
    }
    //Java規範:通常重寫equals方法,咱們都會重寫hashCode方法的
    @Override
    public int hashCode() {
        // TODO Auto-generated method stub
        return this.id;
    }
}

結果:
存在該元素嗎?true
集合的元素:[{編號:110姓名:狗娃}, {編號:119姓名:狗剩}, {編號:120姓名:鐵蛋}]
c集合有包含c2集合的全部元素嗎?false

迭代

toArray()     把集合中的元素所有存儲到一個Object的數組中返回
iterator()

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

/*
 迭代
         toArray() 把集合中的元素所有存儲到一個Object的數組中返回 
         iterator()
  
  */
public class Demo3 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Collection c2=new ArrayList();
        c2.add("小龍女");
        c2.add("孫笑川");
        c2.add("楊過");
        
        Object[] arr2=c2.toArray();//把集合中的元素所有存儲到一個Object的數組中返回
        System.out.println("數組的元素:"+Arrays.toString(arr2));
        Collection c=new ArrayList();
        c.add(new Person(110,"狗娃"));
        c.add(new Person(119,"狗剩"));
        c.add(new Person(120,"鐵蛋"));
        Object[] arr=c.toArray();
        //需求:把編號是110的人信息輸出
        for (int i=0;i<arr.length ;i++) {
            Person p=(Person)arr[i];//從Object數組中取出的元素只能使用Object類型聲明變量接收,若是須要其餘的的類型須要進行強制類型轉換
            if (p.id==110) {
                System.out.println(p);
            }
        }
        
    }

}

結果:
數組的元素:[小龍女, 孫笑川, 楊過]
{編號:110姓名:狗娃}
相關文章
相關標籤/搜索