java快速复习

java


前言

适合已经学习过java但是忘记的朋友快速复习
此篇文章为本人复习java的笔录,会实时更新。
若文章内容有错误,欢迎各位批评指正。
本人使用开发工具为Idea。


一、java概述

1.1 java简介

java是由Sun公司推出的Java程序设计语言java平台的总称。

  • 现成代码多:标准库庞大,拿来就用。
  • 自动管家:内存自己扫,程序员不管释放。
  • 跨平台:字节码给 JVM,安全校验、移植性一并搞定。
  • 特点:简单性、面向对象性、健壮性 、跨平台性、高性能、多线程、动态性。

1.2 跨平台性

在这里插入图片描述

  • Java可以在计算机的操作系统之上再提供一个Java运行环境,该运行环境由Java虚拟机(Java Virtual Machine)、类库以及一些核心文件组成。
  • Java 源程序 → 编译成字节码 → 交给 对应系统的 JVM 翻译成机器码 → 一处编译,到处运行。

注意:

  • JVM 本身是用 C/C++ 写的,针对每个操作系统单独编译,所以 JVM 不能跨平台。
  • Java 程序编译成字节码后,靠对应平台的 JVM 解释/编译执行,因此 Java 程序能跨平台。

1.3 垃圾自动回收

Java 的垃圾回收线程会在后台自动检测和释放不再使用的内存,程序员无需手动管理内存,但可以通过显式将对象引用设为 null 来协助 垃圾收集线程GC,从而减少内存泄漏。
GC 的工作原理:

  1. 对象创建:
Person p = new Person(); // JVM 在堆内存中为这个对象分配空间。
  1. 引用断开:
p = null; // 现在程序中没有任何变量引用这个对象了。
  1. GC 检查:
    • 垃圾回收器周期性地扫描堆内存;
    • 找出“不可达对象”(即没有引用指向它的对象)。
  2. 回收内存:这些不可达对象的内存会被自动释放,供以后重新分配使用。

1.4 内存泄漏

内存泄漏是指程序中不再使用的对象仍被引用,导致垃圾回收器无法释放它们占用的内存空间,长期累积可能引起内存溢出(OutOfMemoryError)。
举例:

import java.util.ArrayList;
import java.util.List;

public class LeakDemo {
    private static List<byte[]> list = new ArrayList<>();

    public static void main(String[] args) {
        while (true) {
            byte[] data = new byte[1024 * 1024]; // 每次创建1MB数据
            list.add(data); // 添加到静态集合里
            System.out.println("对象数量:" + list.size());
        }
    }
}

data 数组本来用完就可以被回收;但你把它 add() 到了一个静态 list;只要 list 一直存在,data 的引用就永远不会断;GC 就不会清理这些数组;最终内存越来越多,直到内存溢出(OutOfMemoryError) 。

1.5 JVM

JVM(Java Virtual Machine)是可运行Java字节码的虚拟计算机系统,本质上是一个软件。加载java源程序编译得到的.class文件,读取其中的虚拟机指令并执行。
此过程由三部分组成,分别是:

  • 代码的装载
  • 代码的校验
  • 代码的执行
    在这里插入图片描述

1.6 JRE、JDK和JVM

  1. JDK(开发工具包),包含:
    • 编译器 javac(把 .java 编译成 .class)
    • 调试器 jdb
    • 打包工具 jar
    • 运行环境(JRE)
  2. JRE(运行环境),包含:
    • JVM(虚拟机)
    • Java 核心类库(rt.jar)
    • 一些运行所需的配置文件
      普通用户只要有 JRE 就能运行 .jar 或 .class 程序,但不能编译。
  3. JVM(虚拟机),功能:
    • 加载字节码文件
    • 解释或即时编译执行(JIT)
    • 管理内存(GC)
    • 提供跨平台能力(Write Once, Run Anywhere)

1.7 编程风格

  • Allmans风格 :“独行”风格,即左、右大括号各自独占一行。
  • Kernighan风格:“行尾”风格,即左大括号在上一行的行尾,而右大括号独占一行 。

1.8 java注释

行注释、块注释和文档注释。

  • 单行注释(快捷键Ctrl+/):
