【Java】面向对象之——接口的理解(一)

简介: 算法

【Java】面向对象之——接口的理解

🎄语法规则

🎄实现多个接口

🎄接口使用实例

🎄接口之间的继承

🎄Cloneable 接口和深浅拷贝

🎄总结

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


有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。


接口(interface)是抽象方法和常量值的定义的集合。

从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。


🎄语法规则

在打印图形的示例中, 我们的父类 Shape 并没有包含别的非抽象方法, 也可以设计成一个接口

interface IShape { 
 void draw(); 
} 
class Cycle implements IShape { 
 @Override 
 public void draw() { 
 System.out.println("○"); 
 } 
} 
public class Test { 
 public static void main(String[] args) { 
 IShape shape = new Cycle(); 
 shape.draw(); 
 } 
} 

1.png


代码解释:


使用 interface 定义一个接口

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

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

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

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

接口不能单独被实例化.

扩展(extends) vs 实现(implements)

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


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


接口中只能包含抽象方法. 对于字段来说, 接口中只能包含静态常量(final static)


interface IShape { 
 void draw(); 
 public static final int num = 10; 
}

其中的 public, static, final 的关键字都可以省略.省略后的 num 仍然表示 public 的静态常量.


提示:


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

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

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


一个错误的代码

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


技巧:接口中的 public, static, final 的关键字都可以省略.


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

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

接口中只能包含抽象方法. 对于字段来说, 接口中只能包含静态常量(final static).


🎄实现多个接口


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

然而 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 Swan extends Animal implements IRunning, ISwimming, IFlying { 
 public Swan(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 + "会游泳"); 
 } 
} 

运行结果如下:

3.png


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


继承表达的含义是 is - a 语义, 而接口表达的含义是 具有 xxx 特性 .


猫是一种动物, 具有会跑的特性.

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

天鹅也是一种动物, 既能跑, 也能游, 还能飞


【这样设计有什么好处呢?】

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


🎄接口使用实例


实例:给对象数组排序

先给定一个学生类

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 + "]"; 
 } 
}

再给定一个学生对象数组, 对这个对象数组中的元素进行排序(按分数降序).

Student[] students = new Student[] { 
 new Student("张三", 95), 
 new Student("李四", 96), 
 new Student("王五", 97), 
 new Student("赵六", 92), 
}; 

按照我们之前的理解, 数组我们有一个现成的 sort 方法, 能否直接使用这个方法呢?

Arrays.sort(students); 
System.out.println(Arrays.toString(students)); 
// 运行出错, 抛出异常. 
Exception in thread "main" java.lang.ClassCastException: Student cannot be cast to 
java.lang.Comparable 

仔细思考, 不难发现, 和普通的整数不一样, 两个整数是可以直接比较的, 大小关系明确. 而两个学生对象的大小关系怎么确定?

这时候就需要我们额外指定.


让我们的 Student 类实现 Comparable 接口, 并实现其中的 compareTo 方法

public 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//重写Comparable接口里的compare To 方法
        public int compareTo(Object o) {
            Student s = (Student)o;
            if (this.score > s.score) {
                return -1;
            } else if (this.score < s.score) {
                return 1;
            } else {
                return 0;
            }
        }
}

在 sort 方法中会自动调用 compareTo 方法(具体原因可以通过ctrl+左键点击sort方法查看源码,此处不多赘叙). compareTo 的参数是 Object , 其实传入的就是 Student 类型的对象.


然后自定义 比较当前对象和参数对象的大小关系 的规则(按分数来算).


如果当前对象应排在参数对象之前, 返回小于 0 的数字;

如果当前对象应排在参数对象之后, 返回大于 0 的数字;

如果当前对象和参数对象不分先后, 返回 0;

再次执行程序, 结果就符合预期了.4.png


注意事项:

对于 sort 方法来说, 需要传入的数组的每个对象都是 “可比较” 的, 需要具备 compareTo 这样的能力. 通过重写 compareTo 方法的方式, 就可以定义比较规则.


