java复习 04
心情复杂呢,现在是6.7高考第一天,那年今日此时此刻我还在考场挣扎数学,虽然结果的确很糟糕,,现在我有点对自己生气明明很多事情待办确无所事事没有目标,不要忘记曾经的自己是什么样子的,去年今日的自己还是充满着希望的,,不要陷入那年高考要是考好了就怎么样的,又反刍一遍伤害自己,不要这样,珍惜当下。。快利用好时间多多学习备战期末!!!
1 File 类删除功能
方法名 | 说明 |
---|---|
public boolean delete() | 删除由此抽象路径名表示的文件或目录 |
绝对路径和相对路径的区别
绝对路径:完整的路径名,不需要任何其他信息就可以定位它所表示的文件。例如:E:\itcast\java.txt
相对路径:必须使用取自其他路径名的信息进行解释。例如:myFile\java.txt
2 mkdir()
和 createNewFile()
在 Java 里,mkdir()
和 createNewFile()
都是 java.io.File
类用于文件、目录操作的方法,用法和场景不同,下面详细介绍:
一、mkdir()
方法
作用:专门用于创建单个目录(文件夹 ),若想创建多级目录,得用 mkdirs()
(注意是复数形式 )。
使用步骤:
- 创建
File
对象:构造方法传入要创建的目录路径。示例:
java
// 相对路径,在当前项目目录下创建名为 "myDir" 的目录
File dir = new File("myDir");
// 绝对路径,根据实际系统调整,比如 Windows 系统
File dirAbsolute = new File("C:\\myProjects\\myDir");
- 调用
mkdir()
方法:返回boolean
值,创建成功返回true
,失败(如路径已存在、权限不足等 )返回false
。示例:
java
File dir = new File("myDir");
boolean isCreated = dir.mkdir();
if (isCreated) {System.out.println("目录创建成功");
} else {System.out.println("目录创建失败,可能已存在或权限不足");
}
注意点:
- 只能创建目录,路径里若有文件后缀(像
myDir\\file.txt
这种想创建目录的情况 ),因不符合目录命名逻辑(系统认为要创建的是带后缀的 “文件形式路径”,但实际是想建目录 ),会创建失败返回false
。 - 父目录不存在时,
mkdir()
无法创建多级目录,比如想创建parentDir\\childDir
,但parentDir
本身不存在,就会创建失败,这时候得用mkdirs()
。
二、createNewFile()
方法
作用:用于创建新的空文件,若文件已存在则不创建,返回 false
。
使用步骤:
- 创建
File
对象:构造方法传入要创建的文件路径(包含文件名及后缀 )。示例:
java
// 相对路径,在当前项目目录下创建 "myFile.txt" 文件
File file = new File("myFile.txt");
// 绝对路径,根据实际系统调整,比如 Windows 系统
File fileAbsolute = new File("C:\\myProjects\\myFile.txt");
- 调用
createNewFile()
方法:该方法会声明抛出IOException
,所以调用时要处理异常(用try-catch
捕获,或在方法上声明throws IOException
)。它返回boolean
值,创建成功返回true
,失败(如路径不存在、权限不足等 )返回false
。示例:
java
File file = new File("myFile.txt");
try {boolean isCreated = file.createNewFile();if (isCreated) {System.out.println("文件创建成功");} else {System.out.println("文件创建失败,可能已存在或路径有误");}
} catch (IOException e) {System.out.println("创建文件时出现 IO 异常:" + e.getMessage());e.printStackTrace();
}
注意点:
- 只能创建文件,不能创建目录,若传入的路径中目录不存在(比如想创建
nonexistDir\\myFile.txt
,但nonexistDir
不存在 ),会抛出IOException
异常 。 - 创建的是空文件,若要往文件里写内容,后续还得结合输入流(如
FileWriter
、BufferedWriter
等 )来操作 。
三、对比总结
方法 | 作用 | 处理内容 | 异常处理 | 路径要求 |
---|---|---|---|---|
mkdir() | 创建单个目录 | 文件夹 | 无需显式处理异常(返回 boolean 标识结果 ) | 父目录存在,路径符合目录命名(别带文件后缀等干扰 ) |
createNewFile() | 创建空文件 | 文件 | 需处理 IOException | 父目录必须存在,路径是合法的文件路径(含文件名、后缀 ) |
简单说,想创建文件夹选 mkdir()
(多级用 mkdirs()
),想创建空文件用 createNewFile()
,根据实际需求和路径情况合理选择!!!!
3 欲构造ArrayList类的一个实例,此类继承了List接口,怎么实现?
以下是在 Java 中构造ArrayList
类实例的几种常见方式:
一、基本语法
1. 直接创建实例
java
import java.util.ArrayList;ArrayList<String> list=new ArrayList<>(); // 存储字符串
ArrayList<Integer> numbers=new ArrayList<>(); // 存储整数
2. 通过接口引用(推荐)~~~~~~~~~~~!!!!!!!!!!
利用面向接口编程的思想,使用List
接口类型引用ArrayList
对象,提高代码灵活性:
java new出来的还是ArrayList哦
import java.util.ArrayList;
import java.util.List;List<String> list=new ArrayList<>(); // 推荐写法
二、带初始容量的构造函数
指定初始容量(不影响动态扩容):
java
List<String> list=new ArrayList<>(100); // 初始容量为100
三、从其他集合创建
通过构造函数传入已有集合:
java
import java.util.Arrays;
import java.util.List;List<String> source=Arrays.asList("a", "b", "c");
List<String> list=new ArrayList<>(source); // 复制source中的元素
四、使用静态工厂方法(Java 9+)
利用List.of()
创建不可变集合后转为ArrayList
:
java
import java.util.ArrayList;
import java.util.List;List<String> immutableList=List.of("a", "b", "c"); // 不可变集合
List<String> list=new ArrayList<>(immutableList); // 转为可变的ArrayList
五、初始化时添加元素
1. 使用add()
方法
java
List<String> list=new ArrayList<>();
list.add("apple");
list.add("banana");
2. 使用Arrays.asList()
(不推荐)
java
import java.util.Arrays;List<String> list=new ArrayList<>(Arrays.asList("apple", "banana"));
3. 使用 Stream API(Java 8+)
java
import java.util.ArrayList;
import java.util.stream.Collectors;
import java.util.stream.Stream;List<String> list=Stream.of("apple", "banana").collect(Collectors.toCollection(ArrayList::new));
六、示例代码
java
import java.util.ArrayList;
import java.util.List;public class ArrayListExample {public static void main(String[] args) {// 1. 基本创建List<String> fruits=new ArrayList<>();fruits.add("apple");fruits.add("banana");System.out.println(fruits); // [apple, banana]// 2. 从其他集合创建List<Integer> numbers=new ArrayList<>(List.of(1, 2, 3));System.out.println(numbers); // [1, 2, 3]// 3. 带初始容量List<Double> prices=new ArrayList<>(10);System.out.println(prices.size()); // 0(容量不影响实际大小)}
}
注意事项
-
泛型类型
- 必须指定泛型类型(如
ArrayList<String>
),否则编译器会警告 “原始类型”。 - Java 7 + 支持菱形语法(
<>
),无需重复指定类型。
- 必须指定泛型类型(如
-
线程安全
ArrayList
是非线程安全的。- 如需线程安全,可使用
Collections.synchronizedList()
或CopyOnWriteArrayList
。
-
性能考虑
- 频繁插入 / 删除时,考虑使用
LinkedList
。 - 初始容量设置合理可减少扩容次数。
- 频繁插入 / 删除时,考虑使用
相关 API
- 常用方法:
add()
、get()
、set()
、remove()
、size()
、isEmpty()
、contains()
、clear()
等。 - 遍历方式:
for-each
、Iterator
、ListIterator
、forEach()
(Java 8+)。
通过以上方式,你可以灵活地创建和使用ArrayList
实例。
4 抽象类实现接口要实现接口中的所有方法吗?不需要哦
在面向对象编程中,抽象类实现接口时,不强制要求实现接口中的所有方法,具体规则取决于编程语言的特性和设计逻辑。以下是详细分析:
一、核心规则:抽象类可部分实现接口方法
1. 接口的要求
接口定义了一组必须被实现的抽象方法(某些语言允许默认方法或静态方法,但核心是契约约束)。
====!!!!普通类实现接口时,必须实现接口的所有方法,否则会编译报错。!!!!====
抽象类实现接口时,则可以选择:
- 实现全部方法:使抽象类更具体,子类可直接继承并使用。
- 实现部分方法:未实现的方法仍需声明为抽象方法,由子类完成最终实现。
2. 编程语言的差异
语言 | 规则说明 |
---|---|
Java | - 接口方法默认是public abstract (JDK 8 + 允许default 方法)。- 抽象类实现接口时,未实现的抽象方法需声明为 abstract ,且访问修饰符需与接口一致(public )。 |
C# | - 接口方法默认是公共的抽象成员。 - 抽象类实现接口时,未实现的方法需声明为 abstract ,且显式使用接口名称限定(显式接口实现)。 |
Python | - 通过抽象基类(abc.ABC )模拟接口,未实现的方法需用@abstractmethod 装饰,子类必须实现。 |
二、示例分析(以 Java 为例)
场景:定义接口Flyable
和抽象类Animal
java
// 接口:定义飞行能力
public interface Flyable {void fly(); // 抽象方法default void land() { // JDK 8+允许默认方法(非必须实现)System.out.println("Land safely");}
}// 抽象类实现接口,部分实现方法
public abstract class Animal implements Flyable {// 实现fly()方法(非必须,但可以选择实现)@Overridepublic void fly() {System.out.println("Animal can fly");}// **未实现接口中的其他抽象方法**(此处无,因接口只有fly()和默认方法land())// 若接口有其他抽象方法,需声明为abstract
}// 子类继承抽象类并实现剩余方法(若无则无需实现)
public class Bird extends Animal {// 无需重写fly(),直接使用父类实现// 若抽象类未实现fly(),则此处必须实现
}
关键说明
- 接口的默认方法:抽象类可直接继承接口的默认方法(如
land()
),无需实现。 - 未实现的抽象方法:若接口中有多个抽象方法,抽象类未实现的部分需声明为
abstract
,例如:java
public interface TwoMethods {void method1();void method2(); }public abstract class MyAbstractClass implements TwoMethods {@Overridepublic void method1() { // 实现method1// 逻辑}// method2()未实现,需声明为抽象方法public abstract void method2(); }
三、为什么抽象类可以部分实现接口?!!!!!!!!!!!
1. 设计目的
抽象类本身是为了被继承而设计的,允许包含抽象方法(未实现)和具体方法(已实现)。
- 部分实现接口:可将接口中通用的逻辑封装在抽象类中,减少子类重复代码。
- 延迟实现:将特定逻辑留给子类实现,符合 “模板方法模式”。
2. 与普通类的区别
- 普通类:必须完整实现接口,否则无法实例化。
- 抽象类:无需完整实现接口,因为它本身不能被实例化,仅作为子类的基类。
例如:Java 的AbstractList
抽象类实现了List
接口,但未实现所有方法(如add(int, E)
),由ArrayList
等子类完成。
四、注意事项
-
访问修饰符匹配
接口方法默认是public
,抽象类实现时必须显式声明为public
,否则会因权限不足报错(如 Java 中默认package-private
会导致编译失败)。 -
子类的责任
若抽象类未实现接口的部分方法,其子类必须实现所有剩余的抽象方法,否则子类也需声明为抽象类。 -
接口默认方法的兼容性
若接口新增默认方法,已有的抽象类实现无需修改,可直接继承该默认方法。
总结
类类型 | 实现接口的要求 |
---|---|
普通类 | 必须实现接口的所有抽象方法 |
抽象类 | 可实现部分或全部抽象方法,未实现的需声明为abstract |
核心逻辑:抽象类通过 “部分实现接口”,为子类提供通用逻辑的同时,保留灵活性,让子类专注于特定实现。这是面向对象设计中 “代码复用” 和 “接口隔离” 原则的体现。
5 java创建一个新线程怎么做?
在 Java 中,创建新线程主要有以下几种方式:
一、继承Thread
类(方式一)
步骤
- 定义类继承
Thread
类,并重写run()
方法(线程执行的核心逻辑)。 - 创建该类的实例,调用
start()
方法启动线程。
示例
java
class MyThread extends Thread {@Overridepublic void run() {System.out.println("线程执行中,ID: " + getId());}
}// 使用方式
MyThread thread=new MyThread();
thread.start(); // 启动新线程,执行run()方法
二、实现Runnable
接口(方式二)
步骤
- 定义类实现
Runnable
接口,实现run()
方法。 - 创建该类的实例,将其作为参数传入
Thread
构造函数。 - 调用
Thread
实例的start()
方法。
示例
java
class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("线程执行中,ID: " + Thread.currentThread().getId());}
}// 使用方式
Thread thread=new Thread(new MyRunnable());
thread.start();
三、使用 Lambda 表达式(Java 8+,简化 Runnable)
步骤
直接用 Lambda 表达式实现Runnable
接口的run()
方法。
示例
java
Thread thread=new Thread(() -> {System.out.println("线程执行中,ID: " + Thread.currentThread().getId());
});
thread.start();
四、实现Callable
接口(带返回值)
步骤
- 定义类实现
Callable<T>
接口,实现call()
方法(返回值类型为T
)。 - 创建
FutureTask<T>
对象,传入Callable
实例。 - 将
FutureTask
作为参数传入Thread
构造函数,调用start()
方法。 - 通过
FutureTask.get()
获取线程执行结果。
示例
java
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;class MyCallable implements Callable<Integer> {@Overridepublic Integer call() {return 100; // 返回计算结果}
}// 使用方式
FutureTask<Integer> futureTask=new FutureTask<>(new MyCallable());
Thread thread=new Thread(futureTask);
thread.start();try {Integer result=futureTask.get(); // 获取返回值(阻塞等待)System.out.println("结果: " + result);
} catch (Exception e) {e.printStackTrace();
}
五、使用线程池(推荐)
步骤
- 创建线程池(如
ExecutorService
)。 - 提交任务(
Runnable
或Callable
)。 - 关闭线程池。
示例
java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;// 创建固定大小的线程池
ExecutorService executor=Executors.newFixedThreadPool(3);// 提交任务
executor.submit(() -> {System.out.println("线程池任务执行中");
});// 关闭线程池
executor.shutdown();
六、对比与选择
方式 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
继承 Thread 类 | 实现简单,直接使用this 引用当前线程 | 单继承限制,无法继承其他类 | 简单场景,无需复用逻辑 |
实现 Runnable | 避免单继承限制,逻辑与线程分离 | 无返回值,无法直接捕获异常 | 需复用任务逻辑 |
Lambda 表达式 | 代码简洁,适合简单任务 | 可读性差,复杂逻辑难以维护 | 简单异步操作 |
实现 Callable | 支持返回值和异常捕获 | 需配合FutureTask ,代码较复杂 | 需要获取执行结果的场景 |
线程池 | 复用线程,提高性能,支持定时 / 调度 | 配置复杂,需手动关闭线程池 | 高并发场景,大量短期任务 |
注意事项
-
start()
vsrun()
- 必须调用
start()
启动新线程,执行run()
中的逻辑。 - 直接调用
run()
会在当前线程执行,不会创建新线程。
- 必须调用
-
线程安全
- 多线程共享资源时需注意同步问题(如
synchronized
、Lock
、volatile
)。
- 多线程共享资源时需注意同步问题(如
-
线程池参数
- 生产环境中建议使用
ThreadPoolExecutor
自定义参数,避免资源耗尽。
- 生产环境中建议使用
示例:完整的线程池使用
java
import java.util.concurrent.*;public class ThreadPoolExample {public static void main(String[] args) {// 创建自定义线程池ExecutorService executor=new ThreadPoolExecutor(2, // 核心线程数5, // 最大线程数60, TimeUnit.SECONDS, // 空闲线程存活时间new LinkedBlockingQueue<>(10), // 任务队列Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy() // 拒绝策略);// 提交任务Future<String> future=executor.submit(() -> {Thread.sleep(1000);return "任务完成";});try {System.out.println(future.get()); // 获取结果} catch (Exception e) {e.printStackTrace();} finally {executor.shutdown(); // 关闭线程池}}
}
根据需求选择合适的创建方式,通常线程池是最优选择,尤其是在高并发场景下。
6 有关线程的知识!!啊啊啊啊!!!!!
Java 线程核心知识总结:
一、线程基础概念
1. 进程 vs 线程
- 进程:程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基本单位(如运行中的 QQ)。
- 线程:进程中的一个执行单元,是 CPU 调度和分派的基本单位(如 QQ 中的文件传输、消息推送)。
2. 多线程优势
- 提高 CPU 利用率
- 提高程序响应速度
- 便于资源共享(线程共享进程内存空间)
3. 线程状态(6 种)
状态 | 描述 |
---|---|
NEW | 线程创建但未启动(new Thread() ) |
RUNNABLE | 运行中或就绪(获取 CPU 时间片时执行) |
BLOCKED | 等待获取锁(如synchronized 同步块) |
WAITING | 等待其他线程唤醒(如wait() 、join() ) |
TIMED_WAITING | 定时等待(如sleep(long) 、wait(long) ) |
TERMINATED | 线程执行完毕或异常终止 |
二、线程创建方式
1. 继承Thread
类
java
class MyThread extends Thread {@Overridepublic void run() {System.out.println("线程执行:" + getName());}
}// 使用
new MyThread().start();
2. 实现Runnable
接口
java
class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("任务执行:" + Thread.currentThread().getName());}
}// 使用
new Thread(new MyRunnable()).start();
3. 实现Callable
接口(带返回值)
java
import java.util.concurrent.*;class MyCallable implements Callable<String> {@Overridepublic String call() {return "执行结果";}
}// 使用
FutureTask<String> task=new FutureTask<>(new MyCallable());
new Thread(task).start();
String result=task.get(); // 获取返回值(阻塞)
4. 线程池(推荐)
java
import java.util.concurrent.*;// 创建固定大小线程池
ExecutorService executor=Executors.newFixedThreadPool(5);// 提交任务
executor.submit(() -> {System.out.println("线程池任务");
});// 关闭线程池
executor.shutdown();
三、线程同步与安全
1. 线程安全问题
多线程同时访问共享资源时可能导致数据不一致(如银行转账)。
2. 同步机制
a. synchronized
关键字
java
// 同步方法
public synchronized void add() {// 线程安全代码
}// 同步块
public void method() {synchronized (this) {// 线程安全代码}
}
b. Lock
接口(JUC 包)
java
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;Lock lock=new ReentrantLock();public void method() {lock.lock();try {// 线程安全代码} finally {lock.unlock(); // 必须在finally中释放锁}
}
c. 原子类(Atomic 包)
java
import java.util.concurrent.atomic.AtomicInteger;AtomicInteger count=new AtomicInteger(0);
count.incrementAndGet(); // 原子操作,线程安全
四、线程通信
1. Object 类的方法
java
// 等待
synchronized (obj) {obj.wait(); // 释放锁,进入WAITING状态
}// 唤醒
synchronized (obj) {obj.notify(); // 随机唤醒一个等待线程obj.notifyAll(); // 唤醒所有等待线程
}
2. JUC 包的Condition
java
import java.util.concurrent.locks.*;Lock lock=new ReentrantLock();
Condition condition=lock.newCondition();// 等待
lock.lock();
try {condition.await(); // 等价于wait()
} finally {lock.unlock();
}// 唤醒
lock.lock();
try {condition.signal(); // 等价于notify()condition.signalAll(); // 等价于notifyAll()
} finally {lock.unlock();
}
五、线程池(重点)
1. 线程池优势
- 降低资源消耗(复用线程)
- 提高响应速度(任务到达时无需创建线程)
- 便于管理线程(控制并发数、定时任务)
2. 线程池创建方式
java
import java.util.concurrent.*;// 1. 固定大小线程池
ExecutorService fixedPool=Executors.newFixedThreadPool(5);// 2. 单线程池
ExecutorService singlePool=Executors.newSingleThreadExecutor();// 3. 缓存线程池(按需创建)
ExecutorService cachedPool=Executors.newCachedThreadPool();// 4. 定时任务线程池
ScheduledExecutorService scheduledPool=Executors.newScheduledThreadPool(3);
scheduledPool.schedule(() -> {}, 1, TimeUnit.SECONDS); // 延迟1秒执行
3. 自定义线程池(推荐)
java
ThreadPoolExecutor executor=new ThreadPoolExecutor(2, // 核心线程数5, // 最大线程数60, TimeUnit.SECONDS, // 空闲线程存活时间new LinkedBlockingQueue<>(100), // 任务队列Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
);
六、JUC 包(并发工具类)
1. CountDownLatch
java
import java.util.concurrent.CountDownLatch;CountDownLatch latch=new CountDownLatch(3); // 计数器初始值为3// 线程中调用
latch.countDown(); // 计数器减1// 主线程等待
latch.await(); // 阻塞直到计数器为0
2. CyclicBarrier
java
import java.util.concurrent.CyclicBarrier;CyclicBarrier barrier=new CyclicBarrier(3, () -> {System.out.println("所有线程到达屏障点");
});// 线程中调用
barrier.await(); // 阻塞直到3个线程都到达
3. Semaphore
java
import java.util.concurrent.Semaphore;Semaphore semaphore=new Semaphore(2); // 允许2个线程同时访问semaphore.acquire(); // 获取许可
try {// 执行受限操作
} finally {semaphore.release(); // 释放许可
}
七、线程相关方法
方法 | 描述 |
---|---|
start() | 启动线程,调用run() 方法 |
run() | 线程执行的核心逻辑 |
sleep(long) | 线程休眠指定毫秒数,不释放锁 |
join() | 等待线程执行完毕 |
interrupt() | 中断线程(设置中断标志,不强制终止) |
isInterrupted() | 判断线程是否被中断 |
setDaemon(true) | 设置为守护线程(JVM 退出时自动终止) |
八、面试高频考点
-
线程创建方式的区别
Thread
vsRunnable
vsCallable
- 单继承限制、返回值、异常处理
-
synchronized
和Lock
的区别- 语法层面 vs API 层面
- 自动释放锁 vs 手动释放锁
- 可中断锁、公平锁特性
-
线程池参数调优
- 核心线程数、最大线程数、队列大小的关系
- 拒绝策略的选择(
AbortPolicy
、CallerRunsPolicy
等)
-
死锁的条件与解决
- 四个必要条件:互斥、占有并等待、不可抢占、循环等待
- 解决方案:破坏任一条件
-
volatile 关键字
- 保证可见性,禁止指令重排序
- 不保证原子性(对比
synchronized
)
九、我自己写的笔记
run方法并没有调用线程,是用start方法启用。
为什么要重写run方法?
因为run()是用来封装被线程执行的代码
run()方法和start()方法的区别?
run()是封装线程执行的代码,直接调用相当于普通方法的调用,没有启用线程!!
start()是启动线程,然后由JVM调用此线程的run()方法
=========================================================================
控制线程~~
setName()方法作为设置线程的名字
package PTA_training.Thread_training;public class MyThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName() + ":" + i);}}
}
package PTA_training.Thread_training;public class MyThreadDemo {public static void main(String[] args) {MyThread m1= new MyThread();MyThread m2= new MyThread();m1.setName("abc");m2.setName("ABC");m1.start();m2.start();}
}
这是一种方法,或者把构造方法里面设置成带String参数的,在进行super继承父类的name也可以实现线程的命名~~
package PTA_training.Thread_training;public class MyThreadDemo {public static void main(String[] args) {MyThread m1= new MyThread("abc");MyThread m2= new MyThread("ABC");m1.start();m2.start();}
}
package PTA_training.Thread_training;public class MyThread extends Thread{public MyThread(String name) {super(name);}@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName() + ":" + i);}}}
总结
Java 线程是并发编程的基础,掌握线程创建、同步机制、线程池和 JUC 工具类是关键。强调一下:
- 线程安全是多线程编程的核心问题
- 线程池是生产环境的首选方案
- JUC 包提供了丰富的并发工具,避免手写底层同步代码
7 StringBuilder buffer = new StringBuilder(s);是什么意思?注意String 不可变性!!!!!!!!!!!!!
-
String的不可变性:
- Java 中的 String 对象是不可变的,一旦创建就不能修改
change
方法中对参数 s 的修改实际上是创建了新的 String 对象- 原引用变量 s 指向的对象未被改变,因此 main 方法中输出仍为 "Java"
public class Main {public static void main(String[] args) {String s = "Java";// 若调用change方法,s仍指向"Java"// change(s); System.out.println(s); // 输出"Java"}public static void change(String s) {s = s + "HTML"; // 创建新对象,不影响原引用,这是新的s啊!}
}
//所以最后的输出还是java,不是java HTML
StringBuilder buffer = new StringBuilder(s);
是 Java 中的代码,它创建了一个 StringBuilder
对象,并使用另一个字符串 s
来初始化这个对象。下面我来详细解释:
关键点说明:
- StringBuilder 类:
StringBuilder
是 Java 中用于处理可变字符序列的类。- 与不可变的
String
类不同!!!!!!!!!!!!!!!!!!!!!!**StringBuilder
允许在不创建新对象的情况下修改字符串内容**。
- 构造函数:
new StringBuilder(s)
使用的是StringBuilder
的构造函数,该构造函数接受一个String
参数。- 这个构造函数会创建一个
StringBuilder
对象,并将参数s
的内容复制到这个对象中。
- 变量声明与赋值:
StringBuilder buffer = ...
声明了一个名为buffer
的变量,其类型是StringBuilder
。- 这个变量指向新创建的
StringBuilder
对象。
代码示例:
假设 s
是一个已有的字符串,例如:
java
String s = "Hello";
StringBuilder buffer = new StringBuilder(s);
这段代码执行后:
buffer
对象的初始内容是"Hello"
。- 你可以对
buffer
进行各种修改操作,如追加、插入或删除字符,而不会影响原始的s
字符串。
常见用途:
StringBuilder
通常用于需要频繁修改字符串的场景,例如:
- 构建复杂的字符串(如 SQL 查询、HTML 片段等)。
- 字符串拼接操作(比直接使用
+
操作符更高效)。 - 需要多次修改字符串内容的循环中。
如果后续需要将 buffer
的内容转换回不可变的 String
,可以调用 buffer.toString()
方法。
8 方法重载!!
方法重载核心规则是 “方法名相同 + 参数列表(参数个数、类型、顺序 )不同”,和返回值类型、访问修饰符无关。