有名內部類
接口:
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”文件