大纲:
1.什么是值类型,什么是引用类型?
2.值类型int和引用类型Integer的区别和转换
3.Java之按值传递和按引用传递
4.Java的equals和==的区别(联系值类型和引用类型)
5.Java内存为什么有堆栈之分?
正文:
1.什么是值类型,什么是引用类型?
[值类型]:也就是基本数据类型
八种: 1,整型 byte,short,int,long
2,浮点型 float,double
3,字符型 char
4,逻辑型 boolean
[引用类型]
除了以上八种基本类型外,所有的类型都称为引用类型 如:Interger Double Float String 数组
2.值类型int和引用类型Integer的区别和转换
一个具有值类型(value type)的数据存放在栈内的一个变量中。即是在栈中分配内存空间,直接存储所包含的值,其值就代表数据本身。值类型的数据具有较快的存取速度。
一个具有引用类型(reference type)的数据并不驻留在栈中,而是存储于堆中。即是在堆中分配内存空间,不直接存储所包含的值,而是指向所要存储的值,其值代表的是所指向的地址。当访问一个具有引用类型的数据时,需要到栈中检查变量的内容,该变量引用堆中的一个实际数据。引用类型的数据比值类型的数据具有更大的存储规模和较低的访问速度。
int Integer 为例:
int 是基本数据类型,Integer 是一个类(引用类型),是int的扩展,是对int的封装,定义了很多的转换方法。
int a=1;
Integer b=new Integer(a);//jdk1.5之前int转Integer
Integer b=a;//jdk1.5之后int转Integer--拆箱装箱机制
a=b.intValue();//Integer转int
拆箱和装箱
装箱(值类型到引用类型)。将一个值类型变量装箱成一个引用类型变量,首先会在托管堆上为新的引用类型变量分配内存空间,然后将值类型变量拷贝到托管堆上新分配的对象内存中,最后返回新分配的对象内存地址。
拆箱(引用类型到值类型)。 获取只想对象中包含值类型部分的指针,然后由程序员手动将其对应的值拷贝给值类型变量。
3.Java之按值传递和按引用传递
在Java里面只有基本类型和按照下面这种定义方式的String是按值传递,其它的都是按引用传递。就是直接使用双引号定义字符串方式:String str = “lingyongqian”;
[值传递]
基本数据类型赋值都属于值传递,传递的是值的拷贝,值传递后,实参传递给形参的值,形参发生改变而不影响实参。即传递后就互不相关。
典型例子:
public class Test {
private void test1(int a){
a = 5;
System.out.println("test1方法中的a="+a);
}
public static void main(String[] args) {
Test t = new Test();
int a = 3;
t.test1(a);//这里传递的参数a就是按值传递,传递后,test1方法对变量值的改变不影响这里的a
System.out.println(”main方法中的a=”+a);
输出结果:
test1方法中的a=5
main方法中的a=3
[引用传递]
引用类型之间赋值属于引用传递。引用传递传递的是对象的引用地址,就是变量所对应的内存空间的地址。也就是它的本身。就是将实参的地址传递给形参,形参改变了,实参当然被改变了,因为他们指向相同的地址。传递前和传递后都指向同一个内存空间。
典型例子
public class Test {
private void test1(A a){
a.age = 20;
System.out.println("test1方法中的age="+a.age);
}
public static void main(String[] args) {
Test t = new Test();
A a = new A();
a.age = 10;
t.test1(a);//这里传递的参数a就是按引用传递
System.out.println(”main方法中的age=”+a.age);
}
}
class A{
public int age = 0;
}
输出结果:
test1方法中的age=20
main方法中的age=20
4.Java的equals和==的区别(联系值类型和引用类型)
对于基本数据类型,值类型来说。他们之间的比较应该用(==)比较的他们的值。
int a=2;int b=2 int c=2;
System.out.println(a==b);输出应为true (int基本数据类型,存在栈中,栈有一个很重要的特性,就是存在栈中的数据可以共享。变量a,b,c同时指向2这个字面值)
对于复合数据类型,引用类型来说。如Integer Double等(==)比较的是内存中的地址空间。同一个引用new出来的对象,比较结果是true。(equals)比较的是地址的值。
String s1 = "haha";
String s2 = “haha”;
System.out.println(s1==s2);—>输出的应为true
说明:s1 与 s2 引用同一个 String 对象。
注意⚠️:
String是一个特殊的包装类数据
关于String str = "abc "的内部工作。Java内部将此语句转化为以下几个步骤:
(1)先定义一个名为str的对String类的对象引用变量:String str;
(2)在栈中查找有没有存放值为 "abc "的地址,如果没有,则开辟一个存放字面值为 "abc "的地址,接着创建一个新的String类的对象o,并将o 的字符串值指向这个地址,而且在栈中这个地址旁边记下这个引用的对象o。如果已经有了值为 "abc "的地址,则查找对象o,并返回o的地址。
(3)将str指向对象o的地址。
值得注意的是,一般String类中字符串值都是直接存值的。但像String str = "abc ";这种场合下,其字符串值却是保存了一个指向存在栈中数据的引用!
String s1=new String(“haha”);
String s2=new String(“haha”);
System.out.println(s1==s2);—>输出的应为false
说明:用new的方式是生成不同的对象,每一次生成一个。
String s1 = “haha";
String s2=new String(“haha”);
System.out.println(s1==s2); —>输出应为false
说明s1与s2分别引用了两个String对象。
而上述三种System.out.println(s1.equals(s2) );输出为true,即它们的内存地址的值是相同的。
5.Java内存为什么有堆栈之分?
当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈也会自然销毁,因此所有在方法中定义的变量都是放在栈内存中。栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
当我们在程序中创建一个对象的时候,这个对象将保存到运行时数据区,以便反复利用(因为对象的创建成本比较大),这个运行时数据区就是堆内存,堆内存中的数据不会随方法的结束而销毁,即使方法结束后,这个对象依然不会被销毁,只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在合适的时候回收它。