java学习笔记

黑马学习视频地址:java基础+进阶

java入门介绍与数据类型

字节

位(bit):一个数字0或者1,代表1位

字节(byte):每逢8位是一个字节,这是数据存储的最小单元

换算规则:1 byte = 8 bit

windows命令提示符

cd + 文件夹名称 进入文件夹

cd + 文件夹1\文件夹2\文件夹3 直接进入多级文件夹

cd… 退回上一级

cd\ 返回根目录

dir 查看当前文件夹内容

cls 清屏

exit 退出

↑ 切回到上条命令

↓ 切换到下条命令

java开发环境

JVM: java虚拟机,java程序的运行环境,java语言的跨平台特性都是由jvm实现的。java须立即本身不具备跨平台功能,每个操作系统下都有不同版本的虚拟机。

JRE: java运行环境,包含JVM和运行时所需要的核心类库。

JDK: java程序开发工具包,包含JRE和开发人员的工具。

java开发说明

java开发三步骤:编写、编译、运行。java源程序->java字节码文件->jvm运行。

cmd命令:javac + 文件名.java -编译java文件

​ java + 文件名 -运行

java基础概念

关键字: 有特殊含义的、被保留的、不能随意使用的字符

​ 特点:1.完全小写的字母。

​ 2.在增强版的记事本有特殊颜色。

标识符: 1.英文字母26个、0-9数字、$符号和_符号。

​ 2.标识符不能数字开头。

​ 3.不能是关键字

常量: 固定不变的量(字符常量、整数常量…空常量)。

基本数据类型:

数据类型关键字内存(字节)
整数型字节型byte1
短整型short2
整型int(默认)4
长整型long8
浮点型单精度浮点数float4
双精度浮点数double(默认)8
字符型字符型char2
布尔类型布尔类型boolean1

注意事项: 1.字符串不是基本类型。

​ 2.数据范围与字节数不一定相关。float比long更广泛。

​ 3.浮点数如果要使用float类型,需要加上一个后缀F。整数如果要使用long,需要加上一个后缀L。

数据类型转换

自动类型转换(隐式):

​ 1.特点:代码不需要进行特殊处理,自动完成。

​ 2.规则:数据范围从小到大。(不一定与字节数相关)

强制类型转换(显式):

​ 1.特点:代码需要特殊处理,不能自动完成。

​ 2.规则:范围小的类型 范围小的变量名 = (范围小的类型)原本范围大的数据。

注意事项:

​ 1.强制类型转换不推荐使用,可能会有精度损失、数据溢出。

​ 2.byte/short/char这三种类型可以发生数学运算,例如加法“+”,在运算时,首先都会被提升成为int类型,然后再计算。

​ 3.boolean类型不能发生数据转换。

编译器优化: byte/short/char这三种类型,如果右侧赋值数值没有超过范围,那么javac编译器会自动隐含地为我们补上一个(byte)(short)(char)。

​ 1.如果没有超过左侧范围,编译器补上强转。

​ 2.如果右侧超过了左侧范围,那么编译器报错。

​ 3.在给变量赋值的时候,如果右侧的表达式当中全都是常量,那么编译器javac将会直接将若干个常量表达式计算得到结果。例如:short result = 5 + 8,编译之后,得到的.class字节码文件当中就相当于:result = 5 + 8;右侧的常量结果数值,没有超过左侧范围,所以正确,这称为”编译器的常量优化“。但是注意:一旦表达式当中有变量参与,那么就不能进行这种优化了。

流程控制

1.判断语句

  1. if语句。
  2. if–else语句。
  3. if–else if–else语句。

2.选择语句

​ switch(表达式){

​ case 常量值1:

​ 语句体1;

​ break;

​ case 常量值2:

​ 语句体3;

​ break;

​ …

​ default:

​ 语句体n;

​ break;

​ }

注意事项:

​ 1.case后面数值不能重复

​ 2.switch后面小括号中只能是下列数据类型:

​ 基本数据类型:byte/short/char/int。

​ 引用数据类型:String字符串、enum枚举。

​ 3.语句格式灵活,前后顺序可以颠倒,而且break可以省略。会执行到遇到break或流程结束。

​ 上面图片中会输出 “我好 大家好”。

3.循环语句

三种循环

  1. for(条件判断,步进语句){

    ​ 循环体

    }

  2. while(条件判断){

    ​ 循环体

    ​ 步进语句

    }

  3. do{

    ​ 循环体

    ​ 步进语句

    }while(条件判断)

    循环控制语句

    1. break:跳出当前循环,当前循环立即结束。比如结束一个for循环。
    2. continue:跳出此次循环剩余内容,马上开始下一次循环。比如结束for循环中i = 2部分。

方法

方法的重载(overlord)

方法的重载: 多个方法的名称一样,但是参数列表不一样。

方法重载与下列因素有关:

​ 1.参数个数不同。

​ 2.参数类型不同。

​ 3.参数的多类型顺序不同。

方法重载与下列因素无关:

​ 1.与参数名称无关。

​ 2.与方法的返回类型无关。

方法的重写(override)

方法的重写: 方法名称一样,参数列表也一样。

特点: 创建的是子类对象,则优先用子类方法。

注意事项:

​ 1.必须保证父子类之间方法的名称相同,参数列表相同。

​ @Override:写在方法前面,用来检测是不是有效的正确覆盖重写。

​ 2.子类方法返回值必须 小于等于 父类方法的返回值范围(如Object类是String的父类)。

​ 3.子类方法的权限必须 大于等于 父类方法的权限修饰符(public > protected > (default) > private)。

设计原则:

对于已经投入使用的类,尽量不要进行修改。推荐定义一个新的类,来重复利用其中的共性内容,并添加改动新的内容。

数组

数组的初始化

数组的初始化: 在内存当中创建一个数组,并且向其中赋予一些默认值。

两种常见的初始化方式:

​ 1.动态初始化(指定长度)。格式:数据类型[ ] 数组名称 = new 数据类型[数组长度];

​ 2.静态初始化(指定内容)。格式1:数据类型[ ] 数组名称 = new 数据类型[]{元素1,元素2,…};

​ 格式2:数据类型[ ] 数组名称 = {元素1,元素2,…};

​ 动态初始化数组时,元素会自动有一个默认值:

​ 1.整数类型,默认为0;

​ 2.浮点类型,默认为0.0;

​ 3.字符类型,默认为’\u0000’;

​ 4.布尔类型,默认为false;

​ 5.引用类型,默认为null;

​ 静态初始化数组时也有默认值过程,不过系统马上自动替换成了具体数值。

数组初始化:

​ 数组必须进行new初始化才能使用其中的元素,如果只是赋值了一个null,没有进行new创建,那么将会发生:空指针异常。

获取数组长度:

​ 格式:数组名称.length;会得到一个int数字代表数组长度。

数组一旦创建,程序运行期间,长度不可以改变。

Arrays数组相关工具类

  1. toString(数组):将参数数组变成字符串。
  2. sort(数组):按照默认升序对数组元素进行排序。

内存

java的内存需要划分成为5个部分:

1.栈(Stack): 存放的都是方法中的局部变量。方法的运行一定要在栈当中运行

​ 局部变量:方法的参数,或者是方法内部的变量。

​ 作用域:一旦超出作用域,立刻从栈内存当中消失。

2.堆(Heap): 凡是new出来的东西,都在堆中。

​ 堆内存里面的东西都有一个地址值:16进制。

​ 堆内存里面的数据,都有默认值。规则:

​ 1.整数类型,默认为0;

​ 2.浮点类型,默认为0.0;

​ 3.字符类型,默认为’\u0000’;

​ 4.布尔类型,默认为false;

​ 5.引用类型,默认为null;

