內(nèi)存中的對(duì)象
| 數(shù)據(jù)類型 | 儲(chǔ)存位置 |
|---|---|
| 基本類型(char byte short int long float double boolean) | 棧 |
| Java對(duì)象 | 堆 |
??
- 聲明基本類型時(shí),棧中就會(huì)分配一些字節(jié)
- 聲明引用變量時(shí),棧中也會(huì)分配一些字節(jié),但是內(nèi)存中不包含對(duì)象的數(shù)據(jù),只包含對(duì)象在堆中的地址
例如:Book book;就把一些字節(jié)分配給引用變量book。book的初始值為null,因?yàn)檫€沒(méi)有對(duì)象賦給它
執(zhí)行book = new Book();就創(chuàng)建了Book的一個(gè)實(shí)例,它儲(chǔ)存在堆中,并將這個(gè)實(shí)例的地址賦給引用變量book。
一個(gè)對(duì)象可以被多個(gè)引用變量引用:
Book myBook = new Book();
Book yourBook = myBook;
第二行代碼把myBook的值復(fù)制給yourBook,結(jié)果是yourBook現(xiàn)在和myBook引用同一個(gè)Book對(duì)象。
類訪問(wèn)控制修飾符
類具有兩種訪問(wèn)修飾
- public
- 默認(rèn)缺省
package base;
public class Book {
String name;
int number;
}
Book 類是base包的一個(gè)成員,由于Book類是公用的,可從任何其他類實(shí)例化。
package base;
class Stu{
String name;
int age;
}
Stu 類的訪問(wèn)限制就是缺省的,只能被同一個(gè)包中的其他類使用。
一個(gè)Java源文件只能包含一個(gè)公共類,但可以包含多個(gè)非公共類
類成員訪問(wèn)修飾符
| 訪問(wèn)級(jí)別 | 從其他包中 | 從同一個(gè)包中的類 | 從子類 | 從同一個(gè)類 |
|---|---|---|---|---|
| Public | 是 | 是 | 是 | 是 |
| Protected | 否 | 是 | 否 | 是 |
| 缺省(包私有) | 否 | 是 | 是 | 是 |
| Private | 否 | 否 | 否 | 是 |
final變量
final 聲明的變量,一旦賦值,就不能改變
?? 注意
- final聲明的基本變量,賦值之后,就不可改變其值
- final 聲明的引用變量(Java對(duì)象),賦值之后,其內(nèi)部屬性可以修改,但引用變量不能再引用其他對(duì)象
本質(zhì)是因?yàn)椋篺inal 限定了變量的棧區(qū)不可改變
package base;
public class Book{
String name;
int age;
public static void main(String args[]){
final Book book = new Book();
final int a = 10;
a = 20; //報(bào)錯(cuò)
book.name = "name";
book.age = 20;
book.age = 21;
book.name = "name2";
book = new Book(); //報(bào)錯(cuò)
}
}
static靜態(tài)變量
?? 靜態(tài)引用變量 static Book book = new Book(); book變量將包含Book對(duì)象的地址,對(duì)象還是儲(chǔ)存在堆中
參數(shù)傳遞
| 數(shù)據(jù)類型 | 傳遞方式 | 說(shuō)明 |
|---|---|---|
| 基本類型 | 值傳遞 | JVM將會(huì)把傳遞進(jìn)來(lái)的變量復(fù)制給一個(gè)新的局部變量 |
| 引用變量 | 引用傳遞 | 局部變量就指向和引用變量一樣的對(duì)象 |
JVM執(zhí)行類的流程
加載->鏈接->初始化
- 加載 JVM將Java類的二進(jìn)制形式加載到內(nèi)存中,并將它緩存在內(nèi)存中,以便再次使用 * 如果沒(méi)有找的制定的類就會(huì)拋出錯(cuò)誤*
- 鏈接 驗(yàn)證->準(zhǔn)備->解析
- 驗(yàn)證 JVM根據(jù)Java編程語(yǔ)言和JVM的語(yǔ)義要求檢查這個(gè)二進(jìn)制形式
- 準(zhǔn)備 準(zhǔn)備要執(zhí)行的類:給這個(gè)類的靜態(tài)變量和其他數(shù)據(jù)分配內(nèi)存控件
- 解析 檢查該類是否引用類其他類/接口,是否能找到和加載其他類/接口,這些檢查是針對(duì)被引用的類/接口遞歸進(jìn)行
- 初始化 JVM用賦值或者缺省值將靜態(tài)變量初始化,并執(zhí)行靜態(tài)初始化程序(static塊中的代碼),初始化發(fā)生在執(zhí)行main方法之前。在初始化之前,類的父類必須先被初始化。這個(gè)過(guò)程遞歸進(jìn)行,直到要初始化的類處于層次結(jié)構(gòu)的最上端為止。
| 類型 | 默認(rèn)值 |
|---|---|
| boolean | false |
| byte | 0 |
| short | 0 |
| int | 0 |
| long | 0L |
| float | 0.0f |
| char | \u0000 |
| double | 0.0d |
| 對(duì)象引用 | null |
對(duì)象比較
?? 引用變量并不包含對(duì)象,而是包含對(duì)象在內(nèi)存(棧)中的地址
因此:
Object a = new Object();
Object b = new Object();
a == b 將返回 false
這樣的比較實(shí)際沒(méi)有多大用處,因?yàn)榇蠖鄶?shù)時(shí)候我們更關(guān)心對(duì)象,而不是對(duì)象的地址。
所以,比較對(duì)象可以通過(guò)兩種方式:
- 提供比較對(duì)象的工具類
- 為類實(shí)現(xiàn)繼承自
java.lang.Object的equals和hashCode方法
Java多態(tài)
多態(tài)是Java面向?qū)ο笕筇匦灾?/p>
要實(shí)現(xiàn)Java多態(tài)有3個(gè)必要條件和2種實(shí)現(xiàn)方式
必要條件
- 繼承
- 重寫(xiě)
- 向上轉(zhuǎn)型
實(shí)現(xiàn)方式
- 繼承
- 接口
對(duì)于繼承實(shí)現(xiàn)的多態(tài):
對(duì)于引用子類類型的父類,在處理該引用時(shí),它適用于繼承該父類的所有子類,子類的
對(duì)象不同,對(duì)方法的實(shí)現(xiàn)也就不同,執(zhí)行相同動(dòng)作產(chǎn)生的行為也就不同。
對(duì)于接口實(shí)現(xiàn)的多態(tài):
指向接口的引用必須是指定實(shí)現(xiàn)了該接口的一個(gè)類的實(shí)例,在運(yùn)行時(shí),根據(jù)對(duì)象引用的實(shí)際類型來(lái)執(zhí)行對(duì)應(yīng)的方法
在繼承鏈中,對(duì)象方法的調(diào)用存在一個(gè)優(yōu)先級(jí)
該優(yōu)先級(jí)為:
this.fun()
super.fun()
this.fun((super)O)
super.fun((super)O)
下面是經(jīng)典的多態(tài)例子:
class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
class C extends B{
}
class D extends B{
}
public class Main {
public static void main(String[] args){
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println("1--" + a1.show(b));//輸出A-A
//執(zhí)行A的show(A object)
//this.show() no
//super.show() no
//(super)b = A
//this.show((super)b) yes
System.out.println("2--" + a1.show(c));//輸出A-A
//因?yàn)锳中沒(méi)有show(C object)方法,
//所有到A的父類中尋找,但是A沒(méi)有父類,
//所以執(zhí)行show((super)c),c的父類為B和A
//因?yàn)锳中只有show(A object)方法,所以最終執(zhí)行show(A object)
/**
* 實(shí)質(zhì)執(zhí)行:a1.show((super)c);
*/
//this.show() no
//super.show() no
//(super)c = B/A
//this.show((super)c=B) no
//this.show((super)c=A) yes
System.out.println("3--" + a1.show(d));//輸出A-D
//執(zhí)行A的show(D Object)
System.out.println("4--" + a2.show(b));//輸出B-A
//a2.show()實(shí)質(zhì)優(yōu)先調(diào)用a2引用的對(duì)象的show方法
//a2的this是指向B的對(duì)象
//this.show no
//super.show no
//(super)b = A
//this.show((super)b) yes
System.out.println("5--" + a2.show(c));//輸出B-A
//a2.show()實(shí)質(zhì)優(yōu)先調(diào)用a2引用的對(duì)象的show方法
//但是B中沒(méi)有show(C object)方法,于是到B的父類A中尋找,也沒(méi)有show(C object)方法,
//于是回到B中嘗試執(zhí)行show((super)c),c的super是B和A,
//B的父類A中只有針對(duì)A的show方法,所以執(zhí)行B中重寫(xiě)的父類的show(A object)方法,而不會(huì)執(zhí)行B的show(B object)
//this.show no
//super.show no
//(super)c = B/A
//this.show((super)c = B) yes
System.out.println("6--" + a2.show(d));//輸出A-D
//a2指向B的對(duì)象中沒(méi)有show(D object)方法,于是到父類A中查找,發(fā)現(xiàn)有符合,
//所以執(zhí)行B的父類A的show(D object)
//this.show no
//super.show yes
System.out.println("7--" + b.show(b));//輸出B-B
//this.show yes
System.out.println("8--" + b.show(c));//輸出B-B
//this.show no
//super.show no
//(super)c = B/A
//this.show((super)c=B) yes
System.out.println("9--" + b.show(d));//輸出A-D
//this.show no
//super.show yes
}
}
運(yùn)行結(jié)果如下:
1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D