【Java SE系列】抽象类与接口

编程入门 行业动态 更新时间:2024-10-26 20:34:53

【Java SE系列】抽象类与<a href=https://www.elefans.com/category/jswz/34/1771365.html style=接口"/>

【Java SE系列】抽象类与接口

内容介绍

  • 1 抽象类
    • 1.1 语法规则
    • 1.2 抽象类的作用
  • 2 接口
    • 2.1 语法规则
    • 2.2 接口使用实例
    • 2.3 克隆接口

1 抽象类

1.1 语法规则

在之前的打印图形例子中, 我们发现, 父类 Shape 中的 draw 方法好像并没有什么实际工作, 主要的绘制图形都是由Shape 的各种子类的 draw 方法来完成的. 像这种没有实际工作的方法, 我们可以把它设计成一个 抽象方法(abstractmethod), 包含抽象方法的类我们称为抽象类(abstract class).

abstract class Shape { abstract public void draw(); 
}
  • 在 draw 方法前加上 abstract 关键字, 表示这是一个抽象方法. 同时抽象方法没有方法体(没有 { }, 不能执行具体代码).
  • 对于包含抽象方法的类, 必须加上 abstract 关键字表示这是一个抽象类.

注意事项

  1. 抽象类不能实例化

    2.抽象方法不能是 private 的()

3.抽象类中可以包含其他的非抽象方法, 也可以包含字段. 这个非抽象方法和普通方法的规则都是一样的, 可以被重写,也可以被子类直接调用.(抽象类除了包含抽象方法和不能实例化之外和普通类相似
4.final修饰的抽象方法也不能被重写,因为final修饰就代表方法不能进行修改即不能重写.

🔑打印图形栗子:

abstract class Printf{String name = "ant";abstract public  void printf();
}
class Rect extends Printf{@Overridepublic void printf() {System.out.println("△");}}
class Cur extends Printf{@Overridepublic void printf() {System.out.println("○");}}
class Flower extends Printf{@Overridepublic void printf() {System.out.println("❀");}
}
public class Test {public static void printY(Printf pintf){pintf.printf();}public static void main(String[] args) {printY(new Cur());printY(new Rect());printY(new Flower());}
}

1.2 抽象类的作用

抽象类存在的最大意义就是为了被继承.
抽象类本身不能被实例化, 要想使用, 只能创建该抽象类的子类. 然后让子类重写抽象类中的抽象方法.
使用抽象类的场景就如上面的代码, 实际工作不应该由父类完成, 而应由子类完成. 那么此时如果不小心误用成父类了,使用普通类编译器是不会报错的. 但是父类是抽象类就会在实例化的时候提示错误, 让我们尽早发现问题.

💡小知识:
使用抽象类相当于多了一重编译器的校验.

2 接口

接口是抽象类的更进一步. 抽象类中还可以包含非抽象方法, 和字段. 而接口中包含的方法都是抽象方法, 字段只能包含静态常量.

2.1 语法规则

我们仍然通过打印图案的栗子来看:

interface Printf{public static final String name = "ant";abstract public  void printf();
}
class Rect implements Printf{@Overridepublic void printf() {System.out.println("△");}}
class Cur implements Printf{@Overridepublic void printf() {System.out.println("○");}}
class Flower implements Printf{@Overridepublic void printf() {System.out.println("❀");}
}
public class Test {public static void printY(Printf printf){printf.printf();}public static void main(String[] args) {printY(new Cur());printY(new Rect());printY(new Flower());}
}

💡知识点:
接口中的方法一定是抽象方法, 因此可以省略 abstract。
接口中的方法一定是 public, 因此可以省略 public。
接口中可以有static方法。
抽象方法默认是public abstract的
接口中成员变量默认是public static final修饰的
在调用的时候同样可以创建一个接口的引用, 对应到一个子类的实例。
接口不能单独被实例化
当一个类实现了一个接口后,重写方法必须加上public。
一个类可以通过关键字extends继承一个抽象类或普通类,但是只能继承一个类,同时可以通过implement实现多个接口,接口之间用逗号隔开。

🐾我们来看一个错误案例:

interface IShape {abstract void draw() ; // 即便不写public,也是public 
}
class Rect implements IShape {void draw() {System.out.println("□") ; //权限更加严格了,所以无法覆写。}
}

这里报错就是因为接口中方法默认是public的,而Rect中的draw方法是包访问修饰符修饰的,作用范围比public小,由于重写方法的作用范围要大于等于父类的方法,所以程序就报错了。

2.2 接口使用实例

接下来我们用接口来实现给对象数组排序
方法一:实现Comparator接口

Comparator接口中含有比较方法,所以我们只需要创建几个类然后实现Comparator接口并重写compara方法就能实现排序功能。

💫代码实现:

package demo3;import java.util.Arrays;
import java.util.Comparator;/*** Created with IntelliJ IDEA.* Description:* User: admin* Date: 2021-11-13* Time: 下午5:11*/
class Student {String name;int age;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 +'}';}/* @Overridepublic int compareTo(Student o) {return (this.age-o.age);}*/}
class AgeComparator implements Comparator<Student>{@Overridepublic int compare(Student o1, Student o2) {return o1.age-o2.age;}
}
class NameComparator implements Comparator<Student>{@Overridepublic int compare(Student o1, Student o2) {return o1.name.compareTo(o2.name);}
}
class ScoreComparator implements Comparator<Student>{@Overridepublic int compare(Student o1, Student o2) {return (int)(o1.score-o2.score);}
}
public class Test {public static void main(String[] args) {Student[] student = new Student[3];student[0] = new Student("zhangsan",12,98.9);student[1] = new Student("lisi",6,95.9);student[2] = new Student("wangwu",18,88.9);AgeComparator ageComparator = new AgeComparator();NameComparator nameComparator = new NameComparator();ScoreComparator scoreComparator = new ScoreComparator();System.out.println(Arrays.toString(student));Arrays.sort(student,ageComparator);System.out.println(Arrays.toString(student));Arrays.sort(student,nameComparator);System.out.println(Arrays.toString(student));Arrays.sort(student,scoreComparator);System.out.println(Arrays.toString(student));}
}


方法一:实现Comparable接口

在 sort 方法中会自动调用 compareTo 方法.所以我们只需要在Student类中实现Comparable接口并重写compara To方法即可实现排序。

package demo3;import java.util.Arrays;
import java.util.Comparator;/*** Created with IntelliJ IDEA.* Description:* User: admin* Date: 2021-11-13* Time: 下午5:11*/
class Student implements Comparable<Student>{String name;int age;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 +'}';}@Overridepublic int compareTo(Student o) {return this.age-o.age;}
}
public class Test {public static void main(String[] args) {Student[] student = new Student[3];student[0] = new Student("zhangsan",12,98.9);student[1] = new Student("lisi",6,95.9);student[2] = new Student("wangwu",18,88.9);System.out.println(Arrays.toString(student));Arrays.sort(student);System.out.println(Arrays.toString(student));}
}