3.方法区(Method Area): 存储.class相关信息,包含方法的信息。

4.本地方法栈(Native Method Stack): 与操作系统有关。

5.寄存器(pc Register): 与CPU相关。

​ 两个数组内存图(指向不同地址)

​ 两个数组内存图(指向同一地址)

​ 一个对象的内存图

​ 两个对象的内存图(指向同一地址)

​ 对象当参数传递内存图

​ 对象作为方法的返回值内存图:

面向对象思想

面向过程和面向对象

​ **面向过程: ** 当需要实现一个功能的时候,每一个具体步骤都要亲历亲为,详细处理每一个细节。(自己造轮子)。

面向对象: 当需要实现一个功能的时候,不关心具体的步骤,而是找一个已经具有该功能的人,来帮我做事。(别人造好轮子了,直接拿来用)。

举例:

​ 洗衣服

​ 面向过程:脱衣–>找个盆–>放洗衣粉–>加点水–>浸泡十分钟–>揉一揉–>清洗衣服–>拧干–>晾起来。

​ 面向对象:脱衣服–>打开全自动洗衣机–>扔衣服–>按钮–>晾起来。

​ 面向过程:强调步骤。

​ 面向对象:强调对象,这里对象就是洗衣机。

面向对象三大特征:封装、继承、多态

封装

​ 封装性在Java当中的体现:

​ 1.方法就是一种封装。

​ 2.关键字private也是一种封装

​ 封装就是将一些细节信息隐藏起来,对于外界不可见。

继承:

​ 继承是多态的前提,如果没有继承,就没有多态。

​ 继承主要解决的问题就是:共性抽取。

​ 继承中父类(也可以叫基类、超类)和子类(也可以叫派生类)。

​ 特点:

​ 1.子类可以拥有父类的内容。

​ 2.子类还可以有自己专有的内容。

​ 在父子继承关系中,如果有成员变量(成员方法)重名,则创建子类对象是,有两种访问方式。

​ 1.直接通过子类对象访问成员变量:等号左边是谁就优先用谁,没有就往上找。

​ 2.间接通过成员方法访问成员变量:方法属于谁就优先用谁,没有就往上找。

​ 3.访问成员方法的规则:创建对象是谁就优先用谁,如果没有则向上找。

​ 注意事项:无论是成员变量还是成员方法,如果没有都向上找父类,绝对不会向下找子类。

​ 区别子类方法中重名的三种变量

​ 1.局部变量:直接写成员变量名。

​ 2.本类的成员变量:this.成员变量名。

​ 3.父类的成员变量:super.成员变量名。

​ 继承关系中父子类构造方法的访问特点:

​ 1.子类构造方法中有一个默认隐含的“super()”调用,所以一定是先调用父类构造,后执行子类构造。

​ 2.子类构造可以通过super关键字来调用父类的重载构造。

​ 3.super的父类构造方法调用必须是子类构造方法的第一个语句,不难一个子类构造方法调用多个super。

总结: 子类必须调用父类的构造方法,不写赠送super();写了则用写了的指定的super调用,super只能有一个,且必须在子类构造方法的第一行。

继承三个特点:

​ 1.单继承,一个类的直接父亲只有一个。

​ 2.多级继承,一个类可以有一个父类,父类也可以有父类。

​ 3.一个父类可以有多个子类。

多态:

​ extends继承和implements实现,是多态性的前提。

​ 一个对象拥有多种形态,就是对象的多态性。

​ 代码当中体现多态性,就是父类名称指向子类对象。

​ 格式:

​ 父类名称 对象名 = new 子类名称();

​ 或者 接口名称 对象名 = new 实现类名称();

​ 多态中成员变量特点:

​ 1.直接通过对象名称访问成员变量:等号左边是谁就优先用谁,没有就往上找。

​ 2.间接通过成员方法访问成员变量:方法属于谁就优先用谁,没有就往上找。

​ 3.访问成员方法的规则:创建对象是谁就优先用谁,如果没有则向上找。

​ 口诀:

​ 成员变量:编译看左边,运行还看左边。

​ 成员方法:编译看左边,运行看右边。

向上转型和向下转型:

​ 向上转型:对象的向上转型就是多态写法。

​ 格式:父类名称 对象名 = new 子类名称();

​ 注意事项:向上转型一定是安全的。

​ 向下转型:对象的向下转型就是一个还原的动作。

​ 格式:子类名称 对象名 = (子类名称) 父类对象;

​ 注意事项:必须保证对象创建时是改子类,才能转型成改子类。比如new 猫 创建的,才能向下转型成猫。

​ instanceof:判断前面对象是不是后面的实例对象。

​ 格式:对象 instanceof 类名称 ;

​ 返回:返回的是一个boolean值。

对象

匿名对象

​ 创建对象的标准格式:

​ 类名称 对象名 = new 类名称();

​ 匿名对象就是只有右边的对象,没有左边的名字和赋值运算符。

​ new 类名称();

​ 注意事项:匿名对象只能使用唯一的一次,下次再用需再创建一个对象。

集合

ArrayList

​ 对于ArrayList来说,有一个尖括号代表泛型。

​ 泛型:也就是装在集合当中的所有元素,全都是统一的什么类型。

​ 注意:泛型只能是引用类型,不能是基本类型,如果要用基本类型可以使用基本类型的包装类。

备注:从jdk1.7+开始,右侧的尖括号内部可以不写内容,但是<>本身还是要写的。

注意事项:

​ 对于ArrayList集合来说,直接打印得到的不是地址值,而是内容。

​ 如果内容为空,得到的是空的中括号[]。

常用方法:

​ public boolean add(E e);向集合当中添加元素,参数的类型和泛型一致。

​ public E get (int index);从集合当中获取元素,参数是索引编号,返回值就是对应位置的元素。

​ public E remove (int index);从集合当中删除元素,参数是索引编号,返回值就是被删除的元素。

​ public int size();获取集合的尺寸长度,返回值是集合中包含的元素个数。

自动装箱

​ 自动装箱:基本类型 —>包装类型

​ 自动拆箱:包装类型 —>基本类型

字符串

字符串常量池(堆内存中)

​ 字符串常量池:程序当中直接写上双引号的字符串,就在字符串常量池中。

“==”判断

​ 基本类型:==号比较的是数值。

​ 引用类型:==号比较的是地址。

image-20201117224040563

常用方法

equals: 比较两个字符串内容,严格区分大小写。推荐使用方式 “abc”.equals(字符串变量)

​ 详情可见:https://blog.csdn.net/qq_21808961/article/details/80504104

静态Static关键字

修饰成员变量

​ 如果一个成员变量使用了static关键字,那么这个变量不在属于对象自己,而是属于所在的类。多个对象共享同一份数据。

​ 例:room使用了static修饰

image-20201117233442585 修饰成员方法

​ 一旦使用static修饰成员方法,那么就成了静态方法。静态方法不属于对象,属于类的。

​ 如果没有static关键字,必须先创建对象,才能使用方法。

​ 使用static修饰方法,可以通过对象使用方法(不推荐),也可以直接通过类名调用方法(推荐)。

总结: 无论成员变量还是成员方法,一旦使用static修饰都推荐直接使用类名调用。

方式: 类名称.静态方法();类名称.静态变量;

注意事项:

​ 1.静态不能访问非静态。(因为内存当中是有静态变量,有非静态变量)

​ 2.静态方法中不能使用this关键字。

静态static内存图

image-20201118000715051

静态代码块

​ 静态代码块格式:

​ public calss 类名称{

​ static{

​ //静态代码块内容

​ }

​ }

特点: 当第一次使用本类时,静态代码块执行唯一的一次。

静态内容总是优先于非静态,所以静态代码块比构造方法先执行。

Super和this关键字

