1、异常(Exception)

程序执行过程中发生中断,我们叫做异常,如果异常。

异常思维导图

1.1、异常的分类

异常分为检查性异常、运行时异常、和错误。
检查性异常:在编译时发生的异常。
运行时异常:编译完成之后触发的异常。
错误:不是异常,系统抛出的错误,程序员无法处理。

所有的异常类都继承于Exception类,Exception是Throwable的子类,Throwable还有一个子类Error。

1.2、异常处理的方式

1.2.1、try-catch处理

语法
try{
可能发生异常的代码;
}catch(Exception e){
e.printStackTrace();
}

try----捕捉
catch—处理
Exception --是处理的异常类型
e --异常变量
e.printStackTrace(); --打印异常信息

如下图代码发生了异常,程序终止了运行,我们需要对其进行处理。

当我们对异常进行处理了,后面的代码也能运行了。

1.2.2、多重处理异常

当一次性可能会发生多种异常,我们需要多重处理,多重处理异常的时候异常类型要按照大小来排序。
语法
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}

处理方式

package com.Ex;import java.util.InputMismatchException;
import java.util.Scanner;import com.sc.sc;public class exception2 {public static void main(String[] args) {try {int is = 10/0;int arr [] = {1,3};System.out.println(arr[2]);} catch (ArithmeticException e) {System.out.println("被除数不能为0!");}catch (ArrayIndexOutOfBoundsException e1) {System.out.println("下标越界!!");}}
}

1.2.3、throws/throw抛出异常

throws/throw抛出异常交给上级处理,直到被处理为止。

throws 出现在方法声明上,而throw通常都出现在方法体内。
throws 表示出现异常的一种可能性,并不一定会发生这些异常;
throw则是抛出了异常,执行throw则一定抛出了某个异常对象。

1.3、finally块

finally快,无论发生什么异常,块里的代码都会执行!
除非在try或者catch里面加System.exit(0);直接退出虚拟机。

1.4、异常分为处理可不处理

编译时异常
编译时异常一定要处理,要么try catch住,要么往外抛,谁调用,谁处理,不处理编译器不会让你通过,就无法执行。

运行时异常
不是必须进行try catch的异常,运行时异常一般是由程序员造成的异常,jvm会一直把异常往上抛,如果是多线程就由Thread.run()抛出,如果是单线程就被main()抛出,最后要么就是线程终止,要么就是主程序终止。

常见运行时异常
除数不能为0异常:ArithmeticException
下标越界异常:ArrayIndexOutOfBoundsException
空指针异常:NullPointerException

错误
指的是系统级别的异常,程序员无法处理。

1.5、自定义异常

自定义异常要继承Exception异常,通过throws/throw进行抛出。

package com.Ex;public class myException extends Exception {public myException() {}public myException(String msg) {super(msg);}public static void main(String[] args) {try {new myException().show(11);} catch (myException e) {System.out.println(e.getMessage());}}public void show(int age) throws myException {if (age < 18) {throw new myException("未成年!!!");}}
}运行结果未成年

2、IO流

2.1、file类

file代表目录和文件,主要适用于对目录和文件的操作。
创建一个文件对象

//创建一个文件对象File file = new File("F:\\");

创建文件

