Java基础

*** 天下熙熙,皆为利来;天下攘攘,皆为利往;***

String类的常用方法

String当中与获取相关的常用方法

  1. public int length():获取字符串当中含有的字符个数,拿到字符串的长度。
  2. public String concat(String str):将当前字符串和参数字符串拼接成为返回值新的字符串。
  3. public char charAt(int index):获取索引位置的单个字符。(索引从0开始。)
  4. public int indexOf(String str):查找参数字符串在本字符串当中首次出现的索引位置,如果没有返回-1值。

字符串的截取方法

  1. public String substring(int index):截取从参数位置一直到字符串末尾,返回新字符串。
  2. public String substring(int begin, int end): 截取从begin开始,一直到end结束,中间的字符串。
  3. 备注:[begin,end),包含左边,不包含右边。

字符串当中与转换相关的常用方法

  1. public char[] toCharArray():将当前字符串拆分成为字符数组作为返回值。
  2. public byte[] getBytes():获取当前字符串底层的字节数组。
  3. public String replace(CharSequence oldString, CharSequence newString):将所有出现的来字符串替换成为新的字符串,返回替换之后的结果新字符串。
  4. 备注:CharSequence意思就是说可以接受字符串类型。

字符串分割的方法

public String[] split(String regex):按照参数的规则,将字符串切分成为若干部分。
注意事项:split方法的参数其实是一个“正则表达式”。如果按照英文句点“."进行切分,必须写“\.”(两个斜杠)。

静态static关键字

修饰成员变量

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

修饰成员方法

一旦使用static修饰成员方法,那么这就成为了静态方法。静态方法不属于对象,而是属于类的。
如果没有static关键字,那么必须首先创建对象,然后通过对象才能使用成员方法。

静态代码块

静态代码块的格式是:
public class 类名称{
static {
//静态代码块的内容
}
}
特点:当第一次用到本类时,静态代码块执行唯一 一次。

数组工具类Arrays

java.util.Arrays是一个与数组相关的工具类,里面提供了大量静态方法,用来实现数组常见的操作。

常用方法:

  1. public static String toString(数组):将参数数组变成字符串(按照默认格式:[元素1,元素2,元素3…])。
  2. public static void sort(数组):按照默认升序(从小到大)对数组的元素进行排序。
    备注:
    1.如果是数值,sort默认按照升序从小到大。
    2.如果是字符串,sort默认按照字母升序
    3.如果是自定义的类型,那么这个自定义的类需要有Comparable或Comparator接口的支持。
  3. public static void fill(数组,value):向目标数组中填充指定value值。
  4. public static int binarySearch(数组,value):二分法查找法查找指定value在数组中的索引位置。
  5. public static boolean equals(数组1, 数组2):比较俩数组内容是否相同。

数学工具类Math

java.util.Math类是数学相关的工具类,里面提供了大量的静态方法,完成与数学运算相关的操作。

常用方法:

  1. public static double abs(double num):获取绝对值。
  2. public static double ceil(double num):向上取整。
  3. public static double floor(double num):向下取整。
  4. public static long round(double num):四舍五入。
  5. Math.PI代表篇近似的圆周率常量。

继承

继承的格式

在继承的关系中,“子类就是一个父类”。也就是说,子类可以被当作父类看待。
例如父类是员工,子类是讲师,那么“讲师就是一个员工”。关系:is-a。

定义父类的格式:(一个普通类定义)
public class 父类名称{
//…
}
定义子类的格式:
public class 子类名称 extends 父类名称{
//…
}

继承中成员变量的访问特点

再父子类的继承关系中,如果成员变量重名,则创建子类对象时,访问有两种:

  1. 直接通过子类对象访问成员变量: 等号左边是谁,就优先用谁,没有则往上找。
  2. 间接通过成员方法访问成员变量: 方法属于谁就优先用谁,没有则向上找。

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

局部变量:     直接写变量名
本类的成员变量:   this.成员变量名
父类的成员变量:    super.成员变量名

继承中成员方法的访问特点

在父子类的继承关系中,创建子类对象,访问成员方法的规则:
  创建的对象是谁,就优先用谁,如果没有则向上找。
注意事项:无论是成员方法还是成员变量,如果没有都是想上找父类,绝对不会向下找子类的。

继承中方法的覆盖重写

重写(Override)
概念:在继承关系中,方法的名称一样,参数列表也一样。
重写与重载的区别:
重写(Override):方法的名称一样,参数列表【也一样】。
重载(OverLoad):方法的名称一样,参数列表【不一样】。
方法的覆盖重写特点:创建的是子类对象,则优先用子类方法。
方法覆盖重写的注意事项:

  1. 必须保证父子类之间方法的名称相同,参数列表也相同。
  2. @Override:写在方法前面,用来检测是不是有效的正确覆盖重写。这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。
  3. 子类的返回值必须【小于等于】父类方法的返回值范围。
  4. 子类方法的权限必须【大于等于】父类方法的权限修饰符。
  5. 小扩展提示:public > protected > (default) > private 备注:(default)不一定是关键字default,可以是什么都不写,留空。

继承中构造方法的访问特点

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

  1. 子类构造方法当中有一个默认隐含的“super()”调用,所以一定是先调用的父类构造,后执行的子类构造。
  2. 子类构造可以通过super关键字来调用父类重载构造。
  3. super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造。
  4. 总结: 子类必须调用父类构造方法,不写则赠送super():写了则用写的指定的super调用,super只能有一个,还必须是第一个。

super关键字的用法有三种:

  1. 在子类的成员方法中,访问父类的成员变量。
  2. 在子类的成员方法中,访问父类的成员方法。
  3. 在子类的构造方法中,访问父类的构造方法。
    在第三种用法当中要注意:
    A. this(…)调用也必须是构造方法的第一个语句,唯一 一个
    B. super和this两种构造调用,不能同时使用。

抽象

抽象方法和抽象类的格式

  1. 抽象方法:就是加上abstract关键字,然后去掉大括号,直接分号结束。
  2. 抽象类:抽象方法所在的类,必须是抽象类才行。在class之前写上abstract即可。

抽象方法和抽象类的使用

如何使用抽象类和抽象方法:

  1. 不能直接创建new抽象类对象。
  2. 必须用一个子类来继承抽象父类。
  3. 子类必须覆盖重写抽象父类当中所有的抽象方法。 覆盖重写(实现):子类去掉抽象方法的abstract关键字,然后补上方法体大括号。
  4. 创建子类对象进行使用。
  5. 一个抽象类不一定含有抽象方法,只要保证抽象方法所在的类是抽象类,即可。
  6. 抽象类中,可以有构造方法。是供子类创建对象时,初始化父类成员使用的。

接口

接口的定义

接口就是多个类的公共规范。
接口是一种引用数据类型,最重要的内容就是其中的,抽象方法。

如何定义一个接口的格式:
public interface 接口名称{
//接口内容
}
备注:换成了关键字interface之后,编译生成的字节码文件任然是:. Java–>.class。

如果是Java7,那么接口中可以包含的内容有:
1.常量
2.抽象方法

如果是Java8,还可以额外包含有:
3.默认方法
4.静态方法

如果是Java9,还可以额外包含有:
5.私有方法

在任何版本的Java中,接口都能定义抽象方法。
格式:
public abstract 返回值类型 方法名称(参数列表);

注意事项:
1.接口当中的抽象方法,修饰符必须是俩个固定的关键字:public abstract
2.这两个关键字修饰符,可以选择性的省略。

接口的使用

接口的使用步骤:
1.接口不能直接使用,必须有一个“实现类”来“实现”该接口。
格式:
public class 实现类名称 implements 接口名称{
//…
}
2.接口的实现类必须覆盖重写(实现)接口中所有的抽像方法。
实现:去掉abstract关键字,加上方法体大括号。
3.创建实现类的对象,进行使用。
注意事项:
如果实现类并没有覆盖重写接口中所有的抽象方法,那么这个实现类自己就必须是抽象类。
从Java8开始,接口里允许定义默认方法。
格式:
public default 返回值类型 方法名称(参数列表){
方法体
}
备注:接口当中的默认方法,可以解决接口升级的问题。

接口中默认方法的使用:
1.接口的默认方法,可以通过接口实现类对象,直接调用。
2.接口的默认方法,也可以被接口实现类进行覆盖重写。

从Java8开始,接口当中允许定义静态方法。
格式:
public static 返回值类型 方法名称(参数列表){
方法体
}
提示:就是将abstract或者default换成static即可,带上方法体。
注意事项:不能通过接口实现接口实现类的对象来调用接口当中的静态方法。
正确用法:通过接口名称,直接调用其中的静态方法。
格式:
接口名称.静态方法(参数);

问题描述:
我们需要抽取一个共有方法,用来解决两个默认方法之间重复代码的问题。
但是这个共有方法不应该让实现类使用,应该是私有的。
解决方案:
从Java9开始,接口当中允许定义私有方法。
1.普通私有方法,解决多个默认方法之间重复代码的问题。
格式:
private 返回值类型 方法名称(参数列表){
方法体
}
2.静态私有方法,解决多个静态方法之间重复代码问题。
格式:
private static 返回值类型 方法名称(参数列表){
方法体
}

接口中常量的定义和使用

接口当中也可以定义“成员变量”,但是必须使用public static final三个关键字进行修饰。
从效果上看,这其实就是接口的【常量】。
格式:
public static final 数据类型 常量名称 = 数据值;
备注:
一旦使用final关键字进行修饰,说明不可改变。

注意事项:
1.接口当中的常量,可以省略public static final,注意:不写也照样是这样。
2.接口当中的常量,必须进行赋值,不能不赋值。
3.接口中常量的名称,使用完全大写的字母,用下划线进行分隔。