​ super:可以理解为指向父类的一个指针。

​ this:表示指向对象本身的一个指针。

内存图解

image-20201119232744774

final关键字

四种用法:

​ 1.修饰类。(final类不能有子类)

​ 2.修饰方法。 (final修饰方法不能被覆盖重写,abstract和final不能同时用)

​ 3.修饰局部变量。 (final变量不能修改,只能赋值一次)

​ 4.修饰成员变量。 (成员变量具有默认值,所以用了final后一定要手动赋值,对于final成员变量要么直接赋值,要么构造方法赋值)

1.对基本类型来说,不可变说的是变量当中数据不可改变。

2.对于引用类型来说,不可变说的是变量当中地址值不可改变,但是当中的值可以变。

​ 2-例:

final studnet stu2 = new Student("张三");
//stu2 = new Student("李四");不允许的。
stu2.setName("王五");//可以的

四种权限控制符

publicprotected(default)private
同一个类
同一个包
不同包子类
不同包非子类

抽象方法和抽象类

抽象方法: 就是加上abstract关键字。例public abstract void test();

抽象类: 抽象方法所在的类必须是抽象类,在类前面加上abstract。抽象类不一定有抽象方法,但是抽象方法所在的类一定是抽象类。

​ 抽象类中可以有构造方法,供子类创建对象时,初始化父类使用。

​ 子类需要实现抽象类父类所有抽象方法,否则会报错,除非子类也是抽象类。

使用:

​ 1.不能直接创建new抽象类对象。

​ 2.必须用一个子类继承抽象类。

​ 3.子类必须覆盖重写抽象类所有的抽象方法。

​ 4.创建子类对象进行使用。

接口

接口

接口: 是一种引用数据类型,最重要的就是其中的抽象方法。

​ 在java 7中,接口中可以包含的内容有:1.常量。2.抽象方法。

​ 在java 8中,接口中还可以含有:3.默认方法。4.静态方法。

​ 在java 9中,接口中还可以含有:5.私有方法。

默认方法:

​ 1.接口的默认方法,可以通过接口实现类对象,直接调用。(当a,b实现了接口c时,需要给c新增加一个方法,但是这时a,b都已经投入使用了,这时就可以在c中使用默认方法)

​ 2.接口的默认方法,也可以被实现类覆盖重写。

静态方法:

​ 注意事项:静态方法不能通过接口实现类的对象来调用。

​ 调用方式:直接通过接口名加静态方法名。

私有方法:

​ 1.普通私有方法,解决多个默认方法之间代码重复问题。格式: public void test(){}

​ 2.静态私有方法,解决多个静态方法之间代码重复问题。格式: public static void test(){}

成员变量(常量):

​ 1.接口中常量,必须进行赋值,不能不赋值。

​ 2.接口中常量,使用完全大写的字母,用下滑线进行分隔。(命名规制)

注意事项:

​ 1. java中一个类只能有一个父类,但是可以实现多个接口。单继承,多实现。 但是接口和接口之间是多继承的,例接口A可以继承接口B,和接口C。

​ 2.如果实现类中存在重复的抽象方法,只要覆盖重写一次。

​ 3.如果不想重写所有方法,那就把自己变成抽象类。

​ 4.实现的多个接口中存在重复的默认方法,实现类中一定要对冲突的默认方法进行重写。

​ 5.一个接口的直接父类方法和实现接口当中的默认方法重复冲突,优先父类。

内部类

成员内部类

​ 使用成员内部类的两种方式:

​ 1.间接方式:在外部类的方法当中,使用内部类;然后main只是调用外部类的方法。

​ 2.直接方式:公式:外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();

局部内部类(包含匿名内部类)

​ 定义:如果一个类是定义在一个方法的内部的,那么这就是一个局部内部类。

​ “局部”:只有当前所属的方法才能使用它,出了这个方法外面就不能用了。

​ 局部内部类,如果希望访问所在方法的局部变量,那么这个局部变量必须是有效final的。(java8开始,final可以省略)

原因

​ 1.new出来的对象在堆内存当中。

​ 2.局部变量是跟着方法走的,在栈内存当中。

​ 3.方法运行结束之后,立刻出栈,局部变量就会立刻消失。

​ 4.但是new出来的对象就会在堆当中持续存在,直到垃圾回收消失。

匿名内部类

​ 定义:如果接口的实现类只需要使用唯一的一次,那么这种情况下就可以省掉改类的定义,而改为使用匿名内部类。

​ 格式:

​ 接口名称 对象名 = new 接口名称(){

​ //覆盖重写所有抽象方法

​ }

​ 注意:

​ 1.匿名内部类,在创建对象的时候,只能使用唯一一次。(多次创建,使用单独的实现类)

​ 2.匿名对象,在调用方法的时候,只能调用唯一一次。(多次调用,需给对象命名)

​ 3.匿名内部类是省略了【实现类/子类名称】,但是匿名对象是省略了【对象名称】

​ 强调:匿名内部类和匿名对象不是一回事!!

类的权限修饰符

​ 1.外部类:public/(default)

​ 2.成员内部类:public/protected/(default)/private

​ 3.局部内部类:什么都不能写。

Object类和objects类

object类介绍

​ Object是所有类的父类,一个类都会直接或间接的继承该类。

toString()方法

​ 作用:打印对象信息。

​ 重写前:打印包名类名@地址。

​ 重写后:打印对象中的属性值。

equals()方法

​ 作用:比较两个对象

​ 重写前:比较的是对象的地址值。

​ 重写后:比较的是对象的属性值。(重写就是将对象转化为基础属性用"=="比较或者转化为字符创用equals比较,具体请看源码)

Objects类的equals方法

​ 比较两个对象是否相同,就是增加了一些健壮性判断,比如null情况。

包装类

定义

​ 因为没有对应的方法操作基本类型数据,通过定义一个类,把基本数据类型包装起来,这就是包装类。

装箱和拆箱

​ 装箱:基本类型 —>包装类型

​ 拆箱:包装类型 —>基本类型

​ jdk1.5以后支持自动1装箱和拆箱。

​ 自动装箱:直接把int类型的整数赋值给包装类。

​ 自动拆箱:Integer对象是包装类,无法直接参与运算,会自动转换为基本类型再参与计算。

​ ArrayList集合就是典型,ArrayList无法直接存储整数,所以存储Integer类使用到自动装箱和自动拆箱。

集合

概述

​ 集合:java中提供存储数据的容器。集合长度是可变的。集合中存储的都是对象,而且对象类型可以不一致。

集合框架图

image-20201130230051505

Collection常用方法

​ 1.add(E e); 向集合中添加元素。

​ 2.remove(E e); 删除集合中某个元素。

​ 3.clear(); 清空集合中所有元素。

​ 4.contains(E e); 判断集合中是否包含某个元素。

​ 5.isEmpty(); 判断集合是否为空。

​ 6.size(); 获取集合长度。

​ 7.toArray(); 将集合转化为数组。

Iterator接口(迭代器)和增强for循环

迭代器

​ 作用:对集合进行遍历。

​ 常用方法;

​ 1.hasnext(); 判断集合还有没有下一个元素,如果有返回true。

​ 2.next(); 返回迭代的下一个元素。

​ 使用:通过Collection中的 iterator() 方法获取迭代器对象,然后通过 hasnext() 判断还有没有下一个元素,通过 next() 取出下一个元素。

增强for循环

​ 增强for循环底层使用的是迭代器,简化了迭代器的书写。jdk1.5后的新特性。

​ Collection extends Iterator:所有的单列集合都可以使用增强for

​ 增强for循环:用来遍历集合和数组。

​ 格式:for(集合/数组数据类型 变量名:集合/数组名){

​ sout(变量名);

​ }

List集合

​ 特点:

