Advanced Language Features
知識點:一. static修飾符
static修飾符可以用來修飾類的成員變量、成員方法和代碼塊。
. 用static修飾的成員變量表示靜態(tài)變量,可以直接通過類名來訪問;
. 用static修飾的成員方法表示靜態(tài)方法,可以直接通過類名來訪問;
. 用static修飾的程序代碼表示靜態(tài)代碼塊,當Java虛似機加載類時,就會執(zhí)行該代碼塊;
被static所修飾的成員變量和成員方法表明歸某個類所有,它不依賴于類的特定實例,被類的所有實例共享。
1. static 變量
成員變量:定義在類里面、方法外面的變量, 分兩種:
a. 實例變量;
b. 靜態(tài)變量;形式和實例變量類似,在實例變量前面加static關(guān)鍵字;
static變量和實例變量的區(qū)別:
. static變量對于每個類而言在內(nèi)存中只有一個,能被類的所有實例所共享;實例變量對于每個類的每個實例都有一份,它們之間互不影響;
. Java虛擬機在加載類的過程中為static變量分配內(nèi)存,實例變量在加載完類后創(chuàng)建對象時分配內(nèi)存;
. static變量可以直接通過類名訪問,實例變量通過引用類型變量訪問;
舉例: 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++;
}
}
練習:統(tǒng)計一個類創(chuàng)建實例的個數(shù);
2. static 方法
成員方法分為靜態(tài)方法和實例方法。用static修飾的方法叫靜態(tài)方法,或類方法。靜態(tài)方法也和靜態(tài)變量一樣,不需要創(chuàng)建類的實例,可以直接通過類名來訪問。
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方法可以直接訪問所屬類的實例變量和實例方法,直接訪問所屬類的靜態(tài)變量和靜態(tài)方法;
注:1) 不能使用this關(guān)鍵字;
2) 不能使用super關(guān)鍵字,super關(guān)鍵字用來訪問當前實例從父類中繼承的方法和屬性。super關(guān)鍵字與類的特定實例相關(guān);
3) 靜態(tài)方法必須被實現(xiàn)。靜態(tài)方法用來表示某個類所特有的功能,這種功能的實現(xiàn)不依賴于類的具體實例,也不依賴于它的子類。既然如此,當前類必須為靜態(tài)方法提供實現(xiàn)。
b. 父類的靜態(tài)方法不能被子類覆為非靜態(tài)方法。以下代碼編譯出錯。
public class Base {
public static void method() {}
}
public class Sub extends Base {
public void method() {}//編譯出錯
}
c. 父類的非靜態(tài)方法不能被子類覆蓋為靜態(tài)方法;
3. static 代碼塊
類中可以包含靜態(tài)代碼塊,它不存于任何方法中。在Java虛擬機中加載類時會執(zhí)行這些靜態(tài)代碼塊。如果類中包含多個靜態(tài)代碼塊,那么Java虛擬機將按照它們在類中出現(xiàn)的順序依次執(zhí)行它們,每個靜態(tài)代碼塊只會被執(zhí)行一次。(思考:什么時候JVM對一個類進行類加載)
public class Sample {
static int i = 5;
static {//第一個靜態(tài)代碼塊
System.out.println("First Static code i="+i++);
}
static {//第二個靜態(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)造方法用于初始化類的實例,而類的靜態(tài)代碼塊則可用于初始化類,給類的靜態(tài)變量賦初始值。
靜態(tài)代碼塊與靜態(tài)方法一樣,也不能直接訪問類的實例變量和實例方法,而必須通過實例的引用來訪問它們。
//Student s = new Student();
new一個對象的時候JVM都做了那些事情:
1.之前沒有進行類加載
1.類加載,同時初始化類中靜態(tài)的屬性(賦默認值)
2.執(zhí)行靜態(tài)代碼塊
3.分配內(nèi)存空間,同時初始化非靜態(tài)的屬性(賦默認值)
4.調(diào)用父類構(gòu)造器
5.父類構(gòu)造器執(zhí)行完后,如果自己聲明屬性的同時有顯示的賦值,那么進行顯示賦值把默認值覆蓋
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òu)造器還沒有執(zhí)行完 所以子類中的屬性不會顯示賦值 所以只有初始的默認值null
test方法中:super.name=lisi? //這個時候父類構(gòu)造器開始調(diào)用 了 所以父類中的屬性已經(jīng)有了顯示賦的值了
父類構(gòu)造器A中調(diào)用test方法結(jié)束
子類匿名代碼塊中:tom? ? ? ? ? //這個時候父類構(gòu)造器已經(jīng)調(diào)用結(jié)束 所以子類中的屬性已經(jīng)有了顯示賦的值了
子類構(gòu)造器B
結(jié)論:? 子類中的屬性的顯示賦值的時機 是在 父類構(gòu)造器執(zhí)行完之后和子類的匿名代碼塊執(zhí)行之前的某個時候
2.之前已經(jīng)進行了類加載
1.分配內(nèi)存空間,同時初始化非靜態(tài)的屬性(賦默認值)
2.調(diào)用父類構(gòu)造器
3.父類構(gòu)造器執(zhí)行完后,如果自己聲明屬性的同時有顯示的賦值,那么進行顯示賦值把默認值覆蓋
4.執(zhí)行匿名代碼塊
5.執(zhí)行構(gòu)造器
6.返回內(nèi)存地址
練習例子:StaticTest.java? StaticTest2.java
4. 靜態(tài)導入
靜態(tài)導入也是JDK5.0引入的新特性。
要使用靜態(tài)成員(方法和變量)我們必須給出提供這個靜態(tài)成員的類。使用靜態(tài)導入可以使被導入類的靜態(tài)變量和靜態(tài)方法在當前類中可以直接使用,使用這些靜態(tài)成員無需再在前面寫上他們所屬的類名。
//例如:
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)造方法,因為"方法覆蓋"這一概念僅適用于類的成員方法,而不適用于類的構(gòu)造方法,父類的構(gòu)造方法和子類的構(gòu)造方法之間不存在覆蓋關(guān)系. 因此用final修飾構(gòu)造方法是無意義的。父類中用private修飾的方法不能被子類的方法覆蓋,因此private類型的方法默認是final類型的。
1. final類
繼承關(guān)系的弱點是打破封裝,子類能夠訪問父類的方法,而且能以方法覆蓋的方式修改實現(xiàn)細節(jié)。在以下情況下,
可以考慮把類定義為final類型,使得這個類不能被繼承。
. 子類有可能會錯誤地修改父類的實現(xiàn)細節(jié);
. 出于安全,類的實現(xiàn)細節(jié)不允許有任何改動;
. 在創(chuàng)建對象模型時,確信這個類不會再被擴展;
例如JDK中java.lang.String類被定義為final類型;
2. final方法;
某些情況下,出于安全原因,父類不允許子類覆蓋某個方法, 此時可以把這個方法聲明為final類型。例如在
java.lang.Object類中,getClass()方法為final類型。
3. final變量:
final修飾的屬性(成員變量)賦值的位置:
非靜態(tài)的成員變量
1.聲明的同時
2.匿名代碼塊
3.構(gòu)造器(類中出現(xiàn)的所有構(gòu)造器)
靜態(tài)的成員變量
1.聲明的同時
2.static代碼塊
a. final可以修飾靜態(tài)變量、實例變量、局部變量;
b. final變量都必須顯示初始化,否則會導致編譯錯誤;
1) 靜態(tài)變量,定義變量時進行初始化或者static代碼塊中賦值;
2) 實例變量,可以在定義變量時,或者在構(gòu)造方法中進行初始化;
c. final變量只能賦一次值。
public class Sample {
private final int var1 = 1;
public Sample() {
var1 = 2;? ? ? ? ? ? ? ? //編譯出錯,不允許改變var1實例變量的值;
}
public void method(final int param) {
final int var2 = 1;
var2++;? ? ? ? ? ? ? ? ? //編譯出錯,不允許改變var2局部常量的值
param++;? ? ? ? ? ? ? ? //編譯出錯,不允許改變final類型參數(shù)的值;
}
}
public class Sample {
final int var1;? ? ? ? ? ? ? //定義var1實例常量
final int var2 = 0;? ? ? ? ? //定義并初始化var2實例常量
Sample() {
var1 = 1;? ? ? ? ? ? ? //初始化var1實例常量
}
Sample(int x) {
var1 = x;? ? ? ? ? ? ? ? //初始化var1實例常量
}
}
練習 FinalTest.java
三. abstract修飾符
可用來修飾類和成員方法。
. 用abstract修飾的類表示抽象類,抽象類不能實例化,即不允許創(chuàng)建抽象類本身的實例。沒有用abstract修飾的類稱為具體類,具體類可以被實例化。
. 用abstract修飾的方法表示抽象方法,抽象方法沒有方法體。抽象方法用來描述系統(tǒng)具有什么功能,但不提供具體的實現(xiàn)。
沒有abstract修飾的方法稱為具體方法,具體方法具有方法體。
語法規(guī)則;
1) 抽象類中可以沒有抽象方法,但包含了抽象方法的類必須被定義為抽象類;
2) 沒有抽象構(gòu)造方法,也沒有抽象靜態(tài)方法;
3) 抽象類中可以有非抽象的構(gòu)造方法;
4) 抽象類及抽象方法不能被final修飾符修飾。
抽象類不允許實例化:思考原因?
練習 AbstractTest.java
四. 接口
接口使用的目的:解決多重繼承問題;例如Fish類繼承Animal類,表明Fish是一種動物,但魚同樣也是一種食物,如何表示這種關(guān)系呢? 由于Java語言不支持一個類有多個直接的父類,因此無法用繼承關(guān)系來描述魚既是一種食物,又是一種動物,為了解決這一問題,Java語言引入接口類型,簡稱接口。一個類只能有一個直接的父類,但是可以實現(xiàn)多個接口。 采用這種方式,Java語言對多繼承提供了有力的支持。
1. 接口是抽象類的另外一種形式
抽象類抽象到極致就是接口,抽象類可存在有方法體的方法,接口中的方法全部為抽象方法;
2. 接口中的所有方法均是抽象方法, 默認都是public、abstract類型的;
public interface A {
void method1();? ? ? ? ? ? ? ? //合法,默認為public、abstract類型
public abstract void method2();//合法,顯示聲明為public、abstract類型
3. 接口中的成員變量默認都是public, static, final類型,必須被顯式初始化;
public interface A {
int CONST = 1;? ? ? ? ? ? ? ? //合法,CONST默認為public, static, final類型
public static final int OPAQUE = 1;? //合法,顯示聲明為public static final 類型
}
4. 接口中只能包含public, static, final類型成員變量和public、abstract類型的成員方法;
5. 接口中沒有構(gòu)造方法,不能被實例化。
6. 一個類只能繼承一個直接的父類,但能實現(xiàn)多個接口。
抽象類和接口比較:
1. 相同點:
a. 都不能被實例化;
b. 都能包含抽象方法;
2. 不同點;
a. 抽象類中可以為部分方法提供默認的實現(xiàn),從而避免子類中重復(fù)實現(xiàn)它們,提高代碼的可重用性,而接口中只能包含抽象方法;
b. 一個類只能繼承一個直接的父類,這個父類有可能是抽象類;但一個類可以實現(xiàn)多個接口,這是接口的優(yōu)勢所在。
練習:InterfaceTest.java InterfaceTest2.java
五. 訪問控制
面向?qū)ο蟮幕舅枷胫皇欠庋b實現(xiàn)細節(jié)并且公開方法。Java語言采用訪問控制修飾符來控制類及類的方法和變量的訪問
權(quán)限,從而只向使用者暴露方法,但隱藏實現(xiàn)細節(jié)。訪問控制分4種級別。
訪問級別? ? ? 訪問控制修飾符? ? ? ? 同類? ? ? 同包? ? ? 子類? ? ? 不同的包
公開級別:? ? ? public? ? ? ? ? ? ? ? y? ? ? ? y? ? ? ? ? y? ? ? ? ? y
受保護? ? ? ? ? protected? ? ? ? ? ? y? ? ? ? ? y? ? ? ? ? y
默認? ? ? ? ? 沒有訪問控制符? ? ? ? ? y? ? ? ? ? y
私有? ? ? ? ? ? private? ? ? ? ? ? ? ? y
成員變量、成員方法和構(gòu)造方法可以處于4個訪問級別中的一個;
頂層類只可以處于公開或默認訪問級別;
注意:protected和default都有包訪問權(quán)限(同包下可以訪問)
六. 內(nèi)部類
在一個類的內(nèi)部定義的類稱為內(nèi)部類。
內(nèi)部類分為:
成員內(nèi)部類 靜態(tài)內(nèi)部類 局部內(nèi)部類 匿名內(nèi)部類
頂層類(正常類)只能處于public和默認訪問級別,而成員內(nèi)部類可以處于public, protected, private和默認這4種訪問級別;
1.? 靜態(tài)內(nèi)部類;
例子:StaticOutterClass.java
是成員內(nèi)部類的一種,用static修飾。靜態(tài)內(nèi)部類具有以下特點:
1)? 靜態(tài)內(nèi)部類:(相對應(yīng)類中的一個靜態(tài)變量)
靜態(tài)內(nèi)部類中訪問不到外部類的非靜態(tài)屬性或者方法
靜態(tài)內(nèi)部類的對象不需要依賴于外部類的對象
內(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)成員,如果訪問外部類的實例成員,就必須通過外部類的實例去訪問。
class A {
private int a1;? ? ? ? ? ? ? //實例變量a1
private static int a2;? ? ? //靜態(tài)變量a2
public static class B {
int b1 = a1;? ? ? ? ? //編譯錯誤,不能直接訪問外部類A的實例變量a1
int b2 = a2;? ? ? ? ? //合法,可以直接訪問外部類A的靜態(tài)變量a2
int b3 = A.this.a1;? //不合法 靜態(tài)內(nèi)部類中不能訪問外部對象的this
}
}
3) 在靜態(tài)內(nèi)部類中可以定義靜態(tài)成員和實例成員。
class A {
public static class B {
int v1;? ? ? ? ? ? ? ? ? ? ? //實例變量
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;? ? ? ? ? ? ? ? ? ? ? //實例變量
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;? ? ? ? ? ? //編譯錯誤
A.B.v2 = 1;? ? ? ? ? ? //合法
A.B.C.v3 = 1;? ? ? ? ? //合法
}
}
2.? 成員內(nèi)部類:(相當于類中的一個成員變量)
成員內(nèi)部類中不能有static的聲明屬性或者方法
成員內(nèi)部類可以由public protected default private修飾
成員內(nèi)部類是依賴于外部類的對象而存在的
外部類.內(nèi)部類 var = new 外部類().內(nèi)部類();
例子:InstanceOutterClass.java
1) 在創(chuàng)建實例內(nèi)部類的實例時,外部類的實例必須已經(jīng)存在。
Outer.InnerTool tool = new Outer().new InnerTool();
等價于:
Outer outer = new Outer();
Outer.InnerTool tool = outer.new InnerTool();
以下代碼會導致編譯錯誤:
Outer.InnerTool tool = new Outer.InnerTool();
2) 實例內(nèi)部類的實例自動持有外部類的實例的引用。在內(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的當前實例中的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) 外部類實例與內(nèi)部類實例之間是一對多的關(guān)系,一個內(nèi)部類實例只會引用一個外部類實例,而一個外部類實例對應(yīng)零個或多個內(nèi)部類實例。在外部類中不能直接訪問內(nèi)部類的成員,必須通過內(nèi)部類的實例去訪問。
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) 實例內(nèi)部類中不能定義靜態(tài)成員,而只能定義實例成員。
5) 如果實例內(nèi)部類B與外部類A包含同名的成員,那么在類B中, this.v表示類B的成員, A.this.v表示類A的成員。
3.? 局部內(nèi)部類:(相當于一個方法中的局部變量)
局部內(nèi)部類不能用public private等修飾符修飾
寫在方法當中,而且只能在方法當中使用
可以訪問外層類的普通成員變量和靜態(tài)成員變量以及普通方法和靜態(tài)方法,也可以訪問該內(nèi)部類所在方法當中的局部變量,但是這個局部變量必須是final修飾;
例子:LocalOutterClass.java
1) 局部內(nèi)部類只能在當前方法中使用。
class A {
B b = new B();? ? ? ? ? ? ? ? //編譯錯誤;
public void method() {
class B{
int v1;
int v2;
class C {
int v3;
}
}
B b = new B();? ? ? ? ? ? ? ? //合法
B.C c = b.new C();? ? ? ? ? ? //合法
}
}
2) 局部內(nèi)部類和實例內(nèi)部類一樣,不能包含靜態(tài)成員。
class A {
public void method() {
class B{
static int v1;? ? ? ? ? //編譯錯誤
int v2;? ? ? ? ? ? ? ? ? //合法
static class C {? ? ? ? //編譯錯誤
int v3;
}
}
}
}
3) 在局部內(nèi)部類中定義的內(nèi)部類也不能被public、protected和private這些訪問控制修飾符修飾;
4) 局部內(nèi)部類和實例內(nèi)部類一樣,可以訪問外部類的所有成員,此外,局部內(nèi)部類還可以訪問所在方法中的final類型
的參數(shù)和變量。
4.匿名內(nèi)部類:(和局部內(nèi)部類很相似)
匿名內(nèi)部類也是用的最多的內(nèi)部類
可以寫成成員變量的形式,也可以寫在方法當中,一般寫在方法當中較多
匿名內(nèi)部類里可以訪問外部類的普通屬性和方法,已經(jīng)靜態(tài)屬性和方法,如果要訪問這個內(nèi)部類所在方法中的局部變量,那么要求這個局部變量必須是final修飾的
匿名內(nèi)部類里面沒有構(gòu)造函數(shù),因為這個類沒有名字,所以在其他地方不能用
例子:AnonymousOutterClass.java
public class Hello{
public void test(){
//假如A是同包下的一個接口,有一個抽象方法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)鍵字修飾;
實例內(nèi)部類:類的內(nèi)部,方法的外部,不用static關(guān)鍵字修飾;
局部內(nèi)部類:方法的內(nèi)部;
匿名內(nèi)部類:既可以在類的內(nèi)部,方法的外部,也可以在方法的內(nèi)部;
b. 實例化方式:
靜態(tài)內(nèi)部類:new Outer.Inner();? ? ? ? ? //在外部類外創(chuàng)建;
new Inner();? ? ? ? ? ? ? ? //在外部類內(nèi)內(nèi)部類外創(chuàng)建
實例內(nèi)部類:new Outer().new Inner();? ? ? //在外部類外創(chuàng)建;
this.new Inner();? ? ? ? ? ? //在外部類內(nèi)內(nèi)部類外創(chuàng)建
局部內(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)成員;
實例內(nèi)部類:通過內(nèi)部類的實例去訪問內(nèi)部類的成員;
局部內(nèi)部類:不能訪問;
匿名內(nèi)部類:不能訪問;
b. 內(nèi)部類訪問外部類:
靜態(tài)內(nèi)部類:直接訪問外部類的靜態(tài)成員;
實例內(nèi)部類:可以直接訪問外部類的所有成員;
如果實例內(nèi)部類B與外部類A包含同名的成員,那么在類B中, this.v表示類B的成員,
A.this.v表示類A的成員。
局部內(nèi)部類:可以直接訪問外部類的所有成員, 訪問所在方法中的final類型的參數(shù)和變量;
匿名內(nèi)部類:可以直接訪問外部類的所有成員, 訪問所在方法中的final類型的參數(shù)和變量;
七. ==? 和 equals() 的區(qū)別
== :比較的是,值是不是相等
基本數(shù)據(jù)類型比較的是值,引用類型比較的是地址值
equals(Object o): Object類中的方法,所以,在每一個java類中,都會有這個方法,因為每一個java類都是直接或者間接的Object類的子類,會繼承到這個方法
如果自己所寫的類中已經(jīng)重寫了equals方法,那么就安裝用戶自定義的方式來比較倆個對象是否相等,如果沒有重寫過equal方法,那么會調(diào)用父類(Object)中的equals方法進行比較,也就是比較地址值
注意:equals(Object o)方法只能是一個對象來調(diào)用,然后參數(shù)也是要傳一個對象的
所以下面是錯誤的寫法:
int a = 1;
a.equals(1);
因為基本數(shù)據(jù)類型不是算是對象,不能調(diào)用方法
如果是基本數(shù)據(jù)類型那么就用==比較
如果是引用類型的話,想按照自己的方式去比較,就要重寫這個類中的equals方法, 如果沒有重寫,那么equals和==比較的效果是一樣的,都是比較引用的地址值
如果是比較字符串,那么直接用equals就可以了,因為String類里面已經(jīng)重寫了equals方法,比較的時候字符串的內(nèi)容,而不是引用的地址值了
toString(): Object類中的方法,所以,在每一個java類中,都會有這個方法,因為每一個java類都是直接或者間接的Object類的子類,會繼承到這個方法
當前用一個引用指向一個對象的時候,比如:Student s = new Student(),然后如果直接打印這個引用s,其實是調(diào)用了s.toString()方法,然后就會把這個引用里面的存放的堆區(qū)對象的地址值顯示出來
所以我們會常常在類中重寫這個toString()方法,然后讓這個類的引用按照我們要求來返回內(nèi)容。
getClass():Object類中的方法,所以,在每一個java類中,都會有這個方法,并且這個方式final修飾的,不能被子類重寫,這個方法可以返回某一個引用在運行的時候指向?qū)ο蟮念愋?/p>
例如:Person p = new Student()
//會輸出:class com.briup.chap06.Student
//說明這個引用p在運行時指向的是Student這個類的對象
//注意這個引用p的類型是Person的(多態(tài))
System.out.println(p.getClass());
八. 基本數(shù)據(jù)類型對應(yīng)的包裝類型
boolean Boolean
byte Byte
short Short
char Character
int Integer
long Long
float Float
double Double