本文档完全参照廖雪峰的官方网站之Java教程

1.Java基础

1.数据类型

1.基本数据类型

整数类型:byte:1字节,short:2字节,int:4字节,long:8字节
浮点数类型:float:4字节,double:8字节
字符类型:char:2字节
布尔类型:boolean

2.运算符

四则运算:+,-,*,/
求余运算:%
移位运算:>>:右移,<<:左移。左移就是不断地×2,右移就是不断地÷2,还有一种无符号的右移运算,使用>>>,它的特点是不管符号位,右移后高位总是补0。
位运算:&:与运算的规则是,必须两个数同时为1,结果才为1。
|:或运算的规则是,只要任意一个为1,结果就为1。
~:非运算的规则是,0和1互换。
^异或运算的规则是,如果两个数不同,结果为1,否则为0。
布尔运算:永远只有true和false两个值

  • 比较运算符:>,>=,<,<=,==,!=
  • 与运算 &&
  • 或运算 ||
  • 非运算 !

三元运算符:b ? x : y

3.引用类型

字符串类型:例如:String i = “你好”;
数组类型:例如:int[] ns = new int[5];

2.流程控制

1.if

  1. if (条件) {
  2. // 条件满足时执行
  3. }
  1. if (条件) {
  2. // 条件满足时执行
  3. } else {
  4. // 条件不满足时执行
  5. }
  1. if (条件) {
  2. // 条件满足时执行
  3. } else if (条件) {
  4. // 条件满足时执行
  5. } else {
  6. // 条件都不满足时执行
  7. }

2.switch

  1. switch (option) {
  2. case 3:
  3. ...
  4. break;
  5. case 2:
  6. ...
  7. break;
  8. case 1:
  9. ...
  10. break;
  11. default:
  12. ...
  13. break;
  14. }

3.while

  1. while (条件表达式) {
  2. 循环语句
  3. }
  4. // 继续执行后续代码

4.do while

  1. do {
  2. 执行循环语句
  3. } while (条件表达式);

5.for

  1. for (初始条件; 循环条件; 更新计数器) {
  2. // 执行语句
  3. }

6.break

使用break语句跳出当前循环

7.continue

continue提前结束本次循环,直接继续执行下次循环

3.数组操作

1.遍历

方式一:

  1. public class Main {
  2. public static void main(String[] args) {
  3. int[] array = { 1, 2, 3, 6, 5 };
  4. for (int i=0; i<ns.length; i++) {
  5. int n = ns[i];
  6. System.out.println(n);
  7. }
  8. }
  9. }

方式二:

  1. public class Main {
  2. public static void main(String[] args) {
  3. int[] array = { 1, 2, 3, 6, 5 };
  4. for (int arr : array) {
  5. System.out.println(arr);
  6. }
  7. }
  8. }

2.排序

冒泡排序:

  1. import java.util.Arrays;
  2. public class Main {
  3. public static void main(String[] args) {
  4. int[] array = { 8, 2, 9, 3, 5, 1, 6, 0, 18, 95 };
  5. for (int i = 0; i < array.length - 1; i++) {
  6. for (int j = 0; j < array.length - i - 1; j++) {
  7. if (array[j] > array[j+1]) {
  8. // 交换array[j]和array[j+1]:
  9. int tmp = array[j];
  10. array[j] = array[j+1];
  11. array[j+1] = tmp;
  12. }
  13. }
  14. }
  15. // 排序后:
  16. System.out.println(Arrays.toString(array));
  17. }
  18. }

3.n维数组

  1. public class Main {
  2. public static void main(String[] args) {
  3. int[][] array = {
  4. { 1, 2, 3, 4 },
  5. { 5, 6, 7, 8 },
  6. { 9, 10, 11,1}
  7. };
  8. }
  9. }

2.面向对象基础

1.方法

  1. 修饰符 方法返回类型 方法名(方法参数列表) {
  2. 若干方法语句;
  3. return 方法返回值;
  4. }

方法返回值通过return语句实现,如果没有返回值,返回类型设置为void,可以省略return。

1.this变量

在方法内部,可以使用一个隐含的变量this,它始终指向当前实例。因此,通过this.field就可以访问当前实例的字段。
如果没有命名冲突,可以省略this。

2.方法参数

方法可以包含0个或任意个参数。方法参数用于接收传递给方法的变量值。调用方法时,必须严格按照参数的定义一一传递。

3.可变参数

可变参数用类型…定义,可变参数相当于数组类型。

4.参数绑定

调用方把参数传递给实例方法时,调用时传递的值会按参数位置一一绑定。

2.构造方法

创建实例的时候,我们经常需要同时初始化这个实例的字段

  1. // 有参构造
  2. public Person(String name, int age) {
  3. this.name = name;
  4. this.age = age;
  5. }
  6. // 无参构造
  7. public Person() {
  8. }

