文档章节

操蛋的面试题(更新)

汪纬
 汪纬
发布于 2015/12/21 21:47
字数 686
阅读 231
收藏 2
String ww ="hello world";
String ww1 = "hello"+new String(" world");
String ww2 = "hello world";
String ww3 = "hello"+" world";
System.out.println(ww.equals(ww1));
System.out.println(ww==ww1);
System.out.println(ww==ww2);
System.out.println(ww==ww3);
true
false
true
true


谁能告诉我第二个为什么是false??

-------------------------------------------------------------------------------------------------------

华丽的分割线

-------------------------------------------------------------------------------------------------------

百度了一天,我大致总结一下:

Java内存分配:

1. 寄存器:我们在程序中无法控制
2. 栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中
3. 堆:存放用new产生的数据
4. 静态域:存放在对象中用static定义的静态成员
5. 常量池:存放常量
6. 非RAM(随机存取存储器)存储:硬盘等永久存储空间

String是一个特殊的包装类数据。可以用: 

String ww ="hello world";
String ww1 = new String("hello world");


两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。 
而第二种是先在栈中创建一个对String类的对象引用变量str,然后通过符号引用去字符串常量池里找有没有"hello world",如果没有,则将"hello world"存放进字符串常量池,并令str指向”hello world”,如果已经有”hello world” 则直接令str指向“hello world”。 


最烦就是这个不太理解

String ww ="hello world";
String ww1 = "hello"+new String(" world");

ww 还是常量池中"hello world”的引用,ww1因为后半部分 new String(” world”)无法在编译期确定,所以也是一个新创建对象”hello world””的引用,这是网上的说法

后面我找到javap -c 命令查看java真正生成的指令,目前没找到汇编代码:

java指令java指令

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #16                 // String hello world
       2: astore_1      
       3: new           #18                 // class java/lang/StringBuilder
       6: dup           
       7: ldc           #20                 // String hello
       9: invokespecial #22                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      12: new           #25                 // class java/lang/String
      15: dup           
      16: ldc           #27                 // String  world
      18: invokespecial #29                 // Method java/lang/String."<init>":(Ljava/lang/String;)V
      21: invokevirtual #30                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      24: invokevirtual #34                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      27: astore_2      
      28: return        
}

ldc

将int, float或String型常量值从常量池中推送至栈顶

String ww ="hello world";

所以这个是放在常量池中的

其余的操作我YY下啊

先是从常量池中取出 "hello",然后创建一个StringBuilder,把hello作为参数放里面

StringBuilder sb = new StringBuilder("hello");

然后从常量池中取出 " world",赋值给一个String对面,

String new = new String(" world");

然后sb.append(new);

String ww1= sb.toString();

所以ww1是一个String对面的引用和ww常量池中的引用是不一样的

终于明白了,然并卵,面试失败

© 著作权归作者所有

汪纬

汪纬

粉丝 11
博文 649
码字总数 39577
作品 0
崇明
后端工程师
私信 提问
加载中

评论(19)

汪纬
汪纬

引用来自“yogazx”的评论

new String 相当于创建了两个对象,一个在常量池,一个在堆空间,这里相当于返回的是堆空间的内存地址,而直接string ww只在常量池中创建,两者不一致,所以false

如果常量池中的数据加上堆中的数据后字符串存放在哪?
y
yogazx
new String 相当于创建了两个对象,一个在常量池,一个在堆空间,这里相当于返回的是堆空间的内存地址,而直接string ww只在常量池中创建,两者不一致,所以false
HOIY
HOIY
确实是false
啦啦啦拉拉
啦啦啦拉拉
equal是怎么对比来着?字符串都是字节数组
汪纬
汪纬

引用来自“我欲乘风90”的评论

因为做了运算会开辟新的空间

好像别的就没做运算一样
汪纬
汪纬

引用来自“我欲乘风90”的评论

你要是计算机专业的你们老师会不会被你气死。。。

