学习路线
建议顺序基础语法
变量、运算、流程控制,打好地基
面向对象
封装继承多态,理解 Java 核心思想
集合框架
List/Set/Map,日常开发最常用
异常处理
写出健壮、不轻易崩溃的代码
多线程
进阶提升,应对高并发场景
Java 基础语法
入门必学变量与数据类型
Java 是强类型语言,变量必须先声明类型再使用。基本类型共 8 种:整数(byte、short、int、long)、浮点(float、double)、字符 char、布尔 boolean。引用类型:String、数组、类、接口。不同类型占用内存不同,如 int 占 4 字节,long 占 8 字节。
运算符与表达式
算术(+ - * / %)、赋值(= += -=)、比较(== != > <)、逻辑(&& || !)、三元(条件 ? a : b)。重点:== 比较基本类型值,但比较字符串内容必须用 equals();整数相除结果仍是整数,如 5/2 = 2。
流程控制
分支:if/else、switch。循环:for、while、do-while。掌握 break 跳出循环、continue 跳过本次、return 结束方法。循环次数已知用 for,未知用 while。for-each 遍历集合最简洁。
public class HelloWorld {
public static void main(String[] args) {
// 1. 变量与数据类型
int age = 18; // 整型:占用 4 字节
long big = 10000000000L; // 长整型:末尾要加 L
double score = 92.5; // 浮点:默认是 double
boolean isOk = true; // 布尔:只有 true / false
char grade = 'A'; // 字符:用单引号
// 2. 运算符
int a = 10, b = 3;
int sum = a + b; // 13
int mod = a % b; // 1(取余)
double avg = a / (double) b; // 3.33(强转)
// 3. 流程控制
for (int i = 0; i < 3; i++) {
if (i == 1) continue; // 跳过 i=1
System.out.println("Hello World! 第 " + i + " 次");
}
}
}
面向对象编程
核心思想封装 Encapsulation
用 private 隐藏内部字段,通过 getter/setter 暴露受控的访问入口。好处:保护数据不被随意修改、内部逻辑变化不影响外部调用方。
继承 Inheritance
子类用 extends 复用父类的字段和方法,用 @Override 重写方法实现差异化行为。单继承多实现:一个类只能 extends 一个父类,但可实现多个接口。
多态 Polymorphism
父类引用指向子类对象,运行期根据实际对象动态绑定方法。核心是方法重写与向上转型,实现"一个接口,多种实现",大幅提高代码扩展性。
class Animal {
protected String name;
public Animal(String name) { this.name = name; }
public void speak() { System.out.println(name + " 发出声音"); }
}
class Dog extends Animal {
public Dog(String name) { super(name); }
@Override
public void speak() { System.out.println(name + " 汪汪叫"); }
}
class Cat extends Animal {
public Cat(String name) { super(name); }
@Override
public void speak() { System.out.println(name + " 喵喵叫"); }
}
public class PolymorphismDemo {
public static void main(String[] args) {
// 多态:父类引用指向不同子类对象,调用同一方法表现不同
Animal a1 = new Dog("旺财");
Animal a2 = new Cat("咪咪");
a1.speak(); // 输出:旺财 汪汪叫
a2.speak(); // 输出:咪咪 喵喵叫
}
}
💬 评论区 · 面向对象
集合框架
开发必备List 列表
有序、可重复。底层实现不同决定了性能差异:ArrayList(数组,查询快 O(1)、尾部增删快)vs LinkedList(链表,任意位置增删快、查询慢 O(n))。开发中 ArrayList 用得最多。
Set 集合
无序、不可重复,用于去重。内部靠 hashCode() + equals() 判断重复。HashSet(哈希,查找 O(1))、LinkedHashSet(保序)、TreeSet(自动排序,红黑树)。
Map 映射
键值对存储,根据 key 的哈希快速定位 value。HashMap 是最常用的集合,键不可重复、允许一个 null 键。TreeMap 按键自动排序。ConcurrentHashMap 多线程安全。
import java.util.*;
public class CollectionDemo {
public static void main(String[] args) {
// 1. List:有序可重复,常用 ArrayList
List<String> names = new ArrayList<>();
names.add("小明"); names.add("小红"); names.add("小明");
System.out.println("List 大小:" + names.size()); // 3(可重复)
// 2. Set:不可重复,自动去重
Set<String> unique = new HashSet<>(names);
System.out.println("Set 大小:" + unique.size()); // 2(去重后)
// 3. Map:键值对存储
Map<String, Integer> scores = new HashMap<>();
scores.put("小明", 98);
scores.put("小红", 95);
// 遍历 Map:entrySet() 同时取 key 和 value
for (Map.Entry<String, Integer> e : scores.entrySet()) {
System.out.println(e.getKey() + ":" + e.getValue());
}
}
}
💬 评论区 · 集合框架
异常处理
健壮代码异常体系
所有异常与错误继承自 Throwable。下层分两类:Error(系统级,如内存溢出,无法处理)和 Exception(程序级,可处理)。Exception 又分受检异常(编译期强制处理,如 IOException)和运行时异常(运行期,如 NullPointerException)。
try-catch-finally
try 包裹可能出错的代码,catch 捕获并处理,finally 无论是否异常都会执行(常用于释放资源)。Java 7+ 的 try-with-resources 可自动关闭实现了 AutoCloseable 的资源(如文件流)。
public class ExceptionDemo {
public static void main(String[] args) {
// 1. try-catch-finally
try {
int result = 10 / 0; // 抛 ArithmeticException
} catch (ArithmeticException e) {
System.out.println("除数不能为 0:" + e.getMessage());
} finally {
System.out.println("这里无论是否异常都会执行");
}
// 2. 自定义异常:继承 Exception(受检)或 RuntimeException(非受检)
class AgeException extends RuntimeException {
AgeException(String msg) { super(msg); }
}
int age = -1;
if (age < 0) {
throw new AgeException("年龄不能为负数");
}
}
}
💬 评论区 · 异常处理
多线程编程
进阶提升创建线程
三种方式:继承 Thread 类、实现 Runnable 接口(推荐,解耦且可再继承)、实现 Callable 接口(能返回结果)。生产中更常用线程池 ExecutorService 管理线程,避免频繁创建销毁。
线程安全
多线程同时修改共享变量会引发竞态问题。用 synchronized 或 Lock 加锁保证原子性,用 volatile 保证可见性(不保证原子性)。并发工具类:ConcurrentHashMap、AtomicInteger、CountDownLatch。
import java.util.concurrent.*;
public class ThreadDemo {
public static void main(String[] args) {
// 方式一:实现 Runnable + Lambda(推荐)
Runnable task = () -> {
for (int i = 1; i <= 3; i++) {
System.out.println(Thread.currentThread().getName() + " 执行 " + i);
}
};
new Thread(task, "线程A").start();
new Thread(task, "线程B").start();
// 方式二:线程池(生产推荐,避免反复创建线程)
ExecutorService pool = Executors.newFixedThreadPool(3);
pool.submit(task);
pool.submit(task);
pool.shutdown();
}
}
💬 评论区 · 多线程
Java 面试题库
高频考点精选 Java 高频面试题,每题含核心答案、代码示例与面试官追问。先心里作答,再点开对照。
== 比较基本类型值、引用类型内存地址;equals() 默认继承 Object,行为等同 ==,但 String、Integer 等类重写后改为比较内容。自定义类要比较内容,必须重写 equals(并同步重写 hashCode)。
String a = new String("abc"); String b = new String("abc"); System.out.println(a == b); // false,两个不同对象 System.out.println(a.equals(b)); // true,内容相同
char[] 存储,Java 9+ 改用 byte[] + coder(LATIN1/UTF16)以节省空间。字符串字面量存在字符串常量池(方法区/堆),new String 则创建堆对象。设计不可变是为安全(可作 HashMap 键、类加载)、常量池复用、线程安全。
String s1 = "abc"; // 常量池 String s2 = "abc"; // 复用常量池同一对象 String s3 = new String("abc"); // 堆上新建对象 System.out.println(s1 == s2); // true System.out.println(s1 == s3); // false
常量 + 会在编译期合并;但循环内用 + 会反复 new StringBuilder,性能差。循环拼接用显式 StringBuilder。
// 单线程拼接,用 StringBuilder StringBuilder sb = new StringBuilder(); for (int i = 0; i < 1000; i++) { sb.append(i); } String result = sb.toString();
valueOf(),拆箱调 intValue()。最大的坑:Integer 有缓存(-128~127 复用对象),超出范围 == 比较会失败。
Integer x = 100; // 缓存范围内 Integer y = 100; Integer p = 200; // 超出缓存 Integer q = 200; System.out.println(x == y); // true(缓存复用) System.out.println(p == q); // false(不同对象!) System.out.println(p.equals(q)); // true,应这样比
参数列表不同,编译期多态,与返回值无关;重写:子类方法签名与父类一致,用 @Override,运行期多态。一句话——重载看参数,重写看继承。
// 重载:同名不同参 void print(int a) {} void print(String s) {} // 重写:子类覆盖父类方法 @Override void print(int a) { // 签名必须一致 }
相同或更大(protected→public 可以,public→private 不行),否则编译报错。
abstract,可含普通方法和成员变量,单继承,表达"是什么 is-a";接口:方法默认抽象(Java 8+ 有 default/static),可多实现,表达"能做什么 like-a"。Java 8 后接口默认方法淡化了两者差异。
// 抽象类:共享状态 + 模板方法 abstract class Animal { protected String name; // 可以有字段 abstract void speak(); } // 接口:定义能力契约 interface Flyable { void fly(); }
final class Config {} // 类不可被继承 try { // 业务代码 } finally { // 无论是否异常都执行(释放资源) }
引用不能变(不能再指向别的对象),但对象内部字段仍可修改。
动态数组,随机访问 O(1),尾部增删快、中间插入 O(n);LinkedList 底层双向链表,头尾增删 O(1)、随机访问 O(n)。LinkedList 每个节点多存前后指针,内存更大。绝大多场景用 ArrayList。
// 需要按下标快速取,用 ArrayList List<String> list = new ArrayList<>(); String x = list.get(5); // O(1) // 频繁在头部插入,用 LinkedList LinkedList<String> queue = new LinkedList<>(); queue.addFirst("头部");
1.5 倍(old + old>>1),新建数组并 Arrays.copyOf 拷贝。频繁扩容有开销,可预估容量用构造器初始化。
数组 + 链表 + 红黑树。put:① 对 key 的 hashCode 做扰动再 & (n-1) 定位数组下标;② 无元素直接放,有元素按链表尾插;③ 链表长度 >8 且数组 ≥64 转红黑树(查询 O(n)→O(log n));④ 默认容量 16、负载因子 0.75,超过阈值扩容为 2 倍并 rehash。
// 常见使用 Map<String, Integer> map = new HashMap<>(); map.put("A", 1); // 定位下标 → 存放 Integer v = map.get("A"); // 定位下标 → 取/遍历
hash & (n-1) 替代取模,效率更高,且能充分利用低位、减少哈希碰撞。
synchronized,线程安全但并发效率低,已过时;HashMap 线程不安全但单线程性能最好;ConcurrentHashMap(Java 8+ 用 CAS + synchronized 锁桶)线程安全且并发性能高,是并发首选。
// 并发场景用 ConcurrentHashMap,不要用 Hashtable Map<String, Integer> c = new ConcurrentHashMap<>();
锁单个桶/节点,不同桶可并发写,读基本无锁。
IOException、SQLException;运行时异常(继承 RuntimeException):编译期不强制,如 NullPointerException、ArithmeticException。设计上:可预期的外部错误用受检,编程缺陷用运行时。
// 受检异常:必须处理 try { new FileInputStream("a.txt"); // IOException,强制 catch } catch (IOException e) { } // 运行时异常:可以不处理 int x = 1 / 0; // ArithmeticException
内部主动抛出异常对象;throws 在方法声明处声明可能抛出的异常,把处理交给调用方。口诀:throw 是做,throws 是说。
System.exit() 直接退出 JVM;② 发生不可恢复的 Error;③ 线程被 kill。另外,finally 中有 return 会覆盖 try 的返回值,务必避免。
try { return 1; } finally { return 2; // 返回值被覆盖为 2! }
可见性和有序性(禁止指令重排),不保证原子性,适合单个状态标志;synchronized 同时保证原子性 + 可见性 + 有序性,是互斥锁,适合复合操作/临界区。
// volatile 适用:标志位 volatile boolean running = true; while (running) { // 另一个线程改 running 可见 } // synchronized 适用:复合操作 synchronized (this) { count++; // i++ 是三步操作,需要锁 }
Thread t = new Thread(() -> { try { Thread.sleep(100); } catch (InterruptedException e) {} }); System.out.println(t.getState()); // NEW t.start(); // → RUNNABLE
t.getState() 返回 Thread.State 枚举;生产上用 jstack 查看线程栈和锁等待。
不释放锁,到点自动醒,任何地方可调;wait 是 Object 方法,释放锁,必须在 synchronized 内,需 notify/notifyAll 唤醒。
synchronized (lock) { lock.wait(); // 释放 lock 锁,等待 notify } Thread.sleep(1000); // 不释放任何锁,睡 1 秒
对象监视器锁,而任意对象都能当锁,所以放在所有对象共同的父类 Object 上。
线程共享和线程私有:共享——堆(对象、数组,GC 主要区域)、方法区(类信息、常量池,Java 8 后为元空间 Metaspace);私有——虚拟机栈(局部变量、方法调用)、本地方法栈、程序计数器。
// 内存划分(面试背诵版) // 堆 Heap:存放所有 new 出来的对象 // 栈 Stack:方法调用、局部变量、引用 Object obj = new Object(); // ↑引用存栈里 ↑对象本身存堆里
关于我
站长主页刘仕鑫
正在从零系统学习 Java,一边学习一边把知识整理成这份网站。希望能帮到和我一样在编程路上摸索的小伙伴,也欢迎大家在评论区多多交流、共同进步。
🛠️我在学的技能
以下是我正在学习和掌握的知识,也是本站覆盖的内容:
🎯我的学习目标
- ✅掌握 Java 核心语法与面向对象思想,能独立完成小项目
- 🚀攻克多线程与并发,理解线程池与锁的原理
- 📚持续更新本站内容,与大家一起边学边交流
💬 评论区 · 基础语法