java笔记,持续更新中包括java基础,web,各种框架,微服务框架,后续也会单独发布。

Java基础

注意:长篇警告!!目前本笔记7w+字,且图片没能上传成功(懒得搞了)如果觉得有用可以私信我。本笔记为个人学习过程中记录,所学课程均来自网络公开课,笔记内容如有错误欢迎指正。本笔记仅供个人学习使用,转载请联系私信本人
前言:

  • 不同版本

javaSE 桌面

javaME 移动

javaEE 服务器

  • 跨平台

jvm使得java可以跨平台,我们编写的java程序都是编程jvm字节码在jvm上执行,不同的操作系统负责实现本操作系统下的jvm

  • 特性

简单,面向对象,可移植性,高性能,分布式,动态性,多线程,安全性,健壮性

JDK Java Development Kit 包括jre和jvm还有一些他们没有的东西

JRE Java Runtime Environment 除了jvm还有一些其他运行需要的东西(只需要运行java程序只需要安装jre即可)

jvm Hava Virtual Machine

  • java程序运行机制

源文件首先编译成字节码(.class)之后再通过类加载器,字节码校验器 解释器才能运行

一个java文件中只有一个public类,可以有多个class

public class Outer{
    
}
class test{
    public static void main(String[] args){
        //这里写Outer类的测试
    }
}

文章目录

IDEA快捷键

psvm   //自动生成main函数
sout   //自动生成输出
重写方法 alt+insert
选中代码 CTRL+alt+t  抛出异常
alt+7 列出来类的方法大纲
ctrl+f12  类的结构

第一章 (基础)

1.1基本数据类型/变量

  • 基本数据类型 (和其他语言雷士)
    • byte 1字节
    • short 2 byte
    • int 4byte
    • long 8byte
    • float 4byte
    • doublt 8byte
    • char 2byte
    • boolean 1bit
  • 引用数据类型 (类 接口 数组)
1.1.1类型定义
// 【1】 基本数据类型
int num=0;
short num3=30;
long num4=20L;   //add L
float num5=123.3F;   //add F
double num6=1.123;
char name='A';
String name="啊士大夫看见";  //String is not a key word,but a class
Integer name =123124;  //Integer is not a key word,but a class

// 【2】 进制  二进制0b  八进制0  十六进制0x
int i=10;
int i2=010;
int i3=0x10l;

// 【3】 浮点数 舍入误差,最好不要用浮点数进行比较
// 【4】 字符扩展  Unicode 2字节编码 0-65536   97-a  U0000-UFFFF  
char cs ='\u0061';   //unicode编码
// 【5】 String类
String a=new String("hello");
String b = new String("hello"); //a!=b
String c="hello";
String d="hello"; //c==d
1.1.2类型转换
// 【1】 强制类型转换的时候避免内存溢出  (高到低)
int i=128;
byte b=(int)i; 

// 【2】 自动转换  (低到高)
int i =123;
double b=i;

// 【3】 计算之前如果有溢出,可以先转换再计算
long total = 1000000000*(long)20;
1.1.3变量 常量 作用域

final 表示常量

static 类变量可以在类的方法中直接使用

修饰符不存在先后顺序

1.2运算符

// 【1】 Math类,java中没有^幂运算,需要用到Math类的pow方法

// 【2】 条件运算符 ?:
int a = x?a:b; //如果x为真a=a,否则a=b

1.3用户交互

// 【1】 接受用户输入
Scanner scanner = new Scanner(System.in);
//判断用户是否输入
if(scanner.hasNext()){
    String str= scanner.next();  //空格隔开  nextLine可以接受一行以为回车为结束符
    System.out.println(str);
}
scanner.close();

1.4程序结构

//# 1 switch
switch(expression){
    case value:
        //
        break;
    case value:
        //
        break;
    default:
        //      
}
//# 2 增强for循环
for(int x:numbers){
    //numbers是可遍历数据类型,
}

1.5方法

java是值传递,不是引用传递

1.5.1可变参数
// 【1】 只可以指定一个可变参数,必须在普通参数之后
public void test(int... i){    //【可变长的参数,封装到一个对象,本质就是一个数组,通过数组下表来找到不同的值】
    System.out.println(i[0]);
}

1.6数组

数组的长度在创建后是不变的

数组是一个对象

// 【1】 数组的属性
num.length

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r0hIPok6-1681980768116)(…/Asset/image-20230413163002023-16816270541451.png)]

1.6.1数组的声名和创建
int[] nums;  //定义
nums=new int[10];  //使用数组,可以存放10个int类型数字
1.6.2三种初始化
// 【1】 静态初始化
int[] a={1,2,3,4,5}
Man[] manx={new Man(1),new Man(2)}

// 【2】 动态初始化
int[] nums=new int[10];  //创建数组后,通过下标来赋值
nums[0]=1;

// 【3】 默认初始化
int[] nums=new int[10];  //这里面有默认的值0
1.6.3数组工具类Arrays
// 【1】 打印数组
int[] a={1,2,3,4,5};
Arrays.toString(a);
    
// 【2】 数组填充
int[] a={1,2,3,4,5}
Arrays.fill(a,0); //[0,0,0,0,0]

1.7面向对象

  1. 栈是一些方法和引用

  2. 堆里面才是实际的对象,其中堆里面有个特殊的方法区,存放的是类的方法,类加载的时候加载到这里,同时一些静态方法也在这里,随这类一块加载。

  3. 类的具体对象放在堆中,对象属性修改,实际上是把创建该对象的类里面的一些值赋值给该对象。

  4. 一个类只有一个Class对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aUDt7Ilc-1681980768117)(…/Asset/image-20230413165349580-16816270566443.png)]

1.7.1继承

idea中ctrl+h查看当前类的继承关系

java中只有单继承,没有多继承

java中final修饰的类无法被继承

  • this指代自己,super指代直接继承的父类方法,super只能出现在子类的方法中
  • 私有无法继承
  • 调用父类的构造器,调用自己的构造器,只能放在第一行
  • 继承的无参构造会自动调用父类的无参构造
  • 有参构造写好后,自动销毁无参构造,并且该类的子类也同样无法写无参构造。因此写了有参构造后一定要手动添加无参构造方法
  • this()本地无参构造 super()父类无参构造

重写方法

  • 方法名相同
  • 参数列表必须相同
  • 修饰符,范围可以扩大但不能缩小
  • 抛出异常,范围可以缩小,不能扩大(父类没有抛出异常,子类就不可以抛出异常)
//【1】方法重写(静态方法) 和重载不太一样,和属性无关
A a=new A();
a.test();  //子类的方法
B b=new A();   //父类的引用指向子类,
b.test();  //父类的方法【方法的调用只和该引用的类型有关,引用
//【2】方法重写(非静态方法) 谁的实例调谁的方法
1.7.2多态

动态编译,能执行的方法看引用的类型,对象的实例时确定的,时右面new的类型

  1. 多态是方法的多态,属性没有多态
  2. 父类和子类,有联系,否则类形转换异常
  3. 继承关系,方法重写,到底执行谁只有在运行的过程中才能判定(因为可以类型转换)
1.7.3 instanceof 和类型转换
  • instanceof

instanceof 判断一个对象时什么类型

x instanceof y //x是y的子类,结果是true

Object object = new Student();
object instanceof Student;//true
object instanceof Person;//true
object instanceof Teacher;//false
  • 类型转换

子类转换为父类可能会丢失一些方法。

父类转换为子类,强制转换

1.7.4抽象类和接口
  • 抽象类
  1. 有抽象方法的类就是抽象类,抽象方法用abstract修饰。类里面也可以有普通方法
  2. 不能new,只能靠子类来实现,new子类…可以看作是个框架。
  3. 抽象类还是各类,只能用extends来继承,只能单继承
public abstract class Action{
    public void run(){}
}
public class example extends Action{
    public void run(){
        System.out.println("run");
    }
}
  • 接口
  1. 只有规范,没有普通方法,实现约束和实现分离
  2. 不用class用interface
  3. 接口不能被实例化,接口中没有构造方法
public interface UserService{
    //默认都是public abstract 
    public abstract void run();
    void run();//和上面的定义相同
    void add(String str);
}
public class UserServiceImpl implements UserService{
    //这里面需要重写接口的所有方法
}
1.7.5内部类
  • 成员内部类
public class Outer{
    private int id;
    public void out(){
        System.out.println("这是外部类的方法");
    }
   	
    public class Inner{
        public void in(){
            System.out.println("这是内部类的方法");
        }
        public void getId(){
            System.out.println(id);//内部类可以操作外部类的私有属性
        }
    }
    
    public static class Inner{
        public void in(){
            System.out.println("这是内部类的方法");
        }
        public void getId(){
            System.out.println(id);//【这里会报错,因为类是static但是属性不是static属性】
        }
    }
}
Outer outer=new Outer();
Outer.Inner inner = outer.new Inner();//  通过外部类来new内部类
  • 局部内部类,在方法中的类,只局限于方法内部
  • 静态内部类
public class Test{
    private name='123';
    static class inner{
        private age=20;
        public void fun(){
            sout(age,Test.name)
        }
    }
}
Test.inner = new Test.inner();//可以直接new
  • 匿名内部类
interface UserService{
    void hello();
}
public class Test{
    public static void main(String[] args){
        
        //下列下发就是匿名内部类的形式
        new Uservice(){
            public void hello(){
                System.out.println("实现接口的方法");
            }
        }.hello();
        
        //上述写法等价于
        calss User implements UserService{
            public void hello(){
                System.out.println("实现接口的方法");
            }
        }
        User user= new User();
        user.hello();
        
    }
}

1.8static关键字

  • static属性属于类,用类名访问,被所有对象共享

  • static方法属于类,类加载的时候就加载了,不需要实例,直接用类名来调用

  • static方法里面只能调用static修饰的方法

  • 静态代码块,类加载额时候只执行一次

public class Person{
    static{
        System.out.println("静态代码块")//最先执行,只执行一次
    }
    {
        System.out.println("匿名代码块")//第二执行,赋初始值,可以多次执行
    }
    public Person(){
        System.out.println("构造方法")//最后执行
    }
}

1.9异常

  1. 检查性异常:用户错误操作引起的异常
  2. 运行时异常
  3. 错误ERROR 大多数都是虚拟机抛出,Error后虚拟机会选择终止

异常处理框架:所有的异常当作一个对象处理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KhYM0ePc-1681980768118)(…/Asset/image-20230414150322748-16816270763905.png)]

异常处理:

  1. jvm处理及默认处理(打印异常信息到控制台,程序终止)
  2. 抛出异常程序处理
