一切皆對(duì)象
在 Java 中男杈,一切皆為對(duì)象挂脑。這里需要區(qū)分引用和對(duì)象迫肖。
對(duì)象和引用
//等號(hào)左側(cè)的變量名為引用
//等號(hào)右邊的為對(duì)象拷呆。
String str = "Hello World";
String str1 = new String("Hello World");
//false
System.out.println(str==str1);
//true
System.out.println(str==str.intern());
對(duì)于 str 和 str1 引用了不同的地址坡氯,但 str 和 str1 在常量池中的地址卻是一樣的。
數(shù)據(jù)存儲(chǔ)
在程序運(yùn)行時(shí),有以下五個(gè)地方用于存放數(shù)據(jù):
- 寄存器:位于處理器箫柳,存儲(chǔ)速度最快手形,但是數(shù)量有限,不允許直接控制悯恍。
- 棧:位于 RAM 库糠,速度僅次于寄存器。先進(jìn)后出涮毫,壓棧出棧瞬欧。Java 中引用、局部變量罢防、基本類型都存儲(chǔ)于此艘虎。
- 堆:位于 RAM ,用于存儲(chǔ) Java 對(duì)象咒吐,且不需要知道對(duì)象的生命周期野建,創(chuàng)建和回收比棧費(fèi)時(shí)。
- 常量存儲(chǔ):通常直接放于程序代碼內(nèi)部恬叹。
- 非RAM存儲(chǔ):流對(duì)象和持久化對(duì)象候生。如:文件的存儲(chǔ)。
基本類型
Java 中基本類型的大小绽昼、最大值唯鸭、最小值及包裝器對(duì)應(yīng)表。Java 5.0 之后提供了自動(dòng)裝箱和拆箱功能硅确。
高精度數(shù)字
Java 提供 BigInteger 和 BigDecimal 用于高精度計(jì)算目溉,兩者沒(méi)有對(duì)應(yīng)的基本類型。原則上菱农,只要計(jì)算機(jī)有足夠內(nèi)存缭付,兩者能表示的位數(shù)就是無(wú)限大。
BigInteger:支持任意精度的整數(shù)大莫。
BigDecimal:支持任意精度的定點(diǎn)數(shù)
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("請(qǐng)輸入需要計(jì)算的值,如:100000000000000000 1988930304");
while (scanner.hasNext()) {
BigInteger a = scanner.nextBigInteger();
BigInteger b = scanner.nextBigInteger();
System.out.println("和為=" + a.add(b));
}
}
作用域
作用域決定了變量的可見(jiàn)性和生命周期。但是在 Java 中對(duì)象不具備和基本類型一樣的生命周期官份。一個(gè) Java 對(duì)象可以存活于作用域之外只厘。
public void scope() {
//變量i在方法執(zhí)行結(jié)束時(shí)就會(huì)失效
int i = 0;
//引用str在方法執(zhí)行結(jié)束時(shí)就會(huì)失效,我們無(wú)法用引用str繼續(xù)訪問(wèn)這個(gè)對(duì)象
//但引用所指向的對(duì)象會(huì)一直存在直到被系統(tǒng)的垃圾回收器回收舅巷。
String str = new String("Hello World!");
}
垃圾回收有兩種方法:引用計(jì)數(shù)法和可達(dá)性分析法羔味。在 Java 中使用的是后一種
- 引用計(jì)數(shù)法
直接計(jì)數(shù),簡(jiǎn)單高效钠右,Python便是采用該方法赋元。但是如果出現(xiàn) 兩個(gè)對(duì)象相互引用,即使它們都無(wú)法被外界訪問(wèn)到,計(jì)數(shù)器不為0它們也始終不會(huì)被回收搁凸。為了解決該問(wèn)題媚值,java采用的是可達(dá)性分析法。
- 可達(dá)性分析法
這個(gè)方法設(shè)置了一系列的“GC Roots”對(duì)象作為索引起點(diǎn)护糖,如果一個(gè)對(duì)象 與起點(diǎn)對(duì)象之間均無(wú)可達(dá)路徑褥芒,那么這個(gè)不可達(dá)的對(duì)象就會(huì)成為回收對(duì)象。這種方法處理 兩個(gè)對(duì)象相互引用的問(wèn)題嫡良,如果兩個(gè)對(duì)象均沒(méi)有外部引用锰扶,會(huì)被判斷為不可達(dá)對(duì)象進(jìn)而被回收(如下圖)。
0
方法寝受、參數(shù)和返回值
在 Java 中坷牛,方法屬于類的一部分,方法的基本形式如下:
public/protect/private/defualt 返回類型 methodName(參數(shù)列表) {}
方法名和參數(shù)列表唯一的標(biāo)識(shí)一個(gè)方法很澄。
方法調(diào)用有兩種方式:
//調(diào)用對(duì)象的方法
object.method(arg1,arg2);
//調(diào)用類方法京闰,類方法用 static 進(jìn)行修飾
Class.method(arg1,arg2);
方法中的參數(shù)如果為對(duì)象,則傳遞的參數(shù)為引用痴怨,對(duì)引用的修改會(huì)導(dǎo)致原始數(shù)據(jù)的改變忙干。下面的例子是用來(lái)測(cè)試修改引用類型參數(shù)的內(nèi)容會(huì)不會(huì)影響到原始數(shù)據(jù)的 demo。
補(bǔ)充:
- 對(duì) String 類型的參數(shù)修改會(huì)表現(xiàn)出基本類型參數(shù)的特性浪藻,具體原因分析可見(jiàn):Java-String類型的參數(shù)傳遞問(wèn)題
- 值傳遞和引用傳遞的區(qū)別
- 值傳遞:方法操作的是參數(shù)變量(也就是原型變量的一個(gè)值的拷貝)改變的也只是原型變量的一個(gè)拷貝而已捐迫,而非變量本身。所以變量原型并不會(huì)隨之改變爱葵。
- 引用傳遞:也叫做傳址施戴,即方法操作參數(shù)變量時(shí)是拷貝了變量的引用,而后通過(guò)引用找到變量(在這里是對(duì)象)的真正地址萌丈,并對(duì)其進(jìn)行操作赞哗。當(dāng)該方法結(jié)束后,方法內(nèi)部的那個(gè)參數(shù)變量隨之消失辆雾。但是要知道這個(gè)變量只是對(duì)象的一個(gè)引用而已肪笋,它只是指向了對(duì)象所在的真實(shí)地址,而非對(duì)象本身度迂,所以它的消失并不會(huì)帶來(lái)什么負(fù)面影響藤乙。回頭來(lái)看原型變量惭墓,原型變量本質(zhì)上也是那個(gè)對(duì)象的一個(gè)引用(和參數(shù)變量是一樣一樣的)坛梁,當(dāng)初對(duì)參數(shù)變量所指對(duì)象的改變就根本就是對(duì)原型變量所指對(duì)象的改變。所以原型變量所代表的對(duì)象就這樣被改變了腊凶,而且這種改變被保存了下來(lái)划咐。
public static void main(String[] args) {
//按理說(shuō)拴念,執(zhí)行change方法修改參數(shù),但是并沒(méi)有按預(yù)期輸出
//這是個(gè)值得探尋的問(wèn)題
String str = "1";
System.out.println("str=" + str + "褐缠,address in memory=" + str.getClass() + "@" + str.hashCode());
change(str);
System.out.println(str.toString());
System.out.println("after ref,str=" + str+ "政鼠,address in memory=" + str.getClass() + "@" + str.hashCode());
//執(zhí)行change方法對(duì)參數(shù)進(jìn)行修改會(huì)影響到原始數(shù)據(jù)
Person person = new Person(10);
System.out.println("person=" + person.toString());
change(person);
System.out.println("after person=" + person.toString());
}
private static void change(String string) {
System.out.println(string+ ",address in memory=" + string.getClass() + "@" + string.hashCode());
string = "123";
System.out.println(string+ "送丰,address in memory=" + string.getClass() + "@" + string.hashCode());
}
private static void change(Person person) {
person.setAge(11);
}
public static class Person {
private int age;
public Person(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
'}';
}
}
輸出如下:
str=1缔俄,address in memory=class java.lang.String@49
1,address in memory=class java.lang.String@49
123器躏,address in memory=class java.lang.String@48690
1
after ref,str=1俐载,address in memory=class java.lang.String@49
person=Person{age=10}
after person=Person{age=11}