3.方法重载

方法名相同,但各自的参数不同,称为方法重载(Overload)。
注意:方法重载的返回值类型通常都是相同的。
方法重载的目的是,功能类似的方法使用同一名字,更容易记住。
String类提供了多个重载方法indexOf(),可以查找子串:

  • int indexOf(int ch):根据字符的Unicode码查找;
  • int indexOf(String str):根据字符串查找;
  • int indexOf(int ch, int fromIndex):根据字符查找,但指定起始位置;
  • int indexOf(String str, int fromIndex)根据字符串查找,但指定起始位置。

    4.继承

    Java使用extends关键字来实现继承:

    1. class Student extends Person {
    2. }

    在OOP的术语中,我们把Person称为超类(super class),父类(parent class),基类(base class),把Student称为子类(subclass),扩展类(extended class)。
    Java只有单继承。
    为了让子类可以访问父类的字段,我们需要把private改为protected。用protected修饰的字段可以被子类访问。

    1.super

    super关键字表示父类(超类)。子类引用父类的字段时,可以用super.fieldName。

    5.多态

    在继承关系中,子类如果定义了一个与父类方法签名完全相同的方法,被称为覆写(Override)。
    多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法。
    多态的特性就是,运行期才能动态决定调用的子类方法。对某个类型调用某个方法,执行的实际方法可能是某个子类的覆写方法。这种不确定性的方法调用。

    1.final

    继承可以允许子类覆写父类的方法。如果一个父类不允许子类对它的某个方法进行覆写,可以把该方法标记为final。用final修饰的方法不能被Override。

    6.抽象类

    如果一个class定义了方法,但没有具体执行代码,这个方法就是抽象方法,抽象方法用abstract修饰。
    因为无法执行抽象方法,因此这个类也必须申明为抽象类(abstract class)。
    使用abstract修饰的类就是抽象类。我们无法实例化一个抽象类。
    因为抽象类本身被设计成只能用于被继承,因此,抽象类可以强迫子类实现其定义的抽象方法,否则编译会报错。因此,抽象方法实际上相当于定义了“规范”。
    面向抽象编程的本质就是:

  • 上层代码只定义规范(例如:abstract class Person);

  • 不需要子类就可以实现业务逻辑(正常编译);
  • 具体的业务逻辑由不同的子类实现,调用者并不关心。

通过abstract定义的方法是抽象方法,它只有定义,没有实现。抽象方法定义了子类必须实现的接口规范;
定义了抽象方法的class必须被定义为抽象类,从抽象类继承的子类必须实现抽象方法;
如果不实现抽象方法,则该子类仍是一个抽象类;
面向抽象编程使得调用者只关心抽象方法的定义,不关心子类的具体实现。

7.接口

如果一个抽象类没有字段,所有方法全部都是抽象方法,就可以把该抽象类改写为接口:interface。
所谓interface,就是比抽象类还要抽象的纯抽象接口,因为它连字段都不能有。因为接口定义的所有方法默认都是public abstract的,所以这两个修饰符不需要写出来(写不写效果都一样)。
在Java中,一个类只能继承自另一个类,不能从多个类继承。但是,一个类可以实现多个interface。
抽象类和接口的对比如下:

abstract class interface
继承 只能extends一个class 可以implements多个interface
字段 可以定义实例字段 不能定义实例字段
抽象方法 可以定义抽象方法 可以定义抽象方法
非抽象方法 可以定义非抽象方法 可以定义default方法

1.接口继承

一个interface可以继承自另一个interface。interface继承自interface使用extends,它相当于扩展了接口的方法。

2.default方法

在接口中,可以定义default方法。

  1. default void run() {
  2. System.out.println("run");
  3. }

实现类可以不必覆写default方法。default方法的目的是,当我们需要给接口新增一个方法时,会涉及到修改全部子类。如果新增的是default方法,那么子类就不必全部修改,只需要在需要覆写的地方去覆写新增方法。
default方法和抽象类的普通方法是有所不同的。因为interface没有字段,default方法无法访问字段,而抽象类的普通方法可以访问实例字段。

8.静态字段和静态方法

1.静态字段

在一个class中定义的字段,我们称之为实例字段。实例字段的特点是,每个实例都有独立的字段,各个实例的同名字段互不影响。
还有一种字段,是用static修饰的字段,称为静态字段:static field。
实例字段在每个实例中都有自己的一个独立“空间”,但是静态字段只有一个共享“空间”,所有实例都会共享该字段。
推荐用类名来访问静态字段。可以把静态字段理解为描述class本身的字段(非实例字段)。

2.静态方法

