天天看點

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修飾

特殊的匿名内部類:函數式接口以及Lambda表達式

函數式接口:

僅有一個抽象方法的接口可以使用@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檔案如下:

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

其中Mamma l.class和Body.class為兩個類的class檔案

Body$A.class為Body類中有名内部類的class檔案

Body$1.class和Body$2.class為Body類中的匿名内部類的class檔案

總結:

有名内部類編譯後生成“外部類 $ 内部類 . class”檔案

匿名内部類編譯後生成“外部類 $ 數字 . class”檔案