Java之有名內部類與匿名內部類

有名內部類

接口:

public interface Mammal {

	public abstract void move();
}

有名內部類:

public class Body {

	//有名內部類
	class Heart{
		public void work() {//有名內部類的方法
			System.out.println("正在跳動......");
		}
	}
	//靜態代碼塊,創建對象時執行
	{
		Heart heart = new Heart();
		heart.work();
		//在非靜態代碼塊中默認在new前有個 “this.”,故不用再加 “body.”
	}
	
	public static void main(String[] args) {
		Body body = new Body();//創建對象
		Heart heart = body.new Heart();//創建有名內部類對象,需要加 “主類的對象.”
		heart.work();//通過有名內部類對象調用其work方法
	}
}

結果:

正在跳動......
正在跳動......

匿名內部類

匿名內部類:必須和創建對象一起存在

創建方法:
 new 父類構造器([參數列表])|接口(){
   匿名內部類類體;
 }

注:匿名內部類創建的對象一定是普通類或抽象類的子類對象,或接口的實現類

接口:

public interface Mammal {

	public void move();
}

匿名接口內部類:

public class Body {
	
	//匿名內部類由於沒有名字,所以定義匿名內部類的同時要創建對象
	int age = 2;//就如同這一樣,必須把2賦值給一個變量,而不能單獨寫一個2
	static Mammal mammal = new Mammal() {//匿名內部類,Mammal接口的實現類,static是爲了能在下面主函數中直接調用這個內部類
		@Override
		public void move() {//重寫接口的抽象方法
			System.out.println("靠鰭遊動......");
		}
		
		public void eat() {//新定義的方法
			System.out.println("正在喫......");
		}
	};
	
	public static void main(String[] args) {
		mammal.move();//調用匿名內部類的move方法
		
		/*匿名內部類常用於重寫父類或者接口中的方法,當然也可以定義新的屬性和方法,但此方法上轉型對象無法調用
		例如:
		mammal.eat();不能這樣直接用上轉型對象mammal調用eat方法*/
		
		//可以通過下面方式來調用eat方法,但此時重寫的move方法就無效了,沒有必要這樣用
		new Mammal() {//匿名內部類
			@Override
			public void move() {
				System.out.println("靠鰭遊動......");
			}
			
			public void eat() {
				System.out.println("正在喫......");
			}
		}.eat();//直接調用eat方法
	}
}

結果:

靠鰭遊動......
正在喫......

匿名普通的內部類:

public class Test2 {

	//匿名內部類由於沒有名字,所以定義匿名內部類的同時要創建對象
	int age = 2;//就如同這一樣,必須把2賦值給一個變量,而不能單獨寫一個2
	Object object = new Object() {//以Object爲父類創建內部類
		public void move() {
			System.out.println("......");
		}
	};

	public static void main(String[] args) {
		//非上轉型對象可以調用子類新增的屬性和方法,但此時沒有必要這麼麻煩,且只能調用一個
		new Object() {
			public void move() {
				System.out.println("......");
			}
		}.move();
	}
}

匿名內部類對象:匿名內部類是普通類的子類;是接口的實現類
類體通常用於實現抽象方法或重寫父類方法,但也可以丁意思自己新增的屬性和變量
Object爲父類,new Object()爲子類,則object爲上轉型對象
匿名內部類中新增的屬性和方法,無法在上轉型對象中使用

內部類中使用外部變量

public class Test3 {

	public void test(){
		int age = 12;//局部變量
		class Printer{
			public void print(){
				System.out.println(age);//在內部類中使用了內部類外的變量
			}
		}//內部類
	}
}

內部類中可以直接使用外部變量(內部類必須在外部變量作用範圍內)
如果內部類中使用了局部變量,則JDK8以前的版本中必須在局部變量前加final修飾

特殊的匿名內部類:函數式接口

函數式接口:
僅有一個抽象方法的接口可以使用@FunctionalInterface註解修飾,這樣的接口稱之爲函數式接口。

接口:

@FunctionalInterface
public interface IComputer {//函數式接口

	int add(int a,int b);
}

由該接口創建內部類:

public class Test4 {

	public static void main(String[] args) {
		//按常規方法創建匿名內部類
		IComputer computer = new IComputer() {
			@Override
			public int add(int a,int b) {
				return a+b;
			}
		};
		
		//Lambda方法創建:主要用於簡化匿名內部類(JDK8以及以上)
		IComputer computer =(int a,int b)->{
			return a+b;
		};
		
		//也可以忽略不寫參數的數據類型
		IComputer computer =(a,b)->{
			return a+b;
		};
		
		
		//如果方法體僅僅是一行返回值,則大括號和return可省略(同時省略)
		IComputer computer =(a,b)-> a+b;
		
		//輸出結果
		int result = computer.add(1, 1);
		System.out.println(result);
	}
}

內部類的訪問權限

1、外部類或者外部接口的訪問權限必須是public或者默認的
2、內部類或者內部接口則四種訪問權限都可以
3、局部內部類不允許添加任何訪問控制符

public class Test {//外部類必須是public或者默認的

	//內部類訪問權限定義方法像成員變量一樣直接定義在內部類前
	private int age;
	private class Herat{
		
	}
	
	public static void main(String[] args) {
		//局部內部類的定義和局部變量一樣,都不允許添加訪問控制符
		int age;
		class Body{
			
		}
	}
}

內部類的class文件

普通類:

package venus;

public class Mammal {

}

內部類:

package venus;

public class Body {

	
	class A{//有名內部類
		
	}
	
	Mammal mammal = new Mammal() {//匿名內部類
		
	};
	
	Object object = new Object() {//匿名內部類
		
	};
	
	public static void main(String[] args) {
		
	}
	
}

則在eclipse-workspace\venus\bin文件夾中生成了class文件如下:
在這裏插入圖片描述
其中Mamma l.class和Body.class爲兩個類的class文件
Body$A.class爲Body類中有名內部類的class文件
Body$1.class和Body$2.class爲Body類中的匿名內部類的class文件

總結:
有名內部類編譯後生成“外部類 $ 內部類 . class”文件
匿名內部類編譯後生成“外部類 $ 數字 . class”文件

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章