Java基础提升高级API—百知教育java基础学习3
https://www.bilibili.com/video/BV1pE41137JY
函数接口回调 — todo day10



目录
P1-Object类 15:41
P2-Object类中的方法-1 1:08:32
P3-Object类中的方法-2 55:06
P4-包装类 49:17
P5-Object类习题课 45:36
P6-日期处理 24:56
P7-String类的用法 1:04:47
P8-String习题课 25:58
P9-字符串常量池 1:04:48
P10-集合的概念 48:30
P11-List的常用方法 35:27
P12-List的四种遍历方式 1:13:15
P13-泛型 45:57
P14-List的实现类 33:44
P15-Set集合 1:23:26
P16-Map集合 1:14:55
P17-集合习题课 1:01:16
P18-JDK5中的语法 44:22
P19-异常的分类 1:08:31
P20-异常的产生和传递 23:56
P21-声明抛出异常 55:41
P22-捕获异常 1:05:23
P23-IO流的分类 43:34
P24-字节流-1 25:39
P25-字节流-2 34:57
P26-缓冲字节流 1:16:22
P27-对象序列化 40:25
P28-对象的克隆 1:04:49
P29-字符编码与乱码问题 1:12:26
P30-字符流 33:46
P31-File类 20:06
P32-IO习题课 42:45
P33-多线程的基本编程 1:01:23
P34-线程的基本状态 35:57
P35-线程的阻塞 22:40
P36-线程池 1:01:04
P37-Callable和Future接口 54:46
P38-多线程的同步 1:06:12
P39-同步代码块 58:42
P40-同步方法 11:13
P41-线程安全的集合 50:24
P42-队列接口 31:51
P43-死锁问题 28:59
P44-类对象 56:58
P45-反射的应用 1:08:47
P46-单例设计模式 55:02
P47-工厂设计模式 42:55
类和包装类
P1-Object类 15:41
Object类,所有类的父类
如果一个类没有指定父类,默认继承Object类
Object o = 任何对象
Object o != 8种基本类型(byte short int long float double char boolean)
Object 类中定义的方法,是所有java对象都具有的方法 (public protected)
P2-Object类中的方法-1 1:08:32
P3-Object类中的方法-2 55:06

| 方法名 | 作用 | 备注 |
|---|---|---|
| getClass() | 获得对象的实际类型 | o1.getClass()=o2.getClass(); 判断类型是否相同 |
| finalize() | 在对象被垃圾回收时调用 | 没有典型的使用场景 |
| toString() | 返回对象的字符串形式 | System.out.println(o); 等于System.out.pringln(o.toSTring()); |
| equals | 判断两个对象的内容是否相同 | o1.equals(o2) 判断o1和o2内容是否相同 |
垃圾自动收集:由JVM的垃圾收集器自动回收垃圾对象,释放对象的堆空间
问:什么对象被认为是垃圾对象?
答:零引用算法 如果一个对象,没有任何对象引用它,就判断它是垃圾
问: 垃圾对象何时被回收?
答:不得不回收时候,才回收(全家人一起吃饭,刷碗要等到所有人吃完饭以后一起刷,不会一个人吃饭饭后,刷一个碗)
问:finalize() 具体作用?
答: 没有什么作用
JVM规范
JVM产品
System.gc(); //呼吁垃圾回收器,开始收集垃圾
toString()
返回对象的字符串形式
打印一个对象,就是打印这个对象toString()方法的返回值String
可以在子类覆盖toString();方法
== 用在引用类型时候判断地址是否相同
equals 判断内容是否相同 s1.equals(s2) 说明s1 s2 内容相同
object类中的equals方法,依然比较两个对象的地址
getClass() 获得对象实际类型
instanceof 判断对象是不是某一类型 a instanceof Animal ; a instance of Dog ;
equals 标准写法
public boolean equals(Object o){
// 是否同一个对象
// 是否非Null
// 是否同一类
// 强转
// 属性比较
}
//this vs o 比较内容
public boolean equals(Object o){
//1 判断 this o 是不是同一对象 ,你媳妇 和你孩子他妈
if(this == o ) return true;
//2 判断o 是不是Null
if(o ==null) return false;
//3 判断this o 是不是属于同一个类
if(this.getClass() != o.getClass()) return false;
// 4 对o 做强制类型转化,变为 Employee 类型
Employee e =(Employee) o;
// 5 逐个比较属性 基本类型用 == 引用类型 用equals
if(this.age == e.age && this.name.equals(e.name)) {
return true;
}else{
return false;
}
}
P4-包装类 49:17
Object o= 任何对象
Object o =10; error
为8中基本数据类型 各自提供一个类(8个类,是8个基本类型的对象形式)
所有的基本数据类型就有了对应的对象形式
int ---- > Integer
| 基本类型 | 对应的包装类 |
|---|---|
| int | Integer |
| char | Charactor |
| byte | Byte |
| short | Short |
| long | Long |
| float | Float |
| double | Double |
| boolean | Boolean |
- 基本类型 与 包装类之间的转换
int — > Integer
Integer.valueOf(i); 获得一个Integer对象
Integer内部会预先创建 -128 ~ 127 256个对象,如果在此区间不会创建新对象
Integer —> int
a.intValue();
从jdk5开始,编译器帮助我们,自动封箱、自动拆箱 ;
虚拟机还是会区分,什么是基本类型 ,什么是 对象(包装类) ; - 基本类型与String之间的转换 (这块用的多 )
int ----> String
int i=12; String s=i+“”;
String s =String.valueof(i);
String----> int
String s=“123456”; int i=Integer.ParseInt(s); - 包装类与String之间的转换
Integer ----> String
Integer a=1234; String s = a.toString(); //是对象所以有Object的toString()方法 ;
String ----> Integer
String s =“1234”; Integer a =Integer.valueof(s);
P5-Object类习题课 45:36
修饰符总结
| 表格 | 类 | 方法 | 构造方法 | 成员变量 | 局部变量 | 初始代码块 | 成员内部类 |
|---|---|---|---|---|---|---|---|
| private | √ | √ | √ | √ | |||
| 默认 | √ | √ | √ | √ | √ | ||
| protected | √ | √ | √ | √ | |||
| public | √ | √ | √ | √ | √ | ||
| static | √ | √ | √ | √ | |||
| final | √ | √ | √ | √ | |||
| abstract | √ | √ |

