一、基本类型和引用类型
java中一共分为8种基本数据类型:byte、short、int、long、float、double、char、boolean,其中byte、short、int、long是整型.float、double是浮点型,char是字符型,boolean是布尔型.
除了基本的数据类型,其余都是引用型的,像数组、类等.
一个具有引用类型的数据并不驻留在栈中,而是存储于堆中.即是在堆中分配内存空间,不直接存储所包含的值 ,而是指向所要存储的值,其代表的是所指向的地址.当访问一个具有引用类型的数据时,需要到栈中检查变量的内容,改变两引用堆中的一个实际数据.引用类型的数据比值类型的数据具有更大的存储规模和较低的访问速度.引用指向实际对象,实际对象中保存着内容.
例如下面代码:
int num = 20;
String str = "java";
对于基本类型 num ,赋值运算符会直接改变变量的值,原来的值被覆盖掉.
**对于引用类型 str,赋值运算符会改变引用中所保存的地址,原来的地址被覆盖掉,但是原来的对象不会被改变.如上图所示,“hello” 字符串对象没有被改变(没有被任何引用所指向的对象是垃圾,会被垃圾回收器回收). **
二、值传递和引用传递
值传递:方法调用时,实际参数将它的值传递给对应的形式参数,函数接收到的是原始值的副本,此时内存中存在两个相等的基本类型,若方法中对形参执行处理操作,并不会影响实际参数的值.(基本数据类型)
引用传递:方法调用时,实际参数的引用(是指地址,而不是参数的值)被传递给方法中相应的形式参数,函数接收到的是原始值的内存地址,在方法中,形参与实参的内容相同,方法中对形参的处理会影响实参的值.(数组,类,接口)
简单来说:如果参数是基本类型,传递的是基本类型的字面量值的拷贝.
如果参数是引用类型,传递的是该参量所引用的对象在堆中地址值的拷贝.
第一个例子,基本类型:
void foo(int value) {
value = 100;
}
// main方法中调用此方法
foo(num);// num 没有被改变
第二个例子:没有提供改变自身方法的引用类型
void foo(String text) {
text = "windows";
}
// main方法中调用此方法
foo(str); // str 也没有被改变
第三个例子:提供了改变自身方法的引用类型
StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
builder.append("4");
}
foo(sb); // sb 被改变了,变成了"iphone4"
第四个例子:提供了改变自身方法的引用类型,但是不使用,而是使用赋值运算符
StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
builder = new StringBuilder("ipad");
}
foo(sb); // sb 没有被改变,还是 "iphone"
下面是第三个例子的图解:
执行方法之后:
下面是第四个例子的图解:
执行方法之后:
参考:https://www.zhihu.com/question/31203609