java內(nèi)部類之成員內(nèi)部類、局部內(nèi)部類和匿名內(nèi)部類用法及說明
內(nèi)部類概念
一個(gè)類中包含另外一個(gè)類。
分類
- 成員內(nèi)部類。
- 局部內(nèi)部類(包含匿名內(nèi)部類)。
成員內(nèi)部類
定義格式:
修飾符 class 類名稱 { 修飾符 class 類名稱 { //... } //... }
注意:
內(nèi)部類使用外部,可以隨意訪問,但是外部類使用內(nèi)部類要借助內(nèi)部類的對(duì)象。
使用成員內(nèi)部類
兩種方法:
1. 間接方式:在外部類的方法中,使用內(nèi)部類,然后main只調(diào)用外部類的方法。
2. 直接方式:公式:
一般類:類名稱 對(duì)象名 = new 類名稱();
成員內(nèi)部類:外部內(nèi)名稱.內(nèi)部類名稱 對(duì)象名 = new 外部類名稱().new 內(nèi)部類名稱();
Body.java含有一個(gè)內(nèi)部類Heart
public class Body { private String name; //外部類方法 public void methodBody() { System.out.println("外部類的方法"); new Heart().beat();//在外部類方法中使用內(nèi)部類。 } public class Heart { //成員內(nèi)部類 //內(nèi)部類方法 public void beat() { System.out.println("心臟跳動(dòng)"); System.out.println("我叫:"+name); } } }
下面分別介紹兩種方式訪問內(nèi)部類:
間接方式訪問內(nèi)部類
Demo01InnerClass.java
public class Demo01InnerClass { public static void main(String[] args) { Body body = new Body();//外部類對(duì)象 //通過外部類的對(duì)象,調(diào)用外部類的方法,里面間接使用內(nèi)部類Heart body.methodBody();
直接方式訪問內(nèi)部類
public class Demo01InnerClass { public static void main(String[] args) { Body body = new Body();//外部類對(duì)對(duì)象 //外部內(nèi)名稱.內(nèi)部類名稱 對(duì)象名 = new 外部類名稱().new 內(nèi)部類名稱(); Body.Heart heart = new Body().new Heart(); heart.beat(); } }
外部類和內(nèi)部類變量重名問題
當(dāng)外部類的變量和內(nèi)部類變量重名時(shí),在內(nèi)部類方法中訪問外部類變量的格式是:外部類.this.外部類成員變量名
public class Outer { int number = 10; public class Inner { int number = 20; public void methodInner() { int number =30;//內(nèi)部類方法的局部變量 System.out.println(number);//就近原則 System.out.println(this.number); System.out.println(Outer.this.number);//外部類的成員變量 } } }
30
20
10
局部內(nèi)部類
如果類是定義在一個(gè)方法內(nèi)部的,那么這就是一個(gè)局部內(nèi)部類。
“局部”:只有當(dāng)前所屬的方法才能使用它,出了這個(gè)方法外面就不能用了。
定義格式:
修飾符 class 外部類名稱 { 修飾符 返回值類型 外部類方法名稱(參數(shù)列表) { class 局部內(nèi)部類名稱 { //... } } }
Outer.java含有局部內(nèi)部類
public class Outer { public void methodOuter() { class Inner { int num = 10; public void methodInner() { System.out.println(num);//10 } } //這個(gè)內(nèi)部列只有當(dāng)前所屬方法能夠訪問這個(gè)類,出了這個(gè)方法就不能用了 Inner inner = new Inner(); inner.methodInner(); } }
DemoMain.java
public class DemoMain { public static void main(String[] args) { Outer outer = new Outer(); outer.methodOuter(); } }
結(jié)果:
10
注意:
局部內(nèi)部類,如果希望訪問所在方法的局部變量,那么這個(gè)局部變量必須是【有效final的】
備注:從java 8+開始,只要局部變量事實(shí)不變,那么final關(guān)鍵字可以省略。
原因:
1. new 出來的對(duì)象在堆內(nèi)存當(dāng)中。
2. 局部變量是跟著方法走的,在棧內(nèi)存當(dāng)中。
3. 方法運(yùn)行結(jié)束后,立刻出棧,局部變量就會(huì)立刻消失。
4. 但是new出來的對(duì)象在堆當(dāng)中持續(xù)存在,直到垃圾回收消失。
public class MyOuter { public void methodOuter() { final int num = 10;//所在方法的局部變量 /*在棧中的局部變量可能隨著方法結(jié)束出棧消失了,但是創(chuàng)建的內(nèi)部類對(duì)象還存在。 對(duì)象使用常量時(shí)能直接將常量copy進(jìn)來,這時(shí)就要保證這個(gè)常量是不可更改的,也就是final。 */ //num = 20; class MyInner { public void methodInner() { System.out.println(num); } } Inner myinner = new MyInner(); inner.methodInner(); } }
修飾內(nèi)部類的權(quán)限
public > protected > (default) > private
定義一個(gè)類的時(shí)候,權(quán)限修飾符規(guī)則:
- 外部類:public / (default)
- 成員內(nèi)部類:都可以寫,public > protected > (default) > private
- 局部內(nèi)部類:什么都不能寫,但不是de
匿名內(nèi)部類
如果接口的實(shí)現(xiàn)類(或者是父類的子類)只需要使用唯一的一次。
那么這種情況下就可以省略調(diào)該類的定義,而改為使用【匿名內(nèi)部類】。
匿名內(nèi)部類定義格式:
接口名稱 對(duì)象名 = new 類名或者接口名稱() { //覆蓋重寫所有抽象方法 };
代表繼承了或者實(shí)現(xiàn)了該接口的子類對(duì)象。
==接口MyInterface.java==
public interface MyInterface { void method1();//抽象方法 void method2(); }
==接口實(shí)現(xiàn)類MyInterfaceImp.java==
public class MyInterfaceImpl implements MyInterface { @Override public void method1() { System.out.println("實(shí)現(xiàn)類覆蓋重寫了方法1"); } @Override public void method2() { System.out.println("實(shí)現(xiàn)了覆蓋重寫方法2"); } }
測(cè)試類 一
一般接口實(shí)現(xiàn)方法
DemoMain.java
public class DemoMain { public static void main(String[] args) { // MyInterface impl = new MyInterfaceImpl(); // impl.method(); } }
匿名內(nèi)部類實(shí)現(xiàn)接口
DemoMain.java
public class DemoMain { public static void main(String[] args) { //使用匿名內(nèi)部類,但不匿名對(duì)象,對(duì)象名稱就叫obj MyInterface objA = new MyInterface() { @Override public void method1() { System.out.println("匿名內(nèi)部類實(shí)現(xiàn)了方法1-A"); } @Override public void method2() { System.out.println("匿名內(nèi)部類實(shí)現(xiàn)了方法2-A"); } }; objA.method1(); objA.method2(); System.out.println("----------我是分割線----------"); //使用匿名內(nèi)部類,而且省略了對(duì)象名稱,也是匿名對(duì)象 new MyInterface() { @Override public void method1() { System.out.println("匿名內(nèi)部類實(shí)現(xiàn)了方法1-B"); } @Override public void method2() { System.out.println("匿名內(nèi)部類實(shí)現(xiàn)了方法2-B"); } }.method1(); } }
結(jié)果:
匿名內(nèi)部類實(shí)現(xiàn)了方法1-A
匿名內(nèi)部類實(shí)現(xiàn)了方法2-A
----------我是分割線----------
匿名內(nèi)部類實(shí)現(xiàn)了方法1-B
匿名內(nèi)部內(nèi)應(yīng)用
實(shí)現(xiàn)倒計(jì)時(shí)5秒。
public class Demo02_Time { public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("倒計(jì)時(shí)5秒"); } },5000);//倒計(jì)時(shí)5秒 } }
注意事項(xiàng):
對(duì)格式進(jìn)行解析:"new 接口名稱 {...};"進(jìn)行解析
- new代表創(chuàng)建對(duì)象的動(dòng)作
- 接口名稱就是匿名內(nèi)部類需要實(shí)現(xiàn)那個(gè)接口
- {…}這才是匿名內(nèi)部類的內(nèi)容
注意:
- 這個(gè)類只需要使用一次。匿名內(nèi)部類在創(chuàng)建對(duì)象時(shí),只能使用唯一一次。
- 如果希望多次希望多次創(chuàng)建對(duì)象,而且內(nèi)容一樣的話,那么就必須使用單獨(dú)定義的實(shí)現(xiàn)類。
- 匿名對(duì)象,在調(diào)用的時(shí)候,只能調(diào)用唯一一次。
- 如果希望同一個(gè)對(duì)象,調(diào)用多次方法,那么必須給對(duì)象取一個(gè)名字。
- 匿名內(nèi)部類是省略了【實(shí)現(xiàn)類/子類】,但是匿名對(duì)象是省略了【對(duì)象命名】。
強(qiáng)調(diào):匿名和匿名對(duì)象不是一回事。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot設(shè)置Session失效時(shí)間的解決方案
當(dāng)過期時(shí)間是大于1分鐘的時(shí)候是沒有什么問題的,但是如果設(shè)置過期時(shí)間小于1分鐘,就會(huì)失效,這篇文章主要介紹了SpringBoot設(shè)置Session失效時(shí)間的解決方案,需要的朋友可以參考下2024-05-05Java中@DateTimeFormat和@JsonFormat注解介紹
@DateTimeFormat和@JsonFormat都是處理時(shí)間格式化問題的,把其他類型轉(zhuǎn)換成自己需要的時(shí)間類型,下面這篇文章主要給大家介紹了關(guān)于Java中@DateTimeFormat和@JsonFormat注解介紹的相關(guān)資料,需要的朋友可以參考下2022-11-11spring中12種@Transactional的失效場景(小結(jié))
日常我們進(jìn)行業(yè)務(wù)開發(fā)時(shí),基本上使用的都是聲明式事務(wù),即為使用@Transactional注解的方式,本文主要介紹了spring中12種@Transactional的失效場景,感興趣的小伙伴們可以參考一下2022-01-01Java硬幣翻轉(zhuǎn)倍數(shù)遞增試算實(shí)例
這篇文章主要介紹了Java硬幣翻轉(zhuǎn)倍數(shù)遞增試算實(shí)例,有需要的朋友可以參考一下2013-12-12詳解Java多線程編程中LockSupport類的線程阻塞用法
LockSupport類提供了park()和unpark()兩個(gè)方法來實(shí)現(xiàn)線程的阻塞和喚醒,下面我們就來詳解Java多線程編程中LockSupport類的線程阻塞用法:2016-07-07基于logback 實(shí)現(xiàn)springboot超級(jí)詳細(xì)的日志配置
java web 下有好幾種日志框架,比如:logback,log4j,log4j2(slj4f 并不是一種日志框架,它相當(dāng)于定義了規(guī)范,實(shí)現(xiàn)了這個(gè)規(guī)范的日志框架就能夠用 slj4f 調(diào)用)。這篇文章主要介紹了基于logback springboot超級(jí)詳細(xì)的日志配置,需要的朋友可以參考下2019-06-06IDEA項(xiàng)目中配置Maven鏡像源(下載源)的詳細(xì)過程
Maven是一個(gè)能使我們的java程序開發(fā)節(jié)省時(shí)間和精力,是開發(fā)變得相對(duì)簡單,還能使開發(fā)規(guī)范化的工具,下面這篇文章主要給大家介紹了關(guān)于IDEA項(xiàng)目中配置Maven鏡像源(下載源)的詳細(xì)過程,需要的朋友可以參考下2024-02-02