前言:
本篇文章主要讲述对于包,接口,以及多态的理解,以及一些常用接口的了解,如果对于你有所帮助或者启发,不要忘记给作者点个赞哦!
多态
1.1 向下转型(了解)
在前面一篇文章我们介绍了什么是向上转型,向下转型就是用子类的引用去引用父类引用所指的该子类对象,但是这个时候就必须的要进行强转,因为这个时候是要父类的引用被子类的引用所引用,接下来我们可以通过一个代码来理解一下
animal animal=new bird("fja",20); bird bird=(bird) animal;
此时就是子类的引用引用了父类引用所指的该子类对象,其实向下转型还是不安全的,之前我们向上转型中,父类引用子类,可以理解为子类是属于父类的一种,而这里不能说父类是子类的一种。
1.2 instanceof关键字
对于向下转型,我们可以采取利用instanceof关键字来判断父类引用是否是子类的一个实例,具体用法如下
animal animal=new dog("fja",20); if (animal instanceof dog){ System.out.println(333); }
如果animal引用的是dog的一个子类对象,就会执行if语句里面的内容,反之就不会执行if语句里面的内容,这样子可以让向下转型更加安全的实现。
1.3 多态(理解)
对于多态我们可以结合一段代码来进行理解什么是多态!
class shape{ public void draw(){ } } class rect extends shape{ @Override public void draw() { System.out.println("(●ˇ∀ˇ●)"); } } class small extends shape{ @Override public void draw() { System.out.println("small"); } } public class test { public static void func(shape shape){ shape.draw(); } public static void main(String[] args) { rect rect=new rect(); func(rect); small small=new small(); func(small) } }
在这段代码中我们定义了一个shape类里面的draw方法可以帮助我们打印出不同的形状,我们结合之前所讲的动态绑定,继承,就可以来实现通过定义一个父类来实现打印不同的形状,在这里我们可以了解到,在调用函数中,我们不用关注shape引用了那个类型的实例。也就是说通过一个父类shape的引用,来调用同一个方法,表现出来的形式有不同(与shape对应的实例有关),这样的一个行为就被称为是多态。
1.4 多态的好处
之前我们学过private封装,封装的好处就是让类的调用者不需要知道类的实现细节,那么此时多态的作用就是让类的调用者不需要知道这个类的是什么类型,只需要这个对象的某个方法就可以了,这样就让类的调用者对类的使用成本进一步降低。
抽象类
2.1 abstract关键字
在多态中,我们发现通过动态绑定,父类中的方法是没有被执行的,那么这个时候我们可以通过abstract关键字将该方法变为抽象方法,那么包含抽象方法的类就被称为抽象类。
1. abstract class shape{ 2. abstract public void draw(); 3. }
2.2 语法规则
1 不能通过关键字new来实例化抽象类本身,但是可以发生向上转型
2 抽象类最大的作用是被继承
3 抽象类不能被final修饰,被final修饰的类是不能被继承的
4 抽象类中也是可以包含字段与普通方法
5 一个普通类继承了抽象类,那么这个普通类就需要重写抽象类里面的全部抽象方法
6 若一个抽象类A,继承了一个抽象类B,抽象类A可以不重写抽象类B中的抽象方法,此时若有一个普通类C,继承了抽象类A,那么此时就需要重写抽象类A与B中所有的抽象方法。
接口(重点)
3.1 语法规则
1 在抽象类的基础上(可以理解为是抽象类的plus版本),我们利用interface关键字去定义一个接口,abstract public在接口是可以省略的,与抽象类一样,接口也是不能被实例化的。
interface shape{ abstract public void draw(); }
2 接口中不能含有普通方法与字段(如果要写入普通方法,可以在普通方法前用关键字default修饰,表示为这个接口的默认方法)
3 接口中的成员变量都是被public static final(可以被省略)修饰的,并且都要被赋予初值
4 当一个类继承了接口,就要重写该接口中的所有抽象方法
5 接口的实现(implements关键字)
我们通过implements关键字来实现一个接口
interface shape{ abstract public void draw(); } class cloud implements shape{ @Override public void draw() { System.out.println("这是一个接口实现"); } } public class test { public static void main(String[] args) { shape shape=new cloud(); shape.draw(); } }
我们通过定义了一个cloud,通过关键字implements实现接口shape
6 当一个类实现了该接口,那么重写该接口的抽象方法前一定要加上public
接口中可以省略,但是重写时可不能不写,否则是包访问权限,就比接口中的访问权限就要小了。
3.2 实现多个接口
interface Is{ abstract public void eat(); } interface shape{ abstract public void draw(); } class cloud implements shape,Is{ @Override public void draw() { System.out.println("这是一个接口实现"); } @Override public void eat() { System.out.println("实现多个接口!"); } } public class test { public static void main(String[] args) { shape shape=new cloud(); shape.draw(); } }
通过代码我们可以知道一个类可以实现多个接口(本例子就列举了两个接口,其实可以多个接口),但要把每个接口的抽象方法要重写,并且接口之间用逗号隔开。
3.4 接口与接口之间的关系
interface Irunning{ abstract public void run(); } interface Iwalk{ abstract public void walk(); } interface IC extends Irunning{ abstract public void pdd(); }
从代码中我们可以知道,接口与接口之间是通过extends关键字来表示两个接口之间的关系,此时这里的extends不是继承的意思,而表示拓展的意思,一个接口可以拓展另一个接口,而实现两个接口的功能(如果要拓展多个接口,需要用逗号隔开)
3.5 接口的好处
1 弥补java中单继承的缺点,因为可以扩展多个接口,那么我们可以通过继承一个父类,利用implement关键字实现多个接口,从而实现更多的功能
2 多态能够让程序猿不必关注类的类型,那么接口就是让程序猿不必关注类的类型,而是关注类所能实现的功能
例如:
我们先创建三个接口,去实现跑,游,飞三种功能
interface Irun{ void run(); } interface Iswim{ void swim(); } interface Ifly{ void fly(); }
我们在定义一个父类animal
class Animal{ String name; public Animal(String name){ this.name=name; } }
定义实现一个功能的
//定义一个跑的动物 class DOG extends Animal implements Irun{ public DOG(String name) { super(name); } @Override public void run() { System.out.println(name+"四条腿跑"); } }
定义一个实现两个功能的动物
//定义一个会跳回游的青蛙 class frog extends Animal implements Irun,Iswim{ @Override public void run() { System.out.println(name+"在跳"); } @Override public void swim() { System.out.println(name+"游泳"); } public frog(String name) { super(name); } }
定义一个能满足三种功能的动物
//定义能满足这三个功能的动物 class Duck extends Animal implements Irun,Iswim,Ifly{ @Override public void run() { System.out.println(name+"跑"); } @Override public void swim() { System.out.println(name+"游泳"); } @Override public void fly() { System.out.println(name+"飞"); } public Duck(String name) { super(name); } }
在这里我们就可以看到,我们可以通过继承一个类,实现多种接口,从而实现更多的功能,弥补了java中单继承的缺陷。从这里也可以看出接口所要表达的含义就是:具有xxx特性
我们在这个基础上,可以实现一个方法专门用于跑
public static void fun(Irun Irun){ Irun.run(); }
在这个方法的内部我们不关心是什么类型,只要所给的参数会跑就行
public class node { public static void fun(Irun Irun){ Irun.run(); } public static void main(String[] args) { DOG DOG=new DOG("狗"); fun(DOG); } }
接口的可扩展性非常强,只要一个类实现了该接口,就能通过该方法来实现,请看下列代码
lass Robot implements Irun { private String name; public Robot(String name) { this.name = name; } @Override public void run() { System.out.println(this.name + "正在用轮子跑"); } }
Robot robot = new Robot("机器人"); fun(robot);
只要是实现了Irun这个接口,就可以通过实现方法,来实现该类的功能。
3.6 接口与抽象类的区别(要点)
核心区别:抽象类中是可以包含字段与普通方法的,方法与字段是可以直接被子类使用的(不需要重写),接口中不含有普通方法,子类必须重写接口中包含的所有抽象方法
图解区别
面向对象——多态,抽象类,接口(二)-2