int a = 1;  // 这个就是单行注释,使用 // 
  • 块注释(快捷键Ctrl+Shift+/)
    /*
    * 我叫块注释*/
  • 文档注释(先打 /** 后回车)
    /**
     * 我叫文档注释
     */

注释文档将用来生成HTML格式的代码报告,所以注释文档必须书写在类、域、构造函数、方法,以及字段(field)定义之前。

1.9 注意事项

  • 文件名 ≠ public 类名 → 编译直接报错;
  • Java 严格区分大小写。
  • main 手写错一个字母 → 找不到入口,运行提示 “Main method not found”。
  • 一个 .java 最多一个 public 类,且必须和文件名一致;其余类 去掉 public 就行。
  • main 签名 必须是
public static void main(String[] args)

变体(如 String args[]、大小写、少 static)都不行。

  • 入口只在 main——没有 main 就不是可运行 Application。

二、java基本语法

2.1 java程序基本格式

  1. 结构定义语句(如 class、方法头)不用分号结尾;
  2. 功能执行语句(真正干活的代码)必须英文分号 ; 结尾,中文分号 ; 会报 illegal character。
    举例:
public class Demo {                    // ① 结构定义语句——声明类,无分号
    public static void main(String[] args) {  // ② 结构定义语句——声明方法,无分号
        int a = 3;                    // ③ 功能执行语句——真正干活,必须英文分号;
        System.out.println(a);        // ④ 功能执行语句——必须英文分号;
    }                                 // 方法结束的大括号属于结构,无分号
}                                     // 类结束的大括号属于结构,无分号
  1. Java严格区分大小写:大小写必须完全一致 —— class ≠ Class,computer ≠ Computer。
  2. 在 Java 中,字符串不能跨行书写。如果字符串太长,需要分行,可以将其拆成多个字符串,用 + 连接,例如:
System.out.println("这是第一个" + 
                   "Java程序!");

2.2 Java文件命名规则

  1. 文件名与 public 类
    • 如果 Java 文件中有 public 类,文件名必须与该类名一致,并以 .java 作为后缀。
    • 一个 .java 文件中最多只能有一个 public 类;若没有 public 类,文件名可与任意类名相同。
    • Java 区分大小写。
  2. 编译规则
    • 每个类编译后生成一个对应的 .class 文件。
  3. main 方法
    • Java 应用程序必须包含 main() 方法,作为程序入口。
    • main() 方法可以定义在任意类中,不必是 public 类。
    • 文件名应为包含 main() 方法的类名加 .java。

2.3 标识符

  1. 标识符必须以字母、下划线_或美元符开头,后面可以跟字母、数字、下划线或美元符。
  2. 标识符可以包含数字,但不能以数字开头除下划线“_”和“$”符号外,标识符中不包含任何特殊字符,如空格。
  3. 标识符区分大小写,比如,“abc”和“Abc”是两个不同的标识符。
  4. 对于标识符的长度没有限制。
  5. 不能使用Java关键字作为标识符。

关键词:

publicclassstaticvoidmainnew
extendsimplementsimportpackagefinalthis
superreturnifelseswitchcase
forwhiledobreakcontinuedefault
trycatchfinallythrowthrowsinstanceof
abstractinterfaceenumsynchronizedvolatiletransient
constnativestrictfpasserttruefalse

2.4 标识符命名规范

  • 见名知义:命名要清晰表达含义。
  • 驼峰命名法:多个单词组合时,除首单词外,其余单词首字母大写。
  • 避免使用中文或拼音:虽然 Java 支持,但不推荐。
类型命名规则
类名首字母大写(驼峰)
方法名首字母小写(驼峰)
变量名首字母小写(驼峰)
常量全部大写,单词间用下划线 _ 分隔

注意:

  • 所有的关键字都是小写的。
  • 不能使用关键字命名标识符。
  • const和goto是保留字关键字,虽然在Java中还没有任何意义,但在程序中不能用来作为自定义的标识符。
  • true、false和null虽然不属于关键字,但它们具有特殊的意义,也不能作为标识符使用。

2.5 变量

在 Java 中,变量是程序运行过程中用于存储数据的“容器”。每个变量都有:

  • 类型(type):表示变量存储的数据种类,如整数、浮点数、字符等。
  • 名字(name):变量的标识符,用于访问。
  • 值(value):变量存储的数据。

Java是一门强类型语言。即所有的变量都必须显式声明其类型。
变量必须先声明再使用。

示例:

int age = 20;      // 整型变量
double height = 1.75; // 浮点型变量
char grade = 'A';  // 字符变量
boolean isStudent = true; // 布尔型变量

2.5.1 变量的类型

  1. 基本类型:Java 的基本数据类型共 8 种:
类型大小默认值示例
byte1 字节0byte b = 10;
short2 字节0short s = 100;
int4 字节0int i = 1000;
long8 字节0Llong l = 100000L;
float4 字节0.0ffloat f = 3.14f;
double8 字节0.0double d = 3.1415;
char2 字节‘\u0000’char c = 'A';
boolean1 字节(逻辑值)falseboolean flag = true;
  1. 引用类型:引用类型变量用于存储对象的地址(不是对象本身):
    • 类对象:String str = “Hello”;
    • 数组:int[] arr = {1,2,3};
    • 自定义对象:Person p = new Person();

2.5.2 变量的分类

  1. 局部变量
    • 定义在方法、构造器或代码块内部
    • 只在作用域内有效
    • 不存在默认值,使用前必须初始化
    • 在同一个 作用域 内,变量名必须唯一,不允许重复声明
    • 不同作用域可以使用相同变量名(作用域覆盖)
void demo() {
    int x = 5; // 局部变量
    System.out.println(x);
}
  1. 成员变量
    • 定义在类内部、方法外部
    • 每个对象都有独立的副本
    • 有默认值,不必显式初始化
class Person {
    String name;  // 成员变量
    int age;
}
  1. 类变量
    • 使用 static 修饰
    • 属于类共享,每个对象共享同一个变量
class Counter {
    static int count = 0;
}
  1. 常量:使用 final 修饰,值不可修改
final double PI = 3.14159;

2.6 类型转换

在Java中,数据的类型如果是相容的,那么一种数据类型可以转换成另外一种数据类型。数据类型转换的方式有“自动类型转换”和“强制类型转换”两种 。

2.6.1 自动类型转换

将一种类型的变量赋给另一种类型的变量时,就会发生自动类型转换 ,发生自动类型转换需要满足:两种类型兼容、目标类型大于源类型

byteshortcharintlongfloatdouble 

2.6.2 强制类型转换

表示范围大的数据类型要转换成表示范围小的数据类型,需要用到强制类型转换 。
语法:

目标类型 变量名 = (目标类型) 原变量;

2.6.3 类型转换3

由高转低,int → byte 强制类型转换时,只保留低 8 位,高位丢失,数据可能发生 溢出或截断,导致值改变,这是 二进制截断原理,而不是随机错误。
注意:
Java 的整型运算规则:byte、short、char 在计算时会先 自动提升(promote)为 int。
举例:

public class Example03 {
    public static void main(String[] args) {
        byte b1 = 3; // byte类型变量
        byte b2 = 4;
        byte b3 = b1 + b2; // 问题所在
        System.out.println("b3=" + b3);
    }
}

byte b3 = …
试图把 int 类型 赋值给 byte 类型,编译器不允许自动截断(可能丢失数据),所以报错。

2.7 运算符

算术运算符、比较运算符、逻辑运算符、位运算符、赋值运算符、条件运算符

2.7.1 算数运算符

运算符含义示例
+3 + 2 = 5
-3 - 2 = 1
*3 * 2 = 6
/3 / 2 = 1(整型除法)
%取余3 % 2 = 1
++自增i++(先用后加)、++i(先加后用)
--自减i----i

2.7.2 比较运算符

运算符含义返回值类型示例
==等于boolean5 == 5true
!=不等于boolean5 != 3true
>大于boolean5 > 3true
<小于boolean3 < 5true
>=大于等于boolean5 >= 5true
<=小于等于boolean3 <= 5true

2.7.3 逻辑运算符

运算符含义示例
&&与(短路)(a > 0 && b > 0)
||(a > 0 || b > 0)
!!(a > 0)

2.7.4 位运算符

运算符含义示例
&按位与5 & 3 = 1(0101 & 0011 = 0001)
|按位或5 | 3 = 7 (0101 | 0011 = 0111)
^按位异或5 ^ 3 = 6(0101 ^ 0011 = 0110)
~按位取反~5 = -6
<<左移5 << 1 = 10
>>右移5 >> 1 = 2
>>>无符号右移-1 >>> 1 = 2147483647

2.7.5 赋值运算符

运算符含义示例
=赋值a = 5
+=加后赋值a += 3a = a + 3
-=减后赋值a -= 2
*=乘后赋值a *= 2
/=除后赋值a /= 2
%=取余后赋值a %= 2
&=按位与后赋值a &= 3
|=按位或后赋值a |= 7
^=按位异或后赋值a ^= 3
<<=左移后赋值a <<= 2
>>=右移后赋值a >>= 1
>>>=无符号右移后赋值a >>>= 1

2.7.6 算术运算符

变量 = 条件 ? 表达式1 : 表达式2;

2.8 程序基本流程

2.8.1 分支结构

  • if-else语句
if (条件) {
    // 条件为 true 时执行的代码
} else if (其他条件) {
    // 上一个条件不满足,当前条件为 true 时执行
} else {
    // 上述条件都不满足时执行
}
  • switch语句
switch (表达式) {
    case1:
        // 执行代码
        break; // 可选,用于跳出 switch
    case2:
        // 执行代码
        break;
    ...
    default:
        // 所有 case 都不匹配时执行
}

2.8.2 迭代结构

  • while语句
while (条件) {
    // 循环体代码
}
  • do-while语句
do {
    // 循环体代码
} while (条件);
  • for语句
for (初始化; 条件; 更新) {
    // 循环体代码
}

2.8.3 转移语句

  • break语句:在循环中用于立即从当前循环终止控制
for (int i = 1; i <= 5; i++) {
    if (i == 3) {
        break; // i==3 时终止循环
    }
    System.out.println(i);
}
  • continue语句:从其调用处跳至循环的开始处

跳过 本次循环剩余语句,直接进行 下一次循环判断。

for (int i = 1; i <= 5; i++) {
    if (i == 3) {
        continue; // i==3 时跳过本次循环
    }
    System.out.println(i);
}
  • return语句 :其之后的语句将不再执行
    • 立即终止方法执行
    • 并将控制权返回到调用该方法的位置
    • 方法中 return 之后的语句不再执行
public static int test(int x) {
    if (x < 0) {
        return -1; // 立即返回
    }
    return x * 2;
}

public static void main(String[] args) {
    System.out.println(test(-5)); // 输出 -1
    System.out.println(test(3));  // 输出 6
}

Java中没有goto语句,在多层循环时,可以用break、continue实现goto语句的功能。
带标签的 break 可一次跳出多层嵌套,格式 break 标签;,标签须放在目标语句块前。

2.9 数组

  • 数组(Array) 是一种 容器对象,用于 存储固定大小的同类型元素。
  • 一旦数组创建,长度固定,不能动态扩容(除非使用 ArrayList 等集合类)。
  • 索引从 0 开始。

2.9.1 数组的声明

// 方法一:类型在前,方括号在后
int[] arr1;

// 方法二:方括号在变量名后
int arr2[];

推荐使用 int[] arr 这种方式,更清晰地表达“这是一个整型数组”。
Java语言中声明数组时不能指定其长度(数组中元素的个数)。

2.9.2 数组的初始化

  1. 静态初始化
    已知元素,直接赋值:
int[] arr = {1, 2, 3, 4, 5};
  1. 动态初始化

只指定长度,元素使用默认值初始化:

类型默认值
int, short…0
double0.0
char‘\u0000’
booleanfalse
引用类型null
int[] arr = new int[5]; // {0,0,0,0,0}

2.9.3 访问数组元素

int[] arr = {1, 2, 3};
System.out.println(arr[0]); // 1
arr[1] = 10;                // 修改第二个元素

注意越界问题:

System.out.println(arr[3]); // 会抛出 ArrayIndexOutOfBoundsException

2.9.4 数组的长度

int[] arr = {1,2,3};
System.out.println(arr.length); // 3

length 是数组的属性,不是方法。

2.9.5 数组的方法

  1. 普通 for 循环
for(int i = 0; i < arr.length; i++){
    System.out.println(arr[i]);
}
  1. 增强 for 循环(foreach)
for(int num : arr){
    System.out.println(num);
}

2.9.6 多维数组

同一维数组一样,二维数组也是通过new关键字来创建。声明的时候至少指定第一维的长度。仅声明第二维是非法的。
二维数组常用于矩阵或表格:

int[][] matrix = new int[2][3]; // 2行3列
matrix[0][1] = 5;

int[][] matrix2 = {
    {1,2,3},
    {4,5,6}
};

访问二维数组:

System.out.println(matrix2[1][2]); // 6

2.9.7 常用操作

  1. 复制数组
    (1)clone()
int[] copy = arr.clone();

(2)System.arraycopy

System.arraycopy(from, fromIndex, to, toIndex, count)
  1. 数组排序
    (1)sort()
import java.util.Arrays;
Arrays.sort(arr);

(2)冒泡排序

     for (int i = 0; i < arr.length; i++) {
        for (int j = 0; j < arr.length - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
               int temp = arr[j];
               arr[j] = arr[j + 1];
               arr[j + 1] = temp;
           }        }
     }

  1. 数组查找
