本次课程我们来主要讲解一下抽象类以及接口,本期知识点在Java基础学习中非常重要,尤其是接口在今后的编程生涯中,这些知识点将会一直陪伴你,所以没有在这方面学习精通的同学记得要抓紧时间复习呀。
上期知识点:
学习教程推荐:
- 1.北京高淇Java300集(Java强烈推荐)
Java300集零基础适合初学者视频教程_Java300集零基础教程_Java初学入门视频基础巩固教程_Java语言入门到精通 - 2.JavaSE基础全套-从零开始进阶之大神(推荐)
系统教学JavaSE基础全套课程-从0开始进阶至大神_线下录制Java系列课程Java从入门到精通_/JAVA基础/数组/OOP/集合/IO流_ - 3.Java常用类基础实战
【基础夯实】Java常用类实战基础教程_Java八大常用类核心基础_Java常用类基础入门/Java包装类/String类 - 4.Java基础入门必备数学知识【数据结构与算法】(推荐)
Java基础入门必学知识数据结构与算法_Java数据结构与算法基础到进阶/Java基础入门进阶/Java数据结构分析/Java数据结构常见问题_哔哩哔哩_bilibili - 5.Java面向对象编程_OOP基础深入讲解
Java面向对象编程重基础深入讲解_OOP面向对象Java基础干货分享/JavaSE/面向对象编程/OOP程序设计 - 6.GOF23种设计模式-23中设计模式详解课程
GOF23种设计模式讲解_Java gof23种设计模式详解课程_从单例到备忘录模式 23种模式详解
一、知识点:final关键字
final关键字的作用:
final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字。另外,Java中的String类就是一个final类。
- 修饰变量: 被他修饰的变量不可改变。一旦赋了初值,就不能被重新赋值。
final int MAX_SPEED = 120; - 修饰方法:该方法不可被子类重写。但是可以被重载!
final void study(){} - 修饰类: 修饰的类不能被继承。比如:Math、String、System等。
final class A {}
了解以上使用“final关键字”,模拟实现Math类:
模拟实现Math类
public final class Maths {
private Maths(){
}
public static final double PI = 3.14159;
public static final double pow(int x,int y){
double result = 1;
for(int i=0;i<y;i++){
result *= x;
}
return result;
}
public static double abs(double num ){
if(num >=0){
return num;
}else{
return -num;
}
}
}
再次提醒注意:
- 注意:final不能修饰构造方法
- final修饰基本数据类型,值只能赋值一次,后续不能再赋值
- final修饰引用数据类型,final Dog dog = new Dog("亚亚");,不能变化的引用变量的值,可以变化的是对象的属性
示例练习:final关键字修饰引用变量
public class Dog {
String name;
public Dog(String name){
this.name = name;
}
}
public class Test2 {
public static void main(String[] args) {
//final int NUM = 5;
final int NUM;
NUM = 5;
// NUM = 6;
System.out.println(NUM);
//final Dog dog = new Dog();
final Dog dog;
dog = new Dog("丫丫");
dog.name = "欧欧";
//dog = new Dog("菲菲");
}
}
二、抽象类:
·抽象方法
使用abstract修饰的方法,没有方法体,只有声明。定义的是一种“规范”,就是告诉子类必须要给抽象方法提供具体的实现。
·抽象类
使用abstract修饰的类。通过abstract方法定义规范,然后要求子类必须定义具体实现。通过抽象类,我们就可以做到严格限制子类的设计,使子类之间更加通用。
问题1:
Animal an = new Animal();没有一种动物,名称是Animal,所以Animal不能被实例化
解决:抽象类
问题2:
子类必须重写父类的某个方法,否则出现编译错误
解决:抽象方法
抽象类和抽象方法-代码示例:
public abstract class Animal {
private String color;
public Animal() {
}
public Animal(String color) {
this.color = color;
}
public abstract void shout();
public abstract void eat();
public String toString() {
return "Animal{"color='" + color + '\'' + '}';
}
}
public class Dog extends Animal {
private String nickName;
public Dog() {
}
public Dog(String color, String nickName) {
super(color);
this.nickName = nickName;
}
public void shout() {
System.out.println("旺旺旺");
}
public void eat() { }
public String toString() {
return "Dog{nickName='" + nickName + '\'' +"} " + super.toString();
}
}
抽象类主要要点:
1.有抽象方法的类只能定义成抽象类
2.抽象类不能实例化,即不能用new来实例化抽象类。
3.抽象类必须有构造方法,创建子类对象的时候使用
4.一个抽象类至少0个抽象方法,至多(所有的方法都是抽象方法)个抽象方法
5.子类必须重写父类的抽象方法,不重写就提示编译错误;或者子类也定义为抽象类
6.override 重写 implements 实现
父类的方法是抽象的,需要子类实现;父类的方法不是抽象的,子类可以重写
三、接口
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是…则必须能…”的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。
接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。
接口的声明格式:
[访问修饰符] interface 接口名 [extends 父接口1,父接口2…] {
常量定义;
方法定义;
}
定义接口的详细说明:
- 访问修饰符:只能是public或默认。
- 接口名:和类名采用相同命名机制。
- extends:接口可以多继承。
- 常量:接口中的属性只能是常量,总是:public static final 修饰。不写也是。
- 方法:接口中的方法只能是:public abstract。 省略的话,也是public abstract。
接口需要注意的点:
- 子类通过implements来实现接口中的规范。
- 接口不能创建实例,但是可用于声明引用变量类型。
- 一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是public的。
- JDK1.8(不含8)之前,接口中只能包含静态常量、抽象方法,不能有普通属性、构造方法、普通方法。
- JDK1.8(含8)后,接口中包含普通的静态方法、默认方法。
编写需求-训练接口:
需求:飞机、鸟、超人,导弹参加飞行表演。
思路1:定义一个父类Flyable,让飞机、鸟、超人,导弹都继承该类。不可以,因为继承表达的是is-a的关系,而飞机、鸟、超人不是一种事物,
思路2:使用接口,定义一个接口Flyable,让飞机、鸟、超人,导弹都实现该接口。接口表达是has-a的关系
代码示例:定义Flyable 接口:
public interface Flyable {
//接口中只有常量,没有变量。常量都是全局静态常量
public static final int NUM = 5;
/**
* 飞行
* 接口的方法自动采用public abstract修饰。
* 所有方法都是全局抽象方法(<JDK1.8之前)
*/
public abstract void fly();
}
代码示例:实现Flyable 接口:
public class Plane implements Flyable {
@Override
public void fly() {
System.out.println("飞机在平流层平稳的飞行");
}
}
public class Animal {
}
public class Bird extends Animal implements Flyable{
@Override
public void fly() {
System.out.println("鸟儿在空中展翅飞翔");
}
}
public class SuperMan implements Flyable {
@Override
public void fly() {
System.out.println("超人能飞多高呢?");
}
}
示例:测试Flyable 接口:
public class Test {
public static void main(String[] args) {
//new Flyable();
//Flyable.num = 6;
Flyable plane = new Plane();
showFly(plane);
Bird bird = new Bird();
showFly(bird);
SuperMan sm = new SuperMan();
showFly(sm);
Flyable bird3 = new Plane();
bird3.fly();
Eatable eatable = (Eatable)bird3;
eatable.eat();
}
public static void showFly(Flyable fly){
fly.fly();
}
}
总结1:接口的组成
- 接口和数组、类、抽象类是同一个层次的概念
- 成员变量:接口中所有的变量都使用public static final修饰,都是全局静态常量
- 成员方法: 接口中所有的方法都使用public abstract修饰,都是全局抽象方法
- 构造方法:接口不能new,也没有构造方法
- 接口做方法的形参,实参可以该接口的所有实现类
总结2:接口和多继承
C++ 多继承
好处 :可以从多个父类继承更多的功能
缺点:不安全 有两个父类Father1,Father2,都有一个方法giveMoney(),子类如果重写了,没有问题,如果子类没有重写,调用giveMoney()是谁的
Java 单继承
好处:安全
缺点:功能受限
解决方案:既安全,功能又强大,采用接口。接口变相的使Java实现了C++的多继承,又没有C++多继承的不安全性
public class Bird extends Animal implements Flyable,Sleepable
必须先extends 再implements
四、接口应用:内部比较器Comparable
图书类、学生类、新闻类、商品类等是不同的类,可是却都需要有比较的功能,怎么办?共同的父类不可以,可以定义一个比较接口Comparable,其中定义一个实现比较的方法compareTo(Object obj)。让各个类实现该接口即可。Java中就是这么来实现的,下面就来模拟实现一下Comparable接口吧。
【示例】定义Comparable接口:
public interface Comparable {
/**
* 判断两个对象的大小
* @param obj 另外一个对象
* @return
* > 0 正数 大于
* =0 等于
* <0 负数 小于 *
*/
public int compareTo(Object obj);
}
【示例】实现Comparable接口:
public class Book implements Comparable{
private String bookName;//书名
private String author;//作者
private String publisher;//出版社
private double price;//
@Override
public int compareTo(Object obj) {
Book other =(Book)obj;
//return this.bookName.compareTo(other.bookName);//""
if(this.price>other.price){
return 1;
} else if (this.price < other.price) {
return -1;
}else{
return 0;
}
}
public Book(String bookName, String author, String publisher, double price){
this.bookName = bookName;
this.author = author;
this.publisher = publisher;
this.price = price;
}
}
public class Person implements Comparable{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Object obj) {
Person other = (Person)obj;
return this.age - other.age ;
}
}
【示例】测试Comparable接口:
public class Test {
public static void main(String[] args) {
Book book1 = new Book("倚天屠龙记","金庸","清华大学出版社",35);
Book book2 = new Book("倚天屠龙记","金庸","清华大学出版社",31);
//book1.equals(book2)
int result = book1.compareTo(book2);
System.out.println(result);
Person person1 = new Person("张三",24);
Person person2 = new Person("李四",24);
result = person1.compareTo(person2);
System.out.println(result);
}
}
五、JDK1.8的接口新特征:
JDK7及其之前:
接口的变量都是public final static 全局静态常量,无变化
接口中都是抽象abstract方法,不能有static方法(因为abstract和static、final、private不能共存)
JDK1.8及其之后:
- 接口中可以添加非抽象方法(static),实现类不能重写,只能通过接口名调用。
- 如果子类中定义了相同名字的静态方法,那就是完全不同的方法了,直接从属于子类。可以通过子类名直接调用
- 接口中可以添加非抽象方法(default),实现类可以重写,只能通过对象名调用
- 实现类可以直接使用default方法,可以重写default方法,但是必须去掉default。(default只能接口中使用)
- 上级接口中default方法的调用:MyInterface.super.method2()
提供非抽象方法的目的
- 为了解决实现该接口的子类代码重复的问题
- 为了既有的成千上万的Java类库的类增加新功能,且不必对这些类重新进行设计。比如只需在Collection接口中增加default Stream<E> stream(),相应的Set和List接口以及它们的子类都包含此的方法,不必为每个子类都重新copy这个方法。
【代码示例】JDK8的接口新特征:
public interface MyInterface {
public static final double PI = 3.14;
public abstract void method1();
public static void method2(){
System.out.println("JDK1.8中的非抽象方法有两种,一种是static的");
}
public default void method3(){
System.out.println("JDK1.8中的非抽象方法有两种,一种是default的");;
}
public static void main(String[] args) {
MyInterface.method2();
}
}
public class MyClass implements MyInterface {
public void method1() {
System.out.println("接口中的抽象方法,子类必须实现");
}
public void method3(){
MyInterface.method2();
MyInterface.super.method3();
System.out.println("重写接口的default方法,须将default去掉");
}
public static void main(String[] args) {
MyInterface mi = new MyClass();
mi.method1();
MyInterface.method2();
mi.method3();
}
}
六、面向接口编程:
面向接口编程是面向对象编程的一部分。
为什么需要面向接口编程? 软件设计中最难处理的就是需求的复杂变化,需求的变化更多的体现在具体实现上。我们的编程如果围绕具体实现来展开就会陷入”复杂变化”的汪洋大海中,软件也就不能最终实现。我们必须围绕某种稳定的东西开展,才能以静制动,实现规范的高质量的项目。
接口就是规范,就是项目中最稳定的核心! 面向接口编程可以让我们把握住真正核心的东西,使实现复杂多变的需求成为可能。
通过面向接口编程,而不是面向实现类编程,可以大大降低程序模块间的耦合性,提高整个系统的可扩展性和和可维护性。
面向接口编程的概念比接口本身的概念要大得多。设计阶段相对比较困难,在你没有写实现时就要想好接口,接口一变就乱套了,所以设计要比实现难!
接口语法本身非常简单,但是如何真正使用?这才是大学问。我们需要后面在项目中反复使用,大家才能体会到。
学到此处,能了解基本概念,熟悉基本语法,就已经是非常棒的咯。 请继续努力!再请工作后,闲余时间再看看上面这段话,相信你会有更深的体会。