//【1】初识异常  选中代码块后 按ctrl+alt+t
public class Test {
    public static void main(String[] args) {
        int a=1;
        int b=0;

        try {//监控区域
            System.out.println(a/b);
        }catch (Exception e){//里面是需要捕获的异常类型
            System.out.println("程序出现异常");
            e.printStackTrace();//打印错误信息
        }catch(Throwable t){
            System.out.println("【==异常可以多次catch,注意小的异常要先写==】")}finally {
            System.out.println("善后工作");
        }
        
        try{
            new Test().test(1,0);
        }catch(Exception e){
            e.printStackTrace();
        }
        
    }
    public void test(int a,int b){
        if(b==0){
            throw new Exception();//抛出异常,一般在方法中使用,本方法不处理,交给调用改方法的角色去处理
        }
        System.out.println(a/b);
    }
}
//【2】自定义异常
public class MyException extends Exception{
    //传递数字,如果数字大于10抛出异常
    private int detail;
    public MyException(int a){
        this.detail=a;
    }
    //异常打印信息
    @Override
    public String toString() {
        return "MyException{" +
                "detail=" + detail +
                '}';
    }
}
public class Test {
    static void test(int a) throws MyException{
        if(a>10){
            throw new MyException(a);  //抛出异常,不在这里处理
        }
        System.out.println("ok");
    }

    public static void main(String[] args) {
        try {
            test(11);
        } catch (MyException e) {
            System.out.println("MyException=>"+e);  //这里的e就是自定义异常的tostring方法的返回值
        }
    }
}

1.10Stream()流

先学完集合框架后再来看

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SWaVzvIc-1681980768118)(…/Asset/image-20230417155347508.png)]

使用步骤:

  1. 得到Stream流
  2. 利用中间方法过滤
  3. 利用终结方法输出
1.10.1 获取Stream流

注意:双列集合只能通过key获取set集合后,再利用单列集合来操作。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7QOwW82v-1681980768118)(…/Asset/image-20230417155451487.png)]

// 【1】 单列集合获取Steam
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"123","231234","!312423","12344","1234","1234324","3253254");
Stream<String> stream1 = list.stream();  //获取集合的流水线,然后放到流水线上

// 【2】 双列集合获取Stream 根据key
HashMap<String, String> hm = new HashMap<>();
hm.put("123","321");
hm.put("231","432");
Stream<String> stream2 = hm.keySet().stream();

// 【3】 双列集合获取Stream 根据Entries
HashMap<String, String> hm = new HashMap<>();
hm.put("123","321");
hm.put("231","432");
hm.entrySet().stream().forEach(s-> System.out.println(s));

// 【4】 数组获取Stream 【利用arrays来获取】
int[] arr={1,2,3,4,5,6,7};
Arrays.stream(arr).forEach(s -> System.out.println(s)); //【无论是引用数据类型还是自定义数据类型的数组都可以用这个方法】

// 【5】 凌乱的一堆数据(同类型)  【利用Steam.of方法】
Stream.of(1,2,3,4,6).forEach(S-> System.out.println(S));//
1.10.2中间方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MmLlIHnP-1681980768118)(…/Asset/image-20230417160444234.png)]

// 【1】 过滤
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"123","231234","!312423","12344","1234","1234324","3253254");
//注意流只能使用依次,建议中间方法和终结方法利用链式编程
list.stream()
    .filter(s -> s.startsWith("1"))
    .forEach(s -> System.out.println(s));

// 【2】 limit获取前面3个元素 skip写法和limit类似
list.stream()
    .limit(3)
    .forEach(s -> System.out.println(s));

// 【3】 distinct 去重
list.stream()
    .distinct()
    .forEach(s -> System.out.println(s));

// 【4】 concat合并
Stream.concat(list1.stream(),list2.stream()).forEach(s->sout(s));

// 【5】 map类型转换  【String->int】
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张三-3","李四-4","王五-23","天六-44","赵七-4","阿道夫-24","的萨芬-3254");
list.stream()
    .map(s-> Integer.parseInt(s.split("-")[1]))
    .forEach(s-> System.out.println(s));
1.10.3 终结方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S8SYOV9K-1681980768119)(…/Asset/image-20230417162100746.png)]

// 【1】 收集数据 toArray()
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张三-3","李四-4","王五-23","天六-44","赵七-4","阿道夫-24","的萨芬-3254");
//String表示要转化为String数组,value表示流里面的数据个数
String[] strr = list.stream()
    .map(s -> s.split("-")[1])
    .toArray(value -> new String[value]);
System.out.println(Arrays.toString(strr));  //【数组的输出用Arrays里的toString方法】

// 【2】 收集到集合中 collect
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张三-3","李四-4","王五-23","天六-44","赵七-4","阿道夫-24","的萨芬-3254");
//String表示要转化为String数组,value表示流里面的数据个数
List<String> collect = list.stream()
    .map(s -> s.split("-")[1])
    .collect(Collectors.toList());  //【collector.toList()创建list集合,同理toSet会帮我们创建一个hashSet集合并把数据放到集合里面】
System.out.println(collect);

// 【3】收集到Map中 【注意:键不能重复】
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张三-3","李四-4","王五-23","天六-44","赵七-4","阿道夫-24","的萨芬-3254");
Map<String, Integer> collect = list.stream()
    //toMap中有两个参数,一个是键的规则,一个是值的规则
    //Function<当前流的类型,最终键或值的类型>
    .collect(Collectors.toMap(new Function<String, String>() {
        @Override
        public String apply(String s) {
            return s.split("-")[0];
        }
    }, new Function<String, Integer>() {
        @Override
        public Integer apply(String s) {
            return Integer.parseInt(s.split("-")[1]);
        }
    }));
System.out.println(collect);

1.11方法引用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JqfH6fj5-1681980768119)(…/Asset/image-20230417165027396.png)]

// 【1】 快速入门方法引用
public static int subtraction(int num1,int num2){
    return num2-num1;//num2大于num1 从大到小
}
Arrays.sort(arr,类名::方法名);  //

1.11.1引用静态方法

类名::静态方法名字

list.stream().map(Integer::paraseInt).forEach();
//其中paraseInt就是把String转换为int
1.11.2引用成员方法

对象::方法名 this::方法名 super::方法名

public class StringOperation {
    public boolean stringJudge(String s) {
        return s.length()==3&&s.startsWith("张")
    }
}

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张三-3","李四-4","王五-23","天六-44","赵七-4","阿道夫-24","的萨芬-3254");
list.stream().filter(new StringOperation()::stringJudge).forEach();
1.11.3引用构造方法

类名::new

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张三-3","李四-4","王五-23","天六-44","赵七-4","阿道夫-24","的萨芬-3254");
//注意map中的函数形参只有一个,因此Student的构造方法的形参也应该是一个。构造方法的返回值就是Student的对象
List<Student> students = list.stream().map(Student::new).collect(Collectors.toList());
System.out.println(students);

public class Student implements Comparable<Student>{
    private int age;
    private String name;
    public Student(String s){
        String[] strr = s.split("-");
        this.name=strr[0];
        this.age=Integer.parseInt(strr[1]);
    }
}
1.11.4其他引用
  • 使用类名::成员方法

引用规则:

  1. 函数式接口
  2. 被引用的方法必须存在
  3. 被引用方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持一致,返回值需要保持一致。
  4. 被引用的方法可以满足要求
  5. 该引用方式下,抽象方法的第一个参数的类型决定了可以引用那些类(比如第一个参数是String,那么可以引用String的方法)
public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list,"asdf","sadf","asdf","asdf","asdf","asdf","asdf");
    list.stream().map(String::toUpperCase).forEach(s-> System.out.println(s));
}
  • 引用数组的构造方法

数据类型[]::new

用该方法创建数组,需要使得流水线中数据类型和要创建的数组类型相同

public static void main(String[] args) {
    ArrayList<Integer> list = new ArrayList<>();
    Collections.addAll(list,1,2,3,4,5,6,7,8);
    Integer[] integers = list.stream().toArray(Integer[]::new);//【流里面的数据是Integer ,因此引用的是Integer数组的构造方法】
    System.out.println(Arrays.toString(integers));   

}

1.12 动态代理

不修改原码增加新的功能

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8llQNch5-1681980768119)(…/Asset/image-20230420144459472.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oGfNU3a4-1681980768119)(…/Asset/image-20230420144952139.png)]

  • 创建代理对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NgHwD03n-1681980768120)(…/Asset/image-20230420145052082.png)]

// 【1】 原对象
public class BigStar implements star {
    @Override
    public String toString()  {
        return "BigStar{" +
                "name='" + name + '\'' +
                '}';
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    private String name;

    @Override
    public String sing(String name){
        System.out.println(this.name+"正在长"+name);
        return "谢谢";
    }

    @Override
    public void dance(String name){
        System.out.println(this.name+"正在跳舞"+name);
    }

}

// 【2】 接口 是所有需要代理(增加新功能的代码)【代理和原类都要实现该方法】
public interface star {
    //接口中写想要被代理的方法

    public abstract String sing(String name);

    public abstract void dance(String name);
}


// 【3】 代理 
public class ProxyUtil {
    //用于创建一个代理,形参是需要代理的对象 返回值是一个代理
    public static star createProxy(BigStar bigStar){
        /**
         * 第一个参数 指定类加载器
         * 第二个参数指定接口,接口用于指定生成的代理长什么,也就是有什么方法
         * 第三个参数 指定生成的代理对象要做什么事情
        */
        star s = (star) Proxy.newProxyInstance(
                ProxyUtil.class.getClassLoader(),  //找到该类的Class对象,获取加载该类的类加载器,用该加载器加载一次
                new Class[]{star.class},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        /**
                         * 第一个参数:代理对象
                         * 第二个参数 要运行的方法
                         * 第三个参数 调用method方法是传入的实参
                         * */
                        //添加新的功能
                        if("sing".equals(method.getName())){
                            System.out.println("准备话筒,收钱");
                        }else if ("dance".equals(method.getName())){
                            System.out.println("准备场地,收钱");
                        }
                        //执行原有的功能
                        return method.invoke(bigStar,args);
                    }
                }
        );
        return s;
    }
}

// 【4】 测试
class test{
    public static void main(String[] args) {
        //创建某个类的代理
        star proxy = ProxyUtil.createProxy(new BigStar("ikun"));
        proxy.dance("跳舞的名字");
        proxy.sing("唱歌的名字");
    }
}

第二章(常用类,集合框架,Io)

2.1Object类

方法名作用
对象名.equals(对象名)地址比较,如果需要值比较,需要在对象中重写equals方法
对象名.hashCode()为改对象生成一个独立的哈希码,用于区分每个对象,可以重写hashCode()让其和属性值相关联
对象名.toString()打印对象
2.1.1equals()

基本数据类型用== ==比较的是值,引用比较的是地址

equals比较的引用类的地址值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CJcFUXaM-1681980768120)(…/Asset/image-20230414154919652-16816270788567.png)]