有静态字段,就有静态方法。用static修饰的方法称为静态方法。
调用实例方法必须通过一个实例变量,而调用静态方法则不需要实例变量,通过类名就可以调用。静态方法类似其它编程语言的函数。

3.接口的静态字段

因为interface是一个纯抽象类,所以它不能定义实例字段。但是,interface是可以有静态字段的,并且静态字段必须为final类型。

9.包

  1. package com.test.demo

10.作用域

1.public

定义为public的class、interface可以被其他任何类访问。

2.private

定义为private的field、method无法被其他类访问。

3.protected

protected作用于继承关系。定义为protected的字段和方法可以被子类访问,以及子类的子类。

4.package

包作用域是指一个类允许访问同一个package的没有public、private修饰的class,以及没有public、protected、private修饰的字段和方法。

5.局部变量

在方法内部定义的变量称为局部变量,局部变量作用域从变量声明处开始到对应的块结束。方法参数也是局部变量。

6.final

Java还提供了一个final修饰符。final与访问权限不冲突,它有很多作用。

  • 用final修饰class可以阻止被继承。
  • 用final修饰method可以阻止被子类覆写。
  • 用final修饰field可以阻止被重新赋值。
  • 用final修饰局部变量可以阻止被重新赋值。

    11.内部类

    1.Inner Class

    如果一个类定义在另一个类的内部,这个类就是Inner Class:

    1. class Outer {
    2. class Inner {
    3. // 定义了一个Inner Class
    4. }
    5. }

    上述定义的Outer是一个普通类,而Inner是一个Inner Class,它与普通类有个最大的不同,就是Inner Class的实例不能单独存在,必须依附于一个Outer Class的实例。

    1. Outer.Inner inner = outer.new Inner(); // 实例化一个Inner

    2.Anonymous Class

    还有一种定义Inner Class的方法,它不需要在Outer Class中明确地定义这个Class,而是在方法内部,通过匿名类(Anonymous Class)来定义。示例代码如下:

    1. Runnable r = new Runnable() {
    2. // 实现必要的抽象方法...
    3. };

    3.Static Nested Class

    最后一种内部类和Inner Class类似,但是使用static修饰,称为静态内部类(Static Nested Class)。
    Java的内部类可分为Inner Class、Anonymous Class和Static Nested Class三种:

  • Inner Class和Anonymous Class本质上是相同的,都必须依附于Outer Class的实例,即隐含地持有Outer.this实例,并拥有Outer Class的private访问权限;

  • Static Nested Class是独立类,但拥有Outer Class的private访问权限。

    3.Java核心类

    1.String

    String是一个引用类型。
    字符串在String内部是通过一个char[]数组表示的。
    Java字符串的一个重要特点就是字符串不可变。这种不可变性是通过内部的private final char[]字段,以及没有任何修改char[]的方法实现的。

    1.字符串比较

    当我们想要比较两个字符串是否相同时,要特别注意,我们实际上是想比较字符串的内容是否相同。必须使用equals()方法而不能用==。
    两个字符串比较,必须总是使用equals()方法。
    要忽略大小写比较,使用equalsIgnoreCase()方法。

    1. // 是否包含子串:
    2. "dajiahao".contains("jia"); // true
    3. // 提取子串
    4. "Hello".substring(2); // "llo"
    5. "Hello".substring(2, 4); "ll"

    2.去除首尾空白字符

    使用trim()方法可以移除字符串首尾空白字符。空白字符包括空格,\t,\r,\n:

    1. " \tHello\r\n ".trim(); // "Hello"

    注意:trim()并没有改变字符串的内容,而是返回了一个新字符串。
    另一个strip()方法也可以移除字符串首尾空白字符。它和trim()不同的是,类似中文的空格字符\u3000也会被移除:

    1. "\u3000Hello\u3000".strip(); // "Hello"
    2. " Hello ".stripLeading(); // "Hello "
    3. " Hello ".stripTrailing(); // " Hello"

    3.替换子串

    要在字符串中替换子串,有两种方法。一种是根据字符或字符串替换:

    1. String s = "hello";
    2. s.replace('l', 'w'); // "hewwo",所有字符'l'被替换为'w'
    3. s.replace("ll", "~~"); // "he~~o",所有子串"ll"被替换为"~~"

    另一种是通过正则表达式替换:

    1. String s = "A,,B;C ,D";
    2. s.replaceAll("[\\,\\;\\s]+", ","); // "A,B,C,D"

    上面的代码通过正则表达式,把匹配的子串统一替换为”,”。

    4.分割字符串

    要分割字符串,使用split()方法,并且传入的也是正则表达式:

    1. String s = "A,B,C,D";
    2. String[] ss = s.split("\\,"); // {"A", "B", "C", "D"}

    5.拼接字符串

    拼接字符串使用静态方法join(),它用指定的字符串连接字符串数组:

    1. String[] arr = {"A", "B", "C"};
    2. String s = String.join("***", arr); // "A***B***C"

    6.格式化字符串

    字符串提供了formatted()方法和format()静态方法,可以传入其他参数,替换占位符,然后生成新的字符串:

    1. public class Main {
    2. public static void main(String[] args) {
    3. String s = "Hi %s, your score is %d!";
    4. System.out.println(s.formatted("Alice", 80));
    5. System.out.println(String.format("Hi %s, your score is %.2f!", "Bob", 59.5));
    6. }
    7. }

    有几个占位符,后面就传入几个参数。参数类型要和占位符一致。我们经常用这个方法来格式化信息。常用的占位符有:

  • %s:显示字符串;

  • %d:显示整数;
  • %x:显示十六进制整数;
  • %f:显示浮点数。

