韩顺平java面向对象高级编程学习笔记

java面向对象高级编程学习笔记

面向对象高级编程

类变量和类方法

类变量(静态变量)

  • 特点
  1. 被该类所有对象共享
    jdk7以后放在堆,以前放在方法区静态域?
  2. static类变量,在类加载的时候生成。
  • 访问
  1. 类名.类变量名
  2. 对象名.类变量名
  • 细节
  1. 当某个类的所有对象都共享一个变量时,考虑使用类变量
  2. 类变量遵循访问修饰符限制的访问权限
  3. 类变量类加载时就创建了
    4.类变量生命周期随着类的加载开始,随着类的消亡而销毁,与对象无关

类方法(静态方法)

使用同上
不创建实例也能使用,当作工具来使用,则可以将方法设计成静态方法,提高开发效率。

  • 细节
  1. 类方法和普通方法 随类加载而加载,将结构信息存储在方法区;类方法中无this的参数,普通方法隐含着this参数
  2. 类方法中不允许使用和对象相关的关键字,比如 this, super
  3. 静态方法只能访问静态成员(静态变量和静态方法),普通成员可以访问所有成员

main()主方法

  1. main()方法是虚拟机调用
  2. java虚拟机需要调用类的main()方法,所以该方法权限必须是public
  3. java虚拟机在执行main()时不必创建对象,所以必须是public
  4. 该方法一个接收String数组参数,该数组中保存执行java命令时传递给所运行的类的参数
  5. 比如:java 执行的程序 参数1 参数2 参数3
  6. 在main()方法中可以直接调用本类中的静态成员,不可以直接调用非静态成员

代码块

代码块又称为初始化块,属于类中的成员,属于类的一部分
和方法不同,它无方法名,无返回值,无参数,只有方法体,不用通过对象或类显式调用,而是加载类时隐式调用

  • 语法
    【修饰符】{
    代码
    };
  1. 修饰符可选,但写只能写 static
  2. 代码块分两类
    2.1 static修饰:静态代码块
    2.2 无static修饰:非静态代码块/普通代码块
    3.;可省略
  • 相当另一种形式的构造器(堆构造器的补充机制),可以做初始化操作
  • 如果多个构造器有重复语句,这时可以将重复语句抽离写在代码块里

细节

  1. static代码块,对类初始化,随类加载执行,并且只执行一次
  2. 无static普通代码块,每创建一个对象执行一次

类什么时候加载(重要!!!!!!!!!!!!)