接口的内容小结

在Java9+版本中,接口的内容可以有:
1.成员变量其实就是常量,格式:
[public] [static] [final] 数据类型 常量名称 = 数据值;
注意:
常量必须进行赋值,而且一旦赋值不能改变。
常量名称完全大写,用下划线进行分隔。

2.接口中最重要的就是抽象方法,格式:
[public] [abstract] 返回值类型 方法名称(参数列表);
注意:实现类必须覆盖重写接口所有的抽象方法,除非实现类是抽象类。

3.从Java8开始,接口里允许定义默认方法,格式:
[public] default 返回值类型 方法名称(参数列表){方法体};
注意:默认方法也可以被覆盖重写。

4.从Java8开始,接口里允许定义静态方法,格式:
[public] static 返回值类型 方法名称(参数列表){方法体};
注意:应该通过接口名称进行调用,不能通过实现类对象调用接口静态方法。

5.从Java9开始,接口里允许定义私有方法,格式:
普通私有方法: private 返回值类型 方法名称(参数列表){方法体};
静态私有方法: private static 返回值类型 方法名称(参数列表){方法体};
注意: private的方法只有接口自己才能调用,不能被实现类或别人使用。

使用接口的时候,需要注意:
1.接口是没有静态代码块或者构造方法的。
2.一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。
格式:
public class MyInterfaceImpl implements MyInterfaceA , MyInterfaceB{
//覆盖重写所有抽象方法
}
3.如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。
4.如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类就必须是一个抽象类。
5.如果实现类所实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。
6.一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先使用父类当中的方法。

多态

多态的格式与使用

代码当中体现多态性,其实就是一句话:父类引用指向子类对象。
格式:
父类名称 对象名 = new 子类名称();
或者:
接口名称 对象名 =new 实现类名称();

多态中成员变量的使用特点

访问成员变量的两种方式:
1.直接通过对象名称访问成员变量,看等号左边是谁,优先用谁,没有则向上找。
2.间接通过成员方法访问成员变量,看该方法属于谁,优先用谁,没有则想上找。

多态中成员方法的使用特点

在多态的代码中,成员方法的访问规则是:
看new的是谁。就优先用谁,没有则想上找。
口诀:编译看左边,运行看右边。
对比一下:
成员变量:编译看左边,运行还看左边。
成员方法:编译看左边,运行看右边。

对象的转型

1.对象的向上转型,其实就是多态的写法:
格式:父类名称 对象名 = new 子类名称();
含义:右侧创建一个子类对象看,把它当作父类来看待使用。
注意事项:向上转型一定是安全的。从小范围转向了大范围。
2.对象的向下转型,其实是一个【还原】的动作。
格式:子类名称 对象名 = (子类名称)父类对象;
含义:将父类对象,【还原】成为本来的子类对象。

用instanceof关键字进行类型判断

如何才能知道一个父类引用的对象本来是什么子类?
格式:
对象 instanceof 类名称
这将会得到一个Boolean值结果,也就是判断前面的对象能不能当作后面类型的实例。

final关键字

final关键字代表最终、不可改变的。

常见四种用法:
1.可以用来修饰一个类
2.可以用来修饰一个方法
3.还可以用来修饰一个局部变量
4.还可以用来修饰一个成员变量

当final关键字用来修饰一个类的时候,格式:
public final class 类名称{
//…
}
含义:当前类不能有任何子类(太监类)
注意:一个类如果是final的,那么其中所有的成员方法都无法进行覆盖重写(因为没有子类能继承)

当final关键字用来修饰一个方法的时候,这个方法就是最终方法,也就是不能被覆盖重写的。
格式:
修饰符 final 返回值类型 方法名称(参数列表)(
//方法体

注意事项:
对于类、方法来说,abstract关键字和final关键字不能同时使用,因为矛盾。

对于局部变量来说,如果使用final关键字修饰,那么这个变量是不可变的。

对于成员变量来说,如果使用final关键字修饰,那么这个变量也照样是不可变的。

1.由于成员变量具有默认值,所以用了final之后必须手动赋值,不会再给默认值了。
2.对于final的成员变量,要么使用直接赋值,要么通过构造方法赋值。

四种权限修饰符

Java中有四种权限修饰符:
作用范围publicprotected(default)private
同一个类yesyesyesyes
同一个包yesyesyesno
不同包子类yesyesnono
不同包非子类yesnonono

内部类

如果一个事物的内部包含另一个事物,那么这就是一个类内部包含另一个类。
分类:
1.成员内部类
2.局部内部类(包含匿名内部类)
成员内部类的定义格式:
修饰符 class 外部类名称{
修饰符 class 内部类名称{
//…
}
//…
}
注意:内用外,随意访问;外用内,需要使用内部类对象;

如何使用成员内部类?有两种方式:
1.间接方式:在外部类的方法当中,使用内部类,然后main只是调用外部类的方法。
2.直接方式:
创建内部类对象,公式:外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();

内部类的同名变量访问时,如果出现重名现象,那么格式是:
外部类名称.this.外部类成员变量名

如果一个类是定义在一个方法内部的,那么这就是一个局部内部类。
“局部”,只有当前所属的方法才能使用它,出了这个方法外面就不能用了。

定义格式:
修饰符 class 外部类名称{
修饰符 返回值类型 外部类方法名称(参数列表){
class 局部内部类名称{
//…
}
}
}
类的权限修饰符小结:
public > protected > (default) > private
定义一个类的时候,权限修饰符规则:
1.外部类:public / (default)
2.成员内部类: public / protected / (default) / private
3.局部内部类: 什么都不能写

局部内部类,如果希望访问所在方法的局部变量,那么这个局部变量必须是【有效final的】。

备注:从Java8+开始,只要局部变量事实不变,那么final关键字可以省略。
原因:

  1. new 出来的对象在堆内存当中。
  2. 局部变量是跟着方法走的,在栈内存当中。
  3. 方法运行结束之后,立刻出栈,局部变量就会立刻消失。
  4. 但是new出来的对象会在堆当中持续存在,直到垃圾回收消失。

如果接口的实现类(或者父类的子类)只需要使用唯一的一次,那么这种情况下就可以省略掉该类的定义,而改为使用【匿名内部类】。
匿名内部类的定义格式:
接口名称 对象名 = new 接口名称(){
//覆盖重写所有的抽象方法
};

Object类

1.Object类介绍
Object类是所有类的父类,每一个类都会直接或者间接的继承自该类
该类中提供了一些非常常见的方法!
2.toString()方法
A:作用:打印对象的信息
B:重写前:打印的是包名类名@地址值
C:重写后:打印的是对象中的属性值
3.equals()方法
A:作用:比较两个对象
B:重写前:比较的是对象的地址值
C:重写后:比较的是对象中的属性值

Objects类的equals方法:对两个对象进行比较,防止空指针异常

时间日期相关类

java.util.Date:表示日期和时间的类
类Date表示特定的瞬间,精确到毫秒。
毫秒:千分之一秒 1000毫秒 = 1秒
把日期转换为毫秒:
时间原点(0毫秒):1970年1月1日00:00:00(英国格林威治)
注意:
中国属于东八区,会把时间增加8小时
1970年1月1日00:80:00

Date类的空参数构造方法:
Date()获取的就是当前系统的日期和时间
Date类的带参数构造方法:
Date(Long date):传递毫秒值,把毫秒值转换为Date日期
Date类的成员方法:
long getTime():把日期转换为毫秒(相当于System.currentTimeMillis())
反悔自时间原点以来此Date对象表示的毫秒数。

java.text.DateFormat:是日期/时间格式化子类的抽象类
作用:
格式化(也就是日期 ----> 文本)、解析(文本 ----> 日期)
成员方法:
Sting format(Date date) 按照指定的模式,把Date日期格式化为符合模式的字符串
Date parse(String sourse) 把符合模式的字符串解析为Date日期
DateFormat类是一个抽象类,无法直接创建对象使用,可以使用DateFormat的子类
java.text.SimpleDateFormat extends DateFormat
构造方法:
SimpleDateFormat(String pattern) 用指定的模式和默认语言环境的日期格式符号构造 SimpleDateFormat.
参数:
String pattern: 传递指定的模式
模式:区分大小写的

模式含义
y
M
d
H
m
s
S毫秒

java.util.Calendar:表示日历的类
Calendar类是一个抽象类,里面提供了很多操作日历字段的方法(YEAR、MONTH、DAY_OF_MONTH、HOUR)
Calendar类无法直接创建对象使用,里边有一个静态方法叫getInstance(),该方法返回了Calendar类的子类对象
static Calendar getInstance() 使用默认时区和语言环境获取一个日历。
Calendar类的成员方法:
1.public int get(int field):返回给定日历字段的值。
参数:int field:传递指定的日历字段(YEAR、MONTH、DAY_OF_MONTH、HOUR…)
返回值:日历字段代表的具体值
2.public int set(int field,int value):将给定的日历字段设置为给定值。
参数:int field:传递指定的日历字段(YEAR、MONTH、DAY_OF_MONTH、HOUR…)
int value:传递的字段设置的具体的值
3.public int add(int field,int amount):根据日立的规则,为指定的日历字段添加或减去指定的时间量。
把指定的字段增加/减少指定的值
参数:int field:传递指定的日历字段(YEAR、MONTH、DAY_OF_MONTH、HOUR…)
int amount:增加/减少的值
正数:增加
负数:减少
4.public Date getTime():返回一个表示此Calendar时间值(从历元到现在的毫秒偏移量)的Date对象。
int field:日历类的字段,可以使用Calendar类的静态成员变量获取

System类

java.lang.System类中提供了大量的静态方法,可以获取与系统相关的信息或系统级操作,在System类的API文档中,常用的方法有:

  • public static Long currentTimeMillis():返回以毫秒为单位的当前时间。
  • public static void arraycopy(Object src , int srcPos, Object dest , int destPos, int length):将数组中指定的数据拷贝到另一个数组中。
    参数:
    src:原数组
    srcPos:原数组中的起始位置
    dest:目标数组
    destPos:目标数组中的起始位置
    length:要复制的数组元素的数量

StringBuilder类

StringBuilder类的构造方法:

  1. StringBuilder(); 创建一个空的字符串缓冲区对象
  2. StringBuilder(String s); 根据传入的内容创建一个字符串缓冲区对象

StringBuilder类的成员方法:
public StringBujlder append(…):添加任意类型数据的字符串形式,并返回当前对象本身。
参数:可以是任何的数据类型
public void reverse(); 反转当前字符串缓冲区对象中的内容
public String toString(); 将当前字符串缓冲区对象转为字符串对象

装箱与拆箱

装箱:把基本类型的数据,包装到包装类中(基本类型的数据–>包装类)
构造方法:
Integer(int value):构造一个新分配的Integer对象,它表示指定的int值。
Integer(String s):构造一个新分配的Integer对象,它表示String参数所指示int值。(传递的字符串,必须是相应基本类型的字符串,否则会抛出异常)
静态方法:
static Integer valueOf(int i ):返回一个表示指定的int值的Integer实例。
static Integer valueOf(String s ):返回一个表示指定的String值的Integer实例。
拆箱:在包装类中取出基本类型的数据(包装类–>基本类型的数据)
成员方法:
int intValue():以int类型返回该Integer的值。

*基本类型与字符串之间的转换

基本类型-->字符串
1.基本类型数据的值+""最简单的方式(工作中常用)
2.使用包装类中的静态方法
static  String  toString(int  i) : 返回一个表示指定整数的String对象。
3.使用String类中的静态方法
static  String  valueOf(int i):返回int参数的字符串表示形式。
字符串-->基本类型
使用包装类的静态方法parseXXX("字符串"),如:
Integer类: static  int  parseInt(String s )
Double类: static  double  parseDouble(String s )
...

集合-Collection

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

迭代器

java.util.Iterator接口:迭代器(对集合进行遍历)
有两个常用的方法:

  1. boolean hasNext(): 如果仍有元素可以迭代,则返回true。判断集合中还有没有下一个元素,有就返回true,没有就返回false
  2. E next(): 返回迭代的下一个元素。取出集合中的下一个元素
    Iterator迭代器,是一个接口,我们无法直接使用,需要使用Iterator接口的实现类对象,获取实现类的方式比较特殊
    Collection接口中有一个方法,叫iterator() ,这个方法返回的就是迭代器的实现类对象
    Iterator iterator() 返回在此 collection 的元素上进行迭代的迭代器。

迭代器的使用步骤(重点):

  1. 使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态)
  2. 使用Iterator接口中的方法hasNext()判断还有没有下一个元素
  3. 使用Iterator接口中的方法next()取出集合中的下一个元素

泛型的使用

  1. 泛型类和泛型方法
    类名<泛型>
    方法名<泛型>
  2. 泛型接口和泛型方法
    接口名<泛型>
    方法名<泛型>
  3. 泛型通配符
<?>:?可接收任何类型

< ? extends 类名>:上限(?须为后类的子类或本身)
< ? super 类名>:下限(?须为后类的父类或本身)

可变参数

可变参数:是JDK1.5之后出现的新特性
使用前提:
当方法的参数列表数据类型已经确定,但是参数的个数 不确定,就可以使用可变参数。
使用格式:
修饰符 返回值类型 方法名(数据类型… 变量名){}
可变参数的原理:
可变参数底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数
可变参数的注意事项:
1.一个方法的参数列表,只能有一个可变参数
2.如果方法的参数有多个,那么可变参数必须写在参数列表的末尾

数据结构

特点: 先进后出

队列

特点: 先进先出

数组

特点:
查询快: 数组的地址是连续的,我们通过数组的首地址可以找到数组,通过数组的索引可以快速查找某一元素
增删慢: 数组的长度是固定的,我们想要增加/删除一个元素,必须创建一个新数组,把原数组的数据复制过来

链表

特点:
查询慢: 链表中的地址不是连续的,每次查询元素,都必须从头开始查询
增删快: 链表结构,增加/删除一个元素,对链表的整体结构没有影响,所以增删快
单向链表: 链表中只有一条链子,不能保证元素的顺序(存储元素和取出元素有可能不一致)
双向链表: 链表中有两条链子,有一条链子是专门记录元素的顺序,是一个有序的集合

二叉树

二叉树: 分支不能超过两个
排序树/查找树: 在二叉树的基础上,元素是有大小顺序的(左子树小,右子树大)
平衡树: 左子树与右子树相等
红黑树:
特点 : 趋近于平衡树,查询的速度非常的快,查询叶子节点最大次数和最小次数不能超过2倍
约束:
1.节点可以是红色的或者黑色的
2.根节点是黑色的
3.叶子节点(空节点)是黑色的
4.每个红色的节点的子节点都是黑色的
5.任何一个节点到其每一个叶子节点的所有路径上黑色节点数相同

集合

List集合

java.util.List接口 extends Collection接口
List接口的特点:

  1. 有序的集合,存储元素和取出元素的顺序是一致的
  2. 有索引,包含了一些带索引的方法
  3. 允许存储重复的元素
    List接口中带索引的方法(特有)
    public void add(int index, E element):将指定的元素,添加到该集合中的指定位置上。
    public E get(int index):返回集合中指定位置的元素。
    public E remove(int index): 移除列表中指定位置的元素,返回的是被移除的元素。
    public E set(int index, E element):用指定元素替代集合中指定位置的元素,返回更新前的元素。
    注意:
    操作索引的时候,一定要防止索引越界异常

Set集合

java.util.Set接口 extends Collection接口
Set接口的特点:

  1. 没有索引,没有带索引的方法,也不能使用普通的for循环遍历
  2. 不允许存储重复的元素

HashSet

java.util.HashSet集合 implements Set接口
HashSet集合的特点:
3. 没有索引,没有带索引的方法,也不能使用普通的for循环遍历
4. 不允许存储重复的元素
5. 是一个无序的集合,存储元素和取出元素的顺序有可能不一致
6. 底层是一个哈希表结构(查询速度非常的快)

LinkedHashSet

java.util.LinkedHashSet集合 extends HashSet集合
LinkedHashSet集合的特点:
底层是一个哈希表(数组+链表/红黑树)+链表:多了一条链表(记录元素的存储顺序),保证元素有序

哈希值

哈希值:是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出来得到的地址 )
在Object类中有一个方法,可以获取对象的哈希值
int hashCode(): 返回该对象的哈希值

Collections工具类

java.utils.Collections是集合工具类,用来对集合进行操作。部分方法如下:
public static boolean addAll(Collection c , T… elements): 往集合中添加一些元素。
public static void shuffle(List<?> list): 打乱集合中元素顺序。
public static void sort(List list): 将集合中的元素按照默认规则排序(默认是升序)。
注意:
sort(List list)使用前提
被排序的集合里存储的元素,必须实现Comparable,重写接口中的方法compareTo定义排序的规则
Comparable接口的排序规则:
自己(this)-参数:升序
反之为降序

Map集合

java.util.Map<k,v>集合
Map集合的特点:

  1. Map集合是一个双列集合,一个元素包含两个值(一个key,一个value)
  2. Map集合中的元素,key和value的数据类型可以相同,也可以不同
  3. Map集合中的元素,key是不允许重复的,value实可以重复的
  4. Map集合中的元素,key和value是一一对应的

HashMap

java.util.HashMap<k,v>集合 implements Map<k,v>接口
HashMap<k,v>集合的特点:

  1. 是一个无序的集合,存储元素和取出元素的顺序有可能不一致
  2. 底层是一个哈希表结构(查询速度非常的快)

LinkedHashMap

java.util.LinkedHashMap<k,v>集合 extends HashMap<k,v>集合
LinkedHashMap集合的特点:
底层是一个哈希表(数组+链表/红黑树)+链表:多了一条链表(记录元素的存储顺序),保证元素有序

Map集合中常用方法

public V put(K key, V value): 把指定的键与指定的值添加到Map集合中。
返回值:V
存储键值对的时候,key不重复,返回值V是null
存储键值对的时候,key重复,会使用新的value替换map中重复的value,返回被替代的value值
public V remove(Object key): 把指定的键所对应的键值对元素在Map集合中删除,反会被删除元素的值。
返回值:V
key不存在,返回值V是null
key存在,返回被删除的value值

Map集合的第一种遍历方式:通过键找值的方式
Map集合中的方法
Set keySet(): 返回此映射中包含的键的Set视图。
实现步骤:
1.使用Map集合中的方法keySet(),把Map集合所有的Key取出来,存储到一个Set集合中
2.遍历Set集合,获取Map集合中的每一个Key
3.通过Map集合中的方法get(key),通过key找到value

Map集合的第二种遍历方式:使用Entry对象遍历】
Map集合中的方法:
Set<Map.Entry<k,v>> entrySet(): 返回此映射中包含的键的Set视图。
实现步骤:
1.使用Map集合中的方法entrySet(),把Map集合所有的Entry对象取出来,存储到一个Set集合中
2.遍历Set集合,获取每一个Entry对象
3.通过Entry对象中的方法getKey()和getValue()获取键与值

Hashtable

java.util.Hashtable<k,v>集合 implements Map<k,v>接口
Hashtable: 底层也是一个哈希表,是一个线程安全的集合,是单线程集合,速度慢
HashMap:底层是一个哈希表,是一个线程不安全的集合,是多线程的集合,速度快