​ 1.有序集合,存储和取出元素顺序一致。

​ 2.有索引,包含一些带索引的方法。

​ 3.允许重复元素。

​ list特有方法:

​ 1.add(int index,E element):指定位置添加元素

​ 2.get(int index):获取指定位置元素

​ 3.remove(int index):移除指定位置元素

​ 4.set(int index,E element):替换指定位置元素

ArrayList集合

​ ArrayList集合的数据存储结构是数组结构,元素增删慢,查询快。

LinkList集合

​ 特点:

​ 1.LinkList集合的数据存储结构是链表结构,元素增删快,查询慢。

​ 2.里面包含了大量操作首尾元素的方法。

​ 注意:使用LinkList结合特有的方法不能使用多态。

​ 特有方法:

​ 1.addFirst(E e) :将元素插入开头

​ 2.addLast(E e):将元素插入结尾

​ 3.push(E e):将元素压入列表所表示的堆栈

​ 4.getFirst():获取列表第一个元素

​ 5.getLast():获取列表最后一个元素

​ 6.removeFrist():移除并返回列表第一个元素

​ 7.removeLast():移除并返回列表最后一个元素

​ 8.pop():从列表所表示的堆栈弹出元素

Vector集合

​ vector可以实现可增长的对象数组,vector是同步的。

Set集合

​ 特点:

​ 1.不允许存储重复元素

​ 2.没有索引,没有带索引的方法,不能使用普通for循环遍历。

HashSet集合

​ 特点:

​ 1.不允许存储重复元素

​ 2.没有索引,没有带索引的方法,不能使用普通for循环遍历。

​ 3.是一个无序集合,存储和取出顺序可能不一致。

​ 4.底层是一个hash表结构。

元素不重复原理

​ Set集合在调用add方法的时候,add会调用元素的hashCode方法和equals方法,判断元素是否重复。

​ 通过hashCode判断是否有相同哈希值的元素,没有则加入,有相同哈希值的元素,再用eqauls判断两元素是否相同,相同的话新元素就覆盖旧的元素,不相同的话就将元素加到链表中。

image-20201203002524295

​ HashSet存储自定义元素类型:

​ set集合报错元素唯一:

​ 存储的元素(String,Interger…,Student),必须重写hashCode方法和equals方法

LinkedHashSet

​ 特点:底层是一个哈希表+链表。多了一条链表,保证元素有序。

哈希值

​ 哈希值:是一个十进制整数,由系统随机给出(就是对象的地址值,是一个逻辑地址值,模拟出来的,不是数据实际存储的物理地址)

​ 在Object类中,int hashCode() 返回改对象的哈希码值。

​ String类重写了Objec类的hashCode方法。

哈希表

​ hashset集合存储数据的结构(哈希表),哈希表特点:查询速度快

​ jdk1.8之前:哈希表 = 数组 + 链表

​ jdk1.8之后:哈希表 = 数组 + 红黑树(当链表长度超过8位转为红黑树)

​ 数据结构:把元素进行了分组(相同哈希值的元素是一组),链表/红黑树结构把相同的哈希值元素连接在一起。

image-20201203002236547

Collections

​ 常用功能:

​ 1.addAll(Collection c,T… elements):往集合中添加一些元素

​ 2.shuffle(List<?> list):打乱集合顺序

​ 3.sort(List list):将集合中元素按照默认规则排序。使用前提被排序的集合里边存储的元素,必须实现Comparable,重写CompareTo定义排序的规制。

​ CompareTo规则:自己(this) - 参数 :升序

​ 4.sort(List list,Comparator<? super T>):将集合中元素按照指定规则排序。

Map集合

​ 特点:

​ 1.双列集合,一个元素包含两个值(key,value)

​ 2.key和value数据类型可以不同

​ 3.元素中key不能重复,value能重复

​ 4.key和value对应的

常用方法:

​ 1.put(key,value):将键值添加到集合中,key不重复返回null,key重复返回被替换的值

​ 2.remove(key):按照指定的键移除集合中元素,key存在返回被删除的值,key不存在返回null

​ 3.get(key):获取指定键的值,key不存在返回null

​ 4.containsKey(key):判断集合中是否包含key,包含返回true,不包含返回false、

​ 5.keySet():获取集合中所有的键,存入set中

​ 6.entrySet():获取map集合中所有键值对对象的集合(set集合)

​ 遍历map两种方式

​ 第一种:通过键找值。

​ 1.通过keySet()方法把map集合的键存入set集合中。

​ 2.遍历set集合,获取map集合的key。

​ 3.通过map中get(key)方法,通过key找到value。

​ 在map接口中有一个内部接口Entry,当map集合一创建,那么就会在map集合中创建一个entry对象,用来记录键与值。

​ Entry对象中的方法,getKey获取键,getValue获取值

​ 第二种:通过Map.Entry(k,v)获取获取对象

​ 1.通过map集合中的entrySet()方法,把map集合中多个Entry对象取出来,存入set集合中。

​ 2.遍历set集合,获取每一个Entry对象

​ 3.使用Entry对象中的getkey()和getvalue()获取键与值

HashMap

​ 特点:

​ 1.底层是哈希表,查询速度特别快。

​ jdk1.8之前:数组 + 链表

​ jdk1.8之后:数组 + 链表/红黑树(链表长度大于8转化为红黑树)

​ 2.无序集合,存入和取出顺序可能不一致

​ HashMap存储自定义类型的键值:

​ map集合必须保证key值是唯一的:作为可以元素必须重写hashCode方法和equals方法,以保证唯一性。

​ 1.key:person类型

​ person类必须重写hashCode方法和equals方法

​ value:String类型

​ 可以重复

​ 2.key:String类

​ String类重写了hashCode方法和equals方法,可以保证key唯一

​ value:person类型

​ 可以重复

LinkedHashMap

​ 特点:

​ 1.底层是哈希表 + 链表

​ 2.有序集合,一条链表存储顺序

HashTable

​ 特点:

​ 1.底层哈希表,线程安全,单线程集合,速度慢。

​ 2.不能存储空值空键。

泛型

定义

​ 泛型:一种未知的数据类型,当不知用什么数据类型的时候就可以使用泛型。

泛型类和泛型方法

​ 含有泛型的类:定义对象的时候如果不能确定类型,那可以使用泛型。

​ 格式:在类后面加 ,然后把变量和方法定义为泛型。

​ 类名<泛型>

​ 方法名<泛型>

泛型接口和泛型方法

​ 格式:接口名后面加泛型,实现时接口后面加泛型、实现类名后面加泛型、方法加泛型,如果实现类和接口后面不加泛型,方法默认Object类型。

​ 接口名<泛型>

​ 实现类名<泛型> implements 接口名<泛型>{

​ 方法名(泛型)

​ }

泛型通配符

public static void main(String[] args) {
        ArrayList<String> list1 = new ArrayList<>();
        list1.add("sdfas");
        list1.add("asdfa");
        printfinfo(list1);
        printfinfo2(list1);

        ArrayList<Integer> list2 = new ArrayList<>();
        list2.add(21);
        list2.add(22);
        printfinfo(list2);
        printfinfo2(list2);
    }

    public static void printfinfo(ArrayList<?> list){
        for (int i = 0; i < list.size(); i++) {
            System.out.println("泛型通配符----" + list.get(i));
        }
    }

	//泛型方法貌似能达到一样的效果?
    public static <E> void printfinfo2(ArrayList<E> list){
        for (E e : list) {
            System.out.println("泛型方法----" + e);
        }
    }

数据结构

​ 栈(stack):又称堆栈,运算受限的线性表,只允许一段进行增加和删除操作。在元素存储中,先进后出

数组

​ 数组(array):有序的元素列,在内存中开辟一段连续的内存空间。

