面向对象——多态,抽象类,接口(二)
目錄
前言:
多態(tài)
1.1 向下轉(zhuǎn)型(了解)
1.2 instanceof關(guān)鍵字
1.3 多態(tài)(理解)
1.4 多態(tài)的好處
抽象類
2.1 abstract關(guān)鍵字
2.2 語法規(guī)則
接口(重點(diǎn))
3.1 語法規(guī)則
3.2?實(shí)現(xiàn)多個(gè)接口
3.4 接口與接口之間的關(guān)系
3.5 接口的好處
3.6 接口與抽象類的區(qū)別(要點(diǎn))
接口常用實(shí)例
4.1 comparable接口
4.2 comparator接口
4.3 clonable接口和深拷貝
4.3.1 淺拷貝
4.3.2 深拷貝與clonable接口
4.3.3 clonable使用要點(diǎn):
前言:
? ? ? ? 本篇文章主要講述對(duì)于包,接口,以及多態(tài)的理解,以及一些常用接口的了解,如果對(duì)于你有所幫助或者啟發(fā),不要忘記給作者點(diǎn)個(gè)贊哦!
多態(tài)
1.1 向下轉(zhuǎn)型(了解)
在前面一篇文章我們介紹了什么是向上轉(zhuǎn)型,向下轉(zhuǎn)型就是用子類的引用去引用父類引用所指的該子類對(duì)象,但是這個(gè)時(shí)候就必須的要進(jìn)行強(qiáng)轉(zhuǎn),因?yàn)檫@個(gè)時(shí)候是要父類的引用被子類的引用所引用,接下來我們可以通過一個(gè)代碼來理解一下
animal animal=new bird("fja",20);bird bird=(bird) animal;此時(shí)就是子類的引用引用了父類引用所指的該子類對(duì)象,其實(shí)向下轉(zhuǎn)型還是不安全的,之前我們向上轉(zhuǎn)型中,父類引用子類,可以理解為子類是屬于父類的一種,而這里不能說父類是子類的一種。
1.2 instanceof關(guān)鍵字
對(duì)于向下轉(zhuǎn)型,我們可以采取利用instanceof關(guān)鍵字來判斷父類引用是否是子類的一個(gè)實(shí)例,具體用法如下
animal animal=new dog("fja",20);if (animal instanceof dog){System.out.println(333);}如果animal引用的是dog的一個(gè)子類對(duì)象,就會(huì)執(zhí)行if語句里面的內(nèi)容,反之就不會(huì)執(zhí)行if語句里面的內(nèi)容,這樣子可以讓向下轉(zhuǎn)型更加安全的實(shí)現(xiàn)。
1.3 多態(tài)(理解)
對(duì)于多態(tài)我們可以結(jié)合一段代碼來進(jìn)行理解什么是多態(tài)!
class shape{public void draw(){} } class rect extends shape{@Overridepublic void draw() {System.out.println("(●ˇ?ˇ●)");} } class small extends shape{@Overridepublic void draw() {System.out.println("small");} } public class test {public static void func(shape shape){shape.draw();}public static void main(String[] args) {rect rect=new rect();func(rect);small small=new small();func(small)} }在這段代碼中我們定義了一個(gè)shape類里面的draw方法可以幫助我們打印出不同的形狀,我們結(jié)合之前所講的動(dòng)態(tài)綁定,繼承,就可以來實(shí)現(xiàn)通過定義一個(gè)父類來實(shí)現(xiàn)打印不同的形狀,在這里我們可以了解到,在調(diào)用函數(shù)中,我們不用關(guān)注shape引用了那個(gè)類型的實(shí)例。也就是說通過一個(gè)父類shape的引用,來調(diào)用同一個(gè)方法,表現(xiàn)出來的形式有不同(與shape對(duì)應(yīng)的實(shí)例有關(guān)),這樣的一個(gè)行為就被稱為是多態(tài)。
1.4 多態(tài)的好處
之前我們學(xué)過private封裝,封裝的好處就是讓類的調(diào)用者不需要知道類的實(shí)現(xiàn)細(xì)節(jié),那么此時(shí)多態(tài)的作用就是讓類的調(diào)用者不需要知道這個(gè)類的是什么類型,只需要這個(gè)對(duì)象的某個(gè)方法就可以了,這樣就讓類的調(diào)用者對(duì)類的使用成本進(jìn)一步降低。
抽象類
2.1 abstract關(guān)鍵字
在多態(tài)中,我們發(fā)現(xiàn)通過動(dòng)態(tài)綁定,父類中的方法是沒有被執(zhí)行的,那么這個(gè)時(shí)候我們可以通過abstract關(guān)鍵字將該方法變?yōu)槌橄蠓椒?#xff0c;那么包含抽象方法的類就被稱為抽象類。
abstract class shape{abstract public void draw(); }2.2 語法規(guī)則
1 不能通過關(guān)鍵字new來實(shí)例化抽象類本身,但是可以發(fā)生向上轉(zhuǎn)型
2 抽象類最大的作用是被繼承
3 抽象類不能被final修飾,被final修飾的類是不能被繼承的
4 抽象類中也是可以包含字段與普通方法
5 一個(gè)普通類繼承了抽象類,那么這個(gè)普通類就需要重寫抽象類里面的全部抽象方法
6? 若一個(gè)抽象類A,繼承了一個(gè)抽象類B,抽象類A可以不重寫抽象類B中的抽象方法,此時(shí)若有一個(gè)普通類C,繼承了抽象類A,那么此時(shí)就需要重寫抽象類A與B中所有的抽象方法。
接口(重點(diǎn))
3.1 語法規(guī)則
1 在抽象類的基礎(chǔ)上(可以理解為是抽象類的plus版本),我們利用interface關(guān)鍵字去定義一個(gè)接口,abstract public在接口是可以省略的,與抽象類一樣,接口也是不能被實(shí)例化的。
interface shape{abstract public void draw(); }2 接口中不能含有普通方法與字段(如果要寫入普通方法,可以在普通方法前用關(guān)鍵字default修飾,表示為這個(gè)接口的默認(rèn)方法)
3 接口中的成員變量都是被public static final(可以被省略)修飾的,并且都要被賦予初值
4 當(dāng)一個(gè)類繼承了接口,就要重寫該接口中的所有抽象方法
5 接口的實(shí)現(xiàn)(implements關(guān)鍵字)
我們通過implements關(guān)鍵字來實(shí)現(xiàn)一個(gè)接口
interface shape{abstract public void draw(); } class cloud implements shape{@Overridepublic void draw() {System.out.println("這是一個(gè)接口實(shí)現(xiàn)");} } public class test {public static void main(String[] args) {shape shape=new cloud();shape.draw();} }我們通過定義了一個(gè)cloud,通過關(guān)鍵字implements實(shí)現(xiàn)接口shape
6 當(dāng)一個(gè)類實(shí)現(xiàn)了該接口,那么重寫該接口的抽象方法前一定要加上public
?接口中可以省略,但是重寫時(shí)可不能不寫,否則是包訪問權(quán)限,就比接口中的訪問權(quán)限就要小了。
3.2?實(shí)現(xiàn)多個(gè)接口
interface Is{abstract public void eat(); } interface shape{abstract public void draw(); } class cloud implements shape,Is{@Overridepublic void draw() {System.out.println("這是一個(gè)接口實(shí)現(xiàn)");}@Overridepublic void eat() {System.out.println("實(shí)現(xiàn)多個(gè)接口!");} } public class test {public static void main(String[] args) {shape shape=new cloud();shape.draw();} }通過代碼我們可以知道一個(gè)類可以實(shí)現(xiàn)多個(gè)接口(本例子就列舉了兩個(gè)接口,其實(shí)可以多個(gè)接口),但要把每個(gè)接口的抽象方法要重寫,并且接口之間用逗號(hào)隔開。
3.4 接口與接口之間的關(guān)系
interface Irunning{abstract public void run(); } interface Iwalk{abstract public void walk(); } interface IC extends Irunning{abstract public void pdd(); }從代碼中我們可以知道,接口與接口之間是通過extends關(guān)鍵字來表示兩個(gè)接口之間的關(guān)系,此時(shí)這里的extends不是繼承的意思,而表示拓展的意思,一個(gè)接口可以拓展另一個(gè)接口,而實(shí)現(xiàn)兩個(gè)接口的功能(如果要拓展多個(gè)接口,需要用逗號(hào)隔開)
3.5 接口的好處
1 彌補(bǔ)java中單繼承的缺點(diǎn),因?yàn)榭梢詳U(kuò)展多個(gè)接口,那么我們可以通過繼承一個(gè)父類,利用implement關(guān)鍵字實(shí)現(xiàn)多個(gè)接口,從而實(shí)現(xiàn)更多的功能
2 多態(tài)能夠讓程序猿不必關(guān)注類的類型,那么接口就是讓程序猿不必關(guān)注類的類型,而是關(guān)注類所能實(shí)現(xiàn)的功能
例如:
我們先創(chuàng)建三個(gè)接口,去實(shí)現(xiàn)跑,游,飛三種功能
interface Irun{void run(); } interface Iswim{void swim(); } interface Ifly{void fly(); }我們?cè)诙x一個(gè)父類animal
class Animal{String name;public Animal(String name){this.name=name;} }定義實(shí)現(xiàn)一個(gè)功能的
//定義一個(gè)跑的動(dòng)物 class DOG extends Animal implements Irun{public DOG(String name) {super(name);}@Overridepublic void run() {System.out.println(name+"四條腿跑");} }定義一個(gè)實(shí)現(xiàn)兩個(gè)功能的動(dòng)物
//定義一個(gè)會(huì)跳回游的青蛙 class frog extends Animal implements Irun,Iswim{@Overridepublic void run() {System.out.println(name+"在跳");}@Overridepublic void swim() {System.out.println(name+"游泳");}public frog(String name) {super(name);} }定義一個(gè)能滿足三種功能的動(dòng)物
//定義能滿足這三個(gè)功能的動(dòng)物 class Duck extends Animal implements Irun,Iswim,Ifly{@Overridepublic void run() {System.out.println(name+"跑");}@Overridepublic void swim() {System.out.println(name+"游泳");}@Overridepublic void fly() {System.out.println(name+"飛");}public Duck(String name) {super(name);} }在這里我們就可以看到,我們可以通過繼承一個(gè)類,實(shí)現(xiàn)多種接口,從而實(shí)現(xiàn)更多的功能,彌補(bǔ)了java中單繼承的缺陷。從這里也可以看出接口所要表達(dá)的含義就是:具有xxx特性
我們?cè)谶@個(gè)基礎(chǔ)上,可以實(shí)現(xiàn)一個(gè)方法專門用于跑
public static void fun(Irun Irun){Irun.run();}在這個(gè)方法的內(nèi)部我們不關(guān)心是什么類型,只要所給的參數(shù)會(huì)跑就行
public class node {public static void fun(Irun Irun){Irun.run();}public static void main(String[] args) {DOG DOG=new DOG("狗");fun(DOG);} }接口的可擴(kuò)展性非常強(qiáng),只要一個(gè)類實(shí)現(xiàn)了該接口,就能通過該方法來實(shí)現(xiàn),請(qǐng)看下列代碼
lass Robot implements Irun { private String name; public Robot(String name) { this.name = name; } @Override public void run() { System.out.println(this.name + "正在用輪子跑"); } } Robot robot = new Robot("機(jī)器人"); fun(robot);只要是實(shí)現(xiàn)了Irun這個(gè)接口,就可以通過實(shí)現(xiàn)方法,來實(shí)現(xiàn)該類的功能。
3.6 接口與抽象類的區(qū)別(要點(diǎn))
核心區(qū)別:抽象類中是可以包含字段與普通方法的,方法與字段是可以直接被子類使用的(不需要重寫),接口中不含有普通方法,子類必須重寫接口中包含的所有抽象方法
圖解區(qū)別
接口常用實(shí)例
4.1 comparable接口
在java中,我們?cè)跀?shù)組中就學(xué)過了Arrays.sort()對(duì)一個(gè)整數(shù)類型的數(shù)組進(jìn)行排序,那么對(duì)于在實(shí)際處理業(yè)務(wù),有些時(shí)候排序需要我們指定一個(gè)指標(biāo)進(jìn)行排序,這個(gè)時(shí)候就要用到我們java中自帶的comparable接口
class Student implements Comparable<Student>{public String name;public int age;public double score;//這里的this是誰調(diào)用了compareTo方法誰就是@Overridepublic int compareTo(Student o) {//return this.age-o.age;//通過年齡進(jìn)行比較//return (int)(this.score-o.score);//通過分?jǐn)?shù)進(jìn)行比較return this.name.compareTo(o.name);//甚至可以通過名字進(jìn)行排序}public Student(String name, int age, double score) {this.name = name;this.age = age;this.score = score;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", score=" + score +'}';} } public class demo {public static void main(String[] args) {Student student=new Student("haha",24,55);Student student1=new Student("heihei",20,89);System.out.println(student.compareTo(student1));} }我們甚至可以利用這個(gè)接口對(duì)更多個(gè)數(shù)組排序,實(shí)現(xiàn)這個(gè)接口之后,利用Arrays.sort()進(jìn)行排序
public static void main(String[] args) {Student[] students =new Student[3];students[0]=new Student("zhan",21,98);students[1]=new Student("hehe",17,87);students[2]=new Student("keke",34,99);Arrays.sort(students);System.out.println(Arrays.toString(students));}這個(gè)類存在一定的缺點(diǎn),對(duì)于類的侵害性大,所以下面我們?cè)诮榻Bcomparator接口
4.2 comparator接口
先創(chuàng)立一個(gè)學(xué)生類
class Student {public String name;public int age;public double score;public Student(String name, int age, double score) {this.name = name;this.age = age;this.score = score;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", score=" + score +'}';} }創(chuàng)立一個(gè)年齡比較器
class AgeComparator implements Comparator<Student>{@Overridepublic int compare(Student o1, Student o2) {return o1.age-o2.age;} }創(chuàng)立一個(gè)分?jǐn)?shù)比較器
//成績比較器 class ScoreComrarator implements Comparator<Student>{@Overridepublic int compare(Student o1, Student o2) {return (int)(o1.score-o2.score);} }創(chuàng)立一個(gè)名字比較器
//名字比較器 class NameComparator implements Comparator<Student>{@Overridepublic int compare(Student o1, Student o2) {return o1.name.compareTo(o2.name);} }做完上面幾步之后,我們基本就可以實(shí)現(xiàn)一個(gè)(年齡,成績,名字)來排序
比較分?jǐn)?shù)
public class demo {public static void main1(String[] args) {Student student=new Student("haha",24,55);Student student1=new Student("heihei",20,89);ScoreComrarator scoreComrarator=new ScoreComrarator();scoreComrarator.compare(student1,student);} }比較多個(gè)數(shù)組的一個(gè)成績
public class demo {public static void main(String[] args) {Student[] students =new Student[3];students[0]=new Student("zhan",21,98);students[1]=new Student("hehe",17,87);students[2]=new Student("keke",34,99);ScoreComrarator scoreComrarator=new ScoreComrarator();Arrays.sort(students,scoreComrarator);System.out.println(Arrays.toString(students));} }4.3 clonable接口和深拷貝
4.3.1 淺拷貝
class people{public int age; } public class apple {public static void main(String[] args) {people people=new people();people people1=people;System.out.println(people);System.out.println(people1);} }??也就是所淺拷貝就是簡單來理解就是會(huì)有兩個(gè)引用公用了一個(gè)對(duì)象。
4.3.2 深拷貝與clonable接口
class people implements Cloneable {public int age;@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();} } public class apple {public static void main(String[] args)throws CloneNotSupportedException {people people=new people();people people1=(people) people.clone();System.out.println(people);System.out.println(people1);} }?所謂的深拷貝簡單理解就是一個(gè)引用對(duì)應(yīng)單獨(dú)一個(gè)對(duì)象
4.3.3 clonable使用要點(diǎn):
1 clonable接口源碼是不包含任何抽象方法的,是一個(gè)空接口,對(duì)于這個(gè)空接口的作用就是表示當(dāng)前類是可以被克隆的。
2 對(duì)于clone方法結(jié)合clonable我們必須要在實(shí)現(xiàn)接口中重寫方法。
3 由于clone源碼是一個(gè)object類,所以這里我們必須進(jìn)行類型強(qiáng)轉(zhuǎn)。
4 實(shí)現(xiàn)clone接口中需要我們拋異常,這個(gè)在后續(xù)的學(xué)習(xí)中,我們會(huì)講解異常。
淺拷貝與深拷貝的詳細(xì)理解參考這篇文章:
Java深入理解深拷貝和淺拷貝區(qū)別_riemann_的博客-CSDN博客_java深拷貝和淺拷貝的區(qū)別
總結(jié)
以上是生活随笔為你收集整理的面向对象——多态,抽象类,接口(二)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 详解单链表经典OJ题
- 下一篇: java中异常处理机制