一.接口
1.概述
- 比抽象类更加抽象
- 接口不是类,因为接口中没有构造方法
- 接口是引用数据类型,主要用来写抽象方法和常量,但是接口中可以写常量,抽象方法,默认方法,私有方法,静态方法
- 接口使用interface关键字来定义
- 接口没有构造方法,不能创建对象,需要使用类来实现接口
2.格式
public interface 接口{
常量
抽象方法
默认方法
私有方法
静态方法
}
3.接口的实现
public class 实现类名 implements 接口名{
需要重写接口中的抽象方法
默认方法可以选择重写或者直接调用
}
4.接口和类的关系
实现关系
- 单实现: A类 只实现 A接口
- 多实现: A类 同时实现 A接口,B接口,C接口
public class A类[extends 父类名] implements B,C{
}
- 多层实现: A类 继承 B 类,B类 实现 C接口,D接口
注意事项
- 如果多个接口中有同名的抽象方法,只需要重写一次
- 如果多个接口中有同名的默认方法,必须重写一次,不需要加default
注意事项
实现类可以同时继承一个类,实现多个接口,父类中的成员方法与接口中的默认方法重名,子类就近选择执行父类的成员方法
面试题
抽象类和接口的区别是什么?
- 成员特点不同
抽象类中的成员比普通类多一种抽象方法(而且抽象方法也可以不写)
接口中有且只能有抽象方法(JDK1.8以后有带方法体的方法)或者常量 - 关系特点不同
参考上个知识点 - 设计理念不同
抽象类:定义的是整个继承体系的共性内容
接口:定义的是整个继承体系的扩展内容
5.接口和接口的关系
继承关系:
- 单继承: A接口 继承 B接口
- 多继承: A接口 同时继承 B接口,C接口
- 多层继承: A接口 继承 B接口,B接口 继承 C接口
注意事项
- 多个父接口中有重命的抽象方法:子接口无需理会,子接口的实现类只需要实现一次即可
- 如果多个接口中有同名的默认方法,必须重写一次,需要加default
其他成员特点
- 接口中,无法定义成员变量,可以定义常量,其值不可以改变,默认使用public static final 修饰
- 接口中,没有构造方法,不能创建对象
- 没有静态代码块
二.多态
1.概念
同一种行为,具有多个不同的表现形式
2.前提条件
- 必须要有继承(或者实现)关系
- 方法的重写(不重写,无意义)
- 父类引用指向子类对象(格式体现)
3.格式
父类类型 变量名 = new 子类对象;
变量名.方法名();
4.多态的访问特点
- 成员变量:
编译看左边,运行看左边 - 成员方法:
静态:编译看左边,运行看左边
非静态:编译看左边,运行看右边
5.多态的好处和弊端
多态的好处
- 提高代码的扩展性
- 提高代码的可维护性
多态在实际开发中常用的应用场景:
父类型可以作为方法的形参的参数类型, 这样可以接受其任意的子类对象.
public static void test(Person p) {
p.eat();
}
多态的弊端
父类(父接口)引用 不能直接使用子类的特有成员(成员变量和成员方法).
怎么解决这个问题呢?
可以通过向下转型实现
引用类型转换
- 向上转型: 父类引用指向子类对象
多态就是向上转型.
多态本身就是子类向父类类型转换的过程,这个过程是默认的
父类类型 变量名 = new 子类类型();
Animal a = new cat();
- 向下转型
父类类型向子类类型向下转换的过程,这个过程是强制的
一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型
子类类型 变量名 = (子类类型) 父类变量名;
Cat c = (Cat) a;
6.为什么要转型
调用子类特有的方法
创建Animal类:
abstract class Animal {
abstract void eat();
}
创建Cat类
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void catchMouse() {
System.out.println("抓老鼠");
}
}
创建Dog类
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void watchHouse() {
System.out.println("看家");
}
}
定义测试类
public class Test {
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
Cat c = (Cat)a;
c.catchMouse(); // 调用的是 Cat 的 catchMouse
}
}
7.转型的异常
public class Test {
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
Dog d = (Dog)a;
d.watchHouse(); // 调用的是 Dog 的 watchHouse 【运行报错】
//ClassCastException 类型转换异常
}
}
instanceof 关键字
变量名 instanceof 数据类型
如果变量属于该数据类型,返回true。
如果变量不属于该数据类型,返回false
public class Test {
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
if (a instanceof Cat){
Cat c = (Cat)a;
c.catchMouse(); // 调用的是 Cat 的 catchMouse
} else if (a instanceof Dog){
Dog d = (Dog)a;
d.watchHouse(); // 调用的是 Dog 的 watchHouse
}
}
}