Java从入门到放弃09—多态/向上转型/向下转型/多态内存图/抽象类/关键字abstract不能和哪些关键字共存/接口/类与类,类与接口,接口与接口的关系/抽象类与接口的区别

01 多态

  • 多态指的是某个事物,在某个时刻所表现出来的不同状态。

  • 多态的三个必要条件:

    1.要有继承。(存在父类和子类)

    2.要有方法重写,可以没有,但是多态就没有意义了。

    3.父类引用指向子类对象。如Animal为父类,Cat为猫类。父类引用指向子类对象 Animal cat=new Cat();

  • 多态的优势:提高代码的复用性(通过继承来实现),提高代码的扩展性(通过面向父类型传参来实现)。

  • 多态的弊端:父类引用可以访问被子类重写的方法,但不能直接访问子类的特有功能。(可以通过向下转型去访问)

  • 多态其实就是向上转型。子类转为父类


程序示例1:多态形式访问成员变量,编译运行看左边(这里的左边指,new对象的语句中等号的左边)

public class MyTest {public static void main(String[] args) {//以多态的形式来访问成员变量 使用的还是父类的变量//编译看左边,运行也看左边Fu f = new Zi();//多态 父类引用指向子类空间System.out.println(f.num);//访问的是父类变量中的num}
}
class Fu{int num = 100;public void show(){System.out.println("父类的show方法");}
}
class Zi extends Fu{int num=10;@Overridepublic void show() {System.out.println("子类重写过后的show方法");}
}
运行结果:100

程序示例2:多态形式访问成员方法,编译看左边,运行看右边(这里的右边指,new对象的语句中等号的右边)

public class MultiStateTest {public static void main(String[] args) {Animal cat = new Cat();MyUtils.eatTest(cat);Animal dog = new Dog();MyUtils.eatTest(dog);Animal sheep = new Sheep();MyUtils.eatTest(sheep);//使用多态传入sheep(属于animal类),先进入父类,再调用子类重写后的方法(运行看右边)}
}
class Animal{public void eat(){System.out.println("吃饭");}
}
class Cat extends Animal{@Override//检查方法重写 快捷键ctrl+Opublic void eat() {System.out.println("猫吃鱼");}
}
class Dog extends Animal{@Overridepublic void eat() {System.out.println("狗吃肉");}
}
class Sheep extends Animal{@Overridepublic void eat() {System.out.println("羊吃草");}
}
class MyUtils{private MyUtils() {//将工具包私有化,让外部不能使用空参构造创建对象,也不需要}public static void eatTest(Animal animal){//用static修饰该方法,可以不创建对象,通过类名直接调用调用该方法。animal.eat();//根据传入的参数,执行方法重写机制}
}
运行结果:猫吃鱼狗吃肉羊吃草

02 向下转型

  • 父类只能访问子类的重写方法,如果想要父类能够访问子类的特有方法,需要进行向下转型。
  • 向下转型可理解为父类强制转换为子类,语法为 子类名 对象名=(子类名) 父类对象。

程序示例:

public class MultiStateTest01 {public static void main(String[] args) {Humanbeing s= new Student1();//父类引用指向子类,其实就是向上转型,即多态s.eat();//父类可以访问父类的方法,及子类的重写方法s.sleep();//父类可以直接访问子类的重写方法Student1 s1=(Student1)s;//父类引用指向子类s1.learning();//向下转型后,父类才能调用子类的特有方法Humanbeing t=new Techer();t.eat();//父类可以直接访问子类的重写方法t.sleep();//父类可以直接访问子类的重写方法((Techer) t).tech();//省略写法,((Teacher)t)表示向下转型。向下转型后,父类才能调用子类的特有办法}
}
class Humanbeing{public void sleep(){System.out.println("go to sleep");}public void eat(){System.out.println("eat foods");}
}
class Techer extends Humanbeing{@Overridepublic void sleep() {System.out.println("sleep with his wife");}public void tech(){System.out.println("teaching");}
}
class Student1 extends Humanbeing{@Overridepublic void eat() {System.out.println("eat hot-pot");}public void learning(){System.out.println("study");}
}
运行结果:eat hot-potgo to sleepstudyeat foodssleep with his wifeteaching

