java中的抽象类与接口(面试常考,重要)!!(一)

简介: java中的抽象类与接口(面试常考,重要)!!(一)

目录

抽象类

语法规则

注意事项(重要,全部掌握)

抽象类的作用

接口

语法规则

注意事项

提示

类实现多个接口

接口使用实例(Comparable 接口与Comparator接口)

Comparable接口

Comparator接口(比较器)

Comparable接口 与Comparator接口的区别

代码示例

接口间的继承(扩展)

总结

抽象类

语法规则

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

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

注意事项(重要,全部掌握)

抽象方法:一个方法如果被abstract修饰,那么这个方法就是抽象方法。抽象方法可以没有具体的实现。


同时抽象方法不能被private修饰,因为一旦被private修饰后,非抽象子类是不能重写父类私有的抽象方法的。


包含抽象方法的类称作抽象类,其必须被abstract所修饰,一个抽象类中可以没有抽象方法,但是如果一个类中有抽象方法,那么这个类一定是抽象类,其必须被abstract所修饰


抽象类不可以被实例化。不能使用例如Shape shape = new Shape();这样的语句

image.png

但是不影响抽象类发生向上转型,所以说抽象类不可以被实例化,但是可以发生向上转型.


类内的数据成员,和普通类没有区别,可以包含其他的非抽象方法, 也可以包含字段. 这个非抽象方法和普通方法的规则都是一样的, 可以被重写,也可以被子类直接调用


抽象类主要就是用来被继承的.


如果一个非抽象类继承了这个抽象类,那么这个类必须重写抽象类当中的所有的抽象方法。(重要)


当抽象类A 继承 抽象类B 那么A可以不重写B中的抽象方法,但是一旦A要是再被一个非抽象类c继承,那么c类中一定还要重写A中和B中的抽象方法.

代码示例:

abstract class A {
    abstract public void eat();
    public void drink() {
    }
}
abstract class C extends A {
    abstract public void fly();
}
class b extends C {
    @Override
    public void eat() {
        System.out.println("eat");
    }
    @Override
    public void fly() {
        System.out.println("fly");
    }
}

抽象类和抽象方法一定是不能被final修饰的,因为一旦类被final修饰,便不能继承,方法被final修饰,不能被重写

抽象类不能实例化的目的也就是为了继承和重写,所以两者不能同时使用

抽象类实现接口时,可以不需要对接口方法进行重写,即可以重写一部分,不重写一部分

抽象类有构造方法,但是不能使用,即不能创建具体的对象

抽象类的作用

 抽象类存在的最大意义就是为了被继承.

抽象类本身不能被实例化, 要想使用, 只能创建该抽象类的子类. 然后让子类重写抽象类中的抽象方法.

有些同学可能会说了, 普通的类也可以被继承呀, 普通的方法也可以被重写呀, 为啥非得用抽象类和抽象方法呢?

答:确实如此. 但是使用抽象类相当于多了一重编译器的校验.

使用抽象类的场景就如上面的代码, 实际工作不应该由父类完成, 而应由子类完成.

那么此时如果不小心误用成父类了, 使用普通类编译器是不会报错的. 但是父类是抽象类就会在实例化的时候提示错误, 让我们尽早发现问题.

很多语法存在的意义都是为了 “预防出错”, 例如我们曾经用过的 final 也是类似. 创建的变量用户不去修改, 不就相当于常量嘛? 但是加上 final 能够在不小心误修改的时候, 让编译器及时提醒我们.

充分利用编译器的校验, 在实际开发中是非常有意义的.


在实际开发中,抽象类的作用也是非常重要的:


抽象类可以降低接口实现类对接口实现过程难度,因为在实际开发中一个接口中可能会有很多接口是使用不到的,当一个非抽象类去继承这个接口的时候,就需要重写这个接口中的所有抽象方法,造成代码冗余,为了避免这种情况的发生,此时就需要抽象类将接口中不需要使用的抽象方法进行重写,将需要使用的抽象方法继承下来.