package com.files;import java.io.File;
import java.io.IOException;public class file1 {public static void main(String[] args) throws IOException {//创建一个文件对象File file = new File("F:\\zhou.txt");//判断文件是否存在if(!file.exists()) {//不存在就创建一个新文件file.createNewFile();}System.out.println("文件创建成功!");}
}
文件创建成功!

创建文件夹

package com.files;import java.io.File;
import java.io.IOException;public class file1 {public static void main(String[] args) throws IOException {//创建一个文件对象File file = new File("F:\\ss");//判断文件是否存在if(!file.exists()) {//不存在就创建一个新文件夹file.mkdir();}System.out.println("文件夹创建成功!");}
}
文件夹创建成功!

创建多级目录

package com.files;import java.io.File;
import java.io.IOException;public class file1 {public static void main(String[] args) throws IOException {//创建一个文件对象File file = new File("F:\\ss\\dd\\cc\\gg");//判断文件是否存在if(!file.exists()) {//不存在就创建一个新文件夹file.mkdirs();}System.out.println("多级文件夹创建成功!");}
}
多级文件夹创建成功!

2.1.1、file类常用方法

package com.files;import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;public class file2 {public static void main(String[] args) {File file = new File("F:\\zhou.txt");//判断是否文件是否存在System.out.println(file.exists());//判断是否是文件夹System.out.println(file.isDirectory());//判断是否是文件System.out.println(file.isFile());//获取文件的长度System.out.println(file.length());//获取文件的最后一修改时间long time = file.lastModified();Date date = new Date(time);SimpleDateFormat sim = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");System.out.println("文件的最后修改时间为:"+sim.format(date));//设置文件的修改时间file.setLastModified(0);//文件重命名File file1 = new File("F:\\zbb.txt");file.renameTo(file1);System.out.println("文件名字修改成功!");}
}

运行结果

true
false
true
30
文件的最后修改时间为:2020年08月27日 23时44分39秒
文件名字修改成功!

2.1.2、使用file类递归读取磁盘下所有文件

package com.files;import java.io.File;public class file3 {public static void main(String[] args) {File file = new File("F:\\");new file3().search(file);}public void search(File file) {//得到文件夹内的子文件下面的子文件夹File[] files = file.listFiles();//如果时目录就进去循环if (file.isDirectory()) {//遍历文件夹for (File file2 : files) {//遍历所有不是隐藏文件夹if (!file2.isHidden()) {System.out.println(file2.getPath() + file2.length() + "字节");//反复调用方法search(file2);}}}}}

运行结果

F:\附加作业-秒表0字节
F:\附加作业-秒表\.project977字节
F:\附加作业-秒表\css0字节
F:\附加作业-秒表\img0字节
F:\附加作业-秒表\js0字节
F:\附加作业-秒表\计时器已完成.html1768字节
F:\附加作业-秒表\计时器未完成.html2475字节

2.2、流(Stream)的介绍

流是一连串流动的数据,不同介质之间有数据交互的时候可以使用流,数据源可以是文件,还可以是数据库,网络甚至是其他的程序,以先进先出的方式发送和接收数据的通道。

举个例子:站在文件的角度来说,读取文件叫做输入流,向文件写入东西叫做输出流。

2.3、流的分类

流分为输出流和输入流,由于传输的格式不同分为字节流和字符流。
输出流:读取文件信息。
输入流:向文件写入信息。

字节流:指8位的通用字节流,以字节为基本单位,在java.io包中,对于字节流进行操作的类大部分继承于InputStream(输入字节流)类和OutputStream(输出字节流)类;

字符流:指16位的Unicode字符流,以字符(两个字节)为基本单位,非常适合处理字符串和文本,对于字符流进行操作的类大部分继承于Reader(读取流)类和Writer(写入流)类。

2.4、字节流

2.4.1、FileInputStream类读取文件

FileInputStream是字节输入流继承于InputStream。
它的作用是将文件中的数据输入到内存中,我们可以利用它来读文件;
由于它属于字节流,因此在读取Unicode字符(如中文)的文件时可能会出现问题。

package com.io;import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;public class fileinput {public static void main(String[] args) throws IOException {//创建文件对象File file = new File("f:\\zbb.txt");//创建文件输入流对象FileInputStream fis = new FileInputStream(file);//创建字节数组byte [] by = new byte[(int) file.length()];//将读取的数据放到字节数组中fis.read(by);//将数组中的数据转换成字符串System.out.println(new String(by));//使用完流记得关闭fis.close();}
}

运行结果

sdfsdfsdfsdf
sdfsdfsd
sdfsdf

2.4.2、使用FileOutputStream写文件

FileOutputStream类称为文件输出流,继承于OutputStream类,是进行文件写操作的最基本类;
它的作用是将内存中的数据输出到文件中,我们可以利用它来写文件。

package com.io;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;public class fileOutPutS {public static void main(String[] args) throws IOException {//创建文件对象File file = new File("f:\\zbb.txt");//创建文件输出流对象 ,附加第二个参数true,指定进行文件追加,默认为不追加FileOutputStream fos = new FileOutputStream(file,true);//创建数据源String str = "helloword";//将字符串转换成byte数组char[] charArray = str.toCharArray();//遍历byte数组,将数据写入到输出流for (int i = 0; i < charArray.length; i++) {fos.write(charArray[i]);}fos.close();System.out.println("写入数据成功!");}
}

运行结果

写入数据成功!

2.4.3、使用文件输出流输入流复制文件

package com.io;import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;public class cope {public static void main(String[] args) throws IOException {//创建源文件对象File file = new File("f:\\zbb.txt");//创建目标文件对象File file2 = new File("f:\\zhou.txt");if(!file2.exists()) {file2.createNewFile();}//使用源文件创造输入流对象FileInputStream fis = new FileInputStream(file);//使用目标文件创建输出流对象FileOutputStream fos = new FileOutputStream(file2);//创建字节数组用于缓冲byte [] by = new byte[1024];//循环从输入流中读取数据,如果读到-1说明没有数据可读取while (fis.read(by)!=-1) {//写入到文件输出流中fos.write(by);}System.out.println("复制成功!");fis.close();fos.close();}
}

输出结果

复制成功!

2.5、字符流

字节输入输出流可以高效的读写文件,对于Unicode编码的文件可能出现乱码,所以我们使用字符流来解决这个问题。

字符流主要涉及到以下四个类
FileReader类和FileWriter类;
BufferedReader类和BufferedWriter类。

2.5.1、FileReader读取文件

FileReader 是Reader子类,称为文件读取流,允许以字符流的形式对文件进行读操作。

package com.io;import java.io.File;
import java.io.FileReader;
import java.io.IOException;public class fileReaders {public static void main(String[] args) throws IOException {//创建文件对象File file = new File("f:\\zhou.txt");//创建文件读取流对象FileReader fr = new FileReader(file);//创建字符数组,长度是文件的长度char [] c = new char[(int) file.length()];//将读取的数据存到字符数组中fr.read(c);//将字符数组以字符串的形式输出System.out.println(new String(c));}
}

2.5.2FileWrite写文件

FileWriter类称为文件写入流,以字符流的形式对文件进行写操作。

package com.io;import java.io.File;
import java.io.FileWriter;
import java.io.IOException;public class write {public static void main(String[] args) throws Exception {//创建文件对象File file = new File("F:\\zz.txt");//文件不存在就创建if(!file.exists()) {file.createNewFile();}//创建文件写入流对象FileWriter fWriter = new FileWriter(file);//以字符流的形式把数据写入到文件中String str = "asdasdasdfasfa";char[] chars = str.toCharArray();fWriter.write(chars);fWriter.close();}
}

2.5.3、字符流复制文件

package com.io;import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;public class cope1 {public static void main(String[] args) throws Exception {// 创建源文件对象File file = new File("f:\\zbb.txt");// 创建目标文件对象File file2 = new File("f:\\z1.txt");if (!file2.exists()) {file2.createNewFile();}FileReader fReader = new FileReader(file);FileWriter fWriter = new FileWriter(file2);//创建一个字符数组char [] c= new char[1024];while(fReader.read(c)!=-1) {fWriter.write(c);}System.out.println("复制成功!");fWriter.close();fReader.close();}
}

2.6、缓冲流

在每一次读写的时候,都会访问硬盘。 如果读写的频率比较高的时候,其性能表现不佳。
为了解决以上弊端,采用缓存流。
缓存流在读取的时候,会一次性读较多的数据到缓存中,以后每一次的读取,都是在缓存中访问,直到缓存中的数据读取完毕,再到硬盘中读取。

2.6.1、BufferedReader 读取文件

缓存字符输入流 BufferedReader 可以将数据一行一行读取。

package com.io;import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;public class buffread {public static void main(String[] args) throws Exception {//创建文件对象File file = new File("F:\\zhou.txt");// 创建文件字符流FileReader fReader = new FileReader(file);// 缓存流必须建立在一个存在的流的基础上BufferedReader bReader = new BufferedReader(fReader);String str;//逐行读取,str接受读取的数据while((str=bReader.readLine())!=null) {System.out.println(str);}//关闭流bReader.close();fReader.close();}
}

运行结果

sdfsdfsdfsdf
sdfsdfsd
sdfsdfhellowordhelloword

2.6.2、BufferedWriter写文件

package com.io;import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;public class bfwrite {public static void main(String[] args) throws Exception {File file = new File("f:\\zhou.txt");// 通过文件对象创建文件输出字符流对象FileWriter fw = new FileWriter(file);// 将文件输出字符流包装成缓冲流BufferedWriter bw = new BufferedWriter(fw);// 追加的形式写入数据bw.append("123456");bw.write("你好啊!");// 换行bw.newLine();bw.write("asdasdas");// 强制把缓存中的数据写入硬盘,无论缓存是否已满bw.flush();bw.close();fw.close();}
}

2.7、数据流

DataInputStream 数据输入流
DataOutputStream 数据输出流

要用DataInputStream 读取一个文件,这个文件必须是由DataOutputStream 写出的,否则会出现EOFException,因为DataOutputStream 在写出的时候会做一些特殊标记,只有DataInputStream 才能成功的读取。

package com.io;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;public class datainout {public static void main(String[] args) throws IOException {FileOutputStream fos  = new FileOutputStream(new File("f:\\zhou.txt"));DataOutputStream dos =new DataOutputStream(fos);dos.writeBoolean(true);dos.writeInt(300);dos.writeUTF("sdasfsaf");//创建文件对象FileInputStream file = new FileInputStream(new File("f:\\zhou.txt"));//创建数据输入流对象DataInputStream dis = new DataInputStream(file);//创建字节数组boolean b= dis.readBoolean();int i = dis.readInt();String str = dis.readUTF();System.out.println(b);System.out.println(i);System.out.println(str);dis.close();file.close();dos.close();fos.close();}
}

2.8、对象流

对象流指的是可以直接把一个对象以流的形式传输给其他的介质,比如硬盘。
一个对象以流的形式进行传输,叫做序列化。 该对象所对应的类,必须是实现Serializable接口。

package com.io;import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;public class testStream {public static void main(String[] args) throws Exception {//实例化对象并赋值user u = new user("张三", 6666);//创建一个文件用来保存对象File file = new File("F:\\dx.txt");if(!file.exists()) {file.createNewFile();}//创建对象输出流ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));//创建对象输入流ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));//将对象写进去对象输出流oos.writeObject(u);//读取对象的信息Object readObject = ois.readObject();System.out.println(readObject);//关闭流ois.close();oos.close();}
}

2.9、System.in转换和包装

从控制台输入内容到文件去。

package com.io;import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.InputStreamReader;public class sys {public static void main(String[] args) throws Exception {/* 本例从控制台接受输入,然后写入到文件中,直到用户输入"!!!"为止 */File file = new File("f:\\input.txt"); // 创建文件对象if (!file.exists()) // 判断该文件是否存在,如果不存在则创建新文件{file.createNewFile();}FileWriter fr = new FileWriter(file); // 针对文件对象创建文件写入流对象BufferedWriter bw = new BufferedWriter(fr); // 为文件写入流建立缓冲流// 将控制台输入对象转化成字符流,并建立缓冲流BufferedReader bin = new BufferedReader(new InputStreamReader(System.in));String str = bin.readLine(); // 接受从控制台输入的一行字符串while (!(str.equals("n"))) // 如果输入"n"则代表输入结束{bw.write(str); // 将从控制台输入的字符串写入到文件中bw.newLine(); // 换新行str = bin.readLine(); // 再从控制台接受输入}// 关闭所有已经打开的流bw.close();fr.close();bin.close();}
}

3、集合

3.1、集合的概念

java当中数组的长度是不可变的,无法存储可变的数据,也无法存储映射关系的数据,为了解决这个问题java推出了集合框架,所有的集合都位于java.util包下,集合和数组不一样,数组保存的是基本类型数据、和对象的引用,而集合只能保存对象。

3.2、集合的分类

集合分为Collection、和Map,它们是 Java 集合的根接口,这两个接口又包含了一些子接口和实现类。

collection(单列集合)子接口:List、Set、Queue。
Map(键-值对集合)子接口:Hashtable、HashMap、SortedMap。

3.3、List集合

特点:有序可重复。
常用的实现类:ArrayList、LinkedList。

3.3.1、ArrayList

ArrayList底层是一个Object数组,通过索引查询元素,查询快,增删效率低。
创建一个Arraylist集合,默认容量10,每次按1.5倍增长扩容。

package com.collection;import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;public class Arraylist_jh {public static void main(String[] args) {//创建一个 Arraylist集合List<String> list = new ArrayList<String>();//添加元素list.add("张三");list.add("李四");list.add("王五");//删除元素list.remove(0);//修改元素list.set(1, "王麻子");//查询元素System.out.println("查询姓名为:"+list.get(1));//输出集合长度System.out.println("集合的长度为:"+list.size());//查看元素的下标System.out.println("元素的下标为:"+list.indexOf("王五"));//判断是否包含某个元素System.out.println("判断是否包含:"+list.contains("李四"));//截取下标System.out.println("截取的结果:"+list.subList(0, 2));//清空集合//list.clear();//遍历Arraylist集合的三种方式//(1)for循环遍历System.out.println("-----------for循环遍历---------------");for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}//(2)forEach遍历System.out.println("-----------forEach循环遍历------------");for (String string : list) {System.out.println(string);}//(3)迭代器遍历//获得迭代器System.out.println("-----------迭代器遍历------------");Iterator<String> iterator = list.iterator();//判断集合中有没有元素while(iterator.hasNext()) {//如果有元素的画指定指向下一位元素把元素迭代出来,直到集合中没有元素为止System.out.println(iterator.next());}}
}

运行结果

查询姓名为:王麻子
集合的长度为:2
元素的下标为:-1
判断是否包含:true
截取的结果:[李四, 王麻子]
-----------for循环遍历---------------
李四
王麻子
-----------forEach循环遍历------------
李四
王麻子
李四
王麻子

3.3.1、LinkedList集合

LinkedList 类采用链表结构保存对象,这种结构的优点是便于操作首尾元素。需要频繁向集合中插入和删除元素时,使用 LinkedList 类比 ArrayList 类效果高,但是 LinkedList 类随机访问元素的速度则相对较慢。这里的随机访问是指检索集合中特定索引位置的元素。

package com.collection;import java.util.Iterator;
import java.util.LinkedList;public class LinkedList_jh {public static void main(String[] args) {LinkedList<String> list = new LinkedList<String>();//添加元素list.add("张三");list.add("李四");list.add("王五");list.add("王麻子"); //末尾添加元素list.addLast("123");//集合最前面添加元素list.addFirst("456");//删除元素list.remove(0);list.removeLast();//修改元素list.set(1, "李白");//查询元素System.out.println("------------查询---------------");System.out.println(list.get(2));System.out.println(list.getFirst());//清空集合//list.clear();//遍历LinkedList集合System.out.println("-----------遍历的结果------------");Iterator<String> iterator = list.iterator();while (iterator.hasNext()) {String string = (String) iterator.next();System.out.println(string);}}
}

运行结果

------------查询---------------
王五
张三
-----------遍历的结果------------
张三
李白
王五
王麻子

3.3.2、ArrayList和LinkedList的区别

ArrayList 插入,删除数据慢。
LinkedList, 插入,删除数据快。
ArrayList是顺序结构,所以定位很快。
LinkedList 是链表结构,必须得一个一个的找过去,所以定位慢。

3.4、Set集合

无序不可重复,存进去取出来的数据顺序不同,数据不能重复,允许包含一个null值。
常用的实现类:HashSet、TreeSet。

3.4.1、HashSet

HashSet的特点
不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也有可能发生变化。
HashSet 不是同步的,如果多个线程同时访问或修改一个 HashSet,则必须通过代码来保证其同步。
集合元素值可以是 null。

当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据该 hashCode 值决定该对象在 HashSet 中的存储位置。如果有两个元素通过 equals() 方法比较返回的结果为 true,但它们的 hashCode 不相等,HashSet 将会把它们存储在不同的位置,依然可以添加成功。

也就是说,两个对象的 hashCode 值相等且通过 equals() 方法比较返回结果为 true,则 HashSet 集合认为两个元素相等。

package com.collection;import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;public class HashSets {public static void main(String[] args) {Set<String> set = new HashSet<String>();set.add("张三");set.add("李四");set.add("王五");set.add("王五");//遍历HashSet//因为set集合无序,没有索引只能通过迭代器和增强for循环遍历,不能通过下标遍历Iterator<String> iterator = set.iterator();while(iterator.hasNext()){String next = iterator.next();System.out.println(next);}//set集合不可重复,所以插入相同的数据插不进去只会保留一个}
}

运行结果

李四
张三
王五

3.4.2、TreeSet

TreeSet 类同时实现了 Set 接口和 SortedSet 接口。SortedSet 接口是 Set 接口的子接口,可以实现对集合进行自然排序,自然排序指的是升序排序。
TreeSet 只能对实现了 Comparable 接口的类对象进行排序,因为 Comparable 接口中有一个 compareTo(Object o) 方法用于比较两个对象的大小。例如 a.compareTo(b),如果 a 和 b 相等,则该方法返回 0;如果 a 大于 b,则该方法返回大于 0 的值;如果 a 小于 b,则该方法返回小于 0 的值。

package com.collection;import java.util.Scanner;
import java.util.SortedSet;
import java.util.TreeSet;public class TreeSets {public static void main(String[] args) {TreeSet<Double> ts = new TreeSet<Double>();Scanner sc = new Scanner(System.in);for (int i = 0; i < 5; i++) {System.out.print("请输入第:"+(i+1)+"个学生的成绩:");Double double1 = sc.nextDouble();ts.add(Double.valueOf(double1));}//遍历集合for (Double double1 : ts) {System.out.print(double1+"\t");}System.out.println();System.out.print("请输入查找的分数:");double score = sc.nextDouble();if(ts.contains(score)) {System.out.println(score+"分的人存在!");}else {System.out.println("不存在!");}//查询不及格学生的成绩//headSet()这是返回集的最大边界值(不包括该边界值)。SortedSet<Double> sort = ts.headSet((double) 60);System.out.print("不及格的有:");for (Double double1 : sort) {System.out.print(double1+"\t");}SortedSet<Double> sort1 = ts.tailSet((double) 60);System.out.println();System.out.print("60分以上的有:");for (Double double1 : sort1) {System.out.print(double1+"\t");}}
}

运行结果

请输入第:1个学生的成绩:50
请输入第:2个学生的成绩:60
请输入第:3个学生的成绩:70
请输入第:4个学生的成绩:80
请输入第:5个学生的成绩:90
50.0    60.0    70.0    80.0    90.0
请输入查找的分数:50
50.0分的人存在!
不及格的有:50.0
60分以上的有:60.0 70.0    80.0    90.0

3.5、Map集合

Map集合是一种键-值对(key-value)几个,Map中每一个元素都包含key-value,用来保存关系映射型数据,key 和 value 都可以是任何引用类型的数据,key不能重复,value可以重复。Map集合存在一对一关系,可以通过key找到value。

Map 接口主要有两个实现类:HashMap 类和 TreeMap 类。其中,HashMap 类按哈希算法来存取键对象,而 TreeMap 类可以对键对象进行排序。

Map集合常用方法

3.5.1、HashMap集合

package com.collection;import java.util.HashMap;
import java.util.Iterator;
import java.util.Scanner;import com.sc.sc;public class HashMaps {public static void main(String[] args) {HashMap<String, String> has = new HashMap<String, String>();//添加元素has.put("1", "小明");has.put("2", "小黑");has.put("3", "小白");//keySet() 返回 Map 集合中所有键对象的 Set 集合Iterator<String> iterator = has.keySet().iterator();//遍历集合while(iterator.hasNext()) {//获得keyString key = iterator.next();//获得valueString val = has.get(key);System.out.println("编号:"+key+"\t"+"名字:"+val);}Scanner scanner = new Scanner(System.in);System.out.print("请输入要删除的学号:");String str = scanner.next();if(has.containsKey(str)) {has.remove(str);}else {System.out.println("不存在此人!");}//再遍历一次,凸显删除后的结果Iterator<String> iterator1 = has.keySet().iterator();//遍历集合while(iterator1.hasNext()) {//获得keyString key = iterator1.next();//获得valueString val = has.get(key);System.out.println("编号:"+key+"\t"+"名字:"+val);}}
}

执行结果

编号:1  名字:小明
编号:2 名字:小黑
编号:3 名字:小白
请输入要删除的学号:1
编号:2 名字:小黑
编号:3 名字:小白

3.5.2、hashMap遍历集合

package com.collection;import java.util.HashMap;
import java.util.Iterator;import java.util.Map.Entry;public class HashMap2 {public static void main(String[] args) {HashMap<Integer, String> hMap = new HashMap<Integer, String>();//添加hMap.put(1, "周先生");hMap.put(2, "刘先生");//Entry将键值对的的关系封装成了对象,可以从键值对对象中获取key、valuefor (Entry<Integer, String> enMap:hMap.entrySet()) {Integer key = enMap.getKey();String val = enMap.getValue();System.out.println("编号:"+key+"\t"+"姓名:"+val);}//单独打印出keyfor (Integer key:hMap.keySet()) {System.out.println(key);}//单独取出来值for (String string : hMap.values()) {System.out.println(string);}//entrySet 返回map集合中所有键值对的set集合//使用迭代器遍历Iterator<Entry<Integer, String>> iterator = hMap.entrySet().iterator();while (iterator.hasNext()) {Entry<Integer, String> next = iterator.next();Integer key = next.getKey();String value = next.getValue();System.out.println("编号:"+key+"\t"+"姓名:"+value);}//通过键找值得方式遍历for(Integer key : hMap.keySet()){String value = hMap.get(key);System.out.println(key+":"+value);}}
}
运行结果
```java
编号:1 姓名:周先生
编号:2 姓名:刘先生
1
2
周先生
刘先生
编号:1 姓名:周先生
编号:2 姓名:刘先生
1:周先生
2:刘先生
### 3.5.3、TreeMap集合
TreeMap 是一个有序的key-value集合,它是通过红黑树实现的。**红黑树**
(1)每个节点或者是黑色,或者是红色。
(2)根节点是黑色。
(3)每个叶子节点(NIL\null)是黑色。
(4)如果一个节点是红色的,则它的子节点必须是黑色的。
(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。![在这里插入图片描述](https://img-blog.csdnimg.cn/20200829000429896.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTgyMjk4,size_16,color_FFFFFF,t_70#pic_center)```java
package com.collection;import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;public class TreeMapTest {public static void main(String[] args) {TreeMap<Integer, String> tmap = new TreeMap<>();System.out.println("判断集合是否为空: " + tmap.isEmpty());//添加tmap.put(13, "Yellow");tmap.put(3, "Red");tmap.put(2, "Green");tmap.put(33, "Blue");//遍历集合所有键值得set集合for (Map.Entry entry : tmap.entrySet()) {System.out.println("编号: " + entry.getKey() + ", 颜色: " + entry.getValue());}System.out.println("集合大小: " + tmap.size());System.out.println("集合是否包含这个值: " + tmap.containsValue("Purple"));System.out.println("集合是否包含这个key: " + tmap.containsKey(12));System.out.println("集合最后一个key: " + tmap.lastKey());System.out.println("集合是否存在这个key " + tmap.get(14));System.out.println("删除 key 13");tmap.remove(13);System.out.println("判断是否包含key值13: " + tmap.containsKey(13));Iterator iterator = tmap.keySet().iterator();while (iterator.hasNext()) {System.out.println(iterator.next());}System.out.println("清空集合");tmap.clear();System.out.println("集合大小: " + tmap.size());}
}
判断集合是否为空: true
编号: 2, 颜色: Green
编号: 3, 颜色: Red
编号: 13, 颜色: Yellow
编号: 33, 颜色: Blue
集合大小: 4
集合是否包含这个值: false
集合是否包含这个key: false
集合最后一个key: 33
集合是否存在这个key null
删除 key 13
判断是否包含key值13: false
2
3
33
清空集合
集合大小: 0

4、JDBC

4.1、JDBC简介

JDBC(Java DataBase Connectivity)是用来操作数据库的一款工具类,JDBC是由接口和类组成,里面提供了一些类和接口方便我们对数据库的增删改查。

4.2、怎么使用JDBC

第一步:安装数据库创建数据表插入测试数据(根据自己的需求,本人使用的是mysql数据库)

下载数据库对应的驱动jar包并使用开发工具(本人用的eclipse)创建java项目导入jar包到项目路径下,找到导入的jar包右击找到build path 选择 add to build path即可。

第四步:
①建立连接
②加载驱动
③执行sql语句
④处理结果集
⑤释放资源

package com.zhou.cn;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;public class JdbcDemo1 {public static void main(String[] args) throws ClassNotFoundException, SQLException {//提升作用域是为了方便释放资源Connection conn=null;Statement stm = null;ResultSet rs = null;//加载驱动Class.forName("com.mysql.jdbc.Driver");//jdbc:mysql 使用mysql进行连接  ///代表本机地址后面接数据库地址 //useSSL=fase 需要指定是否使用SSL 不然程序运行的时候会多一段很长的代码//这是因为MySQL在高版本需要指明是否进行SSL连接。String url="jdbc:mysql:///sys?useSSL=false";//数据库的用户名String username="root";//数据库的密码String password="19990704";//建立连接 需要传三个参数:路径、数据用户名、数据库密码conn = DriverManager.getConnection(url,username,password);//定义sql语句用来执行String sql ="select * from user";//执行sql语句并返回结果集stm = conn.createStatement();rs = stm.executeQuery(sql);//遍历结果集,如果结果集没东西返回-1while (rs.next()) {//获得数据库的字段值需要跟数据字段名一样int id = rs.getInt("id");String name=rs.getString("name");String pwd=rs.getString("password");System.out.println("id=:"+id+"\tname="+name+"\tpassword="+pwd);}//释放资源conn.close();stm.close();rs.close();}}

运行结果

4.3、JDBC常用API

  1. Driver接口

Driver接口是所有JDBC驱动程序必须实现的接口,该接口专门提供给数据库厂商使用。在编写JDBC程序时,必须要把指定数据库驱动程序或类库加载到项目的classpath中。

  1. DriverManager类

Driver Manager类用于加载JDBC驱动并且创建与数据库的连接。在Driver Manager类中,定义了两个比较重要的静态方法。如表所示:
registerDriver(Driver driver)
该方法用于向 DriverManager中注册给定的JDBC驱动程程序

getConnection(String url,String user,String pwd)
该方法用于建立和数据库的连接,并返回表示连接的 Connection对象

3、executeQuery(String sql)

用于执行SQL中的select语句,该方法返回一个表示查询结果的ResultSet对象

4、 PreparedStatement接口

PreparedStatement是Statement的子接口,用于执行预编译的SQL语句,防止sql注入

executeUpdate()

5、在此PreparedStatement对象中执行SQL语句,该语句必须是个DML语句或者是无返回内容的SQL语句,比如DDL语句。

6、executeQuery()
在此PreparedStatement对象中执行SQL查询,该方法返回的ResultSet对象
7、ResultSet接口
常用方法

next()将游标从当前位置向下移一行,判断数据表有没有值有就遍历出来,没有返回-1。
getString(int columnIndex)

用于获取指定字段的String类型的值,参数columnIndex代表字段的索引。

getString(String columnName)

用于获取指定字段的String类型的值,参数column Name代表字段的名称。

getInt(int columnIndex)

用于获取指定字段的int类型的值,参数columnIndex代表字段的索引。

getInt(String columnName)

用于获取指定字段的int类型的值,参数columnName代表字段的名称。

getDate(int columnIndex)

用于获取指定字段的Date类型的值,参数columnIndex代表字段的索引。

getDate(String columnName)

用于获取指定字段的Date类型的值,参数column Name代表字段的名称。

4.4、封装JDBC工具类

当我们进行相应的操作每次都要加载驱动,建立连接,执行sql,返回结果集,释放资源 很麻烦,使用面向对象的思想将这些操作进行一个封装,大大提高了程序的耦合性。

public class DButil {private static final String URL="jdbc:mysql:///sys?useSSL=false&&characterEncoding=utf-8";private static final String USER="root";private static final String PASSWORD="19990704";static {//加载驱动try {Class.forName("com.mysql.jdbc.Driver");} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}}//获得连接public static Connection getConnection() {Connection conn = null;if(conn==null) {try {conn = DriverManager.getConnection(URL, USER, PASSWORD);return conn;} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}return null;}public static void close(ResultSet rs, PreparedStatement psmt, Connection con) {try {if (rs != null) {rs.close();}if (psmt != null) {psmt.close();}if (con != null) {con.close();}} catch (SQLException e) {e.printStackTrace();}}/*** 更新  传一个sql语句和一个Objec数组,没有就写null*/public static int Update (String sql,Object...parms) {Connection conn =null;PreparedStatement ps=null;conn =DButil.getConnection();try {//预编译sql语句ps = conn.prepareStatement(sql);if(parms !=null) {for (int i = 0; i < parms.length; i++) {ps.setObject(i+1, parms[i]);}}int count = ps.executeUpdate();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}return -1;}/*** 查询方法 传一个sql语句和一个Objec数组,没有就写null*/public static ResultSet Select (String sql,Object...parms) {Connection conn =null;PreparedStatement ps=null;ResultSet rs = null;conn =DButil.getConnection();try {//预编译sql语句ps = conn.prepareStatement(sql);if(parms !=null) {for (int i = 0; i < parms.length; i++) {ps.setObject(i+1, parms[i]);}}rs = ps.executeQuery();return rs;} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;}

4.5、JDBC进行增删改查

创建接口

package com.zhou.cn.demo2;
//创建接口,创建增删改查方法//使用接口创建方法
public interface CRUD {//添加方法int addUser(int id,String name,String pwd);//删除方法int delateUser(int id);//修改方法int updateUser(String name,int id);//根据id查询方法User selectUserById(int  id);
}

创建与数据库表名对应的实体类

package com.zhou.cn.demo2;public class User {/*** 创建数据库表中对应的实体类以及属性*/private int id;private String name;private String password;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public User() {super();// TODO Auto-generated constructor stub}public User(int id, String name, String password) {super();this.id = id;this.name = name;this.password = password;}@Overridepublic String toString() {return "User [id=" + id + ", name=" + name + ", password=" + password + "]";}//构造方法}

创建工具类

package com.zhou.cn.demo2;import java.net.URL;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class DButil {private static final String URL="jdbc:mysql:///sys?useSSL=false&&characterEncoding=utf-8";private static final String USER="root";private static final String PASSWORD="19990704";static {//加载驱动try {Class.forName("com.mysql.jdbc.Driver");} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}}//获得连接public static Connection getConnection() {Connection conn = null;if(conn==null) {try {conn = DriverManager.getConnection(URL, USER, PASSWORD);return conn;} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}return null;}public static void close(ResultSet rs, PreparedStatement psmt, Connection con) {try {if (rs != null) {rs.close();}if (psmt != null) {psmt.close();}if (con != null) {con.close();}} catch (SQLException e) {e.printStackTrace();}}/*** 更新*/public static int Update (String sql,Object...parms) {Connection conn =null;PreparedStatement ps=null;conn =DButil.getConnection();try {//预编译sql语句ps = conn.prepareStatement(sql);if(parms !=null) {for (int i = 0; i < parms.length; i++) {ps.setObject(i+1, parms[i]);}}int count = ps.executeUpdate();return count;} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}return 0;}/*** 查询*/public static ResultSet Select (String sql,Object...parms) {Connection conn =null;PreparedStatement ps=null;ResultSet rs = null;conn =DButil.getConnection();try {//预编译sql语句ps = conn.prepareStatement(sql);if(parms !=null) {for (int i = 0; i < parms.length; i++) {ps.setObject(i+1, parms[i]);}}rs = ps.executeQuery();return rs;} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;}
}

创建接口的实现类

package com.zhou.cn.demo2;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;//接口的实现类
public class UserImpl implements CRUD{@Overridepublic int addUser(int id,String name,String pwd) {Connection conn = null;try {//通过工具类获得数据连接conn = DButil.getConnection();//创建sql ?代表占位数代表你需要要传几个参数String sql="insert into user values(?,?,?)";Object [] object= {id,name,pwd};int update = DButil.Update(sql,object);return update;} catch (Exception e) {// TODO: handle exception}finally {DButil.close(null, null, conn);}return 0;}@Overridepublic int delateUser(int id) {Connection conn = null;try {//通过工具类获得数据连接conn = DButil.getConnection();//创建sql ?代表占位数代表你需要要传几个参数String sql="delete from user where id=?";Object [] object= {id};int delete = DButil.Update(sql,object);return delete;} catch (Exception e) {// TODO: handle exception}finally {DButil.close(null, null, conn);}return 0;}@Overridepublic int updateUser(String name,int id) {Connection conn = null;try {//通过工具类获得数据连接conn = DButil.getConnection();//创建sql ?代表占位数代表你需要要传几个参数String sql="update user set name=? where id=?";Object [] object= {name,id};int delete = DButil.Update(sql,object);return delete;} catch (Exception e) {// TODO: handle exception}finally {DButil.close(null, null, conn);}return 0;}@Overridepublic User selectUserById(int id) {Connection conn = null;try {//通过工具类获得数据连接conn = DButil.getConnection();//创建sql ?代表占位数代表你需要要传几个参数String sql="select * from user where id=?";Object [] object= {id};ResultSet rs = DButil.Select(sql,object);while(rs.next()) {User u = new User(rs.getInt("id"),rs.getString("name"),rs.getString("password"));return u;}} catch (Exception e) {// TODO: handle exception}finally {DButil.close(null, null, conn);}return null;}}

创建测试类

package com.zhou.cn.demo2;public class testJDBC {public static void main(String[] args) {//实例化接口实现类UserImpl userImpl = new UserImpl();//通过构造方法赋值//使用接口实现类对象调用方法int addUser = userImpl.addUser(35,"阿萨大大","77777");//如果添加成功数据库受影响行数为1,否则为0System.out.println(addUser>0?"添加成功":"添加失败");int deleteUser = userImpl.delateUser(11);System.out.println(deleteUser>0?"删除成功":"删除失败");int update = userImpl.updateUser("张三", 12);System.out.println(update>0?"修改姓名成功":"修改姓名失败");User user=userImpl.selectUserById(20);System.out.println(user);}
}
输出结果添加成功
删除成功
修改姓名成功
User [id=20, name=阿萨大大, password=77777]

4.6、prepareStatement和Statement的区别

(1)prepareStatement会先初始化SQL,先把这个SQL提交到数据库中进行预处理,多次使用可提高效率。

在SQL语句中可以包含?,可以用ps = conn.prepareStatement("select * from Cust where ID=?");int sid = 1001;ps.setInt(1,sid);rs = ps.executeQuery();可以把?替换成变量。

(2)Statement不会初始化,没有预处理,每次都是从0开始执行SQL。

Statement 只能用 int sid = 1001;Statement stmt = conn.createStatement();
//使用Statement可以将传来的参数拼接到条件后面,容易引发sql注入,不太建议使用statementResultSet rs = stmt.executeQuery("select * from Cust where ID="+sid);来实现

什么是sql注入
将(恶意)的SQL命令注入到数据库而不是按照数据库设计者的理念去执行sql语句。

举个例子:select * from user where username=‘张三’#’’ and password=‘123’ ;
上面这句sql执行后,用户只需要输入账号,无论输入密码对不对和不输入密码都会登录成功,原因是因为#'让后面的代码失效了。

第二个例子:select * from user where username=‘张三’ or ‘1=1’ and password=‘zzz’’;
原因:or '1=1’使语句改变了,相当于是万能钥匙了

4.7、JDBC事物处理

4.7.1、什么是事务

对数据库的增删改的sql语句我们可以从称之为一个事务。

4.7.2、事务必须满足四个条件

①原子性:事务要么成功,要么失败。
②一致性:执行完事务的时候,数据库保持一致状态。例如两个账号之间进行转账,无论是否成功两个账号之间余额之和不变。
③隔离性:事务独立运行。当一个事务运行后,其他事务会被撤回。
④持久性:软、硬件崩溃后,InnoDB数据表驱动会利用日志文件重构修改。

4.7.3、JDBC中的事务处理

在JDBC中是通过接口Collection来完成的。
Collection接口操作事务的一些方法

setAutoCommit(boolean)设置事务是否自动开启事务,true为自动提交事务,false为开启事务。

commit():提交结束事务。

rollback():回滚结束事务。

来演示一下JDBC事务的处理
首先创建一张表,字段属性有name、money。

然后编写java代码

package com.zhou.sw;import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;import com.zhou.cn.demo2.DButil;public class affair {public static void main(String[] args)  {Connection conn = null;try {//通过工具类连接conn= DButil.getConnection();//开启事务conn.setAutoCommit(false);//设置转账人的姓名和金额String name1="张三";Double money1=5000.0;//首先查询转账人的金额String moneys="select money from account where name=?";Object [] objects= {name1};ResultSet rs = DButil.Select(moneys, objects);double balance = 0;while (rs.next()) {balance=rs.getInt("money");}//判断转账人的余额是否足够转账if(balance>=money1) {String sql1="update account set money=money-? where name=?";Object [] objects1= {money1,name1};int i = DButil.Update(sql1, objects1);//判断账户金额是否减少,当金额减少才能为对方账户添加金额if(i>0) {System.out.println("转账成功,张三账户金额减少"+money1+"元");//设置转账人的姓名和金额String name2="李四";//执行收款sql语句String sql2="update account set money=money+? where name=?";Object [] objects2= {money1,name2};int j = DButil.Update(sql2, objects2);//提交事务给李四添加对应的金额conn.commit();System.out.println(j>0?"收款成功,李四账户余额增加"+money1+"元":"收款失败");}}else {System.out.println("余额不足");}}catch (Exception e) {try {//发生异常就回滚conn.rollback();} catch (SQLException e1) {// TODO Auto-generated catch blockthrow new RuntimeException();}}finally {//释放资源DButil.close(null, null, conn);}}
}

4.8、事务隔离级别

一个事务与其他事务隔离的程度称为隔离级别,相互之间隔离影响程度越大那么就说明隔离级别越小。

数据库隔离级别,并发可能出现的几种状态
脏读:读取未提交的事务的结果。
不可重复读:其他事务导致某个事物两次读取的数据不一样。(不可重读针对已经提交的数据。两次或多次读取同一条数据)
幻读:其他事务导致某个事物两次读取的数量不一样。(幻读针对已经提交的数据、或者两次或多次读取不同行数据,并且数量上新增或减少)。

针对并发可能出现的几种状态,JDBC有五种隔离级别解决问题,通过Collection接口即可调用。

  • TRANSACTION_NONE 无事务
  • ** TRANSACTION_READ_UNCOMMITTED** 允许读脏,不可重读,幻读。
  • TRANSACTION_READ_COMMITTED 直译为仅允许读取已提交的数据,即不能读脏,但是可能发生不可重读和幻读。
  • TRANSACTION_REPEATABLE_READ 不可读脏,保证同一事务重复读取相同数据,但是可能发生幻读。
  • TRANSACTION_SERIALIZABLE 直译为串行事务,保证不读脏,可重复读,不可幻读,事务隔离级别最高。

5、多线程

5.1、什么是多线程

多线程指的是一个程序在运行期间产生了多个线程。

5.2、实现多线程的方法

1、通过接口

//通过实现接口的方式
public class Thread1 implements Runnable{//线程的主体@Overridepublic void run() {for (int i = 1; i <=10; i++) {System.out.println(Thread.currentThread().getName()+"线程执行了"+i+"次");}}public static void main(String[] args) {//实例化对象Thread1 thread1 = new Thread1();//实例化线程对象 添加对象Thread thread = new Thread(thread1);//设置线程的名字thread.setName("线程1");//通过线程对象启动线程 start 启动线程的方法而不是直接调用run方法会执行main方法的线程thread.start();}}

运行结果

线程1线程执行了1次
线程1线程执行了2次
线程1线程执行了3次
线程1线程执行了4次
线程1线程执行了5次
线程1线程执行了6次
线程1线程执行了7次
线程1线程执行了8次
线程1线程执行了9次
线程1线程执行了10次

2、通过继承Thread类

//通过继承Threan类的方式
public class Thread1 extends Thread{//线程的主体@Overridepublic void run() {for (int i = 1; i <=10; i++) {System.out.println(Thread.currentThread().getName()+"线程执行了"+i+"次");}}public static void main(String[] args) {//实例化对象Thread1 thread1 = new Thread1();//设置线程的名字thread1.setName("线程A");//通过线程对象启动线程 start 启动线程的方法而不是直接调用run方法会执行main方法的线程thread1.start();}}

运行结果

线程1线程执行了1次
线程1线程执行了2次
线程1线程执行了3次
线程1线程执行了4次
线程1线程执行了5次
线程1线程执行了6次
线程1线程执行了7次
线程1线程执行了8次
线程1线程执行了9次
线程1线程执行了10次

5.3、线程五种状态

任何线程一般具有5种状态,即创建,就绪,运行,阻塞,终止。
①创建状态
当实例化一个进程对象的时候处于创建状态,此时线程已经有了相应的内存空间和其他资源,但还处于不可运行状态。
②就绪状态
创建线程对象后使用线程对象调用start()方法启动线程属于就绪状态,此时线程进入线程队列排队等待cpu分配资源。
③运行状态
当就绪状态被调用并获得处理器资源时,线程就进入了运行状态。此时,自动调用该线程对象的 run() 方法。run() 方法定义该线程的操作和功能。
④阻塞状态
线程在特定情况下被影响会暂时被CPU终止执行,进入阻塞状态,如果调用sleep(),suspend(),wait() 等方法,线程都将进入阻塞状态,发生阻塞时线程不能进入排队队列,只有当引起阻塞的原因被消除后,线程才可以转入就绪状态。
⑤死亡状态
线程调用 stop() 方法时或 run() 方法执行结束后,即处于死亡状态。处于死亡状态的线程不具有继续运行的能力。

注意:java在执行的时候会执行两个线程,第一个是main线程、第二个是垃圾回收线程。

5.4、操作线程的方法以及线程锁

5.4.1、强制运行线程

在线程操作中,可以使用 join() 方法让一个线程强制运行,线程强制运行期间,其他线程无法运行,必须等待此线程完成之后才可以继续执行。

//通过继承Threan类的方式
class Thread1 extends Thread{//线程的主体@Overridepublic void run() {for (int i = 1; i <=10; i++) {System.out.println(Thread.currentThread().getName()+"线程执行了"+i+"次");}}};
public class Thread2 {public static void main(String[] args) {//实例化对象Thread1 thread1 = new Thread1();//设置线程的名字thread1.setName("线程A");//通过线程对象启动线程 start 启动线程的方法而不是直接调用run方法会执行main方法的线程thread1.start();for (int i = 1; i <=10; i++) {if(i>10) {try {thread1.join();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println("main线程执行了"+i+"次");}}
}

运行结果

main线程执行了1次
main线程执行了2次
main线程执行了3次
main线程执行了4次
main线程执行了5次
main线程执行了6次
main线程执行了7次
main线程执行了8次
main线程执行了9次
main线程执行了10次
线程A线程执行了1次
线程A线程执行了2次
线程A线程执行了3次
线程A线程执行了4次
线程A线程执行了5次
线程A线程执行了6次
线程A线程执行了7次
线程A线程执行了8次
线程A线程执行了9次
线程A线程执行了10次

5.4.2、线程的休眠

线程的休眠

在程序中允许一个线程进行暂时的休眠,直接使用 Thread.sleep() 即可实现休眠。

//通过继承Threan类的方式
class Thread1 extends Thread{//线程的主体@Overridepublic void run() {for (int i = 1; i <=10; i++) {try {//设置线程休眠单位毫秒 //每隔两秒执行一下线程Thread.sleep(2000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName()+"线程执行了"+i+"次");}}};
public class Thread2 {public static void main(String[] args) {//实例化对象Thread1 thread1 = new Thread1();//设置线程的名字thread1.setName("线程A");//通过线程对象启动线程 start 启动线程的方法而不是直接调用run方法会执行main方法的线程thread1.start();}
}

运行结果

线程A线程执行了1次
线程A线程执行了2次
线程A线程执行了3次
线程A线程执行了4次
线程A线程执行了5次
线程A线程执行了6次
线程A线程执行了7次
线程A线程执行了8次
线程A线程执行了9次
线程A线程执行了10次

5.4.3、中断线程

当一个线程运行时,另外一个线程可以直接通过interrupt()方法中断其运行状态。

class MyThread implements Runnable{ // 实现Runnable接口 public void run(){  // 覆写run()方法 System.out.println("1、进入run()方法") ; try{ Thread.sleep(10000) ;   // 线程休眠10秒 System.out.println("2、已经完成了休眠") ; }catch(InterruptedException e){ System.out.println("3、休眠被终止") ; return ; // 返回调用处 } System.out.println("4、run()方法正常结束") ; } }; public class ThreadInterruptDemo{ public static void main(String args[]){ MyThread mt = new MyThread() ;  // 实例化Runnable子类对象 Thread t = new Thread(mt,"线程");     // 实例化Thread对象 t.start() ; // 启动线程 try{ Thread.sleep(2000) ;    // 线程休眠2秒 }catch(InterruptedException e){ System.out.println("3、休眠被终止") ; }          t.interrupt() ; // 中断线程执行 } };
运行结果1、进入run()方法
3、休眠被终止

5.4.4线程的优先级

在 Java 的线程操作中,所有的线程在运行前都会保持在就绪状态,那么此时,哪个线程的优先级高,哪个线程就有可能会先被执行。


public class Threandemo3 extends Thread{@Overridepublic void run() {for (int i = 1; i <=10; i++) {System.out.println(Thread.currentThread().getName()+ "运行了 = " + i+"次") ;}}public static void main(String[] args) {Threandemo3 t1 = new Threandemo3();Threandemo3 t2 = new Threandemo3();Threandemo3 t3 = new Threandemo3();//设置线程名字t1.setName("A线程");t2.setName("B线程");t3.setName("C线程");//设置线程优先级最低t1.setPriority(Thread.MIN_PRIORITY);//设置线程优先级最高t2.setPriority(Thread.MAX_PRIORITY);//设置线程优先级中等t3.setPriority(Thread.NORM_PRIORITY);//启动线程t1.start();t2.start();t3.start();}
}

运行结果

B线程运行了 = 1次
B线程运行了 = 2次
B线程运行了 = 3次
A线程运行了 = 1次
A线程运行了 = 2次
A线程运行了 = 3次
A线程运行了 = 4次
A线程运行了 = 5次
A线程运行了 = 6次
C线程运行了 = 1次
A线程运行了 = 7次
B线程运行了 = 4次
B线程运行了 = 5次
B线程运行了 = 6次
B线程运行了 = 7次
B线程运行了 = 8次
B线程运行了 = 9次
B线程运行了 = 10次
A线程运行了 = 8次
C线程运行了 = 2次
A线程运行了 = 9次
C线程运行了 = 3次
A线程运行了 = 10次
C线程运行了 = 4次
C线程运行了 = 5次
C线程运行了 = 6次
C线程运行了 = 7次
C线程运行了 = 8次
C线程运行了 = 9次
C线程运行了 = 10次

由此可见线程B的优先级最高C的优先级最低

5.4.5、线程礼让

在线程操作中,也可以使用 yield() 方法将一个线程的操作暂时让给其他线程执行。


public class Threandemo3 extends Thread{@Overridepublic void run() {for (int i = 1; i <=10; i++) {System.out.println(Thread.currentThread().getName()+ "运行了 = " + i+"次") ;//当i==5 线程转让给其他线程if(i>=5) {System.out.println("礼让");Thread.yield();}}}public static void main(String[] args) {Threandemo3 t1 = new Threandemo3();Threandemo3 t2 = new Threandemo3();//设置线程名字t1.setName("A线程");t2.setName("B线程");//启动线程t1.start();t2.start();}
}

运行结果

A线程运行了 = 1次
B线程运行了 = 1次
A线程运行了 = 2次
A线程运行了 = 3次
A线程运行了 = 4次
A线程运行了 = 5次
礼让
A线程运行了 = 6次
礼让
B线程运行了 = 2次
A线程运行了 = 7次
礼让
A线程运行了 = 8次
礼让
A线程运行了 = 9次
礼让
B线程运行了 = 3次
B线程运行了 = 4次
A线程运行了 = 10次
礼让
B线程运行了 = 5次
礼让
B线程运行了 = 6次
礼让
B线程运行了 = 7次
礼让
B线程运行了 = 8次
礼让
B线程运行了 = 9次
礼让
B线程运行了 = 10次
礼让

5.4.6、同步锁和死锁

一个多线程的程序如果是通过 Runnable 接口实现的,则意味着类中的属性被多个线程共享,那么这样就会造成一种问题,如果这多个线程要操作同一个资源时就有可能出现资源同步问题。

synchronized(同步对象){
需要同步的代码
}


public class Threandemo3 implements Runnable{private int ticket = 10 ;    // 假设一共有10张票 @Overridepublic  void run() {for (int i = 1; i <=10; i++) {synchronized (this) {if(ticket>0) {//证明还有票System.out.println(Thread.currentThread().getName()+"线程卖票还剩:  " + (ticket--)+"张票" ); }}}}public static void main(String[] args) {Threandemo3 t1 = new Threandemo3();Thread ts = new Thread(t1);Thread td = new Thread(t1);ts.start();td.start();}
}

运行结果

Thread-0线程卖票还剩:  10张票
Thread-0线程卖票还剩:  9张票
Thread-0线程卖票还剩:  8张票
Thread-0线程卖票还剩:  7张票
Thread-0线程卖票还剩:  6张票
Thread-0线程卖票还剩:  5张票
Thread-0线程卖票还剩:  4张票
Thread-0线程卖票还剩:  3张票
Thread-0线程卖票还剩:  2张票
Thread-0线程卖票还剩:  1张票

上面代码创建了线程两个对象使用同步锁之后只能由一个窗口卖完十张票

同步方法
synchronized 方法返回值 方法名称(参数列表){
}


public class Threandemo3 implements Runnable{private int ticket = 10 ;    // 假设一共有10张票 @Overridepublic synchronized void run() {for (int i = 1; i <=10; i++) {if(ticket>0) {//证明还有票System.out.println(Thread.currentThread().getName()+"线程卖票还剩:  " + (ticket--)+"张票" ); }}}public static void main(String[] args) {Threandemo3 t1 = new Threandemo3();Thread ts = new Thread(t1);Thread td = new Thread(t1);ts.start();td.start();}
}
运行结果
```java
Thread-0线程卖票还剩:  10张票
Thread-0线程卖票还剩:  9张票
Thread-0线程卖票还剩:  8张票
Thread-0线程卖票还剩:  7张票
Thread-0线程卖票还剩:  6张票
Thread-0线程卖票还剩:  5张票
Thread-0线程卖票还剩:  4张票
Thread-0线程卖票还剩:  3张票
Thread-0线程卖票还剩:  2张票
Thread-0线程卖票还剩:  1张票

5.4.7、死锁

同步可以保证资源共享操作的正确性,但是过多同步也会产生问题。

class Zhangsan{ // 定义张三类 public void say(){ System.out.println("张三对李四说:“你给我钱,我就把东西给你。”") ; } public void get(){ System.out.println("张三得到东西了。") ; }
};
class Lisi{ // 定义李四类 public void say(){ System.out.println("李四对张三说:“你给我东西,我就把钱给你”") ; } public void get(){ System.out.println("李四得到钱了。") ; }
};
public class ThreadDeadLock implements Runnable{ private static Zhangsan zs = new Zhangsan() ;       // 实例化static型对象 private static Lisi ls = new Lisi() ;       // 实例化static型对象 private boolean flag = false ;  // 声明标志位,判断那个先说话 public void run(){  // 覆写run()方法 if(flag){ synchronized(zs){   // 同步张三 zs.say() ; try{ Thread.sleep(500) ; }catch(InterruptedException e){ e.printStackTrace() ; } synchronized(ls){ zs.get() ; } } }else{ synchronized(ls){ ls.say() ; try{                      Thread.sleep(500) ; }catch(InterruptedException e){ e.printStackTrace() ; } synchronized(zs){ ls.get() ; } } } } public static void main(String args[]){ ThreadDeadLock t1 = new ThreadDeadLock() ;      // 控制张三 ThreadDeadLock t2 = new ThreadDeadLock() ;      // 控制李四 t1.flag = true ; t2.flag = false ; Thread thA = new Thread(t1) ; Thread thB = new Thread(t2) ; thA.start() ; thB.start() ; }
};

运行结果

张三对李四说:“你给我钱,我就把东西给你。”
李四对张三说:“你给我东西,我就把钱给你”

Java SE 高级教程相关推荐

  1. Oracle Java SE高级版

    具统计,当前有90%以上的企业采用Java进行应用系统的开发,其中有很大一部分企业还在使用5年甚至10年以前版本的Java.由于这种复杂的IT环境,客户无法从开发的最底层实现风险的控制和管理,也就无法 ...

  2. java程序设计高级教程答案_Java高级程序设计实战教程答案

    [简答题]如何决定选用 HashMap 还是 TreeMap ? [单选题]下面说法不正确的是 ______ . [简答题]请简述类编写规范. [简答题]遍历一个 List 有哪些不同的方式? [填空 ...

  3. java se实践教程_Java SE实践教程

    第1章 进驻爪哇岛--JAVA的基本语法.1 1.1 讲解2 1.1.1 爪哇岛的历史与演变2 1.1.2 爪哇岛基本生存规则4 1.1.3 爪哇岛上新人新风尚11 1.2 练习15 1.2.1 搭建 ...

  4. Java编程高级教程,这些数据库索引的高频面试题,你都掌握了多少

    HASH HASH即哈希索引,哈希索引多用于等值查询,时间复杂夫为o(1),效率非常高,但不支持排序.范围查询及模糊查询等. BTREE BTREE即B+树索引,INnoDB存储引擎默认的索引,支持排 ...

  5. 新书上架:《Java SE 实践教程》

    在 NetBeans 中文社区参与了此书的写作,今年终于上架了 :-) http://www.china-pub.com/195637&ref=ps http://www.douban.com ...

  6. JAVA SE基础知识总结

    JAVA基础篇 1_JAVA语言概述 1.1 JAVA的总体概述 1.2 JAVA语言概述 1.2.1 基础常识 1.2.2 计算机语言的发展迭代史 1.2.3 Java语言版本迭代概述 1.2.4 ...

  7. 第一阶段Java SE学习概述

    Java SE学习概述 Java SE 学习分为五个阶段 第一部分:基础程序设计: 第二部分:面现象对象编程: 第三部分:Java SE 高级应用: 第四部分:JavaSE 新特性: 第五部分:MyS ...

  8. java高级教程_高级Java教程

    java高级教程 课程大纲 学习Java基础很容易. 但是,真正钻研该语言并研究其更高级的概念和细微差别将使您成为一名出色的Java开发人员. 网络上充斥着"软","便宜 ...

  9. java中的jpa_JPA教程–在Java SE环境中设置JPA

    java中的jpa JPA代表Java Persistence API,它基本上是一个规范,描述了一种将数据持久存储到持久存储(通常是数据库)中的方法. 我们可以将其视为类似于Hibernate之类的 ...

最新文章

  1. 2018-3-25论文(Grey Wolf Optimizer)自然界狼群的生活等级
  2. ECLIPSE 调试F8-------运行到下一断点处 F5-------STEP INTO F6-------STEP OVER
  3. Spring5源码 - 06 Spring Bean 生命周期流程 概述 01
  4. 北京内推 | 地平线视觉算法团队招聘视觉算法实习生
  5. java中类与类的关系_Java中类与类的关系
  6. qt根据散点图拟合曲线_R可视化 | 散点图系列(1)
  7. SpringBoot非官方教程 | 第三篇:SpringBoot用JdbcTemplates访问Mysql
  8. 终端仿真程序_SecureCRT for mac(终端SSH工具)
  9. opencv 直方图
  10. java string.format_如果性能很重要,我应该使用Java的String.format()吗?
  11. atlas 200 远程图形化桌面
  12. 把博客园的博客导出为MovableType的文本格式
  13. 《Google Go: A Primer》学习笔记
  14. DevChartControl的颜色配置
  15. 作为面试官,如何甄别应聘者的包装程度?
  16. ISCC2021 wp
  17. python与其他的数据分析有什么区别_学好python和数据分析有什么关系?
  18. 手把手教你学51单片机-变量进阶与点阵LED
  19. 计算机网络基础——访问控制列表
  20. 三菱Q系列PLC编程TCP Socket套接字程序

热门文章

  1. 基于Java+Spring+Vue+elementUI大学生求职招聘系统详细设计实现
  2. python安装需要什么电脑配置_自学python用什么配置电脑?
  3. linux下最好的chm阅读器KchmViewer,安装使用/与oklular,xCHM,gnochm简单比较
  4. jQuery 特效:盒子破碎和移动动画效果
  5. 苹果手机怎样添加无线网服务器,如何让苹果手机网速提升三倍?
  6. 星网锐捷语音网关密码重置恢复出厂设置
  7. Pygame pgu 入门详解
  8. 加拿大:国家资助研究项目IRAP已自主研发区块链浏览器
  9. 只需几步,用Python3实现属于自己的搜索引擎
  10. WIN10 共享 访问WIN7提示 出现“你不能访问此共享文件夹,因为你组织的安全策略阻止未经身份验证的来宾访问