文档章节

转-Java中的堆栈

关西大汉弹琵琶
 关西大汉弹琵琶
发布于 2015/05/29 10:42
字数 2047
阅读 20
收藏 1


关于Java中的堆栈:

栈与堆都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。

Java的堆是一个运行时数据区,类的对象从中分配空间。这些对象通过new、newarray、anewarray和multianewarray等指令建立,它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,因此,用堆保存数据时会得到更大的灵活性。变量所需的存储空间只有在运行时创建了对象之后才能确定。Java的垃圾收集器会自动收走这些不再使用的数
据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。

栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和引用对象,栈里存的却是堆的首地址名;就像引用变量。 

Java中分配堆内存是自动初始化的。Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在堆栈中分配,也就是说在建立一个对象时从两个地方都分配内存,在堆中分配的内存实际建立这个对象,而在栈中分配的内存只是一个指向这个堆对象的指针(引用变量)而已。 在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。 

在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。

引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉)。

例子:
String s=new String("123");
这个s就在栈里面,而他的"123"这个对象在堆里面。 s 指向"123";
3.就对象本身而言,他的所有属性的值如果不是单例或者静态的,就是存储在堆里面的。一个类的所有对象的属性值都在堆里面并且占用不同的内存空间,而一个类的方法只在方法区里占一个地方

栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:
int a = 3;
int b = 3; 

编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。

这时,如果再令a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响
到b的值。

a-------》3
b-------》3 ,这个3是共享存在的,a,b指向同一个地址,然后存进4,4也是共享存在的。

a,b先指向3个共享,然后a指向4,b仍然指向3.

3和4是存放在栈中,a和b是引用对象



要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一
个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。 


String是一个特殊的包装类数据。可以用:
String str = new String("abc");------------------开辟新的空间,创建新对象
String str = "abc"; -----------------------------使用共享的字符串

两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。
而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”,相当于指向“abc”的地址。

比较类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==,下面用例子说明上面的理论。
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true
可以看出str1和str2是指向同一个对象的。

String str1 =new String ("abc");
String str2 =new String ("abc");
System.out.println(str1==str2); // false
用new的方式是生成不同的对象。每一次生成一个。


因此用第二种方式创建多个”abc”字符串,第一种方式在内存中其实只存在一个对象而已. 这种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度
,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。

另一方面, 要注意: 我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,创建了String类的对象str。担心陷阱!对象可能并没有被创建!而可能
只是指向一个先前已经创建的对象。只有通过new()方法才能保证每次都创建一个新的对象。

以下是一个例子:

package LearnJava;
/**
 * Created by Jimmy on 2015/4/16.
 */
import java.lang.String;

class Value{
    int v;
    String s;

    public Value(){
        v = 1;
        s = "";
    }

    //覆盖equals方法
    public boolean equals(Object arg){
        if(!(arg instanceof Value) || arg == null)
            return false;
        //必须将Object转化为Value,否则不能访问v和s字段
        Value oarg = (Value)arg;
        return oarg.v == this.v && oarg.s == this.s;
    }
}
public class equal {

    public static void main(String[] args) {

        int i = 1;
        int j = 1;
        String s = "a";
        String ss = "a";
        Value v1 = new Value();
        Value v2 = new Value();

        if (i == j)
            System.out.println("int with same value ==");
        else
            System.out.println("int with same value not ==");

        if (s.equals(ss))
            System.out.println("String with same value equals");
        else
            System.out.println("String with same value not equals");

        if (v1 == v2)
            System.out.println("class ==");
        else
            System.out.println("class not ==");

        if (v1.equals(v2))
            System.out.println("class equal");
        else
            System.out.println("class not equal");
    }
}

执行结果是:

    

int with same value ==
String with same value equals
class not ==
class equal


打印信息:

1, 对自定义的类来说, 如果没有覆盖Value的equals方法,则equals默认比较的为同一性而不是相等性,即如果指向同一个对象才返回true. 

2,大部分预定义类,比如String都已经覆盖了equals使之反应的是相等性

3, Integer, Double 等包装类也是跟自定义类一个效果,==不相等,但是equal相等
















本文转载自:http://blog.csdn.net/hbhhww/article/details/8152838

关西大汉弹琵琶
粉丝 8
博文 41
码字总数 14221
作品 0
浦东
程序员
私信 提问
JVM:如何分析线程堆栈

在这篇文章里我将教会你如何分析JVM的线程堆栈以及如何从堆栈信息中找出问题的根因。在我看来线程堆栈分析技术是Java EE产品支持工程师所必须掌握的一门技术。在线程堆栈中存储的信息,通常远...

0x0bject
2014/11/09
20K
19
Java虚拟机JVM内部体系结构

Java虚拟机JVM内部体系结构 易百教程移动端:请扫描本页面底部(右侧)二维码并关注微信公众号,回复:"教程" 选择相关教程阅读或直接访问:http://m.yiibai.com 。 JVM(Java虚拟机)是一个抽象...

LYQ1990
2018/07/18
250
0
黑马程序员---面向对象之String类创建对象的一点思考

-------------------------android培训、java培训、期待与您交流! ------------------------- 最近在上黑马论坛时经常有同学问到关于String类创建对象的问题,最多的就是诸如:String str ...

长平狐
2013/07/01
122
0
JAVA虚拟机起步-虚拟机调优

JAVA虚拟机起步OutOfMemory问题解决记录。 问题: JAVA虚拟机报错 # java.lang.OutOfMemoryError: requested 32756 bytes for ChunkPool::allocate. Out of swap space? # # Internal Error......

飓风2000
2014/03/01
353
0
Java并发(1)- 聊聊Java内存模型

引言 在计算机系统的发展过程中,由于CPU的运算速度和计算机存储速度之间巨大的差距。为了解决CPU的运算速度和计算机存储速度之间巨大的差距,设计人员在CPU和计算机存储之间加入了高速缓存来...

knock_小新
2018/07/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

springboot全家桶,集成shiro,rabbitmq,redis, mybatis,druid,swagger

搭建了一个SpringBoot的模板,下载即可作为单体应用的服务后台模板 项目地址:https://gitee.com/devilscode/springboot_template 项目集成框架 springboot 作为基础框架 shiro 权限管理 ra...

devils_os
12分钟前
2
0
云服务器的优势有哪些?

与传统的服务器相比,云服务器有多种显著的优势,因此近年来云服务器租用一直都很受消费者的欢迎。 那么云服务器都有哪些优势呢? 云服务器的稳定性很好 虚拟主机是很多用户建站的首选方案,这...

云漫网络Ruan
13分钟前
2
0
好程序员web前端学习路线分享CSS浮动-清除浮动篇

好程序员web前端学习路线分享CSS浮动-清除浮动篇,为什么要清除浮动   这里所说的清除浮动,并不是不要浮动了,而是清除浮动与浮动之间的影响。那么到底会有什么影响呢? 1.高度塌陷   ...

好程序员官方
23分钟前
1
0
我有酒,你有故事吗?

记录学习的每一秒,巨杉技术社区有奖征文全新启动! 如果, 你热爱数据技术,乐于尝(zhe)试(teng), 又喜欢写点什么~ 那么, 无论你是架构大佬,还是DBA大神, 只要你愿意通过文字分享你...

巨杉数据库
27分钟前
1
0
【Git】ignore文件不生效

简介 使用git的过程中, 某些文件可能不希望上传到服务器,例如日志、本地化配置等信息。这时候,我们可以通过配置.gitignore文件忽略这些文件的提交。 配置.gitignore 常见的配置如下: HELP...

Areya
30分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部