java String 类常量池分析及 "equals" 和 "== 区别详细介绍
这里有新鲜出炉的 Java 设计模式, 程序狗速度看过来!
Java 程序设计语言
java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言, 是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台 (即 JavaEE(j2ee), JavaME(j2me), JavaSE(j2se)) 的总称
这篇文章主要介绍了 java String 类常量池分析及 "equals" 和 "== 区别详细介绍的相关资料, 需要的朋友可以参考下
java "equals" 和 "== 异同
首先简单说一下 equal 和 ==
== 操作对于基本数据类型比较的是两个变量的值是否相等,
对于引用型变量表示的是两个变量在堆中存储的地址是否相同,
即栈中的内容是否相同
equals 操作表示的两个变量是否是对同一个对象的引用,
即堆中的内容是否相同
综上,== 比较的是 2 个对象的地址, 而 equals 比较的是 2 个对象的内容
再简单介绍一下 String 类
String 类 又称作不可变字符序列
String 使用 private final char value[]来实现字符串的存储, 也就是说 String 对象创建之后, 就不能再修改此对象中存储的字符串内容 String 类有一个特殊的创建方法, 就是使用 ""双引号来创建例如 new String("123")实际创建了 2 个 String 对象, 一个是"123"通过"" 双引号创建的, 另一个是通过 new 创建的. 只不过他们创建的时期不同, 一个是编译期, 一个是运行期 java 对 String 类型重载了 + 操作符, 可以直接使用 + 对两个字符串进行连接运行期调用 String 类的 intern()方法可以向 String Pool 中动态添加对象
区分两种创建 String 对象的方法和 new()
String 是一个特殊的包装类数据可以用:
- String str1 = new String("123");
- String str2 = "123";
两种的形式来创建
第一种是用 new()来新建对象的, 它会在存放于堆中每调用一次就会创建一个新的对象(实际是两个正如上文所说, 但是在常量池中存在 123 后就不会再在常量池中创建新的 123)
第二种是先在栈中创建一个对 String 类的对象引用变量 str, 然后通过符号引用去字符串常量池里找有没有 "abc", 如果没有, 则将 "abc" 存放进字符串常量池, 并令 str 指向 abc, 如果已经有 abc 则直接令 str 指向 abc
这时我们应该注意
一方面, 第一种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度, 因为 JVM 会自动根据栈中数据的实际情况来决定是否有必要创建新对象而对于 String str = new String("123"); 的代码, 则一概在堆中创建新对象, 而不管其字符串值是否相等, 是否有必要创建新对象, 从而加重了程序的负担另一方面, 我们在使用诸如 String str = "123"; 的格式定义类时, 总是想当然地认为, 创建了 String 类的对象 str
对象可能并没有被创建! 而可能只是指向一个先前已经创建的对象只有通过 new()方法才能保证每次都创建一个新的对象
请看下列实例
- package testString;
- public class testString {
- public static void main(String[] args) {
- String a = "123";
- String b = "123";
- System.out.println(a == b);
- System.out.println(a.equals(b));
- System.out.println("------------------------------------------");
- /**
- * true
- * true
- * 此处创建一个字符串 "123" 储存在常量池中
- * 因为 "123" 储存在常量区, 并且唯一, 即两个 String 引用 a 和 b 所的地址相同所以 a==b 为 true
- * 并且两个引用在所指对象在堆中的内容相同所以 a.equals(b)为 true
- */
- String c = new String("1234");
- String d = new String("1234");
- System.out.println(c == d);
- System.out.println(c.equals(d));
- System.out.println("------------------------------------------");
- /*
- * false
- * true
- * 此处创建三个字符串 1234, 一个在常量池中, 两个通过 new 储存在堆中
- * 因为 c 和 d 此时指向的是堆中的两个 String 对象, 所以地址不同 c==d 为 false
- * 但是 c 与 d 堆中内容相同所以 c.equals(d)为 true
- */
- String e = "a1";
- String f = "a" + 1;
- System.out.println(e == f);
- System.out.println(e.equals(f));
- System.out.println("------------------------------------------");
- /**
- * true
- * true
- * 此处创建 a1a2 个字符串其中 a1a 他们两个均在常量池中, 你可能会问 + 是个运算符重载么?
- * 是的, java 自己有一定的运算符重载但是你没法使用定义自己的运算符重载, 和 c++ 不同, String f = "a"+1;
- * 这句会被编译器做成 String f=a1; 这与我们讲到的第一种情况相同, 不再赘述
- * 编译器之所以这么做是因为他在编译时就能够确定
- */
- String g = "gh";
- String hh = "h";
- String h = "g" + hh;
- System.out.println(g == h);
- System.out.println(g.equals(h));
- System.out.println("------------------------------------------");
- /**
- * false
- * true
- * 与上面不同的是这里的 h 在编译时不能确定(编译器是这样认为的), 所以 h 所指的对象在运行时确定储存在堆中,
- * 所以 g==h 为 true 而 g.equals(h)为 false
- */
- }
- }
来源: http://www.phperz.com/article/18/0210/359264.html