这样其他类只需要去继承不同的抽象类,依照自己业务的要求去寻找自己所需要的抽象类,然后对抽象类中的抽象方法进行重写就行了,从而降低了接口实现过程中的难度。

接口

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

语法规则

我们直接通过一段代码来进行总结:

1.interface Shape1 {  
 -    //接口中定义的成员变量都会被默认为常量,由public  static final默认进行修饰,所以就算不写public  static final也无所谓,  
 -    int a = 10;  
 -    public static final String name = "sss";  
 -  
 -    //接口中的方法几乎都为抽象方法,默认为public abstract进行修饰,所以就算不写public abstract也无所谓  
 -    void draw();  
 -  
 -    //当然接口中也可以定义非抽象方法,用default关键字即可,default是在java8中引入的关键字,具体可看csdn博客  
 -    default void drink() {  
 -        System.out.println("喝水");  
 -    }  
13.}  
 -  
15.class Cycle1 implements Shape1 {  
 -    @Override  
 -    public void draw() {  
 -        System.out.println("画一个⚪");  
 -    }  
 -  
21.}  
 -  
23.class React1 implements Shape1 {  
 -    @Override//注解  
 -    public void draw() {  
 -        System.out.println("画一个□");  
 -    }  
 -  
29.}  
 -  
31.public class TestMain {  
 -    public static void fun(Shape1 shape) {  
 -        shape.draw();  
 -    }  
 -  
 -    public static void main(String[] args) {  
 -        //接口也是可以发生向上转型的,前提是一个类必须实现了这个接口  
 -        //例如下面的代码,因为Cycle1类实现了Shape1这个接口,所以此时接口类型的shape引用可以指向Cycle1类的实例了  
 -        Shape1 shape = new Cycle1();  
 -        Shape1 shape1=new React1();  
 -        shape.draw();  
 -        shape1.draw();  
 -    }  
44.}  

使用 interface 定义一个接口

接口中的方法一定是抽象方法, 因此可以省略 abstract

接口中的方法一定是 public,因此可以省略 public

Cycle 使用 implements 继承接口. 此时implements表达的含义不再是 “扩展”, 而是 “实现”

在调用的时候同样可以创建一个接口的引用, 对应到一个子类的实例.

接口不能单独被实例化.

注意事项

接口当中的方法都是抽象方法。其默认前缀为public abstract,在书写时是可以省略的,因为编译器默认这个方法就是 public abstract

抽象类其实可以有具体实现的方法。这个方法是被default修饰的(JDK1.8加入的)

接口当中只能包含静态常量,所有常量的前缀全部默认为public static

final,在书写时是可以省略的,因为编译器默认这个成员变量就是public static final

接口当中的成员变量默认是:public static final 成员方法是:public abstract

接口是不可以被实例化的。 Shape shape = new Shape();(不允许)

接口和类之间的关系 : implements(实现),当一个非抽象类实现了这个接口且接口中有抽象方法时,则这个类必须重写接口中的所有抽象方法,如果这个类是抽象类,则可以不实现接口中的所有方法,因为抽象类中允许有抽象方法的存在

接口的出现是为了实现多继承.一个类可以实现多个接口。但是只能继承一个父类

只要这个类 实现了该接口,那么就可以进行向上转型。

当然一个接口也可以去继承(扩展)多个接口

扩展(extends)与实现(implements)的区别

扩展指的是当前已经有一定的功能了, 进一步扩充功能.

实现指的是当前啥都没有, 需要从头构造出来.

提示

1.我们创建接口的时候, 接口的命名一般以大写字母 I 开头.

2.接口的命名一般使用 “形容词” 词性的单词.

3.阿里编码规范中约定, 接口中的方法和属性不要加任何修饰符号, 保持代码的简洁性.

不加任何修饰符号的意思就是常量省略public static final ,抽象方法省略前缀public abstract

一个错误的代码:

