第一章 冒泡排序
1.1 冒泡排序
-
冒泡排序概述
- 对要进行排序的数据中相邻的数据进行两两比较,将较大的数据放在后面
- 每一轮比较完毕,最大值在最后面,下一轮比较就少一个数据参与
- 每轮比较都从第一个元素(索引为0的元素)开始
- 依次执行,直至所有数据按要求完成排序
- 如果有n个数据进行排序,总共需要比较n - 1轮
-
冒泡排序代码实现
public class Test { public static void main(String[] args) { int[] arr = {45, 25, 35, 55, 15}; // 外层循环控制比较轮数 for (int i = 0; i < arr.length - 1; i++) { // 内层循环控制比较次数 for (int j = 0; j < arr.length - 1 - i; j++) { // 比较并交换 if (arr[j] > arr[j+1]){ int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } System.out.println("排序后:"+ Arrays.toString(arr)); } }
第二章 选择排序
2.1 选择排序
-
选择排序概述
- 对要进行排序的数组中,使某个元素依次和后面的元素逐个比较,将较大的数据放在后面
- 每一轮比较完毕,最小值在最前面,下一轮比较就少一个数据参与
- 每轮比较都从下一个(轮数+1)元素开始
- 依次执行,直至所有数据按要求完成排序
- 如果有n个数据进行排序,总共需要比较n - 1轮
-
选择排序代码实现
public class Test { public static void main(String[] args) { int[] arr = {45, 25, 35, 55, 15}; // 外层循环控制比较轮数 for (int i = 0; i < arr.length - 1; i++) { // 内层循环控制每轮比较的次数 for (int j = i + 1; j < arr.length; j++) { if (arr[i] > arr[j]) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } } System.out.println("排序后:" + Arrays.toString(arr)); } }
第三章 查找
3.1普通查找
原理
-遍历数组,获取每一个元素,
-判断当前遍历的元素是否和要查找的元素相同,
-如果相同就返回该元素的索引,结束循环
-循环结束视为没有找到,就返回一个负数作为标识(一般是-1)
3.2 二分查找
-
二分查找
- 每一次都去获取数组的中间索引所对应的元素,然后和要查找的元素进行比对,如果相同就返回索引
- 如果不相同,就比较中间元素和要查找的元素的值:
- 如果中间元素的值大于要查找的元素,说明要查找的元素在左侧,那么就从左侧按照上述思想继续查询(忽略右侧数据);
- 如果中间元素的值小于要查找的元素,说明要查找的元素在右侧,那么就从右侧按照上述思想继续查询(忽略左侧数据);
-
前提:数据有序
-
二分查找代码实现
public class Test { public static void main(String[] args) { int[] arr = {10, 14, 21, 38, 45, 47, 53, 81, 87, 99}; System.out.println(searchBinary(arr, 47));// 5 System.out.println(searchBinary(arr, 50));// -1 } // 定义一个方法,实现二分查找 public static int searchBinary(int[] arr, int num) { // 1.定义一个int类型的变量,用来记录左边元素的索引,初始值为0 int left = 0; // 2.定义一个int类型的变量,用来记录右边元素的索引,初始值为arr.length-1 int right = arr.length - 1; // 3.使用while循环查找,查找条件: left <= right while (left <= right) { // 4.计算中间元素的索引: middle = (left+right)/2 int middle = (left + right) / 2; // 5.判断比较中间索引对应的元素与要查找的元素: // 6.如果相等,直接返回中间元素的索引 if (arr[middle] == num) { return middle; } else if (arr[middle] < num) { // 7.如果中间索引对应的元素 小于 要查找的元素,说明要查找的元素在右边,就需要改变left的值: middle+1 left = middle + 1; } else if (arr[middle] > num) { // 8.如果中间索引对应的元素 大于 要查找的元素,说明要查找的元素在左边,就需要改变right的值: middle-1 right = middle - 1; } } // 9.循环结束还没有找到,直接返回-1作为标识 return -1; } }
第四章 异常
4.1 异常
异常概念
- 概述: 指的是java程序运行期间出现的不正常情况,导致jvm终止程序的运行
- 特点:
- java是面向对象的语言,产生的每个异常其实都是一个异常对象,每个异常对象一定会有所属的异常类
- 常见的异常类:
- ClassCastException,
- NullPointerException,
- ArrayIndexOutOfBoundsException,
- ArithmeticException
- parseException
- java中默认将异常抛给jvm处理,而jvm处理的方式就是中断运行,将异常信息输出到控制台
异常体系
- Throwable类: 是 Java 语言中所有错误或异常类的父类
- Error类(错误): 表示错误,不可以通过代码进行纠正使得程序继续运行,只能事先避免
- eg: 栈内存溢出错误… XXXError类
- Exception类(异常):表示异常,可以通过代码进行纠正使得程序继续运行
- eg: 类型转换异常…
- Error类(错误): 表示错误,不可以通过代码进行纠正使得程序继续运行,只能事先避免
异常分类
-
编译异常: 程序在编译期间出现的异常,如果不处理,程序无法通过编译
- 除了RuntimeException及其子类都是表示编译异常
-
运行异常: 程序在运行期间出现的异常,如果不处理,程序可以通过编译,但在运行的时候会出现异常
- RuntimeException及其子类都是表示运行异常
第五章 异常的产生和处理
5.1 异常的产生
throw关键字的作用
-
在java中,提供了一个throw关键字,它用来抛出一个指定的异常对象。
-
throw用在方法内,来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。
throw关键字的使用格式
-
格式:
throw 异常对象;
-
代码:
public class Test { public static void main(String[] args) { int[] arr = { 34, 12, 67 }; int num = getElement(arr, 4); System.out.println("over"); } // 对给定的数组通过给定的角标获取元素。 public static int getElement(int[] arr, int index) { // 判断的步骤 if (index < 0 || index > arr.length-1){ // 索引不存在,就需要产生异常----jdk认识ArrayIndexOutOfBoundsException System.out.println("产生了异常"); throw new ArrayIndexOutOfBoundsException(""+index);// 产生异常抛出,然后结束方法 // System.out.println("==");// 编译报错,因为这是永远都不会执行的代码 }else { int element = arr[index]; return element; } } }
5.2 声明处理异常
-
概述:使用throws关键字将问题标识出来, 表示当前方法不处理异常,而是提醒给调用者, 让调用者来处理…
-
格式:
修饰符 返回值类型 方法名(形参列名) throws 异常类型1,异常类型2,...{}
-
特点:
-
throws关键字是用在方法的声明之上的,也就是方法小括号的后面
-
throws可以一次抛一个或多个异常
-
使用声明处理异常,处理完后,如果程序运行期间没有出现异常,程序可以继续往下执行
-
使用声明处理异常,处理完后,如果程序运行期间有出现异常,程序不可以继续往下执行
-
代码:
声明处理用在
1.运行时不会出现异常的编译异常上
2.当前方法不想处理异常 ,但是在到达jvm之前必须处理该异常(捕获处理),否则程序会异常终止
public class Test { public static void main(String[] args) throws ParseException{ /* - 概述:使用throws关键字将问题标识出来, 表示当前方法不处理异常,而是提醒给调用者, 让调用者来处理.... - 格式: 修饰符 返回值类型 方法名(形参列名) throws 异常类型1,异常类型2,...{} - 特点: - throws关键字是用在方法的声明之上的,也就是方法小括号的后面 - throws可以一次抛一个或多个异常 - 使用声明处理异常,处理完后,如果程序运行期间没有出现异常,程序可以继续往下执行 - 使用声明处理异常,处理完后,如果程序运行期间有出现异常,程序不可以继续往下执行 */ // 以下程序运行的时候是没有异常的,但编译的时候有编译异常(主要是因为parse方法里面产生了一个编译异常对象,并且是声明处理) SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd"); Date date1 = sdf1.parse("1999-10-10"); System.out.println("date1:" + date1); System.out.println("========"); // 以下程序运行的时候是有异常的 SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日"); Date date2 = sdf2.parse("1999-10-10"); System.out.println("date2:" + date2); } }
-
-
使用场景:
- 用来处理编译异常,并且该程序在运行期间不会出现异常
-
声明处理多个异常:
// 声明处理多个异常--->分别抛出各个异常类 public static void method1(int num) throws FileNotFoundException,IOException{ if (num == 10){ // 产生一个异常 throw new FileNotFoundException("文件找不到异常"); }else{ // 产生一个异常 throw new IOException("Io异常"); } } // 声明处理多个异常--->抛出所有异常的父类 public static void method2(int num) throws Exception{ if (num == 10){ // 产生一个异常 throw new FileNotFoundException("文件找不到异常"); }else{ // 产生一个异常 throw new IOException("Io异常"); } }
5.3 捕获处理异常try…catch
-
概述: 也是一种处理异常的方式,这种处理异常的方式处理完异常后,无论程序是否发生异常,程序都可以继续往下执行.
-
格式:
try{ // 可能会发生异常的代码 }catch(异常类型 变量名){ // 打印异常的信息,发生异常后需要执行的代码 }
-
注意:
- try,catch都不能单独使用
- try中的代码如果发生了异常,try中发生异常位置之后的代码就不执行了
-
执行流程:
- 首先执行try中的代码:
- 如果try中的代码发生了异常,就会执行catch里面的代码,执行完catch里面的代码后,程序继续往下执行
- 如果try中的代码没有发生异常,就不会执行catch里面的代码,而是继续往下执行
-
代码:
public class Test { public static void main(String[] args) { // 以下程序运行的时候是没有异常的 try{ SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd"); Date date1 = sdf1.parse("1999-10-10"); System.out.println("date1:" + date1); }catch (ParseException e){ System.out.println("发生了异常1"); } System.out.println("========"); // 以下程序运行的时候是有异常的 try{ SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日"); Date date2 = sdf2.parse("1999-10-10");// 发生异常 System.out.println("date2:" + date2);// 这里的代码就不执行 }catch (ParseException e){ System.out.println("发生了异常2"); } System.out.println("over..."); } }
-
获取异常信息: ---->Throwable类
-
public String getMessage():获取异常的描述信息,原因(提示给用户的时候,就提示错误原因)
-
public String toString():获取异常的类型和异常描述信息(不用)
-
public void printStackTrace():打印异常的跟踪栈信息并输出到控制台
public class Test { public static void main(String[] args) { // - public String getMessage():获取异常的描述信息,原因(提示给用户的时候,就提示错误原因 // - public String toString():获取异常的类型和异常描述信息(不用) // - public void printStackTrace():打印异常的跟踪栈信息并输出到控制台 try { SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日"); Date date2 = sdf2.parse("1999-10-10");// 发生异常,创建异常对象 throw new ParseException("异常信息"); System.out.println("date2:" + date2); } catch (ParseException e) { // System.out.println("异常信息:" + e.getMessage());// Unparseable date: "1999-10-10" // System.out.println("e:" + e.toString());// java.text.ParseException: Unparseable date: "1999-10-10" e.printStackTrace(); } System.out.println("over..."); } }
-
5.4 finally 代码块
finally代码块的概述
finally:因为异常会引发程序跳转,导致有些语句执行不到。而finally就是解决这个问题的,在finally代码块中存放的代码在正常情况下一定会被执行的。
finally代码块的语法格式
try{
可能会出现异常的代码
}catch(异常的类型 变量名){
处理异常的代码或者打印异常的信息
}finally{
无论异常是否发生,都会执行这里的代码(正常情况,都会执行finally中的代码,一般用来释放资源)
}
执行步骤:
1.首先执行try中的代码,如果try中的代码出现了异常,那么就直接执行catch()里面的代码,执行完后会执行finally中的代码,然后程序继续往下执行
2.如果try中的代码没有出现异常,那么就不会执行catch()里面的代码,但是还是会执行finally中的代码,然后程序继续往下执行
注意:finally不能单独使用。
案例演示
public class Test {
public static void main(String[] args) {
// 以下程序运行的时候是没有异常的
try{
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = sdf1.parse("1999-10-10");
System.out.println("date1:" + date1);
}catch (ParseException e){
System.out.println("发生了异常1");
}finally {
System.out.println("finally代码块1...");
}
System.out.println("========");
// 以下程序运行的时候是有异常的
try{
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日");
Date date2 = sdf2.parse("1999-10-10");// 发生异常
System.out.println("date2:" + date2);
}catch (ParseException e){
System.out.println("发生了异常2");
// System.exit(0);// 非正常情况---jvm退出
return;// 正常情况
}finally {
System.out.println("finally代码块2...");
}
System.out.println("over...");
}
}
5.5 finally面试题
public class Test {
public static void main(String[] args) {
System.out.println(method1());// 30
System.out.println(method2());// 20
}
public static int method1() {
int num = 10;
try {
System.out.println(1 / 0);
} catch (ArithmeticException e) {
num = 20;
// catch中的return会做2件事情:
// 1.记录要返回的值,然后执行finally代码块--->20
// 2.返回之前记录的返回值--->执行完finally后就不执行了(因为finally有return)
return num;
} finally {
num = 30;
return num;// ---->返回30,然后结束方法
}
}
public static int method2() {
int num = 10;
try {
System.out.println(1 / 0);
} catch (ArithmeticException e) {
num = 20;
// catch中的return会做2件事情:
// 1.记录要返回的值,然后执行finally代码块--->20
// 2.返回之前记录的返回值--->20 (finally没有return)
return num;
} finally {
num = 30;
}
return num;
}
}
5.6 异常注意事项
-
try/catch/finally都不可以单独使用
-
运行时异常被抛出可以不处理(不捕获也不声明抛出)
-
在try/catch后可以追加finally代码块,其中的代码一定会被执行,通常用于资源回收
-
方法重写时的注意事项
-
父类的方法抛出异常,子类覆盖(重写)父类方法时,只能抛出相同的异常或该异常子集
-
父类的方法未抛出的异常,子类覆盖(重写)父类方法时,只能处理,不能抛出
-
代码:
class Fu { public void method1(int num) throws FileNotFoundException { } public void method2(int num) { } } class Zi extends Fu { // 父类的方法声明处理异常,子类覆盖(重写)父类方法时,只能抛出相同的异常或该异常子集 // 解决方式:使用捕获处理异常 @Override public void method1(int num) throws FileNotFoundException/*,IOException 编译报错*/ { } // 父类的方法未声明处理异常,子类覆盖(重写)父类方法时,只能捕获处理,不能声明处理 @Override public void method2(int num) /*throws FileNotFoundException 编译报错*/{ } } public class Test { public static void main(String[] args) { } }
-
-
try…catch捕获多个异常的方式以及注意事项:
// try...catch捕获多个异常: // 方式一:分别捕获处理 public static void method1(int num) { if (num == 10) { try { throw new FileNotFoundException("文件找不到异常"); } catch (FileNotFoundException e) { e.printStackTrace(); } } else { try { throw new IOException("IO异常"); } catch (IOException e) { e.printStackTrace(); } } } // 方式二:一次捕获多次处理--->前边的类不能是后边类的父类或同类 public static void method2(int num) { try { if (num == 10) { throw new FileNotFoundException("文件找不到异常"); } else { throw new IOException("IO异常"); } } catch (FileNotFoundException e1) { e1.printStackTrace(); } catch (IOException e2) {// 一定要放在后面,因为IOException是FileNotFoundException的父类 e2.printStackTrace(); } } // 方式三:一次捕获一次处理 public static void method3(int num) { try { if (num == 10) { throw new FileNotFoundException("文件找不到异常"); } else { throw new IOException("IO异常"); } } catch (IOException e) { e.printStackTrace(); } }
第六章 自定义异常
6.1 自定义异常
-
理解:在开发中根据自己业务的异常情况来定义异常类表示某种异常问题.
-
原因:Java中异常类具备异常发生中断程序的功能,但一些异常情况是java没有定义的,需要根据业务自行定义(例:年龄负数问题)
-
自定义异常类分类
-
自定义编译期异常: 自定义类 并继承于java.lang.Exception
-
自定义运行时期异常:自定义类 并继承于java.lang.RuntimeException
// 编译异常 public class MyException1 extends Exception { } // 运行异常 public class MyException2 extends RuntimeException { }
-
-
需求:按照如下要求完成案例
-
模拟注册操作,如果用户名已存在,则抛出异常并提示:亲,该用户名已经被注册
public class MyRegisterException extends RuntimeException { public MyRegisterException() { } public MyRegisterException(String message) { super(message); } } public class Test { public static void main(String[] args) { // 练习:模拟注册操作,如果用户名已存在,则抛出异常并提示:亲,该用户名已经被注册 String username = "itheima"; // 用户输入要注册的用户名 Scanner sc = new Scanner(System.in); System.out.println("请输入要注册的用户名:"); String name = sc.nextLine(); // 判断用户输入的用户名 if (username.equals(name)) { // 产生注册异常 try { throw new MyRegisterException("亲,该用户名已经被注册"); } catch (MyRegisterException e) { System.out.println("异常信息:" + e.getMessage()); } } else { System.out.println("恭喜您,注册成功!"); } System.out.println("over..."); } }
-
第七章 多线程
7.1 并发与并行
- 并行:指两个或多个事件在同一时刻发生(同时执行)。
- 并发:指两个或多个事件在同一个时间段内发生(交替执行)。
7.2 线程与进程
-
进程:进程是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;
-
进程是应用程序的可执行单元
-
一个应用程序可以有多个进程
-
每个进程执行都会有独立的内存空间(堆空间和栈空间是独立的)
-
线程:是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一条线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
-
线程是进程的可执行单元
-
一个进程可以有多条线程
-
每个线程执行都会有独立的内存空间(堆空间共享,栈空间独立,线程消耗的资源比进程小)
-
一个java程序只有一个进程,然后有多条线程,但是一次只运行一条线程
-
一个进程一次只能执行一条线程,所以java中只有多线程并发,没有多线程并行
-
线程的调度: 当一个cpu以某种顺序执行多个线程,我们把这种情况称之为线程调度
- 分时调度:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间
- 抢占式调度:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性)----->随机性:进程中的多个线程,本质上是依赖于并发式运行,具体哪个线程什么时候被cpu调用执行,程序员并不能直接完全决定
- Java线程的调度方式: 抢占式
7.3 Thread类
概述:
java.lang.Thread类代表**线程**,所有的线程对象都必须是Thread类或其子类的实例
每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码
Java使用线程执行体来代表这段程序流,在Tread线程中,使用run()方法代表线程执行体
构造方法
public Thread():创建一个新的线程对象,默认名称
public Thread(String name):创建一个指定名字的新的线程对象
public Thread(Runnable target):创建一个带有指定任务的线程对象,通过参数Runnable指定任务
public Thread(Runnable target,String name):创建一个带有指定任务的线程对象并指定线程名字
常用方法
public String getName():获取当前线程名称
public void start():导致此线程开始执行; Java虚拟机调用此线程的run方法
public void run():此线程要执行的任务在此处定义代码
public static void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停执行
public static Thread currentThread() :返回对当前正在执行的线程对象的引用
通过Thread类的api,可以指定创建线程有2种方式:
1.通过继承Thread类的方式,重写run()方法,创建子类对象,调用start()方法启动
2.通过实现Runnable接口的方式,重写run()方法,创建Thread线程对象,并传入实现类对象,使用Thread线程对象调用start方法启动线程,执行任务
3.通过创建Thread线程对象,并传入Runnable接口的匿名内部类
7.4 继承方式创建线程
-
步骤:
- 创建一个子类继承Thread类
- 在子类中重写run方法,把线程需要执行的任务代码放入run方法中
- 创建子类对象,调用start()方法启动线程,执行任务
-
实现:
public class MyThread extends Thread { @Override public void run() { // 线程需要执行的任务代码 for (int i = 0; i < 100; i++) { System.out.println("子线程i的值是:"+i); } } } public class Test { public static void main(String[] args) { /* - 创建一个子类继承Thread类 - 在子类中重写run方法,把线程需要执行的任务代码放入run方法中 - 创建子类对象,调用start()方法启动线程,执行任务 注意: 1.线程不能重复启动,只能启动一次 2.启动线程,一定要调用start()方法 */ // 创建线程对象 MyThread mt = new MyThread(); // 启动线程,执行任务 mt.start();// 默认调用run方法 // 线程需要执行的任务代码 for (int j = 0; j < 100; j++) { System.out.println("主线程j的值是:"+j); } } }
7.5 实现方式创建线程
-
Runnable是一个任务接口,里面有一个抽象方法run(),可以在run方法中书写线程的任务代码
-
实现步骤:
- 创建实现类实现Runnable接口
- 在实现类中,重写run方法,把线程需要执行的任务代码放入run方法中
- 创建实现类对象
- 创建Thread线程对象,并传入实现类对象
- 使用Thread线程对象调用start方法启动线程,执行任务
-
实现:
public class MyRunnable implements Runnable { @Override public void run() { // 线程需要执行的任务代码 for (int i = 0; i < 100; i++) { System.out.println("子线程i的值是:"+i); } } } public class Test { public static void main(String[] args) { /* 实现步骤: - 创建实现类实现Runnable接口 - 在实现类中,重写run方法,把线程需要执行的任务代码放入run方法中 - 创建实现类对象 - 创建Thread线程对象,并传入实现类对象 - 使用Thread线程对象调用start方法启动线程,执行任务 */ // 创建实现类对象 MyRunnable mr = new MyRunnable(); // 创建Thread线程对象 Thread t = new Thread(mr); // 启动线程执行任务 t.start(); // 主线程需要执行的任务代码 for (int j = 0; j < 100; j++) { System.out.println("主线程j的值是:"+j); } } }
7.6 匿名内部类方式
-
原理: 可以传入Runnable接口的匿名内部类
-
步骤:
- 创建Thread线程对象,并传入Runnable接口的匿名内部类
- 在Runnable匿名内部类中重写run方法,书写线程需要执行的任务代码
- 使用Thread线程对象调用start方法启动线程,执行任务
-
实现:
public class Test { public static void main(String[] args) { /* - 创建Thread线程对象,并传入Runnable接口的匿名内部类 - 在Runnable匿名内部类中重写run方法,书写线程需要执行的任务代码 - 使用Thread线程对象调用start方法启动线程,执行任务 */ // 创建线程对象,传入任务对象 Thread t = new Thread(new Runnable() { @Override public void run() { // 线程任务需要执行的任务代码 for (int i = 0; i < 100; i++) { System.out.println("子线程i的值是:"+i); } } }); // 启动线程,执行任务 t.start(); // 主线程需要执行的任务代码 for (int j = 0; j < 100; j++) { System.out.println("主线程j的值是:"+j); } } }
7.7 创建并启动多条线程
-
通过继承的方式:
public class MyThread extends Thread { public MyThread() { } public MyThread(String name) { super(name); } @Override public void run() { System.out.println(getName() + ":线程的任务代码..."); } } public class Test { public static void main(String[] args) { // 创建并启动多条线程 new MyThread().start(); new MyThread().start(); new MyThread().start(); new MyThread().start(); new MyThread().start(); new MyThread("张三1").start(); new MyThread("张三2").start(); new MyThread("张三3").start(); new MyThread("张三4").start(); new MyThread("张三5").start(); // 当前正在执行的线程: 主线程 System.out.println(Thread.currentThread().getName() + ":主线程的任务代码..."); } }
-
通过实现的方法:
public class MyRunnable implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName()+":开始执行线程任务代码..."); // 暂停 try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+":结束执行线程任务代码..."); } } public class Test { public static void main(String[] args) { // 创建任务对象 MyRunnable mr = new MyRunnable(); // 创建并启动多条线程-->默认名称 new Thread(mr).start(); new Thread(mr).start(); new Thread(mr).start(); new Thread(mr).start(); new Thread(mr).start(); // 创建并启动多条线程-->指定名称 new Thread(mr,"张三1").start(); new Thread(mr,"张三2").start(); new Thread(mr,"张三3").start(); new Thread(mr,"张三4").start(); new Thread(mr,"张三5").start(); } }
7.8 实现方式创建线程的优势
实现Runnable接口比继承Thread类所具有的优势:
- 适合多个相同的程序代码的线程去共享同一个资源(任务)。
- 可以避免java中的单继承的局限性。
- 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
- 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。
总结
1.冒泡排序和选择排序,二分查找要理解其原理
2.异常的处理(声明处理,捕获处理)---->alt+回车--->选择处理方式
3.创建并启动线程的三种方式
4.创建并启动多条线程
- 能够理解冒泡排序的执行原理
- 对要进行排序的数据中相邻的数据进行两两比较,将较大的数据放在后面
- 每一轮比较完毕,最大值在最后面,下一轮比较就少一个数据参与
- 每轮比较都从第一个元素(索引为0的元素)开始
- 依次执行,直至所有数据按要求完成排序
- 如果有n个数据进行排序,总共需要比较n - 1轮
- 能够理解选择排序的执行原理
- 对要进行排序的数组中,使某个元素依次和后面的元素逐个比较,将较大的数据放在后面
- 每一轮比较完毕,最小值在最前面,下一轮比较就少一个数据参与
- 每轮比较都从下一个(轮数+1)元素开始
- 依次执行,直至所有数据按要求完成排序
- 如果有n个数据进行排序,总共需要比较n - 1轮
- 能够理解二分查找的执行原理
- 每一次都去获取数组的中间索引所对应的元素,然后和要查找的元素进行比对,如果相同就返回索引
- 如果不相同,就比较中间元素和要查找的元素的值:
- 如果中间元素的值大于要查找的元素,说明要查找的元素在左侧,那么就从左侧按照上述思想继续查询(忽略右侧数据);
- 如果中间元素的值小于要查找的元素,说明要查找的元素在右侧,那么就从右侧按照上述思想继续查询(忽略左侧数据);
- 能够辨别程序中异常和错误的区别
- Error类(错误): 表示错误,不可以通过代码进行纠正使得程序继续运行,只能事先避免
- Exception类(异常):表示异常,可以通过代码进行纠正使得程序继续运行
- 说出异常的分类
- 编译异常: 程序在编译期间出现的异常,如果不处理,程序无法通过编译
- 运行异常: 程序在运行期间出现的异常,如果不处理,程序可以通过编译,但在运行的时候会出现异常
- 列举出常见的三个运行期异常
ArrayIndexOutOfBoundsException
NullPointerException
ClassCastException
...
- 能够使用try...catch关键字处理异常
格式,执行流程
- 能够使用throws关键字处理异常
格式,特点,使用场景
- 能够自定义并使用异常类
创建异常类继承Exception或者RuntimeException
- 说出进程和线程的概念
进程: 其实就是.exe文件
线程: 其实就是进程的可执行单元
- 能够理解并发与并行的区别
并发: 多个事件在同一时刻交替发生
并行: 多个事件在同一时刻同时发生
- 能够使用继承类的方式创建多线程
创建子类继承Thread类
在子类中重写run方法,把线程需要执行的任务代码放入run方法中
创建子类线程对象,调用start方法启动线程,执行任务
- 能够使用实现接口的方式创建多线程
创建实现类实现Runnable接口
在实现类中重写run方法,把线程需要执行的任务代码放入run方法中
创建Thread类线程对象,并传入任务对象
调用start方法启动线程,执行任务
- 能够说出实现接口方式的好处
1. 适合多个相同的程序代码的线程去共享同一个资源(任务)。
2. 可以避免java中的单继承的局限性。
3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
4. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。