【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方法进行排序了


相关文章
|
7天前
|
存储 安全 Java
Java面向对象最新超详细总结版!
Java面向对象最新超详细总结版!
25 7
Java面向对象最新超详细总结版!
|
1天前
|
安全 Java 调度
Java一分钟:多线程编程初步:Thread类与Runnable接口
【5月更文挑战第11天】本文介绍了Java中创建线程的两种方式:继承Thread类和实现Runnable接口,并讨论了多线程编程中的常见问题,如资源浪费、线程安全、死锁和优先级问题,提出了解决策略。示例展示了线程通信的生产者-消费者模型,强调理解和掌握线程操作对编写高效并发程序的重要性。
32 3
|
1天前
|
Java API
Java 接口
5月更文挑战第6天
|
2天前
|
存储 安全 Java
Java一分钟之-Map接口与HashMap详解
【5月更文挑战第10天】Java集合框架中的`Map`接口用于存储唯一键值对,而`HashMap`是其快速实现,基于哈希表支持高效查找、添加和删除。本文介绍了`Map`的核心方法,如`put`、`get`和`remove`,以及`HashMap`的特性:快速访问、无序和非线程安全。讨论了键的唯一性、`equals()`和`hashCode()`的正确实现以及线程安全问题。通过示例展示了基本操作和自定义键的使用,强调理解这些概念对编写健壮代码的重要性。
6 0
|
2天前
|
存储 安全 Java
Java一分钟之-集合框架进阶:Set接口与HashSet
【5月更文挑战第10天】本文介绍了Java集合框架中的`Set`接口和`HashSet`类。`Set`接口继承自`Collection`,特征是不允许重复元素,顺序不确定。`HashSet`是`Set`的实现,基于哈希表,提供快速添加、删除和查找操作,但无序且非线程安全。文章讨论了`HashSet`的特性、常见问题(如元素比较规则、非唯一性和线程安全性)以及如何避免这些问题,并提供了代码示例展示基本操作和自定义对象的使用。理解这些概念和注意事项能提升代码效率和可维护性。
9 0
|
2天前
|
存储 安全 算法
Java一分钟之-Java集合框架入门:List接口与ArrayList
【5月更文挑战第10天】本文介绍了Java集合框架中的`List`接口和`ArrayList`实现类。`List`是有序集合,支持元素重复并能按索引访问。核心方法包括添加、删除、获取和设置元素。`ArrayList`基于动态数组,提供高效随机访问和自动扩容,但非线程安全。文章讨论了三个常见问题:索引越界、遍历时修改集合和并发修改,并给出避免策略。通过示例代码展示了基本操作和安全遍历删除。理解并正确使用`List`和`ArrayList`能提升程序效率和稳定性。
7 0
|
2天前
|
Java
【JAVA进阶篇教学】第四篇:JDK8中函数式接口
【JAVA进阶篇教学】第四篇:JDK8中函数式接口
|
3天前
|
Java
Java一分钟之-抽象类与接口的应用场景
【5月更文挑战第9天】Java中,抽象类和接口用于实现多态和抽象。抽象类不能实例化,提供部分实现和定义模板;接口包含无实现的抽象方法,用于定义行为规范和解耦合。选择时,关注行为用接口,部分实现用抽象类。注意抽象类的`final`和`static`方法、接口冲突等问题,明确设计目标,适度抽象,遵循接口设计原则,以提高代码质量。
12 1
|
3天前
|
Java
Java一分钟之-多态性:理解重写与接口
【5月更文挑战第9天】本文介绍了Java中的多态性,主要通过方法重写和接口实现。重写允许子类根据实际类型执行不同实现,关键点包括方法签名相同、访问权限不降低以及final、static和abstract方法不可重写。接口是抽象类型,包含抽象方法,提供另一种多态性实现。常见问题包括混淆重载与重写、不理解动态绑定以及滥用接口。为避免问题,需明确重写目的、合理设计接口,并在使用多态时注意类型检查。多态性是提升代码质量和灵活性的关键。
10 1
|
3天前
|
Java
java面向对象——包+继承+多态(一)-2
java面向对象——包+继承+多态(一)
16 3