介面的概念:
官方解釋:Java介面是一系列方法的宣告,是一些方法特征的集合,一個介面只有方法的特征沒有方法的實作,因此這些方法可以在不同的地方被不同的類實作,而這些實作可以具有不同的行為(功能,即子類可以重寫抽象類的方法),
在介面中,它的方法是絕對抽象的(jdk8以前),用來抽象子類的能力、規則,例如鳥的fly,🐟的swim,數字能夠Compare,這就是鳥類,🐟類的能力,
在現實中也有很多事物用到了介面的概念
例如:資料線,在使用資料線充電時,只要你使用安卓的資料線,一般都能夠給安卓手機充電,因為這類充電線的插口都按照Android的規則、規格來生產資料線,這里使用到的是介面能定義規則(資料線并不是真正使用了JAVA中的介面,而是資料線的插口被制定了一個生產規則,包括插口大小,內部接線規則,假如我們要寫一個資料線的類,那么我們可以將這些規則以常量或者無方法體的抽象方法寫入介面中)
生活中很多物品的規格都是嚴格要求好的,這有利于產品的拓展,
對于面對物件的java語言也是如此,物件是用來描述、描繪一個事物的,有了介面,可以提高物件的擴展性,靈活性,
介面中除了默認方法和靜態方法,都沒有方法體
- 在jdk8以前,所有方法都是抽象的.
- 介面沒有方法體,是因為,介面是用來規范代碼,使得代碼結構更清晰,
- jdk8,介面可以有默認方法,默認方法有方法體,并且子類可以不實作默認方法,直接使用,也可以覆寫介面的方法
意義:現在有一個介面和若干個實作該介面的類,假如只是部分介面需要這個新方法,那怎么辦?
1.在介面中直接添加新方法:所有類都要實作該方法,很麻煩
2.使用抽象類(建議看完下面抽象類再來看這個):使用抽象類實作介面并添加新方法,需要實作的子類繼承自抽象類即可
3.在介面中添加默認方法!! - 介面無法實體化
一個類可以實作多個介面
介面可以繼承其他介面,并且可以多繼承介面,但是介面介面需要使用extends
public interface InterfaceB extends InterfaceA,InterfaceC{
}
//這里要注意了,介面繼承介面,介面可以不實作其父介面的抽象方法
//雖然這個介面里面沒有抽象方法,但是實作這個介面的類必須實作介面A中的方法
//即:類實作某個介面,從層級關系上講,類必須實作其介面層級往上的所有的抽象方法
public interface InterfaceA {
void doWork();
}
public interface InterfaceC {
}
一個類如果要實作某個介面,需要實作其中所有的抽象方法
1.因為介面是提取規則、能力,實作這個介面肯定就有這種能力,既然介面都抽象了這種方法,那子類都應該有這些方法,
為什么需要介面?
- java無法多繼承,介面可以用來抽象特性,可以彌補無法多繼承的局限,同時也避免了多繼承的復雜性
- 良好的代碼書寫規范和清晰的代碼層級關系利于原始碼的閱讀和理解
介面無法實體化
介面的方法都是public的
- 因為介面是提取規則,沒有子類實作介面,介面就沒存在的意義了,要被子類實作,public是最好的,不同包內也可以實作這個介面
介面中的屬性默認public static final
- 因為介面中抽象的是規則,規則不應該能被改變,并且能被子類使用,定義靜態常量時候必須有初始值
介面也有標識作用:
- 例如Serializable,其內部是連抽象方法都沒有的,沒有內容,這個介面的作用只是標識這個類具有某種功能,

