astore

工作10年后,再看String s = new String("xyz") 创建了几个对象?

限于喜欢 提交于 2020-09-26 12:04:50
这个问题相信每个学习java的同学都不陌生,作为一个经典的面试题,到现在工作这么多年了我真是认为挺操蛋的一个问题,在网上到现在你仍然可以看见很多讨论这个问题的人,其中不乏工作很多年的人都有争论,我认为还是有必要来说一说这个问题的。 从方法区说起 常量池存在于方法区,而方法区在jdk1.7版本前后改变比较大,所以还是先来说说方法区的演变。 在jdk1.7版本之前,常量池存在于方法区,方法区是堆的一个逻辑部分,他有一个名字叫做 非堆 。 1.7版本把字符串常量池放到了堆中。 而在1.8以后,则是移除了永久代,方法区概念保留,方法区的实现改为了元空间,常量池还是在堆中。 为什么要说方法区的改变,只是为了文章接下来的内容不会由于JDK的版本而产生分歧,接下来内容都会以jdk1.8版本作为基础来讨论。 String s = new String("xyz"); 先来一段代码 public class Test { public static void main(String[] args) { String s = "xyz"; } } 接着我们javac编译代码,然后用javap来反编译,执行javap -c Test 从结果来看,ldc命令 在常量池中创建了一个"xyz"的对象,然后把他推至操作数栈顶 ,然后astore保存到局部变量,return返回。 接着看第二段面试题中的代码

虚拟机字节码指令表

安稳与你 提交于 2020-08-19 05:34:56
虚拟机字节码指令表收藏学习备用 字节码 助记符 指令含义 0x00 nop 什么都不做 0x01 aconst_null 将null推送至栈顶 0x02 iconst_m1 将int型-1推送至栈顶 0x03 iconst_0 将int型0推送至栈顶 0x04 iconst_1 将int型1推送至栈顶 0x05 iconst_2 将int型2推送至栈顶 0x06 iconst_3 将int型3推送至栈顶 0x07 iconst_4 将int型4推送至栈顶 0x08 iconst_5 将int型5推送至栈顶 0x09 lconst_0 将long型0推送至栈顶 0x0a lconst_1 将long型1推送至栈顶 0x0b fconst_0 将float型0推送至栈顶 0x0c fconst_1 将float型1推送至栈顶 0x0d fconst_2 将float型2推送至栈顶 0x0e dconst_0 将double型0推送至栈顶 0x0f dconst_1 将double型1推送至栈顶 0x10 bipush 将单字节的常量值(-128~127)推送至栈顶 0x11 sipush 将一个短整型常量值(-32768~32767)推送至栈顶 0x12 ldc 将int, float或String型常量值从常量池中推送至栈顶 0x13 ldc_w 将int,

java.lang.String 的 + 号操作到底做了什么?

生来就可爱ヽ(ⅴ<●) 提交于 2020-08-15 04:45:28
作者:丶Pz https://www.cnblogs.com/panzi/p/11956782.html 在之前的面试经历中,对于 String 的考察还是挺频繁的,大致考察以下几个知识点: String 常量池 new String() == 和 equals 的区别 native 方法 String.intern() 虽然面试中大体答对了,但是今天早上微信群里的一个问题我却答不上来,这个问题是这样的: String str3 = "what"; String str4 = str3 + " a nice day"; //运行时, + 相当于 new,所以堆中会有 "what a nice day"对象,常量池中会有"what"," a nice day"两个对象,而不会有 "what a nice day"对象。 //这句话大佬们看看对不对啊,我怎么感觉不对啊 //常量池不会有"what a nice day" 对象吗? 看完这个问题,说实话我也是有点懵的,我只是知道 "what a nice day"不会在常量池,但是不知道具体的原因,后来群里的同学说 + 号是调用了 StringBuffer 的append 方法。 我去证实了,发现确实调用了 append 方法,但是当时没有 调用toString()方法,我很疑惑。(最后经过证实,是 StringBuilder

JDK核心JAVA源码解析(8)

