Java基本語(yǔ)法之內(nèi)部類(lèi)示例詳解
1.內(nèi)部類(lèi)概念及分類(lèi)
將一個(gè)類(lèi)定義在另一個(gè)類(lèi)的內(nèi)部或者接口內(nèi)部或者方法體內(nèi)部,這個(gè)類(lèi)就被稱為內(nèi)部類(lèi),我們不妨將內(nèi)部類(lèi)所在的類(lèi)稱為外圍類(lèi),除了定義在類(lèi),接口,方法中的內(nèi)部類(lèi),還有一種特殊的內(nèi)部類(lèi),那就是使用關(guān)鍵字new創(chuàng)建一個(gè)匿名類(lèi)的對(duì)象,而這個(gè)匿名類(lèi)其實(shí)就是一個(gè)內(nèi)部類(lèi),具體說(shuō)是一個(gè)匿名內(nèi)部類(lèi),經(jīng)常用于傳入構(gòu)造器實(shí)參構(gòu)造對(duì)象,例如PriorityQueue對(duì)象的創(chuàng)建。
一個(gè)類(lèi)定義在另一個(gè)類(lèi)的內(nèi)部或者接口內(nèi)部,并且沒(méi)有static修飾時(shí),這個(gè)內(nèi)部類(lèi)就稱為實(shí)例內(nèi)部類(lèi),使用static修飾時(shí),這個(gè)內(nèi)部類(lèi)被稱為靜態(tài)內(nèi)部類(lèi)(嵌套類(lèi)),將一個(gè)類(lèi)定義在代碼塊內(nèi)部,特別是方法體內(nèi)部,這個(gè)內(nèi)部類(lèi)被稱為本地內(nèi)部類(lèi)或者局部?jī)?nèi)部類(lèi),還有一種就是上面所說(shuō)的匿名內(nèi)部類(lèi)。
2.實(shí)例內(nèi)部類(lèi)
2.1實(shí)例內(nèi)部類(lèi)的創(chuàng)建
實(shí)例內(nèi)部類(lèi)的定義很簡(jiǎn)單,就直接定義在外圍類(lèi)的里面就可以了。問(wèn)題是如何創(chuàng)建一個(gè)內(nèi)部類(lèi)對(duì)象,首先,需要明白內(nèi)部類(lèi)與外圍類(lèi)中的成員變量與方法是平起平坐的,都是屬于外圍類(lèi)對(duì)象的(無(wú)static修飾),所以想要內(nèi)部類(lèi)對(duì)象先得有外圍類(lèi)對(duì)象,第一種創(chuàng)建內(nèi)部類(lèi)對(duì)象的方式就是使用一個(gè)方法返回一個(gè)內(nèi)部類(lèi)對(duì)象,并且這個(gè)內(nèi)部類(lèi)對(duì)象的類(lèi)型為OutClassName.InnerClassName,即外圍類(lèi)名.內(nèi)部類(lèi)名。
public class Outer {
class Inner1 {
private String str;
public Inner1(String s) {
this.str = s;
}
public String readStr() {
return this.str;
}
}
class Inner2 {
private int val;
public Inner2(int i) {
this.val = i;
}
public int readVal() {
return this.val;
}
}
//創(chuàng)建內(nèi)部類(lèi)
public Inner1 creatInner1(String s) {
return new Inner1(s);
}
public Inner2 creatInner2(int i) {
return new Inner2(i);
}
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner1 inner1 = outer.creatInner1("Inner1");
Outer.Inner2 inner2 = outer.creatInner2(2);
System.out.println(inner1.readStr());
System.out.println(inner2.readVal());
}
}
//output: Inner1 2 Process finished with exit code 0
2.2使用.this和.new
當(dāng)然,創(chuàng)建一個(gè)內(nèi)部類(lèi)還有其他的方法,就是使用外圍類(lèi)的對(duì)象.new來(lái)創(chuàng)建一個(gè)內(nèi)部類(lèi)對(duì)象,語(yǔ)法為:
外部類(lèi)對(duì)象.new 內(nèi)部類(lèi)構(gòu)造方法;
public class Outer {
class Inner1 {
private String str;
public Inner1(String s) {
this.str = s;
}
public String readStr() {
return this.str;
}
}
class Inner2 {
private int val;
public Inner2(int i) {
this.val = i;
}
public int readVal() {
return this.val;
}
}
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner1 inner1 = outer.new Inner1("Inner1");
Outer.Inner2 inner2 = outer.new Inner2(2);
System.out.println(inner1.readStr());
System.out.println(inner2.readVal());
}
}
//output: Inner1 2 Process finished with exit code 0
內(nèi)部類(lèi)的特性不止如此,內(nèi)部類(lèi)還能與外圍類(lèi)鏈接,首先實(shí)例內(nèi)部類(lèi)對(duì)象的創(chuàng)建是依賴外圍類(lèi)對(duì)象的引用,實(shí)例內(nèi)部類(lèi)與外圍類(lèi)的成員變量地位一樣,如果想要通過(guò)內(nèi)部類(lèi)對(duì)象訪問(wèn)外圍類(lèi)的成員變量與方法(特別是同名變量)。在內(nèi)部類(lèi)中,可以使用外圍類(lèi)名.this獲取外圍類(lèi)對(duì)象,然后使用獲得的這個(gè)外圍類(lèi)對(duì)象來(lái)使用外圍類(lèi)的變量與方法。
public class Outer {
private String outStr;
public Outer(String str) {
this.outStr = str;
}
public void printOuter() {
System.out.println(this.outStr);
}
class Inner {
private String str;
public Inner(String s) {
this.str = s;
}
public String readStr() {
return this.str;
}
//使用.this獲取父類(lèi)對(duì)象引用
public Outer outer() {
return Outer.this;
}
}
public static void main(String[] args) {
Outer outer = new Outer("outerString");
Outer.Inner inner = outer.new Inner("innerString");
Outer out = inner.outer();
out.printOuter();
}
}
//output: outerString Process finished with exit code 0
其實(shí)內(nèi)部類(lèi)對(duì)象中有兩個(gè)this,直接使用this.成員獲取的是內(nèi)部類(lèi)對(duì)象自己的成員,而像上面使用外圍類(lèi)名.this.成員獲取的是外圍類(lèi)的成員,也就是說(shuō)在內(nèi)部類(lèi)中this指向內(nèi)部類(lèi)對(duì)象自己的引用,外部類(lèi)名.this指向外圍類(lèi)對(duì)象的引用。
當(dāng)出現(xiàn)內(nèi)部類(lèi)與外圍類(lèi)變量名相同時(shí),這兩個(gè)this就有很大的用處了。
public class Outer {
public int a = 12;
public int b = 16;
public int c = 20;
class Inner{
public int a = 8;
public int c = 48;
public int d = 2;
public void printVal() {
System.out.println("外圍類(lèi)變量a=" + Outer.this.a);
System.out.println("外圍類(lèi)變量b=" + Outer.this.b);
System.out.println("外圍類(lèi)變量c=" + Outer.this.c);
System.out.println("內(nèi)部類(lèi)變量a=" + this.a);
System.out.println("內(nèi)部類(lèi)變量c=" + this.c);
System.out.println("內(nèi)部類(lèi)變量d=" + this.d);
}
}
public Inner creatInner() {
return new Inner();
}
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.creatInner();
inner.printVal();
}
}
//output: 外圍類(lèi)變量a=12 外圍類(lèi)變量b=16 外圍類(lèi)變量c=20 內(nèi)部類(lèi)變量a=8 內(nèi)部類(lèi)變量c=48 內(nèi)部類(lèi)變量d=2 Process finished with exit code 0
如果沒(méi)有出現(xiàn)同名,直接獲取的成員即可,可以不用使用上面所說(shuō)的this,出現(xiàn)同名,直接訪問(wèn)的成員默認(rèn)是內(nèi)部類(lèi)對(duì)象的。
2.3內(nèi)部類(lèi)實(shí)現(xiàn)迭代打印
內(nèi)部類(lèi)可以與外圍類(lèi)的所有元素的訪問(wèn)權(quán)限,所以我們可以嘗試使用內(nèi)部類(lèi)來(lái)遍歷輸出外圍類(lèi)中的元素,雖然內(nèi)部類(lèi)與外圍類(lèi)的成員地位是平等,但內(nèi)部類(lèi)畢竟也是類(lèi),它也可以像外圍類(lèi)一樣繼承類(lèi)和實(shí)現(xiàn)接口。
import java.util.Arrays;
interface Selector{
//判斷是否迭代完全部元素
public boolean end();
//獲取當(dāng)前元素
public Object current();
//迭代下一個(gè)元素
public void next();
}
public class SequeArray {
private Object[] items;
private int usedSize;
public SequeArray(int capacity) {
items = new Object[capacity];
}
public void add(Object val) {
if (usedSize == items.length) items = Arrays.copyOf(items, 2 * usedSize);
items[usedSize++] = val;
}
private class SequeSelector implements Selector{
private int index;
public boolean end() {
return index == usedSize;
}
public Object current() {
return items[index];
}
public void next() {
if (index < usedSize) index++;
}
}
public SequeSelector sequeSelector() {
return new SequeSelector();
}
public static void main(String[] args) {
SequeArray array = new SequeArray(10);
for (int i = 0; i < 10; i++) {
array.add(i+1);
}
//發(fā)生了向上轉(zhuǎn)型
Selector selector = array.sequeSelector();
while (!selector.end()) {
System.out.print(selector.current() + " ");
selector.next();
}
}
}
//output: 1 2 3 4 5 6 7 8 9 10 Process finished with exit code 0
2.4內(nèi)部類(lèi)的繼承
內(nèi)部類(lèi)的繼承有一點(diǎn)麻煩,因?yàn)閮?nèi)部類(lèi)的構(gòu)造器必須依賴外圍類(lèi)的引用,所以需要一段特殊的語(yǔ)法來(lái)說(shuō)明內(nèi)部類(lèi)與外圍類(lèi)的關(guān)聯(lián):
外圍類(lèi)引用.super();
具體怎么使用看如下一段代碼:
public class Outer {
class Inner{
}
}
class Person extends Outer.Inner {
private String str;
private int id;
public Person(Outer out, String str, int id) {
out.super();
this.str = str;
this.id = id;
}
public void readVal() {
System.out.println(this.str + this.id);
}
}
當(dāng)內(nèi)部類(lèi)被繼承的時(shí)候,需要通過(guò)外圍類(lèi)的引用傳入父類(lèi)的構(gòu)造方法中并調(diào)用super()才能通過(guò)編譯。
如果內(nèi)部類(lèi)繼承外部類(lèi),直接繼承即可,不需要這么麻煩。
程序生成一個(gè)java文件的字節(jié)碼文件時(shí),命名為公共外部類(lèi)$內(nèi)部類(lèi)。
內(nèi)部類(lèi)可以無(wú)限嵌套,一般沒(méi)人這么干。
3.靜態(tài)內(nèi)部類(lèi)
靜態(tài)內(nèi)部類(lèi)也稱嵌套類(lèi),它就是在實(shí)例內(nèi)部類(lèi)的定義前加入一個(gè)static關(guān)鍵字,像下面這樣:
public class Outer {
static class Inner{
}
}
與實(shí)例內(nèi)部類(lèi)的區(qū)別是靜態(tài)內(nèi)部類(lèi)是屬于類(lèi)的而不是屬于對(duì)象的,因此靜態(tài)內(nèi)部類(lèi)的創(chuàng)建不依賴與外部類(lèi)對(duì)象,這是和實(shí)例內(nèi)部類(lèi)最大的區(qū)別之一。
public class Outer {
static class Inner{
private String str;
public Inner(String s) {
str = s;
}
}
public static void main(String[] args) {
Outer.Inner inner = new Outer.Inner("我是靜態(tài)內(nèi)部類(lèi)!");
System.out.println(inner.str);
}
}
//output: 我是靜態(tài)內(nèi)部類(lèi)! Process finished with exit code 0
4.匿名內(nèi)部類(lèi)
匿名內(nèi)部類(lèi)的用法我們已經(jīng)見(jiàn)過(guò)了,就是創(chuàng)建PriorityQueue對(duì)象時(shí),默認(rèn)創(chuàng)建的是小堆,需要傳入比較器來(lái)創(chuàng)建大堆。
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
像上面這種在方法中使用new關(guān)鍵字創(chuàng)建一個(gè)匿名類(lèi)的對(duì)象作為實(shí)參,里面這個(gè)匿名類(lèi)就是匿名內(nèi)部類(lèi),創(chuàng)建過(guò)程中的Comparator匿名類(lèi)對(duì)象是繼承所需傳參類(lèi)型的,在這里也就是Comparator類(lèi)。
如果使用自定義類(lèi)型傳入優(yōu)先隊(duì)列,是一定要實(shí)現(xiàn)比較器的,實(shí)現(xiàn)比較器最常見(jiàn)的方式就是匿名內(nèi)部類(lèi)與Lambda表達(dá)式。
假設(shè)我有一個(gè)Person類(lèi)數(shù)組,需要對(duì)他們的name排序,如果不使用內(nèi)部類(lèi),就需要在Person類(lèi)中實(shí)現(xiàn)比較器。
import java.util.Arrays;
import java.util.Comparator;
class Preson {
public String name;
public Integer id;
public Preson(String name, Integer id) {
this.name = name;
this.id = id;
}
@Override
public String toString() {
return "Preson{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
}
class PersonComparator implements Comparator<Preson> {
@Override
public int compare(Preson o1, Preson o2) {
return o1.name.compareTo(o2.name);
}
}
public class Main {
public static void main(String[] args) {
Preson preson1 = new Preson("aboluo", 24);
Preson preson2 = new Preson("zhousi", 25);
Preson preson3 = new Preson("syyfjy", 2);
Preson[] presons = {preson1, preson2, preson3};
Arrays.parallelSort(presons, new PersonComparator());
System.out.println(Arrays.toString(presons));
}
}
//output:
[Preson{name='aboluo', id=24}, Preson{name='syyfjy', id=2}, Preson{name='zhousi', id=25}]
Process finished with exit code 0
使用內(nèi)部類(lèi)上述代碼就變?yōu)椋?/p>
import java.util.Arrays;
import java.util.Comparator;
class Preson {
public String name;
public Integer id;
public Preson(String name, Integer id) {
this.name = name;
this.id = id;
}
@Override
public String toString() {
return "Preson{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
}
public class Main {
public static void main(String[] args) {
Preson preson1 = new Preson("aboluo", 24);
Preson preson2 = new Preson("zhousi", 25);
Preson preson3 = new Preson("syyfjy", 2);
Preson[] presons = {preson1, preson2, preson3};
Arrays.parallelSort(presons, new Comparator<Preson>() {
@Override
public int compare(Preson o1, Preson o2) {
return o1.name.compareTo(o2.name);
}
});
System.out.println(Arrays.toString(presons));
}
}
//output:
[Preson{name='aboluo', id=24}, Preson{name='syyfjy', id=2}, Preson{name='zhousi', id=25}]
Process finished with exit code 0
還有一個(gè)本地內(nèi)部類(lèi),就是類(lèi)定義在方法中,就不多說(shuō)了,基本上不用,用法如下:
public class Outer {
public void func() {
class Inner{
//
}
}
}
以上就是Java基本語(yǔ)法之內(nèi)部類(lèi)示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Java內(nèi)部類(lèi)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java9中對(duì)集合類(lèi)擴(kuò)展的of方法解析
這篇文章主要介紹了Java9 中對(duì)集合類(lèi)擴(kuò)展的of方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
SpringBoot打印POST請(qǐng)求原始入?yún)ody體方式
這篇文章主要介紹了SpringBoot打印POST請(qǐng)求原始入?yún)ody體方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
詳解SpringBoot之訪問(wèn)靜態(tài)資源(webapp...)
這篇文章主要介紹了詳解SpringBoot之訪問(wèn)靜態(tài)資源(webapp...),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
java中Spring Security的實(shí)例詳解
這篇文章主要介紹了java中Spring Security的實(shí)例詳解的相關(guān)資料,spring security是一個(gè)多方面的安全認(rèn)證框架,提供了基于JavaEE規(guī)范的完整的安全認(rèn)證解決方案,需要的朋友可以參考下2017-09-09
Java CAS基本實(shí)現(xiàn)原理代碼實(shí)例解析
這篇文章主要介紹了Java CAS基本實(shí)現(xiàn)原理代碼實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07
Java并發(fā)編程——volatile關(guān)鍵字
這篇文章主要介紹了Java并發(fā)編程——volatile關(guān)鍵字的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)Java并發(fā)編程,感興趣的朋友可以了解下2020-10-10
jmeter壓力測(cè)試工具簡(jiǎn)介_(kāi)動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了jmeter壓力測(cè)試工具相關(guān)介紹資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
詳解利用Spring的AbstractRoutingDataSource解決多數(shù)據(jù)源的問(wèn)題
本篇文章主要介紹了詳解利用Spring的AbstractRoutingDataSource解決多數(shù)據(jù)源的問(wèn)題。具有一定的參考價(jià)值,有興趣的可以了解一下。2017-03-03