HashMap集合:可以存储null值,null键
Hashtable集合:不可以存储null值,null键

Hashtable和Vector集合一样,在JDK1.2版本之后被更先进的集合(HashMap,ArrayList)取代了
Hashtable的子类Properties依然活跃在历史舞台
Properties集合是一个唯一和IO流相结合的集合

JDK9对集合添加的优化——of方法

JDK9的新特性:
list接口,set接口,Map接口:里边增加了一个静态的方法of,可以给集合一次性添加多个元素
static List of (E… elements)
使用前提:
当集合中存储的元素的个数已经确定了,不再改变时使用
注意:
1.of方法只适用于List接口,Set接口,Map接口,不适用于接口的实现类
2.of方法的返回值是一个不能改变的集合,集合不能再使用add,put方法添加元素,会抛出异常
3.Set接口和Map接口在调用of方法的时候,不能有重复的元素,否则会抛出异常

Debug调试

Debug调试程序:
可以让代码逐行执行,查看代码执行的过程,调试程序中出现的Bug.
使用方式:
在行好的右边,鼠标左键单击,添加断点(每个方法的第一行,哪里有Bug添加到哪里)
右键,选择Debug执行程序
程序就会停留在添加的第一个断点处
执行程序:
F8:逐行执行程序
F7:进入到方法中
Shift+F8:跳出方法
F9:跳到下一个断点,如果没有下一个断点,那么就结束程序
Ctrl+F2:退出debug模式,停止程序
Console:切换到控制台

异常

java.lang.Throwable类: 是java语言中所有错误或异常的超类。
Exception: 编译期异常,进行编译(写代码)Java程序出现的问题
RuntimeException: 运行期异常,Java程序运行过程中出现的问题
一场就相当于程序得了一个小毛病,把异常处理掉,程序可以继续执行
Error: 错误
错误就相当于程序得了一个无法治愈的毛病,必须修改源代码,程序才能继续执行

thows

throws关键字: 异常处理的第一种方式,交给别人处理
作用:
当方法内部抛出异常对象的时候,那么我们就必须处理这个异常对象
可以 使用throws关键字处理异常对象,会把异常对象声明抛给方法的调用者处理(自己不处理,给别人处理),最终交给JVM处理---->中断处理
使用格式:在方法声明时使用
修饰符 返回值类型 方法名(参数列表) throws AAAException, BBBException{
throw new AAAException(“产生原因”);
throw new BBBException(“产生原因”);
}
注意:
1.throws关键字必须写在方法声名处
2.throws关键字后边声明的异常必须是Exception或者其子类
3.方法内部如果抛出多个异常对象,那么throws后边必须也声明多个异常
如果抛出的多个异常对象有子父类关系,那么直接声明父类异常即可
4.调用了一个声明抛出异常的方法,我们就必须处理声明的异常
要么继续使用throws声明抛出,交给方法的调用者处理,最终交给JVM
要么try…catch自己处理异常

try…catch

try…catch: 异常处理的第一种方式,自己处理异常
格式:
try{
可能产生异常的代码
}catch(定义一个异常的变量,用来接收try中抛出的异常对象){
异常的处理逻辑,接收异常对象之后,怎么处理异常对象
一般在工作中,会把异常的信息记录到一个日志中
}

catch(异常类名 变量名){
}
注意:
1.try中可能会抛出多个异常对象,那么就可以使用多个catch来处理这些异常对象
2.如果try中产生了异常,那么就会执行catch中的异常处理逻辑,执行完毕catch中的处理逻辑,继续执行try…catch之后的代码
如果try中没有产生异常,那么就不会执行catch中异常的处理逻辑,执行完try中的代码,继续执行try…catch之后的代码

Throwable类中定义了3个异常处理的方法
String getMessage(): 返回此throwable的简短描述。
String toString(): 返回此throwable的详细描述。
String printStackTrace(): JVM打印异常对象,默认此方法,打印的异常信息是最全面的。

finally

finally代码块
格式:
try{
可能产生异常的代码
}catch(定义一个异常的变量,用来接收try中抛出的异常对象){
异常的处理逻辑,接收异常对象之后,怎么处理异常对象
一般在工作中,会把异常的信息记录到一个日志中
}

catch(异常类名 变量名){
}finally{
无论是否出现异常都会执行
}
注意:
1.finally不能单独使用,必须和try一起使用
2.finally一般用于资源释放(资源回收),无论程序是否出现异常,最后都要资源释放(IO)
3.如果finally中有return语句,永远返回finally中的结果,避免该情况。

子父类的异常: —— 如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。
——父类方法没有抛出异常,子类重写父类该方法时也不能抛出异常,此时子类产生该异常,只能捕获处理,不能声明抛出
注意:
父类抛异常时什么样,子类异常就什么样

自定义异常

自定义异常类:
java提供的异常类,不够我们使用,需要自己定义一些异常类
格式:
public class XXXException extends Exception/RuntimeException{
添加一个空参数的构造方法
添加一个带异常信息的构造方法
}
注意:
1.自定义异常类一般都是以Exception结尾,说明该类是一个异常类
2.自定义异常类,必须得继承 Exception或者RuntimeException
继承 Exception:那么自定义的异常类就是一个编译期异常,如果方法内部抛出了编译期异常,就必须处理这个异常,要么throws,要么try…catch
继承 RuntimeException :那么自定义的异常类就是一个运行期异常,交给虚拟机处理(中断处理)

多线程

创建多线程程序的第一种方式:创建Thread类的子类
java.lang.Thread类:是描述现成的类,我们想要实现多线程程序,就必须继承Thread类

实现步骤:
1.创建一个Thread类的子类
2.在Thread类的子类中重写Thread类中的run方法,设置线程任务(开启线程要做什么)
3.创建Thread类的子类对象
4.调用Thread类中start方法,开启新的线程,执行run方法
void start() 使线程开始执行; java 虚拟机调用该线程的run方法。
结果是两个线程并发的运行;当前线程(main线程)和另一个线程。
多次启动一个线程是非法的,特别是当线程已经结束执行后,不能再重新启动。
Java程序属于抢占式调度,哪个线程的优先级高,那个线程优先执行 ;同一个优先级,随机选择一个执行

获取线程的名称:
1.使用Thread类中的方法getName()
String getName() 返回该线程的名称
2.可以先获取到当前正在执行的线程,使用线程中的方法getName()获取线程的名称
static Thread currentThread() 返回对当前正在执行的线程对象的引用。

设置线程的名称:
1.使用Thread类中成员方法setName(名字)
void setName(String name) 改变线程名称 ,使之与参数name相同。
2.创建一个带参数的构造方法,参数传递现成的名称;调用父类的带参构造方法,把线程名称传递给父类,让父类(Thread)给子线程起一个名字
Thread(String name) 分配新的 Thread对象

public   static   void  sleep(long  millis):  是当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
毫秒数结束之后,线程继续执行 

创建多线程程序的第二种方式:实现Runnable接口
Java.lang.Runnable
Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为run的无参数方法。
java.lang.Thread类的构造方法
Thread(Runnable target) 分配新的Thread对象
Thread(Runnable target , String name) 分配新的Thread对象

实现步骤:
1.创建一个Runnable接口的实现类
2.在实现类中重写Runnable接口的run方法,设置线程任务
3.创建一个Runnable接口的实现类对象
4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象
5.调用Thread类中的start方法,开启新的线程执行run方法

实现Runnable接口创建多线程程序的好处:
1.避免了单继承的局限性
一个类只能继承一个类,类继承了Thread类就不能继承其他类
实现了Runnable接口,还可以继承其他的类,实现其他的接口
2.增强了程序的扩展性,降低了程序的耦合性(解耦)
实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离(解耦)
实现类中,重写了run方法:用来设置线程任务
创建Thread类对象,调用start方法:用来开启新线程

线程安全

解决线程安全问题的第一种方案:使用同步代码块
格式:
synchronized(锁对象){
可能会出现线程安全的代码(共享数据的代码)
}
注意:
1.通过代码块中的锁对象,可以使用任意地对象
2.但是必须保证多个线程使用的锁对象是同一个
3.锁对象作用:
把同步代码块锁住,只让一个线程在同步代码块中执行

解决线程安全问题的第二种方案:使用同步方法
使用步骤:
1.把访问了共享数据的代码抽取出来,放到一个方法中
2.在方法上添加synchronized修饰符
格式:定义方法的格式
修饰符 synchronized 返回值类型 方法名(参数列表){
可能会出现线程安全的代码(共享数据的代码)
}

解决线程安全问题的第三种方案:使用lock锁
java.util.concurrent.locks.Lock接口
Lock接口实现提供了比使用synchronized方法和语句可获得的更广泛的锁定操作。
Lock接口中的方法:
void lock():获取锁
void unlock(): 释放锁
java.util.concurrent.locks.ReentrantLock implements Lock接口

使用步骤:
1.在成员位置创建一个ReentrantLock对象
2.在可能会出现安全问题的代码前调用Lock接口中的方法lock获取锁
3.在可能会出现安全问题的代码后调用Lock接口中的方法unlock释放锁

线程之间的通信

等待唤醒机制
Object类中的方法
void wait()
在其他线程调用此对象的notify()方法或notifyAll()方法前,导致当前线程等待。
void notify()
唤醒此对象监视器上等待的单个线程。
会继续执行wait方法之后的代码

进入到TimeWaiting(计时等待)有两种方式:
1.使用sleep(long m)方法,在毫秒值结束之后,线程睡醒进入到Runnable/Blocked状态
2.使用wait(long m)方法,wait方法如果在毫秒值结束之后,还没有被notify唤醒,就会自动醒来,线程进入到Runnable/Blocked状态

