柚子快報(bào)邀請(qǐng)碼778899分享:開(kāi)發(fā)語(yǔ)言 【Java】接口詳解
柚子快報(bào)邀請(qǐng)碼778899分享:開(kāi)發(fā)語(yǔ)言 【Java】接口詳解
接口是抽象類的更進(jìn)一步. 抽象類中還可以包含非抽象方法, 和字段. 而接口中包含的方法都是抽象方法, 字段只能包含靜態(tài)常量。
一個(gè)簡(jiǎn)單的接口代碼示例
interface IShape {
void draw();
}
class Cycle implements IShape {
@Override
public void draw() {
System.out.println("○");
}
}
public class Data {
public static void main(String[] args) {
IShape shape = new Rect();
shape.draw();
}
}
定義接口的注意事項(xiàng):
使用 interface 定義一個(gè)接口接口中的方法一定是抽象方法, 因此可以省略 abstract接口中的方法一定是 public, 因此可以省略 publicCycle 使用 implements 繼承接口. 此時(shí)表達(dá)的含義不再是 "擴(kuò)展", 而是 "實(shí)現(xiàn)"在調(diào)用的時(shí)候同樣可以創(chuàng)建一個(gè)接口的引用, 對(duì)應(yīng)到一個(gè)子類的實(shí)例.接口不能單獨(dú)被實(shí)例化
定義一個(gè)完整的接口是這樣的:
interface Ishape{
? ? ? ? public static final int num = 10;
? ? ? ? public abstruct void draw();
}
?但是嚴(yán)格來(lái)說(shuō)我們?cè)诙x一個(gè)接口的時(shí)候通常會(huì)省略? public static final 和?public abstruct ,在我們定義接口的時(shí)候里面的變量和方法會(huì)自動(dòng)加上。
省略之后的寫(xiě)法:
interface Ishape{
? ? ? ? ?int num = 10;
? ? ? ? ?void draw();
}
實(shí)現(xiàn)多個(gè)接口
?有的時(shí)候我們需要讓一個(gè)類同時(shí)繼承自多個(gè)父類. 這件事情在有些編程語(yǔ)言通過(guò) 多繼承 的方式來(lái)實(shí)現(xiàn)的.然而 Java 中只支持單繼承, 一個(gè)類只能 extends 一個(gè)父類. 但是可以同時(shí)實(shí)現(xiàn)多個(gè)接口, 也能達(dá)到多繼承類似的效果。
代碼示例:
interface Ifly{
void fly();
}
interface Irunning{
void running();
}
interface Iswimming{
void swimming();
}
abstract class Animal{
public String name;
public int age;
public Animal(String name,int age){
this.name = name;
this.age = age;
}
abstract public void eat();
}
class Dog extends Animal implements Iswimming , Irunning{
public Dog(String name,int age){
super(name,age);
}
@Override
public void running() {
System.out.println(this.name + "正在跑");
}
@Override
public void swimming() {
System.out.println(this.name + "正在游泳");
}
@Override
public void eat() {
System.out.println(this.name + "正在吃狗糧");
}
}
public class Data{
public static void test1(Animal animal){
animal.eat();
}
public static void test2(Ifly ifly){
ifly.fly();
}
public static void test3(Iswimming iswimming){
iswimming.swimming();
}
public static void test4(Irunning irunning){
irunning.running();
}
public static void main(String[] args) {
test1(new Dog("小黃" ,20));
test3(new Dog("小黃" ,20));
test4(new Dog("小黃" ,20));
}
}
上面的代碼展示了 Java 面向?qū)ο缶幊讨凶畛R?jiàn)的用法: 一個(gè)類繼承一個(gè)父類, 同時(shí)實(shí)現(xiàn)多種接口。
在這個(gè)代碼中我們定義了三個(gè)接口:Ifly 、Irunning 、Iswimming 。一個(gè)抽象類:Animal 。然后定義了一個(gè)類來(lái)繼承這個(gè)抽象類并且實(shí)現(xiàn)了兩個(gè)接口。
上述代碼運(yùn)行結(jié)果:
接口的常見(jiàn)使用案例
Comparable接口
?給對(duì)象數(shù)組排序
代碼示例:
class Student implements Comparable
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
@Override
public String toString() {
return "[" + this.name + ":" + this.score + "]";
}
@Override
public int compareTo(Student o) {
return this.score - o.score;
}
}
public class Data{
public static void main(String[] args) {
Student[] student = {
new Student("小明",87),
new Student("小黃",94),
new Student("小李",89)};
Arrays.sort(student);
System.out.println(Arrays.toString(student));
}
}
在這個(gè)代碼中我們定義了一個(gè) Student 類:
class Student { private String name; private int score; public Student(String name, int score) { this.name = name; this.score = score; } @Override public String toString() { return "[" + this.name + ":" + this.score + "]"; } }
?然后用這個(gè)類創(chuàng)建了一個(gè)數(shù)組:
Student[] student = {
new Student("小明",87),
new Student("小黃",94),
new Student("小李",89)};
接著我們給 Student 類實(shí)現(xiàn)接口 Comparable
上述代碼的運(yùn)行結(jié)果:
?注意事項(xiàng): 對(duì)于 sort 方法來(lái)說(shuō), 需要傳入的數(shù)組的每個(gè)對(duì)象都是 "可比較" 的, 需要具備 compareTo 這樣的能力. 通過(guò)重寫(xiě) compareTo 方法的方式, 就可以定義比較規(guī)則。
Comparator接口
另外一種比較一個(gè)類的兩個(gè)實(shí)例的方法:
代碼示例:
class Person implements Comparable
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Person o) {
return this.age - o.age;
}
}
class AgeComparator implements Comparator
@Override
public int compare(Person o1, Person o2) {
return o1.age - o2.age;
}
}
class NameComparator implements Comparator
@Override
public int compare(Person o1, Person o2) {
return o1.name.compareTo(o2.name);
}
}
public class Data{
public static void main(String[] args) {
Person p1 = new Person("小明",20);
Person p2 = new Person("小黃",30);
System.out.println(p1.compareTo(p2));
AgeComparator agecomparator = new AgeComparator();
System.out.println(agecomparator.compare(p1,p2));
NameComparator namecomparator = new NameComparator();
namecomparator.compare(p1,p2);
}
}
在這個(gè)代碼中我們?yōu)榱诉M(jìn)行比較,額外創(chuàng)建了一個(gè)類來(lái)實(shí)現(xiàn) Comparator 接口并且在該類里面重寫(xiě) compare 方法。
Clonable 接口
淺拷貝 VS 深拷貝
淺拷貝示例
代碼示例:
class Person implements Cloneable{
public int age;
public Person(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Data{
public static void main(String[] args) throws CloneNotSupportedException {
Person p1 = new Person(20);
Person p2 = (Person)p1.clone();
System.out.println(p1);
System.out.println(p2);
}
}
這里我們定義了一個(gè)類 Person 并且實(shí)現(xiàn)了接口 Cloneable 重寫(xiě)了方法 clone 。在測(cè)試類中我們將 p1 里面的內(nèi)容拷貝到了 p2 里面。
代碼運(yùn)行結(jié)果:
接著我們?cè)俣x一個(gè) Money 類:
class Money{
public double money = 19.9;
}
并且在 Person 類中使用這個(gè)類:
?
class Person implements Cloneable{
public int age;
public Money m = new Money();
public Person(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
?接著我們?cè)龠M(jìn)行拷貝,將 p1 里面的內(nèi)容拷貝到 p2 里面,然后我們改變 p2 里面的內(nèi)容,并且將其輸出:
很快我們就能看出一個(gè)問(wèn)題:改變 p2 里面的內(nèi)容,而 p1 里面的內(nèi)容也跟著改變了呢?
接著我們引入深拷貝的理念:
深拷貝示例
代碼示例:
class Money implements Cloneable{
public double money = 19.9;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Person implements Cloneable{
public int age;
public Money m = new Money();
public Person(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person tmp = (Person)super.clone();
tmp.m = (Money)this.m.clone();
return tmp;
}
}
public class Data{
public static void main(String[] args) throws CloneNotSupportedException {
Person p1 = new Person(20);
Person p2 = (Person)p1.clone();
System.out.println(p1.m.money);
System.out.println(p2.m.money);
p2.m.money = 99.9;
System.out.println(p1.m.money);
System.out.println(p2.m.money);
}
}
運(yùn)行結(jié)果:
我們發(fā)現(xiàn)我們剛剛提出的問(wèn)題被解決了。
這里我們改變了兩個(gè)地方:
1、 將 Money 類也實(shí)現(xiàn) Clonable 接口重寫(xiě) clone 方法,將其具備能被拷貝的能力。
class Money implements Cloneable{
public double money = 19.9;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
2、重寫(xiě) Person 類里面的 clone 方法。
?
protected Object clone() throws CloneNotSupportedException {
Person tmp = (Person)super.clone();
tmp.m = (Money)this.m.clone();
return tmp;
}
接口間的繼承
接口可以繼承一個(gè)接口, 達(dá)到復(fù)用的效果. 使用 extends 關(guān)鍵字。
interface IRunning {
void run();
}
interface ISwimming {
void swim();
}
interface IAmphibious extends IRunning, ISwimming {
void eat();
}
接口間的繼承相當(dāng)于把多個(gè)接口合并在一起。這里我們定義接口 Iamphibious 來(lái)繼承了接口 IRunning 和接口 ISwimming 。這樣該接口就有了另外兩個(gè)接口里面的抽象方法,并且該接口也可以定義另外的抽象方法。
總結(jié)
抽象類與接口的區(qū)別:
核心區(qū)別: 抽象類中可以包含普通方法和普通字段, 這樣的普通方法和字段可以被子類直接使用(不必重寫(xiě)), 而接口中不能包含普通方法, 子類必須重寫(xiě)所有的抽象方法。
柚子快報(bào)邀請(qǐng)碼778899分享:開(kāi)發(fā)語(yǔ)言 【Java】接口詳解
好文推薦
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。