java内存简单总结
来源:互联网 发布:2017年大数据市场规模 编辑:程序博客网 时间:2024/06/06 10:03
栈中用来存放一些原始数据类型的局部变量数据和对象的引用(String,数组.对象等等)但不存放对象内容
堆中存放使用new关键字创建的对象.
public class Cat {
private double weight;
private int age;
public Cat(double _weight, int _age) {
this.weight = _weight;
this.age = _age;
}
public double getWeight() {
return weight;
}
public int getAge() {
return age;
}
public void setWeight(double weight) {
this.weight = weight;
}
public void setAge(int age) {
this.age = age;
}
}
当new对象时:
Cat kitty = new Cat(3.0, 2);
Cat构造函数定义了两个形参,也就是局部变量,在我们试图通过new向它传实参值时, 在栈内存中定义了两个引用变量,_weight,_age并赋值,即两个引用变量所在栈内存中内容分别为3.0,2,同时在堆中开辟了一块新空间, 空间中有两个内存区域,而内存中内容为系统初始化内容。 然后通过构造函数将栈内存中值赋给堆内存中值,就这样堆内存中新空间就被赋值了,接下来就像大家所想的那样将引用kitty指向这块新空间。 做完上面的事情后,局部变量将从栈中弹出,这个过程是自发的。
Cat kitty = new Cat(3.0, 2);
new Seg().change(kitty);
System.out.println(kitty.getAge());
public void change(Cat _cat) {
_cat.setAge(5);
}
new出kitty时,在栈内存中定义了一个引用,指向堆中分配的内存,堆内存存放kitty的信息。
然后,我们开始调用change方法了,在我们把kitty传给该方法时,在栈内存中就定义了局部变量_cat,该引用变量将被指向kitty所指向的堆内存区域,
然后_cat对它指向的堆内存区域内容进行了更改,这不就是kitty所指堆内存区域被更改了吗?因为它们指向同一块堆内存。就这样,调用kitty.getAge()时,将得到5这样的结果。最后,分配出来的_cat将从栈中弹出。
String是一个特殊的引用类型的数据类型,可以用:
String str = new String("abc");
String str = "abc";
两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。而第二种是先在栈中创建
一个对String类的对象引用变量str,然后通过符号引用去字符串常量池 里找有没有"abc",如果没有,则将"abc"存放进字符串常量池 ,
并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”。
关于equals()和==:
这个对于String简单来说就是比较两字符串的Unicode序列是否相当,如果相等返回true;而==是 比较两字符串的地址是否相同,也
就是是否是同一个字符串的引用。
String s4 = "abc";
String s5 = "abc";
System.out.print(s4.equals(s5)); // true
System.out.print(s4 == s5); //true
对“abc”的值,实际上是在class文件被JVM装载到内存当中就已经为“abc”这个字符串在常量池的CONSTANT_String_info表中分配了空间来存储“abc”这个值。既然“abc”
这个字符串常量存储在常量池中,常量池是属于类型信息的一部分,类型信息也就是每一个被转载的类型,
这个类型反映到JVM内存模型中是对应存在于JVM内存模型的方法区中,也就是这个类型信息中的常量池是存在于在方法区中,方法区可以在一个堆中自由分配。
这也就说明了为什么s4==s5,因为它们俩都是指向常量池中“abc”串的引用,
而像new出来的String在新分配的堆内存中内容“abc”,只是常量池中“abc”串的拷贝。所以,请大家不要用new方法来初始化String类型,直接赋值就可以了。
String s6 = "kvill";
String s7 = "kvill";
String s8 = "kv" + "ill";
System.out.println(s6 == s7); // true
System.out.println(s6 == s8);// true
首先,我们要知结果为道Java 会确保一个字符串常量只有一个拷贝。 因为例子中的 s6和s7中的”kvill”都是字符串常量,它们在编译期就被确定了,所以s6==s7为true;而”kv”和”ill”也都是字符串常量,当一个字 符串由多个字符串常量连接而成时, 它自己肯定也是字符串常量,所以s2也同样在编译期就被解析为一个字符串常量,所以s2也是常量池中”kvill”的一个引用。所以我们得出s6==s7==s8;用new String() 创建的字符串不是常量,不能在编译期就确定,所以new String() 创建的字符串不放入常量池中,它们有自己的地址空间。
String s9 = "kvill";
String s10 = new String("kvill");
String s11 = "kv" + new String("ill");
System.out.println(s9 == s10);
System.out.println(s9 == s11);
System.out.println(s10 == s11);
s9还是常量池 中"kvill”的应用,s10因为无法在编译期确定,所以是运行时创建的新对象”kvill”的引用, s11因为有后半部分newString(”ill”)所以也无法在编译期确定,所以也是一个新创建对象”kvill”的引用;明白了这些也就知道为何得出此结果了。
final StringBuffer a = new StringBuffer("111");
final StringBuffer b = new StringBuffer("222");
// a=b;//此句编译不通过
a.append("222");// 编译通过
final只对引用的"值"(即内存地址)有效,它迫使引用只能指向初始指向的那个对象,改变它的指向会导致编译期错误。至于它所指向的对象 的变化,final是不负责的。
String a1 = "a1";
String b1 = "a" + 1;
System.out.println((a1 == b1));
String c1 = "atrue";
String d1 = "a" + "true";
System.out.println((c1 == d1));
String e1 = "a3.4";
String f1 = "a" + 3.4;
System.out.println((e1 == f1));
JVM对于字符串常量的"+"号连接,将程序编译期,JVM就将常量字符串的"+"连接优化为连接后的值,拿"a" +
1来说,经编译器优化后在class中就已经是a1。在编译期其字符串常量的值就确定下来,故上面程序最终的结果都为true。
String str1 = "ab";
String str2 = "b";
String str = "a" + str2;
System.out.println((str1 == str));
JVM对于字符串引用,由于在字符串的"+"连接中,有字符串引用存在,而引用的值在程序编译期是无法确定的,即"a"+bb无法被编译器优化,只有在程序运行期来动态分配并将连接后的新地址赋给str2。所以上面程序的结果也就为false。
String t1 = "ab";
final String t2 = "b";
String t3 = "a" + t2;
System.out.println((t1 == t3)); // result = true
对于final修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的常量 池中或嵌入到它的字节码流中。所以此时的"a" +bb和"a" +"b"效果是一样的。故上面程序的结果为true。
public static String getBB() {
return "b";
}
String aa = "ab";
final String bbb = getBB();
String bb = "a" + bbb;
System.out.println((aa == bb));
JVM对于字符串引用bb,它的值在编译期无法确定,只有在程序运行期调用方法后,将方法的返回值和"a"来动态连接并分配地址为str2,故上面 程序的结果为false。
字符串是一个特殊包装类,其引用是存放在栈里的,而对象内容必须根据创建方式不同定(常量池和堆).有的是编译期就已经创建好,存放在字符串常 量池中,而有的是运行时才被创建.使用new关键字,存放在堆中。
- java内存简单总结
- Java内存模型简单总结
- Java内存泄漏简单的分析总结
- Java内存简单分析
- Java内存简单介绍
- Java内存简单分析
- MTK 内存管理简单总结
- MTK 内存管理简单总结
- MTK 内存管理简单总结
- MTK 内存管理简单总结
- 内存管理的简单总结
- python 内存管理简单总结
- java内存管理总结
- JAVA 内存管理总结
- Java 内存管理总结
- java内存模型总结
- Java 内存管理总结
- java内存泄漏总结
- B. Physics Practical
- respond-design
- .Net调用非托管代码(P/Invoke与C++InterOP)
- jQuery遍历列表数据
- H264 码率控制
- java内存简单总结
- 概率主题模型简介 Introduction to Probabilistic Topic Models
- myeclipse6.5下使用hibernate3.6进行逆向工程
- 透明路由
- 无法创建表,提示:指定的架构名称 "dbo" 不存在,或者您没有使用该名称的权限。解决方法
- Gartner指明2014年几大战略技术趋势
- 修改vim的tab,使其占4个空格
- 关于mybatis中的count(*)
- squashfs 解开和压制