Java经典面试题下包含答案

news2024/9/22 9:30:45

在这里插入图片描述

21.String、StringBuffer和StringBuilder的区别是什么?

线程安全:

  • String中的对象是不可变的,线程安全
  • StringBuffer对方法加了同步锁,所以是线程安全的
  • StringBuilder没有对方法加同步锁,所以是非线程安全的

使用效率:

  • String进行操作时,每次都会生成一个新的String对象,然后将指针指向新的String对象。
  • 而StringBuffer和StringBuilder每次都会对本身进行操作而不是生成新对象。StringBuilder比StringBuffer使用效率较高,但线程不安全

可变性:
String:
在这里插入图片描述
fianl修饰的类不能被继承,修饰的方法不能被重写,修饰的基本类型数据不能改变,修饰的引用类型则不能在指向其他对象。因为final修饰的数组并不是String不可变的根本原因,因为这个数组保存的内部数据是可变的,真正的原因有以下几点:

  1. 字符串数组被final修饰并且为私有,并且String没有提供修改这个字符串的方法
  2. String类被final修饰导致不能被继承,避免了子类破坏String不可变

StringBuilder与StringBuffer:
在这里插入图片描述
StringBuilder与StringBuffer都继承于AbstractStringBuilder,该抽象类也是使用字符数组保存字符串,但没有使用final和private修饰。而且还提供很多操作字符串的方法
在这里插入图片描述
如何选择三者:

  • 少量操作使用String
  • 单线程下大量操作使用StringBuilder
  • 多线程下大量操作使用StringBuffer

字符串拼接使用 + 还是StringBuilder?

public static void main(String[] args) {
        String str = "";
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            str += "a";
        }
        long end = System.currentTimeMillis();
        System.out.println("String拼接100000次花费时间: " + (end - start));
        StringBuilder stringBuilder = new StringBuilder();
        start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            stringBuilder.append("a");
        }
        end = System.currentTimeMillis();
        System.out.println("StringBuilder拼接100000次花费时间: " + (end - start));
    }

在这里插入图片描述
首先我们可以得出当数据量很大时,StringBuilder的拼接效率远远高于String拼接,那么为什么呢?

因为String通过"+“进行拼接时,实现会先创建StringBuilder然后调用append()调用toString()得到一个String对象。当我们在循环里使用”+"进行拼接时,会创建大量的StringBuilder对象,每循环一次就会创建一个

字符串常量池:
字符串常量池主要是为了提升性能并减少内存消耗,给字符串专门开辟了一块区域,为了防止字符串重复创建

public static void main(String[] args) {
        // 将字符串"abc"保存在字符串常量池
        String s1 = "abc";
        // 从字符串常量池直接返回"abc"的引用
        String s2 = "abc";
        System.out.println(s1 == s2);
    }

在这里插入图片描述
String s = new String(“a”) 会创建几个对象?
这里分两种情况:

  1. 常量池存在"abc"的引用,那么只会在堆空间中创建一个对象
  2. 常量池中不存在"abc"的引用,首先会在字符串常量池中创建,然后再堆中创建,那么共创建2个字符串对象

intern()是做什么的?
intern()是一个native方法,作用是将字符串保存在常量池中,也分为以下两种情况:

  1. 字符串常量池存在该字符串的引用,直接返回该引用
  2. 字符串常量池不存在该字符串的引用,就在常量池创建一个指向该字符串对象并将引用返回

String变量与常量做+运算时发生了什么?

public static void main(String[] args) {
        String str1 = "abc";
        String str2 = "efg";
        String str3 = "abc" + "efg";
        String str4 = str1 + str2;
        String str5 = "abcefg";
        System.out.println(str3 == str4);
        System.out.println(str3 == str5);
        System.out.println(str4 == str5);
    }

在这里插入图片描述
为什么会出现这种情况呢?
因为对于编译器可以确定的字符串,也就是字符串常量,JVM会将其存入字符串常量池。也会将拼接后的字符串常量在编译器就存入字符串常量池,得益于编译器优化。