线程池

线程池:JDK1.5之后提供的
java.util.concurrent.Executors:线程池的工厂类,用来生成线程池
Executors类中的静态方法:
static ExecutorService newFixedThreadPool(int nThreads): 创建一个可重用固定线程数的线程池
参数:
int nThreads: 创建线程池中包含的线程数量
返回值:
ExecutorService接口,返回的是ExecutorService接口的实现类对象,我们可以使用ExecutorService接口接收(面向接口编程)
java.util.concurrent.ExecutorService:线程池接口
用来从线程池中获取线程,调用start方法,执行线程任务
submit(Runnable task) 提交一个Runnable 任务用于执行
关闭/销毁线程池的方法
void shutdown()
线程池的使用步骤:
1.使用线程池的工厂类Executors里面提供的静态方法newFixedThreadPool生产一个指定线程数量的线程池
2.创建一个类,实现Runnable接口,重写run方法,设置线程任务
3.调用ExecutorService中的方法submit,传递线程任务(实现类),开启线程,执行run方法
4.调用ExecutorService中的方法shutdown销毁线程池(不建议执行)

Lambda表达式

Lambda表达式:是可推导,可以省略
凡是根据上下文推导出来的内容,都可以省略不写
可以省略的内容:
1.(参数列表):括号中参数列表的数据类型,可以省略不写
2.(参数列表):括号中的参数如果只有一个,括号中参数列表的数据类型和()都可以省略不写
3.{一些代码}: 如果{}中的代码只有一行,无论是否有返回值,都可以省略({},return,分号)
注意:;要省略{},return,分号)必须一起省略

File

java.io.File类
文件和目录路径名的抽象表示形式。
java把电脑中的文件和文件夹(目录)封装为了一个File类,我们可以使用File类对文件和文件夹进行操作

File类的静态成员变量

static String pathSeparator 与系统有关的路径分隔符,为了方便,它被表示为一个字符串。
static Char pathSeparatorChar 与系统有关的路径分隔符.

static String Separator 与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串。
static Char SeparatorChar 与系统有关的默认名称分隔符.

File类的构造方法

File(String pathname): 通过将给定路径名字符串转换为抽象路径名来创建一个新File实例。
参数:
String pathname:字符串的路径名称
路径可以是以文件结尾,也可以是以文件夹结尾
路径可以是相对路径,也可以是绝对路径
路径可以存在,也可以不存在
创建File对象,只是把字符串路径封装为File对象,不考虑路径的真假情况

File(String parent, String child): 根据parent路径名字符串和child路径名字符串创建一个新File实例。
参数:把路径分成了两部分
String parent :父路径
String child :子路径
好处:
父路径和子路径,可以单独书写,使用起来非常灵活;父路径和子路径都可以变化

File(File parent, String child): 根据parent抽象路径名和child路径名字符串创建一个新File实例。
参数:把路径分成了两部分
String parent :父路径
String child :子路径
好处:
父路径和子路径,可以单独书写,使用起来非常灵活;父路径和子路径都可以变化
父路径是File类型,可以使用File的方法对路径进行一些操作,再使用路径创建对象

File类获取功能的方法

public String getAbsolutePath(): 返回此File的绝对路径名称字符串。
获取的构造方法中传递的路径
无论路径是绝对的还是相对的,getAbsolutePath方法返回的都是绝对路径

public String getPath(): 将此File转换为路径名字符串。
获取构造方法中传递的路径
toString方法调用的就是getPath方法

public String getName(): 返回此File表示的文件或目录的名称。
获取的就是构造方法传递路径的结尾部分(文件/文件夹)

public long length() : 返回由此File表示的文件的长度。
获取的是构造方法指定的文件的大小,以字节为单位
注意:
文件夹是没有大小概念的,不能获取文件夹的大小
如果构造方法中给出的路径不存在,那么Length方法返回0

File类判断功能的方法

public boolean exists() : 此File表示的文件或目录是否实际存在。
用于判断构造方法中的路径是否存在
存在:true
不存在:false

public boolean isDirectory(): 此File表示的是否为目录。
用于判断构造方法中给定的路径是否以文件夹结尾
是:true
否:false
public boolean isFile(): 此File表示的是否为文件。
用于判断构造方法中给定的路径是否以文件结尾
是:true
否:false
注意:
电脑的硬盘中只有文件/文件夹,两个方法是互斥的
这两个方法使用前提,路径必须是存在的,否则都返回false

File类创建删除功能的方法

public boolean createNewFile(): 当且仅当具有该名称的文件尚不存在时,创建一个新的空文件
创建文件的路径和名称在构造方法中给出(构造方法的参数)
返回值:布尔值
true: 文件不存在,创建文件,返回true
false: 文件存在,不会创建,返回false
注意:
1.此方法只能创建文件,不能创建文件夹
2.创建文件的路径必须存在,否则会抛出异常

public boolean mkdir(): 创建单级空文件夹
public boolean mkdirs(): 既可以创建单级空文件夹,也可以创建多级文件夹
创建文件的路径和名称在构造方法中给出(构造方法的参数)
返回值:布尔值
true: 文件夹不存在,创建文件,返回true
false: 文件夹存在,不会创建,返回false;构造方法中给出的路径不存在返回false
注意:
此方法只能创建文件夹,不能创建文件

public boolean delete(): 删除由此File表示的文件或目录。
此方法,可以删除构造方法路径中给出的文件/文件夹
返回值:布尔值
true:文件/文件夹删除成功,返回true
false:文件夹中有内容,不会删除返回false;构造方法中路径不存在返回false

File类遍历目录功能

public File[] listFiles(): 返回一个File数组,表示该File目录中的所有的文件或目录。
遍历构造方法中给出的目录,会获取目录中所有的文件/文件夹,把文件/文件夹封装为File对象,多个File对象存储到File数组中

public String[] list(): 返回一个String数组,表示该File目录中的所有的文件或目录。
遍历构造方法中给出的目录,会获取目录中所有的文件/文件夹的名称,把获取到的多个名称存储到String类型的数组中

注意:
list方法和listFiles方法遍历的是构造方法中给出的目录
如果构造方法中给出的目录的路径不存在,会抛出空指针异常
如果构造方法中给出的路径不是一个目录,也会抛出空指针异常

文件过滤器

在File类中有两个和ListFiles重载的方法,方法的参数传递的就是过滤器
File[] listFiles(FileFilter filter)
java.io.FileFilter接口:用于抽象路径名(File对象)的过滤器。
作用:用来过滤文件(File对象)
抽象方法:用来过滤文件的方法
boolean accept(File pathname) 测试指定抽象路径名是否应该包含在某个路径名列表中。
参数:
File pathname: 使用listFiles方法遍历目录,得到每一个文件对象

File[] listFiles(FilenameFilter filter)
java.io.FilenameFilter接口:实现此接口的类实例可用于过滤文件名。
作用:用于过滤文件名称
抽象方法:用来过滤文件的方法
boolean accept(File dir, String name ) 测试指定抽象路径名是否应该包含在某一文件列表中。
参数:
File dir: 构造方法中传递的被遍历目录
String name: 使用listFiles方法遍历目录,获取的每一个文件/文件夹的名称

		注意:两个过滤器接口是没有实现类的,需要我们自己写实现类,重写过滤方法accept,在方法中自己定义过滤的规则。

文件IO流

字节输出流

java.io.OutputStream: 字节输出流
此对象类是表示输出字节流的所有类的超类
定义了一些子类共性的成员方法:
public void close(): 关闭此输出流并释放与此流相关的任何系统资源。
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) : 将指定的字节写入此输出流。

文件字节输出流

java.io.FileOutputStream extends OutputStream
FileOutputStream: 文件字节输出流
作用:把内存中的数据写入到硬盘的文件中

构造方法:
FileOutputStream(String name) 创建一个向具有指定名称的文件中写入数据的输出文件流。
FileOutputStream(File file) 创建一个向指定File对象表示的文件中写入数据的输出文件输出流。
写入数据的目的地:
String name : 目的地是一个文件的路径
File file : 目的地是一个文件
构造方法的作用:
1.创建一个FileOutputStream对象
2.会根据构造方法中传递的文件/文件路径,创建一个空的文件
3.会把FileOutputStream对象指向创建好的文件

追加写/续写:使用两个参数的构造方法:
FileOutputStream(String name , boolean append) 创建一个向具有指定名称的文件中写入数据的输出文件流。
FileOutputStream(File file, boolean append) 创建一个向指定File对象表示的文件中写入数据的输出文件输出流。
参数:
String name ,File file :写入数据的目的地
boolean append: 追加写开关
true:创建对象不会覆盖原文件,继续在文件的末尾追加写数据
false:创建一个新文件,覆盖原文件

写入数据的原理(内存–>硬盘):
java程序 --> JVM(java虚拟机) --> OS(操作系统) --> OS调用写数据的方法 --> 把数据写到文件中

字节输出流的使用步骤(重点):
1.创建FileOutputStream对象,构造方法中绑定要写入数据的目的地
2.使用FileOutputStream对象中的方法write,写入数据
3.释放资源

字节输入流

java.io.InputStream: 字节输入流
此对象类是表示字节输入流的所有类的超类。

定义了所有子类共性的方法:
int read(): 从输入流中读取数据的下一个字节。
int read(byte[] b) : 从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中。
void close() : 关闭此输入流并释放与该流关联的所有系统资源。

文件字节输入流

java.io.FileInputStream extends InputStream
FileInputStream: 文件字节输入流
作用:把硬盘文件中的数据,读取到内存中使用
构造方法;
FileInputStream(String name)
FileInputStream(File file)
参数: 读取文件的数据源
String name : 文件的路径
File file : 文件
构造方法的作用:
1.创建一个FileInputStream对象
2.会把FileInputStream对象指定的构造方法中要读取的文件

