面向对象(三)
接口
定义与多继承性
接口时一种约定的规范,是多个抽象方法的集合
- 接口中的方法时抽象方法,并不提供功能实现,体现了规范和实现相分离的思想
- 接口不能创建对象,接口不存在构造方法
- 接口体现了低耦合思想(接口用于模块间的解耦)
所谓耦合度,表示组件之间的依赖关系。
依赖关系越多,耦合性越强,同时表明组件的独立性越差
- 接口可以被认为是一种特殊的类,定义接口使用interface关键字
public interface 接口名{
//抽象方法1();
//抽象方法2();
//抽象方法3();
}
- 接口表示具有某些功能的事物,接口名使用名词 ,一般以I开头
定义走路接口
public interface IWalkable {
public void walk();
}
注意: 接口中的方法都是公共的抽象方法
写法
1. public abstract void foo();
2. void print(); //默认省略了public
3. public void showInfo(); //推荐写法
4.从Java8开始, Java支持在接口中定义有实现的方法(这里先不讲,避免概念混淆)
在java中,接口也可以继承,一个接口可以继承多个接口(多继承)
- 定义行走规范
public interface IWalkable { public void walk(); }
- 定义游泳规范
public interface ISwimable { public void swim(); }
- 两栖动物,能走能游泳
public interface IAmphibiable extends IWalkable,ISwimable{
}
//同时继承了两个接口 ,子类继承了父接口的所有方法
接口实现类
我们定义接口时,方法是抽象的,并没有方法体,前面讲到接口是不能创建对象的,所以我们需要去定义一个类去实现这个接口,并且必须实现接口中所有的抽象方法,我们称接口实现类.
格式:
public class 类名 implements 接口名{
//实现接口中抽象方法
}
接口与实现类的关系:
1.接口:定义多个抽象方法,仅定义不提供实现
2.实现类:实现接口,实现接口中所有的抽象方法,完成具体功能的实现
例子:前面已经定义了IWalkable接口,ISwimable接口
定义人类Person实现类
/*
*person作为IWalkable的实现类,必须实现接口中所有的抽象方法
* => 接口约束实现类必须实现 walk() 方法
* => 实现类 has a 接口
* => 实现类具有接口中定义的功能
* => 接口约定了实现类应该具备的功能
* */
public class Person implements IWalkable{
@Override
public void walk() {
System.out.println("人类在步行");
}
}
1.实现类可以继承父类,同时也可以实现一个或多个接口,继承在前,实现在后
2.接口是一种引用数据类型,可以用来声明变量,并接收(引用)所有该接口的实现类对象。
- 创建实现类对象
接口 变量 = new 实现类();
定义青蛙类(Frog),继承动物类(Animal),实现走路,游泳(前面两个接口)
Animal类
public abstract class Animal {
public abstract void sleep();=
}
Frog类
public class Frog extends Animal implements ISwimable,IWalkable{
@Override
public void sleep() {
System.out.println("青蛙在睡觉"); //覆盖了父类的抽象方法
}
@Override
public void swim() {
System.out.println("青蛙会游泳");//实现游泳接口方法
}
@Override
public void walk() {
System.out.println("青蛙会走路");//实现走路接口方法
}
}
测试类
public class Test01 {
public static void main(String[] args) {
Frog f1 = new Frog(); //创建对象f1
f1.sleep(); //f1调用覆盖后的方法sleep()
f1.swim(); //f1调用覆盖后的方法swim()
IWalkable walkable = null; //声明一个接口类型的变量
walkable = new Frog(); //接口可以引用其实现类对象
walkable.walk();
总结:
1.当我们声明一个接口类型的变量时,它表示的意义是希望它的实现类应该具备什么功能
2.重心在于实现类,能不能满足接口约定的功能,重心不在于持有数据,从而不依赖于任何某种特定类型的对象,进而对两个模块的功能进行解耦
}
}
- 接口在实际开发过程中用于两个模块/组件的解耦,降低耦合度
=>未来在架构师眼里,模块和模块之间的衔接都使用接口,
=> 架构师眼里只有接口,我们称为面向接口编程
-
接口表示一种规约(规范、标准),它里面定义了一些列抽象方法(功能),它可以被多个类实 现。
-
面向接口编程,体现的就是多态,其好处:把实现类对象赋给接口类型变量,屏蔽了不同实现类之 间的实现差异,从而可以做到通用编程。
多态
面向对象三大特征:封装,继承,多态
什么是多态?
所谓多态,表示的是一个对象具有多种形态.
-
当同一引用类型变量调用同一方法时,由于引用实例不同,方法产生的结果不同,结果呈现多种形态/状态,这种情况在oop中称为多态
-
当编译时类型和运行时类型不一致时,就会出现多态
-
编译时类型:声明对象变量的类型,编译类型必须是运行类型的父类或接口
-
运行时类型:对象的真实类型
多态发生的条件
- 必须继承
- 必须重写
- 多态建立在重写/实现的基础上
例子;
Animal animal =null;//声明时的类型称为编译类型
animal = new Dog();//运行时类型 new Dog()
多态操作
继承关系
父类引用变量指向于子类对象(父引子),调用方法时实际调用的是子类的方法。
父类 变量名 = new 子类();
变量名.方法();
实现关系
接口引用变量指向实现类对象,调用方法时实际调用的是实现类实现接口的方法。
接口 变量名 = new 实现类();
变量名.方法();
// 接口new实现类可以实现多态
例子:
public class Test01 {
public static void main(String[] args) {
Animal animal =null; //声明时的类型称为编译类型
animal = new Dog(); //运行时类型 new Dog()
Animal animal1 = new Dog();//可以使用父类 引用 子类实例
Animal animal2 = new Cat(); //父类表示更大的群体
/*
*1.父类对象可以引用子类实例(父引子)
*2.当编译时类型和运行时类型不一致时,就会出现多态
*3.编译时类型只能看到自己定义的方法,看不到子类自己特有的方法(不可见)
* */
}
}
多态对象调用方法问题
当把子类赋给父类变量时,调用方法
Animal a1 =new Dog();
a1.shout();
此时a1调用的方法是来自父类还是子类呢?
1.编译时,会先去找父类方法,父类方法存在,会在运行时期找子类方法,子类方法存在运行子类的,没有就会运行父类的方法
2.如果编译的时候没有找到父类方法,那么就会编译报错了
多态中的类型转换
类型转换
自动类型转换:把子类对象赋给父类变量(多态)
Animal a = new Dog();
Object obj = new Dog(); //Object是所有类的根类
强制类型转换:把父类类型对象赋给子类类型变量。
子类类型 变量 = (子类类型)父类对象;
对象的真实类型应该是子类类型
如果需要调用子类特有的方法时, 一定要进行强制类型转换。
public class Test01 {
public static void main(String[] args) {
Animal animal = new Dog();
//想调用Dog独有的方法,把animal强转成Dog类型
animal=(Dog)animal;
Dog dog = (Dog)animal; //强转
dog.eat();
System.out.println(animal instanceof Dog);
}
}
instanceOf
instanceOf运算符:判断该对象是否是某一个类/接口的实例
语法:
boolean b = 对象A instanceof 类B; //判断 A对象是否是 B类的实例?如果是,返回true
多态的好处
多态:同一个对象,在不同时刻体现出来的不同状态。
能都有规范的划分区域,如果需要添加新的业务需求,
我们只需实现某个接口,就可以实现功能,其中展示了多态的功能,有延展性