Java学习笔记(14)

需求:一个银行账户5000块,两夫妻一个拿着存折,一个拿着卡,开始取钱比赛,每次只能取1000,要求不准出现线程安全问题

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修饰一个函数

同步函数要注意的事项:

  1. 如果是一个非静态的同步函数,锁对象是this对象,如果是静态的同步函数,锁对象是当前函数所属的类的字节码文件(class对象)
  2. 同步函数的锁对象是固定的,不能由你来指定的

推荐使用:同步代码块

原因:

  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;
            }
        }
    }*/

注释里的即为同步函数,这里必须使用静态的同步函数,因为如果是非静态的话,两个线程对象就有两个各自的锁对象,不满足锁的条件

死锁:java中同步机制解决了线程安全问题,但是同时也引发死锁现象

 死锁现象出现的根本原因:

  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姓名:狗娃}

猜你喜欢

转载自www.cnblogs.com/zhangwugai/p/10382810.html