例如:

		String str3 = "abc" + "efg";
        String str3 = "abcefg";

大家需要注意不是所有常量都可以进行折叠(常量折叠是将常量表达式的值嵌入在最终代码中,这是Javac编译器堆源代码做的优化),只有在编译器可以确定的常量才可以:

  • final修饰的基本数据类型和字符串变量
  • 基本数据类型基于字符串常量

上述str4是引用的值在编译器是无法确定的,所以我们编译器无法对其进行优化
它相当于:

String str4 = new StringBuilder().append(str1).append(str2).toString();

但是如果我们给字符串变量加上final修饰后,就可以让编译器将其当作常量来处理

public static void main(String[] args) {
        final String str1 = "abc";
        final String str2 = "efg";
        String str3 = "abc" + "efg";
        String str4 = str1 + str2;
        String str5 = "abcefg";
        System.out.println(str3 == str4);
        System.out.println(str3 == str5);
        System.out.println(str4 == str5);
    }

在这里插入图片描述
我们给str1,str2加上final修饰后,String会被编译器当作常量进行处理,在编译期就可以确定它的值,相当于常量访问。

22.方法常见知识

静态方法为什么不能调用非静态成员?
1.静态方法是属于类的,在类加载的时候就会分配内存,可以通过类名直接访问。而非静态成员是属于实例对象的,只有对象实例化之后才存在,需要通过类的实例对象去访问
2.在类的非静态成员不存在时静态方法就已经存在了,此时调用内存中不存在的非静态成员是非法的

静态方法和实例方法有什么不同?
1.调用方式:
在调用静态方法时,可以使用类名.方法名 ,也可以使用对象.方法名 的方式,而实例方法只能使用后面这种方法,静态方法不依赖对象
但是我们为了避免混淆静态方法和非静态方法,我们一般建议使用类名.方法名的方式来调用静态方法

2.访问类成员是否存在限制
静态方法在访问本类成员时,只需要访问静态成员和方法,不能访问实例成员和方法。

什么是可变长参数?
从Java5开始,Java支持可变长参数,也就是允许调用方法时可以传入不定长度的参数,比如:

public static int add(int... n) {
        int sum = 0;
        for (int i : n) {
            sum += i;
        }
        return sum;
    }

在这里插入图片描述
需要注意的是,可变参数只能作为函数的最后一个参数,前面可以有任意个参数,包含0个

public static int add(String name,int... n) {
}

如果方法重载了,优先调用固定参数还是可变参数呢?
这里是会优先匹配固定参数的方法,因为固定参数的方法匹配度更高

public static int add(int n) {
        return 0;
    }
    public static int add(int... n) {
        return 1;
    }

在这里插入图片描述
实际上,我们Java中的可变参数在编译后会被转换成一个数组

23.数值运算精度问题

为什么浮点数运算的时候会有精度丢失问题?

public static void main(String[] args) {
        float a = 2.6f - 1.7f;
        float b = 1.6f - 0.7f;
        System.out.println(a);
        System.out.println(b);
        System.out.println(a == b);
    }

在这里插入图片描述
与计算机在保存浮点数的方式有关系。我们计算机是二进制表示的,计算一个数字时宽度是有限的,无限循环的小树存储在计算机时只能被截断,这也是为什么浮点数没有办法用二进制精确表示

如何解决浮点数运算精度丢失问题?
我们可以使用BigDecimal来实现对浮点数的运算,大部分对运算精度要求比较高的业务场景,都是通过BigDecimal来做的

public static void main(String[] args) {
        BigDecimal a = new BigDecimal("3.0");
        BigDecimal b = new BigDecimal("2.0");
        BigDecimal c = new BigDecimal("1.0");
        System.out.println(a.subtract(b));
        System.out.println(b.subtract(c));
        System.out.println(a.subtract(b).equals(b.subtract(c)));
    }

在这里插入图片描述
超过long整型的数据应该如何表示?
在Java中,64位long整型是最大的整型类型,但如果超过这个范围就会有数值溢出的风险