interface IShape {
    // 即便不写public,也是默认为public权限
    abstract void draw();
}
class Rect implements IShape {
    void draw() {
        //权限更加严格了,所以无法覆写。意思就是Rect类中重写draw方法时必须加上public才可以
        System.out.println("□");
    }
}

image.png

类实现多个接口

有的时候我们需要让一个类同时继承自多个父类. 这件事情在有些编程语言通过 多继承 的方式来实现的.

然而 Java 中只支持单继承, 一个类只能 extends 一个父类. 但是可以同时实现多个接口, 也能达到多继承类似的效果. 现在我们通过类来表示一组动物.

class Animal {
    protected String name;
    public Animal(String name) {
        this.name = name;
    }
}

另外我们再提供一组接口, 分别表示 “会飞的”, “会跑的”, “会游泳的”.

interface IFlying {
    void fly();
}
interface IRunning {
    void run();
}
interface ISwimming {
    void swim();
}

接下来我们创建几个具体的动物
猫, 是会跑的.

class Cat extends Animal implements IRunning {
    public Cat(String name) {
        super(name);
    }
    @Override
    public void run() {
        System.out.println(this.name + "正在用四条腿跑");
    }
}

鱼, 是会游的.

class Fish extends Animal implements ISwimming {
    public Fish(String name) {
        super(name);
    }
    @Override
    public void swim() {
        System.out.println(this.name + "正在用尾巴游泳");
    }
}

青蛙, 既能跑, 又能游(两栖动物)

class Frog extends Animal implements IRunning, ISwimming {
    public Frog(String name) {
        super(name);
    }
    @Override
    public void run() {
        System.out.println(this.name + "正在往前跳");
    }
    @Override
    public void swim() {
        System.out.println(this.name + "正在蹬腿游泳");
    }
}

有一种神奇的动物, 水陆空三栖, 叫做 “鸭子”

class Duck extends Animal implements IRunning, ISwimming, IFlying {
    public Duck(String name) {
        super(name);
    }
    @Override
    public void fly() {
        System.out.println(this.name + "正在用翅膀飞");
    }
    @Override
    public void run() {
        System.out.println(this.name + "正在用两条腿跑");
    }
    @Override
    public void swim() {
        System.out.println(this.name + "正在漂在水上");
    }
}

上面的代码展示了 Java 面向对象编程中最常见的用法: 一个类继承一个父类, 同时实现多种接口.

继承表达的含义是 is - a 语义, 而接口表达的含义是 具有 xxx 特性 .猫是一种动物, 具有会跑的特性.

青蛙也是一种动物, 既能跑, 也能游泳

鸭子也是一种动物, 既能跑, 也能游, 还能飞


这样设计有什么好处呢? 时刻牢记多态的好处, 让程序猿忘记类型. 有了接口之后, 类的使用者就不必关注具体类型, 而只关注某个类是否具备某种能力.

例如, 现在实现一个方法, 叫 “散步”

public static void walk(IRunning running) {
        running.run();
}

在这个 walk 方法内部, 我们并不关注到底是哪种动物, 只要参数是会跑的,就行,此时需要注意的是这个会跑的前提是这个类必须实现了IRunning接口才可以

        //因为此时Cat类实现的是IRunning接口,所以此时可以使用向上转型如下所示,若没有实现IRunning接口,则会报错
        IRunning iRunning = new Cat("猫猫");
        walk(iRunning);
        //同样的因为此时Frog类实现的是IRunning接口,所以此时可以使用向上转型如下所示,若没有实现IRunning接口,同样会报错
        IRunning iRunning1 = new Frog("青蛙");
        walk(iRunning1);


