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

