Java 基础面试题——常见类

news2024/12/24 11:32:35

目录

  • 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")));
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/354305.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C语言进阶】你听说过柔性数组吗?

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前是C语言学习者 ✈️专栏&#xff1a;C语言航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&a…

ChatGPT入门案例|商务智能对话客服(三)

本篇介绍智能客服的基本功能架构和基本概念&#xff0c;并利用对话流技术构建商务智能应用。 01、商务智能客服功能结构 互联网的发展已经深入到社会的各个方面&#xff0c;智能化发展已经成为社会发展的大趋势。在大数据和互联网时代&#xff0c;企业和组织愈加重视客户沟通…

波奇学数据结构:时间复杂度和空间复杂度

数据结构&#xff1a;计算机存储&#xff0c;组织数据方式。数据之间存在多种特定关系。时间复杂度&#xff1a;程序基本操作&#xff08;循环等&#xff09;执行的次数大O渐进法表示法用最高阶的项来表示&#xff0c;且常数变为1。F&#xff08;n&#xff09;3*n^22n1//F(n)为…

git基础使用

Git安装 去安装>> 正式开始 进入要管理的目录&#xff0c;执行命令 git init 查看管理目录下的状态 git status 注&#xff1a;新增文件和修改过后的文件都是红色 管理指定文件&#xff08;红变绿&#xff09; 指定文件&#xff1a;git add 文件名 当前目录下所有&…

【Python入门第十二天】Python 列表

Python 集合&#xff08;数组&#xff09; Python 编程语言中有四种集合数据类型&#xff1a; 列表&#xff08;List&#xff09;是一种有序和可更改的集合。允许重复的成员。元组&#xff08;Tuple&#xff09;是一种有序且不可更改的集合。允许重复的成员。集合&#xff08…

深度学习常用的python函数(一)

由于我只简单的学过python和pytorch&#xff0c;其中有很多函数的操作都还是一知半解的&#xff0c;其中有些函数经常见到&#xff0c;所以就打算记录下来。 1.zip zip(*a):针对单个可迭代对象压缩成n个元组&#xff0c;元组数量n等于min(a中元素的最小长度) a [(1, 2), (3…

springmvc网上商城购物每日推荐购买系统 java ssm

为了解决用户便捷地在网上购物&#xff0c;本文设计和开发了一个熙迪网上购买系统。本系统是基于web架构设计&#xff0c;SSM框架 &#xff0c;jsp技术的前台页面设计与实现&#xff0c;使用Mysql数据库管理&#xff0c;综合采用jsp模式来完成系统的相关功能。主要实现了管理员…

Linux中最基本常见命令总结

❤❤&#x1f49b;&#x1f49b;&#x1f49a;&#x1f49a;&#x1f499;&#x1f499;&#x1f49c;&#x1f49c;您的认可是对我最大的帮助&#x1f49c;&#x1f49c;&#x1f499;&#x1f499;&#x1f49a;&#x1f49a;&#x1f49b;&#x1f49b;❤❤ &#x1f90e;&…

【算法基础】堆⭐⭐⭐

一、堆 1. 堆的概念 堆(heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质: (1)堆中某个结点的值总是不大于或不小于其父结点的值; (2)堆总是一棵完全二叉树。 将根结点最大的堆叫做最大堆或大根堆,根结点…

以太网协议、arp协议、NAT协议、DNS协议

目录 数据链路层&#xff1a; 以太网协议&#xff1a; arp协议 1、arp协议格式 2、arp协议内容解释&#xff1a; arp缓存表 NAT协议&#xff1a;地址转换协议 1、作用&#xff1a;将网络数据当中的私网IP替换成为公网IP&#xff0c;或者将网络数据当中的公网IP替换为私网I…

大数据框架之Hadoop:MapReduce(二)Hadoop序列化

2.1序列化概述 1、什么是序列化 序列化就是把内存中的对象&#xff0c;转换成字节序列&#xff08;或其他数据传输协议&#xff09;以便于存储到磁盘&#xff08;持久化&#xff09;和网络传输。 反序列化就是将收到字节序列&#xff08;或其他数据传输协议&#xff09;或者…

TCP 的演化史-fast retransmit/recovery

工作原因要对一个 newreno 实现增加 sack 支持。尝试写了 3 天 C&#xff0c;同时一遍又一遍梳理 sack 标准演进。这些东西我早就了解&#xff0c;但涉及落地写实现&#xff0c;就得不断抠细节&#xff0c;试图写一个完备的实现。 这事有更简单的方法。根本没必要完全实现 RFC…

大型信息系统

一、大型信息系统二、信息系统的规划方法三、信息系统的规划工具 一、大型信息系统 信息系统规划&#xff08;也称为信息系统战略规划&#xff09;是一个组织有关信息系统建设与应用的全局性谋划&#xff0c;主要包括战略目标、策略和部署能内容。 信息化规划是企业信息化建设…

安全—08day

ApabilitiesapabilitiesLinux Capabilities线程的 capabilitiesPermitted 允许Effective 有效InheritableBoundingAmbient文件的 capabilitiesPermittedInheritableEffective运行 execve() 后 capabilities 的变化案例分析方法一、依次执行如下命令方法二、iptables端口转发方案…

SAP ABAP GUI_DOWNLOAD中下载乱码的问题

1 GUI_DOWNLOAD 1.1 问题表现 GUI_DOWNLOAD在应用当中有时会导致输出的文件在某些电脑正常显示&#xff0c;在某些电脑乱码显示。这个固然是由于各个电脑系统配置有差异&#xff0c;但是我们可以在应用该函数时就排除该差异来保证任意台电脑正常显示输出的文件。 如下…

英语基础-定语从句的特殊用法及写作应用

1. 定语从句的引导词省略的情况 1. that 引导定语从句&#xff0c;从句中缺宾语/表语&#xff0c;that可省略&#xff1b; This is the book that he likes. I like the shirt that you gave me. We do not agree on the plan that you make. China is not the country th…

论文浅尝 | SpCQL: 一个自然语言转换Cypher的语义解析数据集

笔记整理&#xff1a;郭爱博&#xff0c;国防科技大学博士论文发表会议&#xff1a;The 31th ACM International Conference on Information and Knowledge Management&#xff0c;CIKM 2022动机随着社交、电子商务、金融等行业的快速发展&#xff0c;现实世界编织出一张庞大而…

测试人员为什么也要学习Linux操作系统

我相信能够看到这篇文章的你&#xff0c;一定是对计算机感兴趣、想要增加技能从而为以后加薪打基础。今天&#xff0c;我就和大家谈谈我对为什么要学习 Linux 系统的看法。我将从如下这三个方面谈我的看法。 巩固基础知识 做一个合格的软件工程师 学以致用 1. 巩固基础知识 …

2023年美国大学生数学建模C题:预测Wordle结果建模详解+模型代码

目录 前言 一、题目理解 背景 解析 字段含义&#xff1a; 建模要求 二、建模思路 灰色预测&#xff1a; ​编辑 二次指数平滑法&#xff1a; person相关性 只希望各位以后遇到建模比赛可以艾特认识一下我&#xff0c;我可以提供免费的思路和部分源码&#xff0c;以后…

字符设备驱动基础(一)

目录 一、Linux内核对设备的分类 linux的文件种类&#xff1a; Linux内核按驱动程序实现模型框架的不同&#xff0c;将设备分为三类&#xff1a; 总体框架图&#xff1a; 二、设备号------内核中同类设备的区分 三、申请和注销设备号 四、函数指针复习 4.1、 内存四区 …