概念
將一個(gè)類A定義在另一個(gè)類B里面代咸,里面的那個(gè)類A就稱為內(nèi)部類译荞,B則稱為外部類瞪醋。例如忿晕,身體和心臟,只能是包含的關(guān)系不可單獨(dú)分離银受。
成員內(nèi)部類+局部內(nèi)部類
1. 成員局部類
public class Body { // 外部類
public class Heart { // 成員內(nèi)部類
// 內(nèi)部類的方法
public void beat() {
System.out.println("心臟跳動:蹦蹦蹦践盼!");
System.out.println("我叫:" + name); // 正確寫法鸦采!
}
}
// 外部類的成員變量
private String name;
// 外部類的方法
public void methodBody() {
System.out.println("外部類的方法");
new Heart().beat();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
如何使用成員內(nèi)部類?有兩種方式:
- 間接方式:在外部類的方法當(dāng)中咕幻,使用內(nèi)部類渔伯;然后main只是調(diào)用外部類的方法。
- 直接方式肄程,公式:
類名稱 對象名 = new 類名稱();
【外部類名稱.內(nèi)部類名稱 對象名 = new 外部類名稱().new 內(nèi)部類名稱();】
public static void main(String[] args) {
Body body = new Body(); // 外部類的對象
// 通過外部類的對象锣吼,調(diào)用外部類的方法,里面間接在使用內(nèi)部類Heart
body.methodBody();
System.out.println("=====================");
// 按照公式寫:
Body.Heart heart = new Body().new Heart();
heart.beat();
}
注意:內(nèi)用外蓝厌,隨意訪問吐限;外用內(nèi),需要內(nèi)部類對象褂始。
// 如果出現(xiàn)了重名現(xiàn)象诸典,那么格式是:外部類名稱.this.外部類成員變量名
public class Outer {
int num = 10; // 外部類的成員變量
public class Inner {
int num = 20; // 內(nèi)部類的成員變量
public void methodInner() {
int num = 30; // 內(nèi)部類方法的局部變量
System.out.println(num); // 局部變量,就近原則 30
System.out.println(this.num); // 內(nèi)部類的成員變量 20
System.out.println(Outer.this.num); // 外部類的成員變量 10
}
}
}
2. 局部內(nèi)部類
如果一個(gè)類是定義在一個(gè)方法內(nèi)部的崎苗,那么這就是一個(gè)局部內(nèi)部類狐粱。
“局部”:只有當(dāng)前所屬的方法才能使用它,出了這個(gè)方法外面就不能用了胆数。
class Outer {
public void methodOuter() {
class Inner { // 局部內(nèi)部類
int num = 10;
public void methodInner() {
System.out.println(num); // 10
}
}
Inner inner = new Inner();
inner.methodInner();
}
}
定義一個(gè)類的時(shí)候肌蜻,權(quán)限修飾符規(guī)則:
- 外部類:public / (default)
- 成員內(nèi)部類:public / protected / (default) / private
- 局部內(nèi)部類:什么都不能寫
/*
局部內(nèi)部類,如果希望訪問所在方法的局部變量必尼,那么這個(gè)局部變量必須是【有效final的】蒋搜。
備注:從Java 8+開始,只要局部變量事實(shí)不變判莉,那么final關(guān)鍵字可以省略豆挽。
原因:
1. new出來的對象在堆內(nèi)存當(dāng)中。
2. 局部變量是跟著方法走的券盅,在棧內(nèi)存當(dāng)中帮哈。
3. 方法運(yùn)行結(jié)束之后,立刻出棧锰镀,局部變量就會立刻消失娘侍。
4. 但是new出來的對象會在堆當(dāng)中持續(xù)存在,直到垃圾回收消失泳炉。
*/
public class MyOuter {
public void methodOuter() {
int num = 10; // 所在方法的局部變量
class MyInner {
public void methodInner() {
System.out.println(num);
}
}
}
}
匿名內(nèi)部類
- 場景
如果接口的實(shí)現(xiàn)類(或者是子類)只需要使用唯一的一次憾筏,
那么這種情況下就可以省略掉該類的定義,不用單獨(dú)寫一個(gè)子類花鹅,而改為使用【匿名內(nèi)部類】氧腰。
- 格式
匿名內(nèi)部類的定義格式:
接口名稱 對象名 = new 接口名稱() {
// 覆蓋重寫所有抽象方法
};
- 描述
- new 代表創(chuàng)建對象的動作
- 接口名稱 代表匿名內(nèi)部類需要實(shí)現(xiàn)哪個(gè)接口
- {...} 這才是匿名內(nèi)部類的內(nèi)容
- 注意
- 匿名內(nèi)部類,在【創(chuàng)建對象】的時(shí)候,類只能使用唯一一次容贝,對象也只有一個(gè)自脯。
如果希望多次創(chuàng)建對象,而且類的內(nèi)容一樣的話斤富,那么就需要使用單獨(dú)定義的實(shí)現(xiàn)類了膏潮。- 匿名對象,在【調(diào)用方法】的時(shí)候满力,方法只能調(diào)用唯一一次焕参。
如果希望同一個(gè)對象,調(diào)用多次方法油额,那么必須給對象起個(gè)名字叠纷。- 匿名內(nèi)部類是省略了【實(shí)現(xiàn)類/子類名稱】,但是匿名對象是省略了【對象名稱】
強(qiáng)調(diào):匿名內(nèi)部類和匿名對象不是一回事A仕弧I!
public interface MyInterface {
void method1(); // 抽象方法
void method2();
}
public class DemoMain {
public static void main(String[] args) {
// 使用匿名內(nèi)部類掂僵,但不是匿名對象航厚,對象名稱就叫objA
MyInterface objA = new MyInterface() {
@Override
public void method1() {
System.out.println("匿名內(nèi)部類實(shí)現(xiàn)了方法!111-A");
}
@Override
public void method2() {
System.out.println("匿名內(nèi)部類實(shí)現(xiàn)了方法锰蓬!222-A");
}
};
objA.method1();
objA.method2();
System.out.println("=================");
// 使用了匿名內(nèi)部類幔睬,而且省略了對象名稱,也是匿名對象
new MyInterface() {
@Override
public void method1() {
System.out.println("匿名內(nèi)部類實(shí)現(xiàn)了方法芹扭!111-B");
}
@Override
public void method2() {
System.out.println("匿名內(nèi)部類實(shí)現(xiàn)了方法麻顶!222-B");
}
}.method1();
// 因?yàn)槟涿麑ο鬅o法調(diào)用第二次方法,所以需要再創(chuàng)建一個(gè)匿名內(nèi)部類的匿名對象
new MyInterface() {
@Override
public void method1() {
System.out.println("匿名內(nèi)部類實(shí)現(xiàn)了方法舱卡!111-B");
}
@Override
public void method2() {
System.out.println("匿名內(nèi)部類實(shí)現(xiàn)了方法辅肾!222-B");
}
}.method2();
}
}