有名内部類
接口:
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檔案如下:
其中Mamma l.class和Body.class為兩個類的class檔案
Body$A.class為Body類中有名内部類的class檔案
Body$1.class和Body$2.class為Body類中的匿名内部類的class檔案
總結:
有名内部類編譯後生成“外部類 $ 内部類 . class”檔案
匿名内部類編譯後生成“外部類 $ 數字 . class”檔案