Advanced Language Features
知識(shí)點(diǎn):一. static修飾符
static修飾符可以用來修飾類的成員變量鬼譬、成員方法和代碼塊诀蓉。
. 用static修飾的成員變量表示靜態(tài)變量什湘,可以直接通過類名來訪問骑祟;
. 用static修飾的成員方法表示靜態(tài)方法,可以直接通過類名來訪問态贤;
. 用static修飾的程序代碼表示靜態(tài)代碼塊舱呻,當(dāng)Java虛似機(jī)加載類時(shí),就會(huì)執(zhí)行該代碼塊抵卫;
被static所修飾的成員變量和成員方法表明歸某個(gè)類所有狮荔,它不依賴于類的特定實(shí)例胎撇,被類的所有實(shí)例共享介粘。
1. static 變量
成員變量:定義在類里面殖氏、方法外面的變量, 分兩種:
a. 實(shí)例變量;
b. 靜態(tài)變量;形式和實(shí)例變量類似姻采,在實(shí)例變量前面加static關(guān)鍵字雅采;
static變量和實(shí)例變量的區(qū)別:
. static變量對(duì)于每個(gè)類而言在內(nèi)存中只有一個(gè),能被類的所有實(shí)例所共享慨亲;實(shí)例變量對(duì)于每個(gè)類的每個(gè)實(shí)例都有一份婚瓜,它們之間互不影響;
. Java虛擬機(jī)在加載類的過程中為static變量分配內(nèi)存刑棵,實(shí)例變量在加載完類后創(chuàng)建對(duì)象時(shí)分配內(nèi)存巴刻;
. static變量可以直接通過類名訪問,實(shí)例變量通過引用類型變量訪問蛉签;
舉例: public class Counter {
public int count1 = 0;
public static int count2 = 0;
public static void main(String[] args) {
Counter counterA = new Counter();
Counter counterB = new Counter();
counterA.count1++;
counterA.count2++;
counterB.count1++;
counterB.count2++;
}
}
練習(xí):統(tǒng)計(jì)一個(gè)類創(chuàng)建實(shí)例的個(gè)數(shù)胡陪;
2. static 方法
成員方法分為靜態(tài)方法和實(shí)例方法。用static修飾的方法叫靜態(tài)方法碍舍,或類方法柠座。靜態(tài)方法也和靜態(tài)變量一樣,不需要?jiǎng)?chuàng)建類的實(shí)例片橡,可以直接通過類名來訪問妈经。
public class Sample1 {
public static int add(int x, int y) {
return x+y;
}
}
public class Sample2 {
public void method() {
int result = Sample1.add(1,2);
System.out.println("result= " + result);
}
}
a. static方法可以直接訪問所屬類的實(shí)例變量和實(shí)例方法,直接訪問所屬類的靜態(tài)變量和靜態(tài)方法捧书;
注:1) 不能使用this關(guān)鍵字吹泡;
2) 不能使用super關(guān)鍵字,super關(guān)鍵字用來訪問當(dāng)前實(shí)例從父類中繼承的方法和屬性。super關(guān)鍵字與類的特定實(shí)例相關(guān)经瓷;
3) 靜態(tài)方法必須被實(shí)現(xiàn)爆哑。靜態(tài)方法用來表示某個(gè)類所特有的功能,這種功能的實(shí)現(xiàn)不依賴于類的具體實(shí)例了嚎,也不依賴于它的子類泪漂。既然如此,當(dāng)前類必須為靜態(tài)方法提供實(shí)現(xiàn)歪泳。
b. 父類的靜態(tài)方法不能被子類覆為非靜態(tài)方法萝勤。以下代碼編譯出錯(cuò)。
public class Base {
public static void method() {}
}
public class Sub extends Base {
public void method() {}//編譯出錯(cuò)
}
c. 父類的非靜態(tài)方法不能被子類覆蓋為靜態(tài)方法呐伞;
3. static 代碼塊
類中可以包含靜態(tài)代碼塊敌卓,它不存于任何方法中。在Java虛擬機(jī)中加載類時(shí)會(huì)執(zhí)行這些靜態(tài)代碼塊伶氢。如果類中包含多個(gè)靜態(tài)代碼塊趟径,那么Java虛擬機(jī)將按照它們?cè)陬愔谐霈F(xiàn)的順序依次執(zhí)行它們瘪吏,每個(gè)靜態(tài)代碼塊只會(huì)被執(zhí)行一次。(思考:什么時(shí)候JVM對(duì)一個(gè)類進(jìn)行類加載)
public class Sample {
static int i = 5;
static {//第一個(gè)靜態(tài)代碼塊
System.out.println("First Static code i="+i++);
}
static {//第二個(gè)靜態(tài)代碼塊
System.out.println("Second Static code i="+i++);
}
public static void main(String[] args) {
Sample s1 = new Sample();
Sample s2 = new Sample();
System.out.println("At last, i= "+i);
}
}
類的構(gòu)造方法用于初始化類的實(shí)例蜗巧,而類的靜態(tài)代碼塊則可用于初始化類掌眠,給類的靜態(tài)變量賦初始值。
靜態(tài)代碼塊與靜態(tài)方法一樣幕屹,也不能直接訪問類的實(shí)例變量和實(shí)例方法蓝丙,而必須通過實(shí)例的引用來訪問它們。
//Student s = new Student();
new一個(gè)對(duì)象的時(shí)候JVM都做了那些事情:
1.之前沒有進(jìn)行類加載
1.類加載,同時(shí)初始化類中靜態(tài)的屬性(賦默認(rèn)值)
2.執(zhí)行靜態(tài)代碼塊
3.分配內(nèi)存空間,同時(shí)初始化非靜態(tài)的屬性(賦默認(rèn)值)
4.調(diào)用父類構(gòu)造器
5.父類構(gòu)造器執(zhí)行完后,如果自己聲明屬性的同時(shí)有顯示的賦值,那么進(jìn)行顯示賦值把默認(rèn)值覆蓋
6.執(zhí)行匿名代碼塊
7.執(zhí)行構(gòu)造器
8.返回內(nèi)存地址
例子:
package com.briup.ch06;
public class Test {
public static void main(String[] args) {
A a = new B();
}
}
class A{
protected String name = "lisi";
public A() {
System.out.println("父類構(gòu)造器A");
System.out.println("父類構(gòu)造器A中調(diào)用test方法開始,由于子類重寫過test方法所以這里執(zhí)行子類的test方法");
test();
System.out.println("父類構(gòu)造器A中調(diào)用test方法結(jié)束");
}
public void test(){
}
}
class B extends A{
private String name = "tom";
{
System.out.println("子類匿名代碼塊中:"+name);
}
public B() {
System.out.println("子類構(gòu)造器B");
}
public void test(){
System.out.println("test方法中:this.name="+this.name);
System.out.println("test方法中:super.name="+super.name);
}
}
打印結(jié)果:
父類構(gòu)造器A? ? ? ? ? ? ? ? ? ? ? ? ? ? //子類構(gòu)造器調(diào)用父類構(gòu)造器
父類構(gòu)造器A中調(diào)用test方法開始,由于子類重寫過test方法所以這里執(zhí)行子類的test方法
test方法中:this.name=null? ? //這個(gè)時(shí)候父類構(gòu)造器還沒有執(zhí)行完 所以子類中的屬性不會(huì)顯示賦值 所以只有初始的默認(rèn)值null
test方法中:super.name=lisi? //這個(gè)時(shí)候父類構(gòu)造器開始調(diào)用 了 所以父類中的屬性已經(jīng)有了顯示賦的值了
父類構(gòu)造器A中調(diào)用test方法結(jié)束
子類匿名代碼塊中:tom? ? ? ? ? //這個(gè)時(shí)候父類構(gòu)造器已經(jīng)調(diào)用結(jié)束 所以子類中的屬性已經(jīng)有了顯示賦的值了
子類構(gòu)造器B
結(jié)論:? 子類中的屬性的顯示賦值的時(shí)機(jī) 是在 父類構(gòu)造器執(zhí)行完之后和子類的匿名代碼塊執(zhí)行之前的某個(gè)時(shí)候
2.之前已經(jīng)進(jìn)行了類加載
1.分配內(nèi)存空間,同時(shí)初始化非靜態(tài)的屬性(賦默認(rèn)值)
2.調(diào)用父類構(gòu)造器
3.父類構(gòu)造器執(zhí)行完后,如果自己聲明屬性的同時(shí)有顯示的賦值,那么進(jìn)行顯示賦值把默認(rèn)值覆蓋
4.執(zhí)行匿名代碼塊
5.執(zhí)行構(gòu)造器
6.返回內(nèi)存地址
練習(xí)例子:StaticTest.java? StaticTest2.java
4. 靜態(tài)導(dǎo)入
靜態(tài)導(dǎo)入也是JDK5.0引入的新特性望拖。
要使用靜態(tài)成員(方法和變量)我們必須給出提供這個(gè)靜態(tài)成員的類渺尘。使用靜態(tài)導(dǎo)入可以使被導(dǎo)入類的靜態(tài)變量和靜態(tài)方法在當(dāng)前類中可以直接使用,使用這些靜態(tài)成員無(wú)需再在前面寫上他們所屬的類名说敏。
//例如:
import static java.lang.Math.random;
import static java.lang.Math.PI;;
public class Test {
public static void main(String[] args) {
//之前是需要Math.random()調(diào)用的
System.out.println(random());
System.out.println(PI);
}
}
二. final修改符
final具有"不可改變的"含義鸥跟,它可以修飾非抽象類、非抽象成員方法和變量盔沫。
. 用final修飾的類不能被繼承医咨,沒有子類;
. 用final修飾的方法不能被子類的方法覆蓋迅诬;
. 用final修飾的變量表示常量腋逆,只能被賦一次值;
final不能用來修飾構(gòu)造方法侈贷,因?yàn)?方法覆蓋"這一概念僅適用于類的成員方法惩歉,而不適用于類的構(gòu)造方法,父類的構(gòu)造方法和子類的構(gòu)造方法之間不存在覆蓋關(guān)系. 因此用final修飾構(gòu)造方法是無(wú)意義的俏蛮。父類中用private修飾的方法不能被子類的方法覆蓋撑蚌,因此private類型的方法默認(rèn)是final類型的。
1. final類
繼承關(guān)系的弱點(diǎn)是打破封裝搏屑,子類能夠訪問父類的方法争涌,而且能以方法覆蓋的方式修改實(shí)現(xiàn)細(xì)節(jié)。在以下情況下,
可以考慮把類定義為final類型辣恋,使得這個(gè)類不能被繼承亮垫。
. 子類有可能會(huì)錯(cuò)誤地修改父類的實(shí)現(xiàn)細(xì)節(jié);
. 出于安全伟骨,類的實(shí)現(xiàn)細(xì)節(jié)不允許有任何改動(dòng)饮潦;
. 在創(chuàng)建對(duì)象模型時(shí),確信這個(gè)類不會(huì)再被擴(kuò)展携狭;
例如JDK中java.lang.String類被定義為final類型继蜡;
2. final方法;
某些情況下,出于安全原因稀并,父類不允許子類覆蓋某個(gè)方法仅颇, 此時(shí)可以把這個(gè)方法聲明為final類型。例如在
java.lang.Object類中碘举,getClass()方法為final類型忘瓦。
3. final變量:
final修飾的屬性(成員變量)賦值的位置:
非靜態(tài)的成員變量
1.聲明的同時(shí)
2.匿名代碼塊
3.構(gòu)造器(類中出現(xiàn)的所有構(gòu)造器)
靜態(tài)的成員變量
1.聲明的同時(shí)
2.static代碼塊
a. final可以修飾靜態(tài)變量、實(shí)例變量殴俱、局部變量政冻;
b. final變量都必須顯示初始化枚抵,否則會(huì)導(dǎo)致編譯錯(cuò)誤线欲;
1) 靜態(tài)變量,定義變量時(shí)進(jìn)行初始化或者static代碼塊中賦值汽摹;
2) 實(shí)例變量李丰,可以在定義變量時(shí),或者在構(gòu)造方法中進(jìn)行初始化逼泣;
c. final變量只能賦一次值趴泌。
public class Sample {
private final int var1 = 1;
public Sample() {
var1 = 2;? ? ? ? ? ? ? ? //編譯出錯(cuò),不允許改變var1實(shí)例變量的值拉庶;
}
public void method(final int param) {
final int var2 = 1;
var2++;? ? ? ? ? ? ? ? ? //編譯出錯(cuò)嗜憔,不允許改變var2局部常量的值
param++;? ? ? ? ? ? ? ? //編譯出錯(cuò),不允許改變final類型參數(shù)的值氏仗;
}
}
public class Sample {
final int var1;? ? ? ? ? ? ? //定義var1實(shí)例常量
final int var2 = 0;? ? ? ? ? //定義并初始化var2實(shí)例常量
Sample() {
var1 = 1;? ? ? ? ? ? ? //初始化var1實(shí)例常量
}
Sample(int x) {
var1 = x;? ? ? ? ? ? ? ? //初始化var1實(shí)例常量
}
}
練習(xí) FinalTest.java
三. abstract修飾符
可用來修飾類和成員方法吉捶。
. 用abstract修飾的類表示抽象類,抽象類不能實(shí)例化皆尔,即不允許創(chuàng)建抽象類本身的實(shí)例呐舔。沒有用abstract修飾的類稱為具體類,具體類可以被實(shí)例化慷蠕。
. 用abstract修飾的方法表示抽象方法珊拼,抽象方法沒有方法體。抽象方法用來描述系統(tǒng)具有什么功能流炕,但不提供具體的實(shí)現(xiàn)澎现。
沒有abstract修飾的方法稱為具體方法,具體方法具有方法體每辟。
語(yǔ)法規(guī)則剑辫;
1) 抽象類中可以沒有抽象方法,但包含了抽象方法的類必須被定義為抽象類影兽;
2) 沒有抽象構(gòu)造方法揭斧,也沒有抽象靜態(tài)方法;
3) 抽象類中可以有非抽象的構(gòu)造方法;
4) 抽象類及抽象方法不能被final修飾符修飾讹开。
抽象類不允許實(shí)例化:思考原因?
練習(xí) AbstractTest.java
四. 接口
接口使用的目的:解決多重繼承問題盅视;例如Fish類繼承Animal類,表明Fish是一種動(dòng)物旦万,但魚同樣也是一種食物闹击,如何表示這種關(guān)系呢? 由于Java語(yǔ)言不支持一個(gè)類有多個(gè)直接的父類成艘,因此無(wú)法用繼承關(guān)系來描述魚既是一種食物赏半,又是一種動(dòng)物,為了解決這一問題淆两,Java語(yǔ)言引入接口類型断箫,簡(jiǎn)稱接口。一個(gè)類只能有一個(gè)直接的父類秋冰,但是可以實(shí)現(xiàn)多個(gè)接口仲义。 采用這種方式,Java語(yǔ)言對(duì)多繼承提供了有力的支持剑勾。
1. 接口是抽象類的另外一種形式
抽象類抽象到極致就是接口埃撵,抽象類可存在有方法體的方法,接口中的方法全部為抽象方法虽另;
2. 接口中的所有方法均是抽象方法暂刘, 默認(rèn)都是public、abstract類型的捂刺;
public interface A {
void method1();? ? ? ? ? ? ? ? //合法谣拣,默認(rèn)為public、abstract類型
public abstract void method2();//合法叠萍,顯示聲明為public芝发、abstract類型
3. 接口中的成員變量默認(rèn)都是public, static, final類型,必須被顯式初始化苛谷;
public interface A {
int CONST = 1;? ? ? ? ? ? ? ? //合法辅鲸,CONST默認(rèn)為public, static, final類型
public static final int OPAQUE = 1;? //合法,顯示聲明為public static final 類型
}
4. 接口中只能包含public, static, final類型成員變量和public腹殿、abstract類型的成員方法独悴;
5. 接口中沒有構(gòu)造方法,不能被實(shí)例化锣尉。
6. 一個(gè)類只能繼承一個(gè)直接的父類刻炒,但能實(shí)現(xiàn)多個(gè)接口。
抽象類和接口比較:
1. 相同點(diǎn):
a. 都不能被實(shí)例化自沧;
b. 都能包含抽象方法坟奥;
2. 不同點(diǎn)树瞭;
a. 抽象類中可以為部分方法提供默認(rèn)的實(shí)現(xiàn),從而避免子類中重復(fù)實(shí)現(xiàn)它們爱谁,提高代碼的可重用性晒喷,而接口中只能包含抽象方法;
b. 一個(gè)類只能繼承一個(gè)直接的父類访敌,這個(gè)父類有可能是抽象類凉敲;但一個(gè)類可以實(shí)現(xiàn)多個(gè)接口,這是接口的優(yōu)勢(shì)所在寺旺。
練習(xí):InterfaceTest.java InterfaceTest2.java
五. 訪問控制
面向?qū)ο蟮幕舅枷胫皇欠庋b實(shí)現(xiàn)細(xì)節(jié)并且公開方法爷抓。Java語(yǔ)言采用訪問控制修飾符來控制類及類的方法和變量的訪問
權(quán)限,從而只向使用者暴露方法阻塑,但隱藏實(shí)現(xiàn)細(xì)節(jié)蓝撇。訪問控制分4種級(jí)別。
訪問級(jí)別? ? ? 訪問控制修飾符? ? ? ? 同類? ? ? 同包? ? ? 子類? ? ? 不同的包
公開級(jí)別:? ? ? public? ? ? ? ? ? ? ? y? ? ? ? y? ? ? ? ? y? ? ? ? ? y
受保護(hù)? ? ? ? ? protected? ? ? ? ? ? y? ? ? ? ? y? ? ? ? ? y
默認(rèn)? ? ? ? ? 沒有訪問控制符? ? ? ? ? y? ? ? ? ? y
私有? ? ? ? ? ? private? ? ? ? ? ? ? ? y
成員變量叮姑、成員方法和構(gòu)造方法可以處于4個(gè)訪問級(jí)別中的一個(gè)唉地;
頂層類只可以處于公開或默認(rèn)訪問級(jí)別;
注意:protected和default都有包訪問權(quán)限(同包下可以訪問)
六. 內(nèi)部類
在一個(gè)類的內(nèi)部定義的類稱為內(nèi)部類传透。
內(nèi)部類分為:
成員內(nèi)部類 靜態(tài)內(nèi)部類 局部?jī)?nèi)部類 匿名內(nèi)部類
頂層類(正常類)只能處于public和默認(rèn)訪問級(jí)別,而成員內(nèi)部類可以處于public, protected, private和默認(rèn)這4種訪問級(jí)別极颓;
1.? 靜態(tài)內(nèi)部類朱盐;
例子:StaticOutterClass.java
是成員內(nèi)部類的一種,用static修飾菠隆。靜態(tài)內(nèi)部類具有以下特點(diǎn):
1)? 靜態(tài)內(nèi)部類:(相對(duì)應(yīng)類中的一個(gè)靜態(tài)變量)
靜態(tài)內(nèi)部類中訪問不到外部類的非靜態(tài)屬性或者方法
靜態(tài)內(nèi)部類的對(duì)象不需要依賴于外部類的對(duì)象
內(nèi)部類 變量名字 = new 內(nèi)部類();
public class A {
public static class B{
private int v;
public void say(){
System.out.println("hello");
}
}
public static void main(String[] args){
B b = new B();
}
}
2) 靜態(tài)內(nèi)部類可以直接訪問外部類的靜態(tài)成員兵琳,如果訪問外部類的實(shí)例成員,就必須通過外部類的實(shí)例去訪問骇径。
class A {
private int a1;? ? ? ? ? ? ? //實(shí)例變量a1
private static int a2;? ? ? //靜態(tài)變量a2
public static class B {
int b1 = a1;? ? ? ? ? //編譯錯(cuò)誤躯肌,不能直接訪問外部類A的實(shí)例變量a1
int b2 = a2;? ? ? ? ? //合法,可以直接訪問外部類A的靜態(tài)變量a2
int b3 = A.this.a1;? //不合法 靜態(tài)內(nèi)部類中不能訪問外部對(duì)象的this
}
}
3) 在靜態(tài)內(nèi)部類中可以定義靜態(tài)成員和實(shí)例成員破衔。
class A {
public static class B {
int v1;? ? ? ? ? ? ? ? ? ? ? //實(shí)例變量
static int v2;? ? ? ? ? ? ? ? //靜態(tài)變量
public static class C {
static int v3;? ? ? ? //靜態(tài)內(nèi)部類
}
}
}
4) 可以通過完整的類名直接訪問靜態(tài)內(nèi)部類的靜態(tài)成員清女。
class A {
public static class B {
int v1;? ? ? ? ? ? ? ? ? ? ? //實(shí)例變量
static int v2;? ? ? ? ? ? ? ? //靜態(tài)變量
public static class C {
static int v3;? ? ? ? //靜態(tài)內(nèi)部類
int v4;
}
}
}
public class Tester {
public void test() {
A.B b = new A.B();
A.B.C c = new A.B.C();
b.v1 = 1;
v.v2 = 1;
A.B.v1 = 1;? ? ? ? ? ? //編譯錯(cuò)誤
A.B.v2 = 1;? ? ? ? ? ? //合法
A.B.C.v3 = 1;? ? ? ? ? //合法
}
}
2.? 成員內(nèi)部類:(相當(dāng)于類中的一個(gè)成員變量)
成員內(nèi)部類中不能有static的聲明屬性或者方法
成員內(nèi)部類可以由public protected default private修飾
成員內(nèi)部類是依賴于外部類的對(duì)象而存在的
外部類.內(nèi)部類 var = new 外部類().內(nèi)部類();
例子:InstanceOutterClass.java
1) 在創(chuàng)建實(shí)例內(nèi)部類的實(shí)例時(shí),外部類的實(shí)例必須已經(jīng)存在晰筛。
Outer.InnerTool tool = new Outer().new InnerTool();
等價(jià)于:
Outer outer = new Outer();
Outer.InnerTool tool = outer.new InnerTool();
以下代碼會(huì)導(dǎo)致編譯錯(cuò)誤:
Outer.InnerTool tool = new Outer.InnerTool();
2) 實(shí)例內(nèi)部類的實(shí)例自動(dòng)持有外部類的實(shí)例的引用嫡丙。在內(nèi)部類中, 可以直接訪問外部類的所有成員读第,包括
成員變量和成員方法曙博。
public class A {
private int a1;
public int a1;
static int a1;
public A(int a1, int a2) {
this.a1 = a1;
this.a2 = a2;
}
protected int methodA() {
return a1*a2;
}
class B {
int b1 = a1;? ? ? ? ? ? ? //直接訪問private的a1
int b2 = a2;? ? ? ? ? ? ? //直接訪問public的a2
int b3 = a3;? ? ? ? ? ? ? //直接訪問static的a3
int b4 = A.this.a1;? ? //訪問類A的當(dāng)前實(shí)例中的a1
int b5 = methodA();? ? ? ? //訪問methodA()方法
}
public static void main(String args[]) {
A.B b = new A(1,2).new B();
System.out.println("b.b1="+b.b1);? ? //打印b.b1=1;
System.out.println("b.b2="+b.b2);? ? //打印b.b2=2;
System.out.println("b.b3="+b.b3);? ? //打印b.b3=0;
System.out.println("b.b4="+b.b4);? ? //打印b.b4=3;
System.out.println("b.b5="+b.b5);? ? //打印b.b5=2;
}
}
3) 外部類實(shí)例與內(nèi)部類實(shí)例之間是一對(duì)多的關(guān)系,一個(gè)內(nèi)部類實(shí)例只會(huì)引用一個(gè)外部類實(shí)例怜瞒,而一個(gè)外部類實(shí)例對(duì)應(yīng)零個(gè)或多個(gè)內(nèi)部類實(shí)例父泳。在外部類中不能直接訪問內(nèi)部類的成員,必須通過內(nèi)部類的實(shí)例去訪問。
class A {
class B {
private int b1 = 1;
public int b2 = 2;
class C{}
}
public void test() {
int v1 = b1;? ? ? ? ? ? ? ? ? ? ? ? ? //invalid
int v2 = b2;? ? ? ? ? ? ? ? ? ? ? ? ? //invalid
B.C c1 = new C();? ? ? ? ? ? ? ? ? ? //invalid
B b = new B(); //valid
int v3 = b.b1;? ? ? ? ? ? ? ? ? ? ? ? ? //valid
int v4 = b.b2;? ? ? ? ? ? ? ? ? ? ? ? ? //valid
B.C c2 = b.new C();? ? ? ? ? ? ? ? ? ? //valid
B.C c3 = new B().new C();? ? ? ? ? ? ? //valid
}
}
4) 實(shí)例內(nèi)部類中不能定義靜態(tài)成員惠窄,而只能定義實(shí)例成員逝她。
5) 如果實(shí)例內(nèi)部類B與外部類A包含同名的成員,那么在類B中睬捶, this.v表示類B的成員黔宛, A.this.v表示類A的成員。
3.? 局部?jī)?nèi)部類:(相當(dāng)于一個(gè)方法中的局部變量)
局部?jī)?nèi)部類不能用public private等修飾符修飾
寫在方法當(dāng)中,而且只能在方法當(dāng)中使用
可以訪問外層類的普通成員變量和靜態(tài)成員變量以及普通方法和靜態(tài)方法,也可以訪問該內(nèi)部類所在方法當(dāng)中的局部變量,但是這個(gè)局部變量必須是final修飾擒贸;
例子:LocalOutterClass.java
1) 局部?jī)?nèi)部類只能在當(dāng)前方法中使用臀晃。
class A {
B b = new B();? ? ? ? ? ? ? ? //編譯錯(cuò)誤;
public void method() {
class B{
int v1;
int v2;
class C {
int v3;
}
}
B b = new B();? ? ? ? ? ? ? ? //合法
B.C c = b.new C();? ? ? ? ? ? //合法
}
}
2) 局部?jī)?nèi)部類和實(shí)例內(nèi)部類一樣介劫,不能包含靜態(tài)成員徽惋。
class A {
public void method() {
class B{
static int v1;? ? ? ? ? //編譯錯(cuò)誤
int v2;? ? ? ? ? ? ? ? ? //合法
static class C {? ? ? ? //編譯錯(cuò)誤
int v3;
}
}
}
}
3) 在局部?jī)?nèi)部類中定義的內(nèi)部類也不能被public、protected和private這些訪問控制修飾符修飾座韵;
4) 局部?jī)?nèi)部類和實(shí)例內(nèi)部類一樣险绘,可以訪問外部類的所有成員,此外誉碴,局部?jī)?nèi)部類還可以訪問所在方法中的final類型
的參數(shù)和變量宦棺。
4.匿名內(nèi)部類:(和局部?jī)?nèi)部類很相似)
匿名內(nèi)部類也是用的最多的內(nèi)部類
可以寫成成員變量的形式,也可以寫在方法當(dāng)中,一般寫在方法當(dāng)中較多
匿名內(nèi)部類里可以訪問外部類的普通屬性和方法,已經(jīng)靜態(tài)屬性和方法,如果要訪問這個(gè)內(nèi)部類所在方法中的局部變量,那么要求這個(gè)局部變量必須是final修飾的
匿名內(nèi)部類里面沒有構(gòu)造函數(shù),因?yàn)檫@個(gè)類沒有名字,所以在其他地方不能用
例子:AnonymousOutterClass.java
public class Hello{
public void test(){
//假如A是同包下的一個(gè)接口,有一個(gè)抽象方法go
A a = new A(){
public void go(){
System.out.println("gogogo");
}
};
}
}
幾種內(nèi)部類的區(qū)別:
1. 創(chuàng)建
a. 聲明的位置:
靜態(tài)內(nèi)部類:類的內(nèi)部黔帕,方法的外部代咸,用static關(guān)鍵字修飾;
實(shí)例內(nèi)部類:類的內(nèi)部成黄,方法的外部呐芥,不用static關(guān)鍵字修飾;
局部?jī)?nèi)部類:方法的內(nèi)部奋岁;
匿名內(nèi)部類:既可以在類的內(nèi)部思瘟,方法的外部,也可以在方法的內(nèi)部闻伶;
b. 實(shí)例化方式:
靜態(tài)內(nèi)部類:new Outer.Inner();? ? ? ? ? //在外部類外創(chuàng)建滨攻;
new Inner();? ? ? ? ? ? ? ? //在外部類內(nèi)內(nèi)部類外創(chuàng)建
實(shí)例內(nèi)部類:new Outer().new Inner();? ? ? //在外部類外創(chuàng)建;
this.new Inner();? ? ? ? ? ? //在外部類內(nèi)內(nèi)部類外創(chuàng)建
局部?jī)?nèi)部類:new Inner();? ? ? ? ? ? ? ? ? //只能在方法內(nèi)部創(chuàng)建虾攻;
匿名內(nèi)部類:new 類名() {};
2. 訪問
a. 外部類訪問內(nèi)部類:
靜態(tài)內(nèi)部類:通過完整的類名直接訪問靜態(tài)內(nèi)部類的靜態(tài)成員;
實(shí)例內(nèi)部類:通過內(nèi)部類的實(shí)例去訪問內(nèi)部類的成員;
局部?jī)?nèi)部類:不能訪問铡买;
匿名內(nèi)部類:不能訪問;
b. 內(nèi)部類訪問外部類:
靜態(tài)內(nèi)部類:直接訪問外部類的靜態(tài)成員霎箍;
實(shí)例內(nèi)部類:可以直接訪問外部類的所有成員;
如果實(shí)例內(nèi)部類B與外部類A包含同名的成員奇钞,那么在類B中, this.v表示類B的成員漂坏,
A.this.v表示類A的成員景埃。
局部?jī)?nèi)部類:可以直接訪問外部類的所有成員, 訪問所在方法中的final類型的參數(shù)和變量媒至;
匿名內(nèi)部類:可以直接訪問外部類的所有成員, 訪問所在方法中的final類型的參數(shù)和變量;
七. ==? 和 equals() 的區(qū)別
== :比較的是,值是不是相等
基本數(shù)據(jù)類型比較的是值,引用類型比較的是地址值
equals(Object o): Object類中的方法,所以,在每一個(gè)java類中,都會(huì)有這個(gè)方法,因?yàn)槊恳粋€(gè)java類都是直接或者間接的Object類的子類,會(huì)繼承到這個(gè)方法
如果自己所寫的類中已經(jīng)重寫了equals方法,那么就安裝用戶自定義的方式來比較倆個(gè)對(duì)象是否相等,如果沒有重寫過equal方法,那么會(huì)調(diào)用父類(Object)中的equals方法進(jìn)行比較,也就是比較地址值
注意:equals(Object o)方法只能是一個(gè)對(duì)象來調(diào)用,然后參數(shù)也是要傳一個(gè)對(duì)象的
所以下面是錯(cuò)誤的寫法:
int a = 1;
a.equals(1);
因?yàn)榛緮?shù)據(jù)類型不是算是對(duì)象,不能調(diào)用方法
如果是基本數(shù)據(jù)類型那么就用==比較
如果是引用類型的話,想按照自己的方式去比較,就要重寫這個(gè)類中的equals方法, 如果沒有重寫,那么equals和==比較的效果是一樣的,都是比較引用的地址值
如果是比較字符串,那么直接用equals就可以了,因?yàn)镾tring類里面已經(jīng)重寫了equals方法,比較的時(shí)候字符串的內(nèi)容,而不是引用的地址值了
toString(): Object類中的方法,所以,在每一個(gè)java類中,都會(huì)有這個(gè)方法,因?yàn)槊恳粋€(gè)java類都是直接或者間接的Object類的子類,會(huì)繼承到這個(gè)方法
當(dāng)前用一個(gè)引用指向一個(gè)對(duì)象的時(shí)候,比如:Student s = new Student(),然后如果直接打印這個(gè)引用s,其實(shí)是調(diào)用了s.toString()方法,然后就會(huì)把這個(gè)引用里面的存放的堆區(qū)對(duì)象的地址值顯示出來
所以我們會(huì)常常在類中重寫這個(gè)toString()方法,然后讓這個(gè)類的引用按照我們要求來返回內(nèi)容谷徙。
getClass():Object類中的方法,所以,在每一個(gè)java類中拒啰,都會(huì)有這個(gè)方法,并且這個(gè)方式final修飾的,不能被子類重寫,這個(gè)方法可以返回某一個(gè)引用在運(yùn)行的時(shí)候指向?qū)ο蟮念愋?/p>
例如:Person p = new Student()
//會(huì)輸出:class com.briup.chap06.Student
//說明這個(gè)引用p在運(yùn)行時(shí)指向的是Student這個(gè)類的對(duì)象
//注意這個(gè)引用p的類型是Person的(多態(tài))
System.out.println(p.getClass());
八. 基本數(shù)據(jù)類型對(duì)應(yīng)的包裝類型
boolean Boolean
byte Byte
short Short
char Character
int Integer
long Long
float Float
double Double