`
gao_20022002
  • 浏览: 164804 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

由String看Java堆栈问题,包括==以及equal()。

    博客分类:
  • Java
阅读更多
由String看Java堆栈问题,包括==以及equal()。
首先看代码:
1
public class TestString {
	public static void main(String[] args) {
		String a0 = "abc";
		String b0 = "abc";
		if (a0 == b0) {
			System.out.print("==");
		} else {
			System.out.print("!=");
		}
	}
}

执行结果为:
==

2
public class TestString {
	public static void main(String[] args) {
		String a0 = String.valueOf("abc");
		String b0 = String.valueOf("abc");
		if (a0 == b0) {
			System.out.print("==");
		} else {
			System.out.print("!=");
		}
	}
}

执行结果为:
==

3
public class TestString {
	public static void main(String[] args) {
		String a0 = "abc"+"def";
		String b0 = "abcdef";
		if(a0==b0){
			System.out.print("==");
		}else{
			System.out.print("!=");
		}
	}
}

执行结果为:
==

4
public class TestString {
	public static void main(String[] args) {
                  String a0 = "abc";
		String b0 = "def";
		String c0 = "abcdef";
		String d0 = a0 + b0;
		if (c0 == d0) {
			System.out.print("==");
		} else {
			System.out.print("!=");
		}
	}
}

执行结果为:
!=

5
public class TestString {
	public static void main(String[] args) {
		String a0 = new String("abc");
		String b0 = new String("abc");
		if (a0 == b0) {
			System.out.print("==");
		} else {
			System.out.print("!=");
		}
	}
}

执行结果为:
!=

6
public class TestString {

	public static void main(String[] args) {

		String a0 = String.valueOf("abc")+String.valueOf("def");
		String b0 = String.valueOf("abcdef");

		if (a0 == b0) {
			System.out.print("==");
		} else {
			System.out.print("!=");
		}
	}

}

执行结果为:
!=

我们的都知道,Java的内存分配策略:栈中存放基本数据类型(或者叫内置类型)以及引用类型(或者叫对象句柄),而堆中存放对象数据。
String很特殊,根据Think In Java介绍:“通过编译器和特殊的覆盖或过载运算符+和+=,可将引号字符串转换成一个String”。可见引号字符串本身并不是一个String,而是通过运算符的重载转换成了String。注意:没有=号。
故此:我们要问,引号字符串通过重载以后转换成String存在于什么位置?
查询网上没有具体的分析,书籍上也没有准确的说明。
根据执行结果猜想:
学习过类加载可能知道,有个常量区。
暂且假设将此部分数据存放于此空间中,看能否得到合理的解释。

Java的内存分配栈中存放两种类型数据:
1、基本数据类型:此处疑问?存放的是具体的数据还是也是一个内存地址。
假设1:栈中存放的是具体的数据,当然所有出现在基本类型的操作均可以解释。
假设2:数据存放于上边提到的常量区,而栈中存放的是此常量区对应数据的地址。所有基本数据类型操作似乎也可以解释。
其实Java设计师们很注重内存的利用,我们可能看见很多文章曾提到这样一个概念,当int n =1;时,Java会在内存中搜索,看有没有1的存在,假如有的话,则不会重新分配空间建立1,如果没有的话,则会建立1,假如int m=1;则Java不会再建立1的空间。可见似乎内存中存在一个存放数据的地方。如果用次观点解释假设2完全成立。
现在以下的结论均在假设2下展开。
2、引用类型:栈中存放的是对象的引用,此引用是通过new创建的对象在对中分配的地址。
现在分析String。
属于什么类型?基本数据类型、引用类型。
当作为String str = "abc";建立时,作为基本类型的假设2合理一些(参见第1部分代码)。
当作为String str = new String("abc");建立时,毫无疑问作为引用类型处理(参见第5部分代码)。

我们暂且将+作为一种Java特殊的处理机制,当它处理引号字符串时不会采用new方式建立String(即像"abc"+"def"),而对于栈中数据处理时会采用new方式建立String(即像a+b)。(参见第3、4、6部分代码)。

当作为String str = String.valueOf("abc");建立或者执行+时,完全可以解释通过。
其实String.valueOf()可以看做是对"abc"的封装,但不是new的(参见第2、6部分代码)。


其实现在要是按照以上的观点,可以得出这样一种结论:
栈中存放的是句柄,包括基本数据类型。内存中存在另外一块区域(常量区),存放基本数据类型数据以及引号字符串数据。
堆中存放的是对象,且必须是new的或者通过+运算符的重载隐式new的。

乱想了一通,与一些理论违背,因为好多东西解释不通,所以胡思乱想了。
欢迎评论,谢谢。
7
3
分享到:
评论
10 楼 tf03172003 2009-09-15  
从4楼这里,学到一些东西:
只有"abc" + "def"是在常量池中操作,其他的比如:a0 + b0, String.valueOf("abc") + String.valueOf("def")等等都是对象操作


9 楼 gao_20022002 2008-07-02  
几天没有来了,呵呵。
感谢各位的支持。
让高手们见笑了。
8 楼 zhangxi123 2008-07-01  
今天是第二次看到这样的内容了!其实他们原理是很简单的没必要这么深究!《JAVA优化编程》对String的讲解非常详细!
如果真想研究java的堆栈的话请读《深入java虚拟机》!如果想学习java基础方面的东西《java编程思想》是必不可少的!
7 楼 bearice 2008-06-29  
JVM的实现不保证具有相同内容的字符串一定具有相同的引用,一般来说,在类初始化时根据常量构造的相同字符串引用是相同的,后续构造出的字符串引用可能不同。要保证相同字符串引用相同,请使用intern方法。其他信息请参看JLS
6 楼 mercyblitz 2008-06-27  
不客气!
5 楼 gao_20022002 2008-06-27  
非常感谢mercyblitz的分析。

无意之间看到一篇关于此问题的文章,与大家共同分享。
http://gao-20022002.iteye.com/blog/208788
找不到原文了,自己转载一下。
4 楼 mercyblitz 2008-06-27  
我非常欣赏你的这种深入精神,不过我要指出一点你的误解:
引用
当作为String str = "abc";建立时,作为基本类型的假设2合理一些(参见第1部分代码)。

首先,String一定是对象,是引用类型(大概你知道Java底层有三种数据类型,这里不错说了),你看看String的实现,他其实在类中有一个
 private final char value[];
,作为类的一个属性,这有可以说明为什么String不变,若在大于默认规定大小,String会动态的变化,但是一旦new只有里面的value是不会变化的,除非创建第二个对象。
引用

我们暂且将+作为一种Java特殊的处理机制,当它处理引号字符串时不会采用new方式建立String(即像"abc"+"def"),而对于栈中数据处理时会采用new方式建立String(即像a+b)。(参见第3、4、6部分代码)。


在String两个常量“+”操作时,在底层的确在new String,实际上建立这一个StringBuilder()(参看Java语言规范);以你的例子:
在此层操作为
new StringBuilder().append("abc").append("def").toString(),
参考StringBuilder的toString(),实际上它又是对原字符的复制,而不是重新,他会复制字符串的地址。
这样的代码3就可以得到解释,对于非常量,如代码4中,即对象的“+”操作,这个实际上是C++的符号重载(实际上面也是重载),编译器会去判断(他们是对象,非常量),所以不会相等。代码6是同理,看看String.valueOf()方法的实现:
 public static String valueOf(Object obj) {
	return (obj == null) ? "null" : obj.toString();
    }

3 楼 wangshu3000 2008-06-27  
看不太明白。。。台基础了。。。对于“”+“”之类的不太懂。。。
2 楼 yeyongjin 2008-06-27  
                  
1 楼 rendq 2008-06-27  
看了以后觉得不错,我也对相关程序进行了测试,仍持有个人看法:4,5,6三段程序中的if条件改成这样
if (a0.equals(b0)) {   
            System.out.print("==");   
        } else {   
            System.out.print("!=");   
        }   
的话,结果就大相径庭了。在JAVA中,==比较的是地址,而equals()比较的是字面值。基本数据类型确实是一个内存地址,所以在示例1,2,3中可以完全成立。拿4来说吧,d0存方的是"abc"和"def"的两个地址,而c0只有"abcdef"一个地址,条件自然不能成立。  

相关推荐

    equal与==区别

    在Java编程语言中,`equal`方法和`==`操作符都是用来比较对象之间是否相等的工具,但它们之间存在重要的差异。本文将从三个方面进行详细的对比分析:字符串的比较、非字符串对象的比较以及基本数据类型的比较。 ###...

    3 Java中关于==和equal的区别 以及equals()方法重写

    Java 中关于 == 和 equal 的区别 及其 equals() 方法重写 Java 语言是 Sun 公司的开发成果,其主要特点是可以执行强,与平台的无关性使其实用性更强。但是 Java 中的 == 与 equal 是有区别的。 == 操作符是 Java ...

    JAVA Integer == equal 比较 doc 比较大小 是否相等

    JAVA 中的 Integer 比较 在 Java 中,我们经常需要比较两个 Integer 对象是否相等,但是在使用 "==" 运算符时,可能会出现一些意外的结果。本文将深入探讨 Java 中的 Integer 比较,了解为什么使用 "==" 运算符可能...

    浅析java中String类型中“==”与“equal”的区别

    Java 中的 String 类型是一个基本数据类型,然而在使用 String 类型的时候,我们经常会遇到“==”和 “equal” 两个操作符的使用问题。这两个操作符都是用于比较字符串的,但是它们在比较机制和结果上存在着很大的...

    java中==与equal()区别

    字符串池由 String 类维护,我们可以调用 intern() 方法来访问字符串池。当运用引号内包含文本创建对象时,所创建的对象是加入到字符串池里面的。 只有引号内包含文本创建对象才会将创建的对象放入到字符串池。...

    Java_详解_1、==和Equal

    Java_详解_1、==和Equal用法与比较

    Java_String_的方法

    ### Java字符串方法详解 #### 一、创建并初始化字符串 在Java中,字符串是一个非常重要的数据类型,通常用于处理文本信息。字符串一旦创建后不可改变,这是因为它被设计成不可变对象(`immutable object`)。Java...

    calculator.java

    JButton equal=new JButton("="); JButton point=new JButton("."); JButton plus=new JButton("+"); JButton minus=new JButton("-"); JButton multi=new JButton("×"); JButton division=new JButton("÷")...

    java中 == 与 equal 的区别讲解

    在Java编程语言中,`==` 和 `equals()` 是两种常用的比较操作符,它们在不同情况下有着不同的含义和用途。本文将深入探讨这两者之间的差异,并通过实例代码和理论解释来帮助理解。 首先,`==` 操作符主要用于基本...

    【Java面试题】equals与==的区别

    【Java面试题】equals与==的区别

    Java常用类与基础API-String的构造器与常用方法

    ### Java常用类与基础API-String的构造器与常用方法 #### 一、String的常用API-1 ##### (1)构造器 1. **介绍** - `public String()`: - 初始化新创建的 `String` 对象,以使其表示空字符序列。即创建了一个...

    浅谈java 中equals和==的区别

    在Java编程语言中,`equals()` 和 `==` 运算符经常被用来比较对象,但它们之间存在着显著的区别。理解这些差异对于编写正确、健壮的代码至关重要。以下是关于 `equals()` 和 `==` 在Java中的详细解释。 首先,`==` ...

    String类的方法

    在Java编程语言中,`String` 类是用于表示不可变文本序列的一个重要类。本文将详细介绍 `String` 类的一些常用方法及其应用场景,并通过示例代码加深理解。 #### 1. `length()` - **功能**:返回字符串中的字符...

    JAVA字符串函数一览.txt

    ### JAVA字符串函数详解 在Java编程语言中,字符串处理是一项非常重要的技能,特别是在面试或实际开发过程中。本文将详细介绍《JAVA字符串函数一览》中的关键函数及其用法。 #### 1. `substring()` `substring()`...

    比较两个string(不区分大小写)

    在编程领域,字符串(String)是数据处理中非常常见的一种数据类型,用于表示一系列字符。在很多情况下,我们可能需要比较两个字符串是否相等,但不考虑它们的大小写差异。这个任务在各种语言中都有相应的实现方法。...

    关于string的比较

    在Java编程语言中,`String`类是用于处理文本字符串的基本类型之一。由于字符串经常被用来存储和操作文本数据,在实际应用中,对字符串进行比较是非常常见的需求。本文将深入探讨如何在Java中比较字符串,并解释几种...

    Java初学者都必须理解的六大问题

    ### Java初学者必知六大问题详解 #### 问题一:我们声明了什么? 在Java中,当我们写下以下代码时: ```java String s = "Hello world!"; ``` 大多数人可能会回答:“声明了一个String类型的变量s,其值为'Hello ...

    java 字符串中文判断

    在Java中,一个`char`类型的变量可以存储一个Unicode字符,而Unicode字符集包含了几乎所有的文字,包括中文。每个Unicode字符都有一个唯一的编码,中文字符也不例外。 中文字符在Unicode中的范围通常是\u4e00到\u9...

    学Java你必须要知道的三个基础问题

    - `String` 类在 Java 中是不可变的,这意味着一旦一个 `String` 对象被创建,其内容就不能更改。 - 示例:`String s = "Hello"; s = s + " world!";`,这里创建了两个 `String` 对象,`s` 的引用首先指向 `"Hello...

    java 常用方法

    ### Java常用方法详解 ...以上就是关于Java中常用的字符串操作、文本框和文本区、按钮、标签以及选择框的基本用法和实例。熟练掌握这些基本组件和操作能够帮助开发者更高效地进行GUI界面的设计和开发。

Global site tag (gtag.js) - Google Analytics