JAVA內部類總結筆記
內部類分為四類:成員內部類、區域性(作用域)內部類、匿名內部類、靜態內部類。
成員內部類 | 區域性(作用域)內部類 | 匿名內部類 | 靜態內部類 | |
訪問修飾符 | 有 | 無 | 無 | 有 |
成員內部類
就像一個成員變數和方法一樣,你說她有沒有修飾符?有的呀!同時可以訪問外部類的靜態/非靜態變數和方法。
若內部類擁有與外部類同名成員(變數/方法),預設訪問成員內部類。訪問外部 外部類.this.成員(變數/方法)
綜上:想成員一樣的成員內部類,使用時需要先建立外部物件。
public class Outter { private Inner inner = null; public void printMsg() { System.out.println("我是一個快樂的外部類"); } public class Inner { public void printMsg() { System.out.println("我是一個快樂的內部類"); } public void printAgain() { this.printMsg(); Outter.this.printMsg(); } } /** * 聽說使用getXXX的方式獲取例項物件會更優雅哦 */ public Inner getInner() { if (null == inner) inner = new Inner(); return inner; } public static void main (String[] args) { //建立外部類物件 Outter outter = new Outter(); Outter.Inner inner = outter.new Inner(); Inner inner2 = outter.getInner(); inner.printMsg(); inner2.printMsg(); outter.printMsg(); inner.printAgain(); } }
列印結果:
這是我隨手寫的一個醜陋的內部類。printAgain寫了在內部類呼叫同名外部類成員的方式。
區域性內部類
聯想一下,區域性?區域性變數啥的,作用域是區域性的。這裡的區域性內部類是指方法內定義內部類和作用域內定義內部類。她們的訪問許可權僅限方法/作用域。
她們有修飾符嗎?你想想,你家方法內部的變數寫修飾符了嗎?小傻瓜。
public class Outter { private MemberInner inner = null; public void printMsg() { System.out.println("Outter.printMsg: 我是一個快樂的外部類"); } /** * 成員內部類 */ public class MemberInner { public void printMsg() { System.out.println("Inner.printMsg: 我是一個快樂的內部類"); } public void printAgain() { //他自己 this.printMsg(); //他外面的 Outter.this.printMsg(); } } /** * 聽說使用getXXX的方式獲取例項物件會更優雅哦 */ public MemberInner getInner() { if (null == inner) inner = new MemberInner(); return inner; } public MemberInner ordinaryMethod() { /** *區域性內部類-方法內 */ class LocalInner extends MemberInner{ @Override public void printMsg() { System.out.println("LocalInner.printMsg: 人家才不是成員內部類呢,我是一個可愛的方法內區域性內部類啊!"); } } return new LocalInner(); } public void anotherOrdinaryMethod (Boolean isTrue) { if (isTrue) { /** *區域性內部類-作用域 */ class AnotherLocalInner { public void printMsg() { System.out.println("AnotherLocalInner.printMsg: 我是一個可愛的作用域內部類啊!"); } } this.printMsg(); printMsg(); new AnotherLocalInner().printMsg(); } } public static void main (String[] args) { //建立外部類物件 Outter outter = new Outter(); //成員內部類 Outter.MemberInner inner = outter.new MemberInner(); MemberInner inner2 = outter.getInner(); inner.printMsg(); inner2.printMsg(); outter.printMsg(); inner.printAgain(); System.out.println("----------------------華麗麗的分割線---------------------"); //區域性內部類 outter.ordinaryMethod().printMsg(); outter.anotherOrdinaryMethod(true); } }
列印結果:
Inner.printMsg: 我是一個快樂的內部類 Inner.printMsg: 我是一個快樂的內部類 Outter.printMsg: 我是一個快樂的外部類 Inner.printMsg: 我是一個快樂的內部類 Outter.printMsg: 我是一個快樂的外部類 ----------------------華麗麗的分割線--------------------- LocalInner.printMsg: 人家才不是成員內部類呢,我是一個可愛的方法內區域性內部類啊! Outter.printMsg: 我是一個快樂的外部類 Outter.printMsg: 我是一個快樂的外部類 AnotherLocalInner.printMsg: 我是一個可愛的作用域內部類啊! Process finished with exit code 0
綜上:無
匿名內部類
感覺大多是用在swing程式設計,監聽事件啊、介面回撥什麼的。對繼承方法的重寫或者實現什麼的。
她沒有修飾符,由於沒有名字(類名),可憐得連構造方法也沒有QAQ(不能定義構造方法,但有內部程式碼塊來初始化引數)。
public class Outter {
private MemberInner inner = null;
public void printMsg() {
System.out.println("Outter.printMsg: 我是一個快樂的外部類");
}
/**
* 成員內部類
*/
public class MemberInner {
public void printMsg() {
System.out.println("Inner.printMsg: 我是一個快樂的內部類");
}
public void printAgain() {
//他自己
this.printMsg();
//他外面的
Outter.this.printMsg();
}
}
/**
* 聽說使用getXXX的方式獲取例項物件會更優雅哦
*/
public MemberInner getInner() {
if (null == inner)
inner = new MemberInner();
return inner;
}
/**
* 內部類使用了方法的形參age
*/
public MemberInner ordinaryMethod(int age) {
/**
*區域性內部類-方法內
*/
class LocalInner extends MemberInner{
@Override
public void printMsg() {
System.out.println("倫家今年" + (age) + "歲呢");
System.out.println("LocalInner.printMsg: 人家才不是成員內部類呢,我是一個可愛的方法內區域性內部類啊!");
}
}
return new LocalInner();
}
public void anotherOrdinaryMethod (Boolean isTrue) {
if (isTrue) {
/**
*區域性內部類-作用域
*/
class AnotherLocalInner {
public void printMsg() {
System.out.println("AnotherLocalInner.printMsg: 我是一個可愛的作用域內部類啊!");
}
}
this.printMsg();
printMsg();
new AnotherLocalInner().printMsg();
}
}
public void getAnonymousInner(AnonymousInner anonymousInner) {
System.out.println("這麼可愛一定是" + anonymousInner.whatSex() + "吧!");
}
/**
* 內部類使用方法形參
*/
public AnonymousInner transferValue(String sex) {
return new AnonymousInner() {
@Override
public String whatSex() {
return sex;
}
};
}
public static void main (String[] args) {
//建立外部類物件
Outter outter = new Outter();
//成員內部類
Outter.MemberInner inner = outter.new MemberInner();
MemberInner inner2 = outter.getInner();
inner.printMsg();
inner2.printMsg();
outter.printMsg();
inner.printAgain();
System.out.println("----------------------華麗麗的分割線---------------------");
//區域性內部類
outter.ordinaryMethod(12).printMsg();
outter.anotherOrdinaryMethod(true);
System.out.println("----------------------華麗麗的分割線---------------------");
//匿名內部類
outter.getAnonymousInner(new AnonymousInner() {
@Override
public String whatSex() {
return "男孩子";
}
});
outter.getAnonymousInner(outter.transferValue("女孩子"));
}
}
/**
* 匿名內部類的抽象類
*/
abstract class AnonymousInner {
public abstract String whatSex();
}
在方法ordinaryMethod中,使用了外部方法的形參age,在我試圖修改age時,ide提示錯誤:
Variable 'age' is accessed from within inner class,needs to be final or effectively final
變數age是在內部類中訪問的,需要時final修飾的或是實際上的最終變數。
*在以前內部類相關博文中提到,區域性內部類和匿名內部類使用外部類區域性變數或形參時必須是final,但在JAVA8中不再必須final了,是effectively final也支援。即只要你不去修改外部區域性變數/形參的值,則視為effectively final,就不會報錯。
關於JAVA8以前必須使用final修飾的原因:
首先,一個有內部類的類,在編譯器編譯時,會將內部類單獨編譯成一個class檔案,即有兩個class檔案。內部類不是直接使用傳遞引數,而是通過拷貝備份(利用自身構造器)的方式來使用,所以如果內部類使用的變數和外部方法的變數不是同一個,在內部類中變數發生變化,會造成資料的不一致性,因此用final來限定區域性變數和形參的不可變。
靜態內部類
想一想,不充錢你會變得更強嗎?
想一想,你在用你的工具類的時候需要去new她嗎?不。
所以,不需要外部類先去建立例項物件。因此可以推斷,他(靜態內部類)也不能使用外部類的非靜態成員(變數/方法),因為外部類非靜態成員是依賴具體物件的。
public class AnotherOutter {
public static class StaticInner {
public void printMsg() {
System.out.println("想一想,不充錢?你會變得更強嗎?----靜態內部類");
}
}
public static void main (String[] args) {
StaticInner staticInner = new StaticInner();
staticInner.printMsg();
}
}
class Strangers {
public static void main (String[] args) {
AnotherOutter.StaticInner staticInner = new AnotherOutter.StaticInner();
staticInner.printMsg();
}
}
關於內部類的總結就到這裡了,如果有錯誤的地方歡迎各位指正,謝謝(づ ̄3 ̄)づ╭❤~。