Java 基础面试题——常见类
目录
- 1.String 为什么是不可变的?
- 2.字符串拼接用“+” 和 StringBuilder 有什么区别?
- 3.String、StringBuffer 和 StringBuilder 的区别是什么?
- 4.String 中的 equals() 和 Object 中的 equals() 有何区别?
- 5.Object 类有哪些常用的方法?
- 6.如何获取当前系统的剩余内存、总内存及最大堆内存?
- 7.LocalDateTime & Calendar
- 7.1.如何取当前的年、月、日、时、分、秒、毫秒?
- 7.2.如何获取从 1970 年 1 月 1 日 0 时 0 分 0 秒到现在的毫秒数?
- 7.3.如何获取某年某月的最后一天?
- 7.4.如何打印昨天的当前时刻?
- 7.5.如何格式化日期?
1.String 为什么是不可变的?
(1)String 类中使用 final 关键字修饰的字符数组来保存字符串,如下面的代码所示:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {/** The value is used for character storage. */private final char value[];...
}
(2)我们知道被 final 关键字修饰的类不能被继承,修饰的方法不能被重写,修饰的变量是基本数据类型则值不能改变,修饰的变量是引用类型则不能再指向其他对象。因此,final 关键字修饰的数组保存字符串并不是 String 不可变的根本原因,因为这个数组保存的字符串是可变的(final 修饰引用类型变量的情况)。
(3)String 真正不可变的原因如下:
① 保存字符串的数组被 final 修饰且为私有的,并且String 类没有提供/暴露修改这个字符串的方法。
② String 类被 final 修饰导致其不能被继承,进而避免了子类破坏 String 的不可变性。
2.字符串拼接用“+” 和 StringBuilder 有什么区别?
(1)Java 语言本身并不支持运算符重载,“+”和“+=”是专门为 String 类重载过的运算符,也是 Java 中仅有的两个重载过的运算符。
public static void main(String[] args) {String str1 = "he";String str2 = "llo";String str3 = "world";String str4 = str1 + str2 + str3;
}
上述代码对应的字节码如下:

可以看出,字符串对象通过 “+” 的字符串拼接方式,实际上是通过 StringBuilder 调用 append() 方法实现的,拼接完成之后调用 toString() 得到一个 String 对象。不过在循环内使用“+”进行字符串的拼接的话,存在比较明显的缺陷:编译器不会创建单个 StringBuilder 以复用,会导致创建过多的 StringBuilder 对象,从而比较占用内存空间,并且效率较低。
public static void main(String[] args) {String[] arr = {"he", "llo", "world"};String s = "";for (int i = 0; i < arr.length; i++) {s += arr[i];}System.out.println(s);
}
上述代码对应的字节码如下所示:

(2)如果直接使用 StringBuilder 对象进行字符串拼接的话,就不会存在这个问题了。
public static void main(String[] args) {String[] arr = {"he", "llo", "world"};StringBuilder s = new StringBuilder();for (String value : arr) {s.append(value);}System.out.println(s);
}
上述代码对应的字节码如下所示:

如果在 IDEA 中使用 “+” 来拼接字符串的话,会出现建议使用 StringBuilder 的提示,如下图所示:

