Java基础提升高级API---百知教育java基础学习3

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

基本类型对应的包装类
intInteger
charCharactor
byteByte
shortShort
longLong
floatFloat
doubleDouble
booleanBoolean
  • 基本类型 与 包装类之间的转换
    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/OutputStreamReader/Writer
FileInputStream/FileOutputStreamFileReader/FileWriter节点流
孙1BufferedInputStream/BufferedOutputStreamBufferedReader/BufferedWriter过滤流
孙2PrintStreamPrintWriter过滤流 替换孙1
孙3ObjectInputStream/ObjectOutputStream过滤流
电脑600600600
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");
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值