1. 这段程序的结果是什么?
private static void test1() { String a = "a" + "b" + 1; String b = "ab1"; System.out.println(a == b); }
运行结果:
true
为什么呢?
a 引用是直接赋值的,b 引用是通过“+”赋值的,a 和b 两个引用为什么会指向同一
个内存单元?这就是JVM 的“编译时优化”
当编译器在编译代码:String a = "a" + "b" + 1;时,会将其编译为:String a = "ab1";。
为何?因为都是“常量”,编译器认为这3 个常量叠加会得到固定的值,无须运行时再
进行计算,所以就会这样优化。
关于“==”
首先要知道“==”用于匹配内存单元上的内容,其实就是一个数字,计算机内部也只
有数字,而在Java 语言中,当“==”匹配的时候,其实就是对比两个内存单元的内容是否一样。
如果是原始类型 byte、boolean、short、char、int、long、float、double,就是直接比较
它们的值。这个大家应该都清楚,这里不再详谈。
如果是引用(Reference),比较的就是引用的值,“引用的值”可以被认为是对象的逻
辑地址。如果两个引用发生“==”操作,就是比较相应的两个对象的地址值是否一样。换
一句话说,如果两个引用所保存的对象是同一个对象,则返回true,否则返回false(如果
引用指向的是null,其实这也是一个JVM 赋予给它的某个指定的值)。
理解寓意:大家各自拿到了一个公司的offer,现在我们看看哪些人拿到的offer 是同一
个公司的。
关于“equals()”
equals()方法,首先是在Object 类中被定义的,它的定义中就是使用“==”方式来匹配
的(这一点大家可以参看Object 类的源码)。也就是说,如果不去重写equals()方法,并且
对应的类其父类列表中都没有重写过equals()方法,那么默认的equals()操作就是对比对象的地址。
equals()方法之所以存在,是希望子类去重写这个方法,实现对比值的功能,类似的,
String 就自己实现了equals()方法。为什么要自己去实现呢?因为两个对象只要根据具体业
务的关键属性值来对比,确定它们是否是“一致的或相似的”,返回true|false 即可。
2. 这段程序的结果是什么?
private static String getA() {return"a";} public static void test2() { String a = "a"; final String c = "a"; String b = a + "b"; String d = c + "b"; String e = getA() + "b"; String compare = "ab"; System.out.println(b == compare); System.out.println(d == compare); System.out.println(e == compare); }
结果:
false
true
false
第 1 个输出false。
“b”与“compare”对比,根据代码清单1-2 中的解释,compare 是一个常量,那么b
为什么不是呢?因为b = a + "b",a 并不是一个常量,虽然a 作为一个局部变量,它也指向
一个常量,但是其引用上并未“强制约束”是不可以被改变的。虽然知道它在这段代码中
是不会改变的,但运行时任何事情都会发生,尤其是在“字节码增强”技术面前,当代码
发生切入后,就可能发生改变。所以编译器是不会做这样优化的,所以此时在进行“+”运
算时会被编译为下面类似的结果:
StringBuilder temp = new StringBuilder();
temp.append(a).append("b");
String b = temp.toString();
注:这个编译结果以及编译时合并的优化,并非胖哥凭空捏造的,在后文中探讨javap
命令时,这些内容将得到实际的印证。
第 2 个输出true。
与第 1 个输出false 做了一个鲜明对比,区别在于对叠加的变量c 有一个final 修饰符。
从定义上强制约束了c 是不允许被改变的,由于final 不可变,所以编译器自然认为结果是
不可变的。
final 还有更多的特性用于并发编程中,我们将在第5 章中再次与它亲密接触。
第 3 个输出false。
它的叠加内容来源于一个方法,虽然方法内返回一个常量的引用,但是编译器并不会
去看方法内部做了什么,因为这样的优化会使编译器困惑,编译器可能需要递归才能知道
到底返回什么,而递归的深度是不可预测的,递归过后它也并不确保一定返回某一个指定
的常量。另外,即使返回的是一个常量,但是它是对常量的引用实现一份拷贝返回的,这
份拷贝并不是final 的。
3. 这段程序的结果是什么?
public static void test3() { String a = "a"; String b = a + "b"; String c = "ab"; String d = new String(b); println(b == c); println(c == d); println(c == d.intern()); println(b.intern() == d.intern()); }
结果:
false
false
true
true
当调用 intern()方法时,JVM 会在这个常量池中通过equals()方
法查找是否存在等值的String,如果存在,则直接返回常量池中这个String 对象的地址;若
没有找到,则会创建等值的字符串(即等值的char[]数组字符串,但是char[]是新开辟的一
份拷贝空间),然后再返回这个新创建空间的地址。只要是同样的字符串,当调用intern()
方法时,都会得到常量池中对应String 的引用,所以两个字符串通过intern()操作后用等号
是可以匹配的。
4. String“+”
原始代码为:
String a = "a"; String b = "b"; String c = a + b + "f";
编译器会将它编译为:
String a = "a"; String b = "b"; StringBuilder temp = new StringBuilder(); temp.append(a).append(b).append("f"); String c = temp.toString();
5. String、StringBuffer与StringBuilder之间区别
关于这三个类在字符串处理中的位置不言而喻,那么他们到底有什么优缺点,到底什么时候该用谁呢?下面我们从以下几点说明一下
5.1.三者在执行速度方面的比较:StringBuilder > StringBuffer > String
5.2.String <(StringBuffer,StringBuilder)的原因
String:字符串常量
StringBuffer:字符创变量
StringBuilder:字符创变量
从上面的名字可以看到,String是“字符创常量”,也就是不可改变的对象。对于这句话的理解你可能会产生这样一个疑问 ,比如这段代码:
String s = "abcd"; s = s+1; System.out.print(s);// result : abcd1
我们明明就是改变了String型的变量s的,为什么说是没有改变呢? 其实这是一种欺骗,JVM是这样解析这段代码的:首先创建对象s,赋予一个abcd,然后再创建一个新的对象s用来 执行第二行代码,也就是说我们之前对象s并没有变化,所以我们说String类型是不可改变的对象了,由于这种机制,每当用String操作字符串时,实际上是在不断的创建新的对象,而原来的对象就会变为垃圾被GC回收掉,可想而知这样执行效率会有多底。
而StringBuffer与StringBuilder就不一样了,他们是字符串变量,是可改变的对象,每当我们用它们对字符串做操作时,实际上是在一个对象上操作的,这样就不会像String一样创建一些而外的对象进行操作了,当然速度就快了。
5.3.一个特殊的例子:
String str = “This is only a” + “ simple” + “ test”; StringBuffer builder = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
你会很惊讶的发现,生成str对象的速度简直太快了,而这个时候StringBuffer居然速度上根本一点都不占优势。其实这是JVM的一个把戏,实际上:
String str = “This is only a” + “ simple” + “test”;
其实就是:
String str = “This is only a simple test”;
所以不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的String对象的话,速度就没那么快了,譬如:
String str2 = “This is only a”;
String str3 = “ simple”;
String str4 = “ test”;
String str1 = str2 +str3 + str4;
这时候JVM会规规矩矩的按照原来的方式去做。
5.4.StringBuilder与 StringBuffer
StringBuilder:线程非安全的
StringBuffer:线程安全的
当我们在字符串缓冲去被多个线程使用是,JVM不能保证StringBuilder的操作是安全的,虽然他的速度最快,但是可以保证StringBuffer是可以正确操作的。当然大多数情况下就是我们是在单线程下进行的操作,所以大多数情况下是建议用StringBuilder而不用StringBuffer的,就是速度的原因。
对于三者使用的总结: 1.如果要操作少量的数据用 = String
2.单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
3.多线程操作字符串缓冲区 下操作大量数据 = StringBuffer
相关推荐
- **知识点**:解释为什么`String`类是不可变的(immutable),以及不可变性带来的好处。 - **例题**:选择题中可能会问到关于字符串池的概念以及如何利用这一点来提高程序性能。 #### 2. 字符串比较 - **知识点**...
Java中String的知识点
下面将详细探讨`String`类的数据结构、常用方法以及适用于初学者的一些关键知识点。 首先,`String`对象存储在常量池中,这是一个内存区域,用于保存所有的字符串字面量。这种设计是为了优化性能,因为相同的字符串...
Java 基础知识点汇总 以下是 Java 基础知识点汇总的详细说明: ### 1. 面向对象的特征 面向对象编程(Object-Oriented Programming,OOP)是一种编程范式,它强调使用对象和类来组织和结构化代码。面向对象编程的...
java核心知识点整理 1.Java中没有多继承,而是用接口来代替多继承 2.运行一个已经编译的程序时,Java解释器总是从指定类的main方法中的代码开始执行,因此,执行代码中必须有一个main函数。 3.Java是典型的强类型...
综上所述,Java基础知识点包括String类的使用、接口与继承的概念、I/O流的操作以及反射的应用。掌握这些基础知识是成为一名合格Java开发者的前提,也是进一步学习Java高级特性和框架的基础。通过深入理解和实践,...
Java 基础知识点 Java 是一种面向对象的编程语言,它具有抽象、继承、封装、多态性等特征。下面是 Java 基础知识点的详细解释: 1. 面向对象的特征: 面向对象编程的四个基本特征是抽象、继承、封装和多态性。 *...
Java知识点整理 Java是一种广泛使用的面向对象的编程语言,它具有丰富的API(应用程序接口)和强大的功能。在Java考试中,掌握以下知识点至关重要: 1. **JAVA SE**(Java标准版)是Java的核心部分,包括基础语法...
在Java编程语言中,String类型扮演着至关重要的角色。...在实际开发中,理解和熟练运用这些知识点,能够有效地编写出高效、安全的Java代码。同时,对于字符串的操作,还需要注意线程安全问题,尤其是在多线程环境中。
Java中的String类是一个重要的数据类型,用于存储和操作字符串数据。String类的特点是不可变性,也就是说,一旦String对象被创建,其值就无法改变。...掌握这些知识点对于编写高效、健壮的Java程序是十分必要的。
Java是世界上最流行的编程语言之...这些知识点构成了Java开发者必备的基础,深入理解它们有助于编写出高效、稳定的代码。在实际开发中,还需要结合设计模式、异常处理、网络编程等知识,才能构建出完整的Java技术体系。
标题:“2021 - JAVA秋招基础知识点面试题”的知识点总结 1. JDK与JRE的区别: JDK是Java开发工具包,它包含了JRE和一些其他工具,如编译器javac和调试工具等。JRE是Java运行环境,仅用于运行Java程序。简单来说,...
Java 中的数据类型转换是一个基本的知识点。除了 String 和 int 类型的相互转换之外,还有许多其他数据类型的转换,例如将 String 类型转换为 double、float、long 等类型,或者将这些类型转换为 String 类型。 在 ...
在本文中,我们将深入探讨`JAVA_String`相关的知识点,包括其创建、操作、比较以及内存管理等方面。 首先,`String`类位于`java.lang`包中,这意味着在编写Java程序时,我们无需显式导入它。`String`对象一旦创建,...
### JAVA学习知识点详解 #### 一、类的定义与使用 在Java中,类是面向对象编程的基础单元,用于封装数据和操作这些数据的方法。通过类可以定义对象的行为和属性。 **1. This代词** `this`关键字是Java中的一个...
本文将介绍如何将String类型转换成Timestamp类型,并对相关的知识点进行详细的解释。 首先,让我们了解一下Timestamp类型。在Java中,Timestamp类型是java.sql包下的一个类,该类继承自java.util.Date类,用于表示...
以下是对Java相关知识点的详细总结: 1. **基础语法**:Java的基础包括变量、数据类型(基本类型如int、char,引用类型如类、接口)、运算符(算术、比较、逻辑等)、流程控制(条件语句if/else,循环语句for/while...
下面我们将深入探讨`String`类的一些关键知识点,以及如何通过练习来熟练掌握它们。 1. **创建String对象**: - 字面量方式:`String str = "Hello, World!";` - 构造器方式:`String str = new String("Hello, ...
它被广泛用于存储文本信息,而关于字符串创建的理解,以及"equals()"方法和"=="运算符的区别,是每个Java开发者都应深入掌握的知识点。 首先,让我们来探讨字符串的创建。在Java中,有多种创建字符串的方式: 1. *...
Java 面向对象基础知识点 Java 是一门面向对象的编程语言,面向对象编程(Object-Oriented Programming,OOP)是 Java 语言的核心。了解 Java 面向对象的基础知识是掌握 Java 语言的关键,本文将对 Java 面向对象的...