int index = Arrays.binarySearch(arr, 10);
  1. 数组转字符串
System.out.println(Arrays.toString(arr));

2.10 字符串

String 是 Java 中的 对象类型,用于存储 一串字符。

  • 在 Java 中,字符串是 不可变的(immutable):
  • 对字符串的任何修改都会产生一个新的字符串对象。
  • Java 中的字符串使用 双引号 " " 表示。

2.10.1 字符串的创建方式

  1. 直接赋值
String str1 = "Hello"; // 字符串常量池
  1. 使用构造方法
String str2 = new String("Hello"); // 堆内存

2.10.2 字符串常规操作

  1. 获取长度
String str = "Hello";
int len = str.length(); // 5
  1. 访问字符
char ch = str.charAt(0); // 'H'
  1. 遍历字符串
for(int i = 0; i < str.length(); i++){
    System.out.println(str.charAt(i));
}

// 增强 for
for(char c : str.toCharArray()){
    System.out.println(c);
}
  1. 比较字符串
String a = "abc";
String b = "abc";
String c = new String("abc");

System.out.println(a == b);      // true(同一字符串常量池)
System.out.println(a == c);      // false(不同对象)
System.out.println(a.equals(c));// true(内容相同)
  1. 查找与截取
String str = "Hello World";

System.out.println(str.indexOf("o"));      // 4
System.out.println(str.lastIndexOf("o"));  // 7
System.out.println(str.substring(0, 5));  // Hello
  1. 大小写转换
