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

