第一 成員内部類
定義在另一個類的内部,而且與成員方法和屬性平級叫成員内部類。
1成員内部類中不能存在static關鍵字,即,不能聲明靜态屬性、靜态方法、靜态代碼塊等。
2在成員内部類中通路外部類的成員方法和屬性,要使用“外部類名.this.成員方法”和“外部類名.this.成員屬性”的形式
3建立成員内部類的執行個體使用“外部類名.内部類名 執行個體名 = 外部類執行個體名.new 内部類構造方法(參數)”的形式。在建立内部類執行個體之前需要先建立外部類的執行個體對象。
Java代碼
package test5;
public class MyTest {
public static void main(String[] args) {
Outer outer=new Outer("test");
Outer.Inner inner = outer.new Inner(20);
}
}
class Outer{
Outer(String str){
}
protected class Inner{
public Inner(int a){
}
}
}
4成員内部類可以可以使用public,protected,default,private,static,final,abstract來修飾.當然了,被static修飾的内部類,是靜态内部類。
5内部類在編譯之後生成一個單獨的class檔案,裡面包含該類的定義,是以内部類中定義的方法和變量可以跟父類的方法和變量相同。例如上面定義的三個類的class檔案分别是:MyTest.class、Outer.class和Outer$Inner.class三個檔案。内部類的定義檔案名形式是“外部類定義名$内部類定義名”,即Outer$Inner.class。該檔案反編譯之後的代碼是:
Java代碼
package test5;
public class Outer$Inner
{
public Outer$Inner(Outer paramOuter, int a)
{
}
}
6外部類無法直接通路成員内部類的方法和屬性,隻能通過“内部類執行個體名.方法名(參數)”和“内部類執行個體名.屬性名”的形式通路内部類的方法和屬性
Java代碼
package test5;
public class MyTest {
public static void main(String[] args) {
Outer outer=new Outer("test");
outer.test();
}
}
class Outer{
private Inner inner;
Outer(String str){
//建立内部類執行個體
inner = new Inner(10);
}
public void test(){
//隻能通過執行個體通路方法和屬性
inner.print();
}
protected class Inner{
public Inner(int a){
}
public void print(){
System.out.println("Inner");
}
}
}
7與外部類平級的類繼承内部類時,其構造方法中需要傳入父類的執行個體對象。且在構造方法的第一句調用“外部類執行個體名.super(内部類參數)”。
如:
Java代碼
package test5;
public class MyTest {
public static void main(String[] args) {
Outer outer = new Outer("test");
new Extender(outer,10);
}
}
class Outer{
Outer(String str){}
protected class Inner{
public Inner(int a){
}
}
}
class Extender extends Outer.Inner{
public Extender(Outer outer,int a){
//外部類執行個體名.super(内部類參數清單)
outer.super(a);
}
}
第二 靜态内部類
使用static修飾的成員内部類叫靜态内部類。
1靜态内部類更外部類沒有任何關系,隻是在生成類名和類定義時有影響。靜态内部類可以看做是與外部類平級的類。使用方式與外部類平級的類完全相同。
2靜态内部類不能通路外部類的非靜态的屬性和方法。外部類不能通路内部類的非靜态的屬性和方法。
3靜态内部類建立執行個體的形式:外部類名.内部類名 執行個體名 = new外部類名.内部類名(參數)
第三 局部内部類
定義在代碼塊、方法體内、作用域(使用花括号“{}”括起來的一段代碼)内的類叫局部内部類。
1局部内部類隻能在代碼代碼塊、方法體内和作用域中使用(建立對象和使用類對象).
如:
Java代碼
package test5;
public class MyTest {
public static void main(String[] args) {
}
}
class Outer{
Outer(String str){}
{
class Inner{
public Inner(int a){
}
}
System.out.println("Inner.class.getName()=="+Inner.class.getName());
}
public void test(){
//這是錯誤的,局部内部類隻在本作用域中可見
//System.out.println("Inner.class.getName()=="+Inner.class.getName());
}
}
2局部内部類通路外部類的屬性和方法使用“外部類名.this.屬性名”和“外部類名.this.方法名(參數)”的形式
3局部内部類通路作用域内的局部變量,該局部變量需要使用final修飾。
4局部内部類的定義可以使用abstract修飾,聲明為抽象類。
第四 匿名内部類
1匿名内部類定義和執行個體化形式如下:
new父類構造方法(參數){
//注:該方法名必須在父類中已經存在
修飾符 傳回參數類型 方法名(參數清單){
}
}
2匿名内部類隻能和new連用,用于建立一個執行個體。匿名内部類隻能使用一次,建立執行個體之後,類定義會立即消失(想要多次使用就要用到反射的知識了)。
3匿名内部類必須繼承一個類(抽象的、非抽象的都可以)或者實作一個接口。如果父類(或者父接口)是抽象類,則匿名内部類必須實作其所有抽象方法。
如:
Java代碼
public class InnerClassTest {
public static void main(String[] args) {
//定義一個匿名内部類,并執行個體化對象
Test test = new Test(){
@Override
public void print() {
System.out.println("匿名内部類實作父類所有的抽象方法!");
}
};
test.print();
System.out.println("匿名内部類的類名:test.getClass().getName()=="+test.getClass().getName());
System.out.println("父類的類名:Test.class.getName()=="+Test.class.getName());
System.out.println("test.getClass().equals(Test.class)=="+test.getClass().equals(Test.class));
System.out.println("test.getClass().getSuperclass().equals(Test.class)=="+test.getClass().getSuperclass().equals(Test.class));
}
}
abstract class Test{
public abstract void print();
}
運作結果:
Java代碼
匿名内部類實作父類所有的抽象方法!
匿名内部類的類名:test.getClass().getName()==test5.InnerClassTest$1
父類的類名:Test.class.getName()==test5.Test
test.getClass().equals(Test.class)==false
test.getClass().getSuperclass().equals(Test.class)==true
InnerClassTest$1.class檔案反編譯之後的結果如下,證明它确實是繼承了父類:
Java代碼
class InnerClassTest$1 extends Test
{
public void print()
{
System.out.println("匿名内部類實作父類所有的抽象方法!");
}
}
4匿名内部類不能是抽象類,因為匿名内部類在定義之後,會立即建立一個執行個體。
5匿名内部類不能定義構造方法,匿名内部類沒有類名,無法定義構造方法,但是,匿名内部類擁有與父類相同的所有構造方法。
6匿名内部類中可以定義代碼塊,用于執行個體的初始化,但是不能定義靜态代碼塊。
如下:
Java代碼
public class InnerClassTest {
public static void main(String[] args) {
//定義一個匿名内部類,并執行個體化對象
Test test = new Test(){
{
System.out.println("匿名内部類的代碼塊");
}
public void print(){
System.out.println("匿名内部類的print方法");
}
};
test.print();
}
}
class Test{
public void print(){
System.out.println("class Test的print方法");
}
}
輸出結果為:
Java代碼
匿名内部類的代碼塊
匿名内部類的print方法
7匿名内部類中可以定義新的方法和屬性(不能使用static修飾),但是無法顯式的通過“執行個體名.方法名(參數)”的形式調用,因為使用new建立的是“上轉型對象”。
注:
上轉型對象特點:
<!--[if !supportLists]-->① <!--[endif]-->父類聲明指向子類對象,形式:
父類名(父接口名) 上轉型執行個體名 = new 子類構造方法(參數);
<!--[if !supportLists]-->② <!--[endif]-->子類可以重寫父類的方法,上轉型執行個體調用的方法隻能是子類重寫父類的方法或者父類的方法,不能調用子類獨有的方法。
<!--[if !supportLists]-->③ <!--[endif]-->上轉型對象可以強制轉換成子類對象:形式:子類名 執行個體名 = (子類名)上轉型對象;
轉換成子類對象之後,與“new 子類構造方法(參數)”形式定義的對象無差別。
雖然不能通過“執行個體名.方法名(參數)”的形式調用子類獨有的方法,但是可以通過反射來調用:
Java代碼
package test5;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class InnerClassTest {
public static void main(String[] args)
throws SecurityException, NoSuchMethodException,
IllegalArgumentException, IllegalAccessException,
InvocationTargetException {
//定義一個匿名内部類,并執行個體化對象
Test test = new Test(){
//匿名内部類中可以定義屬性
private int a;
//匿名内部類中可以定義方法
public void xxx() {
System.out.println("xxx方法");
}
//匿名内部類中可以重寫父類的方法
public void print() {
a = 10;
}
};
//通過反射調用子類方法
Class c = test.getClass();
Method m = c.getMethod("xxx");
m.invoke(test);
}
}
class Test{
public void print(){
System.out.println("父類方法");
}
}
8匿名内部類通路外部類的局部變量,則該局部變量需要使用final聲明。匿名内部類中通路外部類的成員方法和屬性使用“外部類名.this.方法名(參數)”和“内部類名.this.屬性名”的形式。
Java代碼
package test5;
public class InnerClassTest {
private int a;
public static void main(String[] args) {
new InnerClassTest().go();
}
public void go(){
a = 100;
//外部類的局部變量
final int b=10;
Test test = new Test(){
public void print() {
//匿名内部類通路外部類的屬性
System.out.println("InnerClassTest.this.a=="+InnerClassTest.this.a);
//匿名内部類中通路外部類的局部變量
System.out.println("b=="+b);
}
};
test.print();
}
}
abstract class Test{
public abstract void print();
}
9匿名内部類不能重寫父類的靜态方法。