java的內(nèi)部類和外部類用法講解
一、為何使用內(nèi)部類
- 內(nèi)部類提供了更好的封裝,只有外部類能訪問內(nèi)部類
- 內(nèi)部類可以獨立繼承一個接口,不受外部類是否繼承接口影響
- 內(nèi)部類中的屬性和方法即使是外部類也不能直接訪問,相反內(nèi)部類可以直接訪問外部類的屬性和方法,即使private
- 利于回調(diào)函數(shù)的編寫
一個內(nèi)部類的例子:
public class OuterClass {
private String outerName;
private int outerAge;
public class InnerClass{
private String innerName;
private int innerAge;
}
}
二、內(nèi)部類與外部類的聯(lián)系
2.1 內(nèi)部類是一個相對獨立的實體,與外部類不是is-a關(guān)系
內(nèi)部類是一個編譯時概念,編譯后外部類及其內(nèi)部類會生成兩個獨立的class文件: OuterClass.class和OuterClass$InnerClass.class,我用javac編譯器對上面的OuterClass進行編譯:
?D:\>javac OuterClass.class
編譯后的結(jié)果:

2.2 內(nèi)部類可以直接訪問外部類的元素,但是外部類不可以直接訪問內(nèi)部類的元素
public class OuterClass {
private String outerName;
private int outerAge;
public class InnerClass{
private int innerName;
InnerClass(){
//內(nèi)部類可以訪問外部類的元素
outerName="I am outer class";
outerAge=23;
}
public void display(){
System.out.println(outerName+" and my age is "+outerAge);
}
}
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
innerClass.display();
}
}
在上面例子中我們可以看到,內(nèi)部類可以直接訪問外部類屬性,盡管外部類屬性是用private修飾的。這是因為在創(chuàng)建外部類時,內(nèi)部類會自動捕獲一個外部類的引用,所以內(nèi)部類訪問外部類元素,實際上是通過他所持有外部類引用訪問的。在java中,我們可以通過OuterClass.this來獲得外部類的引用,請看下面例子:
public class OuterClass {
public void display(){
System.out.println("this is OuterClass...");
}
public class InnerClass{
//獲取外部類的引用
public OuterClass getOuterClass(){
return OuterClass.this;
}
public void innerDisplay(){
//內(nèi)部類也可以通過外部類的引用訪問外部元素
getOuterClass().display();
}
}
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
innerClass.innerDisplay();
}
}
2.3 外部類可以通過內(nèi)部類引用間接訪問內(nèi)部類元素
public class OuterClass {
public void display(){
//外部類訪問內(nèi)部類元素,需要通過內(nèi)部類引用訪問
InnerClass innerClass=new InnerClass();
innerClass.innerDisplay();
}
public class InnerClass{
public void innerDisplay(){
System.out.println("I am inner class");
}
}
public static void main(String[] args) {
OuterClass outerClass=new OuterClass();
outerClass.display();
}
}
三、創(chuàng)建內(nèi)部類
3.1 在外部類外面(或外部類main方法)創(chuàng)建內(nèi)部了對象
其實上面2.2例子中我們已經(jīng)看到了如何創(chuàng)建內(nèi)部類。如果要創(chuàng)建一個內(nèi)部類對象,必須利用outerClass.new來創(chuàng)建:
1 OuterClass outerClass = new OuterClass();
2 OuterClass.InnerClass innerClass = outerClass.new InnerClass();??
其實我們還可以一步到位: OuterClass.InnerClass innerClass=new OuterClass().new InnerClass();?
內(nèi)部類創(chuàng)建方法示例:
public static void main(String[] args) {
//先創(chuàng)建外部類對象,再創(chuàng)建內(nèi)部類對象
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass1 = outerClass.new InnerClass();
innerClass1.innerDisplay();
//一步到位創(chuàng)建
OuterClass.InnerClass innerClass2=new OuterClass().new InnerClass();
innerClass2.innerDisplay();
}
3.2 在外部類里面創(chuàng)建內(nèi)部類
正如2.3代碼中display()方法那樣,在外部類里面創(chuàng)建內(nèi)部類,就像創(chuàng)建普通對象一樣直接創(chuàng)建:
InnerClass innerClass=new InnerClass()
四、內(nèi)部類的種類:
在Java中內(nèi)部類主要分為成員內(nèi)部類、方法內(nèi)部類、匿名內(nèi)部類、靜態(tài)內(nèi)部類。
4.1 成員內(nèi)部類
成員內(nèi)部類也是最普通的內(nèi)部類,它是外部類的一個成員,所以他是可以無限制的訪問外圍類的所有成員屬性和方法,盡管是private的,但是外圍類要訪問內(nèi)部類的成員屬性和方法則需要通過內(nèi)部類實例來訪問。
在成員內(nèi)部類中要注意兩點:
- 成員內(nèi)部類中不能存在任何static的變量和方法
- 成員內(nèi)部類是依附于外圍類的,所以只有先創(chuàng)建了外圍類才能夠創(chuàng)建內(nèi)部類
4.2 方法內(nèi)部類
方法內(nèi)部類定義在外部類的方法中,局部內(nèi)部類和成員內(nèi)部類基本一致,只是它們的作用域不同,方法內(nèi)部類只能在該方法中被使用,出了該方法就會失效。 對于這個類的使用主要是應用與解決比較復雜的問題,想創(chuàng)建一個類來輔助我們的解決方案,到那時又不希望這個類是公共可用的,所以就產(chǎn)生了局部內(nèi)部類。
4.3 匿名內(nèi)部類
匿名內(nèi)部類其實就是一個沒有名字的方法內(nèi)部類,所以它符合方法內(nèi)部類的所有約束,初次之外,還有一些地方需要注意:
- 匿名內(nèi)部類是沒有訪問修飾符的。
- 匿名內(nèi)部類必須繼承一個抽象類或者實現(xiàn)一個接口
- 匿名內(nèi)部類中不能存在任何靜態(tài)成員或方法
- 匿名內(nèi)部類是沒有構(gòu)造方法的,因為它沒有類名。
一般使用匿名內(nèi)部類的場景是,要繼承或?qū)崿F(xiàn)的接口只有一個抽象方法,比如添加一個監(jiān)聽器:
public class Button {
public void click(){
//匿名內(nèi)部類,實現(xiàn)的是ActionListener接口
new ActionListener(){
public void onAction(){
System.out.println("click action...");
}
}.onAction();
}
//匿名內(nèi)部類必須繼承或?qū)崿F(xiàn)一個已有的接口
public interface ActionListener{
public void onAction();
}
public static void main(String[] args) {
Button button=new Button();
button.click();
}
}
4.4 靜態(tài)內(nèi)部類
關(guān)鍵字static可以修飾成員變量、方法、代碼塊,其實它還可以修飾內(nèi)部類,使用static修飾的內(nèi)部類我們稱之為靜態(tài)內(nèi)部類。靜態(tài)內(nèi)部類與非靜態(tài)內(nèi)部類之間存在一個最大的區(qū)別,我們知道非靜態(tài)內(nèi)部類在編譯完成之后會隱含地保存著一個引用,該引用是指向創(chuàng)建它的外圍內(nèi),但是靜態(tài)內(nèi)部類卻沒有。沒有這個引用就意味著:
- 靜態(tài)內(nèi)部類的創(chuàng)建是不需要依賴于外圍類,可以直接創(chuàng)建
- 靜態(tài)內(nèi)部類不可以使用任何外圍類的非static成員變量和方法,而內(nèi)部類則都可以
public class OuterClass {
private static String outerName;
public int age;
static class InnerClass1{
/* 在靜態(tài)內(nèi)部類中可以存在靜態(tài)成員 */
public static String _innerName = "static variable";
public void display(){
/*
* 靜態(tài)內(nèi)部類只能訪問外部類的靜態(tài)成員變量和方法
* 不能訪問外部類的非靜態(tài)成員變量和方法
*/
System.out.println("OutClass name :" + outerName);
}
}
class InnerClass2{
/* 非靜態(tài)內(nèi)部類中不能存在靜態(tài)成員 */
public String _innerName = "no static variable";
/* 非靜態(tài)內(nèi)部類中可以調(diào)用外部類的任何成員,不管是靜態(tài)的還是非靜態(tài)的 */
public void display(){
System.out.println("OuterClass name:" + outerName);
System.out.println("OuterClass age:" + age);
}
}
public void display(){
/* 外部類能直接訪問靜態(tài)內(nèi)部類靜態(tài)元素 */
System.out.println(InnerClass1._innerName);
/* 靜態(tài)內(nèi)部類可以直接創(chuàng)建實例不需要依賴于外部類 */
new InnerClass1().display();
/* 非靜態(tài)內(nèi)部的創(chuàng)建需要依賴于外部類 */
OuterClass.InnerClass2 inner2 = new OuterClass().new InnerClass2();
/* 非靜態(tài)內(nèi)部類的成員需要使用非靜態(tài)內(nèi)部類的實例訪問 */
System.out.println(inner2._innerName);
inner2.display();
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.display();
}
}
到此這篇關(guān)于java的內(nèi)部類和外部類用法講解的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
寶塔面板配置及部署javaweb教程(全網(wǎng)最全)
這篇文章主要介紹了寶塔面板配置及部署javaweb教程(全網(wǎng)最全),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-06-06
MyBatis通用Mapper中的通用example(排序)詳解
這篇文章主要介紹了MyBatis通用Mapper中的通用example(排序)詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12
SpringBoot調(diào)用Poi-tl實現(xiàn)渲染數(shù)據(jù)并生成Word文檔
這篇文章主要為大家詳細介紹了SpringBoot如何調(diào)用Poi-tl實現(xiàn)渲染數(shù)據(jù)并生成Word文檔,文中的示例代碼講解詳細,有需要的小伙伴可以了解下2023-09-09
SpringBoot@Profile注解和Spring?EL(多環(huán)境注入)
為了方便, Spring還提供了 Profile機制, 使我們可以很方便地實現(xiàn)各個環(huán)境之間的切換,在使用DI來依賴注入的時候,能夠根據(jù)@profile標明的環(huán)境,將注入符合當前運行環(huán)境的相應的bean,本文通過示例代碼介紹SpringBoot@Profile注解和Spring?EL,需要的朋友可以參考下2024-02-02

