JAVA 必须掌握技能(三)-Java 基础知识
版权声明:本文为CSDN博主「iswitched」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44873106/article/details/89787021
1 环境变量配置
JAVA_HOME:jdk路径
Path:要把jdk的bin目录路径,添加到path变量
2.八种数据基本类型
比较简单此处不单独罗列
引用数据类型:数组,类,接口
2.1 char :Unicode编码的字符,或字符的整数编码,必须用单引号
float默认值是0.0f;
double默认值是0.0d;
2.2基本类型字面值规则
1.整数字面值是int类型,如果右侧赋值超出int范围,需要做转型处理
2.byte,short,char 三种比int小的整数,在自身范围内可以直接赋值。 byte d=1+3 正确,1+3编译器会自动转成4
3.浮点数字面值是double;浮点数转成整数会直接舍弃小数点后位数。
4.字面值后缀,L D F
5.字面值前缀,0b 二进制;0x 16进制;0 8进制; \u char 类型16进制
2.3基本类型的运算规则
1.计算结果的数据类型与运算中的最大类型一致。
2.byte,short,char三种比int小的整数,计算时会自动转成int 做加法运算时,数据类型会自动转成int,除了自增加自减不进行转化外,其它情况都是无long型时,所有非int类型转成int类型;有long类型时,都转成long类型。 char类型相加,提升为int类型。
3.整数运算溢出。Integer.MAX_VALUE+1 得负数最小值
4.浮点数运算不精确
5.浮点数特殊值 infinity 整数除0 ;Nan 负数开方
2.4 基本类型的类型转换
数字类型之间可以互相转换,从小到大自动转换,从大到小需要强制转型。
double d = 245; float d=100;自动转型
2.5运算符
&& :逻辑与(短路与),两边同为真结果才为真,短路与:左边是假,右边忽略不执行
& :不管左边结果是什么都要执行右边(&的左右两边都要参与运算)
|| :逻辑或(短路或),两边只要有一个真结果就是真,短路或:左边是真,右边忽略不执行
3.流程控制
3.1 switch:只能判断byte short char int enum jdk1.7之后的string。
从成立的case 无条件穿透所有的case包括default直到结束或者遇到break中断跳出循环;
如果所有条件都不成立,则执行default
3.2 for循环
3.3 break 和 continue
Break 中断、跳出循环和switch
Continue 跳过后面的代码 继续进入循环的下一轮执行
3.4 for-each循环
数组遍历、集合迭代遍历的语法简化
4.面向对象 —— 封装、继承、多态 ★ ★ ★ ★ ★
封装
1 类:模板、图纸 。类中定义对象的属性数据(成员变量),方法(成员方法)类第一次使用时会加载到方法区
2 对象:从模板中创建的具体实例,实例是数据的打包
新建实例时,在堆内存中新分配内存空间给这个实例
3引用变量:理解成“遥控器”,保存一个实例的内存地址(引用变量保存在栈),引用变量的特殊值:null 不保存任何实例的内存地址
4构造方法:新建实例对象时,立即执行的一个特殊方法;构造方法必须和类同名,并且没有返回值类型。
一个类中必须有构造方法,自己没定义,系统会添加默认构造方法,构造方法一般用来给属性赋值
5 构造方法重载
一个类中可以定义多个不同参数的构造方法,是方法重载的一种体现
6 方法重载Overload:
同名不同参,与返回值类型无关,所有方法都可以重载7 this关键字:this.xxx 特殊引用,引用当前对象的地址
this(…):构造方法之间的调用,必须是首行代码,如果有多个构造方法,会通过this(…)调取下面的所有构造方法,完成赋值。
注意this不能在静态方法中使用
继承
Java的继承是单继承多实现,只能继承一个父类(如果不继承其他类,默认继承object类),但可以实现多个接口
1.不能继承的有:构造方法,私有成员
过程:先新建父类对象,再新建子类对象,两者作为一个整体对象,调用成员时,先找子类,再找父类
2.方法重写:override
继承的方法,在子类中重新定义父类中的方法(只能在子类重写),方法名相同,参数的个数和类型也必须相同,返回值类型也必须相同。
方法重写返回值类型如果是基本类型应与父类的一致;重写要求方法名完全相同,返回值类型如果是基本类型或无返回值时必须一致。
3.父类的构造方法
新建子类对象时会先新建父类对象,也会先执行父类的构造方法
默认执行父类的无参构造,默认隐含调用super();
new Student() 默认执行父类无参构造
new Student(……)默认执行父类无参构造
手动调用父类的有参构造,super(参数):父类没有无参构造时必须手动调用
4.super
Super.xxxx() 方法重写时,调用父类中同一个方法的代码
Super(参数) 调用父类的构造方法,默认调用父类无参构造super(),手动调用有参构造super(),必须是首行代码
注意super不能在静态方法中使用
多态
一个对象具有多种形态的表现,多态的前提是必须有继承。
void f(父类型 o1) { }
把一个子类型的实例当做父类型来处理,所有的子类型都可以传递到该方法,被当做父类型处理;作用:一致的类型
1. 类型的转换
A. 向上转型
子类的实例转成父类型,用父类型的引用变量,来引用子类实例,向上转型后,只能调用父类定义的通用成员,子类特有成员被隐藏
B. 向下转型
已经转成父类型的子类实例,转回子类型为了对子类型进行特殊处理
2. Instanceof 运行期类型识别
当多种子类型都被当做父类型来处理,要对某种子类型进行特殊处理,可以先判断其真实类型再向下转型——对真实类型,及其父类型判断,都返回true。格式:
s instanceof Line
5.数组
属于object类,用来存放一组数据的数据结构,数组是最基本的一种数据结构但不是基本数据类型,数组是相同数据类型组成的集合,数组中的元素按线性顺序排序
1 数组的创建
数组创建后若未指定初始值,则会依据数组类型的不同来设置默认值
int[] a = new int[6]; // 新建int[]数组,长度6,默认值都是0,数组的起始地址值保存在变量a。 int[] a = {6,2,6,8}; Int[] a= new int[]{1,2,3,4,5}; a = new int[]{7,3,8,1,7,9,3,1}; // 为存在的数组变量赋值直接初始化数据,要添加数据类型
2 数组的长度属性 a.length
数组一旦创立,长度不可变
最大下标 a.length-1
允许0长度的数组
3 二维数组
存放数组的数组
int[][] a = new int[3][2];
外围长度为3,内部3个数组长度为2,一共有4个数组,内部数组默认值0,外围数组保存的是内部数组的地址。
int[][] a = new int[3][];
只建一个外围数组长度3,3个位置都是null,之后可以建新数组放入内部。
4 Arrays 数组工具类
Arrays.toString //(数组) 把数组数据连接成字符串。 Arrays.sort //(数组) 数组排序 基本类型:优化的快速排序;引用类型:优化的合并排序。 Arrays.binarySearch //(数组,目标值) 二分法查找,在有序数组中查找目标值下标,找不到返回 -(插入点+1)。 Arrays.copyof // (数组,长度) 复制数组成一个指定长度的新数组。
5 数组 复制
Arrays.copyof // (数组,长度) 复制数组成一个指定长度的新数组 System.arraycopy // (原数组,原数组起始位置,目标数组,目标数组起始位置,复制的数量) ——不会创建新的数组,目标数组要事先存在。
6. 变量
// 1 局部变量:定义在方法中或局部代码块中,必须初始化(第一次赋值时分配内存空间) // 局部变量的作用域在定义它的大括号内有效,在作用范围内不能重复定义。 // 2 成员变量:定义在类中,自动初始化默认值,访问受访问控制符限制;局部变量可以和成员变量同名。
7.Object类
如果一个类不继承其他类,则默认继承Object类
1.方法
toString() // 获得一个对象的字符串表示。 // Object中的默认实现是:“类名@地址”可在子类中重写toString方法。 equals() // 当前对象与参与对象比较是否相等。 a.equals(b) // Object中的默认实现是比较内存地址。 // this == obj:== // Object中比较内存地址,基本类型默认比较内容值。
8.String 类
String是封装char[] 数组的对象
S =”abcd”
S={-value:[‘a’,’b’,’d’,’g’]}
1.字符串创建
Char[] a ={‘a’,’b’,’c’}; String s = new String(a); >>>简易语法>>> String s = “abcd”
2.字符串的常量池
String s1 = “abcd” // 字符串的字面值写法。第一次使用一个字符串字面值时,会在字符串常量池中新分配内存,再次使用相同字面值时,直接访问常量池中存在的对象,而不会重复创建
3.字符串 中的Equals 和 “==”
// “==”比较内存地址 // Equals 看父类中的方法,object中的默认方法是比较内存地址,String类中重写了父类方法比较的是字符内容。如下说明: char[] a = {'a','b','c','d'}; String s1 = new String(a);//堆中新分配内存 String s2 = "abcd"; //在常量池新分配内存 String s3 = "abcd"; //访问常量池中存在的对象 System.out.println(s1==s2); //false 比较内存地址 System.out.println(s2==s3); //true 比较内存地址 String类中重写了equals方法,方法中比较的是字符内容 System.out.println(s1.equals(s2));//true 比较字符串内容 System.out.println(s2.equals(s3));//true 比较字符串内容
4.字符串不可变且字符串连接效率低,每次连接都会新建字符串对象
5.字符串的常用方法
charAt(i) // 获取指定位置的字符 length() // 字符串长度,字符的数量 indexof() // 找第一个子串出现的初始位置,找不到返回-1 indexof // (子串,start)从执行位置向后找 lastIndexof(子串) // 从后向前找 subString(start) // 截取start到末尾 subString(start,end ) // 截取(start,end )范围 trim() // 去除两端的空白字符 matches() // 用来判断是否匹配正则表达式
6.StringBuilder: 可变的字符序列,封装char[]数组,提供了一组方法,可以对内部封装的字符进行修改,常用来代替字符串做高效的字符串连接
append()// 追加字符内容,内部数组默认初始容量16,放满后翻倍+2; delete(start,end) // 删除区间(start,end); deleteCharAt(i)// 删除指定位置 i; insert(i,内容) // 在指定位置插入内容; insertCharAt(i,字符)// 在指定位置插入单个字符; replace(start,end,内容)// 替换指定范围的内容; // StringBuilder和StringBuffer // StringBuilder:线程不安全,效率高;JDK1.5版本后的新类。 // StringBuffer:线程安全,旧版本的类。
9.正则表达式
一般用来判断用户的输入内容是否符合格式要求
matches()// 字符串的方法,用来判断是否匹配 if(s.matches(regex)) {} split(正则):// 用匹配的子串来拆分字符串 String s = "aaa,bbb,ccc"; String[] a = s.split(",");
replace(正则,子串)替换所有匹配的子串
10.基本类型的包装类
// 把基本类型当做对象来使用 byte – Byte short – Short int – Integer long – Long float – Float double – Double char – Character boolean – Boolean
1. 数字父类Number
// 子类:Byte,Short,Integer,Long,Float,Double,BigDecimal,BigInteger // 取出基本类型值的方法 byteValue(),shortValue(),intValue(),longValue(),floatValue(),doubleValu()
2. Intger类
// 创建Integer对象: a= { value:6} Integer a = new Integer(6); Integer a = Integer.valueOf(6); // Integer 类中存在256个Integer缓存对象,封装-127到128;如果访问指定范围内的值,会访问缓存对象,如果超出范围,会新建对象。
3. Integer类的方法
// 字符串解析成int Integer.parseInt(); Byte.parseByte(); Integer.toBinaryString() // 转成二进制字符串 Integer.toOctalString() // 转成八进制字符串 Integer.toHexString(255) // 转成十六进制字符串
4. BigDcimal和BigInteger 类
BigDcimal精确的浮点数运算
BigInteger 超大的整数运算
创建对象:
BigDecimal bd = BigDecimal.valueOf(2); // 方法: add(BigDecimal bd) subtract(BigDecimal bd) multiply(BigDecimal bd) divide(BigDecimal bd) divide(BigDecimal bd,保留位数,舍入方式) setScale(保留位数,舍入方式)
5. 自动装箱,自动拆箱
// 基本类型值,自动装箱成包装对象 // Integer a = 6; 编译器编译成: Integer a = Integer.valueOf(6); // 自动拆箱(自动拆箱要注意null值) // int i = a; 编译器编译成: int i = a.intValue();
11.抽象类
半成品类,没有完成的类;抽象方法:没有代码,只有方法的定义,抽象类不能创建实例,主要用来被继承。
public abstract void f(); //包含抽象方法的类一定是抽象类 public abstract class A { };
抽象方法的作用:
作为通用方法,在父类中定义;要求子类,必须实现这个方法。
1)抽象类可以有自己的构造方法
2)抽象类可以有具体的方法
3)包含抽象方法的类一定是抽象类,必须使用abstract关键字修饰,这个方法必须由子类来实现。
4)抽象类不能使用new关键字来创建实例
5)当一个类中只要有一个抽象方法,这个类就必须是抽象类
6)抽象类可以定义实例变量和静态变量以及常量
7)抽象类可以再继承抽象类,也可以继承普通的类
12.关键字 final
内存地址不可变,可以修饰常量、类、方法
1. final 常量:值不可变,但引用类型因为保存的是地址,所以内容可以变。
final Point a = new Point(3,4); a.x = 30;//对 a.y = 40;//对
2. final 方法不能在子类重写,但可以被继承。;final不能用于修饰构造方法,父类的private成员方法是不能被子类方法覆盖的,因此private类型的方法默认是final类型的。
3. final 类 不能被继承,没有子类
Static — 静态 共享的数据
静态成员属于类,而不属于实例
静态成员
用类来调用静态成员 Soldier.count
实例成员
用实例来调用实例成员 s1.id
工具方法
Math.Random() Arrays.toString() String.valueOf()
静态方法中不能直接调用实例的成员(非静态),只能用实例调用
class A { public static void main(String[] args) { f();//静态调静态 } static void f() { g();//错,静态不能直接调用非静态 A a = new A(); a.g();//只能用实例调用 } void g(){ } }
静态初始化块
class A { static { // 静态初始化块 // 类被加载时,只执行一次 } }
静态变量保存在方法区类的空间中,只保存一份可以在所有实例中共享的数据
对象的加载过程
加载类
- 1.加载父类,为父类静态变量分配内存 – 后台执行不可见
- 2. 加载子类,为子类静态变量分配内存
- 3. 执行父类静态变量的赋值运算,和静态初始化块
- 4. 执行子类静态变量的赋值运算,和静态初始化块
新建实例
- 5. 新建父类实例,为父类实例变量分配内存
- 6. 新建子类实例,为子类实例变量分配内存
- 7. 执行父类的实例变量赋值运算
- 8. 执行父类的构造方法
- 9. 执行子类的实例变量赋值运算
- 10. 执行子类的构造方法
13.集合
用来存放一组数据的数据结构
数组的缺点: 长度固定 ; 访问方式单一只能下标访问; 前面增删数据操作繁琐
集合的继承结构:
- Collection 是对象集合, Collection 有两个子接口 List 和 Set,
- List 可以通过下标 (1,2…) 来取得值,值可以重复,而 Set 只能通过游标来取值,并且值是不能重复的
- ArrayList , Vector , LinkedList 是 List 的实现类
- ArrayList 是线程不安全的, Vector 是线程安全的,这两个类底层都是由数组实现的
- LinkedList 是线程不安全的,底层是由链表实现的
- Map 是键值对集合
- HashTable 和 HashMap 是 Map 的实现类
- HashTable 是线程安全的,不能存储 null 值
- HashMap 不是线程安全的,可以存储 null 值
ArrayList
数组列表,封装了一个数组,及其操作代码和更便捷的方法,内部数组默认初始容量10 放满后,1.5倍增长
方法
add(数据)— 添加数据;get(int i)—访问指定下标数据; remove(int i)移除指定位置数据,返回被移除的数据; remove(数据)— 找到第一个相等的数据,找到移除并返回true,找不到返回false; size() 元素的数量;iterator() 辅助新建迭代器
效率
访问任意位置效率高,增删数据效率可能降低
LinkedList — 双向链表
方法
和ArrayList有相同的方法
- LinkedList 两端数据操作方法
- addFirst(数据);addLast(数据);getFirst();getLast();removeFisrt()
- removeLast()
- 效率
两端效率高
HashMap — 哈希表、散列表 (面试必问) ★ ★ ★ ★ ★
存放键值对数据,用键来快速定位数据,来提取键对应的值
键:不重复,无序
- Hashmap中的key-value都是储存中entry数组中的
- Hashmap的实现不是同步的,意味着它不是线程安全的
- Hashmap的实例有两个参数影响其性能:初始容量,和加载因子
- 方法
- put(key,value)放入键值对数据,重复的键会覆盖旧值
- get(key)获得键对应的值,键不存在,得到null
- remove(key)移除键值对数据,返回被移除的值
- size()键值对的数量
哈希运算过程
HashMap内部,使用entry[]数组存放数据
- 数组默认初始容量16
- 放满后容量翻倍+2
- key.hashCode()获得键的哈希值
- 用哈希值和数组长度,运算产生下标值 i
- 新建entry对象来封装键值对数据
- Entry对象,放入i 位置
- 如果是空位置,直接放入
- 如果有数据,一次equals()比较是否相等
- 找到相等的,覆盖旧值
- 没有相等的,链表连接在一起
- 负载率、加载因子超过0.75
- 新建翻倍容量的新数组
- 所有数据,重新执行哈希值,存入新数组
- Jdk 1.8
- 链表长度到8,转成红黑树
- 树上的数据减少到6,转回成链表
hashCode()
hashCode()是object的方法,默认实现是用内存地址作为哈希值
可以重写方法来获得相同的哈希值
哈希运算中要有相同的哈希值,才能保证计算出相同下标值,并且要equals()也要相等(equals方法也要重写),才可以覆盖旧值,否则会链表连接。
重写hashCode的惯用算法:(x.y是变量的值)
14.异常
封装错误信息的对象
错误信息:类型、提示消息、行号
异常的继承结构
捕获异常
try { } catch(AException e) { } catch(BException e) { } catch(父类型Exception e) { } finally { // 不管出不出错,都会执行 }
如果抛出异常,并且中catch中有return语句,这个return语句会先执行,执行之后将结果保
存在缓存中,再去查看是否有finally,如果有finally就先执行finally语句,之后再返回缓存中
return的值,如果finally中也有return,那么finally中的return会覆盖掉之前缓存中的return,
即最终会返回finally中的return值
throw 手动抛出异常,执行异常的抛出动作 类似 return;当程序出现逻辑错误,不自动创建并抛出异常,可以手动判断逻辑错误,手动创建异常对象并抛出。
底层的异常往上层抛,在上层处理
if(...) { AException e = new AException(); throw e; }
异常包装
- 捕获的异常对象,包装成其他类型再做抛出,多种类型简化成一种类型,不能抛出的异常包装成能抛出的异常再抛。
- RuntimeException 和 其他Exception
- RuntimeException— 非检查异常,编译器不检查是否有异常处理代码,存在默认的抛出管道
- 其他异常 — 编译器检查是否有处理代码,不处理,不能编译。
15.接口
极端的抽象类,结构设计工具,用来解耦合,隔离现实
Implements代替extends
Interface 代替class
接口的定义:
公开的抽象方法 公开的常量 公开的内部类、内部接口
- 1)接口只能定义常量
- 2)接口只能定义抽象方法
- 3)接口只能继承接口,不能继承普通的类和抽象类
- 4)接口是没有构造方法
注意:
- 1)在接口中定义常量时,可以不用final static修饰,因为编译器在编译时会自动加上。
- 2)在接口中定义抽象方法时可以省略abstract关键字,编译器在编译时同样会加上。
类可以同时继承多个接口
class A implements X,Y,Z {} class A extends B implements X,Y,Z {}
接口和接口的继承
interface A extends X,Y,Z {}
16.文件、字符操作流
File
封装一个磁盘路径字符串,提供了一组对文件、文件夹的操作方法,可以封装文件夹路径、文件路径、不存在的路径。 {path=“d:/abc”}
方法
- getName() 获取文件名
- getPatrent() 获取父目录
- getAbsolutePath()完整路径
- length() 文件字节量,对文件夹无效,会返回假数据
- isFile() 判断是否是文件
- isDirectory()是否是文件夹
创建、删除
- createNewFile()新建文件,文件已存在不会新建,返回false;文件夹不存在会出现异常
- mkdirs()逐层创建多层文件夹
- delete()删除文件、空目录
目录列表
- list()得到String[] 包含所有文件名 [“a.txt”, “b.mp3”, “c.jpg”]
- listFiles() 得到 File[],包含所有文件的封装的File对象 [{…}, {…}, {…}]
流 Stream
数据的读写操作(io操作),抽象成数据在管道中流动
单方向流动
- 输入流,只能用来读取数据(读入内存)
- 输出流,只能用来输出数据(内存数据向外输出)
只能从头到尾,顺序流动一次,不能反复流动,如果要重复流动,可以重新创建新的流
InputStream,OutputStream
字节流的抽象父类
方法:
- write(int b) 只输出int四个字节中,末尾的一个字节值 [1][2][3][4] —> [4]
- write(byte[], start, length) 输出byte[] 数组中,从start开始的length个字节值
- read() 读取一个字节值,补三个0字节,变成int [4] —> [1][2][3][4],读取结束后,再读取会返回 -1。
- read(byte[] buff) 按数组的长度,读取一批字节值,存放到指定的数组中,并返回这一批的字节数量,读取结束后,再读取会返回 -1。
- FileInputStream,FileOutputStream — 文件流
- ObjectInputStream,ObjectOutputStream —对象序列化、反序列化
序列化 把一个对象的信息,按固定的字节格式,变成一串字节序列输出
方法:
- writeObject(Object obj) 把对象变成一串字节序列输出
- readObject() 读取序列化数据,反序列化恢复对象
- Serializable 接口——被序列化的对象,必须实现 Serializable 接口
不序列化的变量
Static — 属于类,不随对象被序列化输出
Transient —临时,只在程序运行期间,在内存中存在,不会被序列化持久保存
字符编码
- ASC-II 0到 127,英文、指令字符
- iso-8859-1 Latin-1 西欧编码 ,把ASC-II扩展到255
- CJK 编码 亚洲编码,中日韩
- GBK 国标码 英文单字节,中文双字节
- Unicode 万国码 常用表,双字节 生僻字 三字节或四字节
- UTF-8 Unicode 的传输格式 Unicode Transformation format英文,单字节某些字符,双字节;中文,三字节;特殊符号,四字节
Java的char类型是 Unicode
Java的转码运算
InputStreamReader,OutputStreamWriter
字符编码转换流 OutputStreamWriter — 把Java的Unicode编码字符,转成其他编码输出
InputStreamReader —读取其他编码字符,转成Unicode字符
17.内部类
- 定义在类内部、方法内部或局部代码块内部的类,用来辅助外部实例运算,封装局部数据,或局部的运算逻辑。
- 非静态内部类、属于实例的内部类 非静态内部类实例,必须依赖于一个外部类的实例才能存在。
- 静态内部类 静态内部类,与普通的类没有区别。
- 局部内部类
- 局部定义的类型,类似于局部变量,有作用范围,只能在局部代码块内使用这种类型
局部内部类中,使用外面的局部变量,必须加 final,jdk1.8,缺省。
匿名内部类
Weapon w = new Weapon() {...}; //{} - 匿名类 //new - 新建匿名类的实例 // Weapon - 父类型 // () - super(),可传参数super(1,2,3)
18.Java内存管理
堆内存 用来存放由new创建的对象实例和数组。Java堆是所有线程共享的一块内存区域,在虚拟机启动时创建,此内存区域的唯一目的就是存放对象实例。注意创建出来的对象只包含属于各自的成员变量,并不包括成员方法。
栈内存 保存的是堆内存空间的访问地址,或者说栈中的变量指向堆内存中的变量(Java中的指针)
l 栈:保存局部变量的值,包括:1.用来保存基本数据类型的值;2.保存类的实例,即堆区对象的引用(指针)。也可以用来保存加载方法时的帧。常量池存在于堆中(1.7b后的新版本)。
普通类型的变量在栈中直接保存它所对应的值,而引用类型的变量保存的是一个指向堆区的指针,通过这个指针,就可以找到这个实例在堆区对应的对象。因此,普通类型变量只在栈区占用一块内存,而引用类型变量要在栈区和堆区各占一块内存。
方法区是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
19.线程
在进程内部,并行执行的任务
创建线程(两种方式)
- 继承 Thread
- 实现 Runnable
继承 Thread
编写 Thread 的子类,并重写 run() 方法。启动之后,自动运行 run() 方法中的代码
实现 Runnable
实现 Runnable 接口,实现它的 run() 方法,Runnable 封装在线程中执行的代码,新建线程对象时,把Runnable对象放在线程内,启动
线程的状态
线程的方法
- Thread.currentThread() 获得正在执行的线程实例
- Thread.sleep(毫秒值) 让正在执行的线程,暂停指定的毫秒值时长
- getName(),setName() 线程名
- start() 启动线程 interrupt() 打断线程的暂停状态
- join() 当前线程暂停,等待被调用的线程结束
- setDaemon(true) 后台线程、守护线程
JVM虚拟机退出条件,是所有前台线程结束,当所有前台线程结束,虚拟机会自动退出
不会等待后台线程结束 例如:垃圾回收器是一个后台线程。
线程同步 synchronized
让多个线程共享访问数据时,步调一致的执行。一个线程修改时,其他线程等待修改完成后才能执行;一个线程访问时,其他线程等待访问结束
任何实例,都有一个“同步锁”,synchronized 关键字,要求一个线程必须抢到同步锁才能执行
synchronized(对象) { // 共享的数据访问代码 } // --抢对象的锁 synchronized void f() { } // -- 抢当前实例的锁 static synchronized void f() { }// --抢类的锁
生产者、消费者模型
线程之间传递数据
等待和通知方法必须在synchronized 代码内调用, 等待和通知的对象,必须是加锁的对象。