占位符还可以带格式,例如%.2f表示显示两位小数。如果你不确定用啥占位符,那就始终用%s,因为%s可以显示任何数据类型。

7.类型转换

要把任意基本类型或引用类型转换为字符串,可以使用静态方法valueOf()。这是一个重载方法,编译器会根据参数自动选择合适的方法:

  1. String.valueOf(123); // "123"
  2. String.valueOf(45.67); // "45.67"
  3. String.valueOf(true); // "true"
  4. String.valueOf(new Object()); // 类似java.lang.Object@636be97c

字符串转换为int类型:

  1. int n1 = Integer.parseInt("123"); // 123
  2. int n2 = Integer.parseInt("ff", 16); // 按十六进制转换,255

8.转换为char[]

String和char[]类型可以互相转换,方法是:

  1. char[] cs = "Hello".toCharArray(); // String -> char[]
  2. String s = new String(cs); // char[] -> String

2.StringBuilder

为了能高效拼接字符串,Java标准库提供了StringBuilder,它是一个可变对象,可以预分配缓冲区,这样,往StringBuilder中新增字符时,不会创建新的临时对象。
StringBuilder和StringBuffer接口完全相同,现在完全没有必要使用StringBuffer。
用指定分隔符拼接字符串数组时,使用StringJoiner或者String.join()更方便;
用StringJoiner拼接字符串时,还可以额外附加一个“开头”和“结尾”。

3.包装类型

因为包装类型非常有用,Java核心库为每种基本类型都提供了对应的包装类型:

基本类型 对应的引用类型
boolean java.lang.Boolean
byte java.lang.Byte
short java.lang.Short
int java.lang.Integer
long java.lang.Long
float java.lang.Float
double java.lang.Double
char java.lang.Character

1.Auto Boxing

因为int和Integer可以互相转换。
这种直接把int变为Integer的赋值写法,称为自动装箱(Auto Boxing),反过来,把Integer变为int的赋值写法,称为自动拆箱(Auto Unboxing)。

2.不变类

所有的包装类型都是不变类。
一旦创建了Integer对象,该对象就是不变的。
对两个Integer实例进行比较要特别注意:绝对不能用==比较,因为Integer是引用类型,必须使用equals()比较。

3.进制转换

Integer类本身还提供了大量方法,例如,最常用的静态方法parseInt()可以把字符串解析成一个整数。

4.JavaBean

JavaBean是一种符合命名规范的class,它通过getter和setter来定义属性;
属性是一种通用的叫法,并非Java语法规定;
可以利用IDE快速生成getter和setter;
使用Introspector.getBeanInfo()可以获取属性列表。

5.枚举类

Java使用enum定义枚举类型,它被编译器编译为final class Xxx extends Enum { … };
通过name()获取常量定义的字符串,注意不要使用toString();
通过ordinal()返回常量定义的顺序(无实质意义);
可以为enum编写构造方法、字段和方法
enum的构造方法要声明为private,字段强烈建议声明为final;
enum适合用在switch语句中。

6.记录类

从Java 14开始,提供新的record关键字,可以非常方便地定义Data Class:

  • 使用record定义的是不变类;
  • 可以编写Compact Constructor对参数进行验证;
  • 可以定义静态方法。

    7.BigInteger

    BigInteger用于表示任意大小的整数;
    BigInteger是不变类,并且继承自Number;
    将BigInteger转换成基本类型时可使用longValueExact()等方法保证结果准确。

    8.BigDecimal

    BigDecimal用于表示精确的小数,常用于财务计算;
    比较BigDecimal的值是否相等,必须使用compareTo()而不能使用equals()。

    9.常用工具类

    Java提供的常用工具类有:

  • Math:数学计算

  • Random:生成伪随机数
  • SecureRandom:生成安全的随机数