面试踩过的坑

1、 “==”和equals 的区别

  • “==”是运算符,如果是基本数据类型,则比较存储的值;如果是引用数据类型,则比较所指向对象的地址值
  • equals是Object的方法,比较的是所指向的对象的地址值,一般情况下,重写之后比较的是对象的值

ps:问的是:int a = 3;if(a==3){},比较的是值还是内存地址。这个忘了,想到另一个概念整数常量池,是自己想多了,和整数常量池的问题记混了,看到a==3,就想着3不会在内存中新建。傻了,这里再说下在方法中int a = 3。a和3(基本类型)都是保存在栈中的,引用类型对象才会在栈中存堆的内存地址。所以==比较基本类型时只能比较值,没有什么内存地址给你比较。

下面代码

Integer a = 3;//自动装箱:等价于 Integer.valueOf(3)
System.out.println(a==3);
Integer b = new Integer(4);
System.out.println(b==4);

结果是true ,true,虽然Integer是个整数对象,不是基本类型,按理说要比较内存地址,这里应该比较内存了,但是Integer和int一起运算时会拆包成基本类型,所以比的还是值。

Integer p = new Integer(5);
Integer q = new Integer(5);
System.out.println(p == q);  // 输出 false(显式创建新对象)

这里比较的都是引用类型,比较就是内存地址了。 

2、整数常量池

Integer  i = 123;
Integer  i2 = 123;
System.out.println(i==i2);Integer  i3 = 129;
Integer  i4 = 129;
System.out.println(i3==i4);

输出结果:

true
false

解释如下:

整数常量池的作用场景

  1. 自动装箱(Autoboxing)

    • 当将基本类型 int 转换为包装类 Integer 时(比如赋值给 Integer 变量,或存入集合类),Java 会尝试复用常量池中已缓存的 Integer 对象,而不是每次都创建新对象。

    • 例如:

      Integer a = 100; // 自动装箱,使用常量池中的对象 Integer b = 100; System.out.println(a == b); // 输出 true(同一对象)

  2. 手动创建 Integer 对象

    • 如果直接通过 new Integer() 创建对象,会强制生成新实例,绕过常量池:

      Integer c = new Integer(100); Integer d = new Integer(100); System.out.println(c == d); // 输出 false(不同对象)
      
  3. 超出缓存范围的情况

  4. 当数值超出 -128~127 范围时,即使通过自动装箱,也会生成新对象:

    Integer e = 200;

    Integer f = 200;

    System.out.println(e == f); // 输出 false(超出缓存范围)

 整数常量池的实现原理

Java 在 Integer 类中通过静态内部类 IntegerCache 实现缓存

private static class IntegerCache {
    static final int low = -128;
    static final int high; // 默认 127,可通过 JVM 参数调整
    static final Integer[] cache;
    
    static {
        // 初始化缓存数组
        high = 127;
        cache = new Integer[(high - low) + 1];
        for (int i = 0; i < cache.length; i++) {
            cache[i] = new Integer(i - 128);
        }
    }
}

通过 Integer.valueOf(int) 方法获取 Integer 对象时,会优先从缓存中取:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + 128];
    return new Integer(i);
}

3 整数塞入map后怎么存放值的

Stdent zzw = new Stdent("zzw", 15);
Map<String ,Object> map = new HashMap<>();
map.put("stu", zzw);
Integer i =new Integer(22);
map.put("size",i);
System.out.println(map);
i =new Integer(33);
zzw.age =20;
System.out.println(map);
static class Stdent{public String name ;public int age ;public Stdent(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Stdent{" +"name='" + name + '\'' +", age=" + age +'}';}
}

结果:

{size=22, stu=Stdent{name='zzw', age=15}}
{size=22, stu=Stdent{name='zzw', age=20}}

这里为什么age变了,size没有变?

标下每个变量在内存中怎么存的

关键解释

  1. 对象存储位置

    • new Stdent("zzw", 15) 和 new Integer(22) 是对象实例,存储在堆中。

    • 它们的地址分别是 0x100 和 0x200(假设的内存地址)。

  2. 引用变量存储位置

    • zzw 和 i 是引用变量,存储在栈中。

    • 它们的值是堆中对象的地址(如 zzw = 0x100)。

  3. put 操作存储的内容

    • map.put("stu", zzw) 和 map.put("size", i) 存入的是 堆中对象的地址(即 0x100 和 0x200),而不是变量 zzw 或 i 的栈地址。

    • Map 的键值对中存储的是实际对象的引用。

然后后面改变值的时候,zzw.age =20 ,只是改变stu对象里的值,map的引用并不变,就是stu存的还是student对象在堆中的内存地址,所以后面打印的会变。那为什么map中的size的输出不变呢。因为Intger对象是final修饰的,这个对象不可以修改,i =new Integer(33);后面半句会在堆中建一个新的内存地址,然后前半句把i在栈中存的内存地址换成这个新的,但是map里存的还是之前对象的地址。所以不会输出不会变。

4、map的操作都是深拷贝还是浅拷贝?

上个例子其实可以看出来,zzw.age=20,然后map里的stu里的age也跟着变了,所以map的put方法是个浅拷贝,问了下deepseek告诉我map的操作几乎都是浅拷贝,那我想putall也是了?

Stdent zzw = new Stdent("zzw", 15);
Map<String ,Object> map = new HashMap<>();
map.put("stu", zzw);
map.put("size",22);
Map<String ,Object> map2 = new HashMap<>();
map2.putAll(map);
map.clear();
System.out.println(map);
System.out.println(map2);

结果是

{}
{size=22, stu=Stdent{name='zzw', age=15}} 