2.1 创建对象实例
2.2 创建子类对象实例,父类被加载(父类先加载,子类后加载
2.3 直接使用类的静态成员(静态属性、静态方法)
4. 使用只是使用类的静态变量,不会调用普通代码块,而是创建对象时才调用,创建一次,调用一次。

创建一个对象时,在一个类 调用顺序是:(重点)

第一步
  1. 调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态属性初始化,则按照定义顺序调用
calss A{
//静态属性初始化
	private static int n1 = getN();
	static{//静态代码块
		System.out.println("A静态代码块");
	}
	public static getN1(){
		System.out.println("getN1调用");
		return 100;
	}
}
执行顺序:
getN1调用
A静态代码块
第二步
  1. 调用普通代码块和普通属性初始化(注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按照定义顺序调用
calss A{
    //普通属性初始化
	private static int n2 = getN2();
	{
		System.out.println("A普通代码块");
	}
	static{//静态代码块  第 1 步
		System.out.println("A静态代码块");
	}
	//静态属性初始化
	private static int n1 = getN1();  //第 2 步
	public static getN1(){
		System.out.println("getN1调用");
		return 100;
	}
	public int getN2(){
		System.out.println("getN2调用");
		return 200;
	}
	public A{
		System.out.println("构造器调用");
	}
}
执行顺序:
A静态代码块
getN1调用
getN2调用
A普通代码块
构造器调用
第三步
  1. 构造器调用
    最后调用构造器

构造器调用

构造器前面隐含了 super()调用普通代码块调用普通

class A{
	public A(){//构造器
		//隐藏的执行要求
		//隐藏部分(1)
		super();
		//隐藏部分(2)
		//调用普通代码块
		System.out.println("ok");
	}
}

创建子类对象时,他们的静态代码块、普通代码块、静态变量初始划、普通变量初始化、构造方法调用顺序如下:

删除线格式 在这里插入图片描述

静态代码块只能调用静态成员,普通代码块可以使用任意成员

设计模式

单例设计模式

  1. 就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且只提供一个取得其对象实例的方法
  2. 饿汉式和懒汉式
  • 饿汉式
    (1) 构造器私有化(防止直接 new)
    (2) 类的内部创建对象,不管用不用都创建
    (3) 向外暴露一个公共的static方法返回一个实例对象
public class SingleTon {
    public static void main(String[] args) {
        Friend f = Friend.getInstance();
        System.out.println(f);
    }
}

class Friend{
    
    private String name;
    // 2. 在类内部直接创建对象
    private static Friend f = new Friend("xiaohong");
    
    // 1. 构造器私有化
    private Friend(String name){
        this.name = name;
    }
    // 3. 提供一个公共方法获得实例
    public static Friend getInstance(){
        return f;
    }
}
  • 懒汉式
    (1) 构造器私有化
    (2) 类内部创建对象,使用时才创建
    (3) 向外暴露一个公共的static方法返回一个实例对象
public class Single01 {
    public static void main(String[] args) {
    	//cat1 == cat2
        Cat cat1 = Cat.getInstance();
        System.out.println(cat1);
        Cat cat2 = Cat.getInstance();
        System.out.println(cat2);
    }
}
class Cat{
    private String name;
    // 
    private static Cat cat;
    //步骤
    //1. 构造器私有化
    //2. 定义一个static类对象
    //3. 提供一个public的stati方法,可以返回一个Cat对象

    public Cat(String name) {
        this.name = name;
    }

    public static Cat getInstance(){
        if(cat == null){
            cat = new Cat("tom");
        }
        return cat;
    }

    @Override
    public String toString() {
        return toString();
    }
}
  • 区别
    (1)创建对象时机不同,饿汉式类加载时创建,懒汉式使用时才创建
    (2)懒汉式可能有线程安全问题,饿汉式没有
    (3)饿汉式可能浪费资源,创建了实例未使用

模板设计模式

抽象类最佳实践

final关键字

  1. 修饰,则该类不能被继承
  2. 修饰方法,该方法不能被重写
  3. 修饰类属性,该属性不能被修改
  4. 修饰局部变量,该局部变量不能被修改
  • 细节
  1. final修饰的属性必须定义时进行初始化,且不可修改
  2. 赋值位置:
    (1)定义时
    (2)构造器(非静态)
    (3)代码块
    在这里插入图片描述
  3. 修饰的属性是静态的static时,不能在构造器赋值
  4. final修饰类可以实例化
  5. 类中有方法被final修饰,该类可以继承,方法不能重写
  6. 类是final类了,没必要再写final方法
  7. final和static 往往搭配使用,效率更高,不会导致类加载,底层编译器做了优化处理
  8. 包装类不能被继承

抽象类

抽象类

  • 细节
  1. abstract 修饰方法,抽象方法不能有方法体
  2. 抽象类不能实例化
  3. 抽象类可以没有抽象方法
  4. 有抽象方法,必须声明为抽象类
  5. abstract只能修饰类 或者 方法
  6. 继承抽象类之后必须实现抽象类的所有抽象方法, 或者也声明为抽象类
  7. 抽象方法不能用private、final、static,因为这些和重写违背

接口

  1. jdk8接口中可以有属性、抽象方法、默认实现方法、静态方法
public interface A{
	public int n1 =1;//属性
	public abstract void f();//可以省略关键字abstract
	default public void f2();//默认实现方法
	public static void f3();//静态方法
}
  1. 接口不能被实例化
  2. 一个普通类实现接口必须实现接口的所有方法
  3. 接口中所有方法是public,抽象方法可以不用abstract修饰
  4. 一个类可实现多个接口
  5. 类中的属性只能是final的,而且是public static final
  6. 访问属性:接口名.属性名
  7. 接口不能继承类,但可以继承接口
  8. 接口修饰符只能是public和默认,和类一样
interface A{
	int n1 = 10; //等价于public static final int n1 =10;
}

接口与继承类

  1. 继承:解决代码复用性、可维护性
  2. 接口: 设计好规范方法,让其它类去实现,灵活,解耦(接口规范性 + 动态绑定机制)

接口的多态性

  1. 接口引用可以指向,实现了该接口的类的对象
  2. 多态传递
interface A{}
interface B extends A{}
class C extends B{}
A a = new C();

内部类

最大特点

  • 可以直接访问私有属性,是类的第五大成员(属性、方法、构造器、代码块、内部类)

分类

定义在外部类局部位置

局部,相当一个局部变量

局部内部类(有类名)

在这里插入图片描述
在这里插入图片描述

匿名内部类(无类名)重要!!

简化开发,匿名内部类只能使用一次,

interface A{
	public void run();
}
class B{
	A tiger = new A(){
		@Override
		public void run(){
			System.out.println("run");
		}
	}
	tiger.run();
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

定义在外部类成员位置上
成员内部类(无static修饰)

不在方法中,在外部类的一个成员位置定义,可以添加任意访问修饰符,与成员一样

静态内部类(有static修饰)

在这里插入图片描述
在这里插入图片描述

枚举和注解

枚举

  • 自定义类实现枚举
  • 使用enum
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

enum类的各种方法

public enum Enumeration02 {
    //
    SPRING("春"),SUMMER("夏"),AUTUMN("秋"),WIMTER("冬");
    private String name;

    private Enumeration02(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
    @Override
    public String toString(){
        return "{name:"+ name + "}";
    }
}
public class Enumeration01 {
    public static void main(String[] args) {
        Enumeration02 spring = Enumeration02.SPRING;
        //1. 输出列举对象的名字
        System.out.println(spring.name());

        //2. ordinal()输出该枚举对象的次序
        System.out.println(spring.ordinal());

        //3. 反编译可以看到 values方法,返回 Enumeration01[]数组
        //含有所有枚举对象
        Enumeration02[] allValue = Enumeration02.values();
        for(Enumeration02 season: allValue){
            //增强for循环
            System.out.println(season);
        }

        //4. 将字符串转换成枚举对象,要求字符串为已有常量,否则报异常
        Enumeration02 autumn = Enumeration02.valueOf("AUTUMN");
        System.out.println("autumn+" + autumn);
        System.out.println(Enumeration02.AUTUMN == autumn); //true


        //5. 比较两个枚举常量的序号, 返回的是spring的序号减去autumn的序号值
        System.out.println(spring.compareTo(autumn)); // 0-2=-2
        //
        System.out.println(spring.getDeclaringClass());
        System.out.println(spring.getClass());
    }
}

反射

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

异常

两类

  • Error错误:java虚拟机无法解决的严重问题
  • Exception:一般性问题,可以使用针对性的代码进行处理,分为两大类运行时异常【程序运行时发生的异常】和编译时的异常【编程时,编译器检查出的异常】
  • try 多个catch 捕获异常时,先捕获子类异常再父类,只捕获一次
public void f(){public static int f(){
        int i = 0;
        try {
            String[] names = new String[3];
            System.out.println(names[0].equals("tom"));
            return i;
        } catch (NullPointerException e){
            System.out.println("null:"+ i);
            return ++i;   // 这里i的值保存在一个临时变量temp中, 指向完finally最后返回temp保存的这个值
        }catch (Exception e) {
            e.printStackTrace();
        } finally {
            ++i;
            System.out.println("finally: " + i);
        }
        System.out.println("out of try i:" + i);
        return i;
    }
}

自定义异常

定义异常类继承Exception或者RuntimeException
  • 继承Exception
    属于编译异常
  • 继承RuntimeException
    属于运行异常
意义位置后面跟的东西
throws异常处理的一种方式方法声明处异常类型
throw手动生成异常对象的关键字方法体中异常对象

在这里插入图片描述

包装类

Serializable接口

所谓序列化即可以保存类型和数据本身,可以在网络中传输,保存到文件

Integer

Object o = true ? new Integer(1): new Double(2.0);
// 三元运算符看作一个整体
System.out.println(o) ;//  输出1.0

常用类

String

实现了Serializable接口,说明String可以串行化,在网络中传输

  1. 本质还是保存在字符数组里
  2. value 是一个final类型, 不可以修改(这里不能修改指的是不能指向新的地址,但是可以修改单个字符串内容
private final char value[];//存放字符串内容

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

案例分析

在这里插入图片描述

1.这里首先在堆中new一个对象,开辟一个空间,空间里有str和ch数组
2. str是new出来的,所以也指向一个String堆空间,在这个空间里有一个value属性,这个value指向常量池中的”hsp“
3. ch是一个final数组,数组默认保存在堆中,ch指向数组[‘j’,‘a’,‘v’,‘a’]
在主方法栈中, ex指向这个对象的引用,ex调用chang方法,产生一个新的栈,在这个栈中有两个参数str he ch[],str指向2中的String堆空间,但是执行 str="java"语句后,这个chang方法栈中的str指向了常量池中的”java“字符串(类成员属性str指向的仍然是String堆空间);chang方法栈中的ch指向的是3中的ch数组,指向同一个数组,ch[0]='h’则直接把堆中数组的第一个变量写成h
4. 输出时是输出类成员属性str指向的内容, 数组ch[]指向的地址不变,内容变化了

  • 数组默认保存在堆中

案例

在这里插入图片描述

String t1 = “hellp” + name;
两个常量拼接,是创建一个StringBuilder 对象,然后向这个对象里append追加“hello” 和name指向的常量池中的值,然后在堆中开辟一个String堆空间,把这个空间给t1,把StringBuilder里的值放在常量池里,再由空间里的value指向它

StringBuffer

在这里插入图片描述

由第3条可知,StringBuffer类型的可变长字符串用char[] value保存,没有final,整个保存在堆中,不会放在常量池
StringBuffer不用每次更新地址,空间不够了才扩展更新
在这里插入图片描述

StringBuilder

  • 不是线程安全的
  • 提供可变字符序列,提供一个与StringBuffer兼容的API
    +

String 、StringBuffer、 StringBuilder对比

在这里插入图片描述
在这里插入图片描述

Math

  //Math常用静态方法
        //1.abs绝对值
        int a = Math.abs(-1);
        System.out.println(a);//1
        //2. pow求幂
        double b = Math.pow(2,3);
        System.out.println(b);//8.0
        //3.ceil向上取整
        double ceil = Math.ceil(-3.02);
        System.out.println(ceil);//-3.0
        //4.floor向下取整
        double floor = Math.floor(-4.8);
        System.out.println(floor);//-5.0
        //5. round 四舍五入
        double r = Math.round(-4.8);
        System.out.println(r);//-5.0
        //6.sqrt 开方
        double s = Math.sqrt(9.0);
        System.out.println(s);//3.0
        //7.random随机数 返回的值满足  0 <= x < 1
        double x = Math.random();
        System.out.println(x);

Arrays类

用于操作数组
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

BigInteger

不能直接+ -*/,使用相应的方法进行运算

BigDecimal

保存高精度的数,double不够用时使用
使用相应的方法进行运算
除法时可能除不尽,在方法后面指定精度即可解决

BigDecimal bd1 = new BigDecimal("111111111111111111.9999");
BigDecimal bd2 = new BigDecimal(112);
//如果结果是无限循环小数,就会保留分子的精度
System.out.println(bd1.divide(bd2,BigDecimal.ROUND_CEILING));

LocalDate(日期/年月日)、LocalTime(时间/时分秒)、LocalDateTime(日期和时间)

  • 第一代 Date
  • 第二代Calender
  • 第三代 jdk8引入
    在这里插入图片描述
public static void main(String[] args) {
        //1. now()返回日期时间对象
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println(localDateTime);
        //2. 使用DateTimeFormatter对象进行格式化
        // 创建DateTimeFormatter对象
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String format = dateTimeFormatter.format(localDateTime);
        System.out.println(format);
    }

在这里插入图片描述

集合框架体系

在这里插入图片描述

单列集合

  • 保存一个元素

Collection接口、子接口及实现类

Collection
List
Set
ArrayList
LinkedList
Vector
HashSet
TreeSet

在这里插入图片描述

在这里插入图片描述

  1. Collection 接口遍历元素方式1-使用Iterator(迭代器)
    在这里插入图片描述

在这里插入图片描述
2. Collection 接口遍历对象方式2-for 循环增强
在这里插入图片描述
3. for循环

List

在这里插入图片描述

List接口实现类的三种遍历方式

在这里插入图片描述

ArrayList
  • 线程不安全
  • 效率高
  • 由数组实现数据存储
  • 基本等同于Vector
ArrayList底层结构和源码分析

在这里插入图片描述

transient(短暂的、瞬时的)修饰,表示该属性不会被序列化

LinkedList
  • 线程不安全
  • 实现了双端队列和双向链表
  • 可以添加任意元素,包括你null
Vector
  • 线程安全
ArrayList 和 Vector比较

在这里插入图片描述

ArrayList 和LinkedList比较

在这里插入图片描述

Set接口

  • 常用方法和List一样
  • 遍历
  1. 可以使用迭代器
  2. 增强for循环
  3. 不能使用索引的方法获取
HashSet
  • 无序
  • 元素不能重复
  • 添加顺序与取出顺序不同,但是取出顺序固定
  • 实现了Set接口
  • 实际上是HashMap
  • 可以放空值null
  • HashSet底层维护的是数组+单向链表
  • HashMap底层是数组+链表+红黑树
HashSet底层机制

在这里插入图片描述
equals()不能简单的认为是比较内容,每个类都可以重写自己的equals()方法,String是重写了equals()方法比较内容

在这里插入图片描述
关于threshold(阈值)扩容的问题,是整个table表中所有元素个数达到12就会扩容;整个table表中每个索引元素后面跟着的链表中的元素都包括在内

LinkedHashSet
  • 底层维护的是LinkedHashMap
  • LinkedHashMap是HashMap的子类
    在这里插入图片描述

LinkedHashSet是HashSet的子类

TreeSet

双列集合

  • 以键值对的形式保存元素
Map
HashMap
TreeMap
Properties
HashTable

在这里插入图片描述

Map

在这里插入图片描述

Map接口特点
 Map map = new HashMap();
 map.put("01","jack");    // k-v
 map.put("02","stion");   // k-v
 map.put("01","tom");    // k-v
  1. k-v 最后是保存在 HashMap$Node node = newNode(hash, key, value, null)
  2. k-v 为了方便遍历, 还会创建EntrySet 集合, 该集合存放的元素的类型是Entry,而一个Entry对象就有 k,v ,EntrySet<Entry<K,V>> 即: transient Set<Map.Entry<K,V>> entrySet;.
  3. entrySet 中, 定义的类型是 Map.Entry, 但是实际上存放的还是 HasMap$Node, 这是因为 static class Node<K,V> implements Map.Entry<K,V>

在这里插入图片描述

右侧一对数据 保存在entry里,再把entry放在entrySet里,
所有的key放在一个keySet里
Set 和entrySet里其实只是建立了简单的引用,指向HashMap$Node,并重新拿一份数据

Map六大遍历方式
第一组 取出所有key,通过key,取出对应value
  • Set keySet = map.keySet();
  1. 增强for循环
  2. 迭代器
第二组 取出所有values
  • Collection values = map.values();
  1. 增强for
  2. 迭代器
第三组 通过EntrySet 获取 k-v
  • Set entrySet = map.entrySet();
  • ** EntrySet<Map.Entry<K,V>>
  1. 增强for
  2. 迭代器
		Iterator iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Object next =  iterator.next();
            System.out.println(next.toString());
            // HashMap$Node --实现--> Map.Entry(getKey,getValue)
			//这里取出来的next其实是保存在HashMap$Node, 但是这个Node实现了Map.Entry, 所以可向下转型
			System.out.println(next.getClass());//class java.util.HashMap$Node
            Map.Entry m = (Map.Entry) next;
            System.out.println(m.getKey()+"--"+m.getValue());
        }
HashMap线程不安全,没有实现同步
HashMap底层机制实现和源码分析

看笔记吧

HashTable线程安全

在这里插入图片描述
在这里插入图片描述

Properties

在这里插入图片描述

TreeMap

在这里插入图片描述

在这里插入图片描述

这里第一次添加也是调用动态绑定的匿名内部类(也是个对象)的compare方法,方法参数传入两个相同的key,因为第一次添加没有要比较的,然后compare返回值也没有用变量接收,不会对后面有影响
这里compare作用是比较key是否为null,如果为空,会有空指针异常
在这里插入图片描述
在这里插入图片描述

TreeMap这里使用cpmpare方法比较两个Key是否相等,是否相等决定于自己设计的compare方法,HashMap是用equals方法比较两个Key是否相等

开发中如何选择集合实现类

在这里插入图片描述

Collections工具类

在这里插入图片描述
在这里插入图片描述

TreeSet和HashSet如何实现去重

在这里插入图片描述

例题

Person类并没有实现Compareable接口,所以在执行到比较去重的代码就会报错。
在这里插入图片描述

泛型

好处

在这里插入图片描述

介绍

  • 泛型可以理解为表示数据类型的一种数据类型
    在这里插入图片描述

在这里插入图片描述

泛型语法

在这里插入图片描述

自定义泛型类

  • 基本语法
class 类名<T,R...>{ 
//...表示可以有许多个泛型成员  
}
  • 细节
  1. 普通成员可以使用泛型(属性、方法)
  2. 使用泛型数组,不能初始化
  3. 静态方法中不能使用类的泛型
  4. 泛型类的类型, 是在创建对象时确定的(因为创建对象时,需要指定确定类型)
  5. 如果在创建对象时候没有指定类型,默认为Object

自定义泛型接口在这里插入图片描述

自定义泛型方法

在这里插入图片描述

泛型方法与使用泛型的区别

在这里插入图片描述
在这里插入图片描述

泛型的继承和通配符

在这里插入图片描述

线程

  • 单线程
  • 多线程
  • 并发
    同一时刻,多个任务交替进行,造成一种“貌似同时”的错觉,比如单核cpu实现的多任务是并发
  • 并行
    同一时刻,多个任务同时进行,多核cpu可以实现并行

创建线程

在这里插入图片描述

  1. 继承Thread类,重写run方法
  2. 实现Runnable接口,重写run方法
    run方法是Runna接口里的方法,Thread类里的run方法是实现的Runna接口里的run方法
  3. 主线程结束,子线程不会立刻结束,会执行完再结束

线程常用方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

线程7大状态

在这里插入图片描述

RUNNABLE状态代表可以运行,但是不一定马上运行;在此基础可以细分为两种状态,READY 和RUNNING, 这由线程调度器决定,(操作系统决定)

  • 线程状态转换图
    在这里插入图片描述

Synchronized

在这里插入图片描述
在这里插入图片描述

互斥锁

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

上图要求多个线程的锁对象为同一个 解释

在这里插入图片描述

如上图,执行注释掉的两条语句,new了两个不同的对象,相当于m1()方法中的this分别是指向着两个对象,锁对象不是同一个了,锁不住,没用了

线程死锁

多个线程占用了对方的资源,双方都无法获得

在这里插入图片描述
在这里插入图片描述

A线程拿到o1,B线程拿到o2;之后A尝试获取o2失败,同理B也失败,进入死锁

释放锁

在这里插入图片描述
在这里插入图片描述

例题

public class Thread02 {
    public static void main(String[] args) {
        Walet walet = new Walet(10000);
        Thread thread01 = new Thread(walet);
        Thread thread02 = new Thread(walet);
        thread01.setName("1号");
        thread02.setName("2号");
        thread01.start();
        thread02.start();

    }
}

class Walet implements Runnable {
    private int salary;
    public Walet(int salary) {
        this.salary = salary;
    }

    @Override
    public void run() {
        while (true) {
            //1.这里使用synchronized对象锁
            //2.当线程执行到这里,就会取争夺this对象锁
            //3.哪个线程争夺到this对象锁,就执行 synchronized 代码块 ,执行完毕, 释放this对象锁
            //4.争取不到this对象锁,进入阻塞状态blocked,准备继续争夺
            //5.this对象锁是非公平锁
            synchronized (this) {
                if (salary <= 0) {
                    System.out.println("余额不足");
                    break;
                }
                salary -= 1000;
                System.out.println("线程名" + Thread.currentThread().getName() + "余额" + this.salary);
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

文件

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

IO流

在这里插入图片描述
在这里插入图片描述

文件字节流

InputStream

在这里插入图片描述

OutputStream

 //得到一个FileOutputStream对象
            fileOutputStream = new FileOutputStream(filePath);
            String str = "hello,dscdv";
            fileOutputStream.write(str.getBytes("utf-8"),1,3);
            //2.追加模式
            fileOutputStream = new FileOutputStream(filePath,true);
            fileOutputStream.write(str.getBytes(),0,str.length());

文件拷贝

  public static void main(String[] args) {
        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;
        String root = "E:\\javaProjectExercise\\javacode\\test\\src\\file\\a.txt";
        String dest = "E:\\javaProjectExercise\\javacode\\test\\src\\file\\b.txt";
        try {
            fileInputStream = new FileInputStream(root);
            fileOutputStream = new FileOutputStream(dest);

            //创建一个字节数组用来保存读取的数据
            byte[] bytes = new byte[100];
            int readLen = 0;
            while ((readLen = (fileInputStream.read(bytes)))!= -1) {
                //一遍读,一边写
                fileInputStream.read(bytes);
                //必须根据长度写入
                //因为最后一个字节可能读数据不满,比如最后读了50个数据,但是还是写了100个数据进去
                //不能用这个fileOutputStream.write(bytes);
                fileOutputStream.write(bytes,0,readLen);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fileInputStream.close();
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

文件字符流

在这里插入图片描述
在这里插入图片描述

节点流、处理流

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {
        /**
         * BufferedReader 和 BufferedWriter 是操作   字符文件
         * 不能操作二进制文件, 会造成文件损坏
         */
        String srcFilePath = "E:\\javaProjectExercise\\javacode\\test\\src\\file\\b.txt";
        String destFilePath = "E:\\javaProjectExercise\\javacode\\test\\src\\file\\a.txt";
        BufferedWriter bufferedWriter = null;
        BufferedReader bufferedReader = null;
        String line;
        try {
            bufferedReader = new BufferedReader(new FileReader(srcFilePath));
            bufferedWriter = new BufferedWriter(new FileWriter(destFilePath));
            //按行读取,读不到返回空
            //按行原读取,但是没读换行符
            while ((line = bufferedReader.readLine()) != null){
                bufferedWriter.write(line);
                //添加换行符
                bufferedWriter.newLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(bufferedReader!=null) {
                    bufferedReader.close();
                }
                if(bufferedWriter != null) {
                    bufferedWriter.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

序列化

在这里插入图片描述

对象流

在这里插入图片描述
在这里插入图片描述

ObjectInputStream

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ObjectOutputStream

在这里插入图片描述

标准输入输出流

在这里插入图片描述

转换流

InputStreamReader

在这里插入图片描述

OutPutStreamWriter

在这里插入图片描述

在这里插入图片描述

打引流

PrintStream

在这里插入图片描述

PrintWriter

在这里插入图片描述

Properties类

在这里插入图片描述
在这里插入图片描述

  • 2
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值