String str = "Java";
System.out.println(str.toUpperCase()); // JAVA
System.out.println(str.toLowerCase()); // java

7.去空格

String str = "  hello  ";
System.out.println(str.trim()); // "hello"
  1. 分割字符串
String str = "apple,banana,orange";
String[] arr = str.split(","); // ["apple","banana","orange"]
  1. 判断字符串
String str = "Hello";
System.out.println(str.startsWith("He")); // true
System.out.println(str.endsWith("lo"));   // true
System.out.println(str.contains("ll"));   // true

2.11 StringBuffer

StringBuffer 是 Java 提供的 可变字符串类。
与 String 不同,它 可以直接修改内容,不会生成新的对象。
线程安全(方法上使用了 synchronized),适合多线程场景。

2.11.1 创建方式

  1. 使用无参构造
StringBuffer sb = new StringBuffer(); // 默认容量16
  1. 使用字符串初始化
StringBuffer sb = new StringBuffer("Hello"); // 容量 = 字符长度 + 16
  1. 指定容量
StringBuffer sb = new StringBuffer(50); // 初始容量50

2.11.2 常用操作

  1. 追加内容
StringBuffer sb = new StringBuffer("Hello");
sb.append(" World");   // Hello World
System.out.println(sb);
  1. 插入内容
sb.insert(6, "Java "); // Hello Java World
  1. 替换内容
sb.replace(6, 10, "C++"); // Hello C++ World
  1. 删除内容
sb.delete(6, 9); // 删除索引6到8的字符
System.out.println(sb); // Hello + World
  1. 反转字符串
sb.reverse();
System.out.println(sb); // dlroW + olleH
  1. 获取字符
char ch = sb.charAt(0);
sb.setCharAt(0, 'h'); // 修改第一个字符
  1. 长度与容量
System.out.println(sb.length());   // 当前字符数
System.out.println(sb.capacity()); // 当前容量

容量 ≥ 长度,容量可以动态增长,但长度表示的是实际内容长度。
8.转变为String使用toString()方法
与String的区别

特性StringStringBuffer
可变性不可变可变
线程安全不保证线程安全(同步方法)
拼接效率低(大量操作会产生新对象)高(原地修改)
用途少量字符串操作大量字符串修改操作

2.12 包装类

  1. Java中使用基本类型(如int,float)来保存数值,为了使用方便,有时需要将基本类型的数据包装成对象类型,为了处理这些情况,Java提供了类型包装器类。
  2. Java的类型包装器有Double、Float、Long、Integer、Short、Byte、Character和Boolean,这些类提供了一系列方法,允许基本类型和对象类型之间进行转换。
  3. 主要用于集合类(如 ArrayList)只能存储对象,而不能直接存储基本类型。
基本类型对应包装类
intInteger
doubleDouble
charCharacter
booleanBoolean
byteByte
shortShort
longLong
floatFloat

2.12.1 自动装箱

自动装箱:Java 自动把基本类型转换成对应的包装类对象。
从 Java 5 开始引入,无需手动 new。

int a = 5;
Integer b = a;  // 自动装箱,相当于 Integer.valueOf(a)

应用场景:

ArrayList<Integer> list = new ArrayList<>();
list.add(10);  // 自动装箱,将 int 转成 Integer

2.12.2 自动拆箱

自动拆箱:Java 自动把包装类对象转换回基本类型。

Integer a = 20;
int b = a; // 自动拆箱,相当于 a.intValue()

使用场景:

Integer a = 30;
int sum = a + 10; // 自动拆箱,a -> int

2.12.3 包装类常用方法

方法说明
intValue()转为 int
doubleValue()转为 double
valueOf(String s)将字符串转为对应包装类
parseInt(String s)将字符串转为 int(静态方法)
toString()转为字符串

2.13 输入和输出

2.13.1 控制台输出

使用 System.out.println 和 System.out.print

System.out.println("Hello, Java!"); // 输出并换行
System.out.print("Hello ");         // 输出不换行
System.out.printf("Hello %s!", "Java"); // 格式化输出

格式化占位符常用:

占位符说明
%d十进制整数
%f浮点数
%s字符串
%c字符
%n换行符

2.13.2 控制台输入

  1. 使用 Scanner 类
import java.util.Scanner;

Scanner sc = new Scanner(System.in);

System.out.print("请输入整数: ");
int num = sc.nextInt();

System.out.print("请输入字符串: ");
String str = sc.next();

System.out.println("输入的整数: " + num);
System.out.println("输入的字符串: " + str);

sc.close(); // 关闭扫描器

常用方法:

  • nextInt() → 读取整数
  • nextDouble() → 读取浮点数
  • next() → 读取一个单词(遇空格停止)
  • nextLine() → 读取整行文本
  1. 使用 BufferedReader
import java.io.*;

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("请输入内容: ");
String line = br.readLine(); // 读取一行
System.out.println("输入内容: " + line);

BufferedReader 速度快,但需要处理异常(IOException)。

2.13.3 文件输出

  1. 使用 FileWriter
import java.io.*;

try {
    FileWriter fw = new FileWriter("output.txt");
    fw.write("Hello, Java!");
    fw.close();
} catch(IOException e) {
    e.printStackTrace();
}
  1. 使用 BufferedWriter
BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"));
bw.write("Hello, BufferedWriter!");
bw.newLine(); // 换行
bw.close();

2.13.4 文件输入

  1. 使用 FileReader
