Java个人总结
本文最后更新于 226 天前,其中的信息可能已经有所发展或是发生改变。如有疑问或错误请反馈至邮箱super.lucky.qu@gmail.com

前言

普通字体内容为查阅无误,斜体部分为个人理解

电脑端可以于左栏“文章目录”来索引到指定小节,手机端可以通过左上角按钮唤出菜单索引到指定小节

Java三大特性

封装

封装通过对属性的私有化,使得访问只能通过定义过的方法去访问对象,从而保护数据且方便编码

继承

利用关键字extends建立起子类和父类之间的继承关系,子类具有父类的属性和方法

其中,构造方法不可被继承,属性都可以被继承,方法中被private修饰的不可以被继承

在java当中只允许单继承,一个类只能有一个直接父类

Java中不支持多继承,但支持多层继承

Object类是所有类的直接或间接父类

只有虚方法才可以被继承

继承中的成员变量访问满足就近原则(先在局部位置找,本类成员位找,父类成员位找,逐级往上)

this.去本类成员变量里找

.super直接去父类里面找

成员方法的直接调用满足就近原则

多态

定义

同类型的对象表现出的不同形态

表现形式

父类类型 对象名称 = 子类对象

构成条件

有继承关系

有父类引用指向子类对象

有方法重写

优点

使用父类作为参数,可以接收所有子类对象,体现多态的拓展性和便利性

在多态形式下,右边对象可以实现解耦合,便于拓展和维护

缺点

当通过多态去调用父类没有而子类中有的成员方法的时候会直接编译报错

解决方法:将父类类型转换为子类类型(与强制转换格式相同)

注意事项

用多态方式调用成员变量遵循编译看左边,运行看左边

调用成员变量也是返回父类的变量

用多态方式调用成员方法遵循编译看左边,运行看右边

调用成员方法试运行子类的方法

语法

注释

//这是行注释

/*
  这是块注释
          */

/**
   这是文档注释
             */

关键字

定义

被java赋予了特定含义的英语单词,其组成全部为小写单词

一些关键字

class

定义一个类,后跟随类名,一个java文件里可以有多个类,但是只能有一个被public修饰的类,且被public修饰的类名需要与文件名保持一致

extends

表示继承关系,比如dog extends animal,表示dog继承animal类

instanceof

格式

类名 instanceof 类名

用途

判断两边类型是否相同,如果相同则返回true,如果不同则返回false

final

final关键字表示最终,被其修饰的元素不能被更改

当final修饰方法,表示该方法作为最终方法,不能被重写

当final修饰类,表示这个类为最终类,不能被继承

当final修饰变量,表示这个变量作为常量,不能被修改

如果修饰的是引用数据类型,则指的是地址值不能被改变

变量与常量

进制

java规定,二进制前以0b开头,十进制不做修改,八进制以0开头,十六进制以0x开头

数据类型

基本数据类型

byte

整数,占用一个字节,取值范围为(-128~127)

常用于存储字节数据

默认初始值为0

short

整数,占用两个字节,取值范围为(-32768~32767)

常用于兼容性考虑

默认初始值为0

int

整数,占用四个字节,取值范围为(-2147483648~2147483647)

常用于存储普通整数

默认初始值为0

long

整数,占用八个字节,取值范围为(-9223372036854775808~9223372036854775807)

常用于存储长整数

定义时需要在定义数值之后加上L作为后缀

默认初始值为0

float

浮点数,占用四个字节,取值范围为(-3.401298e-38~3.402823e+38)

不常用,用于存储浮点数

定义时需要在定义数值之后加上F作为后缀

默认初始值为0.0

double

浮点数,占用八个字节,取值范围为(-4.9000000e-324~1.797693e+308)

常用于存储双精度浮点数

默认初始值为0.0

char

字符型,占用两个字节,取值范围为(0~65535)

常用于存储单个字符

默认初始值为’\u0000′

boolean

布尔型,占用四个字节,取值范围为(true,false)

常用于存储逻辑变量

默认初始值为false

引用数据类型

数组

