小菜鸟

java菜鸟号正在起航

Java 字符串详解:String、StringBuilder 与 StringBuffer

字符串是 Java 中最常用的数据类型之一,Java 提供了 StringStringBuilderStringBuffer 三个类用于处理字符串,但它们的特性和适用场景有显著差异。本文将深入解析这三个类的底层实现、核心特性及最佳实践。

String 类:不可变的字符串

String 类是 Java 中最基础的字符串类,其核心特性是不可变性,这一特性深刻影响了它的使用方式和性能表现。

不可变性的底层实现

String 类被 final 修饰,且其底层存储字符的数组 value 也被 final 修饰,因此字符串对象一旦创建,其内容不可修改。

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    private final char value[]; // 存储字符串的字符数组(final修饰)
    // ... 其他代码
}
  • 不可变性的含义:字符串的任何修改操作(如拼接、替换)都会创建新的String对象,原对象内容保持不变。

    String s = "hello";
    s += " world"; // 生成新对象"hello world",原对象"hello"仍存在

字符串常量池:优化内存占用

为减少重复字符串的内存消耗,Java 引入了字符串常量池(位于方法区),用于存储编译期确定的字符串常量。

两种创建字符串的方式对比:
创建方式 原理 示例
直接赋值(字面量) 优先从常量池查找,若存在则返回引用;否则创建常量并放入池,再返回引用。 String s = "abc";
new String() 构造器 始终在堆中创建新对象,若常量池无对应常量则同时创建并放入池。 String s = new String("abc");
字节码分析:new String("xyz") 的对象创建
阅读全文 »

多线程问题集锦

一、如何保证 T1→T2→T3 的执行顺序?

要确保 T2 在 T1 完成后执行,T3 在 T2 完成后执行,最直观的方案是使用Thread.join()方法。join()的核心作用是让当前线程阻塞,等待目标线程执行完毕后再继续运行,从而强制线程按顺序执行。

实现示例:

public class ThreadOrder {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            System.out.println("T1 执行中...");
            try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println("T1 执行完毕");
        }, "T1");

        Thread t2 = new Thread(() -> {
            try {
                t1.join(); // 等待T1执行完毕
            } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println("T2 执行中...");
            try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println("T2 执行完毕");
        }, "T2");

        Thread t3 = new Thread(() -> {
            try {
                t2.join(); // 等待T2执行完毕
            } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println("T3 执行中...");
            try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println("T3 执行完毕");
        }, "T3");

        // 启动顺序不影响最终执行顺序
        t3.start();
        t2.start();
        t1.start();
    }
}

执行结果:

阅读全文 »

线程简介

进程与线程的核心区别

进程和线程是操作系统中两个核心的执行单元,二者的区别主要体现在资源分配和执行方式上:

对比维度 进程 线程
资源分配 操作系统分配资源的基本单位(拥有独立的堆、方法区等) 进程内的执行单元,共享进程的资源(堆、方法区),但有私有栈和程序计数器
独立性 独立运行环境,一个进程崩溃不影响其他进程 依赖进程存在,同一进程内线程崩溃可能导致整个进程崩溃
调度单位 操作系统调度资源的单位,但调度成本高 CPU 调度的基本单位,调度成本低(上下文切换开销小)
数量关系 一个进程可包含多个线程 线程是进程的一部分,不能独立存在

线程的内存结构

当 JVM 创建一个线程时,会为其分配特殊的内存区域,包含以下关键部分:

  • 程序计数器:记录线程下一条要执行的 JVM 字节码指令,确保线程在 CPU 时间片切换后能恢复执行(线程私有)。
  • Java 栈:跟踪 Java 方法的调用关系,每个方法调用对应一个栈帧,存储局部变量、参数、返回值等(线程私有)。
  • 本地方法栈:支持 native 代码的执行,与 Java 栈类似但用于本地方法调用(线程私有)。
  • 线程本地存储(Thread Local):存储线程私有变量,避免多线程共享带来的并发问题(线程私有)。
  • 状态管理变量:控制线程的生命周期(如状态标记、中断标志等)。

注意:线程的栈帧中,基本类型变量直接存储在栈上,而对象引用存储在栈上,对象本身存储在堆中(堆为进程共享资源)。

线程的创建方式

Java 提供了 4 种创建线程的方式,各有适用场景:

阅读全文 »

Java 注解(Annotation)详解:从元注解到注解处理器

注解(Annotation)是 Java 5 引入的一种元数据(metadata)机制,用于为代码添加额外信息(如配置、约束、说明等),不直接影响代码逻辑,但可通过工具(编译器、框架)解析并产生实际作用(如编译检查、代码生成)。本文将从基础概念、元注解、注解处理器等方面全面解析 Java 注解。

注解的基本概念

什么是注解?

注解是一种特殊的 “标记”,可附加在类、方法、字段等程序元素上,格式为 @注解名(属性=值)。例如:

// 方法上的@Override注解(标记方法重写)
@Override
public void run() { ... }

// 类上的@Deprecated注解(标记类已过时)
@Deprecated
public class OldClass { ... }

注解的作用

  • 编译检查:如 @Override 确保方法正确重写父类方法,编译器会校验正确性。
  • 代码生成:如 Lombok 的 @Data 自动生成 getter/setter 方法,减少模板代码。
  • 运行时处理:如 Spring 的 @Autowired 实现依赖注入,框架在运行时通过反射解析注解。
  • 文档说明:如 @Deprecated 标记过时元素,javadoc 会包含该信息。

元注解:注解的注解

元注解(Meta Annotation)是用于修饰 “注解” 的注解,定义了注解的适用范围、生命周期、继承性等基本特性。Java 内置了 5 种元注解:

@Target:指定注解的适用位置

用于限制注解可附加的程序元素(如类、方法、字段等),属性为 ElementType 数组,常见取值:

ElementType 取值 含义 示例
TYPE 类、接口、枚举 @Service 用于类
METHOD 方法 @Override 用于方法
FIELD 字段(成员变量) @Autowired 用于字段
PARAMETER 方法参数 @RequestParam 用于参数
CONSTRUCTOR 构造器 自定义注解用于构造器
LOCAL_VARIABLE 局部变量 较少使用
ANNOTATION_TYPE 注解类型本身 元注解修饰其他注解
PACKAGE 用于包信息配置
TYPE_PARAMETER(Java 8+) 类型参数(如泛型 <T> @NonNull <T> T get()
TYPE_USE(Java 8+) 任何类型使用处(如变量声明) List<@NonNull String>
阅读全文 »

非线性结构:树与图的核心概念与特性

非线性结构是指数据元素之间存在一对多或多对多关系的结构,无法用线性序列完整描述。常见的非线性结构包括(一对多)和(多对多),它们广泛应用于层次关系建模(如文件系统)、网络关系描述(如社交网络)等场景。

树(Tree):一对多的层次结构

树是一种具有层次关系的非线性结构,核心特征是存在一个根节点,其余节点分属不同子树,形成一对多的分支关系

树的定义与核心特征

树是由 n(n ≥ 0) 个节点组成的有限集合:

  • n = 0 时,称为空树
  • n > 0 时,有且仅有一个根节点(无前驱节点);其余节点可分为若干个互不相交的子集,每个子集本身也是一棵树(称为子树)。

核心特征

  • 根节点唯一,无前驱。
  • 除根节点外,每个节点有且仅有一个前驱(父节点)。
  • 每个节点可以有任意多个后继(子节点)。

树的关键术语

阅读全文 »
0%