System.out.println("=================================");
int a1=new Integer(128);
int a2=new Integer(128);
System.out.println(a1== a2); //true 比较的是值 所以 true
Integer integer1 = Integer.valueOf(a1);
Integer integer2 = Integer.valueOf(a2); //a1 a2 都不影响结果
System.out.println(integer1==integer2); //false 比较的是对象 且128 不在-128~127 需要单独创建
Integer int1=new Integer(120);
Integer int2=new Integer(120);
System.out.println(int1==int2); //false 比较对象
Integer integer11 = Integer.valueOf(int1);
Integer integer12 = Integer.valueOf(int2);//int1 int2 都不影响结果
System.out.println(integer11==integer12); //true 在-128~127 无需单独创建
Integer int3 = new Integer(128);
Integer int4 = new Integer(128);
System.out.println(int3==int4); //false 比较对象
System.out.println("=================================");
P6-日期处理 24:56
package day16;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
/**
* @author leowei
* @date 2020/12/29 - 13:40
*/
public class TestCalendar {
public static void main(String[] args) {
// *******
long timeNowLong = System.currentTimeMillis(); // 距离 1970 年 的毫秒数
System.out.println("timeNow = " + timeNowLong);
// *******
// Calendar c = Calendar.getInstance();
Calendar c = Calendar.getInstance(Locale.FRANCE); //
Date timeNow = c.getTime();
System.out.println("timeNow = " + timeNow);
// *******
c.setTimeInMillis(timeNowLong);
int year = c.get(Calendar.YEAR);
int dayM = c.get(Calendar.DAY_OF_MONTH);
int dayY = c.get(Calendar.DAY_OF_YEAR);
int dayW = c.get(Calendar.DAY_OF_WEEK);
int daySpe =c.getFirstDayOfWeek();
System.out.println("dayW: " + dayW+ " ; dayMonth:"+ dayM + "; dayYear:"+ dayY + " ; year: "+ year +"; firstDayofWeek:"+ daySpe);
//dayW: 3 ; dayMonth:29; dayYear:364 ; year: 2020; firstDayofWeek:1
// *******
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formatTime = sdf.format(timeNow);
System.out.println("formatTime = " + formatTime);
}
}
P7-String类的用法 1:04:47
凡是没有数值含义的数字,一定不要把它当数值类型。
字符串中的常用方法
- 与字符数组相关操作
String(char[] cs) 利用字符数组构造字符串
toCharArray() 把字符串转字符数组 - 基础方法
toUpperCase()
toLowerCase()
charAt(int index)
length()
trim();
equals();
equalsIgnoreCase();//忽略大小写比较,使用场景 验证码 - 与子串相关
contains(String str)
indexof(String str)
indexof(String str,int fromIndex);
substring(int fromIndex)
substring(int fromIndex,int endIndex);
replace(string str1,string str2)
split(String str); str作为分隔符,将字符串切割为String[]
P8-String习题课 25:58
1.判断一个字符串是否为 回文 字符串 abcdcba --》 abcdcba
2. 在一个字符串“ABCDIFGABC234BC23432BAC2343ABCD”中找出所有的“BC”字符串
private static boolean huiwen03() {
String strInput="abcdefggfedcba"; //abcdcba abcba abba 都可以
for(int i=0;i< strInput.length()/2; i++){
if(strInput.charAt(i)!=strInput.charAt(strInput.length()-1-i)) return false;
}
return true;
}
private static void AllIndexOf(String s,String str){
int start=0;
while(true){
int indexOf = s.indexOf(str, start);
if(indexOf==-1) break;
System.out.println(indexOf);
start = indexOf + str.length();
}
}
P9-字符串常量池 1:04:48
串池,与 StringBuilder
一个String对象的内容是不可以改变的,因此多个引用可以指向同一个字符创对象。-----这句话体会一下串池的概念
当字符串的内容发生改变时候,只会创建新对象
虚拟机存储空间 :堆 栈 方法区
串池:字符串常量池 ,用来存放字符串对象,以供多个引用共享(通常存放在方法区)