数组是用于存储同种数据类型的多个值,定义格式为(此处以int类型举例)

int []arr;

数组在定义后需要初始化,初始化分为静态初始化和动态初始化两种,静态初始化的格式为

int []arr = new int[]{元素1,元素2,xxxx,元素n};

可以简写,格式为在原基础上省略”new int[]”

int []arr = {元素1,元素2,xxxx,元素n};

动态初始化格式为(此处以int类型举例)

int []arr = new int[数组长度];

其中数组长度决定了这个数组能存储的数量

需要调用数组中的值的时候只需要输入数组名[索引]即可,其中索引的值从0开始,对应数组中存储的第一个数

数组作为引用数据类型,其数组名存储的是其地址值,其地址值的含义如下

例:[D@776ec8df]

其中,'[]’表示这是一个数组,’D’表示当前数组内元素的数据类型为double类型,’@’为间隔符号,’776ec8df’为数组真正的地址值

数组的长度属性可以通过’.length’调用

String

字符串类型,为引用数据类型,详细内容于“类和方法->类->一些常用类->String”,此处不再叙述

数据类型之间的转换

隐式转换(自动类型提升)

将一个取值范围小的和一个取值范围大的进行计算的时候自动将较小的数据类型数据提升为较大的数据的数据类型

其中,byte、short、char这三种类型的数据在运算的时候,会直接提升至int类型,然后再进行运算,如

byte a = 3;
byte b = 4;
System.out.println(a+b);

此时a+b的数据类型为int类型而不是byte类型

强制转换

将一个取值范围大的数值赋值给取值范围小的变量,会直接删除目标数据类型所需字节之前的字节,格式为

//目标数据类型 变量名 = (目标数据类型)被强制转换的数据
double a = 5.0;
int b = (int)a;

变量

定义

用数据类型和变量名以及值来定义变量,如

int a = 12;

常量

作用

常量一般作为系统的配置信息,方便维护,提高可读性

书写格式

单个单词:全部大写

多个单词:全部大写,单词之间用下划线隔开

运算符

比较运算符

==

比较==号两边的数据是否相等,如果是相等则为true,不相等则为false

比较时基本数据类型比较的是数据的值,引用数据类型比较的则是地址值而非里面的数据

>

比较>号左边的数据是否比右边的数据大,如果为大于则为true,小于则为false

比较时基本数据类型比较的是数据的值,引用数据类型比较的则是地址值而非里面的数据

<

比较<号左边的数据是否比右边的数据大,如果为小于则为true,大于则为false

比较时基本数据类型比较的是数据的值,引用数据类型比较的则是地址值而非里面的数据

>=

比较>=号左边的数据是否大于等于右边的数据,如果是则为true,如果不是则为false

比较时基本数据类型比较的是数据的值,引用数据类型比较的则是地址值而非里面的数据

<=

比较<=号右边的数据是否大于等于左边的数据,如果是则为true,如果不是则为false

比较时基本数据类型比较的是数据的值,引用数据类型比较的则是地址值而非里面的数据

!=

比较!=号两边的数据是否不相等,如果不相等则为true,相等则为false

比较时基本数据类型比较的是数据的值,引用数据类型比较的则是地址值而非里面的数据

算数运算符

+

数字相加

数字相减

*

数字相乘

/

数字相除

%

取余运算,如9%2 = 1

自增&自减运算符

++

使用时变量在++前或者后,在前先用再加一,在后先加一再用

使用时变量在–前或者后,在前先用再减一,在后先减一再用

逻辑运算符

&

与运算符,全真才真,一假则假,会计算符号两边是否都为真,是则返回true,否则返回false

|

或运算符,一真则真,全假才假,会计算符号两边是否都为假,是则返回false,否则返回true

!

非运算符,真则假,假则真,原式为true则返回false,false则返回true

^

两边都为真或者都为假时返回true,两边一真一假则返回false

&&

短路与,当判断左边为假时不判断右边,直接输出false(一假则假)

||

短路或,当判断左边为真时不判断右边,直接输出true(一真则真)