public static void main(String[] args) {
        long a = Long.MAX_VALUE;
        System.out.println(a+1);
    }

在这里插入图片描述
我们可以使用BigInteger来表示:

public static void main(String[] args) {
        BigInteger a = new BigInteger("111111111111111111111111111111111111111");
        BigInteger b = new BigInteger("111111111111111111111111111111111111111");
        System.out.println(a.add(b));
    }

在这里插入图片描述
在这里插入图片描述
我们可以发现BigInteger内部使用int[ ]数组来存储任意大小的整型数据,但BigInteger的运算效率相对较低

24.异常

Java(Throwable)的结构可分为三种类型:错误(Error)、被检查的异常(CheckedException)、运行时异常(RuntimeException)
在这里插入图片描述
Exception和Error有什么关系?
Java中,所有的异常都有一个公共祖先:java.lang包中的Throwable类,而Exception和Error为Throwable类中两个重要子类:

Error: 当资源不足,约束失败,或者是其他程序无法继续运行的条件发生时,就产生Error,程序无法处理的错误。比如:虚拟机内存不够错误(OutOfMemoryError)、虚拟机运行错误(Virtual MachineError)、类加载错误(NoClassDefFoundError)等。当发生这些异常时,JVM会选择终止该线程

Exception: 程序本身可以处理的异常,我们可以通过try - catch进行捕获异常,Exception可以分为必须处理的受检查异常(Checked Exception) 和 可以不处理的非受查异常(Unchecked Exception)

Checked Exception 和 Unchecked Exception 有什么区别?

Unchecked Exception: 该种类型的错误,Java编译器不会检查,当出现该种异常时,即使没有通过throws声明抛出它,也没有使用try-catch语句捕捉它,仍然会编译通过。
RuntimeException及子类都统称为非受查异常,比如:

  • NullPointerException:空指针异常
  • illegalArgumentException:参数异常
  • ArrayIndexOutOfBoundsException:数组越界异常
  • ClassCastException:类型转换异常
  • ArithmeticException:算数异常
  • SecurityException:安全异常
  • IllegalStateException:非法状态异常
  • UnsupportedOperationException:不支持的操作异常
  • NumberFormatException:数值格式异常
    在这里插入图片描述

Checked Exception: 受查异常,如果没有被catch或者throws处理的话,就无法通过编译器。除了RuntimeException及子类外,其他Exception类及子类都属于受查异常,常见的有:

  • ClassNotFoundException
  • IOException
  • FileNotFoundException
  • SQLException

总结:受查异常通常不是程序引起的错误,比如:读取文件时文件不存在引发的:FileNotFoundException。而非受查异常通常是因为糟糕的编程引起的,比如:在没有确保对象引用非空时就使用而引起的:NullPointerException

Throwable有哪些常见方法?
在这里插入图片描述

  • String getMessage():返回异常的简要描述
  • String toString():返回异常的详细信息
  • void printStackTrace():在控制台打印Throwable对象封装的异常信息
  • String getLocalizedMessage():返回异常对象的本地化信息。使用Throwable子类重写该方法,可以生成本地化信息。如果没有重写,那么与getMessage()返回结果相同

25.OOM你遇到过哪些情况,SOF你遇到过哪些情况

OOM
1.OutOfMemoryError异常:
除了程序计算器外,虚拟机内存的其他几个区域都有可能发生OOM异常的可能。
Java Heap溢出:一般异常信息为java.lang.OutOfMemoryError:Java heap spacess
Java堆用于存储对象实例,只要我们不断地创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制来清理这些对象,就会在对象数量达到最大堆容量限制后产生内存溢出异常,当出现该异常时,我们一般先通过内存映像分析工具(Eclipse Memory Analyzer) 堆dump除了的对转存快照进行分析,重点是确认内存中的对象是否是必要的,分清是因为内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)
如果内存泄漏,可进一步通过工具查看泄露对象到GCRoots的引用链,排查是怎样的路径与GCRoots关联导致垃圾收集器无法自动回收

