一、Java重点
1、Java 的特点
(1)平台无关性
Java 秉持 “一次编写,到处运行” 的理念,这堪称其最为显著的特性之一。Java 编译器在处理源代码时,并非像传统编译那样直接生成机器码,而是生成一种中间形式 —— 字节码(bytecode)。字节码本身无法直接运行,它需要借助 Java 虚拟机(JVM)的翻译,转化为对应系统的机器码后才能得以执行。这一机制意味着,只要系统中安装了 JVM,那么编译好的 Java 字节码就能够在该系统上顺利运行,真正实现了跨平台的通用性。
(2)面向对象
Java 是一门纯粹的面向对象编程语言,在 Java 的世界里,几乎所有的元素都可以看作是对象。面向对象编程(OOP)的一系列特性,极大地提升了代码的可维护性和可复用性。这些特性涵盖了类(class)、对象(object)、继承(inheritance)、多态(polymorphism)、抽象(abstraction)以及封装(encapsulation)。借助这些特性,开发者能够以更加模块化、结构化的方式进行编程,让代码逻辑更加清晰,易于扩展和维护。
(3)内存管理
Java 具备自动的垃圾回收机制,这一机制承担起了管理内存以及回收不再使用对象的重要职责。在传统的编程中,开发者需要手动管理内存,这不仅繁琐,还容易引发内存泄漏等各种与内存相关的问题。而在 Java 中,开发者无需再为此类问题操心,垃圾回收机制会在后台自动运行,识别并回收那些不再被引用的对象所占用的内存,从而有效减少了内存泄漏的风险,提高了程序的稳定性和可靠性。
2、JVM、JDK、JRE三者关系
(1)JVM是Java虚拟机,是Java程序运行的环境。它负责将Java字节码(由Java编译器生成)解释或编译成机器码,并执行程序。JVM提供了内存管理、垃圾回收、安全性等功能,使得Java程序具备跨平台性。
(2)JDK是Java开发工具包,是开发Java程序所需的工具集合。它包含了JVM、编译器(javac)、调试器(jdb)等开发工具,以及一系列的类库(如Java标准库和开发工具库)。JDK提供了开发、编译、调试和运行Java程序所需的全部工具和环境。
(3)JRE是Java运行时环境,是Java程序运行所需的最小环境。它包含了JVM和一组Java类库,用于支持Java程序的执行。JRE不包含开发工具,只提供Java程序运行所需的运行环境。
二、面向对象编程
1. 面向对象的四大特性
(1)封装
封装是将数据(属性)和操作数据的方法绑定在一起,隐藏对象的内部实现细节,只对外提供必要的接口。例如,一个 Person
类可以将年龄属性封装起来,通过 getAge()
和 setAge()
方法来访问和修改年龄。
class Person {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
if (age >= 0) {
this.age = age;
}
}
}
(2)继承
继承是指一个类(子类)可以继承另一个类(父类)的属性和方法,从而实现代码的复用和扩展。例如,Student
类继承 Person
类:
class Student extends Person {
private String studentId;
public String getStudentId() {
return studentId;
}
public void setStudentId(String studentId) {
this.studentId = studentId;
}
}
(3)多态
多态是指同一个方法调用可以根据对象的不同类型而表现出不同的行为。多态通过继承、接口和方法重写来实现。例如:
class Animal {
public void makeSound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Dog barks");
}
}
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Cat meows");
}
}
public class PolymorphismExample {
public static void main(String[] args) {
Animal dog = new Dog();
Animal cat = new Cat();
dog.makeSound();
cat.makeSound();
}
}
(4)抽象
抽象是指将现实世界中的事物抽象成类,只关注对象的关键特征和行为,而忽略其具体实现细节。抽象类和接口是实现抽象的两种方式。例如:
abstract class Shape {
public abstract double area();
}
class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
}
2. 抽象类和接口的区别
- 定义:抽象类使用
abstract
关键字定义,接口使用interface
关键字定义。 - 方法实现:抽象类可以有抽象方法和具体方法,接口在 Java 8 之前只能有抽象方法,Java 8 及以后可以有默认方法和静态方法。
- 继承和实现:一个类只能继承一个抽象类,但可以实现多个接口。
- 访问修饰符:抽象类中的方法可以使用各种访问修饰符,接口中的方法默认是
public abstract
的。
三、异常处理
1. 异常的分类
Java 中的异常分为两类:受检查异常(Checked Exception)和不受检查异常(Unchecked Exception)。
- 受检查异常:继承自
Exception
类,编译器会检查此类异常是否被处理或抛出。例如,IOException
。 - 不受检查异常:继承自
RuntimeException
类,编译器不会强制要求处理此类异常。例如,NullPointerException
、ArrayIndexOutOfBoundsException
。
2. 异常处理机制
- try-catch-finally:
try
块中放置可能抛出异常的代码,catch
块用于捕获和处理异常,finally
块中的代码无论是否发生异常都会执行。
try {
int[] arr = {1, 2, 3};
System.out.println(arr[3]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界异常: " + e.getMessage());
} finally {
System.out.println("finally 块执行");
}
- throws:用于在方法声明中抛出异常,将异常处理的责任交给调用者。
public void readFile() throws java.io.IOException {
java.io.FileInputStream fis = new java.io.FileInputStream("test.txt");
}
- throw:用于手动抛出一个异常对象。
public void checkAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("年龄不能为负数");
}
}
四、多线程
1. 创建线程的方式
- 继承
Thread
类
class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程执行");
}
}
public class ThreadExample {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
}
}
- 实现
Runnable
接口
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("线程执行");
}
}
public class RunnableExample {
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();
}
}
- 实现
Callable
接口
import java.util.concurrent.*;
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
return 1 + 2;
}
}
public class CallableExample {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executor = Executors.newSingleThreadExecutor();
MyCallable callable = new MyCallable();
Future<Integer> future = executor.submit(callable);
Integer result = future.get();
System.out.println("结果: " + result);
executor.shutdown();
}
}
2. 线程同步
- synchronized 关键字
可以修饰方法或代码块,保证同一时间只有一个线程可以访问被修饰的方法或代码块。
class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
- Lock 接口
Lock
接口提供了更灵活的锁机制,例如ReentrantLock
。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class CounterWithLock {
private int count = 0;
private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public int getCount() {
return count;
}
}
五、集合框架
1. 主要的集合接口和类
- List:有序、可重复的集合。常见的实现类有
ArrayList
和LinkedList
。ArrayList
基于数组实现,适合随机访问;LinkedList
基于链表实现,适合插入和删除操作。 - Set:无序、不可重复的集合。常见的实现类有
HashSet
和TreeSet
。HashSet
基于哈希表实现,TreeSet
基于红黑树实现,元素会自动排序。 - Map:键值对的集合。常见的实现类有
HashMap
和TreeMap
。HashMap
基于哈希表实现,TreeMap
基于红黑树实现,键会自动排序。
2. HashMap 的工作原理
- 存储原理:
HashMap
内部使用数组和链表(或红黑树)来存储数据。当调用put(key, value)
方法时,首先会计算key
的哈希值,根据哈希值找到对应的数组位置。如果该位置已经有元素,则会以链表或红黑树的形式存储。 - 扩容机制:当
HashMap
中的元素数量达到负载因子(默认 0.75)乘以数组容量时,会进行扩容操作,将数组容量扩大为原来的 2 倍,并重新计算元素的位置。
六、JVM 相关
1. JVM 内存模型
JVM 内存主要分为堆、栈、方法区、本地方法栈和程序计数器。
- 堆:用于存储对象实例,是垃圾回收的主要区域。
- 栈:每个线程都有自己的栈,用于存储局部变量、方法调用等信息。
- 方法区:用于存储类的信息、常量、静态变量等。
- 本地方法栈:用于执行本地方法。
- 程序计数器:记录当前线程执行的字节码行号。
2. 垃圾回收机制
- 常见的垃圾回收算法:标记 - 清除算法、标记 - 整理算法、复制算法、分代收集算法。
- 垃圾回收器:Serial 回收器、Parallel 回收器、CMS 回收器、G1 回收器等。