三元运算符

格式为

关系表达式 ? 表达式1 : 表达式2

运行顺序为首先判断关系表达式,如果表达式为真则执行表达式1,否则执行表达式2

操作符

算数操作符

+

可以将两边的数值进行相加,也可以拼接字符串

赋值操作符

注意事项

除了’=’赋值运算符之外的五种赋值运算符都蕴含了强制类型转换,会在运算完之后强制转换为变量左边的类型,其中,byte、short、char类型的数据同样遵循转化为int计算

=

赋值,将符号右边的值赋给左边

+=

将符号两边进行相加后赋给左边

-=

将符号两边进行相减后赋给左边

*=

将符号两边进行相乘后赋给左边

/=

将符号两边进行相除后赋给左边

%=

将符号两边进行取余后赋给左边

修饰符

static

简介

static表示静态,是java中的一个修饰符,可以修饰成员方法,成员变量,被static修饰的成员变量叫做静态变量

特点

被static修饰的成员变量(即静态变量)被该类所有对象共享,可以用类名去调用,也可以从对象名调用

静态变量是随着类的加载而加载的,是优先于对象而出现的

被static修饰的成员方法叫做静态方法,其中,静态方法多用在测试类和工具类当中,静态方法只能访问静态方法和静态变量,并且静态方法中没有this关键字

public

可以在不同包中被使用无关类

protected

可以在不同包中被使用子类

缺省

可以在当前包中被使用

private

只能在当前类中被访问

类和方法

类的五大成员

属性,方法,构造方法,代码块,内部类

抽象类

如果一个类中存在有抽象方法,那么该类就为抽象类,当有一个类继承抽象类的时候,他必须重写抽象类中的所有抽象方法

抽象类中不一定有抽象方法

有抽象方法的类一定是抽象类

抽象类不能创建对象

可以有构造方法

全类名

包名+类名

如:site.luckyqu.userinfo.User

用来精准表达类(因为类名会重复,但是一个包里面的类名不会重复)

同时使用两个包中的同名类时,需要写全类名

一些常用类

Scanner

接收键盘输入的数值,在使用前需要导他所属的包(java.util.Scanner),使用时先进行创建对象

Scanner sc = new Scanner(System.in);

然后使用时用sc获取值即可,如

int a = sc.nextInt();

Random

生成一个随机数,在使用前需要导他所属的包(java.util.Random),使用时先进行创建对象

Random r = new Random();

然后使用时用r去生成随机数即可,如

int a = r.nextInt(填写想要随机数的范围,不填写则为该数据类型的取值范围)

其中,随机数的范围指的是他的长度,是从0开始随机的,比如填写10,便是从0~9中随机值,可以通过随机后数的加减来达到在任意数到任意数之间随机数的目的

String

定义

String是java定义好的一个类,定义在java.lang中,使用时不需要手动导包,java中所有的字符串文字都被视为此类的对象,字符串创建之后值不会改变

获取方式

一共如下有三种获取方式

使用直接复制的方式获取一个字符串对象

String 变量名 = "abc";

使用空参构造一个空白的字符串

String 变量名 = new String();

使用参数构造一个字符串

String 变量名 = new String("abc");
//还可以用字符数组来构造
char []arr = new char[]{'a','b','c'};
String 变量名 = new String(arr);

其中,也可以用byte类型的数组构建String,他会把这个数据对照ASCII码表转换后给字符串

使用技巧

因为字符串内的内容从定义便无法改变,但是构建字符串的时候使用字符数组来定义,那么字符串内仍然是字符数组,可以通过修改字符数组中的内容来达到”修改”字符串的目的

在内存中,直接赋值获取的字符串在串池,其他形式获取的字符串则在堆中,所以优先使用直接赋值获取字符串

操作方法

字符串和字符串之间的比较

boolean result = s1.equals(s2);

其中,这个方法会返回一个boolean类型的值,s1和s2为要进行比较的两个字符串

这种比较会涵盖大小写,不涵盖大小写的比较为

boolean result = s1.equalsIgnoreCase(s2);

