來自拉鉤教育-JAVA就業(yè)集訓(xùn)營
內(nèi)部類的基本概念
- 當(dāng)一個(gè)類的定義出現(xiàn)在另外一個(gè)類的類體中時(shí),那么這個(gè)類叫做內(nèi)部類(Inner)择吊,而這個(gè)內(nèi)部類所在的類叫做外部類(Outer)促绵。
- 類中的內(nèi)容:成員變量攒庵、成員方法、構(gòu)造方法败晴、靜態(tài)成員浓冒、構(gòu)造塊和靜態(tài)代碼塊、內(nèi)部類尖坤。
內(nèi)部類的實(shí)際作用
- 當(dāng)一個(gè)類存在的價(jià)值僅僅是為某一個(gè)類單獨(dú)服務(wù)時(shí)稳懒,那么就可以將這個(gè)類定義為所服務(wù)類中的內(nèi)部類,這樣可以隱藏該類的實(shí)現(xiàn)細(xì)節(jié)并且可以方便的訪問外部類的私有成員而不再需要提供公有的get和set方法慢味。
內(nèi)部類的分類
- 普通內(nèi)部類 - 直接將一個(gè)類的定義放在另一個(gè)類的類體中场梆。
- 靜態(tài)內(nèi)部類 - 使用static關(guān)鍵字修飾的內(nèi)部類,隸屬于類層級(jí)纯路。
- 局部內(nèi)部類 - 直接將一個(gè)類的定義放在方法體的內(nèi)部時(shí)或油。
- 匿名內(nèi)部類 - 就是指沒有名字的內(nèi)部類。
普通(成員)內(nèi)部類的格式
- 訪問修飾符 class 外部類的類名 {
訪問修飾符 class 內(nèi)部類的類名 {
內(nèi)部類的類體;
}
}
package com.lagou.task10;
/**
* 編程實(shí)現(xiàn)普通內(nèi)部類的定義和使用 -- 文檔注釋
*/
public class NormalOuter {
private int cnt = 1;
// 定義普通內(nèi)部類驰唬,隸屬于外部類的成員顶岸,并且是對(duì)象層級(jí)
public class NormalInner {
private int ia = 2;
public NormalInner() {
System.out.println("普通內(nèi)部類的構(gòu)造方法體執(zhí)行到了!");
}
public void show() {
System.out.println("外部類中的變量cnt的數(shù)值為:" + cnt);
System.out.println("ia = " + ia);
}
}
}
package com.lagou.task10;
public class NormalOuterTest {
public static void main(String[] args) {
// 1.聲明NormalOuter類型的引用指向該類型的對(duì)象
NormalOuter no = new NormalOuter();
// 2.聲明NormalOuter類中的內(nèi)部類的引用指向內(nèi)部類的對(duì)象
NormalOuter.NormalInner ni = no.new NormalInner();
// 調(diào)用內(nèi)部類中的show方法
ni.show();
}
}
普通內(nèi)部類的使用方法
- 普通內(nèi)部類和普通類一樣可以定義成員變量叫编、成員方法以及構(gòu)造方法等辖佣。
- 普通內(nèi)部類和普通類一樣可以使用final或者abstract關(guān)鍵字修飾。
- 普通內(nèi)部類還可以使用private或protected關(guān)鍵字進(jìn)行修飾搓逾。
- 普通內(nèi)部類需要使用外部類對(duì)象來創(chuàng)建對(duì)象卷谈。
- 如果內(nèi)部類訪問外部類中與本類內(nèi)部同名的成員變量或方法時(shí),需要使用this關(guān)鍵字霞篡。
靜態(tài)內(nèi)部類的格式
- 訪問修飾符 class 外部類的類名 {
訪問修飾符 static class 內(nèi)部類的類名 {
內(nèi)部類的類體;
}
}
靜態(tài)內(nèi)部類的使用方式
- 靜態(tài)內(nèi)部類不能直接訪問外部類的非靜態(tài)成員世蔗。
- 靜態(tài)內(nèi)部類可以直接創(chuàng)建對(duì)象端逼。
- 如果靜態(tài)內(nèi)部類訪問外部類中與本類內(nèi)同名的成員變量或方法時(shí),需要使用類名.的方式訪問
局部(方法)內(nèi)部類的格式
訪問修飾符 class 外部類的類名 {
訪問修飾符 返回值類型 成員方法名 (形參列表) {
class 內(nèi)部類的類名 {
內(nèi)部類的類體;
}
}
}
package com.lagou.task10;
/**
* 編程實(shí)現(xiàn)局部內(nèi)部類的定義和使用
*/
public class AreaOuter {
private int cnt = 1;
public void show() {
// 定義局部內(nèi)部類凸郑,只在當(dāng)前方法體的內(nèi)部好使
class AreaInner {
private int ia = 1;
public AreaInner() {
System.out.println("局部內(nèi)部類的構(gòu)造方法裳食!");
}
public void test() {
System.out.println("ia = " + ia);
System.out.println("cnt = " + cnt);
}
}
// 聲明局部內(nèi)部類的引用指向局部內(nèi)部類的對(duì)象
AreaInner ai = new AreaInner();
ai.test();
}
}
package com.lagou.task10;
public class AreaOuterTest {
public static void main(String[] args) {
//1.聲明外部類類型的引用指向外部類的對(duì)象
AreaOuter ao = new AreaOuter();
// 2.通過show方法的調(diào)用實(shí)現(xiàn)局部內(nèi)部類的定義和使用
ao.show();
}
}
局部內(nèi)部類的使用方式
- 局部內(nèi)部類只能在該方法的內(nèi)部可以使用
- 局部內(nèi)部類可以在方法體內(nèi)部直接創(chuàng)建對(duì)象。
- 局部內(nèi)部類不能使用訪問控制符和 static 關(guān)鍵字修飾符芙沥。
- 局部內(nèi)部類可以使用外部方法的局部變量,但是必須是final的浊吏,有局部內(nèi)部類和局部變量的聲明周期不同所致而昨。
回調(diào)模式的概念
- 回調(diào)模式是指 --- 如果一個(gè)方法的參數(shù)是接口類型,則在調(diào)用該方法時(shí)找田,需要?jiǎng)?chuàng)建并傳遞一個(gè)實(shí)現(xiàn)此接口類型的對(duì)象歌憨;而該方法在運(yùn)行時(shí)會(huì)調(diào)用到參數(shù)對(duì)象中所實(shí)現(xiàn)的方法(接口中定義的)。
package com.lagou.task10;
public interface AnonymousInterface {
// 自定義抽象方法
public abstract void show();
}
package com.lagou.task10;
public class AnonymousInterfaceImpl implements AnonymousInterface {
@Override
public void show() {
System.out.println("這里是接口的實(shí)現(xiàn)類");
}
}
package com.lagou.task10;
public class AnonymousInterfaceTest {
// 假設(shè)已有下面的方法墩衙,請(qǐng)問如何調(diào)用下面的方法务嫡?
// AnonymousInterface ai = new AnonymousInterfaceImpl();
// 接口類型的引用指向?qū)崿F(xiàn)類型的對(duì)象,形成了多態(tài)
public static void test(AnonymousInterface ai){
// 編譯階段調(diào)用父類版本漆改,運(yùn)行調(diào)用實(shí)現(xiàn)類重寫的版本
ai.show();
}
public static void main(String[] args) {
// AnonymousInterfaceTest.test(new AnonymousInterface()); // Error:接口不能實(shí)例化
AnonymousInterfaceTest.test(new AnonymousInterfaceImpl());
}
}
匿名內(nèi)部類開發(fā)經(jīng)驗(yàn)分享
- 當(dāng)接口/類類型的引用作為方法的形參時(shí)心铃,實(shí)參的傳遞方式有兩種:
- 自定義類實(shí)現(xiàn)接口/繼承類并重寫方法,然后創(chuàng)建該類對(duì)象作為實(shí)參傳遞挫剑;
- 使用上述匿名內(nèi)部類的語法格式得到接口/類類型的引用即可去扣;
匿名內(nèi)部類的語法格式
- 接口/ 父類類型 引用變量名 = new 接口/父類類型() {方法的重寫};
AnonymousInterface ait = new AnonymousInterface() {
@Override
public void show() {
System.out.println("匿名內(nèi)部類就是這么玩的,雖然你很抽象樊破!");
}
};
AnonymousInterfaceTest.test(ait);
枚舉的基本概念
- 一年中的所有季節(jié):春季愉棱、夏季、秋季哲戚、冬季
- 所有性別:男奔滑、女
- 在日常生活中這些事務(wù)的取值只有明確的幾個(gè)固定值,此時(shí)描述這些事務(wù)的所有值都可以一一列舉出來顺少,而這個(gè)列舉出來的類型就叫做枚舉類型朋其。
package com.lagou.task10;
/**
* 編程實(shí)現(xiàn)所有方向的枚舉,所有的方向:向上祈纯、向下令宿、向左、向右
*/
public class Direction {
private final String desc; // 用于描述方向字符串的成員變量
// 2.聲明本類類型的引用指向本類類型的對(duì)象
public final static Direction UP = new Direction("向上");
public final static Direction DOWN = new Direction("向下");
public final static Direction LEFT = new Direction("向左");
public final static Direction RIGHT = new Direction("向右");
// 通過構(gòu)造方法實(shí)現(xiàn)字符串的初始化腕窥,更加靈活
// 1.私有化構(gòu)造方法粒没,此時(shí)該構(gòu)造方法只能在本類的內(nèi)部使用
private Direction(String desc) {
this.desc = desc;
}
// 通過公有的get方法可以在本類的外部訪問該類成員變量的數(shù)值
public String getDesc() {
return desc;
}
}
package com.lagou.task10;
public class DirectionTest {
public static void main(String[] args) {
/*
// 1.聲明 覅熱餐廳類型的引用指向該類型的對(duì)象并打印特征
Direction d1 = new Direction("向上");
System.out.println("獲取到的字符串是:" + d1.getDesc()); // 向上
Direction d2 = new Direction("向下");
System.out.println("獲取到的字符串是:" + d2.getDesc()); // 向下
Direction d3 = new Direction("向左");
System.out.println("獲取到的字符串是:" + d3.getDesc()); // 向左
Direction d4 = new Direction("向右");
System.out.println("獲取到的字符串是:" + d4.getDesc()); // 向右
System.out.println("-----------------------------------");
Direction d5 = new Direction("向前");
System.out.println("獲取到的字符串是:" + d5.getDesc()); // 向前
*/
// Direction d2 = null;
// Direction.UP = d2;
Direction d1 = Direction.DOWN;
System.out.println(d1.getDesc());
}
}
枚舉的定義
- 使用public static final 表示的常量描述較為繁瑣,使用enum關(guān)鍵字來定義枚舉類型取代常量簇爆,枚舉類型是從Java5開始增加的一種引用數(shù)據(jù)類型癞松。
- 枚舉值就是當(dāng)前類的類型爽撒,也就是指向本類的對(duì)象,默認(rèn)使用public static final 關(guān)鍵字共同修飾响蓉,因此采用枚舉類型.的方式調(diào)用硕勿。
- 枚舉類可以自定義構(gòu)造方法,但是構(gòu)造方法的修飾符必須是 private枫甲,默認(rèn)也是私有的源武。
package com.lagou.task10;
/**
* 編程實(shí)現(xiàn)所有方向的枚舉,所有的方向:向上想幻、向下粱栖、向左、向右
* 枚舉類型要求所有枚舉值必須放在枚舉類型的最前面
*/
public enum DirectionEnum {
// 2.聲明本類類型的引用指向本類類型的對(duì)象
UP("向上"),DOWN("向下"),LEFT("向左"),RIGHT("向右");
private final String desc; // 用于描述方向字符串的成員變量
// 通過構(gòu)造方法實(shí)現(xiàn)字符串的初始化脏毯,更加靈活
// 1.私有化構(gòu)造方法闹究,此時(shí)該構(gòu)造方法只能在本類的內(nèi)部使用
private DirectionEnum(String desc) {
this.desc = desc;
}
// 通過公有的get方法可以在本類的外部訪問該類成員變量的數(shù)值
public String getDesc() {
return desc;
}
}
package com.lagou.task10;
public class DirectionTest {
public static void main(String[] args) {
// 使用 java 5開始的枚舉類型
DirectionEnum de = DirectionEnum.DOWN;
System.out.println(de.getDesc());
}
}
Enum類的概念和方法
- 所有的枚舉類都繼承自java.lang.Enum類,常用方法如下:
package com.lagou.task10;
/**
* 編程實(shí)現(xiàn)方向枚舉類的測(cè)試
*/
public class DirectionEnumTest {
public static void main(String[] args) {
// 1.獲取DirectionEnum類型中所有的枚舉對(duì)象
DirectionEnum[] arr = DirectionEnum.values();
// 2.打印每個(gè)枚舉對(duì)象類在枚舉類型中的名稱和索引位置
for (int i = 0; i < arr.length; i++){
System.out.println("獲取到的枚舉對(duì)象名稱時(shí):" + arr[i].toString());
System.out.println("獲取到的枚舉對(duì)象對(duì)應(yīng)的碎銀位置是:" + arr[i].ordinal()); // 和數(shù)組一樣下標(biāo)重0開始
}
System.out.println("-----------------------------------------------------------------");
// 3.根據(jù)參數(shù)指定的字符串得到枚舉類型的對(duì)象食店,也就是將字符串轉(zhuǎn)換為對(duì)象
// DirectionEnum de = DirectionEnum.valueOf("向下"); // 編譯ok渣淤,運(yùn)行發(fā)生IllegalArgumentException非法參數(shù)異常
DirectionEnum de = DirectionEnum.valueOf("DOWN");
// DirectionEnum de = DirectionEnum.valueOf("UP LEFT"); // 要求字符串名稱必須在枚舉對(duì)象中存在
// System.out.println("轉(zhuǎn)換出來的枚舉對(duì)象名稱時(shí):" + de.toString());
System.out.println("轉(zhuǎn)換出來的枚舉對(duì)象名稱時(shí):" + de); // 當(dāng)打印引用變量時(shí),會(huì)自動(dòng)調(diào)用toString方法
// 4.使用獲取到的枚舉對(duì)象與枚舉類中已有的對(duì)象比較先后順序
System.out.println("-----------------------------------------------------------------");
for (int i = 0; i < arr.length; i++){
// 當(dāng)調(diào)用對(duì)象在參數(shù)對(duì)象之后時(shí)吉嫩,獲取到的比較結(jié)果為 正數(shù)
// 當(dāng)調(diào)用對(duì)象在參數(shù)對(duì)象相同位置是价认,則獲取到的比較結(jié)果為 零
// 當(dāng)調(diào)用對(duì)象在參數(shù)對(duì)象之前時(shí),則獲取到的比較結(jié)果為 負(fù)數(shù)
System.out.println("調(diào)用對(duì)象與數(shù)組中對(duì)象比較先后順序結(jié)果是:" + de.compareTo(arr[i]));
}
}
}
枚舉類實(shí)現(xiàn)接口的方式
- 枚舉類實(shí)現(xiàn)接口后需要重寫抽象方法率挣,而重寫方法的方式有兩種:重寫一個(gè)刻伊,或者每個(gè)對(duì)象都重寫。
注解的基本概念
- 注解(Annotation)又叫標(biāo)注椒功,是從Java5開始增加的一種引用數(shù)據(jù)類型捶箱。
- 注解本質(zhì)上就是代碼中的特殊標(biāo)記,通過這些標(biāo)記可以在編譯动漾、類加載丁屎、以及運(yùn)行時(shí)執(zhí)行指定的處理。
注解的語法格式
訪問修飾符 @interface 注解名稱 {
注解成員;
}
- 自定義注解自動(dòng)繼承 java.lang.annotion.Annotation接口旱眯。
- 通過@注解名稱的方式可以修飾包晨川、類、成員方法删豺、成員變量共虑、構(gòu)造方法、參數(shù)呀页、局部變量的聲明等妈拌。
注解的使用方式
- 注解體中只有成員變量沒有成員方法,而注解的成員變量以“無形參的方法”形式來聲明蓬蝶,其方法名定義了該成員變量的名字尘分,其返回值定義了該成員變量的類型猜惋。
- 如果注解只有一個(gè)參數(shù)成員,建議使用參數(shù)名為value培愁,而類型只能是八中基本數(shù)據(jù)類型著摔、String類型、Class類型定续、enum類型及Annotation類型谍咆。
package com.lagou.task10;
// 若一個(gè)注解中沒有任何的成員,則這樣的注解叫做標(biāo)記注解/標(biāo)識(shí)注解
public @interface MyAnnotation {
// public Direction value(); // 聲明一個(gè)String 類型的成員變量香罐,名字為value 類型有要求
public String value() default "123"; // 聲明一個(gè)String 類型的成員變量卧波,名字為value
public String value2();
}
package com.lagou.task10;
// 表示將標(biāo)簽 MyAnnotation貼在Person類的的代碼中,使用注解時(shí)采用 成員參數(shù)名 = 成員參數(shù)值庇茫,……
//@MyAnnotation(value = "hello", value2 = "world")
@MyAnnotation(value2 = "world")
public class Person {
private String name;
private int age;
}
元注解的概念
- 元注解是可以注解到注解上的注解,或者說元注解是一種基本注解螃成,但是它能夠應(yīng)用到其他的注解上面旦签。
- 元注解主要有 @Retention、@Documented寸宏、@Target宁炫、@Inherited、@Repeatable氮凝。
- @Retention 注解的有效范圍羔巢,或者叫生命周期
- @Documented 描述這個(gè)注解是否在文檔注釋中體現(xiàn)
- @Target 目標(biāo)的意思,這個(gè)注解到底可以修飾那些內(nèi)容
- @Inherited 表示注解是否可以被繼承到所標(biāo)記的這個(gè)類的子類
- @Repeatable 是否可以重復(fù)罩阵。
元注解@Retention
- @Retention 應(yīng)用到一個(gè)注解上用于說明該注解的生命周期竿秆,取值如下:
- RetentionPolicy.SOURCE 注解只在源代碼階段保留,在編譯器進(jìn)行編譯時(shí)它將被丟棄忽視稿壁。
- RetentionPolicy.CLASS 注解只被保留到編譯進(jìn)行的時(shí)候幽钢,它并不會(huì)被加載到JVM中,默認(rèn)方式傅是。
- RetentionPolicy.RUNTIME 注解可以保留到程序運(yùn)行的時(shí)候匪燕,它會(huì)被加載進(jìn)入到JVM中,所以在程序運(yùn)行時(shí)可以獲取到它們喧笔。
package com.lagou.task10;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
//@Retention(RetentionPolicy.SOURCE) // 表示下面的注解在源代碼中有效
//@Retention(RetentionPolicy.CLASS) // 表示下面的注解在字節(jié)碼文件中有效帽驯,默認(rèn)方式
@Retention(RetentionPolicy.RUNTIME) // 表示下面的注解在運(yùn)行時(shí)有效
// 若一個(gè)注解中沒有任何的成員,則這樣的注解叫做標(biāo)記注解/標(biāo)識(shí)注解
public @interface MyAnnotation {
public String value() default "123"; // 聲明一個(gè)String 類型的成員變量书闸,名字為value
public String value2();
}
元注解@Documented
- 使用javadoc工具可以從程序源代碼中抽取類尼变、方法、成員等注釋形成一個(gè)和源代碼配套的API幫助文檔梗劫,而該工具抽取時(shí)默認(rèn)不包括注解內(nèi)容享甸。
- @Documented 用于指定被該注解將被javadoc工具提取成文檔截碴。
- 定義為 @Documented 的注解必須設(shè)置 Retention 值為RUNTIME。
package com.lagou.task10;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
//@Retention(RetentionPolicy.SOURCE) // 表示下面的注解在源代碼中有效
//@Retention(RetentionPolicy.CLASS) // 表示下面的注解在字節(jié)碼文件中有效蛉威,默認(rèn)方式
@Retention(RetentionPolicy.RUNTIME) // 表示下面的注解在運(yùn)行時(shí)有效
@Documented // 表示下面的注解可以被javadoc工具提取到API文檔中日丹,很少使用
// 若一個(gè)注解中沒有任何的成員,則這樣的注解叫做標(biāo)記注解/標(biāo)識(shí)注解
public @interface MyAnnotation {
// public Direction value(); // 聲明一個(gè)String 類型的成員變量蚯嫌,名字為value 類型有要求
public String value() default "123"; // 聲明一個(gè)String 類型的成員變量哲虾,名字為value
public String value2();
}
元注解@Target
- @Target用于指定被修飾的注解能用于哪些元素的修飾,取值如下:
// 表示下面的注解信息可以用于類型择示、構(gòu)造方法束凑、成員變量、成員方法 的修飾
@Target({/*ElementType.TYPE, */ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
元注解@Inherited
- @Inherited 并不是說注解本身可以繼承栅盲,而是說如果一個(gè)超類被該注解標(biāo)記過的注解進(jìn)行注解時(shí)汪诉,如果子類沒有被任何注解應(yīng)用時(shí),則子類就繼承超類的注解谈秫。
@Inherited // 表示下面的注解所修飾的類中的注解使用可以被子類繼承
元注解@Repeatable
- @Repeatable 表示自然可重復(fù)的含義扒寄,從java8開始增加的新特性。
- 從Java8開始對(duì)元注解 @Target 的參數(shù)類型 ElementType 枚舉值增加了兩個(gè):
- 其中 ElementType.TYPE_PARAMETER 表示該注解能寫在類型變量的聲明語句中拟烫,如:泛型该编。
- 其中 ElementType.TYPE_USE 表示該注解能寫在使用類型的任何語句中。
package com.lagou.task10;
import java.lang.annotation.Repeatable;
/**
* 自定義注解用于描述人物的角色
*/
@Repeatable(value = ManTypes.class)
public @interface ManType {
String value() default "";
}
package com.lagou.task10;
/**
* 自定義注解里面可以描述多種角色
*/
public @interface ManTypes {
ManType[] value();
}
package com.lagou.task10;
@ManType(value = "職工")
@ManType(value = "超人")
//@ManTypes({@ManType(value = "職工"), @ManType(value = "超人")}) // 在java8以前處理多個(gè)注解的方式
public class Man {
}
常見的預(yù)制注解
- 預(yù)制注解就是 java語言自身提供的注解硕淑,具體如下: