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修饰一个函数
同步函数要注意的事项:
- 如果是一个非静态的同步函数,锁对象是this对象,如果是静态的同步函数,锁对象是当前函数所属的类的字节码文件(class对象)
- 同步函数的锁对象是固定的,不能由你来指定的
推荐使用:同步代码块
原因:
- 同步代码块的锁对象可以由我们随意指定,方便控制。同步函数的锁对象是固定的,不能由我们来指定
- 同步代码块可以很方便控制需要被同步的代码的范围,同步函数必须是整个函数的所有代码都被同步了
@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中同步机制解决了线程安全问题,但是同时也引发死锁现象
死锁现象出现的根本原因:
- 存在两个或者两个以上的线程
- 存在两个或者两个以上的共享资源
死锁现象的解决方案:没有方案,只能尽量避免发生而已
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();
}
} 结果:
张三拿到了遥控器,准备去拿电池!
狗娃拿到了电池,准备去拿遥控器!
创建多线程方式二:
- 自定义一个类实现Runnable接口
- 实现Runnable的run方法,把自定义线程的任务定义在run方法上
- 创建Runnable实现类对象
- 创建Thread类的对象,并且把Runnable实现类的对象作为实参传递
- 调用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方法要注意的事项:
- wait与notify方法是属于Object对象的(锁对象可以是任意对象,而如果将此方法定义在Thread类中,就不能由锁对象调用了)
- wait与notify方法必须要在同步代码块或者是同步函数中才能使用(只有同步代码块或者是同步函数才有锁的概念)
- 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方法,那么就会唤醒以锁对象为标识符建立的线程池中的等待线程中的其中一个(如果有多个的话,会任意唤醒一个,但一般来说,先等待的会被先唤醒)
线程的停止:
- 停止一个线程,我们一般都会通过一个变量去控制的。(线程执行完任务就停止了,所以可以让线程执行完任务或者是根本不能执行任务代码)
- 如果需要停止一个处于等待状态下的线程,我们需要通过变量配合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();
}
} 结果:
妈妈洗菜
妈妈切菜
妈妈准备炒菜,发现没有酱油了...
儿子下楼..
儿子一直往前走
儿子打完酱油了
上楼,把酱油给老妈
妈妈继续炒菜
全家一起吃饭...
集合:
数组:存储同一种数据类型的集合容器
数组的特点:
- 只能存储同一种数据类型的数据
- 一旦初始化,长度固定
- 数组中的元素与元素之间的内存地址是连续的
注意: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;
} }
集合:
集合是存储对象数据的集合容器
集合比数组的优势:
- 集合可以存储任意类型的对象数据,数组只能存储同一种数据类型的数据
- 集合的长度是会发生变化的,数组的长度是固定的
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姓名:狗娃}
Java学习笔记(14)的更多相关文章
- Java 学习笔记(14)—— 文件操作
java文件操作主要封装在Java.io.File中,而文件读写一般采用的是流的方式,Java流封装在 java.io 包中.Java中流可以理解为一个有序的字符序列,从一端导向到另一端.建立了一个流 ...
- Java学习笔记14(面向对象七:final、static)
final:意为最终,不可变,是一个修饰词 有时候一个类地功能被开发好了,不想让子类重写,修改,这里就会用到final关键字 final修饰类: 不可以被继承,但是可以继承其他类 示例: public ...
- 《Java学习笔记(第8版)》学习指导
<Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...
- 20145330第八周《Java学习笔记》
20145330第八周<Java学习笔记> 第十五章 通用API 通用API 日志:日志对信息安全意义重大,审计.取证.入侵检验等都会用到日志信息 日志API Logger:注意无法使用构 ...
- 20145330第七周《Java学习笔记》
20145330第七周<Java学习笔记> 第十三章 时间与日期 认识时间与日期 时间的度量 GMT(格林威治标准时间):现在不是标准时间 世界时(UT):1972年UTC出来之前,UT等 ...
- Java学习笔记4
Java学习笔记4 1. JDK.JRE和JVM分别是什么,区别是什么? 答: ①.JDK 是整个Java的核心,包括了Java运行环境.Java工具和Java基础类库. ②.JRE(Java Run ...
- golang学习笔记14 golang substring 截取字符串
golang学习笔记14 golang substring 截取字符串golang 没有java那样的substring函数,但支持直接根据 index 截取字符串mystr := "hel ...
- java学习笔记11--集合总结
java学习笔记系列: java学习笔记10--泛型总结 java学习笔记9--内部类总结 java学习笔记8--接口总结 java学习笔记7--抽象类与抽象方法 java学习笔记6--类的继承.Ob ...
- java学习笔记8--接口总结
接着前面的学习: java学习笔记7--抽象类与抽象方法 java学习笔记6--类的继承.Object类 java学习笔记5--类的方法 java学习笔记4--对象的初始化与回收 java学习笔记3- ...
- 20145316许心远《Java学习笔记》第三周总结
20145316许心远<Java程序设计>第3周学习总结 教材学习内容总结 一.定义类: 类定义时使用class关键字 如果要将x绑定到新建的对象上,可以使用"="制定 ...
随机推荐
- vue路由-基础
安装 1.直接下载 / CDN https://unpkg.com/vue-router/dist/vue-router.js 在 Vue 后面加载 vue-router,它会自动安装的: <s ...
- vue-混入mixin
混入 基础 混入 (mixins) 是一种分发 Vue 组件中可复用功能的非常灵活的方式.混入对象可以包含任意组件选项.当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项. 例子: // ...
- Django rest framework 限制访问频率(源码分析)
基于 http://www.cnblogs.com/ctztake/p/8419059.html 当用发出请求时 首先执行dispatch函数,当执行当第二部时: #2.处理版本信息 处理认证信息 处 ...
- linux中字符串转换函数 simple_strtoul【转】
转自:http://blog.csdn.net/tommy_wxie/article/details/7480087 Linux内核中提供的一些字符串转换函数: lib/vsprintf.c [htm ...
- Linux 入门记录:三、Linux 文件基本操作管理
一.复制文件.目录 使用 cp 命令复制文件或目录: $ cp 源文件(夹)目标文件(夹) 常用参数: -r 递归复制整个目录树 -v 显示复制过程的详细信息 二.移动.重命名文件或目录 通过 mv ...
- python的时间和日期--time、datetime应用
time >>> import time >>> time.localtime() #以time.struct_time类型,打印本地时间 time.struct_ ...
- codevs 3287 货车运输 NOIP2013提高组
题目链接:http://codevs.cn/problem/3287/ 题解: 和bzoj3732一毛一样,只不过是找最大生成树和最小值罢了,具体参见我的bzoj3732的博客 #include< ...
- OpenCV编程入门目录
第一部分 快速上手OpenCV 第1 章 邂逅OpenCV 图像处理.计算机视觉与OpenCV OpenCV 概述 起源及发展 应用概述 .2OpenCV 基本架构分析 .3OpenCV3 带来了什么 ...
- 根据节点解析xml
config.xml文件如下: <?xml version="1.0" encoding="gb2312" ?> <root> < ...
- .NET Core 2.0.5安装具体步骤
.NET Core 2.0.5 comprises: .NET Core Runtime 2.0.5 .NET Core SDK 2.1.4 SDK Installer SDK Binaries ...