读取数据的原理(硬盘 --> 内存):
java程序 --> JVM(java虚拟机) --> OS(操作系统) --> OS调用读取数据的方法 --> 读取文件

字节输入流的使用步骤(重点):
1.创建FileInputStream对象,构造方法中绑定要读取的数据源
2.使用FileInputStream对象中的方法read,读取文件
3.释放资源

字符输入流

java.io.Reader: 字符输入流
此对象类是表示输入字符流的所有类的超类
定义了一些子类共性的成员方法:
int read(): 读取单个字符并返回。
int read(char[] cbuf) : 一次读取多个字符,将字符读入数组。
void close() : 关闭此输入流并释放与该流关联的所有系统资源。

文件字符输入流

java.io.FileRreader extends InputStreamReader extends Reader
FileReader: 文件字符输入流
作用:把硬盘文件中的数据,以字符的方式读取到内存中使用
构造方法;
FileReader(String fileName)
FileReader(File file)
参数: 读取文件的数据源
String fileName : 文件的路径
File file : 文件
构造方法的作用:
1.创建一个FileReader对象
2.会把FileReader对象指定的构造方法中要读取的文件

读取数据的原理(硬盘 --> 内存):
java程序 --> JVM(java虚拟机) --> OS(操作系统) --> OS调用读取数据的方法 --> 读取文件

字符输入流的使用步骤(重点):
1.创建FileReader对象,构造方法中绑定要读取的数据源
2.使用FileReader对象中的方法read,读取文件
3.释放资源

字符输出流

java.io.Writer: 字符输出流
此对象类是表示输出字符流的所有类的超类
定义了一些子类共性的成员方法:
public void close(): 关闭此输出流并释放与此流相关的任何系统资源。
public void flush(): 刷新此输出流并强制任何缓冲的输出字符被写出。
public void write(char[] cbuf) :指定的字符数组写入此输出流。
public void write(char[] cbuf,int off, int len) :写入字符数组的某一部分。
public void write(String str) :写入字符串。
public void write(String str,int off, int len) :写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
public abstract void write(int b) : 将指定的字符写入此输出流。

文件字节输出流

java.io.FileWriter extends OutputStreamWriter extends Wtiter
FileWriter: 文件字符输出流
作用:把内存中的数据写入到硬盘的文件中

构造方法:
FileWriter(String fileName) 根据给定的文件名构造一个FileWriter对象。
FileWriter(File file) 根据给定的file对象构造一个FileWriter对象。
写入数据的目的地:
String fileName : 目的地是一个文件的路径
File file : 目的地是一个文件
构造方法的作用:
1.创建一个FileWriter对象
2.会根据构造方法中传递的文件/文件路径,创建一个空的文件
3.会把FileWriter对象指向创建好的文件

追加写/续写:使用两个参数的构造方法:
FileWriter(String name , boolean append) 创建一个向具有指定名称的文件中写入数据的输出文件流。
FileWriter(File file, boolean append) 创建一个向指定File对象表示的文件中写入数据的输出文件输出流。
参数:
String name ,File file :写入数据的目的地
boolean append: 追加写开关
true:创建对象不会覆盖原文件,继续在文件的末尾追加写数据
false:创建一个新文件,覆盖原文件

写入数据的原理(内存–>硬盘):
java程序 --> JVM(java虚拟机) --> OS(操作系统) --> OS调用写数据的方法 --> 把数据写到文件中

字符输出流的使用步骤(重点):
1.创建FileWriter对象,构造方法中绑定要写入数据的目的地
2.使用FileWriter对象中的方法write,写入数据
3.(刷新缓冲区)
4.释放资源

flush方法和close方法的区别:
flush: 刷新缓冲区,流对象可以继续使用。
close:先刷新缓冲区,然后通知系统释放资源,流对象不可以继续再被使用了。

Properties集合

java.util.Properties集合 extends Hashtable<k,v> implements Map<k,v>
Properties类表示了一个持久的属性集。Properties可保存在流中或从流中加载。
Properties集合是一个唯一和IO流相结合的集合
可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用

属性列表中每个键及其对应值都是一个字符串。
Properties集合是一个双列集合,key和value默认都是字符串

使用Properties集合存储数据,遍历取出Properties集合中的数据
Properties集合是一个双列集合,key和value默认都是字符串
Properties集合有一些操作字符串的特有方法:
Object setProperty(String key, String value) 调用Hashtable的方法put,添加元素。
String getProperty(String key) 通过key找到value值,此方法相当于Map集合中的get(key)方法
Set stringPropertyNames() 返回此属性列表中的键集合,其中改键及其对应值是字符串,此方法相当于Map集合中的keySet方法

可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
void store(OutputStream out, String coments)
void store(Writer writer, String coments)
参数:
OutputStream out:字节输出流,不能写入中文
Writer writer:字符输出流,可以写中文
String coments:注释,用来解释说明保存的文件是做什么用的
不能使用中文,会产生乱码,默认是Unicode编码
一般使用""空字符串

使用步骤:
1.创建Properties集合对象,添加数据
2.创建字节输出流/字符输出流对象,构造方法中绑定要输出的目的地
3.使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
4.释放资源

可以使用Properties集合中的方法load,把硬盘中存储的文件(键值对),读取到集合中使用
void load(InputStream inStream)
void load(Reader reader)
参数:
InputStream inStream:字节输入流,不能读取含有中文的键值对
Reader reader:字符输入流,能读取含有中文的键值对

使用步骤:
1.创建Properties集合对象
2…使用Properties集合中的方法load读取保存键值对的文件
3.遍历Properties集合
注意:
1.存储键值对的文件中,键与值默认的连接符号可以使用=,空格(或其他符号)
2.存储键值对的文件中,可以使用#进行注释,被注释的键值对不会再被读取
3.存储键值对的文件中,键与值默认都是字符串,不用再加引号

缓冲流

字节缓冲输出流

java.io. BufferedOutputStream extends OutputStream
BufferedOutputStream:字节缓冲输出流
继承自父类的成员方法:
public void close(): 关闭此输出流并释放与此流相关的任何系统资源。
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) : 将指定的字节写入此输出流。

构造方法:
BufferedOutputStream(OutputStream out) 创建一个新的缓冲输入流,以将数据写入指定的底层输出流。
BufferedOutputStream(OutputStream out, int size) 创建一个新的缓冲输入流,以将具有指定缓冲区大小的数据写入指定的底层输出流。
参数:
OutputStream out:字节输出流
我们可以传递FileOutputStream,缓冲流会给FileOutputStream增加一个缓冲区,提高FileOutputStream的写入效率
int size:指定缓冲流内部缓冲区的大小,不指定默认
使用步骤:
1.创建FileOutputStream对象,构造方法中传递字节输出流
2.创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象,提高FileOutputStream的写入效率
3.使用BufferedOutputStream对象中的方法write,把数据写入到内部缓冲区中
4.使用BufferedOutputStream对象中的方法flush,把内部缓冲区中的数据,刷新到文件中
5.释放资源(会先调用flush方法刷新数据,第四步可省略)

字节缓冲输入流

java.io.BufferedInputStream extends InputStream
BufferedInputStream: 字节缓冲输入流

继承自父类的成员方法:
int read(): 从输入流中读取数据的下一个字节。
int read(byte[] b) : 从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中。
void close() : 关闭此输入流并释放与该流关联的所有系统资源。
构造方法:
BufferedInputStream(InputStream in) 创建一个BufferedInputStream并保存其参数,即输入流in,以便将来使用
BufferedInputStream(InputStream in,int size) 创建具有指定缓冲区大小的BufferedInputStream并保存其参数,即输入流in,以便将来使用
参数:
InputStream in:字节输入流
我们可以传递FileInputStream,缓冲流会给FileInputStream增加一个缓冲区,提高FileInputStream的读取速率
int size:指定缓冲流内部缓冲区的大小,不指定默认

使用步骤:
1.创建FileInputStream对象,构造方法中绑定要读取的数据源
2.创建BufferedInputStream对象,构造方法中传递FileInputStream对象,提高FileInputStream的读取速率
3.使用BufferedInputStream对象中的方法read,读取文件
4.释放资源

字符缓冲输出流

java.io. BufferedWriter extends Writer
BufferedWriter:字符缓冲输出流
继承自父类的成员方法:
public void close(): 关闭此输出流并会先刷新他。
public void flush(): 刷新此输出流并强制任何缓冲的输出字符被写出。
public void write(char[] cbuf) :指定的字符数组写入此输出流。
public void write(char[] cbuf,int off, int len) :写入字符数组的某一部分。
public void write(String str) :写入字符串。
public void write(String str,int off, int len) :写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
public abstract void write(int b) : 将指定的字符写入此输出流。
构造方法:
BufferedWriter(Writer writer) 创建一个使用默认大小输出缓冲区的缓冲字符输出流。
BufferedWriter(Writer writer, int size) 创建一个使用给定大小输出缓冲区的新缓冲字符输出流。
参数:
Writer writer:字符输出流
我们可以传递FileWriter,缓冲流会给FileWriter增加一个缓冲区,提高FileWriter的写入效率
int size:指定缓冲流内部缓冲区的大小,不指定默认

特有的成员方法:
void newLine():写入一个行分隔符,会根据不同的操作系统,获取不同的行分隔符
换行:换行符号
widows: \r\n
linux: /n
mac: /r
使用步骤:
1.创建字符缓冲输出流对象,构造方法中传递字符输出流
2.使用字符缓冲输出流中的方法write,把数据写入到内部缓冲区中
3.使用字符缓冲输出流中的方法flush,把内部缓冲区中的数据,刷新到文件中
4.释放资源(会先调用flush方法刷新数据,第四步可省略)

