本文面介绍了Java语言的核心基础知识。文章首先详细讲解了Java的8种基本数据类型(byte、short、int、long、float、double、char、boolean)及其包装类型的特点、范围和使用方法;接着阐述了变量的声明规则、命名规范和常量的定义方式;然后系统梳理了Java提供的各类运算符(算术、关系、逻辑、位运算等)及其用法;还介绍了流程控制语句,包括条件语句(if、switch)、循环语句(for、while、do-while)和跳转语句(break、continue、return);此外,文章还讲解了Java中的三种注释方式,以及基本数据类型和引用数据类型在JVM中的存储位置(栈内存、堆内存、方法区/元空间等)。整体内容涵盖了Java语言基础的核心知识点,结构清晰,示例丰富。

Java语言基础梳理

一、基础语法

1. 数据类型

Java是一种强类型语言,每个变量都必须声明其数据类型。Java的数据类型分为两大类:基本数据类型和引用数据类型。

1.1 基本数据类型(Primitive Data Types)

Java有8种基本数据类型,它们是Java语言内置的,不是对象,不引用堆内存。

包装类型 (如Boolean、Integer)作为引用类型,其大小 取决于具体的JVM实现 ,没有固定的字节数。这是因为包装类型是对象,会包含对象头、实例数据等额外信息

1.1.1 整数类型(基本数据类型)
  • byte:1字节(8位),范围:-128 到 127

    1
    byte b = 100;
  • short:2字节(16位),范围:-32768 到 32767

    1
    short s = 1000;
  • int:4字节(32位),范围:-2^31 到 2^31-1(约±21亿)

    1
    int i = 100000;
  • long:8字节(64位),范围:-2^63 到 2^63-1

    1
    long l = 100000L; // 注意后面的L或l
1.1.2 整数类型(包装数据类型)
  • Byte:范围:-128 到 127

    1
    Byte b = 100;
  • Short:范围:-32768 到 32767

    1
    Short s = 1000;
  • Integer:范围:-2^31 到 2^31-1(约±21亿)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    Integer i = 100000;

    Integer a = 127;
    Integer b = 127;
    System.out.println(a == b); // 输出true,因为使用了缓存

    Integer c = 128;
    Integer d = 128;
    System.out.println(c == d); // 输出false,超出缓存范围
    /*
    这段代码会输出 false,这是由于 Java 的 Integer 缓存机制导致的。
    Integer 缓存机制详解
    1. 缓存范围
    Java 对 Integer 类型在 -128 到 127 范围内的值进行了缓存
    这个范围由 java.lang.Integer.IntegerCache 类实现
    可以通过 JVM 参数 -XX:AutoBoxCacheMax=<size> 来调整上限
    2. 缓存的工作原理
    当使用 Integer.valueOf() 方法(包括自动装箱)创建 Integer 对象时:
    如果值在缓存范围内,返回缓存中的同一个对象实例
    如果值超出缓存范围,每次都创建新的 Integer 对象
    */
  • Long:范围:-2^63 到 2^63-1

    1
    Long l = 100000L; // 注意后面的L或l
1.1.3 浮点类型(基本数据类型)
  • float:4字节(32位),单精度浮点数

    1
    float f = 3.14F; // 注意后面的F或f
  • double:8字节(64位),双精度浮点数,是默认的浮点类型

    1
    2
    double d1 = 3.14;
    double d2 = Math.PI; // 约等于3.141592653589793
1.1.4 浮点类型(包装数据类型)
  • Float:单精度浮点数

    1
    Float f = 3.14F; // 注意后面的F或f
  • Double:双精度浮点数,是默认的浮点类型

    1
    2
    Double d1 = 3.14;
    Double d2 = Math.PI; // 约等于3.141592653589793
1.1.5 字符类型(基本数据类型)
  • char:2字节(16位),用于表示单个字符,使用Unicode编码

    1
    2
    3
    char c1 = 'A';
    char c2 = '中';
    char c3 = '\u0041'; // Unicode值表示的'A'
1.1.6 字符类型(包装数据类型)
  • Character:用于表示单个字符,使用Unicode编码

    1
    2
    3
    Character c1 = 'A';
    Character c2 = '中';
    Character c3 = '\u0041'; // Unicode值表示的'A'
1.1.7 布尔类型(基本数据类型)
  • boolean:在JVM中通常占用1字节(8位),只有truefalse两个值

    1
    2
    boolean flag = true;
    boolean isEmpty = false;
1.1.8 布尔类型(包装数据类型)
  • Boolean:只有truefalse两个值

    1
    2
    Boolean flag = true;
    Boolean isEmpty = false;

1.2 引用数据类型(Reference Data Types)

引用数据类型指向对象,它们存储的是对象在堆内存中的引用地址。

  • 类(Class):如StringInteger、自定义类等

    1
    2
    String str = "Hello Java";
    Date now = new Date();
  • 接口(Interface):如ListMap

    1
    List<String> list = new ArrayList<>();
  • 数组(Array):存储相同类型元素的容器

    1
    2
    int[] numbers = {1, 2, 3, 4, 5};
    String[] names = new String[3];
  • 枚举(Enum):Java 5引入的一种特殊的类

    1
    enum Weekday { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }

1.3 上面的数据类型也可由JDK17+的类型推断来处理,由JVM自动推断该字段的数据类型

1
2
3
4
5
6
7
var a = 1;
var b = 2.0;
var c = "hello";
var d = true;
var e = 'a';
var f = new Object();
var g = new int[]{1, 2, 3};

2. 变量与常量

2.1 变量

