【JAVA學習筆記】21 內部類

2018.4.22

內部類

成員內部類

人:
	成員變量:
		體重,性別,血液
	成員方法:
		睡覺,吃飯,跑步,敲代碼
	心臟:
		心跳行爲
		會使用到人體內的成員變量,血液。
		心室和心房

[特徵]

在人類中,有些東西,比如內臟用成員方法或者成員變量描述都閒着有點不太合適,因爲這些內臟是屬於[人類的一部分],而且會使用人體的一些屬性
	但是又擁有自己的一些【特徵】

[思考]

能不能把這些器官認爲是一個類,一個屬於人類內部的一個類

內部類:

1.成員內部類
	2.局部內部類
	3.匿名內部類

內部類和外部類關係:

1.成員內部類可以使用外部類的成員變量和成員方法,不管用什麼權限修飾public private,都可以使用	,因爲這是在內部類的內部使用。
		
		2.【在外部類的外部創建外部類的內部類對象】
			格式如下:
				外部類名.內部類名 內部類對象名 = new 外部類().new 內部類名();
			例如:
				Outer.inner inner = new Outer().new Inner();//第一個new是java虛擬機用的,第二個new是Outer用的
		【第一個知識點】:普通的成員變量和成員方法,在沒有對象的情況下,不能在類外使用
		
		3.如果內部類和外部類存在同名的成員變量,這裏默認是就近原則,使用的是內部類的成員變量,如果想要使用外部類的成員的:
		
		格式:
			外部類名.this.同名變量;
			外部類名.this.同名成員方法(參數列表);
			
		4.在外部類的類內方法中,可以創建內部類的對象。


class Outer {
		int num = 100;//外部類的成員變量
		
		private static int s = 10;
					
		
		public void test() {
			
			System.out.println("外部類的test方法");	
		
			}
		
		public void testOuter() {
			
			System.out.println("外部類的成員方法");
			}
		
		class Inner {//這是Outer類的一個成員內部類
			int i = 10;//成員內部類的成員變量
			int num = 50;
			
			public void testInner() {
				
				System.out.println("內部類的成員方法");
			
				
				//如何調用重名的成員變量。
				System.out.println("內部類成員變量:"+num);//請問打印的是50/100(就近原則)
				System.out.println("外部類成員變量:"+Outer.this.num);
				
				//如何調用重名的成員方法
				//調用自己內部類的成員方法
				test();
				//調用外部類的成員方法
				Outer.this.test();
				
				//內部類調用外部類靜態私有話成員變量
				System.out.println(s);
				
				//調用外部類的靜態成員方法
				testStatic();
			}
			
				public void test() {
					
					System.out.println("內部類的test方法");
				}
		}
	
	//new Inner().test();  內部類對象不能在外部類內直接調用方法。	
	
	//但是內部類對象可以在外部類的方法中創建,並且在方法中調用內部類方法	
		
	//在【外部類】中定義【內部類的類對象】,來完成外部類無法做到的事。
	public void createInnerClass() {
			//外部類的成員方中調用內部類的構造方法,通過new關鍵字來創建內部類類對象使用
		Inner inner = new Inner();
			
		inner.testInner();
			
		}
		
		public static void testStatic () {
			System.out.println("外部類的靜態成員方法");
		}
}
public class Demo1 {
	public static void main(String[] args) {
		Outer outer = new Outer();
	//outer.createInnerClass();
		
		//想要在這裏創一個Inner類對象
		//Entry<K,V> entrySet
		//Set<Map.Entry<K,V>>
		//數據類型是Outer.Inner 表示是外部類裏面的內部數據類型
		//沒有外部類的對象就不能調用成員方法,成員變量或者成員內部類。
		
		//如果創建成員內部類的類對象。
		Outer.Inner inner = new Outer().new Inner();
		//inner.testOuter();在類外內部類對象不能調用外部類方法
		//outer.testInner();在類外外部類對象不能調用內部類的成員方法
		
		inner.testInner();//在類外內部類對象可以直接調用內部類的方法。
		outer.testOuter();//在類外外部類對象可以直接調用外部類方法
		
		
	}
}

結果:
    內部類的成員方法
    內部類成員變量:50
    外部類成員變量:100
    內部類的test方法
    外部類的test方法
    10
    外部類的靜態成員方法
    外部類的成員方法

局部內部類

局部內部類:放在方法或者函數內的類,稱之爲局部內部類

