Java8中的接口
public interface Output {
//接口裏定義的成員變量只能是常量
//默認使用public static final修飾
int MAX_CACHE_LINE = 50;
//接口裏定義的普通方法只能是public的抽象方法
void out();
void getData(String msg);
//接口中定義的默認方法,需要使用default修飾
default void print(String... msgs) {
for (String msg : msgs) {
System.out.println(msg);
}
}
//接口中定義類方法,需要使用static修飾
static String staticTest(){
return "接口裏的類方法";
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
Java8中允許在接口中定義默認方法,默認方法必須使用default修飾,該方法不能使用static修飾,無論程序是否指定,默認方法總是使用public修飾。由於默認方法並沒有static修飾,因此不能直接使用接口來調用默認方法,需要使用接口的實現類的實例來調用這些默認方法。
Java8中允許在接口中定義類方法,類方法必須使用static修飾,該方法不能使用default修飾,無論程序是否指定,類方法總是使用public修飾。類方法可以直接使用接口來調用。
接口和抽象類
- 相同點
- 接口和抽象類都不能被實例化,他們都位於繼承樹的頂端,用於被其他類實現和繼承。
- 接口和抽象類都可以包含抽象方法,實現接口或繼承抽象類的普通子類都必須實現這些抽象方法。
- 區別:
- 接口裏只能包含抽象方法和默認方法,不能爲普通方法提供方法實現;抽象類則完全可以包含普通方法。
- 接口裏不能定義靜態方法;抽象類裏可以定義靜態方法。
- 接口裏只能定義靜態常量,不能定義普通成員變量;抽象類裏則既可以定義普通成員變量,也可以定義靜態常量。
- 接口裏不包含構造器;抽象類裏可以包含構造器,抽象類裏的構造器並不是用於創建對象,而是讓其子類調用這些構造器來完成屬於抽象類的初始化操作。
- 接口裏不能包含初始化塊;但抽象類則完全可以包含初始化塊。
- 一個類最多只能有一個直接父類,包括抽象類;但一個類可以直接實現多個接口,通過實現多個接口可以彌補Java單繼承的不足。
內部類
把一個類放在另一個類的內部定義,這個定義在其他類內部的類就被稱爲內部類(也叫嵌套類),包含內部類的類也被稱爲外部類(也叫宿主類)
內部類比外部類可以多用三個修飾符:private、protected、static
非靜態內部類不能擁有靜態成員
在一個類的方法中定義的內部類叫做局部內部類;其他的叫做成員內部類。
非靜態內部類
成員內部類中沒有使用static修飾的內部類是非靜態內部類
非靜態內部類對象和外部類對象的關係是?
- 非靜態內部類對象必須寄生在外部類對象裏,而外部類對象則不必一定有費靜態內部類對象寄生其中。
- 如果存在一個非靜態內部類對象,則一定存在一個被他寄生的外部類對象。
- 但外部類對象存在時,外部類對象裏不一定寄生了非靜態內部類對象。
- 因此外部類對象訪問非靜態內部類成員時,可能非靜態普通內部類根本不存在。
- 而非靜態內部類對象訪問外部類成員時,外部類對象一定存在。
靜態內部類
使用static修飾的內部類被稱爲靜態內部類(也叫類內部類)。這個內部類屬於外部類本身,而不屬於外部類的某個對象。
靜態內部類可以包含靜態成員,也可以包含非靜態成員。
爲什麼靜態內部類的實例方法不能訪問外部類的實例屬性?
- 靜態內部類是外部類的類相關的,而不是外部類的對象相關的。
- 靜態內部類對象不是寄生在外部類的實例中,而是寄生在外部類的類本身中。
- 當靜態內部類對象存在時,並不存在一個被他寄生的外部類對象,靜態內部類對象只持有外部類的類引用,沒有持有外部類對象的引用。
- 如果允許靜態內部類的實例方法訪問外部類的實例成員,但找不到被寄生的外部類對象,這將引起錯誤。
局部內部類
如果把一個內部類放在方法裏定義,則這個內部類就是一個局部內部類,局部內部類僅在該方法裏有效。
實際開發很少使用
匿名內部類
匿名內部類適合創建那種只需要一次使用的類。
創建匿名內部類時會立即創建一個該類的實例,這個類定義立即消失,匿名內部類不能重複使用。
匿名內部類格式:
new 實現接口() | 父類構造器(實參列表)
{
//匿名內部類的類體部分
}
- 1
- 2
- 3
- 4
- 5
最常用的創建匿名內部類的方式是需要創建某個接口類型的對象
interface Product {
public double getPrice();
public String getName();
}
public class AnonymousTest {
public void test(Product p) {
System.out.println("買了一個" + p.getName() + ",花了" + p.getPrice());
}
public static void main(String args[]) {
AnonymousTest ta = new AnonymousTest();
//調用test方法時,需要傳入一個Product參數
//此處傳入其匿名實現類的實例
ta.test(new Product() {
@Override
public double getPrice() {
return 12.3;
}
@Override
public String getName() {
return "U盤";
}
});
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
Lambda表達式
Lambda表達式支持代碼塊作爲方法參數,允許使用更簡潔的代碼來創建只有一個抽象方法的接口(這種接口被稱爲函數式接口)的實例。
比如,有匿名內部類程序:
public class CommandTest {
public static void main(String args[]) {
ProcessArray pa = new ProcessArray();
int[] target = {2, 1, -5, 3};
pa.process(target, new Command() {
@Override
public void process(int[] target) {
int sum = 0;
for (int tmp : target) {
sum += tmp;
}
System.out.println("數組元素的總和是:" + sum);
}
});
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
改爲Lambda表達式代替匿名內部類:
public class CommandTest {
public static void main(String args[]) {
ProcessArray pa = new ProcessArray();
int[] target = {2, 1, -5, 3};
pa.process(target, (int[] array) -> {
int sum = 0;
for (int tmp : array) {
sum += tmp;
}
System.out.println("數組元素的總和是" + sum);
});
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14