如果不存在泄露,就检查虚拟机参数(-Xmx与-Xms)是否合适

2.虚拟机和本地方法栈溢出:
如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError,如果虚拟机在扩展栈时无法申请到足够的内存空间,抛出OutOfMemoryError异常

3.方法区溢出:
方法区用于存放Class的相关信息,如类名、访问修饰符、字段描述、方法描述等。异常信息为:java.lang.OutOfMemoryError:PermGenspace,有可能是方法区保存的class对象没有被及时回收或者class信息占用的内存超出了我们的配置

方法区溢出也是一种我们常见的内存溢出异常,一个类如果要被垃圾收集器回收,判定条件是比较苛刻的。

SOF(StackOverflow栈溢出溢出):
该异常一般当应用程序递归太深而发生堆栈溢出时会抛出该错误

需要注意的是,栈溢出错误往往意味着代码存在问题,过于深的调用层次可能会导致性能和可维护性问题。因此,在解决 StackOverflowError 时,建议对代码进行仔细检查和优化,确保代码的健壮性和性能。

26.语法糖

语法糖:语法糖是指编程语言为了方便程序员开发而设计的一种特殊语法,这种语法对编译语言的功能并没有影响,实现一个相同的功能,基于语法糖写出的代码往往更加简洁。
常见的语法糖有哪些:
泛型、lambda表达式、自动拆装箱、try-with-resources语法、变长参数、增强for循环等

比如:Java中的for-each

public static void main(String[] args) {
        int[] arr = {1,2,3,4,5,6,7};
        for (int i : arr) {
            System.out.println(i);
        }
    }

我们的JVM本身是不能识别语法糖的,Java的语法糖要想被正确执行,需要先通过编译器进行解糖,在编译阶段讲语法糖转为JVM认识的语法。也说明真正支持语法糖的是Java编译器而不是JVM,在compile()中有一部就是desugar(),复负责语法糖解糖的。

27.Java反射的作用与原理

反射:在运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意个对象,都能够调用它的任意一个方法。在java中,只要给定类的名字,就可以通过反射来获得类的所有信息。这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制

哪里会用到反射机制?
jdbc就是典型的反射:

Class.for("com.mysql.jdbc.Drivice.class");//加载MySQL的驱动类

这就是反射。我们大部分都在写业务代码,很少接触到直接使用反射的场景,这并不代表反射没有用,相反,正是因为反射,我们才能这么轻松的使用各种框架。Spring/Spring Boot、MyBatis等框架中都大量使用了反射机制

反射的实现方式:

  1. 获取Class对象:一共有四种方法: 1) Class.forName(“类路径”);2) 类名.class;3)对象名.getClass();4)基本类型的包装类,可以调用包装类的Type属性类获取该包装类的Class对象
Class<?> clazz = Class.forName("com.example.zd")
  1. 获取类的字段:getField(“filename”)方法:可以获取public修饰的字段。getDeclaredField(“filedName”)可以获取指定名称的字段,无论修饰符是什么
Field field = clazz.getDeclaredField("fieldName")
  1. 获取类的方法信息:getMethod(“methodName”,parameterTypes),可获取指定名称和参数类型的公共(public)方法;使用getDeclaredMethod(“methodName”,parameterTypes)方法,可以获取指定名称和参数类型的方法,无论修饰符是什么
Method method = clazz.getDeclaredMethod("methodName", String.class, int.class)
  1. 创建对象实例:使用newInstance()方法,可以通过无参构造函数创建一个对象实例,例如:
Object obj = clazz.newInstance()

使用getConstructor(parameterTypes).newInstacne(arguments)方法可以通过指定构造方法和参数创建对象

Constructor<?> constructor = clazz.getConstructor(String.class, int.class); 
Object obj = constructor.newInstance("arg1", 123)

反射的优缺点:
反射可以让我们的代码更加灵活、为各种框架提供开箱即用的功能提供了便利。不过,反射让我们在运行时有了分析操作类的能力同时,也增加了安全问题,比如:可以无视泛型参数的安全检查(泛型参数的安全检查发生在编译时)。另外,反射的性能也要稍微差点,不过对框架影响不大

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

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