【第二個知識點】
		1.局部變量
			【生存期】
				從聲明定義位置開始,到代碼塊結束
			【作用域】
				只能在當前代碼塊內部。
		2.類對象的
			【生存期】
				通過new關鍵字創建的時候開始,JVM垃圾回收機制調用時,銷燬該對象,結束。 					
			【作用域】
				哪個引用變量擁有這個對象首地址,哪裏就是他的作用域。
				
	說明:
		局部內部類只能函數或者方法中使用,方法或者函數外不能使用。
		
	發現:
		局部內部類中,貌似不能【修改】所在方法或者函數中的局部變量
		
	原因:以下內容可以理解。
	------------------------------------------------------------------
		局部內部類的對象是在函數或者方法的內部通過JVM藉助於New關鍵字,和局部內部類的狗方法,創建
		的一個類對象,並且該對象是由JVM的回收機制回收的。
		
		但是局部變量n是在testInner()方法中,而這個局部變量n的生存週期是和testInner()該方法的大括號有關,
		生存期和作用域都是在大括號以內。
		
		如果在testInnner的方法內部,MethodInner這個類是方法中的局部內部類,而創建的對象在使用testInner()方法中的局部變量時,
		因爲對象的銷燬時間不確定,但是一定是晚於局部變量的銷燬的,
		這裏隱含了一個類對象【延遲局部變量中生存週期】的,這個是不符合Java原理的。
		
		這就是爲什麼不能修改,因爲有可能在這個對象吧誒使用的時候,局部變量的內存空間已經被內存收回,
		換而言之這個局部變量不存在了!!
		
		爲了解決這個問題
		
		【解決方式】
			如果是在局部內部類中使用了蘇在函數或者方法的局部變量,該變量用final修飾
	---------------------------------------------------------------------
			
		要求
			【第三個知識點】
				如果是局部內部類要使用函數或者方法的局部變量,該變量用【final】修飾。

class Test {
	int num = 100;
	
	
	public void testInner() {
		//這裏是在方法中定義一個類,這個類只能在當前方法或者函數中使用。
		int n = 10;
		
				class MethodInner {
					int i = 10;//成員變量在類內任何地方都可以使用。
					
					public void function() {
						num = 20;
						//n = 20;
						System.out.println(i);
						System.out.println(num);
						System.out.println("局部內部類的成員方法");
					}
				}
				
		
		MethodInner inner = new MethodInner();
		inner.function();
	}
	
}


public class Demo2 {
	public static void main(String[] args) {
		
	//	for (int i = 0; i < 10; i++) {
	//		System.out.println(i);
	//	}
		//System.out.println(i);
		
		new Test().testInner();
	}
	
	
}

結果:
    10
    20
    局部內部類的成員方法

匿名內部類

【第四個知識點】
		類的本體
				在類聲明部分,大括號裏面的內容就是類的本體~~
			
				class Test {
					//成員變量
					//成員方法
				}
		匿名內部類就是沒有名字的類,但是有類的本體!!!!
			
		【第五個知識點】
			看到內部類要認識
			哦,這個就是內部類。

//抽象類,所有繼承抽象類的子類都必須實現抽象類的方法。


    abstract class Animal {
    	int age;
    	
    	public abstract void test();
    	abstract public void jump();
    }
    
    class CodingMonkey extends Animal {//會報錯 必須實現上面兩個方法。
    
    	//以下兩個方法是類的本體!!
    	
    	@Override
    	public void test() {
    		System.out.println("這是類本題中的一個成員方法");
    	}
    
    	@Override
    	public void jump() {
    		System.out.println("大吉大利,今晚吃雞。");
    	}
    	
    }
    interface A {
    	int i = 0;//默認缺省屬性 順豐 public static final
    	public void testA();//缺省abstract, 沒有方法體
    }
    
    public class Demo3 {
    public static void main(String[] args) {
    	CodingMonkey monkey = new CodingMonkey();
    	
    	Animal a = new CodingMonkey();//多態,父類的引用指向子類的對象。
    	
    	a.test();
    	monkey.test();
    	monkey.jump();
    	
    	//抽象類有沒有自己的類對象!? 不能
    	//原因:抽象類裏面有抽象方法, 抽象方法沒有方法體,假如有自己類對象調用抽象方法如何運行?所以悖論。
    	
    	
    	
    	
    	//創建了一個匿名內部類的對象賦值給了animal
    			/*
    			 Animal是一個抽象類,animal是抽象類的一個引用類型變量
    			 
    			 new Animal() {
    			 	發現這裏面的內容和繼承該抽象類的子類內容一致,都是抽象類,要求子類實現的方法
    			 	
    			 	這裏是類的本體
    			 	而這裏可以看做是一個類,但是這個類沒有名字
    			 	
    			 	
    			 	所以:這個就是【匿名內部類】
    			 	這裏創建了一個【匿名內部類】的對象,賦值給了Animal的引用數據類型 animal
    			 	
    			 	這裏隱含了一個【繼承】關係。
    			 };
    			 
    			 */
    			
    	 new Animal() {
    		@Override
    		public void test() {
    			System.out.println("這是匿名內部類裏面的test方法");
    		}
    		
    		@Override
    		public void jump() {
    		System.out.println("匿名內部類裏面的jump方法");
    		}
    	
    	}
    	
    	 .jump();
    	
    	
    	//匿名內部類的匿名對象直接調用方法,用於接口。
    	new A() {
    		//這裏是一個類【遵從】接口之後要求實現接口中的抽象方法,這裏也是一個【匿名內部類】,是類的本體。
    		@Override
    		public void testA() {
    		System.out.println("匿名內部類實現interface A中的testA()方法");
    		}
    		
    	}
    	
    	.testA();
    	//用於java android開發
    	
    	
    	Integer[] arr = {3,2,4,5,6,1};
    	
    	
    	//匿名內部類的匿名對象作爲方法的參數。
    	Arrays.sort(arr,new Comparator<Integer>() {
    
    		@Override
    		public int compare(Integer o1, Integer o2) {
    			
    			return o1 - o2;
    		}
    			
    	} );
    	
    	System.out.println(Arrays.toString(arr));
    	
    	
    }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章