//【1】重写equal,使得对象相比的时候比的是值
idea 会自动生成
2.1.2hashCode()

两个对象的值相同,这两个对象的hashCode一定相同(重写的结果)

2.1.2扩展 native关键字

native方法表示java调用调用非java代码的接口。

定义native方法时候

public int hashCode(){
    return Objects.hash(name,age)//重写方法根据值计算hash值
}
2.1.3toString方法

输出实例对象的id可以认为是个地址值

可以重写该方法

Student stu=new Student();
sout(stu);//地址值

//重写toString
idea会自动重写

sout(stu);//这是一个学生

2.2包装类

把基本数据类型包装成对应的类

作用:

  1. 基本数据类型之间的转换
  2. 集合中放的是引用类型(非基本数据类型)
属性/方法作用
MAX_VALUE对应当前基本类型的最大值
TPYE对应当前基本数据类型
⭐Integer.parseInt(str)把String转换为int
⭐Integer.valueof(str)把String类型转化为包装类
⭐对象名.toString转化为String类型
⭐对象名.intValue()把包装类变为基本数据类型
2.2.1自动装箱和拆箱
//【1】手动装箱拆箱
int a=10;
Integer integer=new Integer(a);
int i=integer.intValue();

//【2】自动
int b=10;
Integer integer2=b;//自动装箱
int c=integer2;//自动拆箱

//【3】隐藏装箱拆箱
Integer c=new Integer(10);
c++;//自动拆箱
int cc=10;
c.equals(cc);//隐藏装箱 把cc转换为包装类
2.2.2包装类常见问题
//【1】自动装箱拆箱注意问题
int a=10;
Integer b=10;
a==b;//b变为int,只是比的时候变为int【T】
b.equal(a);//a变为Integer   【T】

Integer a2=10;//自动装箱 【没有new新对象,返回的是缓存区中的地址(一个数)(-128,127)】【浮点类型没有,double类型没有 布尔类型没有】
Integer b2=10;//自动装箱 【没有new新对象,返回的是缓存区中的地址(一个数)(-128,127)】【浮点类型没有,double类型没有 布尔类型没有】
a2==b2;//还是值比较 【T】 
a2.equal(b2);//自动装箱 值比较【T】

Integer a3=200;//自动装箱 【new新对象】
Integer b3=200;//自动装箱
a3==b3;//地址比较 【F】 
a2.equal(b2);//自动装箱 值比较【T】

//【2】 每个包装类都有自己的缓冲区

2.3 String 类

  • 底层JDK1.8
  1. char数组保存String
  2. String的长度就是char数组的长度
  3. concat是创建了一个新的char数组,返回的是一个新的String
  • 底层JDK1.9
  1. 是byte数组。方便String的编码和重编码,节约空间(因为char默认占两个,byte占一个字节)
  2. 去长度的时候需要根据字符所占多少字节进行计算(如果全是英文,数组长度就是字符串长度,如果有中文,数组长度是字符串长度的二倍)
  3. concat和1.8类似,也是创建一个新的数组,只不过是byte数组
简单方法功能
str.length()字符串的长度
isEmpty()是否为空(检测内容是否为"")
startsWith(“as”)以什么开始
endsWith(“as”)以什么结束
toUpperCase()算不变为大写
toLowerCase()全部变为小写
常用方法A功能
str.charAt(int a)【return char】取index为a的字符,下表从0开始
str.substring(0,2)从0-2,不包含2。
str.indexOf(string/int/char)【int】返回字符(字符串)在字符串中首次出现的下标
str.indexOf(str,int)同上,int表示指定下标从哪里开始
str.lastIndexOf()同上
常用方法B功能
str.getBytes()【byte[]】吧string变为byte数组。以便后续进行重新编码
str.split(“-”)【string[]】按照某个字符分割字符串
str.contains(CharSequences s)【Boolean】判断字符串是否包含s
str.replace(char oldChar,char newChar)用newChar替换oldChar
str.replaceFirst(String oldChar,String newChar)【String】
str.replaceAll(String oldChar,String newChar)【String】
常用方法C功能
str.trim()去除首尾空格,可以去除多个
str1.compareTo(str2)【str1大返回+数,str2返回-数】比较大小,依次按照字符的ASCII码比较。
str1.compareToIgnorCase(str2)同上,只不过忽略大小写
str1.concat(str2)产生新的对象(浪费内存)
str1+str2产生新的对象(浪费内存)
2.3.1对象创建
String str="asdf";
String str=new String("asdf");
String ="";//有钱包美钱
String =null;//钱包都没有

// 【2】 byte数组创建字符串
String str=new String(bytes);
String str = new String(bytes,o,len);//把bytes数组从0开始长度为len切片,然后创建String数组
2.3.2StringBuffer和StringBuilder类

底层

  1. 如果创建的时候没有字符串,会自动创建一个长度为16的byte数组
  2. 如果有字符串,会创建一个字符串长度+16的byte数组(区分有没有中文,有中文的化创建字符串长度二倍+16的数组)。如果数组满了,再添加元素的时候,数组扩容为 添加前数组长度*2+2。如果扩容完都不够,直接把新计算后的长度作为新的长度

相同点:

  1. 均表示可变的字符序列

区别:

  1. buffer线程安全,做线程同步检查,效率较低
  2. stringBuilder 线程不安全,不做线程同步 效率高 建议采用该类
StringBuilder常用函数功能
builder.append()末尾追加
builder.insert(3,str)str在当前位置追加
setChartAt(index,char)在index替换为新的char
replace(start,end,str)替换吧[start,end)区间的字符串替换为str
delete(start,end)删除指定区域的字符
reverse()反转字符串
toString()转成String
// 【1】 StringBuilder的常用方法
StringBuilder builder="sadf";   //【X不能这么写】
StringBuilder builder=new StringBuilder("asdf");
builder.append();//最重要的函数,追加任何类型都可以追加
builder.insert(3,"123");

// 【2】 String转成StringBuilder
StringBuilder builder=new StringBuilder(str);
builder.toString();

2.4日期类

2.4.1Date类

**注意:**Date类已经过时了

方法(util中)功能
data.toLocaleString()返回当前的年月日时分秒
data.getTime()获取当前系统毫秒数(统计代码的执行效率,作为唯一标识)
System.currentTimeMillis()获取当前系统毫秒数(统计代码的执行效率,作为唯一标识(uuid也可以))
方法(sql中)功能
data.valueOf(str)【data类型数据】(只能由一种格式 2000-9-9、2000-09-09)根据字符串返回时间类型
toString()返回string
2.4.2DateFormat类

主要用来转换时间

时间对象和字符串之间相互转换

// 【1】 string类型转化为date的时间类型
String str="2023-4-15 12:12:12";
//上下格式一样就可以转
DateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  //【注意new的是实现类】
Date date = format.parse(str);

// 【2】 把时间类型转换为String
DateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  //转换的格式预览
format.format(date);
2.4.3 Calendar日历类

主要用来获取时间

// 【1】 获取年月日
Calendar calendar= new GregorianCalendar();  //【注意new的是实现类】
calendar.get(Calendar.YEAR);//获取年
System.out.println(calendar.get(Calendar.MINUTE));

// 【2】 date=>calendar
Date date= new Date()
calendar.setTime(date);

// 【3】 calendar=>date
Date date = calendar.getTime();

2.5枚举

枚举里面创建的是常量,用来对内容限制

比如性别只有男女,可以把男女定义为枚举类型,只能获取枚举类型中的一种

public enum Gender{
    男,女
}
public class Student{
    private Gender sex;
    public Gender getSex(){
        return sex;
    }
    public Gender setSex(Gender sex){
        this.sex=sex;
    }
}

Student stu=new Student();
stu.setSex(Gender.)

2.6Arrays类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yvtYeKAg-1681980768120)(…/Asset/image-20230417164918855.png)]

第三章 集合框架

注意!!本阶段有联系题目,在这里

黑马程序员Java零基础视频教程_上部(Java入门,含斯坦福大学练习题+力扣算法题和大厂java面试题)_哔哩哔哩_bilibili

黑马程序员Java零基础视频教程_下部(Java入门,含斯坦福大学练习题+力扣算法题和大厂java面试题)_哔哩哔哩_bilibili

集合特点

  1. 集合长度可变,【自动扩容】
  2. 集合不能直接存基本数据类型,需要把他们变为包装类。

体系结构:

  1. 单列集合(列表)Collection
    1. List集合:有序(存取顺序)、可重复、有索引
    2. Set集合:无序、不重复、无索引
  2. 双列集合(字典)

3.1泛型

可以在编译阶段约束操作的数据类型,并进行检查 【格式<>】

注意:泛型只支持引用数据类型

**注意:**泛型不具备继承性

为什么要引入泛型?:

  1. 如果没有泛型,认为是object可以添加任何数据,但是获取数据的时候无法直到是什么类型,因此不方便类型转换

**注意:**java的泛型是伪泛型:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZoPymdP7-1681980768120)(…/Asset/image-20230416150508927.png)]

3.1.1三种泛型定义
  • 泛型类
public class test<E>{   //不确定使用该类的是何种数据类型
}//E可以理解为变量,但不是用来记录数据的,而是纪律数据的类型

public class MyArrayList <E>{
    Object[] obj = new Object[10];
    int size;

    public boolean add(E e){
        obj[size]=e;
        size++;
        return true;
    }
    public E get(int index){
        return (E)obj[index];  //【伪泛型理解类型转换,因此里面实际还是object,只不过添加了个守门员】  
    }
}
  • 方法泛型(只能在本方法中使用)
public <T> void show(T t){
    //不确定形参类型
}
public class ListUtil {

    //把参数二添加到参数一后面
    public static<E> void addAll(ArrayList<E> list,E... e){
        for (int i = 0; i < e.length; i++) {
            list.add(e[i]);
        }
    }

}

  • 泛型接口
public interface 接口名 <E>{
    //实现类给出具体的类型,实现类创建的时候给出具体的类型
}
// 【1】 实现类给出具体的泛型
public class MyImplements implements List<String> {
    @Override
    public int size() {
        return 0;
    }
}

// 【2】 创建时给出具体的泛型
public class My<E> implements List<E> {
    @Override
    public int size() {
        return 0;
    }
}
3.1.2泛型通配符

==设想一种场景,我们定义一种方法,只希望传递ye fu zi类型的数据,如果用泛型方法,那么非这三种引用类型的数据也可以传递,

解决办法就是泛型通配符,?通配符可以进行范围限制

//? extends E:可以传递E和E所有的子类类型
//? super E:可以传递E和E的所有父类类型
public static void method (ArrayList<? extends ye> list){
    //该方法可以接受继承了ye或者ye类型的list
}