public interface CharSequence {

package day14;
/**
* @author leowei
* @date 2020/12/29 - 15:27
*/
public class TestStringAppend {
public static void main(String[] args) {
String s1="ABC";
String s2="ABC";
System.out.println("s1 = s2 :" + s1== s2); //false why???
System.out.println("s1 = s2 :" + (s1== s2)); //true
System.out.println("s1.equals(s2) = " + s1.equals(s2)); //true
System.out.println("s2.equals(s1) = " + s2.equals(s1)); //true
String s3=new String("ABC");
String s4=new String("ABC");
System.out.println("s3==s4 = " + (s3 == s4)); //false
}
}
集合
P10-集合的概念 48:30
集合: 用来存储对象的对象叫做集合-----容器
object[] 数组,最基础的集合
数组是一种基础集合,数组存在如下弊端
1.数组长度固定,数组扩充是需要复杂的拷贝操作
2.数组元素在插入,删除时候不方便
Object[] o={"ABC","DEF","XYZ"}; 要插入LMN 到数组第一个位置
Object[] o={"ABC","DEF","XYZ",null,null,null}; -- step1 扩容
Object[] o={"ABC","DEF","XYZ","XYZ",null,null}; --- step2 挪动
Object[] o={"ABC","DEF","DEF","XYZ",null,null};--- step3 挪动
Object[] o={"ABC","ABC","DEF","XYZ",null,null};--- step4 挪动
Object[] o={"LMN","ABC","DEF","XYZ",null,null}; --- step5 插入

// 自定义List 类
package day14.day15;
import java.util.Objects;
/**
* @author leowei
* @date 2020/12/29 - 16:18
*/
public class TestList {
public static void main(String[] args) {
MyList list = new MyList();
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
list.add("gousheng"); //大于三个自动扩容
list.add("xiaoli");
list.add(0,"huhu");
for(int i=0;i<list.size();i++){
Object o = list.get(i);
System.out.println("o = " + o);
}
/*
o = huhu o = zhangsan o = lisi
o = wangwu o = gousheng o = xiaoli
* */
}
}
class MyList{
private Object[] os =new Object[3];
private int index; //数组中有效元素的个数,也是元素下标范围 0 - index-1 ;
//添加到元素末尾
public void add(Object o){
if(os.length==index){
expand();
}
os[index]=o;
index++;
}
//添加元素到指定pos下标
public void add(int pos,Object o){
if(os.length==index){
expand();
}
for(int i=index;i>pos;i--){
os[i]=os[i-1];
}
os[pos]=o;
index++;
}
//数组扩容 2 倍
public void expand(){
Object[] os2 = new Object[os.length * 2];
for(int i=0;i<os.length;i++){
os2[i]=os[i];
}
os=os2;
}
public int size(){
return index;
}
public Object get(int pos){
return os[pos];
}
}
P11-List的常用方法 35:27

| collection 方法 | 说明 |
|---|---|
| add(Object o) | 把对象放入当前集合 |
| AddAll(Collection c) | |
| Clear() | 清空集合 |
| contains(Object o) | 判断集合中是否存在o |
| remove(Object o) | 00 |
| size() | 00 |
| forEach() | 遍历当前集合 |
| toArray() | 将当前集合转换为Object[] |
| -----list方法-------- | ---------------- |
| add(int pos,Object o) | 将元素插入到当前集合的pos下标上 |
| get(int pos ) | |
| indexOf(Object o) | |
| remove(int pos) | 删除集合中pos位置的元素 |
| set(int pos,Object o) | 将元素设置到当前集合的pos下标上 |
| map 方法 | 说明 |
|---|---|
| put(K key,V value) | 把 key-value 键值对 放入map ,如果key 已经存在,新value覆盖老value |
| V get(K key) | |
| containsKey(K key) | |
| containsValue(V value) | |
| size() | |
| remove(K key) | |
| keySet | 返回所有键的集合 |
| values | 返回map中所有值的集合 |
集合的组成 java.util 包
----collection----接口
接口特点: 元素是对象(Objet)
常用方法:(见上表 )
遍历: 见下
实现类: 无直接实现类
List Collection 子接口
接口特点: 元素有顺序,有下标 ,可以重复
常用方法:(见上表 )
遍历: (四种) 迭代遍历 for-Each遍历 forEach()自遍历 下标遍历
实现类: ArrayList
Set Collection 子接口
接口特点: 元素无顺序,无下标 ,内容不可以重复
常用方法:(见上表 )
遍历: (三种) 迭代遍历 for-Each遍历 forEach()自遍历
实现类: HashSet LinkedHashSet TreeSet (自动对元素进行排序,根据规则过滤重复元素,极少用)
----map----接口
接口特点: 元素是键值对 Key对象 无顺序,内容不可重复 ; value 对象 可以重复
常用方法:
遍历: 见下
实现类: HashMap 使用Hash算法实现(链表数组,红黑树) 1.2 线程不安全 允许Null作为key 或 value
LinkedHashMap HashMap的子类,维护键值对的添加顺序
TreeMap 自动对键进行排序
HashTable 1.0 线程安全 慢 不允许Null作为key 或 value
Properties Hashtable的子类 用于配置文件
简介: 英汉词典就是 map apple --苹果 (apple 不可以重复)
用户名密码 也是 map username1 -- pwd1 (username不可以重复)
P12-List的四种遍历方式 1:13:15
package day14.day15;
import javax.lang.model.SourceVersion;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Objects;
import java.util.function.Consumer;
/**
* @author leowei
* @date 2020/12/29 - 16:18
*/
public class TestList {
private static String result="";
public static void main(String[] args) {
//原始数据
// MyList list = new MyList(); // 自定义List类
list.add("zhangsan");
list.add("lisi");
list.add("wangwu"
//list 的四种遍历方式
System.out.println("==============下标遍历==================");
//方式一 下标遍历 (可以遍历List 不可以遍历Set ,因为set 没有下标 )
for(int i=0;i<list.size();i++){
Object o = list.get(i);
System.out.println(" o = " + o);
}
//方式二 迭代方式遍历 自jdk1.2 方式出现的迭代方式
System.out.println("===============迭代方式遍历=============");
Iterator it = list.iterator();
while(it.hasNext()){
Object next = it.next();
String s =(String) next;
System.out.println(" s = " + s);
}
//方式三 for-Each 自jdk1.5 方式出现的迭代方式
System.out.println("===========for-Each 遍历 ============");
for(Object o: list){
String s=(String)o;
System.out.println("s = " + s);
}
//方式四 forEach 自遍历 自jdk 8 开始 (有如下三种变形)
System.out.println("===========forEach 自遍历 1 接口回调 ============");
class MyConsumer implements Consumer{
@Override
public void accept(Object o) {
System.out.println(o);
}
}
// 接口回调
list.forEach(new MyConsumer());
System.out.println("===========forEach 自遍历2 匿名内部类 ============");
//方式4.1
list.forEach(new Consumer() {
@Override
public void accept(Object o) {
System.out.println(o);
}
});
System.out.println("===========forEach 自遍历 3 lambda ============");
//方式4.2 lambda 把代码当做参数传递
list.forEach(x-> System.out.println("x = " + x));
// final String result="";//result 外部类的局部变量
// lambda 中不能改变 外部类的局部变量
// lambda 访问外部类的局部变量的时候默认增加 final ,final 限定不可以改值,所以要将result放到外部,作为成员变量,供lambda表达式访问
System.out.println("===========番外: forEach 使用成员变量 ============");
list.forEach(x-> result+=x );
System.out.println("result = " + result);
}
}
P13-泛型 JDK 5 45:57
集合中存储的是对象,无法对元素的类型做出约定----类型不安全
List list = new ArrayList();
list.add(对象);
Object o =list.get(0);
String[]
Int[] --------------------数组是安全的,类型确定
JDK1.5 开始使用泛型 ,利用泛型,可以约定集合中元素的类型。
interface A{
void m1(String s);
Interger m2();
}
// 1.5 以后
interface A<T> {
void m1(T s);
}
class B implates A<String>{
public void m1(String){}
}
// 1.5 以后
interface A<T,V> {
void m1(T s);
V m2();
}
class B implements A<String,Integer>{
public void m1(String s){}
public Integer m2{ return 0; }
}
class C implements A<Double,String>{
public void m1(Double d){}
public String m2{ return ""; }
}
// E 约束了集合中元素的类型
interface List <E>{
void add(E o);
E get(int pos);
}
P14-List的实现类 33:44
不同的 list 实现类之间的区别是什么?
散列表: 分散排列
ArrayList (线程不安全,高效) 数组实现 --- 查询快 增删慢 ----- JDK1.2 (1998年)
LinkedList 链表实现 --- 查询慢 增删快
Vector (线程安全,低效) 数组实现 ----- JDK1.0 (1995年)
HashSet 散列表 --- 查询块 增删快
P15-Set集合 1:23:26
https://www.bilibili.com/video/BV1pE41137JY?p=15
看下图,散列表有很多的无效空间,散列表 查询也快,插入也快,是典型的用空间换时间的方式。
先看Hashcode ,hashcode 相同,再比较equals

Set 无下标,无序,不可以重复
(三种) 迭代遍历 for-Each遍历 forEach()自遍历
HashSet 底层 还是数组 ,具体的叫法是 链表数组
如果将自定义的对象放入HashSet ,为了保证元素内容不重复
1.)覆盖hashCode方法,保证内容相同的对象返回相同的整数
2.)覆盖equals方法,保证内容相同的对象返回true
3.)尽量保证不同对象,返回不同hashcode
P16-Map集合 1:14:55
https://www.bilibili.com/video/BV1pE41137JY?p=16

P17-集合习题课 1:01:16
P18-JDK5中的语法 44:22
1.静态引入
2. 可变长参数
//a: 0-n个参数
// 可变长参数相当于数组参数,int... a 相当于 int[] a
// 一个函数的参数表中,只能有一个可边长参数,且必须是参数表的最后一个参数
static void fn(int ... a){ //等同于 static void fn(int[] a){ }
for (int i:a){
System.out.println(i);
}
}
3 标注
// 普通注释: 给人看的
// 标注: 描述代码的代码 给机器看的
// 标注使用场景:
// 用在 包、类、属性、方法、构造函数等程序组件声明之前
//@标注名(属性1=值1,... 属性n=值n);
// 标记标注 没有属性 ()可以省略 @Override
// 单值标注 只有一个属性 如果属性名为value ,value 可以省略 直接写 @标注名(值)
// 普通标注 有属性
4. 格式化输出 printf
public static void main(String[] args) {
String name ="llll";
int age=40;
// 格式化输出
System.out.printf("Student nam=%s,age=%d",name,age); //printf 占位符
}
5. 泛型
6. 自动封箱 装箱
7. 枚举
异常
P19-异常的分类 1:08:31
Throwable/Exception/RuntimeException/ … 继承这个包的类,为检查异常,可以通过人工确认,避免异常发生的 。
避免异常: 尽可能使异常不出现,不发生
处理异常: 当异常发生时,应对这种情况 有部分代码,正常情况不执行,异常发生时候才执行
异常的分类
Throwable 所有异常的父类
Error 错误 严重的底层错误 不可避免 无法处理
Exception 异常 可以处理的
RuntimeException 子类 运行时异常 (编译器)未检查异常 可以避免 (可以处理,可以不处理,如人为的火灾 )
非RuntimeException 子类 (编译器)已检查异常 不可避免 (必须处理, 如地址 )
if(a!=null) a.method(); //避免 NullPointerException
if(i>=0 && i<a.lentgh) System.out.println(a[i]); 避免ArrayIndexoutofBoundsException
if(a instanceof Dog) Dog d =(Dog) a; //避免 ClassCastException
//查看以上几个EXCEPTION都是RuntimeException 的子类,都是可以避免的运行时异常 ,

未检查异常

已检查异常