获取字符串中的第N个字符(返回值为char类型)

char result = s1.charAt(N);

注意,字符串的数字被获取后是以字符形式存储的,比如’0’对应ASCII中的48

从字符串中获取一个范围的字符串

String result = s1.substring(左索引,右索引);

其中,获取出来的字符串包含左索引的字符而不包含右索引的字符,如果只输入一个索引,那么意为从那个索引开始一直截取到字符串末尾,同样包含左索引不包含右索引的字符

检索替换字符串中的关键词

s1.replace("康帅傅","康师傅");
StringBuilder

可以看作是一个容器,创建之后里面的内容是可以变化的

其作用主要在于可以提高字符串的操作效率

作为java已经写好的类已经做出了特殊处理,所以打印时直接打印属性值而非地址值

一般应用场景为字符串的拼接与字符串的反转

创建一个空白可变字符串对象:

StringBuilder sb = new StringBuilder();

根据字符串的内容去创建一个可变字符串对象:

String str1 = "something";
StringBuilder sb = new StringBuilder(str1);

其成员方法有:

添加数据,并返回对象本身

.append(任意类型)

反转容器中的内容

.reverse()

返回长度(字符出现的个数)

.length()

将StringBuilder转化为String

toString()

StringBuilder的原理

首先默认创建一个长度为16的字节数组

当添加的内容长度小于16,直接存储

当添加的内容长度大于16,则会扩容(扩容容量为原来的容量*2+2)

如果扩容之后还不够,则容量扩容为其长度

StringJoiner

可以看作一个容器,于JDK8之后出现

其作用为可以提高字符串的操作效率,可以规定数据之间的间隔符以及开头符号和结束符号

作为java已经写好的类已经做出了特殊处理,所以打印时直接打印属性值而非地址值

其有两种构造方法

创建一个StringJoiner对象,指定拼接时的间隔符号

StringJoiner sj = new StringJoiner("间隔符号");

创建一个StringJoiner对象,指定拼接时的间隔符号以及开始符号和结束符号

StringJoiner sj = new StringJoiner("间隔符号","开始符号","结束符号")

成员方法

添加数据并返回对象本身

.add(String类型)

返回长度(返回字符出现的个数,包含全部间隔符号和开始符号和结束符号)

.length()

返回一个字符串(已经拼接好的结果)

.toString()

内存原理

当直接赋值创建字符串的时候会直接服用串池里的字符串,没有则会在串池里创建

new出来的字符串不会进行复用而是直接开辟一个新的空间

字符串拼接的底层原理分为两种

当拼接的字符串没有变量参与时,会触发优化机制,在编译的时候直接成为最终结果然后赋值

当拼接的字符串有变量参与时,在JDK8之前会采用StringBuilder的方法去拼接

在JDK8之后会先进行一个预估创建一个数组将元素放进去,然后用数组给String赋值

ArrayList

ArraList<E>集合,<E>表示泛型,限定集合中存储数据的类型,用<数据类型>来限定

集合初始长度为0,每次添加一个元素都会自动扩容,每次删除一个元素也会自动释放空间

集合不能直接存基本数据类型,只能存引用数据类型,如果要存基本数据类型,需要转化为他们的包装类来存储

比如创建一个集合用来存储字符串类型的数据

ArrayList<String> = new ArrayList<String>();
//JDK7之后可以省略等号后面<>中的数据类型

直接答应ArrayList类的时候会直接打印集合中的存储数据内容,展示的时候会用[]包裹

成员方法

添加元素,布尔型返回值表示是否添加成功(下列例子以名为arraylist的ArrayList类演示)

arraylist.add("something")

删除指定元素,返回值表示是否删除成功

arraylist.remove("something")

删除指定索引的元素,返回被删除的元素

arraylist.remove(索引)

修改指定索引下的元素,返回原来的元素

arraylist.set(索引,"something")

获取指定索引的元素

arraylist.get(索引)

集合的长度,也就是集合中元素的个数

arraylist.size()

基本数据类型的包装类