注意:
实现Comparable接口有个局限性,即只能排序指定的类型,若要根据其他规则去排序则需要重新修改compara To函数的内容。

2.3 克隆接口

前面我们已经知道创建对象的方法有new,克隆的方式就是第二种创建对象的方式。

Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 “拷贝”. 但是要想合法调用 clone 方法, 必须要先实现 Clonable 接口, 否则就会抛出CloneNotSupportedException 异常.

代码实现:

/*** Created with IntelliJ IDEA.* Description:* User: admin* Date: 2021-11-18* Time: 下午7:36*/
class Person implements Cloneable{int age;public Person(int age) {this.age = age;}@Overridepublic String toString() {return "Person{" +"age=" + age +'}';}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
public class Test {public static void main(String[] args)throws CloneNotSupportedException {Person person = new Person(20);Person person1 = (Person) person.clone();System.out.println(person.age);System.out.println(person1.age);}
}

注意:
1.类必须要实现克隆接口才能进行克隆
2.类中必须要重写clone方法
3.主函数中必须要进行异常抛出
4.当前克隆属于浅拷贝(不会克隆引用指向的对象)后面会实现深拷贝的克隆


深拷贝克隆实现:

class Money implements Cloneable{int num = 10;@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
class Person extends Money implements Cloneable{int age;Money money = new Money();@Overridepublic String toString() {return "Person{" +"age=" + age +'}';}@Overrideprotected Object clone() throws CloneNotSupportedException {Person tep = (Person) super.clone();tep.money = (Money)super.clone();return tep;}
}
public class Test {public static void main(String[] args)throws CloneNotSupportedException {Person person = new Person();Person person1 = (Person) person.clone();person1.money.num = 13;System.out.println(person.money.num);System.out.println(person1.money.num);}
}

此时Person和Person1中的money引用指向不同的对象。

小知识:
深拷贝浅拷贝不是方法自带,是看编程人员如何去设计的。

总结:
1.抽象类可以有普通成员函数,接口一般只存在public abstract方法(jdk1.8中接口也可以有静态方法)。
2.抽象类中的成员变量可以是各种类型的,接口中只能是public static final类型。
3.抽象类只能继承一个,接口可以实现多个。
4.抽象类和接口都不能实例化。
5.抽象类不一定有抽象方法(但是声明为抽象类没有抽象方法也不能实例化),但是包含抽象方法的类一定为抽象类。
6.抽象类是对类本质的抽象,表达的是 is a的关系,抽象类包含并实现子类的通用特性,将子类存在差异化的地方进行抽象,交给子类去实现。
7.接口是对行为的抽象,表达的是 like a的关系,比如鸟可以像飞行器一样飞,但是其本质还是鸟。接口的核心是定义行为即功能,也就是实现类可以做什么,至于主体是谁、如何实现接口都不关心。

作者水平有限,若文章有任何问题欢迎私聊或留言,希望和大家一起学习进步!!!
创作不易,再次希望大家👍支持下,谢谢大家🙏

更多推荐

【Java SE系列】抽象类与接口

本文发布于:2023-06-13 09:33:22,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/678972.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:接口   系列   抽象类   Java   SE

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!