`
gao_20022002
  • 浏览: 160787 次
  • 性别: 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与==区别

    equal与==区别,从三个方面,进行举例比较。

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

    Java语言是sun公司的开发成果,他的主要特点是可以执行强,与平台的无关性使他的实用性更强。但是Java中的==与equal是有区别的。

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

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

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

    主要介绍了浅析java中String类型中“==”与“equal”的区别,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

    java中==与equal()区别

    本文详细描述了==与equal() 的区别 初学者可以很好很专业的理解其区别

    Java_详解_1、==和Equal

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

    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面试题】equals与==的区别

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

    java中 == 与 equal 的区别讲解

    介绍了java中 == 与 equal 的区别,有需要的朋友可以参考一下

    浅谈java 中equals和==的区别

    主要介绍了java 中equals和==的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    java String 类的一些理解 关于==、equals、null

    在对字符串的相等判断,==判断的是地址是否相同,equal()判断的是字符值是否相同。大多数时候==跟equal()的结果都是相同的。

    String 比较

    详细介绍了java String 中的“==”和“equal”

    Java计算器源程序.rar

      Button bPoint,bEqual,bPlus,bMinus,bClear,bMulti,bDivision; //运算符按钮  Button[] b=new Button[10]; //数字按钮   String currentOp,preOp; //当前操作和上一步操作  String foreText,backText; //...

    5fanily,封装,==equal.rar

    /* 定义有final的变量为最终变量不能为其赋值. ... public static void main(String args[]) { Test1 t1=new Test1(); //t1.a=33;//无法为最终变量 a 指定值 System.out.println(t1.a); } }

    string-hashcode:java.lang.String.hashCode

    安装npm install string-hashcode 例子var hashCode = require ( 'string-hashcode' ) ;var s = 'abc' ;console . log ( s . hashCode ) ; // undefinedvar code = hashCode ( s ) ;console . log ( s . hashCode ) ...

    基于JAVA语言的计算器图形界面设计.doc

    2、程序流程图 详细设计 import java.awt.BorderLayout; //导入AWT页面设置类 import java.awt.Button; //导入AWT按钮类 import java.awt.Frame; import java.awt.GridLayout; import java.awt.Panel; import java....

    Java面试题.docx

    18、Java中String的了解 19、String为什么要设计成不可变的? 20、Object类的equal和hashCode方法重写,为什么? 21-40题 21、List,Set,Map的区别 26、ArrayMap和HashMap的对比 29、HashMap和HashTable的区别 ...

    Java Oracle分页处理

    //此对象中保存了页面的所有情况,包括多少页等信息 public PaginationBean getPagePagination() { return pagination; } /** * * */ //实例化PaginationBean的构造函数 public void Init...

    Java+structs快速学习指南

    Struts Logic标签库中包含的标签列表 Tag name Description empty 如果标签parameter,propertie等属性所指定的变量值为null或空字符串,则处理标签包含的内容 equal 如果标签parameter,propertie等属性所指定的...

    关于Java中的“==”与equals()

    [Java学习笔记01] 最近在学习Java程序设计,学到“==”和Object类中的equals()方法的时候有点混乱。 上结论!!! “==”:用于判断二者是否同一,即二者的引用变量是否指向同一个对象。 Object.equals():用于判断...

Global site tag (gtag.js) - Google Analytics