相关文章

【STM32单片机】STM32控制SG90舵机的PWM部分参数的设置解答

STM32控制SG90舵机的PWM部分参数的设置解答 一、舵机控制要知道的知识二、PWM的参数要怎么计算1、为什么要分频呢&#xff1f;2、为什么选择TIM_OCMode_PWM1呢&#xff1f; 每天进步一点点 笔记仅供自学&#xff0c;用来回看复习&#xff0c;不一定适合你&#xff0c;如有错误请…

论青春线上书屋的设计与实现(论文+源码)_kaic

目 录 摘 要 III 第一章 绪论 1 1.1本课题研究背景与意义 1 1.2本课题国内外研究现状 1 第二章 开发技术介绍 3 2.1JDK的安装与配置 3 2.2HTML技术 3 2.3MySQL数据库管理系统 4 2.4JDBC的使用 4 第三章 系统分析 5 3.1系统的设计要求 5 3.2系…

交通 | 动态设施选址问题

论文解读 陈迎新&#xff0c;柯斯琪&#xff0c;曲晨辉&#xff0c;张景琪 编者按 本次解读的文章是Transportation Science 2017年的 《在日益增长的市场中&#xff0c;动态设施选址问题的连续逼近方法》&#xff08;Wang, X., Lim, M. K., & Ouyang, Y. (2017). A conti…

空元素不占用位置处理

一. 问题场景&#xff1a; 如果将一个元素的CSS设置为margin-right: 10px&#xff0c;即使这个元素为空&#xff0c;那么这10px依然存在&#xff0c;效果如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8&q…

【编译原理】词法分析程序设计(C语言)

目录 一、实验内容二、实验原理三、结果分析四、源代码一、实验内容 给定下表所示的一个简单语言的词法规则描述完成以下任务: (1)画出识别该语言词法规则的状态转换图; (2)依据状态转换图,设计并编制词法分析程序,实现从输入源程序中,识别出各类单词,即关键字、标识…

打工人如何利用自动化实现职场突围

作为优秀的打工人&#xff0c;如果可以将办公中的重复性、繁琐性、低效性工作自动化&#xff0c;那么将省去许多日常工作。许亚宁就是这样一个优秀的打工人&#xff0c;善于使用各类自动化工具来提升工作效率&#xff0c;上周的直播他分享了如何利用自动化工具&#xff0c;实现…

设计原则-依赖倒置原则

如同人体结构一样&#xff0c;项目代码也是需要有结构的&#xff0c;如原子逻辑块(不可再分代码块)、方法、类、模块等。结构要么是由成熟的框架搭建起来&#xff0c;要么自己手动划分&#xff0c;但是都需要保证下层模块的变动时不会影响上层模块。注意&#xff1a;这里所说的…

missing-semester————2

文章目录 shell 脚本赋值语法函数逻辑运算符命令替换进程替换通配 shell工具查看命令如何使用查找文件查找代码查找shell指令 shell 脚本 很多情况下需要执行一系列的操作并使用条件或循环这样的控制流。 大多数shell都有自己的一套脚本语言&#xff0c;包括变量、控制流和自…

006-Logstash、FileBeat、ELK整合详解

目录 ELK架构背景需求架构logstash核心概念配置文件结构插件Codec Plugin-Multiline输出&#xff1a;elasticsearch输入&#xff1a;jdbcGrok插件Grok语法 mutate插件Date插件 Logstash Queue Beats配置步骤 ELK整合步骤1&#xff1a;日志采集步骤2&#xff1a;配置Logstash接收…

ChatGLM2体验+ubuntu18.04LTS+CPU版本

ChatGPT在自然语言处理领域的表现让人振奋&#xff0c;开启了大模型在通用人工智能领域的大门。 许多工作随之跟进&#xff0c;并开源&#xff0c;凭借相对小的参数量达到近似GPT的效果&#xff0c;包括LLama&#xff0c;alpace等。 其中LLama训练语料主要选择英语&#xff0…