try {
    FileReader fr = new FileReader("input.txt");
    int ch;
    while((ch = fr.read()) != -1) {
        System.out.print((char)ch);
    }
    fr.close();
} catch(IOException e) {
    e.printStackTrace();
}
  1. 使用 BufferedReader
BufferedReader br = new BufferedReader(new FileReader("input.txt"));
String line;
while((line = br.readLine()) != null) {
    System.out.println(line);
}
br.close();

小结:

I/O 类型特点
控制台输出System.out.println简单直接,适合测试
控制台输入Scanner易用,推荐
高效输入输出BufferedReader/Writer适合大量数据,需处理异常
文件输入输出FileReader/FileWriter简单文件读写
高效文件操作BufferedReader/BufferedWriter高速文件读写

2.14 java错误和异常

2.14.1 错误

Java 中的错误分为三类:

类型说明例子
编译错误(Compile-time Error)编译阶段就能发现的错误,代码无法通过编译。语法错误、类型不匹配、缺少分号等
运行时错误(Runtime Error)程序运行时发生的错误,会抛出异常,但编译能通过。除零、数组越界、空指针等
逻辑错误(Logical Error)语法和运行都正确,但结果不符合预期。算法错误、计算公式错误

2.14.2 异常

异常是运行时可捕获的错误,是 Throwable 的子类。
Java 将异常分为两类:

类型说明特点
受检异常(Checked Exception)编译器要求必须处理或抛出的异常。IOExceptionSQLException
非受检异常(Unchecked Exception)编译器不要求必须处理。继承 RuntimeException,如 NullPointerExceptionArithmeticException

常见异常示例:

异常类说明示例代码
ArithmeticException算术错误,如除零int a = 10 / 0;
NullPointerException空指针引用String s = null; s.length();
ArrayIndexOutOfBoundsException数组越界int[] arr = new int[3]; arr[5];
ClassCastException类型转换错误Object obj = "abc"; Integer i = (Integer)obj;
IOExceptionI/O 操作异常FileReader fr = new FileReader("no_file.txt");

2.14.3 异常处理机制

  1. try-catch 捕获异常
try {
    int a = 10 / 0;
} catch (ArithmeticException e) {
    System.out.println("捕获异常: " + e);
}
  1. try-catch-finally
try {
    int[] arr = new int[3];
    System.out.println(arr[5]);
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("捕获异常: " + e);
} finally {
    System.out.println("无论是否异常都会执行");
}
  1. throws 声明异常
public void readFile() throws IOException {
    FileReader fr = new FileReader("file.txt");
}

三、面向对象

  • 面向对象编程的组织方式是围绕“对象”,而不是围绕“行为”;围绕数据,而非逻辑
  • 面向对象程序采用的观点是“一切都是对象”
  • 面向对象编程语言都提供面向对象模型的机制,这些机制就是:封装,继承和多态性
  • 面向对象程序设计的重点是类的设计,而不是对象的设计。

3.1 封装

封装是将 数据(属性)和操作数据的方法(行为) 包装在一个类中。
提供 访问控制(public、private、protected)隐藏内部实现,只暴露必要接口。
优点:
隐藏内部实现,降低耦合。
提高安全性,防止数据被随意修改。
可以通过 getter/setter 控制访问逻辑。

class Person {
    private String name; // 私有属性
    private int age;

    // getter
    public String getName() {
        return name;
    }

    // setter
    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if(age >= 0) this.age = age; // 控制合法性
    }
}

public class Test {
    public static void main(String[] args) {
        Person p = new Person();
        p.setName("Alice");
        p.setAge(20);
        System.out.println(p.getName() + " " + p.getAge());
    }
}

3.2 继承

继承是 子类继承父类的属性和方法,实现代码复用和层次化设计。
使用关键字 extends。
优点:

  • 代码复用。
  • 体现“is-a”关系(子类是一种父类)。
  • 支持方法重写(Override)。
class Animal {
    public void eat() {
        System.out.println("动物吃东西");
    }
}

class Dog extends Animal {
    public void bark() {
        System.out.println("狗叫");
    }
}

public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();  // 继承自Animal
        dog.bark(); // 自己的方法
    }
}

3.3 多态

多态是 同一个方法调用表现出不同行为的能力。
前提条件:

  • 有继承或实现关系。
  • 方法被重写(Override)。
  • 父类引用指向子类对象。
class Animal {
    public void sound() {
        System.out.println("动物叫");
    }
}

class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("汪汪");
    }
}

class Cat extends Animal {
    @Override
    public void sound() {
        System.out.println("喵喵");
    }
}

public class Test {
    public static void main(String[] args) {
        Animal a1 = new Dog(); // 父类引用指向子类对象
        Animal a2 = new Cat();

        a1.sound(); // 汪汪
        a2.sound(); // 喵喵
    }
}

3.4 类

类(Class) 是 对象的模板或蓝图,定义了对象的属性和行为。
对象(Object) 是类的实例,是程序运行时具体存在的实体。
类是 面向对象编程(OOP) 的核心概念。

class 类名 {
    // 属性(成员变量)
    数据类型 属性名;
    
    // 方法(成员方法)
    返回类型 方法名(参数列表) {
        // 方法体
    }
}

3.4.1 创建对象

public class Test {
    public static void main(String[] args) {
        // 创建对象
        Person p = new Person();
        p.name = "Alice";
        p.age = 20;
        p.sayHello(); // Hello, my name is Alice
    }
}

3.4.2 类的成员

  1. 属性(成员变量)
    • 存储对象状态
    • 可加访问修饰符(private、public、protected)
    • 可以有默认值,也可通过构造方法初始化
  2. 方法(成员方法)
    • 表示对象行为
    • 可操作对象属性

实例方法:方法声明中不用static修饰,必须通 过对象来调用
类方法(静态方法):方法声明中用static修饰,可以通过类名调用

  1. 构造方法(Constructor)
    • 用于初始化对象
    • 名称与类名相同,没有返回值(无void)
    • 可重载
    • 一旦在程序中定义了有参数的构造方法,都需要手动再定义一个无参数的构造方法
class Person {
    String name;
    int age;

    // 无参构造
    Person() {
        name = "Unknown";
        age = 0;
    }