字符缓冲输入流

java.io. BufferedReader extends Reader
BufferedReader :字节缓冲输入流
继承自父类的成员方法:
int read(): 读取单个字符并返回。
int read(char[] cbuf) : 一次读取多个字符,将字符读入数组。
void close() : 关闭此输入流并释放与该流关联的所有系统资源。

构造方法:
BufferedReader (Reader reader ) 创建一个使用默认大小缓冲区的缓冲字符输入流。
BufferedWriter(Reader reader , int size) 创建一个使用给定大小缓冲区的新缓冲字符输入流。
参数:
Reader reader :字符输入流
我们可以传递FileReader ,缓冲流会给FileReader 增加一个缓冲区,提高FileReader 的读取效率
int size:指定缓冲流内部缓冲区的大小,不指定默认

特有的成员方法:
void readLine():读取一行的数据
使用步骤:
1.创建字符缓冲输入流对象,构造方法中传递字符输入流
2.使用字符缓冲输出流中的方法read ,把数据写入到内部缓冲区中
3.释放资源

转换流

字符输出转换流

java.io. OutputStreamWriter extends Writer
OutputStreamWriter :字符输出转换流,是字符流通向字节流的桥梁,可使用指定的charset将要写入流中的字符编码成字节
继承自父类的成员方法:
public void close(): 关闭此输出流并会先刷新他。
public void flush(): 刷新此输出流并强制任何缓冲的输出字符被写出。
public void write(char[] cbuf) :指定的字符数组写入此输出流。
public void write(char[] cbuf,int off, int len) :写入字符数组的某一部分。
public void write(String str) :写入字符串。
public void write(String str,int off, int len) :写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
public abstract void write(int b) : 将指定的字符写入此输出流。
构造方法:
OutputStreamWriter (OutputStream out) 创建一个使用默认字符编码的OutputStreamWriter。
OutputStreamWriter (OutputStream out,String charsetName) 创建一个使用指定字符集的OutputStreamWriter。
参数:
OutputStream out:字节输出流,可以用来写转换之后的字节到文件中
String charsetName:指定的编码表名称,不区分大小写,可以是utf-8/UTF-8/GBK,…不指定默认使用UTF-8

使用步骤:
1.创建OutputStreamWriter 对象,构造方法中传递字节输出流和指定的编码表名称
2.使用OutputStreamWriter 对象中的方法write,把字符转换为字节存储到缓冲区中(编码)
3.使用OutputStreamWriter 对象中的方法flush,把内部缓冲区中的数据,刷新到文件中
4.释放资源(会先调用flush方法刷新数据,第四步可省略)

字节输入转换流

java.io. OutputStreamReader extends Reader
OutputStreamReader :字节输入转换流,是字节流通向字符流的桥梁,可使用指定的charset读取字节并将其解码为字符。

继承自父类的成员方法:
int read(): 读取单个字符并返回。
int read(char[] cbuf) : 一次读取多个字符,将字符读入数组。
void close() : 关闭此输入流并释放与该流关联的所有系统资源。

构造方法:
InputStreamReader(InputStream In) 创建一个使用默认字符编码的InputStreamWriter。
InputStreamReader (InputStream In,String charsetName) 创建一个使用指定字符集的InputStreamReader。
参数:
InputStream In :字节输入出流,用来读取文件中保存的字节
String charsetName:指定的编码表名称,不区分大小写,可以是utf-8/UTF-8/GBK,…不指定默认使用UTF-8

使用步骤:
1.创建InputStreamReader 对象,构造方法中传递字节输入流和指定的编码表名称
2.使用InputStreamWriter 对象中的方法reader读取文件
3.释放资源

注意事项:
构造方法中指定的编码表名称要和文件的编码相同,否则会发生乱码

序列化流

序列化输出流

java.io.ObjectOutputStream extends OutputStream
ObjectOutputStream:序列化输出流
作用:把对象以流的方式写入到文件中保存

构造方法:
ObjectOutputStream(OutputStream out) :创建写入指定OutputStream的ObjectOutputStream.
参数:
OutputStream out:字节输出流

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

使用步骤:
1.创建ObjectOutputStream对象,构造方法中传递字节输出流。
2.使用ObjectOutputStream对象中的方法writeObject,把对象写入到文件中
3.释放资源

序列化输入流

java.io.ObjectInputStream extends InputStream
ObjectInputStream:序列化输入流
作用:把文件中保存的对象,以流的方式读取出来使用。

构造方法:
ObjectInputStream(InputStream in) :创建从指定InputStream读取的ObjectInputStream
参数:
InputStream in:字节输入流

特有的成员方法:
Object readObject(Object obj) 从ObjectInputStream读取对象。

使用步骤:
1.创建ObjectInputStream对象,构造方法中传递字节输出流。
2.使用ObjectInputStream对象中的方法readObject,读取保存对象的文件。
3.释放资源

Serializable

类通过实现java.io.Serialezable接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。
Serializable接口也叫标记型接口
要进行序列化和反序列化的时候,就会检测类上是否有这个标记
当我们进行序列化和反序列化的时候,就会检测类上是否有这个标记

static关键字:静态关键字
静态优先于非静态加载到内存中(静态优先于对象进入到内存中)
被static修饰的成员变量不能被序列化的,序列化的都是对象

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

打印流

java.io.PrintStream:打印流
PrintStream 为其他输出流添加功能,使它们能够方便的打印各种数据值表示形式。
PrintStream特点:
1.只负责数据的输出,不负责数据的读取
2.与其他输出流不同,PrintStream永远不会抛出IOException
3.有特有的方法,print,println
void print(任意类型的值)
void println(任意类型的值并换行)

构造方法:
PrintStream(File file) 输出目的地是一个文件
PrintStream(OutputStream out) 输出目的地是一个字节输出流
PrintStream(String fileName) 输出目的地是一个文件路径
PrintStream extends OutputStream
继承自父类的成员方法:
public void close(): 关闭此输出流并释放与此流相关的任何系统资源。
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) : 将指定的字节写入此输出流。

注意:
如果使用继承自父类的write方法写数据,那么查看数据的时候会查询编码表 97->a
如果使用继自己特有的print/println方法写数据,写的数据原样输出 97->97

可以改变输出语句的目的地(打印流的流向)
输出语句,默认在控制台输出
使用System.setOut方法改变输出语句的目的地改为参数中传递的打印流的目的地
static void setOut(PrintStream out)
重新分配"标准"输出流。

TCP通信

TCP通信的客户端

TCP通信的客户端:向服务器发送连接请求,给服务器发送数据,读取服务器回写的数据
表示客户端的类:
java.net.Socket:此类实现客户端套接字(也可以就叫套接字)。套接字是两台机器间通信的端点。
套接字:包含了IP地址和端口号的网络单位

构造方法:
Socket(String host, int port) 创建一个流套接字并将其链接到指定主机上的指定端口号。
参数:
String host:服务器主机的名称/服务器的IP地址
int port:服务器的端口号

成员方法:
OutputStream getOutputStream() 返回此套接字的输出流
InputStream getInputStream() 返回该套接字的输入流
void close() 关闭此套接字
void shutdownOutputStream() 关闭此套接字的输出流
void shutdownInputStream() 关闭此套接字的输入流

实现步骤:
1.创建一个客户端对象Socket,构造方法绑定服务器的IP地址和端口号
2.使用Socket对象中的方法getOutputStream()获取网络字节输出流OutputStream 对象
3.使用网络字节输出流OutputStream 对象中的方法write,给服务器发送数据
4.使用Socket对象中的方法getInputStream() 获取网络字节输入流InputStream对象
5.使用网络字节输入流InputStream对象中的方法read,读取服务器回写的数据
6.释放资源(Socket)
注意:
1.客户端和服务器进行交互,必须使用Socket中提供的网络流,不能使用自己创建的流对象
2.当我们创建客户端对象Socket的时候,就回去请求服务器和服务器经过三次握手建立连接通路
这时如果服务器没有启动,那么就会抛出异常ConnectExecption: Connection refused:connect
如果服务器已经启动,那么就会进行交互了

TCP通信的服务器端

TCP通信的服务器端:接收客户端的请求,读取客户端发送数据,给客户端写数据
表示服务器端的类:
java.net.ServerSocket:此类实现服务器端套接字

构造方法:
ServerSocket( int port) 创建绑定到特定端口的服务器套接字。
参数:
int port:服务器的端口号
服务器必须明确一件事情,必须知道是哪个客户端请求的服务器
所以可以使用accept方法获取到请求的客户端对象Socket

成员方法:
void close() 关闭此套接字
Socket accept():侦听并接收到此套接字的连接。

实现步骤:
1.创建服务器对象ServerSocket和系统要指定的端口号
2.使用ServerSocket对象中的方法accept()获取到请求的客户端对象Socket
3.使用Socket对象中的方法getInputStream() 获取网络字节输入流InputStream对象
4.使用网络字节输入流InputStream对象中的方法read,读取客户端发送的数据
5.使用Socket对象中的方法getOutputStream()获取网络字节输出流OutputStream 对象
6.使用网络字节输出流OutputStream 对象中的方法write,给客户端发送数据
7.释放资源(Socket,ServerSocket)

函数式接口

函数式接口:有且只有一个抽象方法的接口,称之为函数式接口
当然接口中可以包含其他的方法(默认,静态,私有)

@FunctionalInterface注解
作用:可以检测接口是否是一个函数式接口
是:编译成功
否:编译失败

函数式接口的使用:一般可以作为方法的参数和返回值类型

Lambda的特点:延迟加载
Lambda的使用前提,必须存在函数式接口

