目录
| 多态(接口基础)
接口使用、接口内的抽象方法
接口语法、接口中的抽象方法
-
接口内一般写的都是抽象方法!且必须被 public abstract 修饰,实际上,这两个修饰符可以省略。如:void interfaceMethod( );
-
接口不能有静态代码块,也不能构造方法!(因为接口不能直接new)
[public] interface 接口名{
//接口内容(所允许的类型请见下表)
//接口方法(必须是抽象方法)
[public abstract] 返回类型 方法名();
}
接口使用
-
通过 implements 实现类使用接口
-
下面的代码演示了接口的使用步骤
public interface MyInterface{
void interfaceMethod();
}
class ImplClass implements MyInterface{
@Override
public void interfaceMethod(){
//抽象方法的实现
}
}
ImplClass impleClass = new ImplClass();
接口中一些特例的说明
接口的多实现
-
一个实现类可以实现多个接口(本质上还是Object的继承)
-
若实现类所实现的多个接口中,存在重复的抽象方法(即抽象方法重名),则只需要重写其中一个抽象方法即可
-
若实现类所实现的多个接口中,存在重复的默认方法(即重复方法重名),则实现类必须要对冲突的重复方法进行覆盖重写(记得去掉default)
-
若没有重复的同名默认方法,则可以选择性重写(重写了就用实现类的方法,否则就去找接口中的方法)
-
接口和继承的组合使用
-
虽然说继承和接口同时出现了但是他们还是一样各玩各的 一个类如果既继承了一个抽象类又实现了一个接口我们一定要先写继承在写实现,这是官方规定的语法格式,不可以改变。
public interface MyInterface{
}
class Father{
}
class ExtendsAndImplClass extends Father implements MyInterface{
}
-
若一个类A继承了父类,又实现了多个接口,那么这个类实际上是父类的子类,而不是接口的实现类。因为Java中的优先级:继承 > 接口实现。
接口的多继承
-
Java和C++不同,Java中:类与类不能多继承,但是接口和接口间可以多继承
public interface 继承接口名 extends 被继承接口名A 被继承接口名B ...... { }
-
接口多继承后:
-
必须对父接口中的“同名默认方法”、“抽象方法”进行覆盖重写。
-
且子接口中对父接口的默认方法的覆盖重写 不能去掉default (区别于接口的实现类对于默认方法的重写需要去掉default)
-
接口内的默认、静态、私有方法 & 常量
接口中的默认方法
-
作用:解决“接口新增一个抽象方法,需要在所有实现类中覆盖重写新的抽象方法”的问题
-
默认方法的使用:
-
默认方法可以不用在子类实现类重写。
-
若重写了默认方法,则需要把 default 关键字去掉,再根据重写规则进行重写
-
实现类对象使用的方法,若实现类内没有定义(重写),则会找接口的同名的默认方法执行,否则编译报错
-
-
需要注意:接口内的默认方法不是抽象的。要有方法体!
public default 返回值类型 方法名称(参数列表){
//方法体
}
//实际上,public
下面的代码演示了默认方法的使用
public interface MyInterface{
public void default interfaceDefaultMethod(){
}
}
class ImplClass1 implements MyInterface{
@Override
public void interfaceDefaultMethod(){
//接口1的实现类实现了默认方法,则调用的时候使用的是实现类中的默认方法
}
}
class ImplClass2 implements MyInterface{
//接口2的实现类没实现默认方法,则调用的时候使用的是接口中的默认方法
}
ImplClass1 impleClass1 = new ImplClass1();
ImplClass2 impleClass2 = new ImplClass2();
impleClass1.interfaceDefaultMethod(); //实现类重写了默认方法,则使用的实现类的
impleClass2.interfaceDefaultMethod(); //实现类没有这个方法,则会继续去接口中寻找这个名字的方法,发现是默认方法,则调用
接口中的静态方法
-
需要注意:接口内的静态方法不是抽象的。要有方法体!
-
接口的静态方法使用步骤,和类的静态方法一模一样
-
通过【接口名.静态方法】进行调用
public static 返回值类型 方法名称(参数列表){
//方法体
}
接口内的私有方法
-
作用:若接口内有多个deafult方法且有耦合,则可以使用私有方法进行解耦合。
-
本质上来说,接口内私有方法的目的还是服务于默认方法。因此,掌握接口中的默认方法的使用是基础,然后私有方法是在其基础上解耦合。
public interface MyInterface{
public void default methodA(){
AandB();
}
public void default methodB(){
AandB();
}
private void AandB(){
//私有方法,作为接口中的默认方法A和B的公共部分。然后A和B调用这个方法,从而达到解耦合的目的
}
}
接口内的成员常量
-
接口成员常量,一旦定义,无法更改。基于此,接口中定义的常量必须进行赋值!
-
接口中定义成员常量的三个关键字 public static final 可以选择性不写,编译器会自动加上。
换言之,接口中定义的常量,默认都是 静态不可变的常量
-
命名规则:常量名必须 大写 加 下划线 命名
-
语法
[public static final] 数据类型 常量名 = 数据;
使用:
//在main中:直接使用【接口名 . 常量名称】 即可使用对应数据
System.out.println(MyInterface.FINAL_NUM);
//在 实现类 中:直接使用 【 常量名称 】 即可使用对应数据
@Override
public void method(){
System.out.println(FINAL_NUM);
}
接口总结
类与类之间是单继承的,直接父类只有一个。
类与接口之间是多实现的,一个类可以实现多个接口。
接口与接口之间是多继承的,一个接口可以继承多个不同的接口。
| 多态
多态的概念
-
多态是针对对象,不是针对类而言的
-
铅笔是文具,尺子也是文具,所以它们都能通过【文具指向铅笔/尺子】→ 即【父类引用指向子类对象】
多态的使用:向上转型
-
常见的多态使用,一般都是【对象向上(父类)转型】。向上转型是绝对安全的
-
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法
由此可得向上转型的缺点是:无法调用子类原本特有的方法和变量
多态的使用:向下转型
-
上面提到了向上转型后,若父类中没有调用的方法,那么会编译报错(即多态向上转型后,无法调用父类没有而子类独有的方法)
因此,此时若想调用父类没有而子类独有的方法,则需要把多态的对象进行向下转型
-
需要注意的是:向下转型,必须转成为原先类的对象,否则会报错。
-
可以使用 instanceof 来判断某个对象是不是某个类的实例(强烈建议向下转型的时候都使用这个进行判断后再转型)
对象名 instanceof 类/接口名; //返回一个boolean值
if(XXX instanceof XXX){
//向下转型
}
多态两种转型的代码示例
//接口
public interface Animal{
void eat();
}
//接口实现类:Dog
class Dog implements Animal{
@Override
public void eat(){
System.out.println("Dog eat meat");
}
//子类特有的方法 Picture
public void picture(){
System.out.println("Dog's picture");
}
}
//主方法
public static void Main(String[] args){
//向上转型
Animal dog = new Dog();
dog.eat(); //执行成功。原理:多态向上转型的方法,先查找父类是否有,如果有则去执行【子类的】同名方法。若父类没有,则报错
dog.pucture(); //执行失败。因为父类没有该方法
//向下转型
if(dog instanceof Dog){
Dog dogDown = (Dog)dog;
dogDown.eat(); //执行成功,执行的是子类的eat()。
dogDown.eat(); //执行成功。向下转型后,调用的方法就不再去查找父类是否有该方法了,直接执行子类的,若子类没有再去查找父类(接口的话则报错,因为都是抽象方法)
}
}