byte->Byte

short->Short

char->Character

int->Integer

long->Long

float->Float

double->Double

boolean->Boolean

内部类

定义

在一个类的里面在定义一个类

内部类表示的事物是外部类的一部分

内部类单独出现没有意义

内部类可以直接访问外部类的成员变量,包括私有

外部类想要访问内部类的成员必须创建对象

成员内部类

定义

写在成员位置的,属于外部类的成员

成员内部类可以被一些修饰符所修饰

获取成员内部类的对象

方式一

在外部类中编写方法,对外提供内部类的对象

方式二

直接创建格式

外部类名.内部类名 对象名 = 外部类对象.内部类对象

第二种格式的范例

Outer.Inter oi = new Outer().new Inter();

Outer.this.a

个人理解为

Outer这个类调用了this,而this指向的是调用者的成员变量,所以指向的是Outer的成员变量a,用于在重名变量中调用

静态内部类

定义

静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要先创建对象

创建格式

创建静态内部类的格式为:外部类名.内部类名 对象名 = new 外部类名.内部类名

调用方法

调用非静态方法需要先创建对象,再用对象调用

调用静态方法的格式为 外部类名.内部类名.方法名

局部内部类

定义

将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量,外界无法直接使用,需要在方法内部创建对象并使用,该类可以直接访问外部类的成员,也可以访问方法内的局部变量

匿名内部类

定义

隐藏了名字的内部类

可以写在成员位置,也可以写在局部位置

包含了继承或者实现,方法重写,创建对象

整体就是一个类的子类对象或者接口的实现类的对象

定义格式

new 类名或者接口名(){

    重写方法;

};

使用场景

当方法的参数是接口和类,以接口为例,可以传递这个接口的实现类对象,如果实现类只要使用一次,就可以用匿名内部类简化代码

工具(util)类

定义

帮助做一些事情但是不描述任何事物的类叫做工具类

要求

类名要见名知意,私有化构造方法,方法定义为静态

方法

抽象方法

使用场景

将一个共性方法抽取到父类之后,每一个子类执行的内容不一样,所以在父类中不能有具体的方法体,该方法就可以定义为抽象方法

定义方法

public abstract 返回值类型 方法名( 参数列表);

虚方法

在类中非private、static、final修饰的方法就是虚方法,只有虚方法才能被继承

默认方法

书写格式

public default 返回值类型 方法名(参数列表)

注意事项

默认方法不是抽象方法所以不强制被重写

但是如果被重写,重写的时候去掉default关键字

方法的重写

使用情景

当父类的方法不能满足子类现在的需求时,需要对方法进行重写

书写格式

在继承体系当中,子类出现了和父类一模一样的方法声明,我们就称子类这个方法是重写的方法

在重写时

@Override 放在重写后的方法的上一行,IDE会检查子类重写时语法是否正确·

然后进行同一名字方法的声明

注意事项

子类重写父类方法时,访问权限子类必须大于父类

子类重写父类方法时,返回值类型子类必须小于等于父类

只有被添加到虚方法表的方法才能被重写

子类不能继承父类的构造方法,但是可以通过super调用

子类中所有的构造方法默认先访问父类中的无参构造,再去执行自己

子类构造方法第一行语句默认为super()调用父类的无参构造

可以用this调用本类其他构造方法(并不会再添加super()以造成重复)

接口

定义

接口就是一种规则,是一种对行为的抽象

接口不能实例化

定义方法

Interface 接口名

和类&接口关系

接口不能实例化,接口和类的关系是实现关系,通过implements关键字来表示

public class 类名 implements 接口名{}

一个类可以在继承类的同时实现多个接口

接口和接口的关系为继承关系,可以单继承,也可以多继承,如果实现类实现了最下面的接口,那么就需要重写所有的抽象方法

内部属性

接口中的变量默认是静态常量

接口中没有构造方法

接口中方法默认为抽象方法

语句与代码块

结构语句

选择结构语句

if

格式:

if(关系表达式){
    语句体
}