  • 向下转型的注意事项:必须先new一个子类,该子类开辟出引用空间后,才能进行强制转换。否则会报错ClassCastException 类型转换异常。

程序示例:

public class MyTest {public static void main(String[] args) {Cat cat = new Cat();Animal an=cat; //多态,父类引用指向子类空间,实质是向上转型an.eat();Cat c= (Cat) an; //向下转型c.eat();//向下转型后,可以调用子类的个性功能c.cacheMouse();Dog dog = new Dog();an=dog;Dog d= (Dog) an; //向下转型d.lookDoor();an.eat();// an=new Tiger();Tiger t= (Tiger) an;//执行该语句前,由于没有new出tiger的子类空间并将父类引用指向子类空间,因此程序报错 ClassCastException 类型转换异常t.goSwimming();}
}
class Animal{//父类public void eat(){System.out.println("吃饭");}
}
class Cat extends Animal{@Overridepublic void eat() {//共性方法重写System.out.println("猫吃鱼");}public void cacheMouse(){//个性方法System.out.println("猫抓老鼠");}
}
class Dog extends Animal{//子类@Overridepublic void eat() {//子类重写方法System.out.println("狗吃肉");}public void guardHomer(){//子类个性方法System.out.println("狗守家");}
}class Tiger extends Animal{@Overridepublic void eat() {//子类重写方法System.out.println("老虎不吃素");}public void goSwimming(){//子类个性方法System.out.println("老虎去游泳");}
}
运行结果:猫吃鱼猫吃鱼猫抓老鼠狗看门狗吃骨头Exception in thread "main" java.lang.ClassCastException//报错

03 多态内存图

  • 子类在堆内存中开辟的空间内有一块由super标识的空间,父类在这块空间内进行初始化。
  • 在调用方法时,父类引用会依据动态绑定机制,将引用空间指向子类的重写方法。

程序示例:

public class MyTest {public static void main(String[] args) {Fu fu = new Zi();System.out.println(fu.num);fu.show();Zi zi= (Zi) fu;System.out.println(zi.num);zi.test();}
}
class Fu{int num=100;public void show(){System.out.println("fu show");}
}
class Zi extends Fu{int num=20;@Overridepublic void show() {System.out.println("zi show");}public void test(){System.out.println("zi test");}
}
运行结果:100zi show20zi test

内存图解:


04 多态题目分析

class A {//10.A类虽然有show方法,但是C类对show方法进行了覆盖,因此执行C.showpublic void show() {//3.子类B没有show方法,因此执行A.showshow2();//4./12.执行show2   }public void show2() {//5.由于子类B重写了show2,因此不执行该方法 13.子类C重写了show2,因此执行C.show2System.out.println("我");}}class B extends A {//9.父类B没有show方法,但是继承的A类有show方法public void show2() {//6.执行B.show2,打印爱System.out.println("爱");}}class C extends B {public void show() {super.show();//11.执行父类show方法,即执行父类B继承的父类A的show方法}public void show2() {//13.执行C.show2,打印你System.out.println("你");}}public class DuoTaiTest4 {public static void main(String[] args) {A a = new B();//1.父类a引用指向子类Ba.show();//2.调用父类a的showB b = new C();//7.父类b引用执行子类Cb.show();//8.调用父类b的show}}
运行结果:爱你

05 抽象类

  • 场景引申:父类将所有子类的共性功能向上抽取后,并不知道每个子类对共性功能的具体实现,因此没必要在父类中给出共性功能的具体实现,给出声明即可。
  • 抽象类概述:一个没有方法体的方法应该定义为为抽象方法,而类中如果有抽象方法该类必须定义为抽象类。
  • 抽象类和抽象方法必须用abstract关键字修饰
  • 抽象类格式:权限修饰符 abstract class 类名{}
  • 抽象方法格式:权限修饰符 abstract 返回值类型 方法名();

程序示例

public class MyTest {public static void main(String[] args) {Animal an=new Cat();//抽象类不能直接创建对象,可以采用多态间接的去实例化抽象类an.eat();an.sleep();an.show();}
}
abstract class Animal {public Animal() {System.out.println("父类的构造方法执行了");}public abstract void eat(); //抽象方法,此方法没有具体方法实现public abstract void sleep();//抽象类中既可以有抽象方法,也可以非抽象方法public void show(){System.out.println("这是父类的一个非抽象方法");}
}
class Cat extends Animal{@Overridepublic void eat() {//抽象类的子类必须重写所有抽象方法System.out.println("猫爱吃鱼");}@Overridepublic void sleep() {System.out.println("猫白天睡觉");}
}

  • 抽象类特点:

    1.抽象类不一定有抽象方法,有抽象方法的一定是抽象类。

  1. 抽象类中可以有构造方法,但是抽象类不能直接通过构造方法进行实例化,需要使用多态对抽象类进行实例化。抽象类的构造方法用于子类访问父类数据时的初始化。
  2. 抽象类按照多态的形式,由具体的子类实例化。
  3. 抽象方法必须被重写,否则会报错(要么将子类也定义为抽象类)。

  • 抽象类的面试题

  • 一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?

    答:抽象类中可以没有抽象方法。一个抽象类中没有抽象方法的意义在于该类不用也不能被实例化。比如Java中的有些工具类,虽然被定义为抽象类,但是类中的方法都用static修饰,可以直接通过类名调用,没必要进行实例化,用abstract修饰类名可以防止由该类生成实例。

  • abstract不能和关键字private/final/static并存,为什么?

    答:被abstract修饰的方法需要被子类重写,而被private修饰的类或方法只能在本类中被访问不能被继承,因此冲突。被final修饰的类不能被继承,方法不能被重写,因此冲突。static静态方法存放在方法区的静态区,无需实例化,可用类名调用。而被abstract修饰的方法需要通过多态进行实例化,如果两者并存,通过类名调用抽象的静态方法将是无意义的。


06 接口

  • 接口相关面试题:

  • Java中有多继承吗?

    答:分情况,接口与接口之间可以实现多继承,但是类与类之间不可以多继承,只能单继承或者多层继承。


  • 抽象类和接口的区别:抽象类,抽取所有子类的共性功能,并强制子类对共性功能进行重写。接口定义的是整个继承体系中的一些额外的扩展功能,哪些类想要具备这些扩展功能,可以单独去实现某个接口。区别:1.抽象类中有构造方法,接口中没有构造方法。2.抽象类中既可以有抽象方法,也可以由非抽象方法。接口中全是抽象方法。3.抽象类中既可以有成员变量,也可以有常量,接口中全是公共的静态常量。

  • 注意:JDK1.8之后接口中可以定义默认方法(有具体的方法实现),但是要在权限修饰符后加关键字default,否则会报错。(定义默认方法,能弥补单继承的劣势,类只能单继承,但是类可以实现多个接口,通过接口实现多方法的继承)


  • 接口的特点

    1.接口不能直接实例化,需要通过多态的方式进行实例化。

    2.接口中的子类可以是抽象类,但这样做的意义不大。接口中的子类也可以是具体类,具类要重写接口中的所有抽象方法。

    3.接口用关键字interface表示。

    interface 接口名{}
    

    4.类实现接口用implements表示

    class 类名 implements 接口名{}
    

    类实现多个接口可以表示为(接口可以多继承):

    class 类名 implements 接口名1,接口名2{}
    

  • 接口成员的特点

    interface interface{//没有构造方法public static final int NUM=100;//成员变量只能是常量,默认修饰符为public static finalpublic abstract void test1(){}//JDK1.7之前成员方法只能是抽象方法,默认修饰符为public abstractpublic default void test2(){}//JDK1.8之后成员方法可以具体实现,但是该方法必须被default修饰。
    }
    

    总结:1.成员变量只能是常量,并且是静态的。

    ​ 2.没有构造方法。

    ​ 3.成员方法只能是抽象方法(JDK1.8之后有默认方法)


  • 程序示例
public class Test {public static void main(String[] args) {Cat cat = new Cat();Animal animal1=cat;//抽象父类引用指向子类,实现实例化animal1.eat();Cat c=(Cat)animal1;//向下转型Calc ca1=c;//接口引用指向子类,实现实例化ca1.calc();Jump j=c;//接口引用指向子类,实现实例化j.jumpFireCircle();Dog dog = new Dog();Animal animal2=dog;animal2.eat();Dog d=(Dog)animal2;//向下转型d.guardHome();Calc ca2=d;//接口引用指向子类,实现实例化ca2.calc();}
}abstract class Animal {//成员变量private String name;private int age;//空参构造方法public Animal() {}//有参构造方法public Animal(String name, int age) {this.name = name;this.age = age;}public abstract void eat();
}interface Calc {public abstract void calc();
}interface Jump {public abstract void jumpFireCircle();
}class Dog extends Animal implements Calc{//类实现单接口@Overridepublic void eat() {System.out.println("狗吃肉");}@Overridepublic void calc() {System.out.println("狗学会了10以内的加减法");}public void guardHome(){System.out.println("狗的个性本领是守家");}
}class Cat extends Animal implements Calc,Jump {//类实现多接口@Overridepublic void eat() {System.out.println("猫吃鱼");}@Overridepublic void calc() {System.out.println("猫学会了10以内的加减法");}@Overridepublic void jumpFireCircle() {System.out.println("猫学会了跳火圈");}
}
运行结果:猫吃鱼猫学会了10以内的加减法猫学会了跳火圈狗吃肉狗的个性本领是守家狗学会了10以内的加减法

07 类与类,类与接口,接口与接口的关系

  • 类与类:继承关系,只能单继承,可以多层继承。
  • 类与接口:实现关系,可以单实现,也可以多实现。并且还可以在继承一个类的同时实现多个接口。
  • 接口与接口:继承关系,可以单继承,也可以多继承。

Java从入门到放弃09---多态/向上转型/向下转型/多态内存图/抽象类/关键字abstract不能和哪些关键字共存/接口/类与类,类与接口,接口与接口的关系/抽象类与接口的区别相关推荐

  1. java从入门到放弃(二)

    java从入门到放弃(二) //求园面积 结果保留5位小数double ymj = Math.PI*Math.pow(``2.14``,` `2``);DecimalFormat df1 =new D ...

  2. Java从入门到放弃-序言

    Java从入门到放弃 前言 本人希望由浅及深的探讨java的底层原理,和编程思想,与大家一起学习提升对程序语言的认知.由于自己是理工科出身,所以对底层原理往往非常感兴趣.那么就跟我一起学习Java吧. ...

  3. Java多态中的 向上转型/向下转型

     Java 向上转型和向下转型的详解 转型是在继承的基础上而言的,继承是面向对象语言中,代码复用的一种机制,通过继承,子类可以复用父类的功能,如果父类不能满足当前子类的需求,则子类可以重写父类中的方法 ...

  4. Java 中的上转型和下转型

    在我们的日常中,上转型和下转型都使用的比较少,所以当别人问起来什么是上转型,什么是下转型,自己往往一片模糊,或者不能将他们进行明显的区分. 在这里,我将以我个人理解来论述上下转型,希望对大家有帮助,如 ...

  5. 类.接口.多态.向上转型.向下转型

    一:综述 电脑利用USB接口实现键盘的输入.鼠标的移动 二:代码 USB.java package ClassAndObject;public interface USB {public abstra ...

  6. Java接口,多态,向上转型,向下转型的意义

    接口 官方解释: Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现 ,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能). 包含 ...

  7. JAVA中多态以及向上转型向下转型、重写的讲解

    重写 重写(override):也称为覆盖.重写是子类对父类非静态.非private修饰,非final修饰,非构造方法等的实现过程 进行重新编写, 注意!!!返回值和形参都不能改变. 重写的好处在于子 ...

  8. java:多态详解,以及对象的向上和向下转型

    大家好,兔胆包天我又来啦,今天给大家分享的是多态,多态最主要的是父类引用指向子类对象,还是老办法,直接上代码,代码中注解的很详细哦. 这是第一个代码: //测试多态 public class Anim ...

  9. 访问修饰符、常见的包以及包的权限和包的导入(inport关键字)、继承(super关键字)、多态(向上和向下转型)

    IDEA中快捷生成getter/setter的快捷键为 alt+inser(enter) getter/setter命名规范:都是以gte/set单词开头+要操作的属性名称 一.访问修饰符 Java中 ...

最新文章

  1. 小米:开源不仅要站在巨人的肩膀上,还要为巨人指方向
  2. 读书笔记--MapReduce 适用场景 及 常见应用
  3. 这大概是一篇最简单最清晰的Java JVM执行流程
  4. [luoguP1640] [SCOI2010]连续攻击游戏(二分图最大匹配)
  5. 不调用python函数实现直方图均衡化_直方图均衡化(HE)
  6. C++const类型的引用参数
  7. Microsoft System Center Configuration Manager 2007 工作流中文版
  8. process启动jar包判断成功_恒一广告助力2020年壹基金温暖包安康发放启动仪式成功举办...
  9. 第一范式,第二范式,第三范式,BCNF范式理解
  10. ionic/cordova即时通讯解决方案(上)
  11. 新来的妹子把几百万数据放入了内存,系统立马爆了,我不得已做到了妹子傍边,手把手教妹子...
  12. Anaconda下载与安装详解
  13. 辉凌医药和维健医药就可利新达成战略合作
  14. 1、NESSUS安装
  15. mysql.sock 路径_关于mysql.sock路径的问题
  16. exchange服务器维护,EXCHANGE故障排除步骤简述
  17. 5.Linux系统中解压缩详解
  18. 微信语音麦克风静音_微信中打电话静音是我被静音还是对方被静音,具体这个静音是什么意思...
  19. 15个好用的百度网盘搜索引擎
  20. 2021-09-20德天老师更新好学易懂的python办公自动化批量生成docx

热门文章

  1. FIL WORLD算力众筹助推Filecoin生态落地
  2. Zigbee Light Link协议的五种Key
  3. 【内网学习笔记】9、iodine 使用
  4. 怎样把jpg格式转成pdf格式
  5. “AI+制造”第一股!李开复躬身实践,创新奇智3年IPO!
  6. 极速系列07—利用python将文件夹快速分类
  7. 电子英汉词典附带背单词功能C语言程序设计,附录完整代码
  8. 爬取女友淘宝已购买的宝贝数据,发现了她特殊的秘密...
  9. Office365学习笔记—创建WikiPage
  10. Linux基础知识大合集