常用函数式接口

Supplier

java.util.function.Supplier接口仅包含一个无参的方法:T get()。用来获取一个泛型参数指定类型的对象数据。
Supplier接口被称之为生产型接口,指定接口的泛型是什么类型,那么接口中的get方法就会产生什么类型的数据

Consumer

ava.util.function.Consumer接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛型指定。
Consumer接口中包含抽象方法void accept(T t) ,意为消费一个指定泛型的数据。
至于具体怎么消费(使用),需要自定义(输出,计算)
默认方法:
void andThen(Consumer consumer):连接Consumer接口再同时进行消费(谁写前面谁先消费)

Predicate

java.util.function.Predicate接口
作用:对某种数据类型的数据进行判断,结果返回一个boolean值
Predicate接口中包含抽象方法boolean test(T t) :用来对指定数据类型数据进行判断的方法
结果:
符合条件,返回true
不符合条件,返回false
默认方法:
boolean and(Predicate predicate) :与
boolean or(Predicate predicate) : 或
boolean negate(Predicate predicate) :非

Function

java.util.function.Function<T,R>接口用来根据一个类型的数据的到另一个类型的数据。
前者为前置条件,后者称为后置条件。
Function接口中最主要的抽象方法为:R apply(T t),根据类型T的参数获取类型R的结果。
适用的场景例如:将String类型转换为Integer类型。

Function接口中的默认方法andThen:用来进行组合操作

流式思想

使用Stream流的方式,遍历集合,对集合中的数据进行过滤
Stream流是JDK1.8之后出现的
关注的是做什么,而不是怎么做

获取流

java.util.stream.Stream是java8新加入的最常用的流接口。(这并不是一个函数式接口。)
获取一个流非常简单,有以下几种常用的方式:
所有的Collection集合都可以通过stream默认方法获取流;
default Stream stream()
Stream接口的静态方法of可以获取数组对应的流
static Stream of (T… values)
参数是一个可变参数,那么我们就可以传递一个数组

常用方法——forEach

Stream流中的常用方法——forEach
void forEach(Consumer<? super T> action);
该方法接受一个Consumer接口函数,会将每一个流元素交给该函数进行处理。
Consumer接口是一个消费型的函数式接口,可以传递Lambda表达式,消费数据。

简单记:
forEach方法,用来遍历流中的数据
是一个终结方法,遍历之后就不能继续调用Stream流中的其他方法

常用方法——filter

Stream流中的常用方法——filter:用于对Stream流中的数据进行过滤
Stream filter(Predicate<? super T> predicate);
filter方法的参数Predicate是一个函数式接口,所以可以传递Lambda表达式,对数据进行过滤
Predicate中的抽象方法:
boolean test(T t);
是一个延迟方法,过滤之后还能继续调用Stream流中的其他方法

常用方法——map

Stream流中的常用方法——map
如果需要将流中的元素映射到另一个流中,可以使用map方法
Stream map(Function<? super T, ? extends R> mapper);
该接口需要一个Function函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的流。
map中的抽象方法:
R apply(T t);
是一个延迟方法,映射之后还能继续调用Stream流中的其他方法

常用方法——count

Stream流中的常用方法——count:用于统计Stream流中元素的个数
long count();
是一个终结方法,返回值是一个long类型的整数,使用之后就不能继续调用Stream流中的其他方法

常用方法——limit

Stream流中的常用方法——limit:用于截取流中的元素
limit方法可以对流进行截取,只取用前n个。方法签名:
Stream limit(long maxSize);
参数是一个long型,如果集合当前长度大于参数则截取;否则不进行操作
是一个延迟方法,截取之后还能继续调用Stream流中的其他方法

常用方法——skip

Stream流中的常用方法——skip:用于跳过元素
如果希望跳过前几个元素,可以使用skip方法获取一个截取之后的新流;
Stream skip(long n);
如果流的当前长度大于n,则跳过前n个;否则将会得到一个长度为0的空流。
是一个延迟方法,使用之后还能继续调用Stream流中的其他方法

常用方法——concat

Stream流中的常用方法——concat:用于把流组合到一起
如果有两个流,希望和并成一个流,那么可以使用Stream接口的静态方法concat
static Stream concat(Stream<? extends T> a, Stream<? extends T> b);

方法引用

  • 通过对象名引用成员方法
    使用前提是对象名已经存在的,成员方法也是已经存在
    就可以使用对象名来引用成员方法

  • 通过类名引用静态成员方法
    类已经存在,静态成员方法也是已经存在
    就可以通过类名来引用静态成员方法

  • 使用super引用类的成员方法
    super已经存在,父类的成员方法也是已经存在
    就可以通过super来引用父类的成员方法

  • 使用this引用类的成员方法
    this已经存在,本类的成员方法也是已经存在
    就可以通过this来引用本类的成员方法

  • 类的构造器(构造方法)引用
    使用方引用优化Lambda表达式
    构造方法new 类名(参数)已知
    就可以通过类名来引用new创建对象

  • 数组的构造器(构造方法)引用
    使用方引用优化Lambda表达式
    已知创建的就是 int[]数组
    数组的长度也是已知的
    int[] 引用new,根据参数传递的长度来创建数组

Junit单元测试

  • 测试分类:
  1. 黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值。
  2. 白盒测试:需要写代码,关注程序具体的执行流程。
  • Junit使用:白盒测试
    * 步骤:
    1. 定义一个测试类(测试用例)
    2. 定义测试方法:可以独立运行
    3. 给方法家@Test
    4. 导入junit以来环境
    * 判断结果:
    * 红色:失败
    * 绿色:成功
    * 一般我们会使用断言操作来处理结果
    * Assert.assertEquals(断言结果,测试结果);
    * 补充:
    * @Before:
    * 修饰的方法会在测试方法之前被自动执行
    * @After:
    * 修饰的方法会在测试方法执行之后自动被执行。

反射:框架设计的灵魂

  • 框架:半成品软件,可以在框架的基础上进行软件开发,简化代码

  • 反射:将类的各个组成部分封装为其他对象,这就是反射机制

    • 好处:
    1. 可以在程序运行过程中,操作这些对象
    2. 可以解耦,可以提高程序的可扩展性
  • Class对象功能:

  • 获取功能:

  1. 获取成员变量们
    * Field[] getFields(): 获取所有public修饰的成员变量
    * Field getField(String name):获取指定的public修饰的成员变量
    * Field[] getDeclaredFields():获取所有(忽略修饰符)的成员变量
    * Field getDelaredField(String name):获取指定(忽略修饰符)的成员变量

  2. 获取构造方法们
    *Constructor<?>[] getConstructors(): 获取所有public修饰的构造方法
    * Constructor getConstructor(类<?>… parameterTypes):获取指定的public修饰的构造方法
    * Constructor getDeclaredConstructor(类<?>… parameterTypes):获取指定(忽略修饰符)的构造方法
    * Constructor<?>[] getDeclaredConstructors():获取所有(忽略修饰符)的构造方法

  3. 获取成员方法们
    *Method[] getMethods(): 获取所有public修饰的成员方法
    * Method getConstructor(String name, 类<?>… parameterTypes):获取指定的public修饰的成员方法
    * Method[] getDeclaredMethods():获取所有(忽略修饰符)的成员方法
    * Method getDelaredMethod(String name, 类<?>… parameterTypes):获取指定(忽略修饰符)的成员方法

  4. 获取类名
    * String getName()

  • Field:成员变量
    * 操作:
    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:获取方法名

注解

  • 概念描述:
    * JDK1.5之后的新特性
    * 说明程序的
    * 使用注解:@注解名称

  • 作用分类:
    1. 编写文档:通过代码里标识的注解生成doc文档
    2. 代码分析:通过代码里标识的注解对代码进行分析【使用反射】
    3. 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】

  • JDK中预定义的一些注解
    * @Override:检测被该注解标注的方法是否是继承子父类(接口)的
    * @Deprecated:该注解标注的内容,表示;已过时
    * @SuppressWarnings:压制警告
    * 一般传递参数all

  • 自定义注解
    * 格式:
    元注解
    public @interface 注解名称{
    属性列表;
    }
    * 本质:注解本质上就是一个接口,该接口默认继承Annotation接口
    * public interface MyAnnotation extends java.lang.annotation.Annotation{}
    * 属性:接口中可以定义的成员方法
    * 要求:
    1. 属性的返回值类型有下列取值
    * 基本数据类型
    * String
    * 枚举
    * 注解
    * 以上类型的数组

      		2. 定义了属性,在使用时需要给属性赋值
      			1. 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。
      			2. 如果只有一个属性需要赋值,并且属性的名称时value,则value可以省略,直接定义值即可。
      			3. 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}省略。
    
  • 元注解
    * @Target:描述注解能够作用的位置
    * ElementType取值:
    * TYPE:可以作用于类上
    * METHOD:可以作用于方法上
    * FIELD:可以作用于成员变量上
    * @Retention:描述注解被保留的阶段(生命周期)
    * @Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
    * @Documented:描述注解是否被抽取到api文档中
    * @Inherited:描述注解是否被子类继承

  • 在程序使用(解析)注解:获取注解中定义的属性值
    1. 获取注解定义的位置的对象(Class,Method,Field)
    2. 获取指定的注解
    * getAnnotation(Class)
    //其实就是在内存中生成了一个该注解接口的子类实现对象
    public class ProImpl implements Pro{
    public String className(){
    return “全类名”;
    }
    public String methodName(){
    return “方法名”;
    }
    }
    3. 调用注解中的抽象方法获取配置的属性值

--------------------------------------------------华丽的分割线---------------------------------------------------
---------------------------------javase的学习至此告一段落---------------------------------------------------

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值