3.2Collection(–以下章节为单列–)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qRcJOF6i-1681980768121)(…/Asset/image-20230416100330945.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gqu2QEfg-1681980768121)(…/Asset/image-20230416100633393.png)]

注意: 上述方法如果泛型是自定义,需要该自定义类中重写equal方法,才能保证contains方法正常使用。

3.2.1遍历方式
  • 迭代器遍历

是集合专用的遍历方式

注意点:

  1. 迭代器遍历完毕,指针不会复位【如需再次遍历,需要创建一个新的迭代器】
  2. 循环中只能使用一次next方法,【如果需要在一次循环中多次使用next取到的变量需要用中间变量保存一下】
  3. 迭代器遍历时,不能用集合的方法进行增删改查【如需使用,需要用集合里的方法进行】
  4. 没有索引过界,只有没找到元素异常
// 【1】迭代器方式 默认指向零索引
Collection<String> coll = new ArrayList<>();
Iterator<String> it =coll.iterator();//获取集合的迭代器
if(it.hasNext()){//遍历集合
    String str=it.next();
    if(str.equal("bbb")){
        it.remove();   //用集合方式删除
    }
}

  • for增强遍历

注意点:

  1. 所有的单列集合和数组才能用
  2. 内部原理是个iterator迭代器
  3. 修改for中的变量,不会改变集合中的数据
for(String a:list){
    sout(s);
}
  • lambda表达式遍历
// 【1】匿名内部类实现【底层遍历集合,依次得到每一个元素,把他传给accept方法】
coll.forEach(new Consumer<String>() {
    @Override
    //s依次表示集合中的每个元素
    public void accept(String s) {
        System.out.println(s);
    }
});

// 【2】 lambda表达式【(方法形参)->{方法体}】【和匿名内部类形式对比记忆】
coll.forEach((String s)->{
    System.out.println(s);
});

3.3List集合

Collection的方法List都继承了

有很多索引操作的方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ru5oX5vD-1681980768121)(…/Asset/image-20230416104543135.png)]

3.3.1List系列集合中的两个删除方法
List<Integer> list= new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
//优先调用实际参数和形参完全一致的方法,
list.remove(1);//可以通过索引删除,也可以通过值删除【删除索引1位置的元素】
Integer i=1;
list.remove(i);//【删除1这个元素】
3.3.2List遍历方式

如果需要删除元素,使用迭代器

如果需要添加元素,使用列表迭代器

如果只需要遍历,增强for或者lambda

如果需要操作索引,用普通for

  1. 迭代器(collection 父)
  2. 列表迭代器
// 【1】 是迭代器的子类
ArrayList<String> list = new ArrayList<>();
list.add("1");
list.add("2");
ListIterator<String> it = list.listIterator();
while(it.hasNext()){
    String str=it.next();
    if("2".equals(str)){
        it.add("3");   //          【列表迭代器的添加方法,迭代器没有】
    }
}
  1. 增强for(collection 父)
  2. lambda表达式(collection 父)
  3. 普通for
//【就是根据size get方法获取】
for(size){
    get(i);
}

3.34ist实现类

两种实现类的区别:

  1. ArrayList实现类 数组管理 方便查找,增删慢
  2. LinkedList双向链表管理,查找慢,方便增加
3.4.1ArrayList集合(实现类)

底层:

  1. 数组结构的,数组默认长度是10【如果利用空参创建的集合,默认长度为0】【添加第一个元素时,才会生成长度为10的数组】
  2. 当数组添加满了之后,会自动扩容为1.5倍【如果1.5倍放不下,则会以添加后的实际长度为准】

添加元素原码:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yk9taeJ7-1681980768121)(…/Asset/image-20230416142216057.png)]

image-20230416095619406
ArrayList<String> list =new ArrayList<>();
list.add("as");
list.add("as");
list.add("as");
list.remove("sda");
list.set(0," ");
list.get(1);
list.size();
for(String i:list)
    System.out.println(list.toString());
3.4.2LinkedList集合

底层:

  1. 双向列表结构,查询 慢,增删块,如果操作的是首位元素,速度很快

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RJYVNwt9-1681980768122)(…/Asset/image-20230416143149491.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U3YerPh7-1681980768122)(…/Asset/image-20230416144845050.png)]

3.4.3迭代器实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I7OffWDd-1681980768122)(…/Asset/image-20230416145607817.png)]

3.5 Set集合

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LE4Z6qNP-1681980768122)(…/Asset/image-20230416160643669.png)]

3.6Set实现类

Set实现类区别:

  1. HashSet:存取无序 不重复 无索引
  2. LinkedHashSet: 【存取有序】 不重复 无索引
  3. TreeSet:【可排序】 不重复 无索引

集合选择:

  1. 如果需要去重默认使用HashSet
  2. 如果要求有序,才使用LinkedHashSet
3.6.1HashSet

底层原理

  1. 哈希表存储数据
  2. 哈希表是增删改查性能都较好的结构

哈希表组成:

  1. jdk8之前 数组+链表
  2. jdk8开始:数组+链表+红黑树

使用注意点:

  1. 如果存储的是自定义数据类型,需要重写equals和hashCode方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SufNtJYH-1681980768122)(…/Asset/image-20230416161117421.png)]

**PS:**扩容因子就是扩容时机,以为0.75为例,如果当前元素为16*0.75=12的时候就会扩容(扩容为当前的二倍)。


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e1us0VnK-1681980768123)(…/Asset/image-20230416161413986.png)]

3.6.2LinkedHashESet

底层原理和父类相同

和父类不同的特点:

  1. 保证存取的顺序,双链表来保证。
  2. 添加元素时会链接上个元素,上个元素也会链接下个元素
3.6.3 TreeSet

底层:

  1. 基于红黑树的数据结构实现的

特定:

  1. 可以根据元素值大大小排序
  2. 添加元素的时候默认从小到大的排序
  • 自定义类型的排序
// 【1】 默认排序规则  【默认使用这种方式】
public class Student implements Comparable<Student>{
    private int age;
    private String name;
    @Override
    public int compareTo(Student o) {
        //指定排序规则,例如按照年龄升序【this表示当前,o表示需要比较的】
        return this.getAge()-o.getAge();
        return this.getName()-o.getName();
    }
}

// 【2】 比较器比较,在拆功能键TreeSet对象时候,传递比较器Comparator指定规则【优先使用这种方式】
// o1表示当前元素,o2表示比较的元素
TreeSet<String> treeSet = new TreeSet<>((o1, o2) -> {
    int i = o1.length() - o2.length();
    i= i==0 ? o1.compareTo(o2):i;//如果长度相同调用默认的排序方法,否则就用新的排序方法
    return i;  //【如果需要大到小排序,return -i即可】
});
treeSet.add("a");
treeSet.add("asdf");
treeSet.add("sadf");
System.out.println(treeSet);

3.7 Map(–以下章节为双列)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xAVEwnPs-1681980768123)(…/Asset/image-20230417144149291.png)]

3.7.1常见方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9uef8zK2-1681980768123)(…/Asset/image-20230417142428109.png)]

注意:以上方法所有实现类都可以用

// 【1】 put方法的细节
put如果不存在,直接添加键值对,否则会覆盖,并且把覆盖的值返回

3.7.2遍历
  • key遍历
// 【1】遍历方法通过key遍历。
Set<string> keys = map.keySet();  //【返回一个set集合】
for (String key : keys){
    sout(key);
    sout(map.get(key));
}
  • key-value对遍历
// 【1】 依次获取每个键值对,通过getkey和getvalue获取每个键和值
Set<Map.Entry<String,String>> entries = map.entrySet();   //java中entry代表键值对
for(Map.Entry<String,String> entry:entries){
    sout(entry.getKey());
    sout(entry.getValue());
}

  • lambda表达式遍历
HashMap<String, String> map = new HashMap<>();
map.put("1","123");
map.put("2","236");
map.put("3","369");
map.forEach((key, value) -> System.out.println(key+"->"+value));

3.8Map实现类

3.8.1 HashMap

方法用map的方法api即可

特点(所有map的特点都和key有关):

  1. 无序,不重复,无索引
  2. 底层原理和hashSet的底层一摸一样(只不过需要用到key)
  3. 如果键存储的时自定义对象,需要重写hashCode和equals方法。值不需要
3.9.2LinkedHashMap

特点:

  1. 有序,不重复,无索引(实现和LinkedHashSet一样,双向链表来保证)
3.9.3TreeMap

特点:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-amFF9HIA-1681980768123)(…/Asset/image-20230417150826291.png)]

3.9.4 HashMap和TreeMap的原码(底层原理)

集合进阶-13-HashMap源码超详细解析(一)_哔哩哔哩_bilibili

3.9Collections工具类

基本上都是静态方法

用类名.方法名来做

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RPEIuPtF-1681980768124)(…/Asset/image-20230417152135272.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PiXFKFfi-1681980768124)(…/Asset/image-20230417152210597.png)]

3.10 不可变集合

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5trMqByH-1681980768124)(…/Asset/image-20230417153016903.png)]

List<String> list = List.of("1234", "1234", "1234", "12343214");
list.forEach(new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
});
  • 创建map集合的不可变数组

注意map里面of的参数最多10个,

如果需要传递多个,需要把键值对看作整体,用ofEntries方法

// 【1】 ofEntries方法,传递可变长度键值对
HashMap<String, String> hm = new HashMap<>();
hm.put("a", "1");
Set<Map.Entry<String, String>> entries = hm.entrySet();
//把entries变为数组,指定类型,形参代表具体的类型
//形参这里有个长度,entries集合有个长度,如果entries长度大于数组长度,会重新创建数组,否则不会创建新的数组,直接用
Map.Entry[] arr = entries.toArray(new Map.Entry[0]);
//创建不可变map
Map map = Map.ofEntries(arr);
System.out.println(map);

// 【2】Map.copyOf创建不可变map 【jdk 10之后才支持】
HashMap<String, String> hm = new HashMap<>();
hm.put("a", "1");
Map<String, String> map = Map.copyOf(hm);

第四章 文件和IO流

4.1File

File对象的

  • File对象表示一个路径,可以是文件路径 ,也可以是文件夹的路径
  • 这个路径可以是存在的也可以是不存在的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oEjGQEm1-1681980768124)(…/Asset/image-20230418102036385.png)]

String str="c:\\usersa\\lienware\\Desktop\\a.txtt";
File f1=new File(str);
sout(f1);//
File f1=new File(parent,child);

4.1.1 判断和获取

文件对象.方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eYODt9pE-1681980768125)(…/Asset/image-20230418102532352.png)]

4.1.2创建删除

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A1o8zKeJ-1681980768125)(…/Asset/image-20230418102734844.png)]

