多态
2.特点
- 多态的前提1 : 是继承
- 前提2 : 方法的重写
- 父类引用类型指向子类对象; 如: Animal a = new Cat()
- 多态中,编译看左边 ,运行看右边
1.前提: 继承+ 重写
2.口诀1 : 父类引用指向子类对象
解释: 父类类型的引用类型变量保存的是子类类型的对象的地址值
2.口诀2: 编译看左边, 运行看右边
解释: 编译时要看父类是否定义了这个资源,运行时使用的是子类的功能
3.资源使用情况
- 成员变量使用的是父类的
- 成员方法使用的是父类的方法定义,子类的方法体
- 如果多态对象调用的是子类没有重写过的方法,方法定义与方法体使用都是父类的,所以这个不符合多态的前提,直接使用纯纯的父类对象调用即可.
- 静态资源属于类资源,随着类的加载而加载,只会加载一次,优先于对象进行加载,可以通过类名直接调用,被全局所有对象共享,所以静态不存在重写的现象,在哪个类定义,就属于哪个类的资源
- 我们现在学习的多态,把自己看做是父类类型,参考"花木兰替父从军"
异常
异常图表:
Throwable: 顶级父类
–Error: 错误,程序无法处理
–virtulMachineErrorJava --虚拟机运行错误
–StackOverFlowError
–OutOfMemoryError
–Exception: 我们可以编译修复的错误
–RunTimeException --运行时异常
–ArithmeticException
–InputMismatchExcption
–IOException --IO异常
- 根是 Throwable
- error: 目前我们是暂时解决不了的问题
- exception: 异常 , 运行时异常 ,编译时异常
- 异常的解决方案 ; 两种 第一: 自己捕获自己解决 第二 : 向上抛出 throws 用于团队协作,注意不能把问题抛给main方法,因为调用main方法的是jvm虚拟机
抽象
abstract
- 抽象类是被abstract 修饰的类
- 抽象类对其中的方法不做限制: 全普/全抽/半普半抽
- 抽象类不可以实例化 – 创建对象
- 如果一个子类继承了一个抽象父类,有两种解决方案
继续抽象/实现抽象父类的所有抽象方法,变成普通子类
抽象方法
- 抽象方法是被abstract修饰的方法
- 抽象方法没有方法体{}, 以分号结束
package cn.tedu.oop;
/**
* 本类用作抽象类的入门案例
* @author ZHU
* @create 2021/8/10 17:16
*/
public class AbstractDemo1 {
public static void main(String[] args) {
/**
* 3. 抽象类不可以实例化 -- 创建对象
*/
// new Phone();
Phone p = new XM();
p.money(); //多态对象调用子类实现的方法,注意方法的定义看的还是父类的
p.call(); //多态对象调用父类自己的方法
}
}
//1.创建类
/**
* 1.被abstract 修饰的类是抽象类
* 如果一个类中包含了一个抽象方法,那么这个类必须声明成一个抽象类
*/
abstract class Phone{
//2.创建普通方法
public void call(){
System.out.println("call ing");
}
public void message(){
System.out.println("send message ing");
}
//3.创建本类的抽象方法
/**
* 被abstract修饰的方法时抽象方法,抽象方法没有方法体
*/
abstract public void money();
abstract public void money2();
}
//创建子类小米类
/**
* 4.当一个类继承了一个抽象父类,有两种解决方案:
* 方案一: 变成抽象子类 "躺平,我也不实现,继续抽象"
*方案二: 实现抽象父类中的所有抽象方法,"父债子偿"
*/
//abstract class XM extends Phone{}
class XM extends Phone {
@Override
public void money(){
System.out.println("实现父类未实现的方法");
}
@Override
public void money2(){
System.out.println("实现父类未实现的方法2");
}
}
package cn.tedu.oop;
/**
* 本类用作抽象类的入门案例
* @author ZHU
* @create 2021/8/10 17:16
*/
public class AbstractDemo1 {
public static void main(String[] args) {
/**
* 3. 抽象类不可以实例化 -- 创建对象
*/
// new Phone();
Phone p = new XM();
p.money(); //多态对象调用子类实现的方法,注意方法的定义看的还是父类的
p.call(); //多态对象调用父类自己的方法
}
}
//1.创建类
/**
* 1.被abstract 修饰的类是抽象类
* 如果一个类中包含了一个抽象方法,那么这个类必须声明成一个抽象类
*/
abstract class Phone{
//2.创建普通方法
public void call(){
System.out.println("call ing");
}
public void message(){
System.out.println("send message ing");
}
//3.创建本类的抽象方法
/**
* 被abstract修饰的方法时抽象方法,抽象方法没有方法体
*/
abstract public void money();
abstract public void money2();
}
//创建子类小米类
/**
* 4.当一个类继承了一个抽象父类,有两种解决方案:
* 方案一: 变成抽象子类 "躺平,我也不实现,继续抽象"
*方案二: 实现抽象父类中的所有抽象方法,"父债子偿"
*/
//abstract class XM extends Phone{}
class XM extends Phone {
@Override
public void money(){
System.out.println("实现父类未实现的方法");
}
@Override
public void money2(){
System.out.println("实现父类未实现的方法2");
}
}
package cn.tedu.oop;
/**
* 本类用作多态的入门案例
* @author ZHU
* @create 2021/8/10 10:13
*/
public class TestDemo {
public static void main(String[] args) {
//6.创建对象用于测试
Animal a = new Animal();
Cat c = new Cat();
Dog d = new Dog();
a.eat();
c.eat();
d.eat();
// a.play(); 父类不能调用子类的特有功能
c.play();
d.play();
//8.创建多态对象进行测试
/**
* 3.格式 : 父类引用指向子类对象
* 解释: 创建出来的子类对象的地址值交给父类类型的引用类型变量来保存
*/
Animal a2 = new Dog();
Animal a3 = new Cat();
/**
* 4.编译看左边 运行看右边
* 解释: 必须要父类定义这个方法,才能通过编译
* 必须要子类重写这个方法,才能满足多态,运行时实际干活的是子类
*/
a2.eat();//小猫爱吃小鱼干, 多态对象可以调用重写后的方法
//a2.eat(); 多态对象把自己看做是父类类型,不能使用子类的特有方法
}
/**
* 1.多态的前提: 继承 + 重写
*/
//创建父类
}
class Animal{
public void eat(){
System.out.println("小动物Animal吃啥都行");
}
}
//2.1 创建子类小猫类Cat并与Animal建立继承关系
class Cat extends Animal{
//4.1 添加子类重写的方法
@Override
public void eat(){
System.out.println("小猫爱吃小鱼干");
}
public void play(){
System.out.println("小猫太懒啦");
}
}
//2.2 创建子类小狗类Dog并与Animal建立继承关系
class Dog extends Animal{
@Override
public void eat(){
System.out.println("小狗爱吃肉骨头");
}
public void play(){
System.out.println("小狗Dog跑的老快了");
}
}
package cn.tedu.oop;
/**
* 本类用于测试多态当中的元素使用
* @author ZHU
* @create 2021/8/10 11:12
*/
public class TestDemo2 {
public static void main(String[] args) {
Animal2 a = new Animal2();
Dog2 d = new Dog2();
Animal2 a2 = new Dog2();
d.eat();
a2.eat();
d.play(); //
/**
* 口诀2 :
* 1.编译看左边,运行看右边
* 2.多态中,成员变量使用的都是父类的
*/
/**
* 3.多态中,成员方法的定义使用的是父类的,实现(实现体) 使用的是子类的
*/
/**
* 4.多态中,如果父子都有静态重名的方法,这个不是重写的现象
* 所以静态方法调用的还是父类的实现(方法体)
*/
a2.play();
}
}
class Animal2{
int sum = 10;
public void eat(){
System.out.println("吃啥都行");
}
public static void play(){
System.out.println("玩啥都行");
}
}
/**
* 1. 多态的前提: 继承加重写
*/
//2.创建子类
class Dog2 extends Animal2{
//6.定义子类的成员变量
int sum = 20;
//7.重写父类中的方法
@Override
public void eat(){
System.out.println("小狗爱吃肉包子");
}
/**
* 3.静态方法不存在重写的现象,在哪个类里写,就属于哪个类的资源,可以被类名直接调用
*/
//7.2 添加子类的静态方法
public static void play(){
System.out.println("小狗爱打滚");
}
}
package cn.tedu.oop;
import javax.jws.soap.SOAPBinding;
/**
* 本类用于多态的巩固练习
* @author ZHU
* @create 2021/8/10 14:00
*/
//需求: 设计小汽车类,旗下有两个类: 宝马类与特斯拉类
public class TestExec {
public static void main(String[] args) {
//7.创建一个纯纯的父类对象进行测试
Car c = new Car();
System.out.println(c.getColor()); //null,成员变量的默认值
c.start();//父类对象调用自己的功能
c.stop();
//c.fly() 父类不能调用子类的特有功能
//10.创建一个纯纯的子类对象
BMW b = new BMW();
System.out.println(b.color); //子类对象调用自己的属性
b.start(); //没重写,使用的就是继承自父类的功能
b.stop(); // 没重写,使用的就是继承自父类的功能
//12.创建多态对象进行测试
/**
* 多态对象调用方法,如果方法没有重写,使用的是父类的功能,因为它把自己看作是父类型
* 如果方法重写了,那么方法的定义看父类,方法体看子类
*/
Car c2 = new Car();
c2.start();
c2.stop();
}
}
//1.定义小汽车类
class Car{
//2.添加属性,并对属性进行封装
private String brand;
private String color;
private double price;
private double size;
//3.定义本类的一些行为
public void start(){
System.out.println("启动我心爱的小车车");
}
public void stop(){
System.out.println("赶紧刹车");
}
//2.2 要对属性提供公共的设置与访问方式get() 与 set()
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public double getSize() {
return size;
}
public void setSize(double size) {
this.size = size;
}
}
//4.创建子类宝马类
class BMW extends Car{
//5.添加子类的属性
String color = "五彩斑斓的黑";
@Override //添加注解,标注这是一个重写的方法
//11.添加一个重写的方法
public void start(){
System.out.println("咻咻咻, 发射成功");
}
}
//6.创建子类特斯拉
class TSL extends Car{
//7.添加子类属性
String color = "黑不溜秋的白";
public void fly(){
System.out.println("哎呀,我的小车车飞起来啦");
}
}
package cn.tedu.review;
import java.lang.ref.SoftReference;
/**
* @author ZHU
* @create 2021/8/10 9:08
*/
public class ReviewExtends {
public static void main(String[] args) {
Animal a = new Animal();
Dog d = new Dog("精制狗粮");
WangCai w = new WangCai();
a.eat();
d.eat();
w.eat();
//9.5调用方法进行同名变量测试
w.play();
a.play();
d.play();
System.out.println(w.age);
}
}
class Animal{
public void eat(){
System.out.println("小动物吃啥都行");
}
public void play(){
System.out.println("小动物玩啥都行");
}
}
class Dog extends Animal{
int age =10000;
private String name;
//8.1 创建本类的含参构造
public Dog(String food){
System.out.println("小狗爱吃" + food);
}
@Override
public void play(){
System.out.println("小狗跑得可快了");
}
}
/**
* 给父类dog手动添加了含参构造以后,两个子类都报错了,为什么 ?
* 1.父类Dog手动添加了含参构造后,默认的无参构造会被覆盖
* 2.子类也存在默认的无参构造,并且构造函数的第一句是super(); 表示调用父类的无参构造
* 3.由于父类的无参构造已被覆盖,无可用构造函数,所以报错
*
* 解决方案:
* 前提: 子类创建对象时必须调用构造函数 [先父类构造函数 & 再子类构造函数]
* 注意: 子类并不关系调用的是父类的哪个构造函数,只要有一个可调用即可
* 在子类中调用父类的其他构造函数,格式 super(参数) ; -- 必须写在首行
*/
class WangCai extends Dog{
int age =10;
public WangCai(){
super("肉骨头");
}
@Override
public void play(){
int age = 100;
System.out.println(age);
System.out.println(this.age);
System.out.println(super.age);
}
}
class XiaoBai extends Dog{
//java是一个单继承的语言
public XiaoBai(){
super("狗粮");
}
}