ⅰ亾dé卋堺 提交于 2020-07-28 03:36:00
想写这个系列很久了,对自己也是个总结与提高。原来在学JAVA时,那些JAVA入门书籍会告诉你一些规律还有法则,但是用的时候我们一般很难想起来,因为我们用的少并且不知道为什么。知其所以然方能印象深刻并学以致用。 本文基于 Java 14 在JDK1.5引入自动装箱/拆箱,让开发更高效。自动装箱时编译器调用 valueOf() 将原始类型值转换成对象,同时自动拆箱时,编译器通过调用类似 intValue(),doubleValue() 这类的方法将对象转换成原始类型值。 自动装箱是将 boolean 值转换成 Boolean 对象,byte 值转换成 Byte 对象,char 转换成 Character 对象,float 值转换成 Float 对象,int 转换成 Integer,long 转换成 Long,short 转换成 Short,自动拆箱则是相反的操作。 public static void main(String[] args) { Long v = 6L; long a = v; if (a > v) { } } 通过 javap -c 命令查看: 0 ldc2_w #68 <6> 3 invokestatic #66 <java/lang/Long.valueOf> 6 astore_1 7 aload_1 8 invokevirtual #70 <java/lang

Java ASM学习(2)

非 Y 不嫁゛ 提交于 2020-04-29 09:00:05
1.编译后的方法区,其中存储的代码都是一些字节码指令 2.Java虚拟机执行模型: java代码是在一个线程内部执行,每个线程都有自己的执行栈,栈由帧组成,每个帧表示一个方法的调用,每调用一个方法,都将将新的帧压入执行栈,方法返回时(不管是整成return还是异常返回),该方法对应的帧都将出栈,即按照先进后出的规则。 执行栈与操作数栈不一样,操作数栈包含在执行栈中。每一帧包括局部变量和操作数栈两部分,操作数栈中包括字节码指令用来当操作数的值。比如a.equals(b)将创建一帧,此时该帧将有一个空栈,并且a和b作为局部变量 字节码指令: 由标识该指令的操作码和固定数目的参数组成,操作码指定要进行哪一类操作,参数指定具体精确行为。指令分为两类,一类在局部变量和操作数栈之间传值,一类从操作数栈弹出值计算后再压入 例如: ILOAD,LLOAD,FLOAD,DLOAD,ALOAD读取一个局部变量,并将其值压入操作数栈中,其对应的参数是其读取的局部变量索引i(因为局部变量就是通过索引来进行随机访问的),LLOAD和DLOAD加载时需要两个槽(slot),因为局部变量部分和操作数占部分的每个槽(slot)都可以保存除了long和double之外的java值(long和double需要两个槽)。 ILOAD:加载boolean、 char 、 byte 、 short 、int局部变量

String字符串性能优化的几种方案

独自空忆成欢 提交于 2020-04-18 04:07:11
String字符串是系统里最常用的类型之一,在系统中占据了很大的内存,因此,高效地使用字符串,对系统的性能有较好的提升。 针对字符串的优化,我在工作与学习过程总结了以下三种方案作分享: 一.优化构建的超大字符串   验证环境:jdk1.8   反编译工具:jad 1.下载反编译工具jad,百度云盘下载: 链接:https://pan.baidu.com/s/1TK1_N769NqtDtLn28jR-Xg 提取码:ilil 2.验证 先执行一段例子1代码: 1 public class test3 { 2 public static void main(String[] args) { 3 String str="ab"+"cd"+"ef"+"123" ; 4 } 5 } 执行完成后,用反编译工具jad进行反编译:jad -o -a -s d.java test.class 反编译后的代码: 1 // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. 2 // Jad home page: http://www.kpdus.com/jad.html 3 // Decompiler options: packimports(3) annotate 4 // Source File Name: test.java 5

从单例模式到Happens-Before