接口就相当于是具备某种能力,在这里Comparable接口就表示具有 “可比较能力“,Student类加上(实现)了这个接口,就拥有了可比较能力,就能使用sort方法进行排序了


相关文章
|
3月前
|
数据采集 JSON Java
Java爬虫获取1688店铺所有商品接口数据实战指南
本文介绍如何使用Java爬虫技术高效获取1688店铺商品信息,涵盖环境搭建、API调用、签名生成及数据抓取全流程,并附完整代码示例,助力市场分析与选品决策。
|
3月前
|
消息中间件 缓存 前端开发
从资损百万到零事故:Java 接口幂等设计的艺术与实践
在分布式系统中,重复请求常引发严重资损,如支付双扣、库存超卖等问题,其根源在于接口缺乏幂等性设计。本文通过真实案例揭示幂等性的重要性,并详解8种主流解决方案,涵盖唯一请求ID、乐观锁、悲观锁、状态机等,帮助开发者构建稳定系统,保障业务一致性。无论你是架构师还是开发工程师,都能从中获得实战指导,有效规避重复调用带来的风险。
262 0
|
1月前
|
Java Go 开发工具
【Java】(9)抽象类、接口、内部的运用与作用分析,枚举类型的使用
抽象类必须使用abstract修饰符来修饰,抽象方法也必须使用abstract修饰符来修饰,抽象方法不能有方法体。抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建抽象类的实例。抽象类可以包含成员变量、方法(普通方法和抽象方法都可以)、构造器、初始化块、内部类(接 口、枚举)5种成分。抽象类的构造器不能用于创建实例,主要是用于被其子类调用。抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类abstract static不能同时修饰一个方法。
200 1
|
2月前
|
算法 安全 Java
除了类,Java中的接口和方法也可以使用泛型吗?
除了类,Java中的接口和方法也可以使用泛型吗?
134 11
|
2月前
|
Java
Java基础语法与面向对象
重载(Overload)指同一类中方法名相同、参数列表不同,与返回值无关;重写(Override)指子类重新实现父类方法,方法名和参数列表必须相同,返回类型兼容。重载发生在同类,重写发生在继承关系中。
138 1
|
3月前
|
存储 缓存 安全
Java集合框架(二):Set接口与哈希表原理
本文深入解析Java中Set集合的工作原理及其实现机制,涵盖HashSet、LinkedHashSet和TreeSet三大实现类。从Set接口的特性出发,对比List理解去重机制,并详解哈希表原理、hashCode与equals方法的作用。进一步剖析HashSet的底层HashMap实现、LinkedHashSet的双向链表维护顺序特性,以及TreeSet基于红黑树的排序功能。文章还包含性能对比、自定义对象去重、集合运算实战和线程安全方案,帮助读者全面掌握Set的应用与选择策略。
256 23
|
3月前
|
安全 Java 开发者
Java集合框架:详解Deque接口的栈操作方法全集
理解和掌握这些方法对于实现像浏览器后退功能这样的栈操作来说至关重要,它们能够帮助开发者编写既高效又稳定的应用程序。此外,在多线程环境中想保证线程安全,可以考虑使用ConcurrentLinkedDeque,它是Deque的线程安全版本,尽管它并未直接实现栈操作的方法,但是Deque的接口方法可以相对应地使用。
236 12
|
2月前
|
存储 Java 关系型数据库
Java 项目实战基于面向对象思想的汽车租赁系统开发实例 汽车租赁系统 Java 面向对象项目实战
本文介绍基于Java面向对象编程的汽车租赁系统技术方案与应用实例,涵盖系统功能需求分析、类设计、数据库设计及具体代码实现,帮助开发者掌握Java在实际项目中的应用。
112 0
|
3月前
|
存储 安全 Java
Java集合框架(一):List接口及其实现类剖析
本文深入解析Java中List集合的实现原理,涵盖ArrayList的动态数组机制、LinkedList的链表结构、Vector与Stack的线程安全性及其不推荐使用的原因,对比了不同实现的性能与适用场景,帮助开发者根据实际需求选择合适的List实现。
下一篇
oss云网关配置