查询快: 数组的地址是连续的,可以通过首地址找到数组,并通过索引查询数据。

增删慢: 数组长度固定,要新增或删除元素,必须新建一个数组,把原数组复制过来。

链表

​ 链表(linked list):由一系列节点组成,节点可以动态生成,地址不连续。

查询慢: 链表中地址不是连续的,每次查询元素,都必须从头开始查。

增删快: 链表结构,增加和删除一个元素,对链表整体结构没有影响,所以快。

单向链表: 链表中只有一条链子,不能保证元素顺序(存入和取出)。

双向链表: 链表中有两条链子,一条专门记录顺序。

红黑树

​ 二叉树:分支不能超过两个。

​ 排序树/查找树:二叉树的基础上,元素是有顺序的,左子树小,右子树大。

​ 平衡树:左孩子等于右孩子。

​ 非平衡树:左孩子不等于右孩子。

​ 红黑树

​ 特点:趋近于平衡树,查询速度非常快,查询叶子节点的最大次数和最小次数不能超过两倍。

image-20201202213310504

可变参数

​ jdk1.5之后出现的新特性

​ 使用前提:参数列表数据类型确定,数据个数不确定时,使用可变参数。

​ 格式:修饰符 返回值类型 方法名(数据类型…变量名){}

​ 原理:底层是一个数组,根据传递的参数建立。

​ 注意事项:

​ 1.一个方法参数列表,只能有一个可变参数。

​ 2.如果方法中参数有多个,可变参数在参数列表结尾

异常

概念

​ 异常:程序 执行过程 中,出现的非正常的情况,最终会导致JVM的非正常。异常本身是一个类,产生异常就是穿件异常对象并抛出了一个异常对象。java处理异常方式是中断处理。

异常分类

​ 编译期异常:checked异常。在编译时期,就会检查,如果没有处理异常就会编译失败。(如日期格式化异常)

​ 运行期异常:runtime异常。在运行时期检查异常。编译时期,运行异常编器不会检查。(如数字异常)

异常产生图解

image-20201209202757026

异常处理

抛出异常throw

​ 当程序异常时(如参数不合法等),需要使用抛出异常的方式告诉调用者。

​ 步骤:

​ 1.创建一个异常对象,封装提示信息(信息可以自己编写)

​ 2.通过throw将异常抛出,即可告知调用者。

​ throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。

​ 注意:如果产生了问题,我们就会throw将问题描述类即异常进行抛出,也就是将问题返回给该方法的调用者。

​ 那么对于调用者来说,该怎么处理呢?一种是进行捕获处理,另一种就是继续讲问题声明出去,使用throws声明处理。

objects非空判断

​ 略

声明异常throws

​ 声明异常:将问题标识出来,告诉调用者。如果方法内通过throw抛出了编译时异常,而没有捕获处理,那么必须通过throws进行声明,让调用者去处理。

​ throws运用于方法声明之上,表示当前方法不处理异常,提示方法调用者处理。

​ 格式:方法名() throws 异常类名1,异常类名2…

捕获异常try…catch

​ 捕获异常:java对异常有针对性的语句进行捕获,可以对出现的异常进行指定性的捕获。

​ try:编写可能产生异常的代码。

​ catch:捕获异常,并对捕获到的异常进行处理。

​ 获取异常信息方法:public void printStackTrace();打印异常信息并输出到控制台。

finally代码块

​ 一些特定的代码无论异常是否发生都要执行(如关闭io流),就需要用到。

​ 语法:try…catch…finally:自身需要处理异常,最终还得关闭资源。

​ 当只有在try或者catch中调用退出JVM的相关方法,此时finally才不会执行,否则finally永远会执行。

异常注意事项

​ 多个异常的处理

​ 1.多个异常分别处理。try…catch…;try…catch…。一个try中只有一个异常。

​ 2.多个异常一次捕获,多次处理。try…catch…catch…catch…。try中有多个异常,catch处理异常只能从小到大。

​ 2.多个异常一次捕获一次处理。try…catch…。try中有多个异常,但是catch中直接用父类异常处理。

自定义异常

​ 当java提供的异常不够使用时,自定义异常类。

​ 格式:public calss XXXException extends Exception | RuntimeException{

​ 添加一个空参数的构造方法

​ 添加一个带异常信息的构造方法

​ }

​ 注意:

​ 1.自定义异常类一般都以Exception结尾,说明改类时异常类。

​ 2.自定义类必须继承Exception或者RuntimeException

​ 继承Exception:那么自定义的异常类就是一个编译器异常,如果方法内部出现了异常,需要try…catch或者throws

​ 继承RuntimeException:自定义异常类是一个运行期异常,无需处理,交给虚拟机处理(中断处理)。

多线程

并发和并行

​ 并发:两个或多个事件在同一时间段内发生。

​ 并行:两个或多个事件在同一时刻发生(同时发生)。

线程和进程

​ 进程:指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程。进程是程序的一次执行过程,是系统运行程序的基本单位。系统运行一个程序即是一个进程从创建、运行到消亡的过程。

​ 线程:线程是进程的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中可以有多个线程,这个应用程序可以称之为多线程程序。

线程调度

​ 分时调度:所有线程轮流使用cpu,评价分配每个线程占用cpu时间。

​ 抢占式调度:优先级高的线程优先使用cpu,如果优先级相同,则随机分配。java使用的就是抢占式调度。

主线程

​ 主线程:执行主方法(main)的线程

​ 单线程程序:java程序中只有一个线程,执行从main开始,从上往下依次执行

​ 流程:JVM执行main方法,main方法进入栈内存,jvm找操作系统开辟一条main方法通向cpu的执行路径,cpu可以通过这条路径执行main方法,路径的名字叫主(main)线程。

创建线程类方式

1.继承Threa类

​ 步骤:

​ 1.创建Thread子类,并重写run()方法。run()方法的方法体代表了线程需要完成的任务,run()称为线程执行体。

​ 2.创建thread子类对象。

​ 3.调用对象的start()方法。

2.实现Runnable接口

​ 步骤:

​ 1.创建一个Runnable接口实现类,重写run()方法。

​ 2.创建一个实现类的对象。

​ 3.创建Thread类对象,构造方法中传递Runnable接口实现类对象。

​ 4.调用Thread类对象的start()方法。

​ 实现Runnable接口创建多线程的好处:

​ 1.避免单继承的局限性。

​ 2.增强了程序的扩展性,降低了程序的耦合。

多线程常用方法

​ 1.public String getName():获取当前线程的名称。

​ 2.public void setName(String name):设置线程名称

​ 3.public static void sleep(long millis):使当前线程暂停指定毫秒数。

​ 4.public static Thread currentThread():返回对当前正在执行的线程对象的引用。

多线程内存图解

image-20201210214706948

线程安全

​ 买票问题

image-20201210223226631

synchronize

synchronize:关键字用于方法的某个区块中,表示对这个区块的资源进行互斥访问。

同步代码块

​ 解决线程安全的一种方法:使用同步代码块。

​ 格式:

​ synchronize(锁对象){

​ 可能会出现安全问题的代码(如访问共享数据)。

​ }

​ 注意:

​ 1.通过代码块中的锁对象,可以使用任意对象。

​ 2.必须保证多个线程使用的锁对象是同一个。

​ 3.锁对象的作用:把同步代码块锁住,只让一个线程在同步代码块中执行

同步方法

​ 解决线程安全问题的第二种方法:使用同步方法

​ 步骤:

​ 1.把共享代码抽取出来,放入方法中。

​ 2.给方法添加synchronize修饰符。

​ 格式:

​ public synchronize 返回值类想 方法名(){

​ 共享代码

​ }

​ 注意:

​ 1.同步方法的锁对象是实现类对象也就是this。

​ 2.静态同步方法锁对象不是是this,this是创建对象之后产生的,静态方法优先于对象。静态方法的锁对象是本类的class属性---->class文件对象(反射)

Lock锁

​ jdk1.5之后出现。Lock提供了比synchronize更广泛的锁定操作。

​ 解决线程安全的第三种方式:使用Lock锁。

​ Lock接口中的方法:

​ 1.获取锁:void lock()

​ 2.释放锁:void unlock()

​ 使用步骤:

​ 1.在成员位置创建一个ReentrantLock对象。

​ 2.在可能会出现问题的代码前调用Lock接口中的lock方法获取锁。

​ 3.在可能会出现问题的代码候调用Lock接口中的unlock方法释放锁。

同步技术原理

​ 像自动洗车间,把资源给一辆车使用,这辆车洗完了把资源让出来了,才会给下一辆车洗。车不是排队的,当洗车间空出来时,谁抢到就是谁的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SvbGz4sk-1608815065044)(https://i.loli.net/2020/12/11/KGHcl6Cz1LaqUfe.png)]

线程状态

状态描述
new(新生态)线程刚被创建,没有启动
Runnable(运行态)线程在java虚拟机运行的状态
Blocked(锁阻塞)当线程获取锁而锁被别的线程占用时,线程进入阻塞状态,当线程持有锁时线程变成运行态
Waiting(无限等待)当线程需要被另一个线程唤醒是就进入了waiting状态。需要notify或notifyAll唤醒。
Timed Waiting(计时等待)同waiting状态,当调用sleep等定时睡眠方法时,就会进入计时等待状态,时间结束自动唤醒
Terminated(死亡态)因run方法正常退出而死亡,或者没有捕获异常终止了run而死亡

图解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nQJx48Yt-1608815065049)(https://i.loli.net/2020/12/11/UowhNgcq1sF3VSe.png)]

Oject中等待方法和唤醒方法

​ 等待:

​ 1.sleep(long m):在毫秒值结束后,线程由睡眠进入Runnable/Blocked状态

​ 2.wait(long m):不带参数进入等待状态需要他人唤醒。带参数进入等待状态过时自动唤醒。

​ 唤醒:

​ 1.notify():唤醒在此对象监视器等待的单个线程。

​ 2.notifyAll():唤醒在此对象监视器的所有线程。

等待唤醒机制

线程间通信

​ 概念:多个线程处理同一资源,但是处理的动作不相同。

​ 当多个线程完成同一个任务时,需要线程之间通信,协调多个线程一起操作同一份数据。

等待唤醒机制

​ 一个线程执行完指定操作后,进入等待状态,等待其他线程执行完指定的代码后,将其唤醒。

​ 等待唤醒中的方法:wait(),notify(),notifyAll()

​ 使用wait和notify方法注意:

​ 1.wait方法和notify方法必须由同一个锁对象调用。

​ 2.wait方法和notify方法是属于Object类的方法的。因为锁对象可以是任意对象。

​ 3.wait方法和notify方法必须要在同步方法块或同步函数中使用。

线程池

​ 概念:一个容纳多个线程的容器(LinkedList,使用时就remove,使用完毕就add),其中的线程可以反复使用,省去了频繁创建线程操作,无需反复创建线程消耗资源。

​ 线程池:jdk1.5后

​ Executors:线程池工厂类,用来生成线程池。

​ 工厂类中静态方法newFixedThreadPool(int 线程数)创建一个可重用固定线程的线程池。

​ 返回值:ExecutorService接口的实现类对象,我们可以使用ExecutorService接口接收。

​ ExecutorService接口:

​ 用来从线程池中获取线程,调用stat方法,执行线程任务:submit(Runnable task) 提交一个Runnable任务用于执行。

​ 关闭/销毁线程池方法:void shutdown()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4s6EvZIj-1608815065050)(https://i.loli.net/2020/12/12/uBzb8ylUfwnX21N.png)]

Lambda

​ 格式:(参数类型 参数名称) -> { 代码语句 }。例如

	new Thread(new Runnable() {
        @Override
        public void run() {
        System.out.println("多线程任务执行!");
        }
    }).start();
    
    //可以写为
    new Thread(()->{
    	System.out.println("多线程任务执行!");
    })

​ lambda省略写法

​ 省略规则:

​ 1.小括号中参数类型可以省略。

​ 2.如果小括号中有且只有一个参数,则括号可以省略

​ 3.当大括号中有且只有一条语句,无论是否有返回值,都可以省略大括号、return关键字和分号

​ lambda使用前提:

​ 1.使用lambda必须具有接口,且接口中有且仅有一个抽象方法。

​ 2.使用lambda必须具有上下文推断,也就是方法的参数或局部变量类型必须为lambda对应的接口类型,才能使用lambda作为该接口的实例。

File类

概述

​ 概述:java.io.File雷士文件和目录路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作。

构造方法

​ 1.File(String pathname):通过将给钉钉路径名字符串转换为抽象路径名来创建型的File实例。

​ 2.File(String parent,String child):从父路径名字符串和子路径名字符串创建新的File实例。

​ 3.File(File parent,String child):从父抽象路径名和子路径名字字符串创建新的File实例。

常用方法

获取功能方法

​ 1.public String getAbsolutePath():返回File的绝对路径名字符串。

​ 2.public String getPath():将此File转换为路径名字字符串。

​ 3.public String getName():返回由此File表示的文件或目录的名称。

​ 4.public long length():返回由此File表示的文件的大小。

绝对路径和相对路径

​ 绝对路径:从盘符开始的路径,是一个完整的路径。

​ 相对路径:从相对于项目目录的路径。

判断功能的方法

​ 1.public boolean exists():查询此File表示的文件或目录是否实际存在。

​ 2.public boolean isDirectory():判断此File表示的是否为目录。

​ 3.public boolean isFile():判断此File表示是否为文件。

创建删除功能的方法

​ 1.public boolean createNewFile():当且仅当具有该名称的文件不存在时,创建一个新的空文件。

​ 注意:

​ 此方法只能创建文件,不能创建文件夹。

​ 创建文件的路径必须存在,否则会抛出异常。

​ 2.public boolean delete():删除由此File表示的文件或目录。

​ 3.public boolean mkdir():创建由此File表示的目录。–创建单级空文件夹。

​ 4.public boolean mkdirs():创建由此File表示的目录,包括任何必须但不存在的父目录。–既可以创建单级空文件夹,也可以创建多级文件夹。

​ 注意:当多级创建使用相对路径,不管路径存不存在,都会创建。

递归

概述

​ 递归:指在当前方法内调用自己的这种现象。

​ 分类:

​ 直接递归:方法自己调用自己。

​ 间接递归:方法a调用方法b,方法b调用方法c,方法c调用方法a。

​ 注意事项:

​ 1.递归一定要有出口,否则会发生栈内存溢出。

​ 2.递归次数不能太多,否则也会发生栈内存溢出。

​ 3.构造方法,禁止递归。

递归图解

public class DiGuiDemo {
	public static void main(String[] args) {
		//计算1~num的和,使用递归完成
		int num = 5;
      	// 调用求和的方法
		int sum = getSum(num);
      	// 输出结果
		System.out.println(sum);
		
	}
  	/*
  	  通过递归算法实现.
  	  参数列表:int 
  	  返回值类型: int 
  	*/
	public static int getSum(int num) {
      	/* 
      	   num为1时,方法返回1,
      	   相当于是方法的出口,num总有是1的情况
      	*/
		if(num == 1){
			return 1;
		}
      	/*
          num不为1时,方法返回 num +(num-1)的累和
          递归调用getSum方法
        */
		return num + getSum(num-1);
	}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-57MlTxGe-1608815065053)(https://i.loli.net/2020/12/16/PjN2hCKE1SJzrXw.png)]

IO流

​ 根据流向分类:

​ 1.输入流:把数据从其他设备上读取到内存中的流。

​ 2.输出流:把数据从内存中写出到其他设备上的流。

​ 根据数据类型分类:

​ 1.字节流:以字节为单位,读写数据的流。

​ 2.字符流:以字符为单位,读写数据的流。

​ io的流向:

​ 1.输入:硬盘—>内存

​ 2.输出;内存—>硬盘

​ 顶级父类:

​ 字节流

​ 输入:InputStream

​ 输出:OutputStream

​ 字符流

​ 输入:Reader

​ 输出:Writer

字节流

字节输出流(OutputStream)

​ java.io.OutputStream是字节输出流的所有类的超类,将指定字节信息写出到目的地。

​ 字节输出流的基本共性方法:

​ public void colse():关闭流并释放资源。

​ public void flush():刷新此输出流并强制任何缓冲的输出字节被写出。

​ public void write(byte[] b):将b.length字节从指定的字节数字写入此输出流。

​ public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。

​ public abstract void write(int b) :指定字节的输出流。

FileOutputStream类

​ 文件输出流,将数据写出到文件。

​ 构造方法:

​ FileOutputStream(File file):创建文件输出流写入由指定的File对象表示的文件。

​ FileOutputStream(String name):创建文件输出流以指定的名称写入文件。

​ 使用步骤:

​ 1.创建流对象

​ 2.写出数据

​ 3.关闭流对象,释放资源。

​ 数据追加续写:

​ FileOutputStream(xx xx,boolean append):两个构造方法后面可以多传入一个布尔类型的值,true表示追加数据,false表示清空数据。

​ 写出换行:windows:\r\n ; linux:\n ; mac: \r

​ 格式:fos.write("\r\n".getBytes());

字节输入流(InputStream)

​ InputStream抽象类表示字节输入里的所有类的超类,可以读取字节信息到内存中。

​ 字节输入流基本共性方法:

​ 1.public void colse():关闭流释放资源。

​ 2.public abstract int read():从输入流读取数据的下一个字节。

​ 3.public int read(byte[] b):从输入流中读取一些字节数,并存储到字节数组b中。返回的int值表示的是字节数组b的长度。

FileInputStream类

​ 文件输入流,从文件中读取字节

​ FileInputStream(File file):通过打开与实际文件的连接来创建文件输入流,文件有文件系统中的File对象file命名。

​ FileInputStream(String name):通过打开与实际文件的连接来创建文件输入流,文件有文件系统中的路径名name命名。

​ 使用步骤:

​ 1.创建流对象

​ 2.读取数据,返回字节(读到末尾时返回-1)。

​ 3.关闭流对象,释放资源。

字符流

字符输入流(Reader)

​ reader读取字符流所有类的超类,读取字符信息到内存中。

​ 字符输入流的基本共性方法:

​ 1.public void colse():关闭流释放资源。

​ 2.public int read():从输入流读取一个字符。

​ 3.public int read(char[] cbuf):从输入流中读取一些字符,并存储在字符数组cbuf中,返回的int值表示字符数组长度。

FileReader类

​ FileReader 类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区(一个字节数组,用来临时存储字节数据)。

​ FileReader(File file): 创建一个新的 FileReader ,给定要读取的File对象。

​ FileReader(String fileName): 创建一个新的 FileReader ,给定要读取的文件的名称。

字符输出流(Writer)

​ writer所有写出字符流的超类,将指定字符信息写入到目的地。

​ 基本共性方法:

void write(int c) 写入单个字符。

void write(char[] cbuf)写入字符数组。

abstract void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。

void write(String str)写入字符串。

void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。

void flush()刷新该流的缓冲。 void close() 关闭此流,但要先刷新它。

FileWriter类

java.io.FileWriter类是写出字符到文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。

FileWriter(File file): 创建一个新的 FileWriter,给定要读取的File对象。

FileWriter(String fileName): 创建一个新的 FileWriter,给定要读取的文件的名称

关闭和刷新

​ 因为内置缓存区的原因,如果不关闭输出流,无法写入字符到文件中。但是关闭流对线无法继续写数据,这时可以用flush方法,刷新缓冲区。

​ flush:刷新缓存区,流对象继续使用,最后还是需要close释放资源。

​ close:刷新缓存区,关闭流对象,释放资源。

Properties

​ Properties集合 extends Hashtable<k,v> implements Map<k,v>

​ properties 类表示了一个持久的属性集。Properties可以保存在流中或从流中加载。

​ Properties集合是唯一一个与IO流相结合的集合:

​ 可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储。

​ 可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用。

​ load方法

​ void load(InputStream inStream):字节输入流

​ void load(Reader reader):字符输入流

​ 使用步骤

​ 1.创建Properties集合

​ 2.使用Properties集合对象中的load方法读取保存键值对的文件

​ 3.遍历Properties集合

​ 注意:

​ 1.键值对文件中,键值默认连接符号可以使用符号、空格(其他符号)

​ 2.键值对文件中,使用 # 注释

​ 3.键值对文件中,键值默认是字符串,不用加引号

​ 属性列表中每个键及其对应的值都是一个字符串。

​ Properties集合是一个双列集合,key和value默认都是一个字符串。

​ Properties集合中操作字符串的特有方法

​ Object setPorperty(String key,String value)调用Hashtable的方法put

​ String getPorperty(String key)通过key找到value值,此方法相当于map中的get(key)方法

​ Set stringPorpertyNames()返回此属性中的键集,其中该键对应的值是字符串,此方法相当于map中的keySet方法。

缓冲流

概述

​ 缓冲流,也叫高效流,对4个基本的FileXxx流的增强,所以也是4个流。

​ 按数据类型分类:

​ 字节缓冲流:BufferedInputStream,BufferedOutputStream

​ 字符缓冲流:BufferedReader,BufferedWriter

​ 基本原理:在创建流对象时,会创建一个内置默认大小的缓冲区数组,通过缓冲区读写,减少系统io次数,从而提高读写效率。

字节缓冲流

​ java.io.BufferedOutputStream extends OuptutStream,继承了父类的共性方法,Input也一样。

​ 构造方法:

​ BufferedInputStream(InputStream in):创建一个新的缓冲输入流。

​ BufferedInputStream(InputStream in,int size):创建具有指定缓冲区大小的BufferedInputStream并保存其参数,即输入流in,以便来使用。

​ BufferedOutputStream(OutputStream out):创建一个新的缓冲输出流。

​ BufferedOutputStream(OutputStream out,int size):创建一个缓冲输出流,将指定缓冲区大小的数据写入指定的底层输出流。

​ 使用步骤:

​ 1.创建FileOutputStream对象,构造方法中绑定要输出的目的地。

​ 2.创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象。

​ 3.使用BufferedOutputStream对象中方法write,把数据希尔到内部缓冲区。

​ 4.使用BufferedOutputStream中flush方法,把缓冲区数据刷新到文件。

​ 5.释放资源。

字符缓冲流

​ java.io.BufferedWriter extends Writer,继承了父类的共性方法,Reader也一样

​ 构造方法:

​ BufferedWriter(Writer out)创建一个默认大小输出缓冲区的缓冲字符输出流。

​ BufferedWriter(Writer out,int sz)创建一个使用给定大小输出缓冲区的缓冲字符流。

​ BufferedReader(Reader in)创建一个使用默认大小输入缓冲区的缓冲字符输入流。

​ BufferedReader(Reader in,int sz)创建一个使用制定大小输入缓冲区的缓冲字符输入流。

​ 特有成员方法:

​ BufferedWriter: void newLine()写入一个分隔符。根据操作系统获取。

​ BufferedReader:String readLine()读取一个文本行。读取一行数据。不包含终止符,如果达到流末尾返回null

​ 使用步骤:

​ 1.创建字符缓冲流对象,构造方法中传递字符输出流

​ 2.调用字符缓冲输出流中的方法write,把数据写入到内存缓冲区中。

​ 3.调用flush方法,将缓冲区中的数据刷新到文件中。

​ 4.释放资源

转换流

字符编码和字符集

​ 编码:字符—>字节

​ 解码:字节—>字符

​ 字符编码:自然语言的字符和二进制之间的对应规则。

​ 字符集:也叫编码表。是一个系统支持所有字符的集合,包括各国家文字,标点符号等。

​ 常用字符集:utf-8,gbk

​ idea默认字符集utf-8,windows默认字符集GBK。

​ utf-8中中文字符大部分占用3个字节,GBK中中文字符大部分占用2个字节,当解析方式不匹配时,就会造成乱码。

OutputStreamWriter

​ Writer的子类,是字符通向字节的桥梁,可使用指定的charset将要写入的流中的字符编码成字节。

​ 构造方法:

​ OutputStreamWriter(OutputStream out):创建使用默认字符编码的OutputStreamWriter。

​ OutputStreamWriter(OutputStream out,String charsetName):创建指定字符集的OutputStreamWriter。

​ 使用步骤:

​ 1.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称。

​ 2.使用OutputStreamWriter的write方法,把字符转为字节存储在在缓冲区中。

​ 3.使用flush,将缓冲区中的字节刷新到文件中。

​ 4.释放资源。

InputStreamReader

​ Reader的子类,从字节流到字符流的桥梁。读取字节,使用指定的字符集将其解码为字符。

​ 构造方法:

​ InputStreamReader(InputStream in):创建一个使用默认字符集的字符流。

​ InputStreamReader(InputStream in,String charsetName):创建一个指定字符集的字符流。

​ 使用步骤:

​ 1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称。

​ 2.使用InputStreamReader的read方法读取文件。

​ 3.释放资源

​ 注意事项:构造方法中指定编码要与文件编码相同。

转换流原理图

在这里插入图片描述

序列化和反序列化

序列化

​ 序列化:把对象以流的方式写入文件中保存,叫写对象,也叫对象的序列化。

​ ObjectOutputStream:对象的序列化流。继承OutputStream

​ 构造方法:ObjectOutputStream(OutputStream out):创建写入指定OutputStream 的ObjectOutputStream

​ 特有的成员方法:void writeObject(Object obj):将指定的对象写入ObjectOutputStream

​ 使用步骤:

​ 1.创建ObjectOutputStream对象,构造方法中传递字节输出流。

​ 2.使用ObjectOutputStream对象的writeObject方法,把对象写入文件

​ 3.释放资源。

注意:要进行序列化和反序列化的类必须实现Serializable接口。

反序列化

​ 反序列化:把文件中保存的对象以流的方式读取出来,叫做读对象,也叫对象的反序列化。

​ ObjectInputoutStream:对象的反序列化流。

​ 构造方法:ObjectInputoutStream(InputStream in):创建从指定InputStream 读取的ObjectInputoutStream

​ 特有的成员方法:void readObject(Object obj):从ObjectOutputStream读取对象

​ 使用步骤:

​ 1.创建ObjectInputoutStream对象,构造方法中传递字节输入流。

​ 2.使用ObjectInputoutStream对象的readObject方法,读取保存对象的文件

​ 3.释放资源。

​ 4.使用读取出来的对象。

​ 反序列化前提:实现Serializable接口和必须存在类对应的class文件。

transient关键字:瞬态关键字。被transient修饰的成员变量不能被序列化。

反射

反射

​ 反射:框架设计的灵魂

​ 框架:半成品软件。可以在框架的基础上进行软件开发。

​ 反射:将类的各个组成部分(成员变量、成员方法、构造方法)封装为其他对象,这就是反射机制。

​ 好处:

​ 1.可以在程序运行过程中,操作这些对象。

​ 2.可以解耦,提高程序扩展性。

​ 获取Class对象的方式:

​ 1.Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象。(多用于配置文件)

​ 2.类名.class:通过类名的属性class获取。(多用于参数传递)

​ 3.对象.getClass()。(多用于对象获取字节码的方式)

​ 结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,无论哪种方式获取的Class对象都是同一个。

​ Class对象功能:

​ 1.获取成员变量们:

​ Field[] getFields():获取所有public修饰的成员变量

​ Field getField(String name):获取指定名称的public修饰的成员变量

​ Field[] getDeclaredFields():获取所有变量,不考虑修饰符

​ Field getDeclaredField(String name):获取指定名称的public修饰的成员变量,不考虑修饰符

​ 2.获取构造方法们

​ Constructor<?>[] getConstructors():

​ Constructor getConstructor(类<?>… parameterTypes):

​ Constructor<?>[] getDeclaredConstructors():

​ Constructor getDeclaredConstructor(类<?>… parameterTypes):

​ 3.获取成员方法们

​ Method[] getMethods()

​ Method getMethod(String name,类<?>… parameterTypes)

​ Method[] getDeclaredMethods()

​ Method getDeclaredMethod(String name,类<?>… parameterTypes)

​ 4.获取类名

​ String getName()

​ Filed:成员变量

​ 1.设置值:void set(Object obj,Object value)

​ 2.获取值:get(Object obj)

​ 3.忽略访问权限修饰符的安全检查:setAccessible(true):暴力反射

​ Constructor:构造方法

​ 创建对象:T newInstance(Object… initargs)

​ 如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法。

​ Method:方法对象

​ 执行方法:Object invoke(Object obj,Object… args)

​ 获取方法名称:String getName:获取方法名

java代码三个阶段

​ java代码在计算机中经历的阶段:三个阶段
在这里插入图片描述

注解

​ 概念:说明程序。给计算机看的。

​ 注释:用文字描叙程序。给程序员看的。

​ 定义:注解(Annotation)也叫元数据。一种代码级别的说明。可以声明在包、类、字段、方法参数等面前,用来对元素说明。

​ 作用分类:

​ 1.编写文档:通过注解生成文档

​ 2.代码分析:通过代码中标识的注解对代码分析(使用反射)

​ 3.编译检查:如(Oveeride)

​ jdk预定义注解:

​ 1.@Oveeride:检测被改注解标注的方法是否来自父类。

​ 2.@Deprecate:该注解标识内容,表示已过时。

​ 3.SuppressWarnings:压制警告。

​ 自定义注解:

​ 1.格式:

​ 元注解

​ public @interface 注解名称{}

​ 2.本质:注解本质是一个接口,该接口默认继承Annotation接口

​ 3.属性:接口中可以定义的成员方法

​ 要求:

​ 属性的返回类型:

​ 基本数据类型

​ String

​ 枚举

​ 注解

​ 以上类型数组

​ 定义了属性,使用时就要赋值

​ 1.如果定义属性使用了default默认赋值,使用注解时就可以不赋值。

​ 2.如果只有一个属性需要赋值,并且属性名称为value,value可以省略

​ 3.数组赋值,值用{}包裹,如果只有一个值,则{}省略

​ 元注解:用于描述注解的注解

​ 1.@Target:描述注解能够作用的位置

​ ElementType取值:

​ TYPE:可以作用于类上

​ METHOD:可以作用于方法上

​ FILED:可以作用于成员变量

​ 2.@Retention:描述注解被保留阶段

​ @Retention(RetentionPolicy.Runtime):当前被描述的注解,会被保留到class字节码文件中,并被jvm读到

​ 3.@Documented:描述注解是否被抽取到api文档中

​ 4.Inherited:描述注解是否被子类继承

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值