继承和多态

继承

概念

继承是面向对象编程(Object-Oriented Programming,
OOP)中的一个核心概念。它允许一个类(称为子类或派生类)从另一个类(称为父类或基类)继承属性和方法

为什么要学继承

在实际生活和开发中,事物与事物中存在一些关联,而用Java语言来描述时,代码就会有重复的
比如说,学生和老师在下课后都要去吃饭,那么就要在老师和学生类中分别写同样的方法去描述吃饭这个行为
那我们通过继承(共性抽取),就可以提高代码的灵活性和复用性,只需要再写一个人的类,让学生和老师类继承

extends关键字

通过extends关键字就可以实现继承了

语法格式

修饰符 class 子类 extends 父类{
}

注意事项

注意

  1. 子类会将父类中的成员变量或者成员方法继承到子类中了
  2. 子类继承父类之后,必须要新添加自己特有的成员,体现出与基类的不同,否则就没有必要继承了

访问权限

子类中访问父类的成员变量

子类和父类不存在同名成员变量
遵循就近原则,子类有,优先在子类找,无再去父类找

子类中访问父类的成员方法

通过子类对象访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到
则访问,否则编译报错。

通过派生类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同(重载),根据调用
方法适传递的参数选择合适的方法访问,如果没有则报错;

super关键字

如果子类中存在与父类中相同的成员时
那如何在子类中访问父类相同名称的成员呢?

可以通过super关键字访问父类中的成员

引用形式和this关键字差不多

注意事项

只能在非静态的方法中使用
在子类方法中,访问父类的成员变量和方法

子类构造方法

要记住先有父再有子,在构造子类对象时,先调用父类的构造方法,需要子类把继承下来的成员构造完整,再调用子类的构造方法,将子类自己新增加的成员初始化完整

也就是在子类中需要显性的初始化继承下来的父类构造方法

public class Dog extends Animal{
    private String gendar;
    public Dog(String name,int age,String gendar){
        super(name,age);
        this.gendar=gendar;
    }
    public Dog() {
    }

    public String getGendar() {
        return gendar;
    }
    public void setGendar(String gendar) {
        this.gendar = gendar;
    }

}
public class Animal {
    private String name;
    private int age;
    public Animal(String name,int age){
        this.name=name;
        this.age=age;
    }
    public Animal() {
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

this和super的区别

thissuper
引用对象引用当前对象的属性或方法子类引用父类的属性或方法

继承关系上的执行顺序

public class Dog extends Animal {
    static {
        System.out.println("static:dog()....");
    }
    {
        System.out.println("实例化代码dog()...");
    }
    public Dog(String name,int age){
        super(name,age);
        System.out.println("Dog:构造方法执行了...");
    }
    //静态的不能调用非静态的,不依赖对象的不能调用依赖对象的
    public void eat(){
        System.out.println(getName()+"正在吃饭....");
    }

}
public class Animal {
    private String name;
    private int age;
    static {
        System.out.println("static:Animal()....");
    }
    {
        System.out.println("Animal:实例化代码块()...");
    }

    public void eat()public Animal() {
    }
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("Animal:构造方法执行了");
    }
    //这里省略了set和get方法
 }
public class Test {
    public static void main(String[] args) {
        Animal animal=new Dog("小狗",18);
        animal.eat();
	}
}

在这里插入图片描述

方法的重写

重写注意事项:

  1. 父类方法不能用privatestatic修饰
  2. 子类的访问权限要大于父类
  3. 返回值类型子类必须小于等于父类
  4. 父类引用调用重写的方法
  5. 只有被添加到虚方法表中的方法才能被重写
重写与重载的区别
区别重写override重载overload
定义方法名,类型,返回值一致方法名一致,返回值,参数类型不一致
权限修饰符无要求子类的访问权限必须比父类大或者一样
范围发生在一个类中发生在继承中
访问权限范围
publicprivatedefaultprotected
同类
同包
不同包的非子类
不同包子类

多态

概念

不同的对象对于某一个方法有不同的表现形式

多态的优势

方法中,使用父类作为参数,可以接收所有子类对象
提高了代码的复用性

实现条件

  1. 多态是在继承的基础之下而谈的
  2. 子类必须对父类中的方法进行重写
举个例子

写一个花的类,不同的花开花有不同的形态

public class Flower {
    public Flower() {
    }

    public void open() {
        System.out.println("我要开花!");
    }
}
public class Rose extends Flower {
    public Rose() {
    }
    @Override
    public void open() {
        System.out.println("我是带刺的玫瑰!!!");
    }
}
public class sunFlower extends Flower {
    public sunFlower() {
    }
	@Override
    public void open() {
        System.out.println("我要向阳而生");
    }
}
public class Test {
    public Test() {
    }
    public static void main(String[] args) {
        Rose rose = new Rose();
        sunFlower sunFlowers = new sunFlower();
     
        //通过数组的方式遍历打印
        Flower[] flowers = new Flower[]{rose, sunFlowers};
        Flower[] flw = flowers;
        int count = flowers.length;
        for(int i = 0; i < count; ++i) {
            Flower flower1 = flw[i];
            flower1.open();
        }
    }
}

向上转型

创建一个子类对象,把他当成父类对象来使用

格式

父类类型 对象名 =new 子类类型()

动态绑定

动态绑定:也称为后期绑定(晚绑定),即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体调用那个类的方法。

也就是当程序编译时,通过父类引用子类重写的方法时,实际上调用了子类的方法

使用方式

直接赋值

   Animal animal=new Dog("小狗",18);

作为方法的参数

public class Test {
    public static void func(Animal animal){
        animal.eat();
    }
    public static void main(String[] args) {
         Dog dog=new Dog("小狗",18);
         func(dog);
    }
}

作为返回值

public class Test {
    public static Animal func(){
       Animal animal=new Dog("小狗",18);
       return animal;
    }
   public static void main(String[] args) {
		Animal animal=func();
        animal.eat();
    }
}

多态的弊端

不能调用子类的特有功能
如果一定要调用就要向下转型

向下转型

将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的方法
此时:将父类引用再还原为子类对象即可,即向下转换。

强制性转换(大转小)

public class Test {
    public static void main(String[] args) {
   Animal animal=new Dog("小狗",18);
        Dog dog=(Dog) animal;
        dog.eat();
   }
}

弊端

父类直接指向的可以向下转型,如果不是不能瞎转,如果转换成其他类的类型,就会报错

public class Test {
    public static void main(String[] args) {
        Animal animal=new Dog("小狗",18);
        Cat cat=(Cat) animal;
        cat.eat();
    }
}

在这里插入图片描述

解决方案

通过instanceof关键字去判断父类是否直接引用了子类类型

 if(animal instanceof Dog){
            Dog d=(Dog)animal;
            d.eat();
        }else if(animal instanceof Cat){
            Cat cat=(Cat) animal;
        }else {
            System.out.println("没有这个类型");
        }

可以直接简写成

 if(animal instanceof Dog d){
 			d.eat();
        }else if(animal instanceof Cat c){
            c.eat();
        }else {
            System.out.println("没有这个类型,无法转换");
        }

static静态

在静态方法中,不能直接调用非静态方法 而在非静态方法中是可以直接调用静态方法的
举个例子,我们在静态的Sing()方法里调用非静态的sleep()方法

public class TestDemo1 {
   public static void Sing(){
       System.out.println("我爱唱歌!!!");
       sleep();
   }
   public void sleep(){
       System.out.println("我想睡觉!!!");
       Sing();
   }
}

系统会报错在这里插入图片描述

静态的方法是不依赖对象的,可以直接通过类名访问 非静态是依赖对象的,需要通过对象的引用访问

static可以修饰成员变量
static也可以修饰成员方法

代码块

普通代码块

格式是
{
}
主要作用是限定变量生命周期和作用域
出了作用域就销毁了

静态代码块

格式
static{
}
是随着类的加载而加载的,当类被加载到虚拟机执行时,静态代码块就被执行了,而且只加载一次

实例代码块

格式
{
}
位于类的成员变量之后

构造代码块

格式
public 类名(){
}
构造代码块必须定义在所有构造函数的前面

他们之间谁先优先执行呢?
我们可以用代码求证

public class TestDemo1 {
    static {
        System.out.println("静态代码块执行了!");
    }
    public  TestDemo1(){
        System.out.println("构造代码块执行了!");
    }
    {
        System.out.println("实例代码块执行了!");
    }
}
public class Test {
    public static void main(String[] args) {
       TestDemo1 testDemo1=new TestDemo1();
       TestDemo1 testDemo2=new TestDemo1();
    }
}

结果是:符合我们的结论在这里插入图片描述

总结

通过对类和对象,继承和多态的学习,相信你对java的语法有了一定了解,让我们一起继续学习吧!
在这里插入图片描述

评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值