栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。
1)栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放,目的就在于最快速度取值,个人觉得栈就好比一个常量池,用到谁,谁就被指向,很少用到的,慢慢被内存释放掉。
2)堆则是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些,个人觉得堆是一个通讯录,写清楚了每个人的地址,真正想知道每个人住什么样的房子,那么就沿着这个引用找到这个值对应的内存位置,如果是原生数据类型,那么这些值就在栈中,如果是字符串就要视情况,再次判断。
因为,原生数据类型的大小和生命周期,我们都是预知的,所以,它会存在栈中,如果定义一个int类型的变量,int a=3;那么首先会在栈中创建一个名为a的引用,然后在栈中寻找是否拥有值为3的地址,如果存在。那么将引用a指向这个地址,如果没有那么先开辟一个地址存放3这个值,再将引用a指向这个地址。原生数据类型值得修改,不会修改存放3这个地址的值,而是从栈中再去寻找是否有存放值为修改后的值得地址,没有的话那么继续开辟地址,有的话将引用指向这个地址。
不同于其他封装类,String 比较特别,例如:String a="ccc";和 String a=new String("ccc");是有区别的,a="ccc"它不一定生成对象,如果栈中存在一个地址存放"ccc",那么a就直接指向栈中这个地址,如果没有,在堆中创建一个引用a,用于指向一个值为这个的地址。
我个人理解是这样的,赋值运算一般属于编译过程,例如:String a="ccc";那么String a=new String("ccc");生成新对象应属于一个运行过程的动作,编译过程中会先寻找字符串中池中是否有值为“ccc”的变量,如果没有就在池中创建一个“ccc”,再在堆中创建一个引用指向池中这个地址,类似于new方法,字符串的拼接:String a="ccc";String b="vvvv";String c= a+b;这个过程也属于运行期间才知道的,所以,同样会在堆中创建一个新的对象。
毕竟,也是个初学者可能理解的不是很深入,下面是一个简单的测试程序:
public class StringTest
{
public static void main(String[] args)
{
String str = "ccc";
String str1 = "ccc";
boolean bo = (str.equals(str1));
boolean b = (str==str1);
String str2 = new String("aaa");
String str3 = "aaa";
boolean bo1 = (str2.equals(str3));
boolean b1 = (str2==str3);
String str4 = new String("bbb");
String str5 = new String("bbb");
boolean bo2 = (str4.equals(str5));
boolean b2 = (str4==str5);
System.out.println(b);
System.out.println(b1);
System.out.println(b2);
System.out.println(bo+"-----");
System.out.println(bo1+"-----");
System.out.println(bo2+"-----");
Object obj = new Object();
Object obj1 = new Object();
boolean ob = (obj==obj1);
boolean ob1 = (obj.equals(obj1));
boolean ob2 = (obj.equals(obj));
System.out.println(ob+"///");
System.out.println(ob1+"///");
System.out.println(ob2+"///");
Student student = new Student("zhangsan");
Student student1 = new Student("zhangsan");
boolean ob3 = (student.equals(student1,student));
System.out.println(ob3+"****");
Teacher te = new Teacher("lisi");
Teacher te1 = new Teacher("lisi");
boolean ob4 = (te.equals(te1));
System.out.println(ob4+"---");
Book book = new Book("java");
Book book1 = new Book("java");
boolean bb = (book.autor==book1.autor);
boolean bb1 = (book.name==book1.name);
boolean bb2 = (book.autor.equals(book1.autor));
boolean bb3 = (book.name.equals(book1.name));
System.out.println(bb);
System.out.println(bb1);
System.out.println(bb2);
System.out.println(bb3);
}
}
class Student
{
String name;
public Student(String name)
{
this.name=name;
}
public boolean equals(Student student,Student student1)
{
if(student.name.equals(student1.name))
{
return true;
}
else
{
return false;
}
}
}
class Teacher
{
String name;
public Teacher(String name)
{
this.name = name;
}
}
class Book
{
public static String name="ring";
String autor ;
public Book(String autor)
{
this.autor = autor;
}
}
运行结果如下:
true
false
false
true-----
true-----
true-----
false///
false///
true///
true****
false---
true
true
true
true
所以可以认为String类型可以认为是介于原生数据类型与Objiect类型的特殊类型,关键在于是否生成了对象以及字符串池的定义。