文章目录
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
本次文章内容主要是对面向对象中三大特性的最后一个特性-多态学习总结,其次便是对接口知识的一个总结,由于本次内容涉及到接口的多态使用,所以我才将昨天的内容拿到今天来写,为了一个思路相对清晰与系统的整理才做了一些修改,反正是为了学习嘛,效果好就行
提示:以下是本篇文章正文内容,下面案例可供参考
一、“多态”的学习
(1)什么是多态?
生活中:多态是指“客观事物在人脑中的主观反映”,主观意识上的类别与客观存在的对象具有“is a”的关系,即为多态。
程序中:父类引用指向子类对象,从而产生多种形态。
例如: Animal a=new Dog();
--------------^ ----------------^----------------
--------------|------------------|----------------
---------父类引用------子类对象-----------
条件:二者具有直接或间接的继承关系时,父类引用可以指向子类对象,即形成多态
父类引用仅可调用父类所声明的属性和方法,不能调用子类独有的属性和方法
(2)应用场景(案例)
案例演示:
//创建父类 Animal
public class Animal {
String name;
int age;
char sex;
public void sleep(){
System.out.println("睡觉,睡觉,睡觉");
}
public void eat(){
System.out.println("吃饭,吃饭,吃饭");
}
}
//创建子类对象Cat,并继承父类Animal
public class Cat extends Animal{
String Id;//子类独有属性
//子类独有方法
public void shout(){
System.out.println("喵喵!~~~");
}
}
//创建测试类Test01
public class Test01 {
public static void main(String[] args) {
Cat a=new Cat();//普通情况下实例化对象
System.out.println(a.age);
a.shout();
/**
* 总结:多态情况,父类引用无法访问子类的独有属性和独有方法
*/
//Animal animal=new Cat();//多态情况下实例化对象
//animal.shout(); 访问失败,多态情况下无法访问到子类独有的属性和方法
//System.out.println(animal.Id);
}
}
(3)多态下重写方法
经过案例的演示,虽然在多态下 父类引用无法访问子类对象独有的属性和方法,但是如果在子类中重写了父类中的方法,那么调用结果仍然遵循着重写的规则
(4)多态的应用场景
1、学生上学
案例需求:学生骑着自行车上班
分析:学生类 自行车类 (抽象类)交通工具
步骤:1、创建Car类,编写start 、 stop
2、在原有Teacher 类的基础上编写open、close
//编写抽象类Vehicle
public abstract class Vehicle{
//编写启动方法
public abstract void start();
//编写停止方法
public abstract void stop();
}
//编写自行车类并继承抽象类Vehicle
public class Bike extend Vehicle{
@Override
public void start(){
System.out.println("自行车:握好扶手,踩下脚踏板");
}
@Override
public void stop(){
System.out.println("自行车:捏手刹~~~");
}
}
//编写人类
public class Teacher{
//编写人驾驶方法
public void open(Vehicle v){//将Vehicle作为参数传入
v.start();
}
//编写人停止方法
public void close(Vehicle v){
v.stop();
}
}
//类的多态:子类对象指向父类引用
//父类引用中存储的是子类对象在堆中的地址
Teacher t = new Teacher();
Vehicle v = new Bike();
t.open(v);
System.out.println("欣赏沿途的风景...");
t.close(v);
2、选宠物(将父类作为返回值使用)
//创建父类Pet(定义为抽象类)
public abstract class Pet {
//创建抽象方法---吃
public abstract void eat();
//创建抽象方法--玩
public abstract void play();
}
//创建宠物 Dog 类并继承抽象类Pet完成其中的抽象方法
public class Dog extends Pet{
@Override
public void eat() {
System.out.println("狗在吃骨头");
}
@Override
public void play() {
System.out.println("狗在玩个球");
}
}
//创建宠物 Cat 类 继承并完成Pet的抽象方法
public class Cat extends Pet{
@Override
public void eat() {
System.out.println("猫喜欢吃鱼");
}
@Override
public void play() {
System.out.println("猫在玩毛线球");
}
}
//创建宠物Penguin类 继承Pet并完成其抽象方法
public class Penguin extends Pet{
@Override
public void eat() {
System.out.println("企鹅喜欢吃鱼");
}
@Override
public void play() {
System.out.println("企鹅正在游泳");
}
}
//创建主人类 编写其领养宠物方法(重点部分,将父类作为参数传入)
/**
* 多态形式3:父类作为方法返回值类型,子类实例化 类型自动转换
*/
public class Master {
public Pet getPet(int type){//将父类作为方法返回值类型,子类实例化 类型自动转换
Pet pet=null;
if (type==1){
pet=new Dog();//根据不同的选择实现了多态
}else if (type==2){
pet=new Cat();//根据不同的选择实现了多态
}else if (type==3){
pet=new Penguin();//根据不同的选择
}
return pet;//返回父类
}
}
//编写play方法
public class Play {
/**
* 父类转换为子类:向下转换 (强制) instanceof
*
* (子类转换为父类:向上转换 (自动))
*
* 主人和宠物一起玩
*
*/
public void play(Pet pet){
if (pet instanceof Dog){
Dog dog=(Dog) pet;//向下强制转换
dog.play();
}else if (pet instanceof Penguin){
Penguin penguin=(Penguin) pet;
penguin.play();
}else if (pet instanceof Cat){
Cat cat=(Cat) pet;
cat.play();
}
}
}
//编写Test方法
public class Test {
public static void main(String[] args) {
Scanner input =new Scanner(System.in);
System.out.println("请输入你需要领养的宠物的编号1-dog 2-cat 3-penguin:");
int chioce=input.nextInt();
Master master=new Master();
Pet pet=master.getPet(chioce);
pet.eat();
pet.play();
}
}
总结:如果存在多个子类的时候,需求进行升级,不止是靠自行车去学校也有可能是滑板车的等,这个时候如果纷纷使用重载的方法来进行修改的话会违背 开闭原则–OCP 即:在需求升级时,改变原有的代码是拒绝的,尽量不要改变以前的类,否则容易出Bug
总结以上案例:一、使用父类作为方法形参实现多态,是方法参数的类型更为宽泛
场景二:使用父类作为方法返回值实现多态,使方法可以返回不同子类对象,提高代码的可扩展性和可维护性。
(5)关于转型问题
1、向上转型(即装箱)
所谓向上转型在之前就已经提到过(在认识基本数据类型那一章的时候,别说忘了就在前面),在多态中父类引用中保存真实子类对象,成为向上转型(即多态核心概念)。
注意:
多态就是装箱, Animal a=new Cat(); 时 a只能调用父类中的属性和方法不能调用子类对象中的独有属性和方法,前面已经提到过。
2、向下转型(即拆箱)
所谓拆箱就是将父类引用中的真实子类对象,强转回子类本身类型,(可以使用 instanceOf 来判断是否为父子类关系),同时也只有转换回子类真实类型,才可以调用子类独有的属性和方法
3、类型转换异常
注意:如果向下转型时,若父类中应用的子类对象类型和目标类型不匹配,则会发生类型转换异常
案例演示
//创建父类Animal
class Animal{
public void eat(){
System.out.println("动物在吃.....");
}
}
//创建子类Dog继承父类Animal
class Dog extends Animal{
@Override
public void eat(){
System.out.println("狗在吃骨头....");
}
}
//创建子类Cat继承父类Animal
class Cat extends Animal{
@Override
public void eat(){
System.out.println("猫在吃鱼....");
}
}
//定义测试类
public class TestConvert{
public static void main(String [] args){
Animal a=new Dog();
Cat cat =(Cat)a;
//此处会报错,原因:强转的类型不匹配,由于上面的Animal的真实子类对象是 狗对象(Dog()),下面强转的时候 却把a强转成猫对象,故此会报错
}
}
(6)多态部分总结
多态的两种应用场景:
1、使用父类作为方法形参,实现多态
(1)调用方法时,可传递实参类型包括:本类型对象+其所有的子类对象。
2、使用父类作为方法返回值,实现多态、
(1)调用方法后,可得到的结果类型包括:本类型对象+其所有的子类对象
多态的作用:
1、屏蔽子类间的差异
2、灵活、耦合度降低
二、接口部分知识梳理
(1)什么是接口?
概念:接口是一种特殊的抽象类,其中有 公共静态属性 与 公共抽象方法,没有构造方法,也不能实例化对象
微观角度:接口是一种能力和约定。
(1)接口的定义:代表了某种能力
(2)方法的定义:能力的具体要求
宏观角度:接口是一种标准
1、所谓宏观角度下的接口,就像数据线和鼠标线以及各种能够连接到电脑数据连接口上的线一样,各个设备的功能不同但是他们的插孔形状都是一样的,这也就使得他们可以用一样的插头做不一样的事,而这个插头就是一种标准。
示例图:
格式: interface 接口名 {
//公开静态常量
public static final String FILED=“Value”;
//公共抽象方法
public abstract void method();
}
(2)接口与抽象类的异同
1、与抽象类的相同点
1、都可以继承Object类中的方法
2、都可以作为引用类型实现多态前提是有实现类实现了这个接口(等下后面会提到接口的多态)
3、都可以编译成字节码文件(.class)
4、不能创建对象
2、与抽象类的不同点
1、所有属性都是公开静态常量,隐式使用public static final修饰。
2、所有方法都是公开抽象方法,隐式使用public abstract 修饰
3、没有构造方法、动态代码块、静态代码块
(3)使用接口
使用接口的好处:
1、由于Java是单继承,当父类的方法种类无法满足子类需求时,可以实现接口来扩充子类能力。支持多个接口的实现,可为类扩充多种能力。
2、程序的耦合度更低
3、更自然地使用多态
4、设计与实现完全分离
5、更容易搭建程序框架
6、更容更换具体实现
使用接口的注意事项:
1、任何类在实现接口时,必须实现接口中所有抽象方法,否则此类为抽象类
2、实现接口中的抽象方法时,访问修饰符必须是public
(4)接口的引用(多态部分)
说明:我之所以将接口放到多态后面来讲,就是为了能够让大家更好理解这个接口的引用。
同父类一样,接口也能声明为引用,并指向实现类对象
注意:
1、仅能调用接口中所声明的方法,不能调用实现类中独有的方法。
2、可以强转会实现类本身类型,进行独有方法调用。
接口的多态和父类的多态几乎是一样的,就是将接口当做一个抽象类来作为引用使用,很是方便
总结
以上就是今天要讲的内容,多态部分的重点是理解两个使用场景1、将父类作为参数传入,2、将父类作为返回值使用的好处,接口的内容目前就这些,等以后遇到了新的内容 我再进行补充说明。