 deepseek给的解释

3. map2.putAll(map)

ok,所以clear只是清除map在堆中的信息,切断了这个map和stu和整数对象的引用。

但是map2还是没有变,不是说浅拷贝,map2和map就指向同一个内存地址.

Stdent zzw = new Stdent("zzw", 15);
Map<String ,Object> map = new HashMap<>();
map.put("stu", zzw);
map.put("size",22);
Map<String ,Object> map2 = map;
map.clear();
System.out.println(map);
System.out.println(map2);

结果:

{}
{}

再看一个

Stdent zzw = new Stdent("zzw", 15);
Map<String ,Object> map = new HashMap<>();
map.put("stu", zzw);
map.put("size",22);
Map<String ,Object> map2 = new HashMap<>();
map2.putAll(map);
Stdent zzw2 = new Stdent("zzw2", 30);
map.put("stu", zzw2);
map.put("size", 32);
System.out.println(map);
System.out.println(map2);

 结果:

{size=32, stu=Stdent{name='zzw2', age=30}}
{size=22, stu=Stdent{name='zzw', age=15}}

所以结论就是

Map<String ,Object> map2 = new HashMap<>();
map2.putAll(map);

这里有个2个关键点,1:这里我new了一个map,在堆中新建了内存地址,和之前map不是同一个了,但是2:map里面的对象没有重新new一个新的,还是复用,只是大家(map和map2)都指向这些对象的内存地址。

然后clear只是清空这个map在堆中的内容,他存的对象不回清理。

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

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

相关文章

专业软件开发全流程实践指南

作为一家拥有十余年行业积淀的专业软件开发服务提供商&#xff0c;我们见证了太多项目从无到有的全过程。今天&#xff0c;我们就用最朴实的语言&#xff0c;跟大家聊聊一个软件产品从构思到上线的完整历程。这些经验不仅适用于自建技术团队的企业&#xff0c;对正在寻找软件外…

聊透多线程编程-线程互斥与同步-12. C# Monitor类实现线程互斥

目录 一、什么是临界区&#xff1f; 二、Monitor类的用途 三、Monitor的基本用法 四、Monitor的工作原理 五、使用示例1-保护共享变量 解释&#xff1a; 六、使用示例2-线程间信号传递 解释&#xff1a; 七、注意事项 八、总结 在多线程编程中&#xff0c;线程之间的…

第R4周:LSTM-火灾温度预测

文章目录 一、前期准备工作1.导入数据2. 数据集可视化 二、构建数据集1. 数据集预处理2. 设置X, y3. 划分数据集 三、模型训练1. 构建模型2. 定义训练函数3. 定义测试函数4. 正式训练模型 四、模型评估1. Loss图片2. 调用模型进行预测3. R2值评估 总结&#xff1a; &#x1f36…

toCharArray作用

toCharArray() 是 Java 中 String 类的一个方法&#xff0c;其作用是将字符串对象转换为一个字符数组。下面为你详细介绍其用法、原理和示例。 方法定义 toCharArray() 方法在 java.lang.String 类里被定义&#xff0c;方法签名如下 public char[] toCharArray() 此方法没有…

STM32八股【6】-----CortexM3的双堆栈(MSP、PSP)设计

STM32的线程模式&#xff08;Thread Mode&#xff09;和内核模式&#xff08;Handler Mode&#xff09;以及其对应的权级和堆栈指针 线程模式&#xff1a; 正常代码执行时的模式&#xff08;如 main 函数、FreeRTOS任务&#xff09; 可以是特权级&#xff08;使用MSP&#xff…

驱动支持的最高CUDA版本与实际安装的Runtime版本

查看电脑上安装的CUDA版本的多种方法&#xff0c;适用于不同系统和场景。 方法一&#xff1a;通过命令行工具 1. 查看CUDA Driver API版本&#xff08;显卡驱动支持的CUDA版本&#xff09; 命令&#xff1a;nvidia-smi操作&#xff1a; 打开终端&#xff08;Windows为CMD/Pow…

Python CT图像预处理——基于ITK-SNAP

Python CT图像预处理——nii格式读取、重采样、窗宽窗位设置_python读取nii-CSDN博客 基于原文指出以下几个问题&#xff1a;文件路径设置模糊&#xff1b;nilabel里面使用的get_data() 方法已经过时&#xff1b;需要导入scikit-image&#xff0c;还要导入一个matplotlib。 一…

【MQ篇】RabbitMQ之消息持久化!

目录 一、 交换机持久化 (Exchange Persistence)二、 队列持久化 (Queue Persistence)三、 消息持久化 (Message Persistence)四、 持久化的“黄金三角” &#x1f531;&#xff1a;三者缺一不可&#xff01;五、 来&#xff0c;完整的代码示例&#xff08;整合持久化和确认机制…

[AI技术(二)]JSONRPC协议MCPRAGAgent

Agent概述(一) AI技术基础(一) JSON-RPC 2.0 协议详解 JSON-RPC 2.0 是一种基于 JSON 的轻量级远程过程调用(RPC)协议,旨在简化跨语言、跨平台的远程通信。以下从协议特性、核心结构、错误处理、批量请求等角度进行详细解析: 一、协议概述 1. 设计原则 • 简单性:…

LeetCode238_除自身以外数组的乘积

LeetCode238_除自身以外数组的乘积 标签&#xff1a;#数组 #前缀和Ⅰ. 题目Ⅱ. 示例0. 个人方法一&#xff1a;暴力循环嵌套0. 个人方法二&#xff1a;前缀和后缀分别求积 标签&#xff1a;#数组 #前缀和 Ⅰ. 题目 给你一个整数数组 nums&#xff0c;返回 数组 answer &#…

算法笔记.spfa算法(bellman-ford算法的改进)

题目&#xff1a;&#xff08;来源于AcWing&#xff09; 给定一个 n 个点 m 条边的有向图&#xff0c;图中可能存在重边和自环&#xff0c; 边权可能为负数。 请你求出 1 号点到 n 号点的最短距离&#xff0c;如果无法从 1 号点走到 n 号点&#xff0c;则输出 impossible。 …

07 Python 字符串全解析

文章目录 一. 字符串的定义二. 字符串的基本用法1. 访问字符串中的字符2. 字符串切片3. 字符串拼接4. 字符串重复5.字符串比较6.字符串成员运算 三. 字符串的常用方法1. len() 函数2. upper() 和 lower() 方法3. strip() 方法4. replace() 方法5. split() 方法 四. 字符串的进阶…

Java集成Zxing和OpenCV实现二维码生成与识别工具类

Java集成Zxing和OpenCV实现二维码生成与识别工具类 本文将介绍如何使用Java集成Zxing和OpenCV库&#xff0c;实现二维码的生成和识别功能。识别方法支持多种输入形式&#xff0c;包括File对象、文件路径和Base64编码。 一、环境准备 添加Maven依赖 <dependencies><…

【专题刷题】二分查找(二)

&#x1f4dd;前言说明&#xff1a; 本专栏主要记录本人的基础算法学习以及LeetCode刷题记录&#xff0c;按专题划分每题主要记录&#xff1a;&#xff08;1&#xff09;本人解法 本人屎山代码&#xff1b;&#xff08;2&#xff09;优质解法 优质代码&#xff1b;&#xff…

Java—ThreadLocal底层实现原理

首先&#xff0c;ThreadLocal 本身并不提供存储数据的功能&#xff0c;当我们操作 ThreadLocal 的时候&#xff0c;实际上操作线程对象的一个名为 threadLocals 成员变量。这个成员变量的类型是 ThreadLocal 的一个内部类 ThreadLocalMap&#xff0c;它是真正用来存储数据的容器…

Elasticsearch(ES)中的脚本(Script)

文章目录 一. 脚本是什么&#xff1f;1. lang&#xff08;脚本语言&#xff09;2. source&#xff08;脚本代码&#xff09;3. params&#xff08;参数&#xff09;4. id&#xff08;存储脚本的标识符&#xff09;5. stored&#xff08;是否为存储脚本&#xff09;6. script 的…

客户联络中心能力与客户匹配方式

在数字化时代&#xff0c;客户联络中心作为企业与客户沟通的核心枢纽&#xff0c;其服务能力与客户需求的精准匹配至关重要。随着客户期望的不断提升&#xff0c;传统的“一刀切”服务模式已难以满足个性化需求&#xff0c;如何通过智能化的手段实现服务能力与客户的高效匹配&a…

深入理解网络原理:UDP协议详解

在计算机网络中&#xff0c;数据的传输是通过各种协议实现的&#xff0c;其中用户数据报协议&#xff08;UDP&#xff0c;User Datagram Protocol&#xff09;作为一种重要的传输层协议&#xff0c;广泛应用于实时通信、视频流、在线游戏等场景。本文将深入探讨UDP协议的特性、…

vscode切换Python环境

跑深度学习项目通常需要切换python环境&#xff0c;下面介绍如何在vscode切换python环境&#xff1a; 1.点击vscode界面左上角 2.在弹出框选择对应kernel

【MCP Node.js SDK 全栈进阶指南】中级篇(4):MCP错误处理与日志系统

前言 随着MCP应用的规模和复杂性增长,错误处理与日志系统的重要性也日益凸显。一个健壮的错误处理策略和高效的日志系统不仅可以帮助开发者快速定位和解决问题,还能提高应用的可靠性和可维护性。本文作为中级篇的第四篇,将深入探讨MCP TypeScript-SDK中的错误处理与日志系统…