您好,登錄后才能下訂單哦!
這篇文章主要介紹“怎么使用Java內部類”,在日常操作中,相信很多人在怎么使用Java內部類問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么使用Java內部類”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
一、內部類如何創建
內部類,顧名思義就是類中類,將類定義在外圍類里面:
public class Animal { class Monkey{ private String name = "monkey"; public String getName() { return name; } } class Pig { private String color; Pig(String color) { this.color = color; } String getColor() { return color; } } public void getAnimal(String note) { Monkey monkey = new Monkey(); Pig pig = new Pig(note); System.out.println(pig.getColor()); } public static void main(String[] args) { Animal animal = new Animal(); animal.getAnimal("pink"); } } /* OUTPIT: pink */
因為Monkey和Pig兩個類是定義在 Animal 類中,因此使用起這兩個內部類跟使用普通類沒什么區別。下面這組代碼相信小伙伴也不陌生:
public class Animal { class Monkey{ } class Pig { } public Monkey getMonkey() { return new Monkey(); } public Pig getPig() { return new Pig(); } public static void main(String[] args) { Animal animal = new Animal(); Animal.Monkey monkey = animal.getMonkey(); Animal.Pig pig = animal.getPig(); } }
通過定義方法,來返回執行內部類的引用。不知道細心的小伙伴有沒有注意到內部類的引用有點奇怪:Animal.Monkey。這也是內部類的區別之一,如果要在外部類的非靜態方法之外獲取某個內部類的對象,需要「具體指明這個對象的類型」:OuterClassName.InnerClassName
二、內外相連
內部類存在于外部類里層,因此也具有一定特權:內部類可以訪問外圍對象的所有成員,不需要任何特殊條件,此外,內部類還擁有外部類的所有元素的訪問權。
public class OuterArray { private Integer[] ints; private int next = 0; public OuterArray(int size) { ints = new Integer[size]; } public void add(int x) { if (next < ints.length) { ints[next++] = x; } } class InnerArray { private int i = 0; public boolean end() { return i == ints.length; } public int current() { return ints[i]; } public void next() { if (i < ints.length) { i++; } } } public static void main(String[] args) { OuterArray outerArray = new OuterArray(10); for (int i = 0; i < 10; i++) { outerArray.add(i); } InnerArray innerArray = outerArray.new InnerArray(); while (!innerArray.end()) { System.out.print(innerArray.current()+" "); innerArray.next(); } } }
上組代碼中我們可以看到,InnerArray可以訪問到OuterArray中的每一個屬性,就像自己擁有它們一樣,這帶來了很大的方便。
三、new 和 this
這兩個關鍵字我們肯定都不陌生了,我們平時用到最多的肯定就是new一個對象出來。
public class OuterClass { class InnerClass { } public static void main(String[] args) { OuterClass outer = new OuterClass(); } }
當我們需要OuterClass對象的時候,我們順手就來了個new OuterClass(),但是如果我們需要的是InnerClass對象,那么又該如何處理呢?答案便是:
InnerClass inner = outer.new InnerClass();
可能覺得有點奇怪,為什么此處的new需要以OuterClass對象引用,這是因為內部類對象會暗暗地連接到創建它的外部類對象上,因此必須使用外部類的對象來創建內部類對象。如果你創建的是「嵌套類」(靜態內部類),那么它就不需要對外部類對象的引用。
this關鍵字是用來生成對外部類對象的引用,這樣產生的引用自動具有正確的類型:
public class OuterClass { class InnerClass { public OuterClass getOuterClass() { return OuterClass.this; } } public static void main(String[] args) { OuterClass outer = new OuterClass(); InnerClass inner = outer.new InnerClass(); OuterClass outerClass = inner.getOuterClass(); } }
四、局部內部類
我們上面看到的內部類都是定義在外部類中,這也是內部類的典型用處。但是,我們也可以在一個方法里面或者任意的作用域里面定義內部類。這種也被稱為局部內部類:
public class OuterClass { public Animal getPig(String color) { class Pig extends Animal { @Override public void getAnimal(String color) { super.getAnimal(color); } } return new Pig(); } public static void main(String[] args) { OuterClass outerClass = new OuterClass(); Animal pink = outerClass.getPig("pink"); } }
Pig類是getPig()方法的一部分,而不是OuterClass的一部分,所以在getPig()之外不能訪問Pig類。
五、匿名內部類
在了解什么是匿名內部類之前,我們先看一組代碼:
public class OuterClass { public Animal animal() { return new Animal(){ private String name = "monkey"; @Override public String toString() { return "animal{" + "name='" + name + '\'' + '}'; } }; } public static void main(String[] args) { OuterClass outerClass = new OuterClass(); System.out.println(outerClass.animal()); } } /* OUTPUT: animal{name='monkey'} */
animal()這個方法將返回值的生成與表示這個返回值的類定義結合在一起。而且這個類是匿名的,它沒有名字,正常形式應該是這樣的:
public class OuterClass { class Monkey extends Animal { private String name = "monkey"; @Override public String toString() { return "animal{" + "name='" + name + '\'' + '}'; } } public Animal animal() { return new Monkey(); } }
匿名類再訪工廠:
public interface Service { void method1(); } interface ServiceFactory{ Service getService(); } class Implementation1 implements Service { private Implementation1(){} @Override public void method1() { System.out.println("Implementation1.method1()"); } public static ServiceFactory factory = new ServiceFactory() { @Override public Service getService() { return new Implementation1(); } }; } class Factories{ public static void main(String[] args) { ServiceFactory factory = Implementation1.factory; Service service = factory.getService(); service.method1(); } }
通過內部類獲取外部類的實現,這樣子Implementation1的構造器都可以是private的,并且沒有任何必要去創建作為工廠的具體類,這樣所產生的語法也更具有實際意義,也可以運用在單例模式中。
六、嵌套類
如果不需要內部類對象與外圍類之間有聯系,就可以將內部類聲明為static,這通常稱為嵌套類。普通的內部類對象隱式地保存了一個引用,指向創建它的外圍類對象,然而,當內部類是static的時候,就意味著:
要創建嵌套類的對象,并不需要其外圍類的對象
不能從嵌套類的對象中訪問非靜態的外圍類對象
public class NestClass { static class InnerNestClass{ } public static InnerNestClass get() { return new InnerNestClass(); } public static void main(String[] args) { InnerNestClass innerNestClass = get(); } }
在main()方法中沒有任何NestClass對象是必須的,而是使用選取static成員的普通語法來調用方法。
接口內部類
正常情況下,不能在接口內部放置任何代碼,但嵌套類可以作為接口的一部分。你放到接口中的任何類都自動是public和static的。因為類是static的,只是將嵌套類置于接口的命名空間內,這并不違反接口的規則。你甚至可以在內部類中實現其外部類的接口:
public interface ClassInterface { void test(); class Test implements ClassInterface { @Override public void test() { System.out.println("接口中的嵌套類"); } public static void main(String[] args) { new Test().test(); } } }
如果你想要的創建某些公共代碼,使得它們可以被某個接口的所有不同實現所共用,那么使用接口內部的嵌套類會顯得很方便,盡管在 Java 8 之后可以使用 default 來默認實現接口方法。
七、繼承內部類
內部類作為一種類,被繼承當然也是被允許的。但是因為內部類的構造器必須連接到指向其外圍類對象的引用,所以在繼承內部類的時候,那個指向外圍類對象的引用必須被初始化,而在導出類中不再存在可連接的默認對象
可以看到,通過這樣繼承是會報錯的,解決方法便是:
class ExtendClass { class Inner{} } class WithInner extends ExtendClass.Inner { public WithInner(ExtendClass extendClass) { extendClass.super(); } }
因此我們需要記住,如果要繼承一個內部類的時候,必須在構造器內使用外部類.super(),這樣才能提供了必要的引用,然后程序才能編譯通過。
八、覆蓋內部類?
當子類繼承父類時,子類可以覆蓋父類的方法。那么問題來了,內部類能否被覆蓋?我們通過看一組代碼來找找答案:
public class Flower { class Bud{ public Bud(){ System.out.println("Flower.Bud"); } } public Flower(){ System.out.println("new Flower()"); new Bud(); test(); } public void test() { System.out.println("Flower.test()"); } } class Flower2 extends Flower{ class Bud{ public Bud(){ System.out.println("Flower2.Bud"); } } public void test() { System.out.println("Flower2.test()"); } public static void main(String[] args) { new Flower2(); } } /* OUTPUT new Flower() Flower.Bud Flower2.test() */
從這個例子中我們可以看到,當繼承了某個外圍類的時候,內部類并沒有發生什么特別神奇的變化,這兩個內部類是完全獨立的兩個實體,各自在自己的命名空間內。
九、為什么要使用內部類?
我們在回答這個問題之前先明白一件事情:
「每個內部類都能獨立地繼承一個(接口的)實現,所以無論外圍類是否已經繼承了某個(接口的)實現,對于內部類都沒有影響」
這句話很清楚的說明了內部類的能力,如果沒有內部類提供的、可以繼承多個具體的或抽象的類的能力,一些設計與編程問題就很難解決,從這個角度看,內部類使得多重繼承的解決方案變得完整。接口解決了部分問題,為內部類有效地實現了"多重繼承"。
到此,關于“怎么使用Java內部類”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。