相关文章
|
14小时前
|
Java 开发者 C++
Java面向对象的终极挑战:抽象类与接口的深度解析!
【6月更文挑战第17天】在Java OOP中,抽象类和接口助力代码复用与扩展。抽象类不可实例化,提供通用框架,适合继承;接口包含纯抽象方法,支持多态与松耦合。选择抽象类用于继承已有方法和状态,接口则适用于不相关类共享行为。Java 8后接口能含默认方法,增加设计灵活性。抽象类与接口常结合使用,以实现最佳设计,如`Shape`抽象类实现`Drawable`和`Selectable`接口,展现两者协同优势。理解和熟练运用这对概念是提升代码质量的关键。
|
14小时前
|
Java 测试技术 开发者
超越普通Java开发者:掌握抽象类与接口的高级技巧!
【6月更文挑战第17天】在Java编程中,抽象类和接口是提升代码质量和可维护性的核心要素。通过抽象类实现基类定制,如预设实现并强制子类实现特定方法;接口则提供多继承及默认、静态方法,增强复用和模块化。两者结合使用,抽象类封装状态和行为,接口专注行为契约,利于单元测试中的模拟对象创建。掌握这些技巧,能助你编写出更优雅、高效的代码。
|
14小时前
|
存储 Java 开发者
Java编程新视角:抽象类和接口,你不知道的秘密!
【6月更文挑战第17天】在Java中,抽象类与接口是抽象概念的关键工具。抽象类是不可实例化的模板,包含抽象和具体方法,适合有层次结构的继承;接口仅含抽象方法,像契约般规定实现类的行为,适用于无关对象间的统一接口。Java类单继承但可多实现接口,增加设计灵活性。理解并巧妙运用二者,能提升代码质量和可维护性。
|
14小时前
|
Java 开发者
别再写错代码了!Java抽象类与接口的正确使用姿势!
【6月更文挑战第17天】在Java中,抽象类与接口助力构建灵活代码结构,提升效率。抽象类用于定义公共行为和属性,适合有层次的对象集合;接口包含抽象方法,实现多态,适合不相关对象集合。通过示例展示了如何创建抽象类和实现接口,强调理解其核心价值和使用场景的重要性,以提升代码质量和设计。正确使用抽象类与接口,让代码从平凡走向专业。
|
15小时前
|
Java 程序员
技术日志:揭秘Java编程 —— 抽象类与接口的隐藏力量!
【6月更文挑战第17天】在Java编程中,抽象类和接口如同内功心法,增强代码灵活性和维护性。抽象类`Course`定义共性属性和行为,如显示大纲,子类如`ProgrammingCourse`继承并实现细节。接口`Ratable`提供评分功能,允许不同课程以多态方式实现。通过抽象类和接口,代码组织更有序,系统扩展性更强,犹如武侠高手以平凡招式创出非凡武学。不断学习和探索这些技术,能提升编程技艺,应对复杂挑战。
|
15小时前
|
算法 Java 开发者
震惊!你的Java代码还可以这样写:深入抽象类与接口的世界!
【6月更文挑战第17天】在Java编程中,抽象类与接口如双子星座般引领开发。通过抽象类`Shape`实现形状的共性,如颜色和抽象方法`getArea()`,展示多态性;接口`PerimeterCalculator`则在不修改`Shape`的基础上,允许`Circle`和`Rectangle`添加计算周长功能,体现扩展性。两者结合,助力构建优雅、灵活的程序结构。
|
2天前
|
存储 Java 测试技术
滚雪球学Java(61):从源码角度解读Java Set接口底层实现原理
【6月更文挑战第15天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
11 1
滚雪球学Java(61):从源码角度解读Java Set接口底层实现原理
|
5天前
|
Java
Java基础7-一文搞懂抽象类和接口,从基础到面试题,揭秘其本质区别(二)
Java基础7-一文搞懂抽象类和接口,从基础到面试题,揭秘其本质区别(二)
9 0
|
5天前
|
设计模式 Java 内存技术
Java基础7-一文搞懂抽象类和接口,从基础到面试题,揭秘其本质区别(一)
Java基础7-一文搞懂抽象类和接口,从基础到面试题,揭秘其本质区别(一)
13 0
|
17天前
|
Java
Java抽象类与接口的技术性文章
Java抽象类与接口的技术性文章
23 1