Docker内部工作原理:容器化背后的魔法

Docker内部工作原理是怎样的&#xff1f; 现在我们知道了Docker是什么以及它提供了哪些好处&#xff0c;让我们逐个重要的细节来了解。 什么是容器&#xff1f;它们是如何工作的&#xff1f; 在深入研究Docker的内部机制之前&#xff0c;我们首先要了解容器的概念。简单地说&am…

在工作与生活中保持情绪稳定的艺术

强烈的情绪波动&#xff1a;工作中的挑战 在我的职业生涯中&#xff0c;我经历过许多情绪波动的时刻。其中一个最具挑战性的时刻是在我负责一个重要项目的时候。我需要在短时间内完成大量的工作&#xff0c;同时还要管理一个由不同背景和技能的人组成的团队。这个项目的压力让…

leetcode-704. 二分查找

leetcode-704. 二分查找 文章目录 leetcode-704. 二分查找一.题目描述二.第1次代码提交(非二分查找)三.第2次代码提交(非二分查找&#xff0c;std::find和std::distance)四.第3次代码提交(二分查找)五.关于C中int型的奇数除以2 一.题目描述 二.第1次代码提交(非二分查找) clas…

Openlayers实战:drawstart,drawend 绘制交互应用示例

Openlayers地图中,绘制一个多边形是非常见的一个应用,涉及到交互会在绘制开始 drawstart 和绘制结束drawend时,通常会在绘制完成后取消继续绘制,然后提出feature的一些信息。 效果图 源代码 /* * @Author: 大剑师兰特(xiaozhuanlan),还是大剑师兰特(CSDN) * @此源代…

B066-基础环境-前后端整合 批量删除 下拉 级联 增改

目录 批量删除页面调整普通属性的新增和修改引用属性的新增和修改管理员下拉列表部门树 见文档与代码 cd 子项目 运行前端项目 页面布局分析 批量删除 点击多选 - 改变data - 点击批量删除 - 带参数发请求 页面调整 略 普通属性的新增和修改 新增按钮&#xff1a;点击…

【MySQL系列】在Centos7环境安装MySQL

「前言」文章内容大致是在Centos7环境安装MySQL&#xff0c;演示安装的版本为5.7 「归属专栏」MySQL 「主页链接」个人主页 「笔者」枫叶先生(fy) 「枫叶先生有点文青病」「句子分享」 浮生梦&#xff0c;三生渺渺&#xff0c; 因缘无踪&#xff0c;虽堪恋&#xff0c;何必…

回归预测 | MATLAB实现CNN-BiGRU-Attention多输入单输出回归预测

回归预测 | MATLAB实现CNN-BiGRU-Attention多输入单输出回归预测 目录 回归预测 | MATLAB实现CNN-BiGRU-Attention多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 MATLAB实现CNN-BiGRU-Attention多输入单输出回归预测&#xff0c;CNN-GRU结合…

Vision Transformer(VIT)论文解读及实现

1 论文解读 paper&#xff1a;VIT 1.1 VIT模型架构如下图所示&#xff1a; 图片原始输入维度 H * W * C在H和W按像素P切分&#xff0c;则H 、W可分割为 NPP, NHW/(PP)&#xff0c;N为输入transform序列的长度。 x ∈ R H ∗ W ∗ C > x ∈ R N ∗ P 2 ∗ C x \in R^{H*W…

第三章 SSD存储介质:闪存 3.1

3.1 闪存物理结构 闪存芯片从小到大依此是由&#xff1a;cell&#xff08;单元&#xff09;、page&#xff08;页&#xff09;、block&#xff08;块&#xff09;、plane&#xff08;平面&#xff09;、die&#xff08;核心&#xff09;、NAND flash&#xff08;闪存芯片&#…

Python find()函数使用详解

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;小白零基础《Python入门到精通》 find 1、指定检索位置2、参数为负数3、超出范围3、find()和index()的区别&#x…