    // 有参构造
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

构造方法的特点
(1)构造方法和类具有相同的名字
(2)一个类可以有多个构造方法
(3)构造方法可以有0个、1个或多个参数
(4)构造方法没有返回值和返回类型
(5)构造方法不能被显式调用。构造方法总是和new运算符一起被调用,在创建一个类的新对象的同时,系统会自动调用该类的构造方法为新对象初始化。

  1. 静态成员
class MathUtil {
    static double PI = 3.14159;

    static double square(double x) {
        return x * x;
    }
}

System.out.println(MathUtil.PI);
System.out.println(MathUtil.square(5));
成员类型属于谁调用方式访问限制
静态成员(static)属于类本身可通过类名调用可访问静态成员
不能访问非静态成员
非静态成员属于对象必须通过对象调用可访问所有成员(包括静态)
  1. this 关键字
    • 表示当前对象的引用
    • 用于区分成员变量和局部变量
class Person {
    String name;

    Person(String name) {
        this.name = name; // this.name 是成员变量,name 是参数
    }
}

this关键字:当代码块中出现全局变量、局部变量重名时,
this.变量名 调用全局变量
this关键字作为构造方法调用注意事项

  • this关键字作为构造方法调用时,必须写在构造方法的第一行。
  • this关键字表示当前被引用的实例对象,可以访问对象成员,包括成员变量,成员方法

static 方法中不能用 this:
this 是一个 隐式对象引用,它表示“当前对象本身”。
调用静态方法时,可能根本没有对象存在。因此,没有“当前对象”可以让 this 指向。

  1. 方法重载(Overload)
    • 同一个类中 方法名相同,参数列表(个数、类型、顺序)不同
    • 提高代码可读性
class Calculator {
    int add(int a, int b) { return a + b; }
    double add(double a, double b) { return a + b; }
}
  1. 实例方法和类方法的区别

1.对象调用实例方法
当对象调用实例方法时,该方法中出现的实例变量就是分配给该对象的实例变量;该方法中出现的类变量也是分配给该对象的变量,只不过这个变量和所有的其他对象共享而已。

2.类名调用类方法
类方法不仅可以被类创建的任何对象调用执行,也可以直接通过类名调用。和实例方法不同的是,类方法不可以操作实例变量,这是因为在类创建对象之前,实例成员变量还没有分配内存。

1、非静态变量只限于实例,并只能通过实例来访问。
2、静态方法里只能直接调用同类中的其他静态成员,不能直接访问非静态成员

// static方法中要直接访问非静态变量的尝试会引起编译错误。
         public class Wrong
        {
                int x;
                public static void main(String args[]) {
                       x = 9; // 编译错误!
                }
          } 
  1. 小结
成员类型说明
属性对象的状态(字段、变量)
方法对象的行为
构造方法初始化对象
静态成员类共有,不属于单个对象
this当前对象的引用
方法重载同名方法,参数不同,实现多种调用形式

3.5 访问修饰符

修饰符作用范围
public对所有类可见(最开放)
protected对同包类和子类可见
default对同一个包中的类可见
private仅对当前类可见(最严格)

访问范围比较:

访问修饰符同类同包不同包的子类其他包
public
protected×
default××
private×××

3.6 理解main方法的语法

main方法的标准定义:

public static void main(String[] args)
关键字含义
public公共的。JVM(Java 虚拟机)需要从外部调用这个方法,因此它必须是公共的,否则 JVM 无法访问。
static静态的。JVM 调用 main() 时不会先创建类的对象,所以它必须是静态的,这样 JVM 才能直接通过类名调用。
void无返回值。main() 只是程序的入口,不需要向 JVM 返回任何结果。
main方法名,固定写法。JVM 通过这个名字来定位程序入口。
String[] args参数列表,用于接收命令行传入的字符串参数。
class Test {
    int x = 10;
    public static void main(String[] args) {
        // System.out.println(x); ❌ 错误,无法访问实例成员

        Test t = new Test();      // ✅ 必须创建对象
        System.out.println(t.x);  // ✅ 正确
    }
}

3.7 按值传递和对象引用传递

类型传递内容是否影响原变量示例
基本类型(int、double)值的副本不影响改副本不影响原值
引用类型(对象、数组)引用(地址)的副本可改内部属性
不可改引用本身
改对象内容可反映到外部

3.8 内部类

3.8.1 静态内部类

public class Outer {
    static class Inner {
        int a = 0;    // 实例变量a
        static int b = 0;    // 静态变量 b
    }
}
class OtherClass {
    Outer.Inner oi = new Outer.Inner();
    int a2 = oi.a;    // 访问实例成员
    int b2 = Outer.Inner.b;    // 访问静态成员
}

静态内部类中可以定义静态成员和实例成员。外部类以外的其他类需要通过完整的类名访问静态内部类中的静态成员,如果要访问静态内部类中的实例成员,则需要通过静态内部类的实例。

public class Outer {
    int a = 0;    // 实例变量
    static int b = 0;    // 静态变量
    static class Inner {
        Outer o = new Outer;
        int a2 = o.a;    // 访问实例变量
        int b2 = b;    // 访问静态变量
    }
}

静态内部类可以直接访问外部类的静态成员,如果要访问外部类的实例成员,则需要通过外部类的实例去访问。

3.8.2 匿名内部类

class Person {
    public void sayHello() {
        System.out.println("Hello, I'm a person.");
    }
}

public class Demo {
    public static void main(String[] args) {
        Person student = new Person() {
            public void sayHello() {
                System.out.println("Hello, I'm a student.");
            }
        };

        student.sayHello(); // 输出:Hello, I'm a student.
    }
}

匿名内部类不能有构造方法;
匿名内部类不能定义任何静态成员;
只能创建匿名内部类的一个实例;
一个匿名内部类一定跟在new的后面,创建其实现的接口或父类的对象。

四、继承