执行顺序为,先对关系表达式进行判断,如果关系表达式为真,那么执行语句体,如果关系表达式为假,则跳过执行后面的语句

if else

格式:

if(关系表达式){
    语句体1
}else{
    语句体2
}

执行顺序为,先对关系表达式进行判断,如果关系表达式为真,那么执行语句体1,如果关系表达式为假,那么执行语句体2

if else if else

格式:

if(关系表达式1){
    语句体1
}else if(关系表达式2){
    语句体2
}else{
    语句体3
}

执行顺序为,先对关系表达式1进行判断,如果关系表达式为真,则执行语句体1,如果关系表达式为假,则对关系表达式2进行判断,如果关系表达式为真,则执行语句体2,否则执行语句体3

switch

标准格式:

switch(表达式){
    case 1:
        语句体1;
        break;
    default:
        break;
}

执行顺序为,先执行表达式,然后用表达式的值去依次和case后的数值进行比较,如果相同,就执行该case后对应的语句体,如果所有case后的值都和表达式计算结果数值不一样,则执行default之后的语句,然后结束switch语句

在switch语句的执行过程中,遇到break就会跳出语句

表达式的取值的数据类型只能是byte,short,int,char,在jdk7之后也可以是String

case后面的值不能为变量,且不能与该switch中的其他case语句后的值有重复,在case语句之后如果没有加break则会导致case穿透(在执行完当前case语句后不判断直接执行下一个case语句后的语句体,直到遇到break或者该switch语句的右括号结束)

case之后的值可以是多个,值与值之间用逗号隔开

switch有一种简化写法,但仅在高版本jdk中可用,其格式为:

switch (表达式){
    case 1 -> {语句体1};
    case 2 -> {语句体2};
    default -> {语句体3}
}

这种简化写法可以不用在case或者default之后写break,并且在case或者default指向的大括号之内只有一个语句时,可以省略大括号

循环结构语句

for

格式:

for(初始化语句;条件判断语句;条件控制语句){
    循环体语句
}

执行顺序为,首先执行初始化语句,然后判断条件语句是否为真,不为真则直接执行循环之后的语句,真则执行循环体语句,在执行完循环体语句后执行条件控制语句,然后再次进行条件判断,如果为真则继续执行循环体语句,如果为假则跳出循环

其中,在for循环中定义的变量为这个for循环的局部变量,其作用范围只在循环内

while

格式:

while(条件判断语句){
    循环体语句
}

执行顺序为,首先进行条件判断语句,如果不为真,则执行循环之后的语句,如果为真,则执行循环体语句,在执行完循环体语句之后,再进行条件判断语句,真则继续执行循环体语句,假则跳出循环

其中,条件判断语句中填写true则该while循环会成为永续循环

do while

格式:

do{
    循环体语句
}while(条件判断语句)

执行顺序为,首先执行循环体语句,之后进行条件判断,如果不为真则跳出循环,如果为真则继续执行循环体语句

流程控制语句

continue

结束本次循环并进行下一次循环

break

跳出这个循环

输出语句

System.out.println()

输出语句,括号内为输出内容,当输出内容时变量时,会直接打印变量的值,输出内容可

以是变量之间的运算,会输出运算后的值,null无法直接被打印,需要用字符串形式打印,输出完后会换行

代码块

构造代码块

用处

在构造方法执行之前,优先执行构造代码块中的内容

格式

{代码内容}

静态代码块

用处

随着类的加载而加载,并且自动触发且只执行一次

格式

static {代码内容}

设计模式

适配器设计模式

应用情景

当一个接口中抽象方法过多,但是只需要使用其中的一部分的时候,就可以采用适配器模式

书写步骤

编写一个中间类XXXXXXAdapter,在类里面将所有方法空实现

然后将需要的类继承这个中间类

并将需要的方法进行重写即可

内存分配(jdk1.8后)

方法运行时使用的内存,比如main方法运行,就会进入方法栈中运行

存储对象使用的内存,比如new创建的都存储在堆内存

方法区

存储可以运行的class文件

本地方法栈

寄存器

下一篇