℡╲_俬逩灬. 提交于 2020-03-11 18:01:20
本文已同步到 http://liumian.win/2016/12/14/fromsingletontohappens-before/ 本文主要从简单的单例模式为切入点,分析单例模式可能存在的一些问题,以及如何借助Happens-Before分析、检验代码在多线程环境下的安全性。 知识准备 为了后面叙述方便,也为了读者理解文章的需要,先在这里解释一下牵涉到的知识点以及相关概念。 线程内表现为串行的语义 Within Thread As-If-Serial Semantics 定义 普通的变量仅仅会保证在该方法的执行过程中 所有依赖赋值结果的地方都能获取到正确的结果 ,而不能保证变量赋值操作的顺序与程序代码中的执行顺序一致。 举个小栗子 看代码 int a = 1; int b = 2; int c = a + b; 大家看完代码没准就猜到我想要说什么了。 假如没有重排序这个东西,CPU肯定会按照从上往下的执行顺序执行:先执行 a = 1 、然后 b = 2 、最后 c = a + b ,这也符合我们的阅读习惯。 但是,上文也提及了:CPU为了提高运行效率,在执行时序上不会按照刚刚所说的时序执行,很有可能是 b = 2 a = 1 c = a + b 。对,因为只需要在变量 c 需要变量 a``b 的时候能够得到正确的值就行了,JVM允许这样的行为。 这种现象就是

深入理解JVM

允我心安 提交于 2020-02-27 06:00:32
Java虚拟机的指令由一个字节长度的、代表着某种特定操作含义的数字(称为操作码,Opcode)以及跟随其后的零至多个代表此操作所需的参数(称为操作数,Operand)构成。因为只有一个字节的长度,所以指令总数不能超过256个。 在Java虚拟机的指令集中,大多数指令都包含其操作所对应的数据类型信息,如:i代表对int类型的数据操作,l代表long,s代表short,b代表byte,c代表char,f代表float,d代表double,a代表reference。 解释器的执行模型 Java虚拟机的解释器的执行模型: do { 自动计算PC寄存器的值加1; 根据PC寄存器指示的位置,从字节码流中取出操作码; if (字节码存在操作数) 从字节码流中取出操作数; 执行操作码所定义的操作; } while (字节码流长度 > 0); 常量入栈指令 指令码 操作码(助记符) 操作数 描述(栈指操作数栈) 0x01 aconst_null 将 null推送至栈顶 0x02 iconst_m1 将 -1(int)推送至栈顶 0x03 iconst_0 将 0(int)推送至栈顶 0x04 iconst_1 将 1(int)推送至栈顶 0x05 iconst_2 将 2(int)推送至栈顶 0x06 iconst_3 将 3(int)推送至栈顶 0x07 iconst_4 将 4(int

Long类型数值比较及反汇编分析源码

霸气de小男生 提交于 2020-02-27 04:48:29
一、问题描述 开发过程中遇到如下问题 Long a = 100L; Long b = 100L; System.out.println(a == b); System.out.println(a.equals(b)); System.out.println(a == 100); System.out.println(a.equals(100)); 输出结果: true true true false 但是当Long类型大于127时: Long a = 128L; Long b = 128L; System.out.println(a == b); System.out.println(a.equals(b)); System.out.println(a == 128); System.out.println(a.equals(128)); 输出结果: false true true false 二、问题分析 查看源码:java.lang.Long.java LongCache会预先缓存-128–127范围内的数,通过缓存频繁请求的值代来更好的空间和时间性能, 当数据超出此范围,则new一个Long对象; “==”是比较的地址,超出此范围的数据地址不一致,所以范围内的比较是true,范围外的数据是false; 而a==100则实现了类型的自动向上转换

什么是泛型?

孤人 提交于 2020-02-26 19:12:40
一、泛型的概念 泛型是 Java SE5 出现的新特性,泛型的本质是 类型参数化或参数化类型 ,在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型。 二、泛型的意义 一般的类和方法,只能使用具体的类型:要么是基本类型,要么是自定义的类。如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。 Java 在引入泛型之前,表示可变对象,通常使用 Object 来实现,但是在进行类型强制转换时存在安全风险。有了泛型后: 编译期间确定类型,保证类型安全,放的是什么,取的也是什么,不用担心抛出 ClassCastException 异常。 提升可读性,从编码阶段就显式地知道泛型集合、泛型方法等处理的对象类型是什么。 泛型合并了同类型的处理代码提高代码的重用率,增加程序的通用灵活性。 举个例子: public static void method1() { List list = new ArrayList(); List.add(22); List.add("hncboy"); List.add(new Object()); for (Object o : list) { System.out.println(o.getClass()); } } 未使用泛型前,我们对集合可以进行任意类型的 add 操作,遍历结果都被转换成 Object 类型