// 【1】 创建新的空文件
File f1=new File("E:\\a.txt");   //路径存在但是文件不存在【如果不包含后缀,会创建一个无后缀的文件
boolean b=f1.createNewFile();    //【创建不存在的文件】【如果文件存在,则会创建失败】
System.out.println(b);

// 【2】 创建单级文件夹   
File f1=new File("E:\\test");   //【只能创建一个文件夹】【路径存在会false】
boolean b=f1.mkdir();
System.out.println(b);

// 【3】 创建多级文件夹
File f1=new File("E:\\test\\test1\\tst3");
boolean b=f1.mkdirs();
System.out.println(b);

// 【删除文件】
File f1=new File("E:\\a.txt");   
boolean b=f1.delete();    //【删除不走回收站】【优先删除文件】【如果是文件夹删除空文件夹】
System.out.println(b);
4.1.3 获取和遍历

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HimqsmyQ-1681980768125)(…/Asset/image-20230418103919239.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-piRx9CSW-1681980768125)(…/Asset/image-20230418104114222.png)]

4.2 IO流

读写文件的数据,或者网络中的数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vNkki7io-1681980768125)(…/Asset/image-20230418145745665.png)]

注意:只有 txt和md文件是纯文本文件

  • 体系结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VRWEqi6U-1681980768126)(…/Asset/image-20230418170840712.png)]

4.2.1字符集

详将看 IO流-14-字符集详解(Unicode)_哔哩哔哩_bilibili

4.3字节流

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qkqh2XNn-1681980768126)(…/Asset/image-20230418150114855.png)]

  • 例子:小文件copy
// 【1】 小文件拷贝
public class CopyText {
    public static void main(String[] args) throws IOException {
        //创建输入输出流
        FileInputStream fis = new FileInputStream("a.txt");
        FileOutputStream fos = new FileOutputStream("b.txt");
        //先读一个,然后写一个
        int b;
        while((b=fis.read())!=-1){
            fos.write(b);
        }
        //先开的流后关
        fos.close();
        fis.close();
    }
}

// 【2】 ⭐ 大文件拷贝

4.3.1 FileOutputStream

原理

  1. 创建通道[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LhobUFgL-1681980768126)(…/Asset/image-20230418150604497.png)]

  2. 传输数据[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qDdO41h7-1681980768126)(…/Asset/image-20230418150614075.png)]

关闭通道[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iE8jZq0d-1681980768127)(…/Asset/image-20230418150625588.png)]

  • 创建通道
  1. 可以是字符串表示的路径,也可以是File对象
  2. 文件不一定需要纯在(不存在会自动创建),但是父级路径要存在。
  3. 如果文件已经存在,会清空该文件。
FileOutputStream fs = new FileOutputStream("a.txt");

// 【3】 打破特点3续写开关【第二个参数是续写开关】
FileOutputStream fs = new FileOutputStream("a.txt",true);
  • 写入数据
  1. write参数是整数,但实际上是其对应的字符
//================================write()写入方法=======================================
// 【1】 写入一个数据
fs.write(97);

// 【2】 写入一个数组
public static void main(String[] args) throws IOException {
    FileOutputStream fs = new FileOutputStream("a.txt");
    byte[] bytes={97,98,99,100,101,123};
    fs.write(byte,i,j);//【写入数组下标[i,j]区间的数据】
    fs.close();

}

// 【3】 写入一个字符串【用byte数组】  换行写
FileOutputStream fos = new FileOutputStream("a.txt");
//创建一个字符串,然后变为字节数组
String str="sadkfjklsadf";
byte[] bytes = str.getBytes();
String str2="666";
byte[] bytes2=str2.getBytes();
String wrap="\r\n";  //【\r是移动光标到最前面\n是换行】
byte[] bytes3=wrap.getBytes();
fos.write(bytes);
fos.write(bytes3);         //【换行操作】
fos.write(bytes2);

  • 释放资源
  1. 如果不释放流,java会一直占用该文件
fs.close();
4.3.2 FileInputStream
  1. 原理过程和FileOutputStream类似
  2. 文件不存在会报错
  • 创建通道
FileInputStream fis = new FileInputStream("a.txt");
  • 读入数据

fis.read();

  1. 有一个返回值。一个一个度,读到返回读到的值,读不到返回-1,
// 【1】  读取一个数据
public static void main(String[] args) throws IOException {
    FileInputStream fis = new FileInputStream("a.txt");
    int read = fis.read();
    System.out.println((char)read);
    fis.close();
}

// 【2】 ⭐循环读取
public static void main(String[] args) throws IOException {
    FileInputStream fis = new FileInputStream("a.txt");
    int b;
    while( (b=fis.read())!=-1){  //【循环判断这里读了依次,因此读文件的指针会移动】
        System.out.print((char)b);
    }
    fis.close();
}

// 【3】 数组读取 【尽可能读取满整个数组,如果不满,优先覆盖数组前面的数据】

  • 关闭通道
fis.close();
4.3.2编码和解码(输入写入中文)
String str="asd上的飞机f";
byte[] bytes = str.getBytes("utf-8");// 用utf-8编码
String str2=new String(bytes,"utf-8");// 用utf-8解码,

4.4字符流

为什么会有乱码:

  1. 中文没有读取完毕(解决办法就是字符流)
  2. 编码解码用的不是一个

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JU7xBMmU-1681980768127)(…/Asset/image-20230418163914851.png)]

4.4.1FileReader

读数据

底层:还是字节流,如果遇到中文,会读取多个字节。

  • 创建字符输入流对象
FileReader fr = new FileReader("a.txt");
  • 读取数据

read默认一次读一个字节,遇到中文读取多个字节,然后解码转成10进制(该十进制表示对应字符集上该字符的编码)

// 【1】 空参read()方法读取
public static void main(String[] args) throws IOException {
    FileReader fr = new FileReader("a.txt");
    int read;
    while((read=fr.read())!=-1)
        System.out.print((char)read);
}

// 【2】 数组读取,【char数组和字节流不同,字节流是bytes数组】
public static void main(String[] args) throws IOException {
    FileReader fr = new FileReader("a.txt");
    char[] chars = new char[2];   //【一次读取两个字符】
    int len;
    while((len=fr.read(chars))!=-1){
        System.out.print(new String(chars,0,len));
    }
}
  • 释放资源
fr.close();
4.4.2FileWriter
  • 创建字符流输出对象
  1. 参数是字符串或者file对象
  2. 文件不存会创建,但是父级路径要存在
  3. 有续写开关
  • 写出数据到文件

写出的数据是整数,则最终写出的是该整数在字符集上的结果

// 【1】 写出一个string到文件
public static void main(String[] args) throws IOException {
    FileWriter fw = new FileWriter("a.txt"true);//【第二个参数是学些开关】
    String str="阿斯顿积分考虑 爱看书的肌肤  发生的纠纷 但是,阿斯顿积分他奥兰多开始发,阿斯利康的飞机 覅放天地方";
    fw.write(str,off,len);//从str[0ff]开始写入长度为len
    fw.close();
}
  • 释放资源
fw.close();
4.4.3底层
  1. 字符流有缓冲区,字节流没有,每次尽可能装满缓冲区
  2. 读取一次之后,如果再次new新的流,然后再读,实际上读的是缓冲区的数据。文件中其他数据就不读了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4gJ4xgRu-1681980768127)(…/Asset/image-20230418170222556.png)]

IO流-21-字符输出流的底层原理超详解_哔哩哔哩_bilibili

4.5缓冲流(–以下章节为高级流)

任何有缓冲区的流,再读取大文件的时候,需要刷新缓冲区

4.5.1体系结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0zjmF8tg-1681980768127)(…/Asset/image-20230418171020802.png)]

4.5.2字节缓冲流
  • 介绍

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-64m3tVrK-1681980768127)(…/Asset/image-20230418171052510.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xA9qt29o-1681980768128)(…/Asset/image-20230418171104531.png)]

  • 实例,字节缓冲流copy文件
public static void main(String[] args) throws IOException {
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt",true));//读入文件
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("my.txt"));
    //循环读取,写道目的地
    int len;
    byte[] bytes=new byte[1024];
    while((len=bis.read(bytes))!=-1){
        bos.write(bytes,0,len);
    }
    bos.close();  //【会帮我们自动关闭基本流】
    bis.close();
}
  • 原理

提升效率的原理

  1. 输入的时候有一个8192的缓冲区,同理输出也有
  2. 输入输出数据的时候会一次性读入读出 所有缓冲区中的数据
  3. 我们读取数据的时候实际上是从输入缓冲区和输出缓冲区之间

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P3qKOcYx-1681980768128)(…/Asset/image-20230419093213823.png)]

4.5.3字符缓冲流
  • 介绍

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ODZefjc1-1681980768128)(…/Asset/image-20230419093401619.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NSMNtDbG-1681980768128)(…/Asset/image-20230419093451336.png)]

  • 实例
//1创建集合对象 ,以为String为例 JDK7之后
ArrayList<String> list = new ArrayList<>();
list.add("1");
list.add("2");
ListIterator<String> it = list.listIterator();
while(it.hasNext()){
    String str=it.next();
    if("2".equals(str)){
        it.add("3");   //迭代器本身的添加方法
    }
}

4.6转换流(属于字符流)

InputStreamReader 字符转换输入流(读数据)

OutputStreamWriter 字符转换输出流(写数据)

  1. 字符流和字节流之间的桥梁[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EyM1Kd6b-1681980768129)(…/Asset/image-20230419094516543.png)]
  • 例子
// 【1】 自定字符编码读入写出数据【jdk 10】
FileReader fr = new FileReader("a.txt", Charset.forName("utf-8"));  //【第二个参数不能直接写编码,要用Charset.forNmae("")】
FileWriter fw = new FileWriter("asd.txt", Charset.forName("utf-8"));
int ch;
while((ch=fr.read())!=-1){
    System.out.println((char)ch);
    fw.write(ch);
}
fw.close();
fr.close();

// 【2】 利用字节流读取一行数据
public static void main(String[] args) throws IOException {
    InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//创建字节转字符流
    BufferedReader br=new BufferedReader(isr);//根据字符流创建字符缓冲流
    String str;
    while((str=br.readLine())!=null){
        System.out.println(str);
    }
    br.close();
    isr.close();
}

4.7序列化/反序列化流(操作对象 属于字节流)

主要用于把对象序列化写入本地/反序列化读取对象

4.7.1序列化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MtVXO8sn-1681980768129)(…/Asset/image-20230419100859012.png)]

  • 序列化例子
