##內部類##
###內部類
在一個類中存在的其他類,叫做內部類。
###內部類作用
-
內部類可以很好的實現隱藏,對同一個包中的其他類不可見。一般的非內部類,是不允許有 private 與protected權限的,但內部類可以。
-
內部類擁有外圍類的所有元素的訪問權限。
-
使一個類間接實現多重繼承。
-
當定義一個回調函數,使用匿名內部類會使代碼變得簡潔(匿名內部類應實現接口或是繼承一個基類)。
###內部類原理
內部類既可以訪問自身的數據域,也可以訪問創建它的外圍類對象的數據域。
原理是: -
內部類的對象有一個隱式的引用,它引用了實例化該內部對象的外圍類對象。對外圍類的引用在構造器中設置,編譯器修改了內部類的構造器,添加了外圍類引用參數。故可以訪問外圍類對象的所有屬性。
-
內部類是一種編譯器現象與虛擬機無關。
###內部類分類
局部內部類
-
定義在一個方法中的類,是局部內部類。不能用public或private聲明。作用域限定在聲明這個局部類的塊中。
-
局部內部類可訪問包含它的外部類,還可訪問這個塊中(局部類外)final屬性(即爲final的局部變量)。
匿名內部類
- 只創建一個類的對象,就不需要命名。匿名內部類無構造器,取而代之是將構造器參數傳遞給超類構造器;當匿名內部類實現接口的時候,無構造參數。
- 多用匿名內部類實現事件監聽器和其他回調。現推薦用lambda式。
靜態內部類
- 當使用內部類只是爲了把一個類隱藏在另外一個類的內部,並不需要內部類引用外圍類對象。可將內部類聲明爲static,以便取消產生的引用。
- 靜態內部類與常規內部類不同,靜態內部類可以有靜態域和方法。
###內部類間接多繼承用例
ClassA 基類
/**
* @author gao tianci
* @version $Id: ClassA.java, v 0.1 2017年7月23日 上午10:51:08 gao tianci Exp $
*/
public class ClassA {
public void printA(String ags)
{
System.out.println("[ClassA]--printA()--ags:"+ags);
}
}
ClassB 基類
/**
* @author gao tianci
* @version $Id: ClassB.java, v 0.1 2017年7月23日 上午10:51:25 gao tianci Exp $
*/
public class ClassB {
public void printB(String ags)
{
System.out.println("[ClassB]--printB()--ags:"+ags);
}
}
Printable 接口
/**
* @author gao tianci
* @version $Id: Printable.java, v 0.1 2017年7月23日 上午10:52:02 gao tianci Exp $
*/
public interface Printable {
public void print();
}
ClassInner 類(間接多繼承)
/**
* @author gao tianci
* @version $Id: ClassInner.java, v 0.1 2017年7月23日 上午10:55:02 gao tianci Exp $
*/
public class ClassInner implements Printable {
//外部類成員
private String outerName = "outerName";
private int outerAge;
public void pirntName() {
System.out.println("[ClassInner]--outerName:" + outerName);
}
public void printAge() {
System.out.println("[ClassInner]--outerAge:" + outerAge);
}
/**
* 繼承ClassA
* @author gao tianci
* @version $Id: ClassInner.java, v 0.1 2017年7月23日 下午5:09:44 gao tianci Exp $
*/
private class InnerClassA extends ClassA {
//內部類使用外部類的成員
private String innerAName = outerName;
//內部類使用外部類的成員
public void printInnerA() {
print();
pirntName();
printAge();
System.out.println("[outerName]:" + innerAName);
}
//內部類構造器
public InnerClassA() {
super();
}
}
/**
* 繼承ClassB,間接多繼承
* @author gao tianci
* @version $Id: ClassInner.java, v 0.1 2017年7月23日 下午5:09:48 gao tianci Exp $
*/
public class InnerClassB extends ClassB {
private String innerBName;
public InnerClassB() {
super();
}
//內部類構造器
public InnerClassB(String innerBName) {
super();
this.innerBName = innerBName;
}
public String getInnerBName() {
return innerBName;
}
public void setInnerBName(String innerBName) {
this.innerBName = innerBName;
}
}
/**
* 獲取內部類實例方法
* @return
*/
public InnerClassA getInnerClassA() {
return new InnerClassA();
}
/**
* 獲取內部類實例方法
* @return
*/
public InnerClassB getInnerClassB() {
return new InnerClassB();
}
/**
* @see com.ly.tainci.exercise.InnerClass.Printable#printable()
*/
@Override
public void print() {
System.out.println("[Printable]--print()");
}
public String getOuterName() {
return outerName;
}
public void setOuterName(String outerName) {
this.outerName = outerName;
}
public int getOuterAge() {
return outerAge;
}
public void setOuterAge(int outerAge) {
this.outerAge = outerAge;
}
/**
* 測試用例
*/
@Test
public void test() {
//內部類測試用例
InnerClassA innerClassA = this.getInnerClassA();
innerClassA.printInnerA();
}
}
TestCase 測試用例
/**
* @author gao tianci
* @version $Id: TestCase.java, v 0.1 2017年7月23日 上午10:51:34 gao tianci Exp $
*/
public class TestCase {
@Test
public void test() {
ClassInner classInner = new ClassInner();
classInner.setOuterName("outerName");
classInner.setOuterAge(20);
//繼承接口的方法
System.out.println("----繼承接口的方法----");
classInner.print();
//外部類自己的成員方法
System.out.println("----外部類成員方法----");
classInner.printAge();
classInner.pirntName();
//創建內部類,方法一通過外部類對象創建,內部類修飾符是private則只能在它的外部類範圍使用
InnerClassB innerClassB1 = classInner.new InnerClassB("innerBName1");
//創建內部類,方法二在外部類中提供一個獲取內部類實例的方法,這種方式常推薦
InnerClassB innerClassB2 = classInner.getInnerClassB();
//內部類繼承它的父類方法
System.out.println("----內部類繼承父類的方法----");
innerClassB1.printB(innerClassB1.getInnerBName());
innerClassB2.setInnerBName("innerClassB2");
innerClassB2.printB(innerClassB2.getInnerBName());
//內部類只能在它的內部獲取並使用它的外部類成員
//innerClassB1.print();//錯誤
}
}