P20-异常的产生和传递 23:56
P21-声明抛出异常 55:41
异常处理方式:
1. 声明抛出 : 此种方式只是转移了异常,并没有真正处理异常
public void method() throws IOException
throws 异常类名1 , 异常类名2 , 异常类名3
方法覆盖时,子类不能比父类抛出更多的异常

2. 捕获异常
try{
语句1
语句2
语句…
语句n
}
catch(异常引用1 e){
}
catch(异常引用2 e){
}
catch(异常引用3 e){
}

package day18;
import java.io.EOFException;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* @author leowei
* @date 2020/12/30 - 9:42
* main ---- 总理
* mProvince --- 省长
* mCity ---- 市长
* mVillage ---- 村长
*/
public class TestException {
public static void main(String[] args) throws Throwable {
System.out.println("main 1 ------------------");
mProvince(2);
System.out.println("main 2 ------------------");
System.out.println("main 3 ------------------");
}
// 省长
static void mProvince(int i) throws Exception {
System.out.println("ma 1 =========");
mCity(i);
System.out.println("ma 2 =========");
System.out.println("ma 3 =========");
}
//市长
static void mCity(int i) throws IOException,MyException{
System.out.println("mb 1 ~~~~");
mVillage(i);
System.out.println("mb 2 ~~~~");
System.out.println("mb 3 ~~~~");
}
//村长
static void mVillage(int i) throws EOFException,FileNotFoundException,MyException {
System.out.println("mc 1");
if (i == 0) throw new NullPointerException("模拟空指针异常,夫妻吵架,村长处理");
if (i == 1) throw new EOFException("EOF 文件以外终止,旱灾 村长不处理,报告县长");
if (i == 2) throw new FileNotFoundException("文件没有找到,洪灾 村长不处理,报告县长");
if (i == 3) throw new MyException("我自己定义的异常 ,遇到疫情 村长不处理,报告县长");
System.out.println("mc 2");
System.out.println("mc 3");
}
}
//自定义异常类
class MyException extends Exception{
public MyException(){}
public MyException(String msg){
super(msg);
}
}
P22-捕获异常 1:05:23
try{} catch(){}
try{} catch(){} finally {}
try{} finally {}

package day18;
/**
* @author leowei
* @date 2020/12/30 - 12:15
*/
public class TestFinally {
public static void main(String[] args) {
System.out.println(fn(2)); //结果 2 不管错还是对 都执行 finnally 的语句
System.out.println("---------------------------------");
System.out.println(fn(0)); //结果 2 不管错还是对 都执行 finnally 的语句
}
static int fn(int n){
try {
int a=6/n;
return a;
} catch (Exception e) {
e.printStackTrace();
return 0;
} finally {
return 2;
}
}
}
IO
P23-IO流的分类 43:34
Java程序的输入和输出
流对象(Stream): 用来传输数据的对象
流的分类:3中分类方式
方式1:按照流的方向
-------输入流:读数据
-------输出流 :写数据
方式2:数据单位
-------字节流:以字节为单位串数据, 可以处理一切数据
------- 字符流:以字符为单位串数据 , 专门用于处理文本数据(.txt .html .java .xml)
方式3: 流的功能
-------节点流:实际负责数据传输
-------过滤流:为节点流增强功能