Student stu = new Student("asdf", 123);
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("stu.txt"));
os.writeObject(stu);   //把对象写入出去
os.close();
public class Student implements Serializable ,Comparable<Student>//【写出的类需要实现Serializable接口,该接口为标记接口无方法】
4.7.2反序列化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-emGjEGsv-1681980768129)(…/Asset/image-20230419101531609.png)]

  • 反序列化例子
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("stu.txt"));
Student o = (Student) ois.readObject();
System.out.println(o);
4.7.3注意点
  1. 序列化后,对象如果改变,那么反序列化将会失败
  2. 序列化的时候把所有的成员变量都序列化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P9i1HxbL-1681980768130)(…/Asset/image-20230419102634924.png)]

1的解决办法(定义版本号)

// 【1】 第一种办法
public class Student implements Serializable{
    private static final long serialVersionUID=1L;//【固定版本号】
    private int age;
    private String name;
}

// 【2】 第二种办法
//设置idea,然后利用idea自动生成版本号


2的解决办法 如果有不想被序列化的成员变量怎么办

public class Student implements Serializable{
    private static final long serialVersionUID=1L;//【固定版本号】
    private int age;
    private String name;
    private transient String address; //【transient修饰的成员变量不会被序列化】
}
// 此时如果反序列化读取到transient修饰的变量时为默认初始值

4.8 打印流(字节流、字符流)

  1. 打印流只可以把数据写入到文件
  2. 特有的方法可以实现数据原样写
  3. 特有方法可以实现自动刷新,自动换行
4.8.1字节打印流

无缓冲区

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IT487jPU-1681980768130)(…/Asset/image-20230419103404550.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SJNzN0Pu-1681980768130)(…/Asset/image-20230419103529228.png)]

  • 例子
// 【1】
PrintStream ps = new PrintStream(new FileOutputStream("print.txt"), true, Charset.forName("utf-8"));
//写出数据
ps.println("asdfds"+134);   //【换行输出】
ps.printf("%s 爱上了 %s","阿珍","阿强");   //【占位符输出】
ps.println();
ps.println(true);    //【直接打印true到文件】
ps.close();
4.8.2字符打印流

有缓冲区 ,熟读更快

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HfYqsRXt-1681980768130)(…/Asset/image-20230419104054939.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8b38NOKx-1681980768131)(…/Asset/image-20230419104103677.png)]

  • 例子
// 【1】 
PrintWriter pw = new PrintWriter(new FileWriter("text1.txt"), true);
pw.println("打开附件赛了可就奥萨蒂撒赖扩大c");
pw.print("你好");
pw.close();

4.9压缩/解压缩流(字节流,输入流,输出流)

传输大文件

4.9.1解压缩流

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0pySo6lb-1681980768131)(…/Asset/image-20230419105250434.png)]

// 【1】 解压文件的例子
public class Hello {
    public static void main(String[] args) throws IOException, ClassNotFoundException {

        File src = new File("E:\\test.zip");
        File dest = new File("E:\\");


    }
    public static void unzip(File src,File dest) throws IOException {
        ZipInputStream zip = new ZipInputStream(new FileInputStream(src));
        //获取到的文件夹或者文件
        ZipEntry entry;
        while((entry=zip.getNextEntry())!=null){
            //如果是文件夹就要在目的地处创建同样的文件夹
            if(entry.isDirectory()){
                File file = new File(dest,entry.toString());//dest是根目录,第二个参数是需要写的目录
                file.mkdirs();//可能是多层级,那么需要mkdirs;
            }else{
                FileOutputStream fos = new FileOutputStream(new File(dest, entry.toString()));
                int b;
                while((b=zip.read())!=-1){
                    fos.write(b);
                }
                fos.close();  //关闭一个文件
                zip.closeEntry();  //表示压缩包里的一个文件已经操作完毕了
            }
        }
        zip.close();  //所有文件和文件夹都处理完毕了
    }
}
4.9.2压缩流

IO流-41-压缩流-压缩单个文件_哔哩哔哩_bilibili

4.10常用工具包 Commons-io /hutool

4.10.1 Commons-io

提高io流的效率

如何使用:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4GwrKxs4-1681980768131)(…/Asset/image-20230419145132523.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ML37CZOv-1681980768131)(…/Asset/image-20230419145037898.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FiX06Nik-1681980768131)(…/Asset/image-20230419145140988.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lRpKD5nF-1681980768132)(…/Asset/image-20230419145219658.png)]

4.10.2 Hutool包

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GCn1ysas-1681980768132)(…/Asset/image-20230419153745875.png)]

Hutool — 🍬A set of tools that keep Java sweet.

第五章 多线程&JUC

5.1多线程创建基本写法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-34oVqN9c-1681980768132)(…/Asset/image-20230419160609825.png)]

5.1.1继承Thread类的方式 重写run方法
public class myThread extends Thread{
    public void run(){
        //需要线程执行的代码
        for(int i =0;i<100;i++){
            System.out.println(getName()+"hello");//获取运行的线程的名字
        }
    }
}
class test{
    public static void main(String[] args) {
        myThread t1 = new myThread();
        myThread t2 = new myThread();
        t1.setName("线程1");  //设置线程名字
        t2.setName("线程2");

        t1.start();
        t2.start();
    }
}
5.1.2实现Runable接口,然后实现Run方法
public class myThread implements Runnable {
    //Runnable是函数式接口
    public void run(){
        //需要线程执行的代码
        for(int i =0;i<100;i++){
            //获取到当前线程对象
            Thread thread = Thread.currentThread();
            System.out.println(thread.getName()+"hello");//获取运行的线程的名字
        }
    }
}
class test{
    public static void main(String[] args) {
        myThread my = new myThread();  //创建对象
        Thread thread1 = new Thread(my,"线程名字");  //把实现多线程方法的类放到Thread中
        Thread thread2 = new Thread(my);  //把实现多线程方法的类放到Thread中
        thread1.setName("线程1");
        thread2.setName("线程2");
        thread1.start();
        thread2.start();
    }
}
5.1.3 第三种多线程,可以获取线程运行的结果
  1. 实现callable接口
  2. 重写call有返回值,表示多线程运行结果
  3. 创建自己的类对象(表示多线程要执行的任务)
  4. 创建FutureTask的对象
  5. 创建Thread对象开始线程
public class myThread implements Callable<Integer> {
    //接口后面的泛型表示返回的类型
    @Override
    public Integer call() throws Exception {
        int sum=0;
        for (int i =0;i<=100;i++){
            sum=sum+i;
        }
        return sum;
    }
}
class test{
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        myThread myThread = new myThread();//创建自己的类
        FutureTask<Integer> integerFutureTask = new FutureTask<Integer>(myThread); //多线程管理工具(用于获取执行结果)
        Thread thread = new Thread(integerFutureTask);  //创建多线程
        thread.start();//启动多线程
        Integer integer = integerFutureTask.get();  //通过线程管理类获取执行结果
        System.out.println(integer);
    }
}

5.2Thread常用方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dYeIiVE9-1681980768132)(…/Asset/image-20230419160751671.png)]

5.2.1设置线程名字
// 【1】 可以用setName(间5.1.1)也可以用构造方法
public class myThread extends Thread{
    public myThread() {
        super();
    }

    public myThread(String name) {
        super(name);
    }
    public void run(){
        //需要线程执行的代码
        for(int i =0;i<100;i++){
            System.out.println(getName()+"hello");//获取运行的线程的名字
        }
    }
}
class test{
    public static void main(String[] args) {
        myThread t1 = new myThread("飞机:");
        myThread t2 = new myThread("坦克:");
        t1.setName("线程1");  //设置线程名字
        t2.setName("线程2");
        t1.start();
        t2.start();
    }
}
5.2.2 线程优先级

优先级越高,越容易强到cpu

  1. main优先级最高为1
  2. 优先级从1-10
public class myThread implements Runnable {
    public void run(){
        //需要线程执行的代码
        for(int i =0;i<100;i++){
            //获取到当前线程对象
            Thread thread = Thread.currentThread();
            System.out.println(thread.getName()+"hello");//获取运行的线程的名字
        }
    }
}
class test{
    public static void main(String[] args) {
        myThread my = new myThread();  //创建对象
        Thread thread1 = new Thread(my,"飞机");  //把实现多线程方法的类放到Thread中
        Thread thread2 = new Thread(my,"af d");  //把实现多线程方法的类放到Thread中
        System.out.println(thread1.getPriority());// 获取线程优先级
        thread1.start();
        thread2.start();
    }
}
5.2.3守护线程

其他非守护线程执行完毕之后,守护线程会陆续结束

Thread thread2 = new Thread(my,"af d");  
thread2.setDaemon();//其他线程执行完毕后该线程自动停止
5.2.4礼让插入线程(了解)
// 【1】礼让线程
public class myThread implements Runnable {
    public void run(){
        //需要线程执行的代码
        for(int i =0;i<100;i++){
            //获取到当前线程对象
            Thread thread = Thread.currentThread();
            System.out.println(thread.getName()+"hello");//获取运行的线程的名字
            Thread.yield();//【出让当前cpu的执行权】【如果不出让当该线程获取到cpu后一直等到别人抢占cpu才会停止】
        }
    }
}
class test{
    public static void main(String[] args) {
        myThread my = new myThread();  //创建对象
        Thread thread1 = new Thread(my,"飞机");  //把实现多线程方法的类放到Thread中
        Thread thread2 = new Thread(my,"af d");  //把实现多线程方法的类放到Thread中
        

        thread1.start();
        thread2.start();
    }
}

// 【2】 插入线程
public class myThread implements Runnable {
    public void run(){
        //需要线程执行的代码
        for(int i =0;i<100;i++){
            //获取到当前线程对象
            Thread thread = Thread.currentThread();
            System.out.println(thread.getName()+"hello");//获取运行的线程的名字
            Thread.yield();//出让当前cpu的执行权
        }
    }
}
class test{
    public static void main(String[] args) throws InterruptedException {
        myThread my = new myThread();  //创建对象
        Thread thread1 = new Thread(my,"飞机");  //把实现多线程方法的类放到Thread中
        Thread thread2 = new Thread(my,"af d");  //把实现多线程方法的类放到Thread中
        thread1.start();
        thread1.join();  //只有当thread1的线程全部执行完毕,才会接着执行后面的代码;
        thread2.start();
    }
}

5.3线程

5.3.1线程生命周期

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AjP4ThqA-1681980768133)(…/Asset/image-20230419162607444.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bTjLIktV-1681980768133)(…/Asset/image-20230420101038243.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ek4SdHTw-1681980768133)(…/Asset/image-20230420101219305.png)]

5.3.2线程安全问题

互斥和同步问题

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-231h4xKk-1681980768133)(…/Asset/image-20230419162949145.png)]

    同步代码块不能写道循环外面

// 【1】 同步代码块解决买票安全问题
public class myThread extends Thread {
    static int tickets=100;//户次资源
    static Object obj = new Object();//锁对象 要是唯一的static修饰