抽象類的概念:
面對物件中,物件都是通過類來描述的,有很多相似的物件,這些類中有很多相似的內容,抽象類提取這些類的共性內容后,作為子類的模板,
1. 抽象類中必須含有抽象方法,可以有普通方法
2. 可以有變數、常量
3. 子類只能單繼承,即子類繼承了某抽象類無法繼承其他類
4.抽象類不能實體化,抽象類用來就是提取子類模板,是用來被繼承的,
但是可以以匿名內部類的形式來創建一個物件
-
public static void main(String[] args) { Animals sheep=new Animals() { @Override public void eat(String food) { System.out.println("羊吃"+food); } }; sheep.eat("草"); Animals fish=new Animals() { @Override public void eat(String food) { System.out.println("魚吃"+food); } }; fish.eat("水草"); }
}
這里就是兩個匿名抽象類物件,這里$就代表是匿名物件,
匿名內部類?為什么匿名內部類有參考?以及介面怎么實作匿名方式?
public class Anonymous {
public static void main(String[] args) {
Outer outer = new Outer();
outer.tiger.cry();
outer.dog();
}
}
interface IA{
void cry();
}
class Outer{
//如果要使用IA介面,并創建物件,傳統方式是寫一個類實作介面并創建物件
//但是這個類只需要使用一次所以使用匿名內部類來簡化開發
//匿名內部類的名字由系統自動分配,需要使用物件.getclass
//介面其實是無法new的,但是這里通過大括號并實作其中的方法,是的其可以創建并且將地址傳遞給tiger
//匿名內部類只能使用一次,但是已經創建的tiger可以多次使用
//這里其實是實作IA介面的內部類
IA tiger=new IA() {
@Override
public void cry() {
System.out.println("老虎狂嘯");
}
};
public void dog() {
IA dog = new IA() {
@Override
public void cry() {
System.out.println("小狗汪汪");
}
};
}
new Father(){
@Override
publi void ih(){
sop("匿名內部類呼叫了hi方法")
}
}.hi();//這樣甚至都不用創建變數,直接呼叫
//體現了匿名內部類的物件的特征
Father father=new Father("jack"){
//匿名內部類中不能重寫構造器,不能創建特有方法
//運行型別是Outer$3
//這里可以重寫father的方法
//這里相當于繼承了一個類,省去了創建不必要的新的子類
@Override
public void test() {
super.test();
}
};//這里有大括號,所有是匿名內部類
// Father father=new Father("jack");這里是直接創建father物件
}
class Father{
String name;
public Father(String name){
this.name=name;
}
public void test(){
System.out.println("name="+name);
}
}
介面和抽象類的區別
但是我先舉一個實際的例子,來解釋介面的作用,在此同時也會介紹抽象類和介面的區別
這里我們先假設我們需要實作一種抽象的數字類,來思考一下其需要實作什么功能
- 能保存用戶傳給的值
- 能和其他數字比較(數字不能比較還有什么意義)
- 可以來輸出保存的值
- 最大能保存數字的范圍
- 能和其他數字進行轉換
先別急,現在我們來看一下Java中是如何實作數字類及其子類的
這個是IDEA中的Digrams,想使用可以IDEA中Digrams的使用
來看一下源代碼
public abstract class Number implements java.io.Serializable {
public abstract int intValue();//對應上方的保存值功能,注意這里的所有方法都沒有方法體
public abstract long longValue();//回傳值(相當于保存值、輸出值)
public abstract float floatValue();//同上
public abstract double doubleValue();
public byte byteValue() {//強制轉換
return (byte)intValue();
}
public short shortValue() {
return (short)intValue();
}
private static final long serialVersionUID = -8742448824652078965L;
}
再看一下實作Number抽象類的Integer的原始碼
public final class Integer extends Number implements Comparable<Integer>{//注意這里繼承了Number抽象類和Comparable介面
//保存值的范圍
@Native public static final int MIN_VALUE = 0x80000000;
@Native public static final int MAX_VALUE = 0x7fffffff;
//輸出值
public static String toString(int i, int radix){
....省略
}
//保存值
public int intValue() {
return value;
}
static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
....省略
}
//和其他Integer類比較
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
//轉換成其他數字類
public long longValue() {
return (long)value;
}
}
再來看一下Comparable介面
public interface Comparable<T> {
public int compareTo(T o);
}
//comparable介面中引數使用了泛型,不同的類實作不同的comparable介面即可,實作comparable介面的類需要實作其中的compareTo方法
現在我們思考幾個問題(以下問題均是個人的想法,若不全,若有錯誤可聯系我補充或者更改答案)
- 為什么Comparable是一個介面
解:在撰寫代碼的時候,我們要使得代碼結構清晰,需要規范代碼,這也是抽象類,父類,介面存在的意義之一.使用介面可以提取類的規則,抽象類可以提取類的共性內容,對于比較功能,數字肯定是可以比較是吧,但是很多其他類,比如自己創建一個employee和employer類,兩個類之間可以有工資的比較方法或者其他比較方法,所以說Comparable應該是一個規則,Comparable作為介面最好,這樣有比較功能的類實作該介面就行,如果,有比較功能的類的不實作comparable介面,卻私自定義一個compare方法,那么介面存在的意義就被忽略了,
其次,Java無法實作多繼承,這意味著假如Comparable是抽象類的話,那我們又如何讓Integer繼承Number類,兩個類無法同時被一個類繼承,這里也側面體現了,介面可以解決java無法多繼承的局限, - 為什么Number是一個抽象類
解:抽象類抽取的是子類的特性、共性內容,可以看見Number類中有一些回傳數值和保存數值的方法以及轉換方法,這很明顯是所有數字類的共性內容,先前介紹了數字類應該有的五個個功能,回傳和保存以及轉換只是其中三個功能,但是
為什么數字范圍沒在抽象類中:上面Integer保存范圍是用的final常量,抽象類雖然可以有final屬性,但是不同數字類保存范圍不一樣,不是共同內容
為什么Number中沒有實作Comparable介面,而是其子類去實作Comparable介面:因為Comparable介面有泛型引數T,實作該介面的時候需要填寫引數,所以放在抽象類Number的子類中最合適,方便實作Comparable的CompareTo方法,
我這里寫了一個小代碼
public class IntegetTest extends NumberTest{
@Override
public int compare(NumberTest numberTest) {
return 0;
}
@Override
public int compareTo(NumberTest o) {
return 0;
}
}
假如有數字類繼承了這個介面,其子類需要實作這個compare方法以及compareTo方法并且引數是NumberTest抽象類,
我們看看Double繼承了Number抽象類,那Double怎么實作compareTo方法的
......上方其他代碼省略
public int compareTo(Double anotherDouble) {
return Double.compare(value, anotherDouble.value);
//value是newDouble類是保存在Double類中的一個值,體現了Double保存數值的功能
}
public static int compare(double d1, double d2) {
if (d1 < d2)
return -1; // Neither val is NaN, thisVal is smaller
if (d1 > d2)
return 1; // Neither val is NaN, thisVal is larger
// Cannot use doubleToRawLongBits because of possibility of NaNs.
long thisBits = Double.doubleToLongBits(d1);
long anotherBits = Double.doubleToLongBits(d2);
return (thisBits == anotherBits ? 0 : // Values are equal
(thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
1)); // (0.0, -0.0) or (NaN, !NaN)
}
....下方其他代碼省略
不需要理解很多,這里的compareTo方法使用了Double中保存的value,我們思考一下,假如是Number實作comparable介面,那么子類方法引數應該就是抽象類了,但是抽象類中雖然有保存數值的方法,但是并沒有方法體,如果Number實作該介面,其子類的CompareTo方法和Compare方法的實作會變得麻煩很多,(希望有人能提出關于這部分更好的意見!!)
- 為什么Number不能設計成一個介面
Number是一種模板,它偏向于提取子類的共性內容,介面偏向于提取規則,所以寫成抽象類比較方便
案例總結:
- 抽象類偏向于提取子類共有內容,介面偏向于提取規則,
- 抽象類是一種子類模板
- 合理的介面、抽象類使用可以讓代碼的關系更加清晰,事實上,介面可以提供多繼承的大多數好處,同時還能避免多繼承的復雜性,
如何查看自己所寫的類的關系 ,可以使用Idea的Digrams功能
Idea中超贊的的Digrams功能
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/386571.html
標籤:java
上一篇:Java 常用資料型別的輸入輸出
