您的位置:首页 > 编程语言 > Java开发

Java中对象的内存分配问题

2016-03-22 21:06 423 查看
1.先看一下一下程序代码:

public class MyClass {

public static void main(String[] args) {
String s1 = new String("Hello World!");
String s2 = new String("Hello World!");
String s3 = "Hello World!";
String s4 = "Hello World!";
int t1 = new Integer(1);
int t2 = new Integer(1);
int t3 = 1;
int t4 = 1;

System.out.println("两个new String对象:" + (s1 == s2));
System.out.println("两个String对象:" + (s3 == s4));
System.out.println("两个new Interger对象:" + (t1 == t2));
System.out.println("两个int对象:" + (t3 == t4));
}

}


输出结果如下:

两个new String对象:false
两个String对象:true
两个new Interger对象:true
两个int对象:true


2.查询了一下资料,得到关键字“==”存在如下特性:

基本数据类型(也称原始数据类型):byte,short,char,int,long,float,double,boolean。他们之间的比较,应用双等号(==),比较的是他们的值。

复合数据类型(类):当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址(确切的说,是堆内存地址)。

注:对于第二种类型,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。因为每new一次,都会重新开辟堆内存空间。

3.结论如下:

Java中对象主要存储在堆栈(有时简称栈)和堆中。一般用new关键字,会将新建的对象存储在堆中,因此以上的程序实例中,两个new String对象并不相等,但对于基本数据类型,例如
boolean,char,byte,short,int,long,float,double
等数据类型,Java采用与C和C++相同的方法,不用new来创建变量,而是创建一个并非是引用的“自动变量”,这个变量直接存储“值”,并置于堆栈中,使得这种小的、简单的变量效率变高,这也就是上面的程序实例中,两个new int对象相等,输出为true。

对于非new创建出来的变量,Java会在其字符串常量池(仍位于堆中)创建字符集,然后将对象指向该字符集,当字符串常量池中已有某个字符集时,再次创建“值”相同的对象,指向与前一对象的指向是相同的,这也就是为什么上面两个int和String对象输出都是true

4.关于引用传递,先看如下代码:

public class ManTest {

int age;
String name;

ManTest()
{
this.age = 0;
this.name = null;
}

ManTest(int age,String name)
{
this.age = age;
this.name = name;
}

public void ShowInfo()
{
System.out.println("姓名:" + this.name + ";年龄:" + this.age);
}

public void ChangeInfo( ManTest man)
{
man.age = 10;
man.name = "小明";
}

public static void main(String args[])
{
ManTest man = new ManTest(15,"小红");
man.ShowInfo();
man.ChangeInfo(man);
System.out.println("改变后--------------");
man.ShowInfo();
}
}


输入如下:

姓名:小红;年龄:15
改变后--------------
姓名:小明;年龄:10


引用传递的本身是值传递,但这里实际传递的是对象的hashcode,关于hashcode的资料摘抄如下:

hashCode是指对象的散列码,具体值是由对象的hashCode()方法返回的值,,你甚至可以重写该方法让每个对象的hashCode都一样。散列码一般是和HashTable HashMap这种基于散列码的集合有用,用于提高在集合中查询对象的速度。

而内存地址是对象在内存中的位置,一般和hashCode无关。不过Object对象的hashCode方法是个native方法,有可能和对象的内存地址有关。

ChangeInfo
函数进行修改,使其输出对象的hashcode值,输出如下,可以看到两者的hashcode是完全相同的:

姓名:小红;年龄:15
传入方法前:1669472530
传入方法后:1669472530
改变后--------------
姓名:小明;年龄:10


由此可以看到,Java引用可以改变实参的内容,但是不能改变实参对象本身。这可以通过以下代码来说明。对
ChangeInfo
函数和
main
函数进行如下修改:

public void ChangeInfo( ManTest man)
{
System.out.println("传入方法后:" + man.hashCode());
man = new ManTest(10,"小明");
System.out.println("改变对象后:" + man.hashCode());
System.out.println("在类体的方法中,姓名:" + this.name + ";年龄:" + this.age);
}

public static void main(String args[])
{
ManTest man = new ManTest(15,"小红");
man.ShowInfo();
System.out.println("传入方法前:" + man.hashCode());
man.ChangeInfo(man);
System.out.println("改变后--------------");
man.ShowInfo();
}


输出如下:

传入方法前:2065827189
传入方法后:2065827189
改变对象后:1989444474
在类体的方法中,姓名:小红;年龄:15
改变后--------------
姓名:小红;年龄:15


可以看到,传入的对象没有得到改变。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息