還記得上大學那會,在編程課上總聽到老師說「累不累」,我也很納悶,什麼「累不累」,我上課也不累啊^_^!,後來看書原來講的是「內部類」這個概念,如今想一想也真搞笑。
在Java中,能夠將一個類定義在另外一個類裏面或者一個方法裏面,這樣的類稱爲內部類。html
內部類分爲四種:java
非靜態內部類 BattleScore 「戰鬥成績」
非靜態內部類能夠直接在一個類裏面定義 編程
好比:
戰鬥成績只有在一個英雄對象存在的時候纔有意義
因此實例化BattleScore 的時候,必須創建在一個存在的英雄的基礎上
語法: new 外部類().new 內部類()
做爲Hero的非靜態內部類,是能夠直接訪問外部類的private
實例屬性name的this
package charactor; public class Hero { private String name; // 姓名 float hp; // 血量 float armor; // 護甲 int moveSpeed; // 移動速度 // 非靜態內部類,只有一個外部類對象存在的時候,纔有意義 // 戰鬥成績只有在一個英雄對象存在的時候纔有意義 class BattleScore { int kill; int die; int assit; public void legendary() { if (kill >= 8) System.out.println(name + "超神!"); else System.out.println(name + "還沒有超神!"); } } public static void main(String[] args) { Hero garen = new Hero(); garen.name = "蓋倫"; // 實例化內部類 // BattleScore對象只有在一個英雄對象存在的時候纔有意義 // 因此其實例化必須創建在一個外部類對象的基礎之上 BattleScore score = garen.new BattleScore(); score.kill = 9; score.legendary(); } }
在一個類裏面聲明一個靜態內部類
好比敵方水晶,當敵方水晶沒有血的時候,己方全部英雄都取得勝利,而不僅是某一個具體的英雄取得勝利。
與非靜態內部類不一樣,靜態內部類
水晶類的實例化 不須要一個外部類的實例爲基礎,能夠直接實例化
語法:new 外部類.靜態內部類();
由於沒有一個外部類的實例,因此在靜態內部類裏面不能夠訪問外部類的實例屬性和方法
除了能夠訪問外部類的私有靜態成員外
,靜態內部類和普通類沒什麼大的區別。code
package charactor; public class Hero { public String name; protected float hp; private static void battleWin(){ System.out.println("battle win"); } //敵方的水晶 static class EnemyCrystal{ int hp=5000; //若是水晶的血量爲0,則宣佈勝利 public void checkIfVictory(){ if(hp==0){ Hero.battleWin(); //靜態內部類不能直接訪問外部類的對象屬性 System.out.println(name + " win this game"); } } } public static void main(String[] args) { //實例化靜態內部類 Hero.EnemyCrystal crystal = new Hero.EnemyCrystal(); crystal.checkIfVictory(); } }
匿名類指的是在聲明一個類的同時實例化它
,使代碼更加簡潔精練
一般狀況下,要使用一個接口或者抽象類,都必須建立一個子類 htm
有的時候,爲了快速使用,直接實例化一個抽象類,並「當場
」實現其抽象方法。
既然實現了抽象方法,那麼就是一個新的類,只是這個類,沒有命名。
這樣的類,叫作匿名類對象
package charactor; public abstract class Hero { String name; //姓名 float hp; //血量 float armor; //護甲 int moveSpeed; //移動速度 public abstract void attack(); public static void main(String[] args) { ADHero adh=new ADHero(); //經過打印adh,能夠看到adh這個對象屬於ADHero類 adh.attack(); System.out.println(adh); Hero h = new Hero(){ //當場實現attack方法 public void attack() { System.out.println("新的進攻手段"); } }; h.attack(); //經過打印h,能夠看到h這個對象屬於Hero$1這麼一個系統自動分配的類名 System.out.println(h); } }
本地類能夠理解爲有名字的匿名類
內部類與匿名類不同的是,內部類必須聲明在成員的位置,即與屬性和方法平等的位置。
本地類和匿名類同樣,直接聲明在代碼塊裏面,能夠是主方法,for循環裏等等地方blog
package charactor; public abstract class Hero { String name; //姓名 float hp; //血量 float armor; //護甲 int moveSpeed; //移動速度 public abstract void attack(); public static void main(String[] args) { //與匿名類的區別在於,本地類有了自定義的類名 class SomeHero extends Hero{ public void attack() { System.out.println( name+ " 新的進攻手段"); } } SomeHero h =new SomeHero(); h.name ="地卜師"; h.attack(); } }
在匿名類中使用外部的局部變量,外部的局部變量必須修飾爲final 教程
爲何要聲明爲final,其機制比較複雜,請參考第二個Hero代碼中的解釋 接口
注:在jdk8中,已經不須要強制修飾成final了,若是沒有寫final,不會報錯,由於編譯器偷偷的幫你加上了看不見的final
Hero.java
package charactor; public abstract class Hero { public abstract void attack(); public static void main(String[] args) { //在匿名類中使用外部的局部變量,外部的局部變量必須修飾爲final final int damage = 5; Hero h = new Hero(){ public void attack() { System.out.printf("新的進攻手段,形成%d點傷害",damage ); } }; } }
Hero.java
package charactor; public abstract class Hero { public abstract void attack(); public static void main(String[] args) { //在匿名類中使用外部的局部變量damage 必須修飾爲final int damage = 5; //這裏使用本地類AnonymousHero來模擬匿名類的隱藏屬性機制 //事實上的匿名類,會在匿名類裏聲明一個damage屬性,而且使用構造方法初始化該屬性的值 //在attack中使用的damage,真正使用的是這個內部damage,而非外部damage //假設外部屬性不須要聲明爲final //那麼在attack中修改damage的值,就會被暗示爲修改了外部變量damage的值 //可是他們倆是不一樣的變量,是不可能修改外部變量damage的 //因此爲了不產生誤導,外部的damage必須聲明爲final,"看上去"就不能修改了 class AnonymousHero extends Hero{ int damage; public AnonymousHero(int damage){ this.damage = damage; } public void attack() { damage = 10; System.out.printf("新的進攻手段,形成%d點傷害",this.damage ); } } Hero h = new AnonymousHero(damage); } }