Java內部類超詳細總結(含代碼示例)


什么是內部類

什么是內部類?
顧名思義,就是將一個類的定義放在另一個類的內部
概念很清楚,感覺很簡單,其實關鍵在於這個內部類放置的位置,可以是一個類的作用域范圍、一個方法的或是一個代碼塊的作用域范圍。
所以理解了概念只是第一步,掌握細節才能徹底搞定Java的內部類特性。
看例子,這是最普通的內部類:

public class Product1 {
	class Design{
		private String name = "P30 pro";
		public String showName() {
			return name;
		}
	}

	class Content{
		private int i;
		Content(int value){
			i = value;
		}
		int value() {return i;}
	}
	public void show(int value) {
		Content c = new Content(value);
		Design d = new Design();
		System.out.println(d.showName());
		System.out.println(c.value());
	}
	public static void main(String[] args) {
		Product1 p = new Product1();
		p.show(6000);
	}
}

說明:
上面這個示例展示了內部類最基礎的用法,就是將一個或多個類的定義放在了外圍內的內部。可以看到在show()方法中的使用和普通類一樣,沒有區別。

另外,在外圍類的非靜態方法之外的任意位置,不能通過直接new 內部類的方式創建內部類對象。會報編譯錯誤。
像這樣:
在這里插入圖片描述
還有這樣:
在這里插入圖片描述
如果想要在外圍類非靜態方法之外創建內部類對象。怎么辦呢?

正確的姿勢是這樣子:
在外圍類中增加兩個公共方法,返回內部類的引用。

	public Design design() {
		return new Design();
	}
	public Content content(int value) {
		return new Content(value);
	}

然后通過外部類對象調用方法的方式獲取內部類對象。

	public static void main(String[] args) {
		Product2 p = new Product2();
		p.show(6000);
		Product2.Content c1 = p.content(100);
		Product2.Design d1 = p.design();
	}

值得注意的是,外部類之外的其他類,也是不能直接訪問到該外部類的內部類對象的。
會報編譯錯誤。這也符合內部類的定義,就是為外圍類服務的嘛!

內部類的特性

1.可以鏈接到外部類

當生成一個內部類對象時,此對象與制造它的外圍對象之間就有了一種聯系,所以它能訪問外圍對象的所有成員,而不需要任何特殊的條件。

下面的例子是《Java編程思想》中的示例
首先定義一個Selector接口

public interface Selector {
	boolean end();
	Object current();
	void next();
}

然后定義一個Sequence類,其中定義有一個private的內部類。

public class Sequence {

	private Object[] items;
	private int next = 0;
	public Sequence(int size) {items = new Object[size];}
	public void add(Object x) {
		if(next < items.length) {
			items[next++] = x;
		}
	}
	private class SequenceSelector implements Selector{
		private int i = 0;
		public boolean end() {
			return i == items.length;
		}
		public Object current() {
			return items[i];
		}
		public void next() {
			if(i < items.length) {i++;}
		}
	}
	public Selector selector() {
		return new SequenceSelector();
	}
	public static void main(String[] args) {
		Sequence sequence = new Sequence(10);
		for(int i = 0; i < 10; i++) {
			sequence.add(Integer.toString(i));
		}
		Selector selector = sequence.selector();
		while(!selector.end()) {
			System.out.print(selector.current() + " ");
			selector.next();
		}
	}
}

說明:
可以看到SequenceSelector是一個內部類,其end()、current()和next()都用到了外圍類中private的items字段。

2.使用.this和.new

.this的用法
如果需要生成對外部類對象的引用,可以使用外部類的名字后面緊跟圓點和this。
如下所示:

public class DotThis {
	void name() {System.out.println("name");}
	public class Inner{
		public DotThis outer() {
			return DotThis.this;
		}
	}
	public Inner inner() {return new Inner();}
	public static void main(String[] args) {
		DotThis dt = new DotThis();
		DotThis.Inner inner = dt.inner();
		inner.outer().name();
	}
}

需要注意DotThis.this只是產生了正確的外部類引用。並沒有創建外部類對象。

