Java基本語法之內(nèi)部類示例詳解
1.內(nèi)部類概念及分類
將一個類定義在另一個類的內(nèi)部或者接口內(nèi)部或者方法體內(nèi)部,這個類就被稱為內(nèi)部類,我們不妨將內(nèi)部類所在的類稱為外圍類,除了定義在類,接口,方法中的內(nèi)部類,還有一種特殊的內(nèi)部類,那就是使用關鍵字new創(chuàng)建一個匿名類的對象,而這個匿名類其實就是一個內(nèi)部類,具體說是一個匿名內(nèi)部類,經(jīng)常用于傳入構(gòu)造器實參構(gòu)造對象,例如PriorityQueue對象的創(chuàng)建。
一個類定義在另一個類的內(nèi)部或者接口內(nèi)部,并且沒有static修飾時,這個內(nèi)部類就稱為實例內(nèi)部類,使用static修飾時,這個內(nèi)部類被稱為靜態(tài)內(nèi)部類(嵌套類),將一個類定義在代碼塊內(nèi)部,特別是方法體內(nèi)部,這個內(nèi)部類被稱為本地內(nèi)部類或者局部內(nèi)部類,還有一種就是上面所說的匿名內(nèi)部類。
2.實例內(nèi)部類
2.1實例內(nèi)部類的創(chuàng)建
實例內(nèi)部類的定義很簡單,就直接定義在外圍類的里面就可以了。問題是如何創(chuàng)建一個內(nèi)部類對象,首先,需要明白內(nèi)部類與外圍類中的成員變量與方法是平起平坐的,都是屬于外圍類對象的(無static修飾),所以想要內(nèi)部類對象先得有外圍類對象,第一種創(chuàng)建內(nèi)部類對象的方式就是使用一個方法返回一個內(nèi)部類對象,并且這個內(nèi)部類對象的類型為OutClassName.InnerClassName,即外圍類名.內(nè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)部類 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
當然,創(chuàng)建一個內(nèi)部類還有其他的方法,就是使用外圍類的對象.new來創(chuàng)建一個內(nèi)部類對象,語法為:
外部類對象.new 內(nè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)部類的特性不止如此,內(nèi)部類還能與外圍類鏈接,首先實例內(nèi)部類對象的創(chuàng)建是依賴外圍類對象的引用,實例內(nèi)部類與外圍類的成員變量地位一樣,如果想要通過內(nèi)部類對象訪問外圍類的成員變量與方法(特別是同名變量)。在內(nèi)部類中,可以使用外圍類名.this獲取外圍類對象,然后使用獲得的這個外圍類對象來使用外圍類的變量與方法。
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獲取父類對象引用 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
其實內(nèi)部類對象中有兩個this,直接使用this.成員獲取的是內(nèi)部類對象自己的成員,而像上面使用外圍類名.this.成員獲取的是外圍類的成員,也就是說在內(nèi)部類中this指向內(nèi)部類對象自己的引用,外部類名.this指向外圍類對象的引用。
當出現(xiàn)內(nèi)部類與外圍類變量名相同時,這兩個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("外圍類變量a=" + Outer.this.a); System.out.println("外圍類變量b=" + Outer.this.b); System.out.println("外圍類變量c=" + Outer.this.c); System.out.println("內(nèi)部類變量a=" + this.a); System.out.println("內(nèi)部類變量c=" + this.c); System.out.println("內(nè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: 外圍類變量a=12 外圍類變量b=16 外圍類變量c=20 內(nèi)部類變量a=8 內(nèi)部類變量c=48 內(nèi)部類變量d=2 Process finished with exit code 0
如果沒有出現(xiàn)同名,直接獲取的成員即可,可以不用使用上面所說的this,出現(xiàn)同名,直接訪問的成員默認是內(nèi)部類對象的。
2.3內(nèi)部類實現(xiàn)迭代打印
內(nèi)部類可以與外圍類的所有元素的訪問權(quán)限,所以我們可以嘗試使用內(nèi)部類來遍歷輸出外圍類中的元素,雖然內(nèi)部類與外圍類的成員地位是平等,但內(nèi)部類畢竟也是類,它也可以像外圍類一樣繼承類和實現(xiàn)接口。
import java.util.Arrays; interface Selector{ //判斷是否迭代完全部元素 public boolean end(); //獲取當前元素 public Object current(); //迭代下一個元素 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)部類的繼承
內(nèi)部類的繼承有一點麻煩,因為內(nèi)部類的構(gòu)造器必須依賴外圍類的引用,所以需要一段特殊的語法來說明內(nèi)部類與外圍類的關聯(lián):
外圍類引用.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); } }
當內(nèi)部類被繼承的時候,需要通過外圍類的引用傳入父類的構(gòu)造方法中并調(diào)用super()才能通過編譯。
如果內(nèi)部類繼承外部類,直接繼承即可,不需要這么麻煩。
程序生成一個java文件的字節(jié)碼文件時,命名為公共外部類$內(nèi)部類。
內(nèi)部類可以無限嵌套,一般沒人這么干。
3.靜態(tài)內(nèi)部類
靜態(tài)內(nèi)部類也稱嵌套類,它就是在實例內(nèi)部類的定義前加入一個static關鍵字,像下面這樣:
public class Outer { static class Inner{ } }
與實例內(nèi)部類的區(qū)別是靜態(tài)內(nèi)部類是屬于類的而不是屬于對象的,因此靜態(tài)內(nèi)部類的創(chuàng)建不依賴與外部類對象,這是和實例內(nè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)部類!"); System.out.println(inner.str); } }
//output: 我是靜態(tài)內(nèi)部類! Process finished with exit code 0
4.匿名內(nèi)部類
匿名內(nèi)部類的用法我們已經(jīng)見過了,就是創(chuàng)建PriorityQueue對象時,默認創(chuàng)建的是小堆,需要傳入比較器來創(chuàng)建大堆。
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1 - o2; } });
像上面這種在方法中使用new關鍵字創(chuàng)建一個匿名類的對象作為實參,里面這個匿名類就是匿名內(nèi)部類,創(chuàng)建過程中的Comparator匿名類對象是繼承所需傳參類型的,在這里也就是Comparator類。
如果使用自定義類型傳入優(yōu)先隊列,是一定要實現(xiàn)比較器的,實現(xiàn)比較器最常見的方式就是匿名內(nèi)部類與Lambda表達式。
假設我有一個Person類數(shù)組,需要對他們的name排序,如果不使用內(nèi)部類,就需要在Person類中實現(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)部類上述代碼就變?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
還有一個本地內(nèi)部類,就是類定義在方法中,就不多說了,基本上不用,用法如下:
public class Outer { public void func() { class Inner{ // } } }
以上就是Java基本語法之內(nèi)部類示例詳解的詳細內(nèi)容,更多關于Java內(nèi)部類的資料請關注腳本之家其它相關文章!
相關文章
SpringBoot打印POST請求原始入?yún)ody體方式
這篇文章主要介紹了SpringBoot打印POST請求原始入?yún)ody體方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09詳解SpringBoot之訪問靜態(tài)資源(webapp...)
這篇文章主要介紹了詳解SpringBoot之訪問靜態(tài)資源(webapp...),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-09-09jmeter壓力測試工具簡介_動力節(jié)點Java學院整理
這篇文章主要為大家詳細介紹了jmeter壓力測試工具相關介紹資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08詳解利用Spring的AbstractRoutingDataSource解決多數(shù)據(jù)源的問題
本篇文章主要介紹了詳解利用Spring的AbstractRoutingDataSource解決多數(shù)據(jù)源的問題。具有一定的參考價值,有興趣的可以了解一下。2017-03-03