P24-字节流-1 25:39
java.io.InputStream / OutputStream 是个抽象类 所有字节流的父类
*****InputStream,*****OutputStream ,父类作为子类的后缀
FileInputStream,FileOutputStream 文件字节流
在这里插入代码片
P25-字节流-2 34:57
标准处理FileOutoutStream流的方式
package day19;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* @author leowei
* @date 2020/12/30 - 14:45
*/
public class TestOutputStream2 {
public static void main(String[] args) {
OutputStream os=null;
try {
os =new FileOutputStream("a.txt");
os.write('D');
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(os!=null){
os.close();//关闭流
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
try-with-resource jdk 1.7 开始
try( 实现 AutoCloseable接口的 资源 ){}
catch(Exception e){}
//关闭资源 无需程序员关注了
// 用下面的语句替换上面的语句
//放入 try 块的所有资源必须实现 AutoCloseable接口
try(OutputStream os=new FileOutputStream("a.txt")) {
os.write('D');
}catch(IOException e){
e.printStackTrace();
}
package day19;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* @author leowei
* @date 2020/12/30 - 15:02
*/
public class TestInputStream {
public static void main(String[] args) throws Exception {
m1();
return;
}
// throw exception 的写法
private static void m1() throws IOException {
InputStream is = new FileInputStream("a.txt");
//int read = is.read(); //从文件中读一个字节,返回值就是字节对应的数字 (A --> 65 )
while (true){
int a= is.read();
if(a==-1){
break;
}
System.out.println("a = " + a);
System.out.println("change type a is " + (char)a);
}
is.close();
}
// try-with-resource 写法 (自 jdk 1.7 开始 )
private static void m2() {
try( InputStream inputStream = new FileInputStream("a.txt")){
while (true){
int a= inputStream.read();
if(a ==-1){
break;
}
System.out.println("change type a is " + (char)a);
System.out.println("a = " + a);
}
}catch (IOException e){
e.printStackTrace();
}
}
}
P26-缓冲字节流 1:16:22
BufferedInputStream / BufferedOutputStream 过滤流
缓冲功能,提高IO 效率
IO 编程基本顺序
1.创建节点流
2.封装过滤流
3.读写数据
4.关闭外层流
FileOutputStream fos = new FileOutputStream("a.txt");
BufferedOutputStream out = new BufferedOutputStream(fos);
out.write('A');
out.close();

package day19;
import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @author leowei
* @date 2020/12/30 - 15:53
*/
public class TestBufferedStream {
public static void main(String[] args) throws IOException {
// m1();
m2();
}
// 缓冲流 标准 写法
private static void m1() throws IOException {
FileOutputStream fos = new FileOutputStream("a.txt");
BufferedOutputStream out = new BufferedOutputStream(fos);
out.write('A');
out.write('B');
out.write('C');
out.write('D');
out.flush(); //清空缓冲区, 不关闭流
//out.close(); //关闭 BufferedOutputStream 自动 关闭 其包装的 FileOutputStream
}
// 缓冲流 Jdk 1.7 后的 try-with-resource 写法
private static void m2() {
try (FileOutputStream fos = new FileOutputStream("a.txt");
BufferedOutputStream out = new BufferedOutputStream(fos);
) {
out.write('A');
out.write('B');
out.write('C');
out.write('D');
out.flush(); //清空缓冲区, 不关闭流
//out.close(); //关闭 BufferedOutputStream 自动 关闭 其包装的 FileOutputStream
} catch (Exception e) {
e.printStackTrace();
}
}
}
P27-对象序列化 40:25
ObjectOutputStream / ObjectInputStream 对象流 过滤流
对象序列化: 把对象通过流来传输
只有实现了 java.io.serializable 这个接口,才能实现序列化
用transient修饰的属性成为临时属性,不参加序列化


package day19;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* @author leowei
* @date 2020/12/30 - 16:42
*/
public class TestObjectStream {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Employee e = new Employee("lichao", 44);
FileOutputStream fos = new FileOutputStream("a.data"); // 1. 创建节点流
ObjectOutputStream oos =new ObjectOutputStream(fos); // 2. 创建过滤流
oos.writeObject(e); // 3. 写数据
oos.close(); // 4. 关闭节点
System.out.println("ok");
FileInputStream fis=new FileInputStream("a.data");
ObjectInputStream ois =new ObjectInputStream(fis);
Employee o = (Employee)ois.readObject();
ois.close();
System.out.println(o.getName()+" ---- "+ o.getAge());
// lichao ---- 0
// transient int age; age 使用transient 娶不到值 多以为空
}
}
class Employee implements Serializable{
String name;
transient int age;
//不想让属性参加序列化 -- Transient 临时属性,不参加序列化
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
P28-对象的克隆 1:04:49
透彻的讲 浅拷贝 深拷贝
https://www.bilibili.com/video/BV1pE41137JY?p=28
克隆一个对象: equals 为 true , == 为 false
浅拷贝:需要克隆的类,必须实现Cloneable接口,super.clone() 利用Object类的Clone方法实现
深拷贝:无需实现Cloneable接口
浅拷贝
代码路径: day20.TestClone
https://github.com/wei198621/javaBasic03Apis/blob/main/src/main/java/day20/TestClone.java

浅拷贝代码
浅拷贝: 对象在复制,但是对象内的属性没有复制
//1. 覆盖object类的clone方法,将访问修饰符从Protected提高为public
// 2. 需要克隆的类,必须实现Cloneable接口,
public Object Clone(){
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
package day20;
/**
* @author leowei
* @date 2020/12/30 - 17:45
*/
public class TestClone {
public static void main(String[] args) {
Teacher t = new Teacher("hxz", 44);
Student s = new Student("weilie", 22,t);
System.out.println("s = " + s);
Student s2 =(Student)s.Clone();
System.out.println("s2 = " + s2); //Student implements Cloneable{ 正常clone
System.out.println("s== s2 = " + (s == s2)); // false 不是同一个对象
System.out.println(s.getTeacher()==s2.getTeacher()) ; //true
//System.out.println(s.getName() == s2.getName()); //true
}
}
class Student implements Cloneable{
private String name;
private int age;
private Teacher teacher;
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Teacher getTeacher() {
return teacher;
}
public Student(String name, int age, Teacher teacher) {
this.name = name;
this.age = age;
this.teacher = teacher;
}
// 浅拷贝
//1. 覆盖object类的clone方法,将访问修饰符从Protected提高为public
// 2. 需要克隆的类,必须实现Cloneable接口,
public Object Clone(){
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", teacher=" + teacher +
'}';
}
}
class Teacher{
private String name;
private int age;
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
深拷贝
代码路径: day20.TestCloneDeep
https://github.com/wei198621/javaBasic03Apis/blob/main/src/main/java/day20/TestClone.java

package day20;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* @author leowei
* @date 2020/12/30 - 17:45
*/
public class TestCloneDeep {
public static void main(String[] args) {
Teacher2 t = new Teacher2("hxz", 44);
Student2 s = new Student2("weilie", 22,t);
System.out.println("s = " + s);
//Student2 s2 =(Student2)s.Clone();
Student2 s2 =(Student2)s.ClonePlus();
System.out.println("s2 = " + s2); //Student implements Cloneable{ 正常clone
System.out.println("s== s2 = " + (s == s2)); // false 不是同一个对象
System.out.println(s.getTeacher()==s2.getTeacher()) ; //false
System.out.println(s.getName() == s2.getName()); //false
}
}
class Student2 implements Serializable{
private String name;
private int age;
private Teacher2 teacher;
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Teacher2 getTeacher() {
return teacher;
}
public Student2(String name, int age, Teacher2 teacher) {
this.name = name;
this.age = age;
this.teacher = teacher;
}
// 深拷贝
//1. 当前对象要实现 implements Cloneable ,Serializable 两个接口
public Object Clone() {
//将当前Student对象 放到a.data目录 a.data 在本地,涉及到 虚拟机向本地数据的存储
try (FileOutputStream fos = new FileOutputStream("a.dat");
ObjectOutputStream out = new ObjectOutputStream(fos);) {
out.writeObject(this);
} catch (Exception e) {
}
//将a.data目录数据取出 反序列化到Student对象
try (FileInputStream fis = new FileInputStream("a.dat");
ObjectInputStream in = new ObjectInputStream(fis);) {
Object o = in.readObject();
return o;
} catch (Exception e) {
return null;
}
}
// 深拷贝
//1. 当前对象要实现 implements Cloneable ,Serializable 两个接口
//ByteArrayInputStream ByteArrayOutputStream
public Object ClonePlus() {
//将当前Student对象 byte[] bs bs在虚拟机中,所以很快
byte[] bs =null ;
try ( ByteArrayOutputStream bos =new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);) {
out.writeObject(this);
bs = bos.toByteArray();
} catch (Exception e) {
}
//将byte[] bs 反序列化到Student对象
try ( ByteArrayInputStream bis =new ByteArrayInputStream(bs);
ObjectInputStream in = new ObjectInputStream(bis);) {
Object o = in.readObject();
return o;
} catch (Exception e) {
return null;
}
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", teacher=" + teacher +
'}';
}
}
class Teacher2 implements Serializable{
private String name;
private int age;
public Teacher2(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
P29-字符编码与乱码问题 1:12:26
专门处理char,String 类型的数据,可以方便的处理字符的编解码
不同国家有不同的字符集,不同国家有不同的编码方式,当编码方式和解码方式不统一的时候,会出现乱码。
文字 —> 字符集
‘中’ -----> 10000
‘#’ -----> 10000
编码: 字符 --> 整数的过程 ‘A’–> 65
解码: 整数 --> 字符的过程 65–> ‘A’
常见的编码方式:
- ASCII 美国 字符集:英文字符+特殊字符 英语是世界唯一不会有乱码的语言
- ISO-8859-1 西欧 字符集: 西欧字符集
- GB2312 国标2312 简体中文 此字符集比较小
- GBK 国标2312的扩展
- Big5 繁体中文
- Unicode 全球统一编码方式
-
- UTF-8 ---- 常用的unicode
-
- UTF-16
(知识点: 以后遇到的乱码问题,大半是GBK—UTF-8 之间转换的问题 )
package day20;
import java.io.UnsupportedEncodingException;
/**
* @author leowei
* @date 2020/12/31 - 8:19
*/
public class TestEncodingDecoding {
public static void main(String[] args) throws UnsupportedEncodingException {
String str="xuzhoushijinshanqiaokaofaqu徐州市金山桥开发区11-1号55505室,中关村软件园";
System.out.println(str);
byte[] bytes = str.getBytes("GBK"); //编码 按照GBK方式编码
String strResult1 = new String(bytes,"big5"); //解码 如果不写 jdk 默认 forName("UTF-8");
System.out.println("strResult1 = " + strResult1);
byte[] big5s = strResult1.getBytes("Big5");
String str3 = new String(big5s,"GBK");
System.out.println("str3 = " + str3);
//
}
}

P30-字符流 33:46
流的分类方式1:数据单位
-------字节流:以字节为单位串数据, 可以处理一切数据
------- 字符流:以字符为单位串数据 , 专门用于处理文本数据(.txt .html .java .xml)
流的分类方式1:流的功能
-------节点流:实际负责数据传输
-------过滤流:为节点流增强功能
字节流 java.io.InputStream
-
- InputStream / OutputStream 是个抽象类 所有字节流的父类
-
- FileInputStream,FileOutputStream 文件字节流 节点流
-
- BufferedInputStream / BufferedOutputStream 缓冲字节流 过滤流
-
- ObjectOutputStream / ObjectInputStream 对象流 过滤流
-
- PrintStream 过滤流
字符流 java.io.Reader
-
- Reader/Writer 抽象类 字符流的父类
-
- FileReader/FileWriter 文件字符流 节点流
-
- BufferedReader / BufferedWriter 过滤流 缓冲
-
- PrintWriter 带缓冲的字符输出流,替换BufferedWriter 过滤流 (类似字节流的PrintStream)
-----------特殊类-----------------
-
- InputStreamReader / OutputStreamWriter 把一个字节流构造成一个字符流 ----桥转换类
视频地址:https://www.bilibili.com/video/BV1pE41137JY?p=30
| 项目 | 字节流 | 字符流 | Value |
|---|---|---|---|
| 父 | InputStream/OutputStream | Reader/Writer | |
| 子 | FileInputStream/FileOutputStream | FileReader/FileWriter | 节点流 |
| 孙1 | BufferedInputStream/BufferedOutputStream | BufferedReader/BufferedWriter | 过滤流 |
| 孙2 | PrintStream | PrintWriter | 过滤流 替换孙1 |
| 孙3 | ObjectInputStream/ObjectOutputStream | 过滤流 | |
| 电脑 | 600 | 600 | 600 |
| – | InputStreamReader/OutputStreamWriter | 特殊类 字节转字符 |
把一个字节流构造成一个字符流 ----桥转换类
IO 编程基本顺序
1.创建节点流
2.封装过滤流
3.读写数据
4.关闭外层流
package day20;
import java.io.*;
/**
* @author leowei
* @date 2020/12/31 - 9:12
*/
public class TestReaderWriter {
public static void main(String[] args) throws IOException {
doByZiFu();
doByZiJie();
//平时用 第二种方式
// 如果直接 用 字节流,采用平台默认的编解码方式处理
// 采用字节流转字符流的方式,可以在桥转换类 OutputStreamWriter/InpuStreamReader 中指定字符集
return;
}
//字节方式
private static void doByZiJie() throws IOException {
OutputStream fos=new FileOutputStream("a.txt"); // 文件字节流
Writer fw = new OutputStreamWriter(fos); // (桥转换类)字节流转字符流
PrintWriter out = new PrintWriter(fw); //
out.println("春风杨柳万千条");
out.println("六亿深圳尽舜尧");
out.println("红雨随心翻作浪");
out.println("青山着意化为桥");
out.println("天连五岭银锄落");
out.println("地动三河铁臂摇");
out.println("借问瘟君欲何往");
out.println("纸船明灯照天烧");
out.println("");
out.close();
FileInputStream fis=new FileInputStream("a.txt"); //字节流 节点流
Reader fr = new InputStreamReader(fis); //字节流转 字符流 节点流
BufferedReader in = new BufferedReader(fr); //过滤流 缓冲流
while(true){
String s = in.readLine();
if(s==null) {
break;
}
System.out.println(s);
}
in.close();
}
//字符方式
private static void doByZiFu() throws IOException {
FileWriter fw=new FileWriter("a.txt");
PrintWriter out = new PrintWriter(fw);
out.println("春风杨柳万千条");
out.println("六亿深圳尽舜尧");
out.println("红雨随心翻作浪");
out.println("青山着意化为桥");
out.println("天连五岭银锄落");
out.println("地动三河铁臂摇");
out.println("借问瘟君欲何往");
out.println("纸船明灯照天烧");
out.println("");
out.close();
FileReader fr=new FileReader("a.txt");
BufferedReader in = new BufferedReader(fr);
while(true){
String s = in.readLine();
if(s==null) {
break;
}
System.out.println(s);
}
in.close();
}
}
P31-File类 20:06
P32-IO习题课 42:45
多线程
P33-多线程的基本编程 1:01:23
并发编程 过个任务同时执行
并发原理: CPU分“时间片”交替执行 ,宏观并行,微观串行,由OS负责调度
进程: OS中并发的一个任务,
线程: 在一个进程中,并发的一个顺序执行流程
线程三要素
- CPU OS 负责调度
- 数据 多线程,栈空间独立,堆空间共享
- 代码 为线程编写代码,指派任务 (主线程在main中)
启动线程的方法 1 -
-
- 1 定义类,实现Runnable接口,实现run方法
-
-
-
- 2 主函数中创建Runnable对象(任务对象)
-
-
-
- 3 通过Runnable对象,创建Thread对象(线程对象)
-
-
-
- 4 调用Thread 对象的start方法,启动线程
-
启动线程的方法 2
-
-
- 1 定义类,继承Thread 类,覆盖run方法
-
-
-
- 2 主函数中创建Thread对象(任务对象)
-
-
-
- 3 调用Thread 对象的start方法,启动线程
-

P34-线程的基本状态 35:57


P35-线程的阻塞 22:40


P36-线程池 1:01:04
线程池 JDK5
1.5新增功能: 自动封箱,标注,泛型
1.8 : lambda 表达式
Daug Lea 写了一个多线程的包,放入JDK5包,线程池,用于资源共享,当一个任务结束时,对应的线程资源不会销毁,而是回到线程池中,等待下一个任务
ExecutorService (java.util.concurrent)代表一个线程池

Executors.newFixedThreadPool(n); //获得固定长度的线程池 控制最大并发上限
Executors.newCachedThreadPool(); 获得可变长度线程池,线程数量会随并发任务增长而增多

package day21;
import java.util.concurrent.*;
/**
* @author leowei
* @date 2020/12/31 - 16:40
*/
public class TestExecutor {
public static void main(String[] args) {
// Executors 是工具类 (有很多的静态方法) 用于生产
ExecutorService exeService = Executors.newFixedThreadPool(2);
//ExecutorService exeService2 = Executors.newCachedThreadPool();
TaskA3 a3 = new TaskA3(); //1. 创建任务对象
exeService.submit(a3); //2. 将任务对象提交给线程池
TaskB3 b3 = new TaskB3();
exeService.submit(b3);
// 默认写法
TaskC3 c3 = new TaskC3();
exeService.submit(c3);
/* // 匿名内部类写法
exeService.submit(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println("task4 i= " + i);
}
}
});*/
/* //labmda 表达式写法
exeService.submit(()->{
for (int i = 0; i < 10000; i++) {
System.out.println("task5 i= " + i);
}
});*/
// exeService.shutdown(); 关闭线程池 ,平时不用
}
}
//class TaskA3 extends Thread{
class TaskA3 implements Runnable{
@Override
public void run() {
int count=10000;
for (int i = 0; i < count; i++) {
System.out.println("TaskA ..."+ i + Thread.currentThread().getName());
}
}
}
class TaskB3 implements Runnable{
@Override
public void run() {
int count=10000;
for (int i = 0; i < count; i++) {
System.out.println("TaskB..."+ i+ Thread.currentThread().getName());
}
System.out.println();
}
}
class TaskC3 implements Runnable{
@Override
public void run() {
int count=10000;
for (int i = 0; i < count; i++) {
System.out.println("TaskC..."+ i+ Thread.currentThread().getName());
}
System.out.println();
}
}
P37-Callable和Future接口 54:46
Callable 接口用于取代 Runnable 接口 ,原因:
1.Runnable 接口没有返回值, Daug Lea 看着不顺眼,jdk1.5 中 增加了Callable接口
2. Runnable 接口的run() 方法不能抛出异常,只能在run内部try catch 掉
Future接口: 用来接收和获取线程的返回值,或是线程抛出的异常
Runnable VS Callable ,Callable 1. 抛异常 2.返回值
@FunctionalInterface
public interface Runnable { public abstract void run(); }
@FunctionalInterface
public interface Callable<V> { V call() throws Exception; }
// submit 会有future返回值
public interface ExecutorService extends Executor {
<T> Future<T> submit(Callable<T> task);
}

P38-多线程的同步 1:06:12
多线程共同访问同一个对象,(线程的堆空间共享),如果破坏了不可分割的操作 ,可能导致数据不一致
临界资源: 被多线程共同访问的对象(堆共享,所以会有很多临界资源)
原子操作:不可分割的操作,要么都执行,要么都不执行

代码路径:
https://github.com/wei198621/javaBasic03Apis/blob/main/src/main/java/day22/TestSynchronized.java

P39-同步代码块 58:42
synchronized(obj){ } // 对obj对象加锁的同步代码块
java中,每个对象都有一个互斥锁标记(monitor),用来分配给一个线程
只有拿到对象互斥锁标记的线程,才能进入对obj加锁的同步代码块
线程离开同步代码块的时候,会释放对象的锁标记
可以想象 synchronized 标记内是一个厕所,t1进入厕所后,t2只能等待,无法进入,好好好!!!
线程安全的对象: 改对象成为临界资源,被多线程访问时,不会发生原子操作被破坏,导致数据不一致的问题。

锁的是obj,不是锁代码块

这是我听过的最好理解的同步代码块,synchronized 锁标记 的讲解
女生有男朋友,被sync标记标注 ,只能用于此女生的sync标记,才可以与之拥抱等,

P40-同步方法 11:13
public class A{
public synchronized void m(){} //同步方法 对this加锁的同步代码块
A a1 =new A();
A a2=new A();
a1.m(); //线程获得 m 的权限执行
a2.m(); // 得等 a1 对m的权限释放完毕后,才可以 获取m的执行权限
}
只有获得object锁标记的线程,才能调用obje的同步方法
调用方法之前,竞争obj的锁标记
方法调用结束时,释放obj的锁标记
package day22;
/**
* @author leowei
* @date 2020/12/31 - 23:49
*/
public class TestSynchronizedMethod {
public static void main(String[] args) throws InterruptedException {
test02();
}
//正常打印 ABCD
private static void test02() throws InterruptedException {
MyList2 list = new MyList2();
Thread t1 = new Thread() {
public void run() {
list.add('C'); //add 方法已经增加 synchronized标记
}
};
Thread t2 = new Thread() {
public void run() {
list.add('D'); //add 方法已经增加 synchronized标记
}
};
t1.start();
t2.start();
t1.join(); //主线程等待t1结束
t2.join();
list.print();
}
}
class MyList2{
private char[] data={'A','B',' ',' ',' '};
private int index = 2;
public synchronized void add(char c){
data[index]=c;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
index++;
}
public void print() {
for (int i = 0; i < data.length; i++) {
System.out.println(i + ":" + data[i] + "\t");
}
}
}
P41-线程安全的集合 50:24
ArrayList ----- 所有方法都不是同步方法 ---- 线程不安全
Vector -----所有方法都是同步方法 ----- 线程安全 并发效率低下
线程安全的集合类:既保证线程安全,有保证并发效率很高
ConcurrentHashMap
jdk1.5~jdk1.7 分段锁,控制锁的粒度 把map分为16个片段,针对每个片段加锁
jdk 1.8 采用CAS算法 无锁算法
CopyOnWriteArrayList 永远不会改变集合中的数据,读操作次数远高于写操作
读操作: 获取集合的数据 不用加锁 , 效率高
写操作: 改变集合的数据 复制新的集合的方式来实现写操作 效率低
CopyOnWriteArraySet 原理同 CopyOnWriteArrayList 一致
P42-队列接口 31:51
新的接口
linkedlist 线程不安全
ConcurrentLinkedQueue 线程安全 CAS 无锁算法
Queue 的子接口
BlockingQueue 阻塞队列 当队列为空,从队列取数据,为空,当队列为满,向队列中添加元素的线程会阻塞
有界队列 ArrayBlockingQueue
无界队列 LinkedBlockingQueue
集合体系图

map体系图

P43-死锁问题 28:59
t1-----o.wait(): t1会释放所有锁标记,进入等待状态
t2-----o.notify()/o.notifyAll(): 通知一个/所有 调用过o.wait()的线程,离开等待状态
此视频没有 wait notify 的教学
synchronized(a){ //t1
synchronized(b){
/…
}
}
synchronized(b){ //t2
synchronized(a){
/…
}
}
避免多线程访问临界资源,造成数据不一致的办法
尽可能避免使用临界资源,多使用局部变量存储数据(局部变量存储在栈空间,栈空间线程独立)
尽量使用无锁算法,使用编程安全同时并发效率高的对象
使用synchronized利用锁标记来控制线程安全
package day22;
/**
* @author leowei
* @date 2021/1/1 - 9:35
*/
public class TestSynchronizedLock {
public static void main(String[] args) {
System.out.println(" start ...........................");
Object a ="A";
Object b="B";
Thread tAB = new Thread(new syncThread(a, b), "tAB");
Thread tBA = new Thread(new syncThread(b,a), "tBA");
tAB.start();
tBA.start();
System.out.println(" end ...........................");
}
}
class syncThread implements Runnable{
private Object obj1;
private Object obj2;
public syncThread(Object o1,Object o2){
this.obj1=o1;
this.obj2=o2;
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + obj1);
System.out.println( threadName + obj2);
synchronized (obj1){
synchronized (obj2){
for (int i = 0; i < 100000; i++) {
System.out.println(" print int "+ obj1 + " , "+ obj2 + " :"+ i);
if(i/10==0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}
其他
P44-类对象 56:58
反射是底层技术 , 通常用来实现框架和工具
反射是运行时的类型判定
new ClassA(); ------编译时判断类型
new ?() ----------运行时判断类型
类对象 Class类的对象
类加载: 当JVM第一次使用一个类的时候,需要将此类的字节码文件读入JVM,从而获取这个类的全部信息(类的父类,有哪些属性,方法,构造方法等),并保存起来(保存在JVM的方法区)
Dog类
类的对象:该类的对象 大黑 老白 Dog类的对象
类对象: 记录类信息的对象 记录Dog信息的对象 Class类的对象
类对象是 类加载的产物,在JVM中,包含一个类的全部信息

获取“类对象”的三种方式
类名.class 直接获得“类对象” ,也可以获取到8中基本类型的“类对象”
类的对象.getClass() 获取“类对象”
Class.forName(“类的全名”) 通过类名字符串,获得类对象,可能会先加载类
package day22;
import java.util.ArrayList;
/**
* @author leowei
* @date 2021/1/1 - 11:44
*/
public class TestClass {
public static void main(String[] args) throws Exception {
//类对象获取方式1
Class c1 = ArrayList.class;
//类对象获取方式2
ArrayList list = new ArrayList();
Class c2 = list.getClass();
//类对象获取方式3
String className="java.util.ArrayList";
Class c3 = Class.forName(className);
System.out.println(c1==c2);
System.out.println(c2==c3);
}
}
P45-反射的应用 1:08:47
Class: 封装类的信息
Method:封装方法的信息

类对象.newInstance() 通过类对象,创建类的对象
System.out.println("=============一行代码创建一个student ====================");
Student student = new Student();
System.out.println("==============两行代码创建一个student =====================");
Class c1 = Class.forName("day23.Student"); //优点是可以创建任何类对象
Object o = c1.newInstance(); // c1.newInstance() 通过“类对象”创建“类的对象”
c.getMethod()
Method对象.invoke() 通过Method对象,调用该方法
System.out.println("==============两行代码创建一个student =====================");
Class cls = Class.forName("day23.Student"); //优点是可以创建任何类对象
Object obj = cls.newInstance(); // c1.newInstance() 通过“类对象”创建“类的对象”
//Method study = cls.getMethod("Study",int.class,double.class); //如果study 有多个方法
Method study = cls.getMethod("Study");
study.invoke(obj);
getMethod vs getDeclaredMethod
getDeclaredMethod 可以通过setAccessible(true); 访问类里面的有方法,这是个诀窍,也是个漏洞。
// 反射方式的方法调用 2
// getMethod vs getDeclaredMethod
private static void m4() throws Exception {
System.out.println("=============一行代码创建一个student ====================");
Student student = new Student();
//student.StudyPrivate(); //无法访问
System.out.println("==============两行代码创建一个student =====================");
Class cls = Class.forName("day23.Student"); //优点是可以创建任何类对象
Object obj = cls.newInstance(); // c1.newInstance() 通过“类对象”创建“类的对象”
//
//Method m = cls.getMethod("StudyPrivate"); //NoSuchMethodException: day23.Student.StudyPrivate()
//
Method m = cls.getDeclaredMethod("StudyPrivate"); //java.lang.IllegalAccessException: Class day23.TestReflection can not access a member of class day23.Student with modifiers "private"
m.setAccessible(true); // 设置私有方法为public,可以访问 ,就 不报上面的 IllegalAccessException 异常了
//
m.invoke(obj); // 注意此处是invoke (object)
System.out.println("=================================================");
}
P46-单例设计模式 55:02
java与模式 — (闫红) 符合中国人的习惯
- 单例模式 创建步骤
- 1.创建一个私有 静态 属性 ,是本类的对象
- 2.创建一个公开 静态方法,用于获得此对象
- 3.将构造方法私有
/**
* 单例模式 创建步骤
* 1.创建一个私有 静态 属性 ,是本类的对象
* 2.创建一个公开 静态方法,用于获得此对象
* 3.将构造方法私有
*/
class ClassA{
private static ClassA instance= new ClassA(); // 静态属性,全类共有,只有一份
public static ClassA newInstance(){ // 公开静态方法
return instance;
}
private ClassA(){ // 构造方法默认 public 的,此处改为private ,不让用户通过new ClassA() 创建对象
}
}

package day23;
import javax.lang.model.element.VariableElement;
/**
* @author leowei
* @date 2021/1/1 - 14:33
*/
public class TestSingle {
public static void main(String[] args) {
ClassA classA = ClassA.newInstance();
ClassA classA1 = ClassA.newInstance();
// ClassA classA2 = new ClassA(); //不允许通过构造器创建对象
{
/* ClassB.newInstance();
ClassB.newInstance(); //顺序执行,只会创建一次*/
}
/* {
new Thread(() -> ClassB.newInstance()).start();
new Thread(() -> ClassB.newInstance()).start(); // 多线程执行,会创建多次
}*/
{
new Thread(() -> ClassB2.newInstance()).start();
new Thread(() -> ClassB2.newInstance()).start(); // 多线程执行,不会创建多次
}
}
}
/**
* 单例模式 饿汉模式
* 单例模式 创建步骤
* 1.创建一个私有 静态 属性 ,是本类的对象
* 2.创建一个公开 静态方法,用于获得此对象
* 3.将构造方法私有
*/
class ClassA{
private static ClassA instance= new ClassA(); // 静态属性,全类共有,只有一份
public static ClassA newInstance(){ // 公开静态方法
return instance;
}
private ClassA(){ // 构造方法默认 public 的,此处改为private ,不让用户通过new ClassA() 创建对象
}
}
/**
* 单例模式 懒汉模式 多线程 可能会有问题
*/
class ClassB{
private static ClassB instance= null ; // 静态属性,全类共有,只有一份
public static ClassB newInstance(){ // 公开静态方法
if(instance ==null){
instance =new ClassB();
}
return instance;
}
private ClassB(){ // 构造方法默认 public 的,此处改为private ,不让用户通过new ClassA() 创建对象
System.out.println("new ClassB ");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 单例模式 懒汉模式 多线程不会有问题
*/
class ClassB2{
private static ClassB2 instance= null ; // 静态属性,全类共有,只有一份
public static synchronized ClassB2 newInstance(){ // 公开静态方法
if(instance ==null){
instance =new ClassB2();
}
return instance;
}
private ClassB2(){ // 构造方法默认 public 的,此处改为private ,不让用户通过new ClassA() 创建对象
System.out.println("new ClassB ");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// 第三种单例模式 百知特有,虽然调用实际,但是貌似有多了一个类
//
class ClassC{
private static class Holder{ //创建一个静态内部类 ,包含后一个静态属性
static ClassC instance =new ClassC();
}
public static ClassC newInstance(){
return Holder.instance;
}
private ClassC(){
System.out.println("new Class C ");
}
}
P47-工厂设计模式 42:55
对象创建
开闭原则: 软件对修改关闭,对扩展开放

package day23;
import java.io.*;
import java.util.ArrayList;
import java.util.Properties;
import java.util.Scanner;
import java.util.stream.Stream;
/**
* @author leowei
* @date 2021/1/1 - 15:21
* config.txt 的内容是
animal=day23.Dog
animal2=day23.Dog
*/
public class TestFactory {
public static void main(String[] args) throws Exception {
//Dog a =new Dog();
//Animal a =new Dog();
/* Scanner scanner = new Scanner(System.in);
String next = scanner.next();
Animal a = createAnimal(next); // "Dog";*/
//Animal a = createAnimalBuReflect01(); // "Dog";
Animal a = createAnimalBuReflect02(); // "Dog";
a.eat();
}
// 原始的创建方式
public static Animal createAnimal0(String className) {
if (className.equals("Dog")) {
return new Dog();
}
if (className.equals("Cat")) {
return new Cat();
}
return null;
}
// 反射创建方式 对象
public static Animal createAnimal(String className) {
try {
Class c = Class.forName("day23." + className); // 获取类对象
Object o = c.newInstance();
return (Animal) o;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 反射创建方式 对象 读取配置文件
public static Animal createAnimalBuReflect01() throws IOException {
try {
InputStream is =new FileInputStream("config.txt");
InputStreamReader isr =new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
// while(true){ //只考虑一行的情况
String result = br.readLine();
// }
String[] splits = result.split("=");
Class c = Class.forName(splits[1].trim()); // 获取类对象
Object o = c.newInstance();
return (Animal) o;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 反射创建方式 对象 读取配置文件
public static Animal createAnimalBuReflect02() throws IOException {
try {
InputStream is =new FileInputStream("config.txt");
Properties pro =new Properties();
pro.load(is);
String animal = pro.getProperty("animal");
Class c = Class.forName(animal.trim()); // 获取类对象
Object o = c.newInstance();
return (Animal) o;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
class Animal{
public void eat(){}
}
class Dog extends Animal{
public void eat(){
System.out.println(" Dog eat");
}
}
class Cat extends Animal{
public void eat(){
System.out.println(" Cat eat");
}
}

321

被折叠的 条评论
为什么被折叠?



