成員内部類
定義
成員内部類 :定義在外部類中方法外的類
定義格式:
[修飾符] class 外部類名 [extends 外部類的父類] [implements 外部類的父接口們] {
[修飾符] class 内部類名 [extends 非靜态内部類自己的父類] [implements 非靜态内部類的父接口們] {
靜态内部類的成員清單;
}
// 外部類的其他成員清單
}
外部類、内部類的父類、父接口沒有關系,各是各的
成員内部類特點
成員内部類仍然是一個獨立的類,在編譯之後内部類會被編譯成獨立的.class檔案,但是前面冠以外部類的類名和$符号。例如:Outer$Inner.class
成員内部類可以使用修飾符public,protected,預設,private
成員内部類還可以使用final或abstract修飾
成員内部類中不可以聲明靜态成員
成員内部類可以直接使用外部類的所有成員,包括私有的。如果成員内部類有與外部類的非靜态屬性重名時,可以通過“外部類名.this.屬性”進行差別,如果與外部類的靜态屬性重名時,可以通過“外部類名.類變量”進行差別
外部類要通路内部類的成員,必須要建立内部類的對象。
如何使用成員内部類
在外部類中使用成員内部類:
在外部類的靜态成員中不能使用非靜态的成員内部類
在外部類的非靜态成員中,直接建立内部類的對象來通路内部類的屬性與方法。此時把它當做一個普通的類即可
在外部類的外面使用成員内部類:
要麼通過外部類的對象,去建立内部類的對象
外部類名 外部對象名 = new 外部類型();
内部類名 對象名 = 外部對象名.new 外部類型();
//可合并為:
外部類名.内部類名 對象名 = new 外部類型().new 内部類型();
要麼通過外部類的對象,去擷取内部類的對象
Outer out = new Outer();
Outer.Inner in = out.getInner();
代碼示範:
public class MemberClassTest {
public static void main(String[] args) {
Outer out = new Outer();
out.outerMethod();
//通過外部類的對象,去建立内部類的對象
Outer.Inner oi = out.new Inner();
oi.innerMethod();
//通過外部類的對象,去擷取内部類的對象
Outer.Inner obj = out.getInner();
obj.innerMethod();
}
}
class Outer{
private int a = 1;
private static int b = 2;
public static void outerStaticMethod(){
}
public void outerMethod(){
System.out.println("外部類的方法");
}
class Inner{
private int a = 3;
private int b = 4;
public void innerMethod(){
System.out.println("内部類的方法");
System.out.println("内部類的方法通路外部類的私有非靜态屬性:"+Outer.this.a);
System.out.println("内部類的方法通路外部類的私有靜态屬性:"+Outer.b);
}
}
//通過外部類的某個方法傳回内部類的對象
public Inner getInner(){
return new Inner();
}
}
外部類的方法
内部類的方法
内部類的方法通路外部類的私有非靜态屬性:1
内部類的方法通路外部類的私有靜态屬性:2
内部類的方法
内部類的方法通路外部類的私有非靜态屬性:1
内部類的方法通路外部類的私有靜态屬性:2
靜态内部類
定義
靜态内部類:定義在外部類中方法外,使用 static 修飾的類
定義格式:
[修飾符] class 外部類名 [extends 外部類的父類] [implements 外部類的父接口們] {
[修飾符] static class 内部類名 [extends 靜态内部類自己的父類] [implements 靜态内部類的父接口們] {
靜态内部類的成員清單;
}
// 外部類的其他成員清單
}
靜态内部類的特點
靜态内部類仍然是一個獨立的類,在編譯之後内部類會被編譯成獨立的.class檔案,但是前面冠以外部類的類名和$符号。例如:Outer$Inner.class
靜态内部類可以使用修飾符public,protected,default,private
靜态内部類還可以使用final或abstract修飾
靜态内部類中可以聲明靜态成員
靜态内部類可以直接使用外部類的靜态成員,包括私有的。但不能使用外部類的非靜态成員。
靜态内部類中有與外部類的靜态屬性重名時,如果要使用外部類的屬性,那麼用“外部類名.屬性”
如何使用靜态内部類
在外部類中使用靜态内部類:就和使用其他普通類一樣
在外部類的外面使用成員内部類:
使用靜态内部類的靜态成員:外部類名.靜态内部類名.靜态内部類的靜态成員
使用靜态内部類的非靜态成員:外部類名.靜态内部類名 obj = new 外部類名.靜态内部類名(); obj.靜态内部類的非靜态成員
代碼示範:
public class StaticInnerClassTest {
public static void main(String[] args) {
Outer.StaticInnerClass.innerStaticMethod();
Outer.StaticInnerClass os = new Outer.StaticInnerClass();
os.innerMethod();
}
}
class Outer{
public static void outerStaticMethod(){
StaticInnerClass.innerStaticMethod();
StaticInnerClass si = new StaticInnerClass();
si.innerMethod();
}
public static void outerMethod(){
StaticInnerClass.innerStaticMethod();
StaticInnerClass si = new StaticInnerClass();
si.innerMethod();
}
static class StaticInnerClass{
public static void innerStaticMethod(){
System.out.println("内部類的靜态方法");
}
public void innerMethod(){
System.out.println("内部類的非靜态方法");
}
}
}
局部内部類
定義
局部内部類:定義在方法内、代碼塊内、構造器内
定義格式:
[修飾符] class 外部類名 [extends 外部類的父類] [implements 外部類的父接口們] {
[修飾符] 傳回值類型 方法名([形參清單]){
[修飾符] class 内部類名 [extends 局部内部類自己的父類] [implements 局部内部類的父接口們] {
局部内部類的成員清單;
}
}
// 外部類的其他成員清單
}
局部内部類的特點
局部内部類仍然是一個獨立的類,在編譯之後内部類會被編譯成獨立的.class檔案:“外部類的類名$數字編号内部類名.class”。
局部内部類和局部變量地位類似,不能使用 public,protected,private,static 這些成員修飾符,但是可以使用abstract或final
局部内部類不能使用static修飾,是以也不能包含靜态成員。
隻能在聲明它的方法或代碼塊中使用,而且是先聲明後使用。除此之外的任何地方都不能使用該類,因為作用域的問題。
局部内部類可以使用外部類的成員,包括私有的。但是是否可以使用外部類的非靜态成員要看所在方法是否是非靜态的。
局部内部類可以使用包含它的外部方法中的局部變量
如何使用局部内部類
隻能在聲明它的方法或代碼塊中使用,而且是先聲明後使用。除此之外的任何地方都不能使用該類。
但是它的對象可以通過包含此局部内部類的外部方法的傳回值傳回使用,傳回值類型隻能是局部内部類的父類或父接口類型。
代碼示範:
public class LocalInnerClassTest {
public static void main(String[] args) {
Outer out = new Outer();
Object obj = out.outerMethod();
System.out.println(obj);
System.out.println();
}
}
class Outer{
int value = 5;
public Object outerMethod(){
final int localValue = 10;
class LocalInnerClass {
public void innerMethod(){
System.out.println("局部内部類的方法");
System.out.println("局部内部類的方法可以使用外部類的成員變量:"+value);
System.out.println("局部内部類的方法可以使用外部類的局部變量:"+localValue);
}
}
//先聲明後使用
LocalInnerClass li = new LocalInnerClass();
li.innerMethod();
return li;
}
}
局部内部類的方法
局部内部類的方法可以使用外部類的成員變量:5
局部内部類的方法可以使用外部類的局部變量:10
[email protected]
匿名内部類
定義
匿名内部類 :本質是一個帶具體實作的 父類或者父接口的 匿名的 子類對象。
如果接口的實作類(或者是父類的子類)隻需要使用唯一的一次,那麼這種情況下就可以省略該類的定義,而改為使用【匿名内部類】。
特征:聲明匿名内部類的同時建立該類的對象
前提
存在一個類或者接口,這裡的類可以是抽象類也可以是普通類。
格式:
繼承父類:
new 父類名稱([實參清單]){
// 類的成員清單
};
說明:如果子類調用的是父類的無參構造,那麼()中實參清單不用寫,如果子類調用的是父類的有參構造,那麼就在()中傳入實際參數
實作接口:
new 接口名稱(){
// 類的成員清單
};
接口不是不能執行個體化建立對象嗎,new關鍵字的後面為什麼跟着接口名?
對格式“new 接口名稱() {...}”進行解析:
new代表建立對象的動作
接口名稱表示匿名内部類需要實作哪個接口
{...}是匿名内部類的内容
匿名内部類的特點
匿名内部類仍然是一個獨立的類,在編譯之後内部類會被編譯成獨立的.class檔案::外部類名$數字編号.class
匿名内部類必須繼承父類或實作接口
匿名内部類隻能有一個對象
匿名内部類對象隻能使用多态形式引用
匿名内部類是特殊的局部内部類,局部内部類的所有限制對它都适用
如何使用匿名内部類
以接口舉例,當你使用一個接口時,似乎得做如下幾步操作:
定義接口實作類
重寫接口中的方法
建立子類對象
調用重寫後的方法
我們的目的,最終隻是為了調用方法,那麼能不能簡化一下,把以上四步合成一步呢?
案例需求:
定義筆記本電腦類,電腦有USB接口,通過插入滑鼠、鍵盤等不同裝置,實作各自不同功能。
傳統方式:
定義接口:
public interface USB {
// 使用USB裝置的方法
public void use();
}
定義筆記本類,定義滑鼠類、鍵盤類分别實作USB接口:
class Mouse implements USB {
@Override
public void use() {
System.out.println("點選滑鼠操控電腦...");
}
}
class KeyBoard implements USB {
@Override
public void use() {
System.out.println("鍵盤輸入資料...");
}
}
public class NoteBook {
// USB裝置插入筆記本電腦的方法,要求傳遞的對象要實作USB接口
public void plugIn(USB usb) {
usb.use();
}
}
測試類:
public class AnonymousClassTest {
public static void main(String[] args) {
NoteBook noteBook = new NoteBook();
USB mouse = new Mouse();
noteBook.plugIn(mouse);
USB keyBoard = new KeyBoard();
noteBook.plugIn(keyBoard);
}
}
匿名内部類方式:
定義接口:
public interface USB {
public void use();
}
定義筆記本電腦類:
public class NoteBook {
// 要求傳遞的對象要實作USB接口
public void plugIn(USB usb) {
usb.use();
}
}
測試類:
public class AnonymousClassTest {
public static void main(String[] args) {
NoteBook noteBook = new NoteBook();
// 下面這段代碼,聲明了實作USB接口的匿名内部類,也建立了它的對象
// 但是這個對象既沒有指派給一個變量,也沒有直接調用方法,無法直接使用
new USB() {
@Override
public void use() {
System.out.println("實作了USB接口");
}
};
// 使用方式一:
// 把建立的對象指派給一個變量,然後調用重寫的use方法
// 多态引用
USB mouse = new USB() {
@Override
public void use() {
System.out.println("點選滑鼠操控電腦...");
}
};
mouse.use();
// 使用方式二:
// 用建立的對象直接調用重寫的use方法
new USB() {
@Override
public void use() {
System.out.println("鍵盤輸入資料...");
}
}.use();
// 使用方式三:
// 把建立的對象作為方法實參
noteBook.plugIn(new USB() {
@Override
public void use() {
System.out.println("U盤傳輸資料...");
}
});
}
}
測試結果:
點選滑鼠操控電腦...
鍵盤輸入資料...
U盤傳輸資料...