.new的用法
可以通過該語法創建內部類對象,不過要注意的是要使用外部類的對象去創建。

public class DotNew {
	public class Inner{}
	public static void main(String[] args) {
		DotNew dn = new DotNew();
		DotNew.Inner dnInner = dn.new Inner();
	}
}

內部類分類

1、局部內部類

定義在一個方法中或是方法中某一作用域內的類。稱作局部內部類。

public class Product3 {
	public Section section(String inputName) {
		class ASection implements Section{
			private String name;
			private ASection(String name) {
				this.name = name;
			}
			@Override
			public String hello() {
				return name + " say hello";
			}
		}
		return new ASection(inputName);
	}
	public static void main(String[] args) {
		Product3 p = new Product3();
		Section section = p.section("aaaaa");
		System.out.println(section.hello());
	}
}

ASection是一個Section接口的實現,Section接口代碼如下:

public interface Section {
	String hello();
}

說明:

  • 該內部類在section()方法中,該方法之外不能訪問ASection類;
  • 方法內部類不允許使用訪問權限修飾符(public、private、protected);
  • 注意方法返回的是Section 的引用,即有向上轉型。

另外還可以將內部類的定義放在方法中某一語句塊中,如if語句塊中。

public class Product4 {

	public String check(boolean flag) {
		String checkId = null;
		if(flag) {
			class DetailCheck{
				private String id;
				private DetailCheck(String id) {
					this.id = id;
				}
				String getId() {
					return id;
				}
			}
			DetailCheck dc = new DetailCheck("1111");
			checkId = dc.getId();
		}
		return checkId;
	}
	public static void main(String[] args) {
		Product4 p = new Product4();
		System.out.println(p.check(true));
	}
}

說明:
DetailCheck內部類在if語句塊中,因此它的作用范圍也在if語句塊的范圍之內。超出該范圍是不可用的。比如這樣就會編譯報錯:
在這里插入圖片描述

2、匿名內部類

匿名內部類其實是一種特殊的方法內部類(局部內部類)。它特殊在於將內部類的定義和其對象創建結合在了一塊。沒有通過class關鍵字顯示聲明內部類名稱,故謂之“匿名”。
看代碼示例:

public class Product5 {
	public Section section() {
		return new Section() {
			private String name = "hayli";
			@Override
			public String hello() {
				// TODO Auto-generated method stub
				return name + " haha";
			}
		};
	}
	public static void main(String[] args) {
		Product5 p = new Product5();
		p.section();
	}
}

說明:
此處Section可以是接口,也可是基類。

3、嵌套類(靜態內部類)

使用static關鍵字修飾的內部類,叫做靜態內部類,也稱作嵌套類。
嵌套類和普通內部類之間最大的區別是:

  • 普通內部類對象隱式地保存了一個引用,指向創建它的外部類對象。而嵌套類創建對象,並不需要外部類對象。
  • 不能從嵌套類的對象中訪問非靜態的外部類對象。
  • 普通內部類不能有static數據和static字段,也不能包含嵌套類,但是嵌套類可以包含所有這些東西。
public class Product6 {
	private static int id = 100;
	private static class BSection implements Section{
		private String name = "bbbb";
		@Override
		public String hello() {
			return name + " hello";
		}
		// 只能訪問外部類的靜態數據或字段
		public int getId() {return id;}
		
		// 可以包含靜態數據或方法
		static int x = 200;
		public static void test1() {}
		
		// 可以再嵌套一層
		static class BInner{
			private String name;
			static void test1() {System.out.println("inner ===");}
		}
	}
	public static void main(String[] args) {
		Section section = new BSection();
		section.hello();
	}

總結

本篇介紹了什么是內部類、內部類最普通定義方法和Java內部類的幾種具體類型詳解。雖然工作中使用內部類的機會不會,但是了解這些最基礎的知識,真的在項目中遇到內部類的寫法,也能看懂是怎么回事了。

掃碼關注微信公眾號:二營長的筆記。回復“二營長”,可領取Java相關技術資料。
在這里插入圖片描述


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM