java 接口 多态_Java学习之接口与多态篇

Java学习之接口与多态篇

0x00 前言

在前面写的几篇文章里,讲了封装和继承,那么这篇文章就来讲讲第三大面向对象的特性多态吧,在此之前先接着上篇文章的抽象先来看看Java里面接口的应用。

0x01 接口

接口在java里面属于引用数据类型,是方法的集合。如果说的类的内部封装了成员变量、构造方法和成员方法,那么接口内部主要封装了方法,包括抽象方法,默认方法和静态方法,私有方法。

接口的定义和定义类差不多,定义接口需要使用到interface关键字。虽然说他也会被编译为class文件,但是他并不是一个类,而是另一种引用数据类型。

引用数据类型:数组、接口、类

接口的使用,他和抽象类一样不能直接被创建,但是他可以被实现使用implements关键字。

一个实现接口的类可以看作是接口的子类,需要实现接口里面所有的抽象方法,创建该类的对象,就可以调用方法了,否则他必须是抽象的子类。

定义格式:

public interface 接口名{

}

抽象方法使用 abstract 关键字修饰,可以省略,没有方法体。该方法供子类实现使用。

public interface InterFaceName {

public abstract void method();

}

接口里的默认方法和静态方法

默认方法:使用default进行修饰,不能省略,提供给子类或者子类重写使用。

静态方法:使用static修饰,提供给接口直接调用。

public interface MyInterface {

public static void method(){

//执行语句

}

public default void method2(){

//执行语句

}

}

接口里的私有方法和静态方法

私有方法和定义私有变量一样,使用private修饰,提供给接口的默认方法和静态方法调用。

pubilc interface InterfaceName{

}

实现接口

类和接口的关系为实现关系,这被称为类实现接口,这类可以称为接口的实现类,基本上和抽象类有点类似,也可以称为接口的子类。实现的动作蕾仕于继承,格式几乎一致,但是是使用implements关键字,而不是extends。

实现接口必须重写所有的抽象方法

集成了接口的默认方法,可以直接调用也可以重写

接口代码:

public interface MyInterface {

void eat();

void sleep();

}

实现类代码:

public class Zi implements MyInterface {

@Override

public void eat() {

System.out.println("吃");

}

@Override

public void sleep() {

System.out.println("睡");

}

}

main方法代码:

public static void main(String[] args) {

Zi zi = new Zi();

zi.eat();

zi.sleep();

}

接口默认方法代码实现:

定义接口:

public interface MyInterface {

default void eat() {

System.out.println("吃");

}

public default void sleep(){

System.out.println("睡");

}

}

实现类代码:

public class Zi implements MyInterface {

}

main方法代码:

public static void main(String[] args) {

Zi zi = new Zi();

zi.sleep();

zi.eat();

}

这里接口定义的第一个方法直接defalut使用这个关键字定义默认方法,第二个加上了public这两种写法都可以,前者是省略式的写法。

实现类的任何代码都没写,只写了一个继承,默认方法是默认就定义好的,可以不用写,从实例化对象直接调用,当然也可以在实现类里面进行重写。

接口静态方法使用

静态与.class 文件相关,只能使用接口名调用,不可以通过实现类的类名或者实现类的对象调用。

接口定义:

public interface MyInterface {

static void eat() {

System.out.println("吃");

}

}

实现类定义:

public class Zi implements MyInterface {

}

main方法代码:

public static void main(String[] args) {

MyInterface.eat();

}

这里可以看到在main方法里面,实例化一个对象,然后去访问eat方法是报错的,定义为静态的方法必须使用接口名进行访问。

私有方法的使用

私有方法:只有默认方法可以访问。

私有静态方法:只有默认方法和静态方法可以调用。

如果一个接口有多个默认方法并且重复,那么就可以提取出来封装到私有方法里面,供默认方法去调用他。

public interface LiveAble {

default void func(){

func1();

func2();

} p

rivate void func1(){

System.out.println("跑起来~~~");

} p

rivate void func2(){

System.out.println("跑起来~~~");

}

}

这种写法是jdk9的新特性,jdk8没有,此段描述纯属复制。

0x02 接口多实现

在前面说到因为java只支持单继承,所以一个类只能继承一个父类,但是对于接口来说,一个类是可以实现多个接口的,这就叫做接口的多实现,并且一个类里面可以继承一个父类,同时也实现多个接口。

格式:

class 类名 extends 父类名 impls 接口1,接口2{

...

}

或者

class 父类名 impls 接口1,接口2{

...

}

接口多实现多抽象方法

如果在多个接口中有重名的方法,该重名的方法只需重写一次。

接口多实现多个默认方法

接口中多个默认方法,实现类都可以继承使用。但是如果有重名的方法就必须重写一次。

接口1:

public interface MyInterface {

default void method1(){

System.out.println("我是一个没有感情的默认方法");

}

}

接口2:

public interface MyInterface2 {

default void method1(){

System.out.println("我是一个没有感情的默认方法");

}

}

实现类:

public class Zi implements MyInterface,MyInterface1 {

@Override

public void method1() {

System.out.println("没有感情的方法");

}

}

main方法代码:

public static void main(String[] args) {

Zi zi = new Zi();

zi.method1();

}

而接口中的静态方法就不会存在重名的问他,静态方法访问可以直接使用接口名访问静态方法。

优先级问题

一个类中如果计策了一个父类又实现了多个接口时,父类中的成员方和接口中的默认方法重名,子类就近选择执行的父类成员方法。

注意事项:

接口中,无法定义成员变量,但是可以定义常量,其值不可以改变,默认使用public static final修饰。

接口中,没有构造方法,不能创建对象。

接口中,没有静态代码块。

0x03 多态

多态是面向对象的第三大特性。

多态:指同一种行为,具有不同的表现形式。

多态前提:

1.继承或者实现

2.方法的重写

3.父类引用指向子类[格式]

格式:

父类类型 变量名 = new 子类对象;

变量名.方法名();

父类类型:指向子类对象继承的父类类型,或者是实现的父类接口类型。

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写

后方法。

父类代码:

public abstract class Animal {

public abstract void play();

}

子类1代码:

public class Cat extends Animal {

@Override

public void play() {

System.out.println("撸猫");

}

}

子类2 代码:

public class Dog extends Animal{

@Override

public void play() {

System.out.println("撸狗");

}

}

main方法代码:

public static void main(String[] args) {

Animal cat = new Cat();

Animal dog = new Dog();

cat.play();

dog.play();

}

0x04 多态引用类型转换

多态的转型分为向上转型喝向下转型两种:

我们经常用到的就是向上转型,多态本身就是子类类型向父类类型向上转换的过程。

当父类引用指向子类对象的时候,这就是向上转型。

代码:

Antmal cat = new Cat();

向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。

一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。

格式:

子类类型 变量名 =(子类类型)父类变量名;

在这里来说一下为什么要使用转型

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥

有,而父类没有的方法。编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子

类特有的方法,必须做向下转型。

总结:如果要调用子类拥有而父类没有的方法的时候就要使用到向下转型。

父类代码:

public abstract class Animal {

public abstract void eat();

}

子类:

public class Cat extends Animal {

@Override

public void eat() {

System.out.println("吃鱼");

}

public void catchMouse(){

System.out.println("抓鱼");

}

}

main方法代码:

public static void main(String[] args) {

Animal cat = new Cat();

cat.eat();

Cat c =(Cat)cat;

c.catchMouse();

}

为了避免ClassCastException的发生,Java提供了 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

}

}

}

0x05 结尾

接口与多态篇章更新完成,检测每天一个小总结。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值