  1. Java中只支持单一继承,即一个类只能继承一个父类,而不能继承多个类。
  2. 定义一个类没指明任何父类,则默认自动继承java.lang.Object类。
  3. 继承中,子类拥有父类的所有属性和方法,但父类可通过封装保留自己的隐藏数据,并通过暴露设计提供子类可访问的属性和方法。
  4. 子类不能直接继承父类的构造方法
  5. 调用父类构造方法:
public Teacher(String name, String gender, int age, float salary,String department) {

super(name, age, gender);
this.salary = salary;

}

public Teacher( ){
super();
}

构造方法的调用顺序:

  • 先递归向上:
    • 父类 → 父类的父类 → … → 最顶层 Object
    • 依次执行各父类构造方法。
  • 再向下:
    • 回到直接父类构造方法执行完后,
    • 按出现顺序初始化本类成员变量(含实例代码块)。
  • 最后:
    • 执行子类自己的构造方法剩余代码。

子类重写父类方法时,不能使用比父类中被重写的方法更严格的访问权限。例如,父类中的方法是public权限,子类的方法就不能是private权限。如果子类在重写父类方法时定义的权限缩小,则在编译时将出现错误提示。

4.1 Super关键字

“super”关键字代表父类对象。通过使用super关键字,可以访问父类的属性或方法,也可以在子类构造方法中调用父类的构造方法,以便初始化从父类继承的属性。

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

class Teacher extends Person {
	private float salary;// 薪酬
	private String department;// 部门
	public Teacher(String name, String gender, int age, float salary,	String department) {
		super(name, age, gender);
		this.salary = salary;
	} 
}

子类覆盖父类属性和方法:
子类的属性和父类的属性同名时,即子类的属性覆盖父类属性的同时,用super.属性来引用父类的属性。
子类的方法和父类的方法同名时,即子类的方法覆盖父类方法的同时,用super.方法(参数列表)来引用父类的方法。

  1. 子 类 无 条 件 继 承 父 类 的 无 参 的 构 造 方 法 , 并 在 创 建 新 子 类对象时自动执行
  2. 若子类的构造方法中没有 s u p e r ( ) 语 句 , 创 建 对 象 时 系 统 将 自 动 调 用 父 类 的 无 参 构 造 方 法 , 再 执 行 自 己 的 构 造 方 法
  3. 子类不能继承父类带参数的构造方法,而只能通过 s u p e r 关
    键字调用父类的某个构造方法
  4. 子类的构造方法定义中,若要 调用父类的含参数的构造方法 ,需用 s u p e r 关键字,且该调 用语句必须是子类构造方法的 第一条可执行语句

引用数据类型转换:

  1. 自动转换:子类转换成父类时(或者实现类转换成接口)可以自动完成。例如,Teacher是Person的子类,将一个Teacher对象赋给一个Person类型的变量时,转换自动完成。
  2. 强制转换:父类转换成子类时(或者接口转换成实现类),必须使用强制转换。例如,Teacher类是Person的子类,如果将一个Person对象赋给一个Teacher类型变量的时候,必须使用强制转换。

4.2 This 和 super

区别点thissuper
属性访问先找本类成员 → 找不到再往上(父类)找直接跳过本类,找父类成员
方法调用先绑定本类方法 → 找不到再往上(父类)找直接绑定父类方法
构造调用调用本类其它构造,必须放在首行调用直接父类构造,必须放在子类构造首行

4.3 null关键字

“null”关键字用于标识未初始化的对象。可以将null赋值给引用类型变量,但不可以赋给基本类型变量。

4.4 final关键字

用来修饰类、方法和变量,其含义是“不可改变的、最终的” 。
(1)修饰类:声明为final的类不能被继承,一个final类中的所有方法都隐式地指定为final。
(2)修饰变量:声明为final的变量是一个常量,在定义时必须给予初始值,变量一旦初始化,将不能改变。
(3)修饰方法参数:不允许在方法体内重新赋值。

 final class Person{
     public final void getInfo(final String s){
                s=“java”;//错误
       }
   }

4.5 抽象类

  1. 抽象方法:简单说就是只需要给出方法头部的定义,而不需要实现方法体,因为,没有具体的方法实现,所以称这样的方法为抽象方法。

  2. 如果一个类中含有抽象方法,那么这个类一定是抽象类,反之则不成立。在定义类时,使用abstract修饰。当然,即使类中没有抽象方法这个类也可以用abstract修饰,从而变成一个抽象类。这么做仅仅是为了避免对类进行实例化。

  3. 抽象类不能实例化。

  4. final不能修饰abstract

  5. 抽象类表示的是一种继承关系,一个类只能使用一次继承关系,这样限制了类的多重体现 。

4.6 接口

Java是单继承的语言,利用接口可以模拟多继承。接口是特殊的抽象类,是抽象方法声明和常量的定义集合,而没有变量和方法的实现。
当一个类中所有变量都是final修饰的常量,所有方法都是抽象方法的时候,该类就被 称为接口,使用关键字interface来定义,其中:

  • 定义接口中的常量的修饰符必须是public static final
  • 定义接口中的方法的修饰符必须是public

接口的实现通过“implements”关键字来实现,示例代码如下 :

public class MyClass implements MyInterface {
	public void add(int x, int y) {
		// do something
	}
	public void volume(int x, int y, int z) {
		// do something
	}
}

作为接口来说,一个类可以从接口继承(或者叫实现接口),这也是多继承,接口里面的成员变量不专属于某个对象,都是静态的成员变量,是属于整个类的,因此一个类去实现多个接口也是无所谓的,不会存在对象之间互相冲突的问题。实现多个接口,也就实现了多重继承,而且又避免了多重继承容易出现问题的地方,这就是用接口实现多重继承的好处。

接口具有继承性,通过关键字extends声明该接口是某父类的派生接口;一个接口可以有多个父接口,它们之间 用逗号分隔。

抽象类与接口区别:

概念定义作用
抽象类(abstract class)含有 abstract 方法(或仅作为父类使用)的类一组子类提供统一的模板部分实现
接口(interface)一组抽象方法的集合(Java 8 起可含默认方法)定义行为规范,规定类必须做什么

4.7 Object类

Object类是所有类的顶级父类,在Java体系中,所有类都是直接或间接的继承了Object类。声明类时未使用extends指明父类的,其父类都是Object。
Object类包含了所有Java类的公共属性和方法,这些属性和方法在任何类中均可以直接使用,其中较为重要的方法如下表所示:

方法名作用常见用途
equals(Object obj)判断两个对象是否“内容相等”比较对象内容(需重写)
hashCode()返回对象的哈希值equals 一起重写,用于集合(如 HashMap)
toString()返回对象的字符串描述打印对象信息(建议重写)
getClass()获取对象的运行时类型反射、调试
clone()对象拷贝(浅拷贝)实现对象复制(类需实现 Cloneable
finalize()垃圾回收前调用(已废弃)清理资源(现代开发中不推荐使用)
wait()线程等待用于线程同步(与 synchronized 配合)
notify()唤醒一个等待线程多线程通信
notifyAll()唤醒所有等待线程多线程通信

五、异常

从理论的角度Java中异常分为两类,分别为 :
Error(错误):JVM系统内部错误、资源耗尽等严重情况,建议程序终止。
Exception(异常):因编程错误或偶然的外在因素导致的一般性问题,例如:对负数开平方根、空指针访问、试图读取不存在的文件、网络连接中断等。
在这里插入图片描述

5.1 try-catch-finally

① 如果try里有某条语句发生异常,则try中该语句后的代码不再执行
② Catch如果能捕获异常,则方法中try—catch后的普通代码能执行
③ Catch如果不能捕获异常,则方法中try catch后的普通代码不能执行,但能执行方法中的finally中的语句,并抛出异常

5.2 抛出异常

关键字位置作用后跟内容数量限制
throw方法体内实际抛出异常异常对象只能一个
throws方法声明后声明可能抛出的异常类型异常类型名可多个(用逗号分隔)

六、集合

集合(Collection) 是一种 存储多个数据对象 的容器,用于替代数组,提供更强的动态管理能力。
区别于数组:

特点数组集合
容量固定可动态扩容
元素类型基本类型或对象只能是对象(不能存基本类型)
功能仅存取可增删改查、排序、去重、遍历等

主要接口与实现类:

接口特点常用实现类说明
List有序、可重复ArrayList, LinkedList, Vector像动态数组
Set无序、不重复HashSet, LinkedHashSet, TreeSet自动去重
Queue先进先出(FIFO)LinkedList, PriorityQueue常用于排队结构
Map键值对(key-value)HashMap, LinkedHashMap, TreeMap, Hashtablekey 唯一

总结

后面部分较为粗糙,主要是一次性写也有些疲劳,后续会继续更新。

期末考试题型: 一、 填空题(本题共15空 ,每空1分,共15分。) 二、 单项选择题(本题共20小题,每题1分,共20分。) 三、 是非题(对划“√”,错划“×”,本题共10小题,每题1分,共10分。) 四、 简答题(本题共5小题,每小题5分,共25分。) 五、 程序填空题(本题共5空 ,每空2分,共10分。) 六、 编程题(本题共2小题,每小题10分,共20分。) 二、填空题 1、Java语言是一种完全的_面相对象___程序设计语言。 2、布尔型常量有两个值,它们分别是_true__、_false___。 3、在定义一个方法时,一般都要指明该方法的返回值类型,如果它不返回任何值,则必须将其声明成 void 。 4、在Java的语言环境中已经包含了一组相关的核心类库,它们属于Java.lang包。 5、写出完整的main方法的声明 public static void main(String args[]) 。 6、要设计一个Applet小程序,必须先引入包 java.applet 。 7、设x=2.5,a=7,y=4.7,算术表达式x+a%3*(int)(x+y)%2/4的值为:2.75___ 8、被关键字_final___修饰的方法是不能被当前类的子类重新定义的方法。 9、Java中类成员的限定词有以下几种:private, _protected__, public__, 默认友好。 10、基类的公有成员在派生类中的访问权限由_基类___决定。 11、用static修饰的方法,称为静态方法。它们不是对象的方法,而是整个类的方法。静态方法只能处理用关键字_static___修饰的数据。 12、在Java中有一种叫作__构造方法__的特殊方法,我们在程序中用它来对类的对象成员进行初始化。 13、面向对象技术具有_封装性___、_继承性___、_抽象性___、多态性等特性。 14、Java中所有类都是类 _Object___的子类。 15、顺序执行以下两个语句的输出结果是: 10 。 String s = “我喜欢学习Java!”; System.out.println(s.length( )); 16、据程序的构成和运行环境的不同,Java源程序分为两大类: Application 程序和 Applet 程序。 17、如果一个Java源程序文件中定义有4个类,则使用Sun公司的JDK编译器javac编译该源程序文件将产生 4 个文件名与类名相同而扩展名为 class 的字节码文件。 18、开发与运行Java程序需要经过的三个主要步骤为 编辑源文件 、 编译器编译生成字节码文件 和 解释器执行 。 19、如果一个Java Applet源程序文件只定义有一个类,该类的类名为MyApplet,则类MyApplet必须是 Applet 类的子类并且存储该源程序文件的文件名必须为 MyApplet.java 。 20、 一个Java Application源程序文件名为MyJavaApplication.java,如果使用Sun公司的Java开发工具JDK编译该源程序文件并使用其虚拟机运算这个程序的字节码文件,应该顺序执行如下两个命令: javac MyJavaApplication.javajava MyJavaApplication 。 21、在Java的基本数据类型中,char型采用Unicode编码方案,每个Unicode码字符占用 2 字节内存空间,这样,无论是中文字符还是英文字符,每个都是占用2 字节内存空间。 22、在Java程序中定义的类有两种成员: 静态成员 、 实例成员 。 23、Java源程序是由类定义组成的,每个程序中可以定义若干个类,但是只有一个类是主类。在Java Application中,这个主类是指包含 main 方法的类;在Java Applet里,这个主类是一个系统类 Applet 的子类。 24、创建一个名为 MyPackage 的包的语句是 package MyPackage ; , 该语句应该放在程序的位置为: 程序中非注释行的第一行 。 25、 抽象或abstract 方法是一种仅有方法头,没有具体方法体和操作实现的方法,该方法必须在抽象类之中定义。 最终后final 方法是不能被当前类的子类重新定义的方法。 26、多态是指 一种定义,多种实现 ,在Java中有两种多态,一种是使用方法的 重载 实现多态,另一种是使用方法的 覆盖 实现多态。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值