(第2講)javascript中的引數傳遞和java中的引數傳遞
1、javascript中的引數傳遞:值傳遞
(1)在js函式傳遞中,當基本型別(number, string, boolean, null, undefined, symbol)變數作為引數傳遞時,函式內部對引數的任何操作都不會改變變數的值。
(2)當object型別變數作為引數傳遞時,函式內部對引數的操作會影響變數的值,除非函式內部對引數重新賦值(任何型別的值)。
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8"/>
</head>
<body>
<p>welcome </p>
<script language="JavaScript">
var obj = {};
obj.inner = 10;
var num = 10;
var str = 'Hello';
var boo = true;
var oth = null;
var und = undefined;
var sym = Symbol('foo');
function passingobject(myobj){
myobj.inner = 1+myobj.inner;
}
function passingvalue(myValue){
switch (typeof myValue){
case 'number':
myValue = myValue+1;
break;
case 'string':
myValue = 'I am a new string now!';
break;
case 'boolean':
myValue = false;
break;
default :
case 'number':
myValue = 'Null,Undefined,or Symbol';
}
}
console.log("before num"+num);//10
passingvalue(num);
console.log("after num"+num);//10
console.log("before str = " + str); // before str = Hello
passingvalue(str);
console.log("after str = " + str); // after str = Hello
console.log("before boo = " + boo); // before boo = true
passingvalue(boo);
console.log("after boo = " + boo); // after boo = true
console.log("before oth = " + oth); // before oth = null
passingvalue(oth);
console.log("after oth = " + oth); // after oth = null
console.log("before und = " + und); // before und = undefined
passingvalue(und);
console.log("after und = " + und); // after und = undefined
console.log(sym); // Symbol(foo)
passingvalue(sym);
console.log(sym); // Symbol(foo)
console.log("before obj.inner = " + obj.inner); //www.baiyuewang.net before obj.inner = 10
passingobject(obj); // after obj.inner = 11
console.log("after obj.inner = " + obj.inner);
function changeStuff(a, b, c)
{
a = a * 10;
b.item = "changed";
c = {item: "changed"};
}
var num = 10;
var obj1 = {item: "unchanged"};
var obj2 = {item: "unchanged"};
console.log(obj1.item);//unchanged
console.log(obj2.item); // unchanged
console.log(num);//10
changeStuff(num, obj1, obj2);
console.log(num);//10
console.log(obj1.item); // changed
console.log(obj2.item); // unchanged
</script>
</body>
</html>
2、java中的引數傳遞:值傳遞
(1)對於基本型別變數作為引數傳遞時,java是傳遞值的副本,函式內部對引數的任何操作都不會改變變數的值。
(2)對於一切物件型變數,java都是傳遞引用的副本,函式內部對引數的操作會影響變數的值,除非函式內部對引數重新賦值(任何型別的值)。 要注意String型別,因為屬於final型別,所以總是不會被影響
package com.shenzhoufu;
import java.util.*;
public class Reference {
public static void main(String[] args){
//————————boolean——————————————————————————————
boolean b = true;
System.out.println("unchanged:"+b);//true
testBoo(b);//false
System.out.println("changed:"+b);//true
//————————String——————————————————————————————
String str = ",world!";
System.out.println("unchanged:"+str);//,world!
testString(str);//Hello
System.out.println("changed:"+str);//,world!
//————————————StringBuffer———————————————
StringBuffer strb = new StringBuffer(",world!");
System.out.println("unchanged:"+strb);//,world!
testStringBuffer(strb);//,world!hello
System.out.println("changed:"+strb);//,world!hello
}
//基本型別
public static void testBoo(boolean b){
b = !b;
System.out.println("changing(in test):"+b);
}
//String型別
public static void testString(String s){
String string = "Hello";
System.out.println("newString:"+string);
}
//StringBuffer
public static void testStringBuffer(StringBuffer s){
s.append("hello");
System.out.println("changing(in test)StringBuffer:"+s);
}
}
1、物件是按引用傳遞的
2、Java 應用程式有且僅有的一種引數傳遞機制,即按值傳遞
3、按值傳遞意味著當將一個引數傳遞給一個函式時,函式接收的是原始值的一個副本
4、按引用傳遞意味著當將一個引數傳遞給一個函式時,函式接收的是原始值的記憶體地址,而不是值的副本
{
public static void main(String[] args)
{
StringBuffer s= new StringBuffer("good");
StringBuffer s2=s;
s2.append(" afternoon.");
System.out.println(s);
}
}
物件s和s2指向的是記憶體中的同一個地址因此指向的也是同一個物件。
如何解釋“物件是按引用傳遞的”的呢?
這裡的意思是進行物件賦值操作是傳遞的是物件的引用,因此物件是按引用傳遞的,有問題嗎?
程式執行的輸出是:
good afternoon.
這說明s2和s是同一個物件。
這裡有一點要澄清的是,這裡的傳物件其實也是傳值,因為物件就是一個指標,這個賦值是指標之間的賦值,因此在java中就將它說成了傳引用。(引用是什麼?不就是地址嗎?地址是什麼,不過就是一個整數值)
class Test2
{
public static void main(String[] args)
{ StringBuffer s= new StringBuffer("good");
StringBuffer s2=new StringBuffer("bad");
test(s,s2);
System.out.println(s);// goodhah
System.out.println(s2);//bad為什麼呢????有大神能解釋麼
}
public static void test(StringBuffer s,StringBuffer s2) {
System.out.println(s);//good
System.out.println(s2);//bad
s2=s;
s=new StringBuffer("new");
System.out.println(s);//new
System.out.println(s2);//good
s.append("hah");
s2.append("hah");
System.out.println(s);//newhah
System.out.println(s2);//goodhah
}
}
——————————————————————————————————————————————————
不同的作業系統不太一樣,但一般記憶體都分為4個區域:
1)heap(堆):存放new出來的物件
2)stack(棧):存放區域性變數
3)data segment(資料區):靜態變數 和 字串常量
4)code segment(程式碼區):存放程式碼
Java中進行方法呼叫的時候傳遞引數時,遵循值傳遞的原則:
1)基本資料型別,傳遞的是資料的拷貝
2)引用資料型別,傳遞的是傳遞的引用地址的拷貝,而不是該物件本身
例子:public class Test {
void f(int j) {
System.out.println(j);
}
void ff(String ss) {
System.out.println(ss);
}
public static void main(Stirng[] args) {
int i = 100;
String s = "hello";
Test t = new Test();
t.f(i);
t.ff(s);
}
}
記憶體中的執行過程:
當mian方法開始執行的時候
(1)int i = 100; 棧中分配一塊空間,存放變數i,值為100,基本資料型別只佔一塊空間;
(2)String s = "hello"; "hello"是字串常量,分配在data區,字串常量為String類的一個物件,s指向了這個"hello"物件,這就是引用資料型別,在記憶體中佔兩塊空間;有點形象思維:一提引用型別,就是一塊記憶體指向另一塊記憶體s可以被叫做:引用、引用變數、引用地址,其實s就是一個指標,在這裡不用鑽牛角尖,你就知道s是一個引用,s的值是一個地址,根據這個地址就可以找到一個物件就ok了
(3)Test t = new Test(); 同理,棧中的引用t指向了堆中new出來的這個Test物件;
(4)t.f(i); 方法的形參屬於區域性變數,所以在呼叫f方法的時候,棧記憶體分配一個int型的變數j,將i的值當做實參傳遞過去,i的值是100,現在將100拷貝給了j,那麼j的值就是100,這就是樓主說的“值傳遞”,接著列印,最後方法結束,為該方法分配的區域性變數立刻全部清空,那麼Stack中這個j消失了;
(5)t.ff(s); 呼叫ff方法的時候,棧記憶體分配一個String型的變數ss,將s的值當做實參傳遞過去,s指向了"hello"物件,s的值是一個地址,現在將這個地址拷貝給了ss,那麼ss也就指向這個"hello"了這就是樓主說的"引用傳遞",現在s 和 ss 兩個引用 同時指向了"hello"物件,然後列印ss,最後方法結束,棧中這個ss被清除;
現在main方法執行結束,為main方法分類的區域性變數清除,i,s,t全部消失,data區的符串常量"hello"和堆記憶體的Test物件,由於沒有任何引用指向他們了,就會被垃圾收集器回收