变量是程序中存储数据的容器,其值可以在程序运行过程中改变。

  • 变量声明:需要指定数据类型和变量名

    1
    2
    int age; // 只声明不初始化
    double salary = 5000.0; // 声明并初始化
  • 变量命名规则

    • 必须以字母、下划线_或美元符号$开头
    • 后续字符可以是字母、数字、下划线或美元符号
    • 不能使用Java关键字或保留字
    • 区分大小写
    • 建议使用驼峰命名法(如:userNametotalAmount

2.2 常量

常量是在程序运行过程中其值不能改变的量,使用final关键字修饰。

1
2
final double PI = 3.1415926;
final int MAX_AGE = 120;

常量命名通常使用全大写字母,单词之间用下划线分隔。

3. 运算符

Java提供了丰富的运算符,用于执行各种运算操作。

3.1 算术运算符

用于执行基本的数学运算。

运算符 描述 示例
+ 加法 a + b
- 减法 a - b
* 乘法 a * b
/ 除法(整数相除结果为整数) a / b
% 取模(求余数) a % b
++ 自增1 a++++a
-- 自减1 a----a
1
2
3
4
5
6
int a = 10, b = 3;
int sum = a + b; // 13
int quotient = a / b; // 3(整数除法)
int remainder = a % b; // 1
int postIncrement = a++; // postIncrement=10, a=11
int preIncrement = ++a; // preIncrement=12, a=12

3.2 关系运算符

用于比较两个值之间的关系,返回布尔值truefalse

运算符 描述 示例
== 等于 a == b
!= 不等于 a != b
> 大于 a > b
< 小于 a < b
>= 大于等于 a >= b
<= 小于等于 a <= b
1
2
3
int a = 10, b = 20;
boolean isEqual = (a == b); // false
boolean isGreater = (a > b); // false

3.3 逻辑运算符

用于连接布尔表达式,进行逻辑运算。

运算符 描述 示例 短路特性
&& 逻辑与 a && b 若a为false,不计算b
` ` 逻辑或
! 逻辑非 !a -
1
2
3
4
5
boolean isAdult = true;
boolean hasId = false;
boolean canEnter = isAdult && hasId; // false
boolean hasAccess = isAdult || hasId; // true
boolean notAdult = !isAdult; // false

3.4 位运算符

用于对整数类型的二进制位进行操作。

运算符 描述 示例
& 按位与 a & b
` ` 按位或
^ 按位异或 a ^ b
~ 按位取反 ~a
<< 左移 a << b
>> 右移(符号位不变) a >> b
>>> 无符号右移(补0) a >>> b
1
2
3
4
5
6
int a = 6; // 二进制: 0110
int b = 3; // 二进制: 0011
int c = a & b; // 2 (0010)
int d = a | b; // 7 (0111)
int e = a ^ b; // 5 (0101)
int f = a << 1; // 12 (1100)

3.5 赋值运算符

用于给变量赋值,也可以与其他运算符组合。

运算符 描述 示例 等价于
= 简单赋值 a = b -
+= 加后赋值 a += b a = a + b
-= 减后赋值 a -= b a = a - b
*= 乘后赋值 a *= b a = a * b
/= 除后赋值 a /= b a = a / b
%= 取模后赋值 a %= b a = a % b
&= 按位与后赋值 a &= b a = a & b
` =` 按位或后赋值 `a
^= 按位异或后赋值 a ^= b a = a ^ b
<<= 左移后赋值 a <<= b a = a << b
>>= 右移后赋值 a >>= b a = a >> b
>>>= 无符号右移后赋值 a >>>= b a = a >>> b
1
2
3
int a = 10;
a += 5; // 15,等价于a = a + 5
a *= 2; // 30,等价于a = a * 2

3.6 条件运算符(三元运算符)

Java中唯一的三目运算符,用于简化if-else语句。

语法:条件表达式 ? 表达式1 : 表达式2

  • 如果条件表达式为true,结果为表达式1
  • 如果条件表达式为false,结果为表达式2
1
2
3
int a = 10, b = 20;
int max = (a > b) ? a : b; // 20
String result = (score >= 60) ? "及格" : "不及格";

3.7 instanceof运算符

用于检查对象是否为指定类或其子类的实例。

1
2
3
4
String str = "Hello";
boolean isString = str instanceof String; // true
ArrayList<String> list = new ArrayList<>();
boolean isList = list instanceof List; // true(ArrayList实现了List接口)

3.8 文本字符串

1
2
3
4
5
6
7
8
9
String str1 = "JDK 21 中的 switch 表达式和语句引入了一些新特性,主要包括:\n" +
"1. 模式匹配 switch (Pattern Matching for switch)\n" +
"JDK 21 引入了模式匹配 switch,允许在 switch 表达式中使用类型模式和守卫条件:";

String str2 = """
JDK 21 中的 switch 表达式和语句引入了一些新特性,主要包括:
1. 模式匹配 switch (Pattern Matching for switch)
JDK 21 引入了模式匹配 switch,允许在 switch 表达式中使用类型模式和守卫条件:
""";

4. 流程控制语句

流程控制语句用于控制程序的执行顺序,包括条件语句、循环语句和跳转语句。

4.1 条件语句

  • if语句

    1
    2
    3
    if (条件表达式) {
    // 条件为true时执行的代码
    }
  • if-else语句

    1
    2
    3
    4
    5
    if (条件表达式) {
    // 条件为true时执行的代码
    } else {
    // 条件为false时执行的代码
    }
  • if-else if-else语句

    1
    2
    3
    4
    5
    6
    7
    if (条件表达式1) {
    // 条件1为true时执行的代码
    } else if (条件表达式2) {
    // 条件2为true时执行的代码
    } else {
    // 所有条件都为false时执行的代码
    }
  • switch语句(Java 7+支持String类型,Java 12+支持箭头表达式)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    switch (表达式) {
    case1:
    // 表达式等于值1时执行的代码
    break; // 可选,用于跳出switch语句
    case2:
    // 表达式等于值2时执行的代码
    break;
    // 更多case分支...
    default:
    // 表达式不匹配任何case值时执行的代码
    }

    // Java 12+的箭头表达式语法
    switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
    case TUESDAY -> System.out.println(7);
    case THURSDAY, SATURDAY -> System.out.println(8);
    case WEDNESDAY -> System.out.println(9);
    default -> System.out.println(0);
    }


    // JDK 21 引入了模式匹配 switch,允许在 switch 表达式中使用类型模式和守卫条件
    static String format(Object obj) {
    return switch (obj) {
    case Integer i -> String.format("int %d", i);
    case Long l -> String.format("long %d", l);
    case Double d -> String.format("double %g", d);
    case String s -> String.format("String %s", s);
    default -> String.format("Object %s", obj.toString());
    };
    }


    // 可以在模式后添加 when 子句来增加额外的条件
    static String checkNumber(Number number) {
    return switch (number) {
    case Integer i when i > 0 -> "positive integer";
    case Integer i when i < 0 -> "negative integer";
    case Integer i -> "zero";
    case Double d when d > 0.0 -> "positive double";
    case Double d when d < 0.0 -> "negative double";
    default -> "other number";
    };
    }

    //增强的 null 处理
    static void test(Object obj) {
    switch (obj) {
    case null -> System.out.println("It's a null");
    case String s -> System.out.println("It's a string: " + s);
    default -> System.out.println("It's something else");
    }
    }

    //多个常量的 case 标签
    static String processDay(int day) {
    return switch (day) {
    case 1, 2, 3, 4, 5 -> "Weekday";
    case 6, 7 -> "Weekend";
    default -> "Invalid day";
    };
    }

    // 支持 Record 模式的解构
    record Point(int x, int y) {}
    static String processPoint(Object obj) {
    return switch (obj) {
    case Point(int x, int y) when x == y -> "Diagonal point";
    case Point(int x, int y) -> "Regular point (" + x + ", " + y + ")";
    default -> "Not a point";
    };
    }

4.2 循环语句

  • for循环

    1
    2
    3
    4
    5
    6
    7
    8
    for (初始化表达式; 条件表达式; 步进表达式) {
    // 循环体,当条件表达式为true时执行
    }

    // 增强for循环(for-each,用于遍历数组和集合)
    for (元素类型 变量名 : 数组或集合) {
    // 循环体,变量名代表当前元素
    }

    示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // 传统for循环
    for (int i = 0; i < 10; i++) {
    System.out.println(i);
    }

    // 增强for循环遍历数组
    int[] numbers = {1, 2, 3, 4, 5};
    for (int num : numbers) {
    System.out.println(num);
    }
  • while循环

    1
    2
    3
    while (条件表达式) {
    // 循环体,当条件表达式为true时执行
    }

    示例:

    1
    2
    3
    4
    5
    int i = 0;
    while (i < 10) {
    System.out.println(i);
    i++;
    }
  • do-while循环(至少执行一次循环体)

    1
    2
    3
    do {
    // 循环体
    } while (条件表达式);

    示例:

    1
    2
    3
    4
    5
    int i = 0;
    do {
    System.out.println(i);
    i++;
    } while (i < 10);

4.3 跳转语句

用于在循环或switch语句中改变程序的执行流程。

  • break语句:用于跳出循环或switch语句

    1
    2
    3
    4
    5
    6
    for (int i = 0; i < 10; i++) {
    if (i == 5) {
    break; // 跳出循环
    }
    System.out.println(i); // 只输出0-4
    }
  • continue语句:用于跳过当前循环的剩余部分,进入下一次循环

    1
    2
    3
    4
    5
    6
    for (int i = 0; i < 10; i++) {
    if (i % 2 == 0) {
    continue; // 跳过偶数
    }
    System.out.println(i); // 只输出奇数1,3,5,7,9
    }
  • return语句:用于从方法中返回结果,或直接结束方法的执行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public int add(int a, int b) {
    return a + b; // 返回计算结果
    }

    public void checkAge(int age) {
    if (age < 0) {
    return; // 直接结束方法
    }
    // 后续代码
    }

5. 注释

注释是程序中用于说明代码的文字,不会被编译器执行。Java支持三种注释方式:

  • 单行注释:使用//开头

    1
    int age = 18; // 定义一个整型变量表示年龄
  • 多行注释:使用/*开始,*/结束

    1
    2
    3
    4
    /*
    * 这是一个多行注释
    * 可以跨越多行
    */
  • 文档注释:使用/**开始,*/结束,用于生成API文档

    1
    2
    3
    4
    5
    6
    7
    8
    9
    /**
    * 计算两个数的和
    * @param a 第一个整数
    * @param b 第二个整数
    * @return 两个数的和
    */
    public int add(int a, int b) {
    return a + b;
    }

6. Java中基本数据类型在JVM的存储位置

Java中基本数据类型的存储位置根据其作用域和声明位置有所不同,主要分为以下几个区域:

1. 栈内存 (Stack Memory)

局部变量存储
  • 方法中的局部基本数据类型变量存储在栈内存中
  • 包括方法参数和在方法内部声明的基本类型变量
1
2
3
4
5
public void method() {
int a = 10; // 存储在栈内存中
double b = 3.14; // 存储在栈内存中
boolean flag = true; // 存储在栈内存中
}
特点
  • 访问速度快
  • 生命周期与方法执行周期一致
  • 方法执行完毕后自动释放

2. 堆内存 (Heap Memory)

对象实例中的基本类型字段
  • 作为类的成员变量(非静态)存储在堆内存中,与对象实例一起
  • 作为数组元素的基本类型数据存储在堆内存中
1
2
3
4
5
6
7
8
public class Example {
private int instanceVar = 100; // 作为对象的一部分存储在堆中

public void method() {
int[] array = new int[10]; // 数组对象在堆中,数组元素也在堆中
array[0] = 5; // 数组元素存储在堆中
}
}

3. 方法区/元空间 (Metaspace)

静态变量
  • 类的静态基本数据类型成员变量存储在方法区(JDK 8之前)或元空间(JDK 8及以后)
1
2
3
4
public class Example {
private static int staticVar = 200; // 存储在方法区/元空间
private static final double PI = 3.14159; // 存储在方法区/元空间
}

4. 本地方法栈 (Native Method Stack)

  • 用于存储本地方法(Native Method)调用时的基本数据类型
  • 不常见,主要用于JNI调用
内存分配示例
1
2
3
4
5
6
7
8
9
10
11
12
13
public class MemoryAllocation {
private static int staticVar = 1; // 方法区/元空间
private int instanceVar = 2; // 堆内存(对象实例中)

public void method() {
int localVar = 3; // 栈内存
int[] array = new int[5]; // 数组对象在堆中,引用在栈中
array[0] = 4; // 数组元素在堆中

// 方法执行完毕后,localVar自动释放
// 但堆中的array对象需要垃圾回收器处理
}
}

总结

存储位置 数据类型 说明
栈内存 局部基本变量、方法参数 自动分配和释放,速度快
堆内存 对象中的基本类型字段、数组元素 需要垃圾回收,生命周期较长
方法区/元空间 静态基本变量、常量 类级别的数据,程序运行期间存在
本地方法栈 Native方法中的基本类型 JNI调用使用

对于代码示例中的 Integer i = 129;Integer i1 = 129;,虽然 Integer 是包装类(对象类型),但变量 ii1 的引用本身作为局部变量存储在栈中,而实际的 Integer 对象存储在堆中。

7. Java中的引用数据类型在JVM中的存储位置

Java中的引用数据类型在JVM中的存储位置根据其类型和作用域有所不同,主要分布在以下几个内存区域:

1. 堆内存 (Heap Memory) - 主要存储区域

对象实例
  • 所有通过 new 关键字创建的对象实例都存储在堆内存中
  • 这是引用数据类型最主要的存储位置
1
2
3
4
5
6
7
8
public class Example {
public void method() {
String str = new String("hello"); // String对象存储在堆中
Integer i = new Integer(129); // Integer对象存储在堆中
int[] array = new int[10]; // 数组对象存储在堆中
ArrayList<String> list = new ArrayList<>(); // ArrayList对象存储在堆中
}
}
示例分析(你的代码)
1
2
Integer i = 129;   // 等价于 Integer.valueOf(129) - 对象存储在堆中
Integer i1 = 129; // 等价于 Integer.valueOf(129) - 另一个对象存储在堆中

2. 栈内存 (Stack Memory)

局部引用变量
  • 引用变量本身(即指向对象的引用)存储在栈内存中
  • 实际对象仍然存储在堆内存中
1
2
3
4
5
6
7
8
9
public class Example {
public void method() {
String str; // 引用变量存储在栈中
str = new String("hello"); // "hello"对象存储在堆中,str引用在栈中

List<String> list; // 引用变量存储在栈中
list = new ArrayList<>(); // ArrayList对象存储在堆中,list引用在栈中
}
}

3. 方法区/元空间 (Metaspace)

类的元数据
  • 类的定义信息、静态变量、常量池等存储在方法区(JDK 8前)或元空间(JDK 8及以后)
  • 字符串常量池也位于堆中(JDK 7及以后)或方法区(JDK 6及以前)
1
2
3
4
5
6
7
8
9
10
public class Example {
private static String staticStr = "static string"; // 静态引用在方法区,对象在堆中
private static final String CONSTANT = "constant"; // 常量引用在方法区,对象在堆中或字符串常量池

public void method() {
String str1 = "hello"; // 字符串字面量,存储在字符串常量池中(堆中)
String str2 = "hello"; // 指向同一个字符串常量池中的对象
System.out.println(str1 == str2); // true
}
}

4. 本地方法栈 (Native Method Stack)

  • 存储本地方法(Native Method)调用时的引用数据
  • 主要用于JNI调用
内存分配详细示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MemoryAllocation {
// 静态引用变量存储在方法区,对象存储在堆中
private static List<String> staticList = new ArrayList<>();

// 实例引用变量存储在堆中(作为对象的一部分)
private List<String> instanceList = new ArrayList<>();

public void method() {
// 局部引用变量存储在栈中
List<String> localList;

// 对象实例存储在堆中,引用存储在栈中
localList = new ArrayList<>();

// 字符串对象存储在堆中的字符串常量池
String str = "hello world";

// 数组对象存储在堆中,引用存储在栈中
int[] array = {1, 2, 3, 4, 5};
}
}
内存布局图示
1
2
3
4
5
6
7
8
9
10
11
JVM内存结构:
┌─────────────┐
│ 栈内存 │ ← 局部引用变量
│ (Stack) │
├─────────────┤
│ 堆内存 │ ← 对象实例、数组、字符串常量池
│ (Heap) │
├─────────────┤
│ 方法区/元空间│ ← 类信息、静态变量、常量
│ (Metaspace) │
└─────────────┘

总结

存储位置 数据类型 说明
堆内存 对象实例、数组 主要存储区域,需要垃圾回收
栈内存 局部引用变量 存储指向堆中对象的引用
方法区/元空间 静态引用变量、类信息 存储类级别的引用和元数据
本地方法栈 Native方法中的引用 JNI调用使用

对于代码示例:

1
2
Integer i = 129;
Integer i1 = 129;
  • ii1 这两个引用变量存储在栈内存中
  • 两个 Integer 对象实例存储在堆内存中
  • 由于129超出缓存范围,所以创建了两个不同的对象实例

二、面向对象编程

  • 四大特性
    • 封装:通过访问控制符(private, protected, public, 默认)隐藏实现细节,提供公共方法访问。
    • 继承extends 关键字,实现代码复用。单继承,但可多层继承。
    • 多态
      • 编译时多态:方法重载(Overload)
      • 运行时多态:方法重写(Override),基于继承和接口实现,通过父类/接口引用指向子类对象。
    • 抽象abstract 类和接口(interface)用于定义规范。
  • 类与对象:类的定义、对象的创建(new)、构造方法、this 关键字。
  • 方法:方法的定义、参数传递(值传递)、递归。

2.1 封装

封装(Encapsulation)是面向对象编程的核心概念之一,它指的是将数据(属性)和操作数据的方法(行为)组合在一个单元(类)中,并通过访问控制符来控制对这些数据和方法的访问。

封装的实现方式

Java 中通过访问控制符来实现封装:

1. 访问控制符类型
  • **private**:仅在本类中可访问
  • default(包私有):同一包内可访问
  • **protected**:同一包内或子类可访问
  • **public**:任何地方都可访问
2. 封装的实践示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class BankAccount {
// 私有属性,外部无法直接访问
private double balance;
private String accountNumber;

// 构造函数
public BankAccount(String accountNumber, double initialBalance) {
this.accountNumber = accountNumber;
this.balance = initialBalance;
}

// 公共方法提供受控访问
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}

public boolean withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
return true;
}
return false;
}

// 只读访问
public double getBalance() {
return balance;
}

// 受控的属性修改
public void setAccountNumber(String accountNumber) {
// 可以添加验证逻辑
if (accountNumber != null && !accountNumber.isEmpty()) {
this.accountNumber = accountNumber;
}
}
}

封装的优势

  1. 数据安全:防止外部代码直接修改对象内部状态
  2. 维护性:内部实现可以改变而不影响外部代码
  3. 可控制访问:可以添加验证、日志等逻辑
  4. 代码复用:隐藏复杂实现,提供简洁接口

封装通过合理使用访问控制符,实现了数据隐藏和接口暴露的平衡,是构建健壮、可维护代码的重要手段。

访问控制符 同一类 同一包 不同包的子类 不同包的非子类
private
默认(包访问)
protected
public

2.2 继承

继承(Inheritance)是面向对象编程的基本特性之一,它允许一个类(子类)获得另一个类(父类)的属性和方法,实现代码复用和层次化设计。

继承的基本语法

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 父类(基类)
class Parent {
protected String name;
private int age;

public Parent(String name, int age) {
this.name = name;
this.age = age;
}

public void introduce() {
System.out.println("My name is " + name);
}

protected void displayAge() {
System.out.println("Age: " + age);
}
}

// 子类(派生类)
class Child extends Parent {
private String school;

public Child(String name, int age, String school) {
// 调用父类构造函数
super(name, age);
this.school = school;
}

// 方法重写
@Override
public void introduce() {
super.introduce();
System.out.println("I study at " + school);
}

public void showDetails() {
// 可以访问父类的 protected 成员
displayAge();
System.out.println("School: " + school);
}
}

Java 继承的特点

1. 单继承

Java 只支持单继承,一个类只能直接继承一个父类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Animal {
protected String species;

public void eat() {
System.out.println("Animal is eating");
}
}

class Dog extends Animal {
private String breed;

public void bark() {
System.out.println("Dog is barking");
}
}

// 错误:Java 不支持多继承
// class MultiPet extends Animal, AnotherClass { } // 编译错误
2. 多层继承

虽然 Java 不支持多继承,但支持多层继承:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Vehicle {
protected String brand;

public void start() {
System.out.println("Vehicle started");
}
}

class Car extends Vehicle {
protected int doors;

public void openTrunk() {
System.out.println("Trunk opened");
}
}

class SportsCar extends Car {
private int maxSpeed;

public void accelerate() {
System.out.println("Sports car accelerating");
}

// 可以使用继承自 Vehicle 的方法
public void showBrand() {
System.out.println("Brand: " + brand);
}
}

继承中的关键概念

1. 方法重写(Override)

子类可以重写父类的方法以提供特定实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Shape {
public double calculateArea() {
return 0;
}

public void draw() {
System.out.println("Drawing a shape");
}
}

class Circle extends Shape {
private double radius;

public Circle(double radius) {
this.radius = radius;
}

// 重写父类方法
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}

@Override
public void draw() {
System.out.println("Drawing a circle");
super.draw(); // 调用父类方法
}
}
2. super 关键字

用于访问父类的成员:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Employee {
protected String name;
protected double salary;

public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}

public void displayInfo() {
System.out.println("Name: " + name + ", Salary: " + salary);
}
}

class Manager extends Employee {
private String department;

public Manager(String name, double salary, String department) {
// 调用父类构造函数
super(name, salary);
this.department = department;
}

@Override
public void displayInfo() {
// 调用父类方法
super.displayInfo();
System.out.println("Department: " + department);
}
}

继承的访问控制

访问修饰符 同一类 同一包 子类 不同包
private
default
protected
public

继承的优缺点

优点:

  1. 代码复用:子类可以复用父类的代码
  2. 扩展性:可以在父类基础上添加新功能
  3. 多态性基础:为多态提供支持
  4. 层次结构:建立清晰的类层次关系

缺点:

  1. 紧耦合:子类与父类紧密耦合
  2. 复杂性:深层继承可能导致复杂性增加
  3. 脆弱性:父类的修改可能影响所有子类

继承是 Java 面向对象编程的重要机制,通过 extends 关键字实现单继承但支持多层继承,为代码复用和系统设计提供了强大支持。

补充

implements 不属于继承,它是实现关系。虽然两者都涉及代码复用和类型扩展,但它们在Java中有本质区别:

1. implements(实现)- 接口实现

特点:

  • 类实现接口必须使用 implements 关键字
  • 实现类必须实现接口中所有抽象方法(除非是抽象类)
  • 一个类可以实现多个接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 接口定义
interface Flyable {
void fly();
}

interface Swimmable {
void swim();
}

// 类实现多个接口
class Duck implements Flyable, Swimmable {
@Override
public void fly() {
System.out.println("Duck is flying");
}

@Override
public void swim() {
System.out.println("Duck is swimming");
}
}

2. extends(继承)- 类继承

特点:

  • 子类继承父类使用 extends 关键字
  • 子类继承父类的属性和方法
  • Java中一个类只能继承一个父类(单继承)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 父类
class Animal {
protected String name;

public void eat() {
System.out.println("Animal is eating");
}
}

// 子类继承父类
class Dog extends Animal {
public void bark() {
System.out.println("Dog is barking");
}
}

3. 主要区别对比

特性 extends(继承) implements(实现)
关键字 extends implements
关系类型 继承关系(is-a) 实现关系(can-do)
数量限制 一个类只能继承一个父类 一个类可以实现多个接口
方法实现 可以有具体方法实现 Java 8前只能有抽象方法
访问修饰符 继承所有非private成员 实现所有接口方法
构造器 子类构造器调用父类构造器 接口没有构造器

4. 组合使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 接口
interface Drawable {
void draw();
}

// 父类
class Shape {
protected String color;

public Shape(String color) {
this.color = color;
}

public void display() {
System.out.println("Shape color: " + color);
}
}

// 子类既继承又实现
class Circle extends Shape implements Drawable {
private double radius;

public Circle(String color, double radius) {
super(color); // 调用父类构造器
this.radius = radius;
}

@Override
public void draw() {
System.out.println("Drawing a circle with radius: " + radius);
}
}

5. 语法顺序

当同时使用继承和实现时,必须遵循特定顺序:

1
2
3
class MyClass extends ParentClass implements Interface1, Interface2, Interface3 {
// 类实现
}

总结

  • implements实现接口,不是继承
  • 继承(extends)是 “is-a” 关系,实现(implements)是 “can-do” 关系
  • 两者可以同时存在于一个类中,但 extends 必须在 implements 之前

2.3 多态

Java 多态详解

多态(Polymorphism)是面向对象编程的核心特性之一,指的是同一个接口可以有多种不同的实现方式。Java中的多态分为编译时多态和运行时多态两种。

1. 编译时多态(Compile-time Polymorphism)
定义

编译时多态也称为静态多态,是在编译阶段确定调用哪个方法的多态形式。

方法重载(Method Overloading)
  • 在同一个类中,方法名相同但参数列表不同(类型、个数、顺序)
  • 返回值类型可以不同,但不能仅凭返回值类型区分重载方法
  • 编译器根据调用时传入的参数类型和个数来决定调用哪个方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class Calculator {
// 重载方法1:两个整数相加
public int add(int a, int b) {
return a + b;
}

// 重载方法2:三个整数相加
public int add(int a, int b, int c) {
return a + b + c;
}

// 重载方法3:两个双精度数相加
public double add(double a, double b) {
return a + b;
}

// 重载方法4:整数和字符串连接
public String add(int a, String b) {
return a + b;
}

// 重载方法5:字符串和整数连接(参数顺序不同)
public String add(String a, int b) {
return a + b;
}
}

// 使用示例
public class Main {
public static void main(String[] args) {
Calculator calc = new Calculator();

System.out.println(calc.add(2, 3)); // 调用 add(int, int)
System.out.println(calc.add(2, 3, 4)); // 调用 add(int, int, int)
System.out.println(calc.add(2.5, 3.7)); // 调用 add(double, double)
System.out.println(calc.add(5, "hello")); // 调用 add(int, String)
System.out.println(calc.add("hello", 5)); // 调用 add(String, int)
}
}
2. 运行时多态(Runtime Polymorphism)
定义

运行时多态也称为动态多态,是在程序运行时根据对象的实际类型来决定调用哪个方法的多态形式。

方法重写(Method Overriding)
  • 子类重新定义父类中已有的方法
  • 方法签名(方法名和参数列表)必须完全相同
  • 返回值类型可以是原返回值类型的子类型(协变返回类型)
  • 访问权限不能更低,但可以更高
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// 父类
class Animal {
public void makeSound() {
System.out.println("Animal makes a sound");
}

public void move() {
System.out.println("Animal moves");
}
}

// 子类1
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Dog barks: Woof! Woof!");
}

@Override
public void move() {
System.out.println("Dog runs on four legs");
}

public void wagTail() {
System.out.println("Dog wags tail");
}
}

// 子类2
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Cat meows: Meow! Meow!");
}

@Override
public void move() {
System.out.println("Cat walks gracefully");
}
}

// 子类3
class Bird extends Animal {
@Override
public void makeSound() {
System.out.println("Bird chirps: Tweet! Tweet!");
}

@Override
public void move() {
System.out.println("Bird flies in the sky");
}
}
运行时多态的关键要素
  1. 继承关系
1
// Dog、Cat、Bird 都继承自 Animal
  1. 方法重写
1
// 各个子类都重写了 makeSound() 和 move() 方法
  1. 父类引用指向子类对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class PolymorphismDemo {
public static void main(String[] args) {
// 父类引用指向不同的子类对象
Animal animal1 = new Dog(); // 向上转型
Animal animal2 = new Cat(); // 向上转型
Animal animal3 = new Bird(); // 向上转型

// 运行时根据实际对象类型调用相应方法
animal1.makeSound(); // 输出: Dog barks: Woof! Woof!
animal2.makeSound(); // 输出: Cat meows: Meow! Meow!
animal3.makeSound(); // 输出: Bird chirps: Tweet! Tweet!

animal1.move(); // 输出: Dog runs on four legs
animal2.move(); // 输出: Cat walks gracefully
animal3.move(); // 输出: Bird flies in the sky
}
}
3. 接口实现的多态

接口实现也是运行时多态的重要体现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// 接口定义
interface Drawable {
void draw();
void resize();
}

interface Movable {
void move(int x, int y);
}

// 实现类1
class Circle implements Drawable {
@Override
public void draw() {
System.out.println("Drawing a circle");
}

@Override
public void resize() {
System.out.println("Resizing circle");
}
}

// 实现类2
class Rectangle implements Drawable, Movable {
@Override
public void draw() {
System.out.println("Drawing a rectangle");
}

@Override
public void resize() {
System.out.println("Resizing rectangle");
}

@Override
public void move(int x, int y) {
System.out.println("Moving rectangle to (" + x + ", " + y + ")");
}
}

// 实现类3
class Triangle implements Drawable {
@Override
public void draw() {
System.out.println("Drawing a triangle");
}

@Override
public void resize() {
System.out.println("Resizing triangle");
}
}

// 多态使用示例
public class InterfacePolymorphism {
public static void main(String[] args) {
// 接口引用指向不同实现类对象
Drawable[] shapes = {
new Circle(),
new Rectangle(),
new Triangle()
};

// 运行时多态:根据实际对象类型调用相应方法
for (Drawable shape : shapes) {
shape.draw(); // 每个对象调用自己的 draw() 方法
shape.resize(); // 每个对象调用自己的 resize() 方法
}

// 处理具有多个接口的对象
Movable movable = new Rectangle();
movable.move(10, 20); // 调用 Rectangle 的 move 方法
}
}
4. 多态的内存机制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class PolymorphismMemory {
public static void main(String[] args) {
Animal animal = new Dog(); // 关键点:父类引用,子类对象

// 编译时:检查 Animal 类是否有 makeSound() 方法
// 运行时:查找实际对象(Dog)的 makeSound() 方法并调用
animal.makeSound(); // 调用 Dog 类的 makeSound() 方法

// 无法直接调用子类特有的方法
// animal.wagTail(); // 编译错误!Animal 类没有 wagTail() 方法

// 需要向下转型才能调用子类特有方法
if (animal instanceof Dog) {
Dog dog = (Dog) animal; // 向下转型
dog.wagTail(); // 现在可以调用 Dog 特有方法
}
}
}
5. 多态的优势
1. 代码可扩展性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 添加新的动物类型无需修改现有代码
class Lion extends Animal {
@Override
public void makeSound() {
System.out.println("Lion roars: Roar!");
}

@Override
public void move() {
System.out.println("Lion prowls");
}
}

// 原有代码无需修改即可使用新类型
public class Zoo {
public static void main(String[] args) {
Animal[] animals = {
new Dog(),
new Cat(),
new Bird(),
new Lion() // 新增类型
};

// 统一处理所有动物
for (Animal animal : animals) {
animal.makeSound(); // 自动调用各自实现
}
}
}
2. 降低耦合度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 服务类使用接口编程
class DrawingService {
public void drawShape(Drawable shape) {
shape.draw(); // 不关心具体实现类
shape.resize(); // 只要实现 Drawable 接口即可
}
}

// 使用示例
public class GraphicsApp {
public static void main(String[] args) {
DrawingService service = new DrawingService();

// 可以传入任何实现 Drawable 接口的对象
service.drawShape(new Circle());
service.drawShape(new Rectangle());
service.drawShape(new Triangle());
}
}

总结

特性 编译时多态 运行时多态
实现方式 方法重载 方法重写
决定时机 编译时 运行时
基础 参数列表不同 继承/接口实现
灵活性 较低 较高
性能 较高(编译时确定) 略低(需要动态绑定)

多态是面向对象编程的重要特性,它提高了代码的可扩展性、可维护性和复用性,是设计模式和框架开发的基础。

2.4 抽象

抽象是面向对象编程的核心概念之一,它允许我们定义规范而不提供具体实现,让子类或实现类来完成具体细节。

1. 抽象类(Abstract Class)

基本概念

抽象类是使用 abstract 关键字修饰的类,不能被直接实例化,主要用于被其他类继承。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 抽象类定义
public abstract class Animal {
// 普通成员变量
protected String name;
protected int age;

// 构造方法(可以有)
public Animal(String name, int age) {
this.name = name;
this.age = age;
}

// 普通方法(可以有具体实现)
public void setName(String name) {
this.name = name;
}

public String getName() {
return name;
}

// 抽象方法(必须由子类实现)
public abstract void makeSound();

public abstract void move();

// 抽象类中可以有非抽象方法
public void displayInfo() {
System.out.println("Name: " + name + ", Age: " + age);
}
}
抽象类的特点
  • 使用 abstract 关键字修饰
  • 不能被直接实例化
  • 可以包含抽象方法和非抽象方法
  • 可以包含成员变量、构造方法、静态方法等
  • 子类继承抽象类时,必须实现所有抽象方法(除非子类也是抽象类)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// 具体子类必须实现所有抽象方法
public class Dog extends Animal {
public Dog(String name, int age) {
super(name, age);
}

@Override
public void makeSound() {
System.out.println(name + " says: Woof! Woof!");
}

@Override
public void move() {
System.out.println(name + " runs on four legs");
}

// 可以添加自己的特有方法
public void wagTail() {
System.out.println(name + " wags tail happily");
}
}

// 另一个具体子类
public class Cat extends Animal {
public Cat(String name, int age) {
super(name, age);
}

@Override
public void makeSound() {
System.out.println(name + " says: Meow! Meow!");
}

@Override
public void move() {
System.out.println(name + " walks gracefully");
}

public void climb() {
System.out.println(name + " climbs up the tree");
}
}

// 使用示例
public class AbstractClassDemo {
public static void main(String[] args) {
// Animal animal = new Animal(); // 编译错误!不能实例化抽象类

// 通过父类引用指向子类对象(多态)
Animal dog = new Dog("Buddy", 3);
Animal cat = new Cat("Whiskers", 2);

dog.makeSound(); // 输出: Buddy says: Woof! Woof!
dog.move(); // 输出: Buddy runs on four legs
dog.displayInfo(); // 输出: Name: Buddy, Age: 3

cat.makeSound(); // 输出: Whiskers says: Meow! Meow!
cat.move(); // 输出: Whiskers walks gracefully
cat.displayInfo(); // 输出: Name: Whiskers, Age: 2

// 调用子类特有方法需要向下转型
if (dog instanceof Dog) {
((Dog) dog).wagTail(); // 输出: Buddy wags tail happily
}
}
}

2. 接口(Interface)

基本概念

接口是使用 interface 关键字定义的完全抽象的类型,用于定义规范和契约。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 基本接口定义
public interface Drawable {
// 接口中默认是 public static final 的常量
int MAX_SIZE = 100;

// 接口中默认是 public abstract 的方法
void draw();
void resize();

// Java 8 及以后可以有默认方法实现
default void display() {
System.out.println("Displaying shape with max size: " + MAX_SIZE);
}

// Java 8 及以后可以有静态方法
static void info() {
System.out.println("This is a drawable interface");
}

// Java 9 及以后可以有私有方法
private void helper() {
System.out.println("Helper method for internal use");
}

// Java 9 及以后可以有私有静态方法
private static void staticHelper() {
System.out.println("Static helper method");
}
}
接口的特点
  • 使用 interface 关键字定义
  • 所有方法默认是 public abstract(Java 8前)
  • 所有变量默认是 public static final
  • 类通过 implements 关键字实现接口
  • 一个类可以实现多个接口
  • 接口可以继承其他接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// 实现接口的类
public class Circle implements Drawable {
private double radius;

public Circle(double radius) {
this.radius = radius;
}

@Override
public void draw() {
System.out.println("Drawing a circle with radius: " + radius);
}

@Override
public void resize() {
radius *= 1.5;
System.out.println("Circle resized. New radius: " + radius);
}

// 可以重写默认方法
@Override
public void display() {
System.out.println("Displaying circle with radius: " + radius);
}
}

public class Rectangle implements Drawable {
private double width, height;

public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}

@Override
public void draw() {
System.out.println("Drawing a rectangle " + width + "x" + height);
}

@Override
public void resize() {
width *= 1.2;
height *= 1.2;
System.out.println("Rectangle resized to " + width + "x" + height);
}
}
多接口实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// 多个接口
interface Movable {
void move(int x, int y);
}

interface Resizable {
void resize(double factor);
}

interface Colorable {
void setColor(String color);
String getColor();
}

// 类可以实现多个接口
public class Shape implements Drawable, Movable, Resizable, Colorable {
private double x, y;
private double size;
private String color;

public Shape(double x, double y, double size, String color) {
this.x = x;
this.y = y;
this.size = size;
this.color = color;
}

@Override
public void draw() {
System.out.println("Drawing shape at (" + x + "," + y + ") with size " + size);
}

@Override
public void resize() {
size *= 1.1;
System.out.println("Shape resized to " + size);
}

@Override
public void move(int x, int y) {
this.x = x;
this.y = y;
System.out.println("Shape moved to (" + x + "," + y + ")");
}

@Override
public void resize(double factor) {
size *= factor;
System.out.println("Shape resized by factor " + factor + " to " + size);
}

@Override
public void setColor(String color) {
this.color = color;
}

@Override
public String getColor() {
return color;
}
}

3. 接口的继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 接口可以继承其他接口
interface Shape extends Drawable, Movable {
double getArea();
double getPerimeter();
}

// 标记接口(无方法)
interface Serializable {
// 空接口,用于标记
}

// 函数式接口(只有一个抽象方法)
@FunctionalInterface
interface Calculator {
int calculate(int a, int b);

// 可以有默认方法和静态方法
default void printResult(int result) {
System.out.println("Result: " + result);
}

static boolean isPositive(int value) {
return value > 0;
}
}

4. 抽象类 vs 接口对比

特性 抽象类 接口
关键字 abstract class interface
实现方式 extends implements
继承数量 一个类只能继承一个抽象类 一个类可以实现多个接口
方法实现 可以有具体方法实现 Java 8前全部抽象,之后可有默认实现
成员变量 可以有各种访问修饰符的变量 只能有 public static final 常量
构造方法 可以有构造方法 不能有构造方法
访问修饰符 可以有各种访问修饰符 方法默认 public,变量默认 public static final
设计目的 代码复用,定义共同行为 定义规范和契约

5. 使用场景

抽象类适用场景
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 当多个类有共同的属性和行为时使用抽象类
public abstract class Vehicle {
protected String brand;
protected String model;
protected int year;

public Vehicle(String brand, String model, int year) {
this.brand = brand;
this.model = model;
this.year = year;
}

// 共同的行为
public void start() {
System.out.println(brand + " " + model + " is starting");
}

public void stop() {
System.out.println(brand + " " + model + " is stopping");
}

// 不同的实现
public abstract void accelerate();
public abstract void brake();
}

public class Car extends Vehicle {
public Car(String brand, String model, int year) {
super(brand, model, year);
}

@Override
public void accelerate() {
System.out.println("Car accelerates by pressing gas pedal");
}

@Override
public void brake() {
System.out.println("Car brakes using hydraulic system");
}
}
接口适用场景
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 当需要定义行为规范时使用接口
public interface PaymentProcessor {
boolean processPayment(double amount);
void refund(double amount);
String getPaymentStatus();
}

public class CreditCardProcessor implements PaymentProcessor {
@Override
public boolean processPayment(double amount) {
System.out.println("Processing credit card payment: $" + amount);
return true;
}

@Override
public void refund(double amount) {
System.out.println("Refunding $" + amount + " to credit card");
}

@Override
public String getPaymentStatus() {
return "Credit card payment processed";
}
}

public class PayPalProcessor implements PaymentProcessor {
@Override
public boolean processPayment(double amount) {
System.out.println("Processing PayPal payment: $" + amount);
return true;
}

@Override
public void refund(double amount) {
System.out.println("Refunding $" + amount + " via PayPal");
}

@Override
public String getPaymentStatus() {
return "PayPal payment processed";
}
}

6. 实际应用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// 综合示例:图形系统
abstract class GraphicObject {
protected int x, y;

public GraphicObject(int x, int y) {
this.x = x;
this.y = y;
}

// 共同方法
public void moveTo(int x, int y) {
this.x = x;
this.y = y;
System.out.println("Moved to (" + x + ", " + y + ")");
}

// 抽象方法
public abstract void draw();
public abstract double getArea();
}

interface Resizable {
void resize(double factor);
}

interface Colorable {
void setColor(String color);
}

class Circle extends GraphicObject implements Resizable, Colorable {
private double radius;
private String color;

public Circle(int x, int y, double radius) {
super(x, y);
this.radius = radius;
}

@Override
public void draw() {
System.out.println("Drawing circle at (" + x + ", " + y + ") with radius " + radius);
}

@Override
public double getArea() {
return Math.PI * radius * radius;
}

@Override
public void resize(double factor) {
radius *= factor;
System.out.println("Circle resized. New radius: " + radius);
}

@Override
public void setColor(String color) {
this.color = color;
System.out.println("Circle color set to " + color);
}
}

// 使用示例
public class GraphicsDemo {
public static void main(String[] args) {
GraphicObject[] objects = {
new Circle(10, 20, 5),
new Circle(30, 40, 8)
};

for (GraphicObject obj : objects) {
obj.draw();
System.out.println("Area: " + obj.getArea());

// 如果支持调整大小
if (obj instanceof Resizable) {
((Resizable) obj).resize(1.5);
}

// 如果支持着色
if (obj instanceof Colorable) {
((Colorable) obj).setColor("red");
}
}
}
}

抽象类和接口都是定义规范的重要工具,选择使用哪个取决于具体的设计需求和场景。

三、关键字和核心概念

Java 关键字一览表

关键字 一句话解释
abstract 声明抽象类或抽象方法,不能被实例化
assert 断言,用于调试时检查条件是否为真
boolean 基本数据类型,表示布尔值(true/false)
break 跳出循环或switch语句
byte 基本数据类型,8位有符号整数
case switch语句中的分支标签
catch 捕获并处理异常
char 基本数据类型,16位Unicode字符
class 定义类
const 保留关键字,但未被使用(用final代替)
continue 跳过当前循环迭代,继续下一次循环
default switch语句的默认分支或包访问权限
do do-while循环语句的开始
double 基本数据类型,64位双精度浮点数
else if语句的否则分支
enum 定义枚举类型
extends 类继承或接口扩展
final 声明常量、不可继承的类或不可重写的方法
finally 异常处理中最终执行的代码块
float 基本数据类型,32位单精度浮点数
for for循环语句
goto 保留关键字,但未被使用
if 条件判断语句
implements 类实现接口
import 导入包或类
instanceof 检查对象是否为指定类型实例
int 基本数据类型,32位有符号整数
interface 定义接口
long 基本数据类型,64位有符号整数
native 声明本地方法(由其他语言实现)
new 创建对象实例
package 定义包
private 最严格的访问权限修饰符
protected 包内和子类可访问的访问权限修饰符
public 最宽松的访问权限修饰符
return 从方法返回值或结束方法执行
short 基本数据类型,16位有符号整数
static 声明类变量、类方法或静态代码块
strictfp 严格浮点运算模式
super 引用父类成员
switch 多分支选择语句
synchronized 同步代码块或方法,用于线程安全
this 引用当前对象实例
throw 抛出异常
throws 声明方法可能抛出的异常类型
transient 标记不参与序列化的变量
try 异常处理的尝试代码块
void 方法无返回值
volatile 标记变量为易变的,用于多线程环境
while while循环语句
true 布尔字面值
false 布尔字面值
null 空引用字面值

Java 9+ 新增关键字

关键字 一句话解释
module 定义模块(Java 9+模块系统)
requires 声明模块依赖(Java 9+)
exports 导出包给其他模块(Java 9+)
opens 开放包给其他模块进行反射访问(Java 9+)
uses 声明使用的服务(Java 9+)
provides 提供服务实现(Java 9+)

Java 14+ 新增关键字

关键字 一句话解释
yield switch表达式中的返回值(Java 14+)
record 定义不可变数据类(Java 14+预览,Java 16+正式)
sealed 限制类的继承(Java 15+预览,Java 17+正式)
permits 指定允许继承sealed类的子类(Java 15+预览,Java 17+正式)
non-sealed 声明允许继承的sealed类子类(Java 17+)

总计:Java 8 共有 50 个关键字,Java 9+ 增加到 57 个关键字。

四、写在最后

Java基础语法是学习Java编程的第一步,掌握好这些基础知识对于后续学习面向对象编程、集合框架、多线程等高级特性至关重要。重点需要掌握:

  1. 数据类型:理解基本数据类型和引用数据类型的区别,掌握它们的用法和转换规则
  2. 变量与常量:掌握变量的声明、初始化和命名规则,理解常量的特性
  3. 运算符:熟悉各种运算符的功能和优先级,能够正确使用它们进行运算
  4. 流程控制:掌握条件语句、循环语句和跳转语句的用法,能够编写复杂的控制逻辑
  5. 注释规范:养成良好的注释习惯,提高代码的可读性和可维护性

通过大量的编程练习,可以加深对这些基础知识的理解和掌握,为成为一名优秀的Java程序员打下坚实的基础。