呵呵
我欲乘风90
我欲乘风90
你要是计算机专业的你们老师会不会被你气死。。。
我欲乘风90
我欲乘风90
因为做了运算会开辟新的空间
会哭的鳄鱼
会哭的鳄鱼
按java的基本原理,"hello"+" world"其实是两个String对象,然后,再新建第三个String对象作为最后的结果赋值给你定义的变量。但前面说过,jvm编译器,其实是会优化编译的,当jvm发现你前面引用了"hello world",而这个简单的两个String合并也正好是那个,那他为了优化内存,也同时使用了那个内存地址。但你ww1就不是,因为你表达式里有一个new String,则jvm不会强制进行内存优化。就按照常规的java的Srring合并进行计算了,当然就是一个新的内存地址了。所以,如果你的代码里有大量的字符串合并,一定要用StringBuilder这个类,这个类不会重复创建很多String对象,就不会导致过多的内存消耗,如果是在要求效率好高的场合,比如tcp通信,就可以提高效率,又不会导致gc的频繁执行,提高程序效率。
汪纬
汪纬

引用来自“会哭的鳄鱼”的评论

你ww,ww2,ww3其实都是对常量"hello world"的引用。这个常量在内存中也有一个对应的地址。并且jvm为了优化内存,你在不同代码行里引用的"hello world"其实都是对一个内存地址的引用,所以你的ww==ww2,ww==ww3都是true因为这三个其实指向同一个内存地址。但ww==ww2就是false,因为你是用new出来一个新的String变量,就是一个新的内存地址。当然返回false。所以String的==是比较内存地址,就是比较两个String是否是同一个内存地址。而真正的比较两个String的内容是否相等,必须使用equals。明白了吧。

高人,然而并没有解释+号操作符
微软ASP.NET 电商网站开发实战 MVC6 +HTML5 +WCF+WebAPI+NoSQL+mongoDB+Redis+Core视频 代码 面试题

《微软ASP.NET 电商网站开发实战 MVC6 +HTML5 +WCF+WebAPI+NoSQL+mongoDB+Redis+Core 视频 代码 面试题 》下载网盘:https://yunpan.cn/cP7SNIjgJYYjA 访问密码 7fc6 微软特邀讲师 徐雷Frank...

frankxulei
2016/06/23
0
0
BAT机器学习面试题及解析(301-305题)

本系列作为国内首个AI题库,囊括绝大部分机器学习和深度学习的笔试面试题、知识点,可以作为机器学习自测题,也可以当做查漏补缺的资料库。七月在线AI题库(网页版及APP版)见“阅读原文” ...

t7sfokzord1jaymsfk4
2017/12/29
0
0
2018 前端面试准备

前端面试常见问题按知识点分类整理 前端面试常考问题整理,按模块知识点分类,持续完善中... Front-end-Developer-Questions by Modules and knowledge 前端面试经典问题:CSS 中居中的几种方...

掘金官方
2017/12/14
0
0
金九银十,史上最强 Java 面试题整理。

以下会重新整理所有 Java 系列面试题答案、及各大互联网公司的面试经验,会从以下几个方面汇总,本文会长期更新。 Java 面试篇 史上最全 Java 面试题,带全部答案 史上最全 69 道 Spring 面试...

Java技术栈
2018/09/13
0
0
Git仓库操作命令

创建仓库 在当前目录执行,会生成目录文件,这个和SVN一致。 提交到仓库 :表示提交描述,必须要填。 添加到远端仓库 推送到远端仓库 克隆仓库 直接从远端把代码克隆下来。 仓库状态 仓库更新...

架构之路
2017/11/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Android双向绑定原理简述

Android双向绑定原理简述 双向绑定涉及两个部分,即将业务状态的变化传递给UI,以及将用户输入信息传递给业务模型。 首先我们来看业务状态是如何传递给UI的。开启dataBinding后,编译器为布局...

tommwq
今天
4
0
Spring系列教程八: Spring实现事务的两种方式

一、 Spring事务概念: 事务是一系列的动作,它们综合在一起才是一个完整的工作单元,这些动作必须全部完成,如果有一个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发生过一样。...

我叫小糖主
今天
9
0
CentOS 的基本使用

1. 使用 sudo 命令, 可以以 root 身份执行命令, 必须要在 /etc/sudoers 中定义普通用户 2. 设置 阿里云 yum 镜像, 参考 https://opsx.alibaba.com/mirror # 备份mv /etc/yum.repos.d/CentO...

北漂的我
昨天
5
0
Proxmox VE技巧 移除PVE “没有有效订阅” 的弹窗提示

登陆的时候提示没有有效的订阅You do not have a valid subscription for this server. Please visit www.proxmox.com to get a list of available options. 用的是免费版的,所以每次都提示......

以谁为师
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部