    public void run(){
        while(true){
            synchronized (obj){  //【这里可以用MyThread.class字节码文件对象,是唯一的】
                if (tickets>0){
                    try {
                        sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    tickets--;
                    System.out.println(getName()+"卖出一张票还剩"+tickets+"张票");
                }else{
                    break;
                }
            }
        }
    }
}
class test{
    public static void main(String[] args) throws InterruptedException {
        myThread t1 = new myThread();
        myThread t2 = new myThread();
        myThread t3 = new myThread();
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}
  • 同步方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dkLbRedv-1681980768133)(…/Asset/image-20230419163905894.png)]

// 【2】 同步方法
import javax.swing.plaf.TableHeaderUI;
import java.util.concurrent.Callable;

public class myThread implements Runnable {
    int tickets=0;//互斥资源

    @Override
    public void run(){
        while(true){
            if(method()) break;
            //在同步方法外面睡才能更加清晰的看到多线程效果【千万不要在同步方法里面睡啊,否则还是一个方法执行到底】
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private synchronized boolean method() {
        if (tickets==100){
            return true;
        }else{
            tickets++;
            System.out.println(Thread.currentThread().getName()+"卖出第"+tickets+"张票");
        }
        return false;
    }
}
class test{
    public static void main(String[] args) throws InterruptedException {
        myThread t = new myThread();
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();
    }
}
5.3.3 lock锁

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fWPDS6V8-1681980768134)(…/Asset/image-20230419170039817.png)]

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class myThread extends Thread {
    static int tickets=100;//【互斥资源】
    static Lock lock= new ReentrantLock();  //【需要保证只有一个对象】

    public void run(){
        while(true){
            lock.lock();//上锁
            try {
                if (tickets>0){
                    sleep(100);
                    tickets--;
                    System.out.println(getName()+"卖出一张票还剩"+tickets+"张票");
                }else{
                    break;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally{
                lock.unlock();
            }
        }
    }
}
class test{
    public static void main(String[] args) throws InterruptedException {
        myThread t1 = new myThread();
        myThread t2 = new myThread();
        myThread t3 = new myThread();
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}
5.3.4 生产者消费者的实现
  • 等待唤醒
//互斥资源
public class Desk {
    public static int foodFlag=0;//表示是否有面条
    public static int count=10;
    public static Object Lock=new Object();
}
// 生产者
public class produce extends Thread{
    @Override
    public void run() {
        while(true){
            synchronized (Desk.Lock){
                if(Desk.count==0){
                    break;
                }else{
                    //判断是否有食物,如果有就等待
                    if(Desk.foodFlag==1){
                        try {
                            Desk.Lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }else{
                        System.out.println("做面条");
                        Desk.foodFlag=1;
                        Desk.Lock.notifyAll();
                    }
                }

            }
        }
    }
}
// 消费者
public class consumer extends Thread{
    @Override
    public void run() {
        while(true){
            synchronized (Desk.Lock){
                if(Desk.count==0){
                    break;
                }else{
                    //先去判断是否有东西,有就开吃
                    if(Desk.foodFlag==0){
                        try {
                            //没有东西可吃
                            Desk.Lock.wait();//让当前线程和锁绑定
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                    }else{
                        Desk.count--;
                        System.out.println("吃货正在吃面条,还能再吃"+Desk.count+"!1");
                        Desk.Lock.notifyAll();
                        Desk.foodFlag=0;
                    }

                }

            }
        }
    }
}
// 测试
public class Hello {
    public static void main(String[] args)  {
        produce produce = new produce();
        consumer consumer = new consumer();
        produce.setName("生产则");
        consumer.setName("消费者");
        produce.start();
        consumer.start();


    }
}
  • 阻塞队列

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lp1uA3zl-1681980768134)(…/Asset/image-20230420095957422.png)]

public class Hello {
    public static void main(String[] args)  {
        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);

        produce produce = new produce(queue);
        consumer consumer = new consumer(queue);
        produce.setName("生产则");
        consumer.setName("消费者");
        produce.start();
        consumer.start();


    }
}

//生产者
public class produce extends Thread{
    ArrayBlockingQueue<String> queue;

    public produce(ArrayBlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        while(true){
            try {
                queue.put("面条");// 实际上下面的打印语句在锁的后面,因此结果会出现连续的输出
                System.out.println("厨师做了一碗面条");

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

// 消费者
public class consumer extends Thread{
    ArrayBlockingQueue<String> queue;

    public consumer(ArrayBlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        while(true){
            try {
                String food = queue.take();
                System.out.println(food);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

5.3.5 线程池

线程池用来管理线程,执行完毕后线程不会消失,基于保存在线程池中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yDagjhQF-1681980768134)(…/Asset/image-20230420101512029.png)]

  • 代码实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W6xcPUvQ-1681980768134)(…/Asset/image-20230420101551564.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hAsLjAqU-1681980768135)(…/Asset/image-20230420101614450.png)]

// 【1】 工具类创建线程池对象
public class Hello {
    public static void main(String[] args)  {
        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);
        //获取线程池
        ExecutorService pool1 = Executors.newFixedThreadPool(3);
        //提交任务
        pool1.submit(new produce(queue));
        pool1.submit(new consumer(queue));
        //销毁
        pool1.shutdown();
    }
}


  • 线程池具体

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t1KHOCh2-1681980768135)(…/Asset/image-20230420102952964.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2hApAyJA-1681980768135)(…/Asset/image-20230420102906144.png)]

public class Hello {
    public static void main(String[] args)  {
        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);

        //自定义线程池
        ThreadPoolExecutor pool1 = new ThreadPoolExecutor(
                3,
                6,
                60,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()   //任务拒绝策略是静态内部类,用new 外部类.内部类来创建
        );
        //提交任务
        pool1.submit(new produce(queue));
        pool1.submit(new consumer(queue));


        //销毁
        pool1.shutdown();

    }
}
  • 线程池参数选择

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hVCQYaRt-1681980768135)(…/Asset/image-20230420103652256.png)]

Java能用多少资源[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dTB8E3Iw-1681980768135)(…/Asset/image-20230420103838449.png)]

5.3.6 多线程额外资料

多线程&JUC-33-多线程的额外扩展内容_哔哩哔哩_bilibili

第六章 注解(Annotation)和反射

6.1注解

  1. 注解不是程序本身,可以对程序做出解释和注释(comment)没什么区别
  2. 可以被其他程序读取(编译器)
  3. @+名字(需要被读取的值),通过反射访问
6.1.1内置注解
  1. @Override
  2. @Deprecated (不推荐使用)
  3. Suppress Warning(“all”) (镇压警告,消除方法/类中的警告)

6.1.2元注解

注解其他注解(在其他注解定义的时候使用)

  1. @Target 描述注解的适用范围
  2. @Retention 表示需要什么级别保存该注解信息,用于描述注解的生命周期。(SOURC<CLASS<RUNTIME)
  3. @Documented 说明该注解被包含在javadoc中
  4. @Inherited 说明子类可以继承父类中的该注解
// 【1】 
@Target(value = ElementType.METHOD)//  只能在方法上
@Retention(value = RetentionPolicy.RUNTIME)  //表示我们的注解在运行时还有效
@Documented //我们的注解会生成到javadoc中
@Inherited //子类可以继承父类写的本注解
@interface MyAnnotation{
}
@MyAnnotation   //这里会报错,
public class Hello {
    @MyAnnotation  //自定义的注解写道方法上可以
    public static void main(String[] args)  {
        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);
    }
}
6.1.3自定义注解

@interface 注解名

@Target(value = ElementType.METHOD)//  只能在方法上
@Retention(value = RetentionPolicy.RUNTIME)  //表示我们的注解在运行时还有效
@Documented //我们的注解会生成到javadoc中
@Inherited //子类可以继承父类写的本注解
@interface MyAnnotation{
    String name() default "as";//这是注解的参数 删除类型 参数名() 默认值为as
    int age() default 0;
    int id() default -1;//默认不存在indexof找不到返回-1
    String[] Schools();
}

@MyAnnotation(name="asdf",Schools = {"湖南科技大学","南京航空航天大学"},age=18,id = 12341)
public static void main(String[] args){
    
}

6.2反射

  1. 把静态变为动态
  2. 反射机制允许程序在执行期间借助Reflection API【获取任何类】的【任何内部信息】,并直接操作任意对象的内部属性及其方法
  3. 反射允许对成员变量,成员方法和构造方法的信息进行编程访问(idea的代码补全就是利用反射功能,展示该类的所有方法,包括给出方法的所有形参)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1yZVXUHy-1681980768136)(…/Asset/image-20230420140302125.png)]
  4. 获取的时候是根据Class对象获取

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2qnLe3Oz-1681980768136)(…/Asset/image-20230420134658118.png)]

6.2.1获得Class对象 三种方式
// 【1】 第一种  Class.forName("类全名")【最常用】
public class Hello {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c1=Class.forName("User");   //【参数是包名+类名的格式】
        System.out.println(c1);
    }
}

// 【2】 类名.class 【当作参数传递】
public class Hello {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c1=Student.class;    
        System.out.println(c1);
    }
}

// 【3】 对象名.getclass();  【已经有了这个类的对象的时候才使用】
public class Hello {
    public static void main(String[] args) throws ClassNotFoundException {
        Student s= new Student();
        Class class=s.getClass();   
        System.out.println(c1);
    }
}
6.2.2利用Class对象获取类的构造方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eXh6rEiS-1681980768136)(…/Asset/image-20230420141007187.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eb1SXgkw-1681980768136)(…/Asset/image-20230420141026649.png)]

// 【1】 获取构造方法
public class Hello {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        Class c1=Class.forName("User");   //获取User类的Class对象,一个类被加载后,类的整个结构都会被封装在Class对象中
        Constructor[] cons = c1.getConstructors();  //获取public构造方法【不加s获取单个,默认获取】
        for (Constructor con:cons){
            System.out.println(con);
        }
        Constructor[] cons2=c1.getDeclaredConstructors();  //获取所有构造方法【不加s获取单个】
        Constructor cons3=c1.getDeclaredConstructor(String.class);  //获取单个构造方法,其中获取到的是构造方法只有一个String类型形参的那个
        for (Constructor con : cons2) {
            System.out.println(con);
        }

    }
}

// 【2】 获取构造方法里面的内容
Class c1=Class.forName("User"); 
Constructor cons3=c1.getDeclaredConstructor(String.class,int.class); 
int modifiers = cons3.getModifiers();             //获取修饰符等级
Parameter[] parameters = cons3.getParameters();         //获取所有参数

cons3.setAccessible(true);     //【如果获取到的是私有构造,需要这条语句才可以利用该私有构造创建对象】【暴力反射,暂时忽略权限】
User user = (User) cons3.newInstance("asdf",12);  //利用获取到的构造方法创建对象
System.out.println(user);
6.2.3 获取成员变量

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P41V7o77-1681980768137)(…/Asset/image-20230420142817089.png)]

