接口Interface
- 一系列方法聲明的集合;
- 用來定義規范,標準;
- 接口中可以定義抽象方法,常量,嵌套類型,從Java8開始可以定義:默認方法,靜態方法;
- 上述可以定義的內容,都是隱式public的,因此可以省略public關鍵字;
- 從Java9開始可以定義private方法,不常用;
- 常量可以省略static,final;
- 抽象 方法可以省略abstract關鍵字;
- 不能自定義構造方法,不能定義(靜態)初始化塊,不能實例化;
public interface Test {
public static final int AGE = 100;
public int AGEE = 100;
int AGEEE = 100;
public abstract void test1();
public void test3();
void test2();
class A {
}
}
接口的細節
- 接口名稱可以在任何
使用類型的地方
進行使用; - 一個類可以通過implements關鍵字實現一個或多個接口;
- 實現接口的類必須實現接口中定義的
所有抽象方法
,除非它是個抽象類; - 如果一個類實現的多個接口中相同的抽象方法,只需要實現此方法一次;
- extend與implements可以一起使用,但
implements必須寫在extend的后面
; - 當父類,接口中的方法簽名相同時,那么這
兩個方法的返回值類型
也必須相同; - 一個接口可以通過extend關鍵字繼承一個或者多個接口,
接口支持繼承
; - 當多個父接口中方法簽名相同時,那么返回值類型也必須相同;
抽象類與接口的對比
- 抽象類,重點在于繼承,表明類是什么;
- 接口,重點在于實現,表明類可以做什么;
- 使用抽象類的場景:
- 在緊密相關的類之間共享代碼時;
- 需要除public之外的訪問權限;
- 需要定義實例變量,非final的靜態變量;
- 使用接口的場景:
- 不相關的類實現相同的方法;
- 只是定義特定數據類型的行為,不關心具體是誰實現了行為;
- 想實現類型的多重繼承,接口能多繼承,而抽象類只能單繼承;
接口的升級問題
- 如果接口需要升級,比如增加了新的抽象方法,會導致大幅度的代碼改動,以前實現接口的類都需要改動,若想在不改動以前實現類的前提下進行接口升級,有方案如下:
- 默認方法;
- 靜態方法;
接口_默認方法
- 用default修飾默認方法;
- 默認方法只能是實例方法;
- 當一個類實現的接口中有默認方法時,這個類可以:
- 啥都不干,沿用接口的默認實現;
- 重寫默認方法,覆蓋默認方法的實現;
- 重新聲明默認方法,將默認方法聲明為抽象方法,此類必須是抽象類;
import android.util.Log;
public interface Test {
public abstract void test1();
//默認方法 允許有實現
public default void test2() {
Log.v("Test","test2");
}
}
import android.util.Log;
import com.example.java_test.java.interfaces.Test;
public class Dog implements Test {
@Override
public void test1() {
Log.v("Dog","test1");
}
//Dog類可以不實現 也可實現
@Override
public void test2() {
//實現類 可調用 接口中的默認實現
Test.super.test2();
}
}
import com.example.java_test.java.interfaces.Test;
//重新聲明為抽象方法 自身為抽象類
public abstract class Dog implements Test {
@Override
public abstract void test2();
}
- 當一個接口繼承的父接口中有默認方法時,這個接口可以:
- 啥都不干,沿用接口的默認實現;
- 重寫默認方法,覆蓋默認方法的實現;
- 重新聲明默認方法,將默認方法聲明為抽象方法;
默認方法的細節
- 如果父類定義的非抽象方法與接口的默認方法相同時,最終將調用父類的方法,父類方法的優先級高;
import android.util.Log;
public class Animal {
public void run() {
Log.v("Animal","Animal" + "run");
}
}
import android.util.Log;
public interface Runable {
default void run() {
Log.v("Runable","Runable" + "run");
}
}
public class Dog extends Animal implements Runnable{
}
- 如果父類定義的抽象方法與接口的默認方法相同時,要求子類實現此抽象方法;
- 可通過super關鍵字調用接口的默認方法;
public abstract class Animal {
public abstract void run();
}
import android.util.Log;
public interface Runable {
default void run() {
Log.v("Runable","Runable" + "run");
}
}
public class Dog extends Animal implements Runnable{
@Override
public void run() {
}
}
- 如果(父)接口定義的默認方法與其他(父)接口定義的方法相同時,要求子類實現此默認方法;
import android.util.Log;
public interface Runable {
default void run() {
Log.v("Runable","Runable" + "run");
}
}
import android.util.Log;
public interface Walkable {
default void run() {
Log.v("Walkable","Walkable" + "run");
}
}
public interface Testable extends Runable,Walkable{
@Override
default void run() {
Runable.super.run();
Walkable.super.run();
}
}
import com.example.java_test.java.interfaces.Runable;
import com.example.java_test.java.interfaces.Walkable;
public class Dog implements Runable, Walkable {
@Override
public void run() {
Runable.super.run();
Walkable.super.run();
}
}
- Testable與Dog都必須實現run默認方法;
- 如果類實現的兩個接口中有相同的默認方法,那么類必須實現默認方法,如果兩個接口中只有其中一個接口實現了默認方法,那么類可以不用實現默認方法,規則是類能確定自己調用的是哪個方法;
public interface Animal {
default String myself() {
return "I am an animal";
}
}
public interface Fire extends Animal{
}
public interface Fly extends Animal{
default String myself() {
return "I am able to fly";
}
}
import com.example.java_test.java.interfaces.Fire;
import com.example.java_test.java.interfaces.Fly;
public class Dragon implements Fly, Fire {
}
接口_靜態方法
- 接口中定義的靜態方法只能通過接口名調用,不能被繼承;
import android.util.Log;
public interface Eatable {
public static void eat(String name) {
Log.v("Eatable","eat");
}
}
import android.util.Log;
public interface Sleepable {
public static void eat(String name) {
Log.v("Sleepable","eat");
}
}
import android.util.Log;
public interface Dog extends Eatable,Sleepable{
public static void eat(String name) {
Log.v("Dog","eat");
}
}
import com.example.java_test.java.interfaces.Dog;
import com.example.java_test.java.interfaces.Eatable;
import com.example.java_test.java.interfaces.Sleepable;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Dog.eat("1");
Eatable.eat("1");
Sleepable.eat("1");
}
}
多態
- 同一操作作用于不同的對象,產生不同的執行結果;
- 父類(接口) 指針指向子類的對象;
- 調用子類重寫的方法;
- JVM會根據引用變量指向的具體對象來調用對應的方法,這個行為叫做:虛方法調用,類似C++中的虛函數調用;
- 類與接口都可以實現多態;
- 實例方法,會根據對象本身的類型,確定方法的調用;
類方法的調用細節
- 在Java中只有實例方法存在重寫,類方法是不存在重寫的;
- 與引用類型關聯;
成員變量的訪問細節
- 與引用類型關聯;
instanceof
- 可以通過instanceof判斷某個類型是否屬于某種類型;
public class Animal {
}
import android.util.Log;
public interface Eatable {
public static void eat(String name) {
Log.v("Eatable","eat");
}
}
import com.example.java_test.java.interfaces.Eatable;
public class Dog extends Animal implements Eatable {
}
import com.example.java_test.java.cls.Animal;
import com.example.java_test.java.cls.Dog;
import com.example.java_test.java.interfaces.Eatable;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Object dog = new Dog();
Log.v("MainActivity - 1",String.valueOf(dog instanceof Dog)); //true
Log.v("MainActivity - 2",String.valueOf(dog instanceof Animal)); //true
Log.v("MainActivity - 3",String.valueOf(dog instanceof Eatable)); //true
Log.v("MainActivity - 4",String.valueOf(dog instanceof String)); //false
}
}
- 類型的強制轉換
Object obj = new Cat();
Cat cat = ((Cat) obj);
- 接口用來實現 面向接口編程,減少類之間的耦合性;
匿名類
- 當接口,抽象類的實現類,在整個項目中只用過一次,可以考慮使用匿名類;
import com.example.java_test.java.interfaces.Eatable;
public class Person implements Eatable {
@Override
public void eat() {
Log.v("eat","person - eat");
}
}
public interface Eatable {
void eat();
}
import com.example.java_test.java.cls.Person;
import com.example.java_test.java.interfaces.Eatable;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Person person = new Person();
person.eat();
}
}
- 使用匿名類,Person類文件可以直接刪除;
import com.example.java_test.java.interfaces.Eatable;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Eatable person = new Eatable() {
@Override
public void eat() {
}
};
person.eat();
}
}
- 使用匿名類,直接調用方法;
import com.example.java_test.java.interfaces.Eatable;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//匿名類
new Eatable() {
@Override
public void eat() {
Log.v("eat","person - eat");
}
}.eat();
}
}
-
匿名類的注意點:
- 匿名類不能定義除編譯時常量以外的任何static成員;
- 匿名類只能訪問final 或者 有效final的局部變量,跟局部類類似;
- 匿名類可以直接訪問外部類的所有成員(即使被聲明為private)
- 匿名類只有在實例相關的代碼塊中使用,才能直接訪問外部類中的實例成員(實例變量,實例方法);
- 匿名類不能定義構造方法,可以定義初始化塊;
-
匿名類的使用場景:
- 代碼傳遞;
- 過濾器;
- 回調;
匿名類實現代碼傳遞
package com.example.java_test.java.cls;
import android.util.Log;
public class TimeUtils {
public interface Block {
void execute();
}
//block 是一個實現Block接口的匿名類 實例對象
public static void test(Block block) {
double begin = System.currentTimeMillis();
//匿名類 實例對象 調用接口方法
block.execute();
double end = System.currentTimeMillis();
double duration = (end - begin) / 1000.0;
Log.v("TimeUtils",String.valueOf(duration));
}
}
import com.example.java_test.java.cls.TimeUtils;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TimeUtils.test(new TimeUtils.Block() {
@Override
public void execute() {
test();
}
});
}
public static void test() {
int num = 100000;
String str = "asd";
for (int i = 0; i < num;i++) {
str += i;
}
}
}
- 實現 統計一段代碼執行的耗時時間,采用匿名類的方式,將執行代碼塊 傳遞給TimeUtils,然后TimeUtils處理計算耗時時間;
- 參數block 是一個
實現Block接口的匿名類 實例對象
;
匿名類實現回調
public class NetworkUtils {
public interface Block {
void success(Object response);
void failure();
}
public static void get(String url,Block callBack) {
//根據URL 發送網絡請求
//請求完成后
boolean result = true;
if (result) {
callBack.success("success");
} else {
callBack.failure();
}
}
}
import com.example.java_test.java.cls.NetworkUtils;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NetworkUtils.get("https.www.baidu.com", new NetworkUtils.Block() {
@Override
public void success(Object response) {
Log.v("MainActivity","請求成功");
}
@Override
public void failure() {
Log.v("MainActivity","請求失敗");
}
});
}
}
- 匿名類實現回調與實現代碼傳遞的方式 時相同的;
- 上述使用匿名類實現了 網絡請求的成功與失敗的回調;
匿名類實現條件過濾
public class FileUtils {
public interface Filter {
boolean accept(String fileName);
}
public static String[] getAllFileNames(String dir,Filter filter) {
//1.根據dir路徑 獲取所有文件
String[] allFileNames = {};
//2.文件過濾
String[] filters = {};
for (String fileName : allFileNames) {
if (filter.accept(fileName)) {
}
}
//3.返回過濾之后的文件
return filters;
}
}
import com.example.java_test.java.cls.FileUtils;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FileUtils.getAllFileNames("F://", new FileUtils.Filter() {
@Override
public boolean accept(String fileName) {
return fileName.contains("類");
}
});
}
}
- 將過濾條件封裝成 匿名類,不同的過濾條件 可通過不同的匿名類來實現;
匿名類實現排序
import java.util.Arrays;
import java.util.Comparator;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Integer[] array = {23,11,59,4,423,89,56};
Arrays.sort(array, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
Log.v("MainActivity",Arrays.toString(array));
}
}
- 排序規則是通過匿名類 傳遞給數組的,其中
new Comparator<Integer>() {}
是匿名類實例對象,即一個實現Comparator接口的匿名類實例對象;
Lambda Expression
- Lambda表達式是Java8開始才有的語法;
- 函數式接口:只包含一個抽象方法的接口;
- 可以在接口上面加上@FunctionalInterface注解,表示它是一個函數式接口;
@FunctionalInterface
public interface Filter {
boolean accept(String fileName);
}
- 當匿名類實現的是函數式接口時,可以使用Lambda表達式進行簡化;
- 將上面匿名類實現的統計代碼耗時,文件過濾與數組排序 利用Lambda表達式進行簡化,如下所示:
import com.example.java_test.java.cls.FileUtils;
import com.example.java_test.java.cls.TimeUtils;
import java.util.Arrays;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//使用Lambda表達式
TimeUtils.test(() -> {
test();
});
FileUtils.getAllFileNames("F://",(String fileName) -> {
return fileName.contains("類");
});
Integer[] array = {23,11,59,4,423,89,56};
Arrays.sort(array,(Integer o1, Integer o2) -> {
return o1 - o2;
});
Log.v("MainActivity",Arrays.toString(array));
}
public static void test() {
int num = 100000;
String str = "asd";
for (int i = 0; i < num;i++) {
str += i;
}
}
}
- Lambda表達式的格式:
(參數列表) -> { 函數實現 }
,將匿名類中實現的抽象接口方法,寫成Lambda表達式的格式; - Lambda表達式還可以進行簡化:
- 參數列表可以省略參數類型;
- 當方法實現只有一條語句時,可以省略大括號,分號,return;
- 當方法只有一個參數時,可以省略小括號;
- 當方法沒有參數時,不能省略小括號;
- 再次進行簡化,如下所示:
import com.example.java_test.java.cls.FileUtils;
import com.example.java_test.java.cls.TimeUtils;
import java.util.Arrays;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//使用Lambda表達式
TimeUtils.test(() -> test());
FileUtils.getAllFileNames("F://",(fileName) -> fileName.contains("類"));
Integer[] array = {23,11,59,4,423,89,56};
Arrays.sort(array,(o1,o2) -> o1 - o2);
Log.v("MainActivity",Arrays.toString(array));
}
public static void test() {
int num = 100000;
String str = "asd";
for (int i = 0; i < num;i++) {
str += i;
}
}
}
- Lambda的使用注意點
- Lambda只能訪問final 或者 有效final的局部變量;
- Lambda沒有引入新的作用域;
import com.example.java_test.java.interfaces.Testable;
public class OuterClass {
private int age = 1;
public class InnerClass {
private int age = 2;
void inner() {
//沒有引入新的作用域
Testable t1 = v -> {
Log.v("InnerClass",String.valueOf(v));
Log.v("InnerClass",String.valueOf(age));
Log.v("InnerClass",String.valueOf(this.age));
Log.v("InnerClass",String.valueOf(InnerClass.this.age));
Log.v("InnerClass",String.valueOf(OuterClass.this.age));
};
//Log.v("InnerClass",String.valueOf(v));
//Log.v("InnerClass",String.valueOf(age));
//Log.v("InnerClass",String.valueOf(this.age));
//Log.v("InnerClass",String.valueOf(InnerClass.this.age));
//Log.v("InnerClass",String.valueOf(OuterClass.this.age));
}
}
}
- Testable t1 = v -> { } 大括號形同虛設;
import com.example.java_test.java.interfaces.Testable;
public class OuterClass {
private int age = 1;
public class InnerClass {
private int age = 2;
void inner() {
//沒有引入新的作用域
Testable t1 = v -> {
Log.v("InnerClass",String.valueOf(v));
Log.v("InnerClass",String.valueOf(age));
Log.v("InnerClass",String.valueOf(this.age));
Log.v("InnerClass",String.valueOf(InnerClass.this.age));
Log.v("InnerClass",String.valueOf(OuterClass.this.age));
};
Testable t2 = new Testable() {
@Override
public void test(int a) {
Log.v("InnerClass",String.valueOf(a));
Log.v("InnerClass",String.valueOf(age));
Log.v("InnerClass",String.valueOf(this.age)); //報錯
Log.v("InnerClass",String.valueOf(InnerClass.this.age));
Log.v("InnerClass",String.valueOf(OuterClass.this.age));
}
};
}
}
}
- t1與t2 從本質上來看,是等價的,都是創建一個實現Testable接口的匿名類實例對象,但t2的this.age會報錯,原因在于this現在是指匿名類,匿名類是沒有定義age成員的所以會報錯,t1使用了Lambda表達式,沒有引入新的作用域,不會報錯;
方法引用
- 如果Lambda中的內容僅僅是調用某個方法,可以使用方法引用來簡化;
引用類方法
public interface Testable {
int test(int v1,int v2);
}
import com.example.java_test.java.interfaces.Testable;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Testable testable1 = ((v1, v2) -> {
return v1 > v2 ? v1 : v2;
});
Testable testable2 = ((v1, v2) -> {
return Math.max(v1,v2);
});
Testable testable3 = ((v1, v2) -> Math.max(v1,v2));
//引用類方法
Testable testable4 = Math::max;
testable4.test(100,22);
}
}
引用特定對象的實例方法
public interface Testable {
void test(int v1);
}
import android.util.Log;
public class Person {
public void setAge(int age) {
Log.v("Person",String.valueOf(age));
}
}
import com.example.java_test.java.cls.Person;
import com.example.java_test.java.interfaces.Testable;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//引用特定對象System.out 的實例方法
execute(v -> System.out.println(v),10);
execute(System.out::println,10);
//引用特定對象Person的 實例方法
execute(v -> new Person().setAge(v),20);
execute(new Person()::setAge,20);
}
public static void execute(Testable testable,int v) {
testable.test(v);
}
}
引用特定類型的任意對象的實例方法
import java.util.Arrays;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String[] strings = {"abc","sff","awc","tgd"};
Arrays.sort(strings,(s1,s2) -> s1.compareToIgnoreCase(s2));
Log.v("MainActivity",String.valueOf(Arrays.toString(strings)));
//引用特定類型的任意對象的實例方法
//直接使用類名 引用方法
Arrays.sort(strings,String::compareToIgnoreCase);
}
}
引用構造方法
public interface Testable {
Object test(int v1);
}
public class Person {
public Person(int age) {
System.out.println(age);
}
}
import com.example.java_test.java.cls.Person;
import com.example.java_test.java.interfaces.Testable;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Testable testable = v -> new Person(v);
//引用構造方法
Testable testable1 = Person::new;
}
}
引用數組的構造方法
public interface Testable {
Object test(int v1);
}
import com.example.java_test.java.interfaces.Testable;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Testable testable = v -> new int[v];
//引用數組的構造方法
Testable testable1 = int[]::new;
}
}
引用當前類中定義的實例方法
public interface Testable {
void test(int v1);
}
import com.example.java_test.java.interfaces.Testable;
public class Person {
public void setAge(int age) {
System.out.println(age);
}
public void show() {
Testable testable = v -> setAge(v);
//引用當前類中定義的實例方法
Testable testable1 = this::setAge;
}
}
引用父類中定義的實例方法
public interface Testable {
void test(int v1);
}
public class Person {
public void setAge(int age) {
System.out.println("Person" + age);
}
}
import com.example.java_test.java.interfaces.Testable;
public class Student extends Person{
@Override
public void setAge(int age) {
System.out.println("Student" + age);
}
public void show() {
Testable testable = v -> setAge(v);
//引用當前類中定義的實例方法
Testable testable1 = super::setAge;
}
}
- 總結如下:
image.png