查看字节码的方式之一:
在控制台使用命令 javap -v xxx.class 即可,不过在此之前需要先将 xxx.java 进行编译得到 xxx.class 文件才行。
3.String、StringBuffer 和 StringBuilder 的区别是什么?
(1)底层数据结构
- String 是只读字符串,它并不是基本数据类型,而是一个对象。从底层源码来看是一个 final 类型的字符数组,所引用的字符串不能被改变,一经定义,无法再增删改。每次对 String 的操作都会生成新的 String 对象。例如每次拼接操作(即两个字符串相加): 隐式地在堆上 new 了一个跟原字符串相同的 StringBuilder 对象,再调用 append() 拼接后面的字符。
private final char value[];
- StringBuffer 和 StringBuilder 都继承了 AbstractStringBuilder 抽象类,在 AbstractStringBuilder 中也是使用字符数组保存字符串,不过没有使用 final 和 private 关键字修饰(如下面的代码所示),最关键的是这个 AbstractStringBuilder 类还提供了很多修改字符串的方法,例如 append 方法。所以在进行频繁的字符串操作时,建议使用 StringBuffer 和 StringBuilder 来进行操作。
/**
* The value is used for character storage.
*/
char[] value;
(2)线程安全性
- String 中的对象是不可变的,也就可以理解为常量,所以是线程安全的、
- StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。
- StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。
(3)性能
- 每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。
- StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。
- 相同情况下使用 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。
- 性能:StringBuilder > StringBuffer > String
(4)使用场景
- 操作少量的数据:建议使用 String;
- 单线程操作字符串缓冲区下操作大量数据: 建议使用 StringBuilder;
- 多线程操作字符串缓冲区下操作大量数据: 建议使用 StringBuffer;
4.String 中的 equals() 和 Object 中的 equals() 有何区别?
String 中的 equals 方法是被重写过的,比较的是 String 字符串的值是否相等。Object 的 equals 方法是比较的对象的内存地址。
5.Object 类有哪些常用的方法?
(1)Object 是所有类的根,是所有类的父类,所有对象包括数组都实现了 Object 的方法。Object 类结构如下图所示:

(2)各种方法介绍如下:
① clone()
保护方法,实现对象的浅复制,只有实现了 Cloneable 接口才可以调用该方法,否则抛出 CloneNotSupportedException 异常,深拷贝也需要实现 Cloneable,同时其成员变量为引用类型的也需要实现 Cloneable,然后重写 clone()。
② finalize()
该方法和垃圾收集器有关系,判断一个对象是否可以被回收的最后一步就是判断是否重写了此方法。
③ equals()
该方法使用频率非常高。equals 和 == 的区别见上面的4.1题,但是在 Object 中两者是一样的。子类一般都要重写这个方法。
④ hashCode()
该方法用于哈希查找,重写了 equals() 一般都要重写 hashCode(),这个方法在一些具有哈希功能的 Collection 中用到。
⑤ notify()
配合 synchronized 使用,该方法唤醒在该对象上等待队列中的某个线程(同步队列中的线程是给抢占 CPU 的线程,等待队列中的线程指的是等待唤醒的线程)。
⑥ notifyAll()
配合 synchronized 使用,该方法唤醒在该对象上等待队列中的所有线程。
⑦ wait()
配合 synchronized 使用,wait() 就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait() 一直等待,直到获得锁或者被中断。wait(long timeout) 设定一个超时间隔,如果在规定时间内没有获得锁就返回。
调用该方法后当前线程进入睡眠状态,直到以下事件发生:
- 其他线程调用了该对象的 notify 方法;
- 其他线程调用了该对象的 notifyAll 方法;
- 其他线程调用了 interrupt 中断该线程;
- 时间间隔到了。此时该线程就可以被调度了,如果是被中断的话就抛出一个 InterruptedException 异常。
6.如何获取当前系统的剩余内存、总内存及最大堆内存?
(1)可以通过 java.lang.Runtime 类中与内存相关方法来获取剩余的内存、总内存及最大堆内存。通过下面方法可以获取到堆使用的百分比及堆内存的剩余空间。
freeMemory() 方法返回剩余空间的字节数
totalMemory() 方法总内存的字节数
maxMemory() 返回最大内存的字节数
(2)示例如下:
class Solution {public static void main(String[] args) {System.out.println("JVM 从操纵系统那里挖到的最大的内存 maxMemory : " + Runtime.getRuntime().maxMemory() / 1024 / 1024 + "M");System.out.println("JVM 已经从操作系统那里挖过来的内存 totalMemory : " + Runtime.getRuntime().totalMemory() / 1024 / 1024 + "M");System.out.println("JVM 从操纵系统挖过来还没用上的内存 freeMemory : " + Runtime.getRuntime().freeMemory() / 1024 / 1024 + "M");System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");byte[] b1 = new byte[3 * 1024 * 1024];System.out.println("JVM 从操纵系统那里挖到的最大的内存 maxMemory " + Runtime.getRuntime().maxMemory() / 1024 / 1024 + "M");System.out.println("JVM 已经从操作系统那里挖过来的内存 totalMemory : " + Runtime.getRuntime().totalMemory() / 1024 / 1024 + "M");System.out.println("JVM 从操纵系统挖过来还没用上的内存 freeMemory : " + Runtime.getRuntime().freeMemory() / 1024 / 1024 + "M");}
}
输出结果如下:
JVM 从操纵系统那里挖到的最大的内存 maxMemory : 3154M
JVM 已经从操作系统那里挖过来的内存 totalMemory : 213M
JVM 从操纵系统挖过来还没用上的内存 freeMemory : 208M
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
JVM 从操纵系统那里挖到的最大的内存 maxMemory 3154M
JVM 已经从操作系统那里挖过来的内存 totalMemory : 213M
JVM 从操纵系统挖过来还没用上的内存 freeMemory : 205M
7.LocalDateTime & Calendar
7.1.如何取当前的年、月、日、时、分、秒、毫秒?
创建 java.util.Calendar 实例,调用其 get() 传入不同的参数即可获得参数所对应的值。
import java.util.Calendar;public class TestDateAndTime {public static void main(String[] args) {//获取当前的年、月、日、时、分、秒、毫秒Calendar calendar = Calendar.getInstance();//年System.out.println(calendar.get(Calendar.YEAR));//月,需要注意的是 Calendar.MONTH 是从 0 开始的System.out.println(calendar.get(Calendar.MONTH) + 1);//天System.out.println(calendar.get(Calendar.DATE));//时System.out.println(calendar.get(Calendar.HOUR));//分System.out.println(calendar.get(Calendar.MINUTE));//秒System.out.println(calendar.get(Calendar.SECOND));//毫秒System.out.println(calendar.get(Calendar.MILLISECOND));}
}
7.2.如何获取从 1970 年 1 月 1 日 0 时 0 分 0 秒到现在的毫秒数?
import java.util.Calendar;public class TestDateAndTime {public static void main(String[] args) {Calendar calendar = Calendar.getInstance();//以下 2 种方法均可以获取从 1970 年 1 月 1 日 0 时 0 分 0 秒到现在的毫秒数System.out.println(System.currentTimeMillis());System.out.println(Calendar.getInstance().getTimeInMillis());}
}
7.3.如何获取某年某月的最后一天?
import java.time.LocalDate;
import java.util.Calendar;public class TestDateAndTime {public static void main(String[] args) {Calendar calendar = Calendar.getInstance();//某月最后一天//2018-05月最后一天,6月1号往前一天calendar.set(Calendar.YEAR, 2018);calendar.set(Calendar.MONTH, 5);calendar.set(Calendar.DAY_OF_MONTH, 1);calendar.add(Calendar.DAY_OF_MONTH, -1);System.out.println(calendar.get(Calendar.YEAR) + "-" + (calendar.get(Calendar.MONTH) + 1) + "-" + calendar.get(Calendar.DAY_OF_MONTH));//JDK 1.8 java.time 包LocalDate date = LocalDate.of(2019, 6, 1).minusDays(1);System.out.println(date.getYear() + "-" + date.getMonthValue() + "-" + date.getDayOfMonth());}
}
7.4.如何打印昨天的当前时刻?
import java.time.LocalDateTime;public class YesterdayCurrent {public static void main(String[] args) {LocalDateTime today = LocalDateTime.now();LocalDateTime yesterday = today.minusDays(1);System.out.println(yesterday);}
}
或者使用以下方式:
import java.util.Calendar;public class YesterdayCurrent {public static void main(String[] args) {Calendar cal = Calendar.getInstance();cal.add(Calendar.DATE, -1);System.out.println(cal.getTime());}
}
7.5.如何格式化日期?
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;public class TestDateAndTime {public static void main(String[] args) {Date date = new Date();SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//格式化日期System.out.println(simpleDateFormat.format(date));//JDK 1.8 java.time 包System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));}
}
相关文章:
Java 基础面试题——常见类
目录1.String 为什么是不可变的?2.字符串拼接用“” 和 StringBuilder 有什么区别?3.String、StringBuffer 和 StringBuilder 的区别是什么?4.String 中的 equals() 和 Object 中的 equals() 有何区别?5.Object 类有哪些常用的方法?6.如何获…...
Windows 系统从零配置 Python 环境,安装CUDA、CUDNN、PyTorch 详细教程
文章目录1 配置 python 环境1.1 安装 Anaconda1.2 检查环境安装成功1.3 创建虚拟环境1.4 进入/退出 刚刚创建的环境1.5 其它操作1.5.1 查看电脑上所有已创建的环境1.5.2 删除已创建的环境2 安装 CUDA 和 CUDNN2.1 查看自己电脑支持的 CUDA 版本2.2 安装 CUDA2.3 安装 CUDNN2.4 …...
[REDIS]redis的一些配置文件
修改配置文件 vim /etc/redis/redis.conf目录 protected-mode tcp-backlog timeout tcp-keepalive daemonize pidfile loglevel databases 设置密码 maxclients maxmemory maxmemory-policy maxmemory-samples 默认情况下 bind127.0.0.1 只能接受本机的访问请求。在不写的情况…...
Java反序列化漏洞——CommonsCollections4.0版本—CC2、CC4
一、概述4.0版本的CommonsCollections对之前的版本做了一定的更改,那么之前的CC链反序列化再4版本中是否可用呢。实际上是可用的,比如CC6的链,引入的时候因为⽼的Gadget中依赖的包名都是org.apache.commons.collections ,⽽新的包…...
下载网上压缩包(包含多行json)并将其转换为字典的解决方案
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。喜欢通过博客创作的方式对所学的知识进行总结与归纳,不仅形成深入且独到的理…...
【郭东白架构课 模块一:生存法则】11|法则五:架构师为什么要关注技术体系的外部适应性?
你好, 我是郭东白。 前四条法则分别讲了目标、资源、人性和技术周期,这些都与架构活动的外部环境有关。那么今天我们来讲讲在架构活动内部,也就是在架构师可控的范围内,应该遵守哪些法则。今天这节课,我们就先从技术体…...
Mindspore安装
本文用于记录搭建昇思MindSpore开发及使用环境的过程,并通过MindSpore的API快速实现了一个简单的深度学习模型。 什么是MindSpore? 昇思MindSpore是一个全场景深度学习框架,旨在实现易开发、高效执行、全场景覆盖三大目标。 安装步骤 鉴于笔者手头硬…...
C++010-C++嵌套循环
文章目录C010-C嵌套循环嵌套循环嵌套循环举例题目描述 输出1的个数题目描述 输出n行99乘法表题目描述 求s1!2!...10!作业在线练习:总结C010-C嵌套循环 在线练习: http://noi.openjudge.cn/ https://www.luogu.com.cn/ 嵌套循环 循环可以指挥计算机重复去…...
设计模式之迭代器模式与命令模式详解和应用
目录1 迭代器模式1.1 目标1.2 内容定位1.3 迭代器模式1.4 迭代器模式的应用场景1.5 手写字定义的送代器1.6 迭代器模式在源码中的体现1.7 迭代器模式的优缺点2 命令模式2.1 定义2.2 命令模式的应用场景2.3 命令模式在业务场景中的应用2.4 命令模式在源码中的体现2.5 命令模式的…...
【QA】[Vue/复选框全选] v-model绑定每一项的赋初值问题
发生场景:不只是复选框的状态改变,还有的功能要用到复选框的选中状态,比如:购物车计算总价,合计等等。 引入:复选框 checkbox 在使用时,需要用v-model绑定布尔值,来获取选中状态&…...
python基于django+vue微信小程序的校园二手闲置物品交易
在大学校园里,存在着很多的二手商品,但是由于信息资源的不流通以及传统二手商品信息交流方式的笨拙,导致了很多仍然具有一定价值或者具有非常价值的二手商品的囤积,乃至被当作废弃物处理。现在通过微信小程序的校园二手交易平台,可以方便快捷的发布和交流任何二手商品的信息,并…...
设计模式之观察者模式
什么是观察者模式 观察者模式定义了对象之间一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象都能收到通知并自动刷新。 观察者模式主要包含以下几个角色: Subject(目标):指被观察的对…...
Java Lambda表达式
目录1 Lambda表达式1.1 函数式编程思想概括1.2 Lambda表达式标准格式1.3 Lambda表达式练习1(抽象方法无参无返回值)1.4 Lambda表达式练习2(抽象方法带参无返回值)1.5 Lambda表达式练习2(抽象方法带参带返回值ÿ…...
【1237. 找出给定方程的正整数解】
来源:力扣(LeetCode) 描述: 给你一个函数 f(x, y) 和一个目标结果 z,函数公式未知,请你计算方程 f(x,y) z 所有可能的正整数 数对 x 和 y。满足条件的结果数对可以按任意顺序返回。 尽管函数的具体式子…...
java基础学习 day41(继承中成员变量和成员方法的访问特点,方法的重写)
继承中,成员变量的访问特点 a. name前什么都不加,name变量的访问采用就近原则,先在局部变量中查找,若没找到,继续在本类的成员变量中查找,若没找到,继续在直接父类的成员变量中查找,…...
【c语言进阶】深度剖析整形数据
🚀write in front🚀 📜所属专栏: 🛰️博客主页:睿睿的博客主页 🛰️代码仓库:🎉VS2022_C语言仓库 🎡您的点赞、关注、收藏、评论,是对我最大的激励…...
【信息系统项目管理师】项目管理十大知识领域记忆敲出(采购风险沟通干系人)
【信息系统项目管理师】项目管理十大知识领域记忆敲出(采购风险沟通干系人) 这里写目录标题【信息系统项目管理师】项目管理十大知识领域记忆敲出(采购风险沟通干系人)一.项目采购管理记忆敲出1.合同管理:2.规划采购管…...
[LeetCode 1237]找出给定方程的正整数解
题目描述 题目链接:[LeetCode 1237]找出给定方程的正整数解 给你一个函数 f(x, y) 和一个目标结果 z,函数公式未知,请你计算方程 f(x,y) z 所有可能的正整数 数对 x 和 y。满足条件的结果数对可以按任意顺序返回。 尽管函数的具体式子未知…...
6.2 构建 RESTful 应用接口
第6章 构建 RESTful 服务 6.1 RESTful 简介 6.2 构建 RESTful 应用接口 6.3 使用 Swagger 生成 Web API 文档 6.4 实战:实现 Web API 版本控制 6.2 构建 RESTful 应用接口 6.2.1 Spring Boot 对 RESTful 的支持 Spring Boot 提供的spring-boot-starter-web组件完全…...
20230218英语学习
How Italian Artist’s Mild Colors Dominate World of Design 温柔的“莫兰迪色”,如何引领设计时尚? The Morandi color scheme has become an across-the-board fashion that now prevails in the world of design.Soft and sophisticated Morandi c…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解
文章目录 1. 题目描述1.1 链表节点定义 2. 理解题目2.1 问题可视化2.2 核心挑战 3. 解法一:HashSet 标记访问法3.1 算法思路3.2 Java代码实现3.3 详细执行过程演示3.4 执行结果示例3.5 复杂度分析3.6 优缺点分析 4. 解法二:Floyd 快慢指针法(…...
Xcode 16 集成 cocoapods 报错
基于 Xcode 16 新建工程项目,集成 cocoapods 执行 pod init 报错 ### Error RuntimeError - PBXGroup attempted to initialize an object with unknown ISA PBXFileSystemSynchronizedRootGroup from attributes: {"isa">"PBXFileSystemSynchro…...