// 【1】 获取成员变量
Class c1=Class.forName("User");
Field[] filds=c1.getFields();    //其他方法类似
for (Field fild : filds) {
    System.out.println(fild);
}

// 【2】 获取成员变量的内容
public class Hello {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class c1=Class.forName("User");
        Field[] filds=c1.getDeclaredFields();
        for (Field fild : filds) {
            System.out.println("成员变量"+fild);
            String name = fild.getName();  //获取该成员变量的名字
            System.out.println("成员变量的名字"+name);
            Class<?> type = fild.getType();  //获取该成员变量的类型
            System.out.println("成员变量的类型"+type);
            int modifiers = fild.getModifiers();  //获取该成员变量的修饰等级
            System.out.println("成员变量的修饰等级"+modifiers);
            User u = new User("name", 11, "男");
            fild.setAccessible(true);
            Object o = fild.get(u);//获取具体对象的该成员变量的具体值
            System.out.println("成员变量的具体值"+o);
            // 修改成员变量的具体值
            //fild.set(u,"")//u是具体对象 第二个参数是要改为什么
            System.out.println("===================================================");
        }
    }
}
6.2.4获取成员方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jULiCp8s-1681980768137)(…/Asset/image-20230420144014169.png)]

// 【1】写法和6.2.2---6.2.3类似
6.2.5 获取方法的泛型
  • 获取方法参数里面的泛型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aGMq4OpX-1681980768137)(…/Asset/image-20230420151924220.png)]

  • 获取方法泛型返回值的类型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Z98yXYw-1681980768137)(…/Asset/image-20230420152229467.png)]

第七章 JVM

7.1JVM的位置

在操作系统之上,每个操作系统负责实现各自的jvm,这是java可以跨平台的基础。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6fVwpw5k-1681980768137)(…/Asset/image-20230420154428301.png)]

7.2Jvm的体系结构

简单图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gx0Qw1ve-1681980768138)(…/Asset/image-20230413165349580-16816270566443.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ArtGiCAH-1681980768138)(…/Asset/image-20230420154844916.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0V21gb08-1681980768138)(…/Asset/image-20230420154945677.png)]

垃圾只有在堆区和方法区

详细图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xht6CiPA-1681980768138)(…/Asset/image-20230420155153932.png)]

大部分插件都是在执行引擎上下功夫

7.3类加载器

作用:

  1. 加载Class文件 new Student(); 引用在栈里面,具体在堆里面
Car.class文件加载过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F0omsyPy-1681980768138)(…/Asset/image-20230420155736886.png)]

加载器分类
  1. 虚拟机自带
  2. 启动类(跟)加载器 rt.jar 【这里的一般不动】
  3. 扩展类加载器(app加载器的上层) jre\lib\ext 【
  4. 应用程序加载器(我们写的类加载器一般都是这个)

层层递进先从应用程序开始找

7.4双亲委派机制

保证安全(步骤):

  1. 类加载器收到类的加载请求,把请求给到最高层(ROOT)
  2. 加载器检查是否能够加载当前这个类,能加载就使用,否则就抛出异常,通知子加载器进行加载。

写好的类会层层递进的寻找,如果在上层的加载器中找到了同名类,则会加载该类,并不会加载自己写的类,下图程序会报找不到main函数错误,因为加载的是ROOT下的String类,这是java自带的类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H8zuBBLe-1681980768139)(…/Asset/image-20230420160508729.png)]

注意:更具体的请百度

7.5沙箱安全机制

  1. java安全模型的核心是java沙河机制,该机制把java代码限定在jvm的特定范围中运行,严格限制代码堆本地系统资源的访问。
  2. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d7wQVzYa-1681980768139)(…/Asset/image-20230420161740212.png)]
  3. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KuSnNucS-1681980768139)(…/Asset/image-20230420161754864.png)]
  4. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QveBM9nk-1681980768139)(…/Asset/image-20230420161802556.png)]
  5. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kW0jmC3L-1681980768140)(…/Asset/image-20230420161855441.png)]
基本组件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y9xI7phP-1681980768140)(…/Asset/image-20230420162352820.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oUdjhJhu-1681980768140)(…/Asset/image-20230420162415618.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VDaVgxoO-1681980768140)(…/Asset/image-20230420162708731.png)]

7.6 native本地方法接口

  1. 带了native修饰的,说明java的作用范围达不到了,会调用底层c语言的功能。
  2. native方法会进入本地方法栈
⭐补充,调用其他接口

比如调用python可以用socket WebService http等,可以访问其他类编写的程序

比如java调用pyton程序。可以用url的方式调用,在python程序中处理该url请即可

7.7 pc寄存器

每个线程都有一个层序计数器,是线程私有的,就是一个指针,指向方法中的方法字节码,在执行引擎读取下一条指令,是一个非常小的内存空间

7.8 方法区

  1. 所有线程共享,所有字段和方法字节码,以及一些特殊方法比如构造函数,接口代码也在这里定义,定义的方法的信息都保存在此,是共享区域。
  2. 这里面还有一个静态方法区,随类一起加载
  3. 可以理解为把加载的类放到这里
  4. 还有一个静态常量池,如果类 默认有一些值就加载到这里,实例化该类对象的时候如果没有修改该值,实际上该值是指向方法区中静态常量池的

总的一句话:静态变量,常量,类信息,运行时的常量池,都在该区域,但是实际变量存在堆

7.9 栈/堆

6、深入理解一下栈_哔哩哔哩_bilibili

jvm栈溢出
  • 递归调用溢出,程序会不让执行

7.10堆内存调优

方法区和堆,大部分都是调堆

三种jvm 我用的是HotSpot虚拟机(window)

新生区/老年去/永久区

GC垃圾回收 常用算法

JMM

名字
System.out.println(“成员变量的名字”+name);
Class<?> type = fild.getType(); //获取该成员变量的类型
System.out.println(“成员变量的类型”+type);
int modifiers = fild.getModifiers(); //获取该成员变量的修饰等级
System.out.println(“成员变量的修饰等级”+modifiers);
User u = new User(“name”, 11, “男”);
fild.setAccessible(true);
Object o = fild.get(u);//获取具体对象的该成员变量的具体值
System.out.println(“成员变量的具体值”+o);
// 修改成员变量的具体值
//fild.set(u,“”)//u是具体对象 第二个参数是要改为什么
System.out.println(“===================================================”);
}
}
}


#### 6.2.4获取成员方法

[外链图片转存中...(img-jULiCp8s-1681980768137)]

```java
// 【1】写法和6.2.2---6.2.3类似
6.2.5 获取方法的泛型
  • 获取方法参数里面的泛型

[外链图片转存中…(img-aGMq4OpX-1681980768137)]

  • 获取方法泛型返回值的类型

[外链图片转存中…(img-1Z98yXYw-1681980768137)]

第七章 JVM

7.1JVM的位置

在操作系统之上,每个操作系统负责实现各自的jvm,这是java可以跨平台的基础。

[外链图片转存中…(img-6fVwpw5k-1681980768137)]

7.2Jvm的体系结构

简单图

[外链图片转存中…(img-gx0Qw1ve-1681980768138)]

[外链图片转存中…(img-ArtGiCAH-1681980768138)]

[外链图片转存中…(img-0V21gb08-1681980768138)]

垃圾只有在堆区和方法区

详细图

[外链图片转存中…(img-xht6CiPA-1681980768138)]

大部分插件都是在执行引擎上下功夫

7.3类加载器

作用:

  1. 加载Class文件 new Student(); 引用在栈里面,具体在堆里面
Car.class文件加载过程

[外链图片转存中…(img-F0omsyPy-1681980768138)]

加载器分类
  1. 虚拟机自带
  2. 启动类(跟)加载器 rt.jar 【这里的一般不动】
  3. 扩展类加载器(app加载器的上层) jre\lib\ext 【
  4. 应用程序加载器(我们写的类加载器一般都是这个)

层层递进先从应用程序开始找

7.4双亲委派机制

保证安全(步骤):

  1. 类加载器收到类的加载请求,把请求给到最高层(ROOT)
  2. 加载器检查是否能够加载当前这个类,能加载就使用,否则就抛出异常,通知子加载器进行加载。

写好的类会层层递进的寻找,如果在上层的加载器中找到了同名类,则会加载该类,并不会加载自己写的类,下图程序会报找不到main函数错误,因为加载的是ROOT下的String类,这是java自带的类

[外链图片转存中…(img-H8zuBBLe-1681980768139)]

注意:更具体的请百度

7.5沙箱安全机制

  1. java安全模型的核心是java沙河机制,该机制把java代码限定在jvm的特定范围中运行,严格限制代码堆本地系统资源的访问。
  2. [外链图片转存中…(img-d7wQVzYa-1681980768139)]
  3. [外链图片转存中…(img-KuSnNucS-1681980768139)]
  4. [外链图片转存中…(img-QveBM9nk-1681980768139)]
  5. [外链图片转存中…(img-kW0jmC3L-1681980768140)]
基本组件

[外链图片转存中…(img-y9xI7phP-1681980768140)]

[外链图片转存中…(img-oUdjhJhu-1681980768140)]

[外链图片转存中…(img-VDaVgxoO-1681980768140)]

7.6 native本地方法接口

  1. 带了native修饰的,说明java的作用范围达不到了,会调用底层c语言的功能。
  2. native方法会进入本地方法栈
⭐补充,调用其他接口

比如调用python可以用socket WebService http等,可以访问其他类编写的程序

比如java调用pyton程序。可以用url的方式调用,在python程序中处理该url请即可

7.7 pc寄存器

每个线程都有一个层序计数器,是线程私有的,就是一个指针,指向方法中的方法字节码,在执行引擎读取下一条指令,是一个非常小的内存空间

7.8 方法区

  1. 所有线程共享,所有字段和方法字节码,以及一些特殊方法比如构造函数,接口代码也在这里定义,定义的方法的信息都保存在此,是共享区域。
  2. 这里面还有一个静态方法区,随类一起加载
  3. 可以理解为把加载的类放到这里
  4. 还有一个静态常量池,如果类 默认有一些值就加载到这里,实例化该类对象的时候如果没有修改该值,实际上该值是指向方法区中静态常量池的

总的一句话:静态变量,常量,类信息,运行时的常量池,都在该区域,但是实际变量存在堆

7.9 栈/堆

6、深入理解一下栈_哔哩哔哩_bilibili

jvm栈溢出
  • 递归调用溢出,程序会不让执行

7.10堆内存调优

方法区和堆,大部分都是调堆

三种jvm 我用的是HotSpot虚拟机(window)

新生区/老年去/永久区

GC垃圾回收 常用算法

JMM

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值