javaSE---类的继承和多态

目录

类的继承

1.类的继承的概念

1.Java中,类只支持单继承,也就是说一个类只能有一个直接父类

2.子类只能继承父类的共有成员

3.多个类可以继承同一个父类

4.Java可以满足多层继承

 5.java中被 final 标志的类,是最终类,不可以被继承

6.继承的执行顺序

2.重写父类方法

3.super关键字

1.使用super关键字调用父类的成员变量和成员方法

2.使用super关键字调用父类的构造方法

类的多态

1.对象的类型转换

向上转型

向下转型

instanceof关键字

2. 动态绑定

3.多态的概念



类的继承

1.类的继承的概念

Java中,类的继承是指在一个现有类的基础上去构建一个新的类,子类会自动拥有父类所有可继承的属性和方法

在程序中,如果想要声明一个类继承另外一个类,需要使用extends关键字,其基本语法如下

【修饰符】 class 子类名 extends 父类名{

}

class Dog{
    public String name;
    public int age;
public void eat(){
    System.out.println("dog can eat");
}
}
class Bird {
    public String name;
    public int age;

    public void eat() {
        System.out.println("bird can eat");
    }

    public void fly() {
        System.out.println("bird can fly");
    }
}

在这个代码中,我们发现两个类有公共部分,那么我们可以将这些公共部分抽出来

class Animal {
    public String name;
    public int age;
    public void eat() {
        System.out.println("dog can eat");
    }
}
class Dog extends Animal{
}
class Bird  extends Animal{
    public void fly() {
        System.out.println("bird can fly");
    }
}
    public class text {
        public static void main(String[] args) {
            Dog dog=new Dog();
            dog.name="汪汪";
            dog.age=10;
            System.out.println(dog.name);
            System.out.println(dog.age);
        }
}

Dog 和Bird称为子类或者派生类,Animal称为父类或者基类或者超类,Dog和Bird通过extends关键字继承了Animal类,子类会自动拥有父类所有公共的成员

2.注意事项

1.Java中,类只支持单继承,也就是说一个类只能有一个直接父类

 c这个类不能同时继承Dog类和Bird类

2.子类只能继承父类的共有成员

class Animal {
    public String name;
    public int age;
    public void eat() {
        System.out.println("dog can eat");
    }
    private void fun(){
        System.out.println("hi");
    }
}
class Dog extends Animal{
}

 父类Animal中,fun方法是私有方法,不能被子类继承

3.多个类可以继承同一个父类

class Dog extends Animal{
}
class Bird  extends Animal{
    public void fly() {
        System.out.println("bird can fly");
    }
}

4.Java可以满足多层继承

class Animal {
    public String name;
    public int age;
    public void eat() {
        System.out.println("dog can eat");
    }
   public  void fun(){
        System.out.println("hi");
    }
}
class Bird  extends Animal{
    public void fly() {
        System.out.println("bird can fly");
    }
}
class Dog extends Bird{
}
    public class text {
        public static void main(String[] args) {
           Dog dog=new Dog();
            dog.age=10;
            dog.name="汪汪";
         dog.fly();
            dog.fun();
        }
}

Bird类继承了Animal类,Dog类继承了Bird类,那么Dog类可以拥有Bird类和Animal类的所有公开成员 

 5.java中被 final 标志的类,是最终类,不可以被继承

6.继承的执行顺序

 一个类,先执行静态代码块,后执行实例化代码块,后执行构造方法

class A{
   static {
        System.out.println("父类的静态代码块");
    }
    {
        System.out.println("父类的实例化代码块");
    }
    public A(){
        System.out.println("父类的构造方法");
    }
}
class B extends A{
    static {
        System.out.println("子类的静态代码块");
    }
    {
        System.out.println("子类的实例化代码块");
    }
    public B(){
        System.out.println("子类的构造方法");
    }
}
public class text {
    public static void main(String[] args) {
        B b=new B();
    }

 

 在继承中,先加载父类静态代码块,后加载子类静态代码块,后加载父类的实例化代码块和构造方法,最后加载子类的实例化代码块和构造方法

静态首先加载(先父类后子类)

全部加载父类(先实例后构造)

全部加载子类(先实例后构造)

2.重写父类方法

子类可以继承父类的公开方法,但有时,我们需要在子类中对继承的方法进行修改,也就是对父类方法进行重写

子类中重写的方法需要和父类中被重写的方法有一样的方法名,参数列表和返回值类型

(方法的重载:返回值类型不影响,要求方法名相同,参数类型和个数不同)

class Animal {
    public void eat() {
        System.out.println("dog can eat");
    }
    public  void fun(){
        System.out.println("hi");
    }
}

class Dog extends Animal{
    public void eat() {//重写父类的eat方法
        System.out.println("汪汪爱吃骨头");
    }
}
    public class text {
        public static void main(String[] args) {
           Dog dog=new Dog();
           dog.eat();
            Animal animal=new Animal();
            animal.eat();
        }
}

  定义了Dog类和Animal类,Dog类继承了Animal类,并对父类的eat方法进行了重写,从运行结果可以看到,调用的是 Dog类的eat方法时,执行Dog类中的重写的eat方法。调用Animal类的eat方法时,执行Animal类中的eat方法。

  • 子类重写父类方法时,不能使用比父类方法更加严格的访问权限
  • 静态方法不能重写
  • private或者final修饰的方法不能重写

3.super关键字

由上面我们可以发现,在子类对象中没有办法直接访问父类成员,可以用super关键字来访问父类的成员变量,成员方法和构造方法

1.使用super关键字调用父类的成员变量和成员方法

super.成员变量

super.成员方法

class Animal {
    int age = 9;

    public void eat() {
        System.out.println("dog can eat");
    }
    public void fun() {
        System.out.println("hi");
    }
}
class Dog extends Animal{
    public void eat() {
        System.out.println("汪汪爱吃骨头");
        super.eat();//调用了父类的eat方法
    }
    public void print(){
        System.out.println(super.age);//调用了父类的成员变量
    }
}
    public class text {
        public static void main(String[] args) {
           Dog dog=new Dog();
           dog.eat();
          dog.print();
        }
}

2.使用super关键字调用父类的构造方法

使用super关键字调用父类的构造方法,具体格式如下

super(【参数1,参数2……】)

class Animal {
   public Animal(String name){
       System.out.println(name);
   }
    public Animal(int age){
        System.out.println(age);
    }
}
class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }
    public Dog(int age) {
        super(age);
    }
}
    public class text {
        public static void main(String[] args) {
          Dog dog=new  Dog(56);
           new  Dog("汪汪");
        }
}

定义了类Animal和类Dog,Dog类继承了父类Animal,其中Dog类和Animal类内部分别都有两个构造方法,内部的两个方法之间构成了重载。

在创建Dog类对象时一定会调用Dog类的构造方法, Dog dog=new  Dog(56);实例化对象时执行了Dog内部的构造方法,从而调用了super(age)方法,调用父类Animal中有参数age的构造方法

注意:借用super关键字来调用父类的构造方法的代码必须在子类构造方法的第一行,且只能使用一次

 java的每一个类中至少会有一个构造方法:如果说在一个类中没有定义构造方法,系统会自动地为这个类创建一个默认的构造方法,这个默认的构造方法没有参数,方法体中也没有任何代码。一旦为该类定义了构造方法,系统将不会提供默认的无参数构造方法

注意:子类的构造方法一定会调用父类的某一个构造方法 :子类可以提供super关键字指定调用某一个父类的构造方法,如果没有使用super关键字,实例化子类对象时,会默认调用父类无参的构造方法

class Base {

  Base() {

  	System.out.print("Base"); 

  }

}

public class Alpha extends Base {

  public static void main( String[] args ) {

    new Alpha();//调用子类构造方法,从而一定调用父类构造方法

    new Base();

  } 

}

这个题中,子类没有自己定义的构造方法,这时系统会默认存在一个构造方法,public Alpha{ }。实例化对象时,会调用子类的构造方法,然后子类的构造方法一定会调用父类的构造方法,没有super关键字指定时,默认调用父类无参数的构造方法。

  1. 如果说父类定义了构造方法,那么不会调用系统默认的构造方法(这个默认的构造方法没有参数,方法体中也没有任何代码)。
  2. 只要父类定义的构造方法有一个没有参数,没有使用super关键字指定调用哪一个构造方法时,会默认调用这个定义的没有参数构造方法
  3. 如果父类定义的构造方法有参数,且不存在没有参数的构造方法,这时候就必须使用super关键字来调用父类有参数的构造方法,否则会编译错误

类的多态

1.对象的类型转换

向上转型

父类引用 引用子类对象

  public static void main(String[] args) {
          Dog dog=new  Dog();
            Animal  animal=dog;//animal引用了子类对象
//等价于:
            Animal animal=new Dog();//父类引用 引用了子类对象
        }

 发生时机

  • 直接赋值
  public static void main(String[] args) {
        
            Animal animal1=new Dog();//父类引用 引用了子类对象
        }
  • 方法传参
class Dog extends Animal {
    public void eat(Animal animal){
        
    }
}
    public class text {
        public static void main(String[] args) {
            Dog dog=new  Dog();
            dog.eat(dog);
        }
  • 方法返回值
lass Dog extends Animal {
    public Animal eat(){
        Dog dog=new  Dog();
return  dog;
    }
}

 父类引用只能引用父类的成员,不能引用子类特有的方法

class Animal {
    public void animal(){
        System.out.println("吃");
    }
}
class Dog extends Animal {
    public void  dog(){
        System.out.println("汪汪吃骨头");
    }
}
    public class text {
        public static void main(String[] args) {
            Animal animal = new Dog();//父类引用 引用了子类对象
            animal.dog();//error,父类引用只能引用父类里面的成员
       
        }
   }

报错 在把子类对象当作父类使用时,不能用父类直接引用子类特有的方法

创建Dog对象时指向了Animal父类类型,这样创建的Dog类对象会自动向上转型为Animal类,通过dog这个引用调用Dog内部特有的dog方法,由于dog方法是Dog类特有的,使用Animal类对象无法调用这个方法

向下转型

为了解决以上的问题,要进行强制类型转化

public class text {
        public static void main(String[] args) {
            Animal animal = new Dog();//父类引用 引用了子类对象
           Dog dog=(Dog)animal;//向下转型
           dog.dog();//error
        }
}

 anmial对象本质应该是Dog类型,被向上转型为Animal类型, Dog dog=(Dog)animal;//向下转型,anmial对象强制转化为Dog类型,这样可以调用子类的特有方法。

向下转型时不能强制转化为其他类型

class Animal {
    public void animal(){
        System.out.println("吃");
    }
}
class Dog extends Animal {
    public void  dog(){
        System.out.println("汪汪吃骨头");
    }
}
class Bird extends Animal{
    int a=10;
}
    public class text {
        public static void main(String[] args) {
            Animal animal = new Dog();//父类引用 引用了子类对象
           Bird bird=(Bird)animal;//向下转型
        }
   
    }

 因为  Animal animal = new Dog();anmial对象本质是Dog类型,但是向上转型为Animal类型。Bird bird=(Bird)animal;anmial对象本质是Dog类型,不能向下转型为Bird类型,只能向下转型为Dog类型

instanceof关键字

为了避免上述异常的发生,Java提供了一个关键字instanceof来判断一个对象是否是一个类的对象或者子类对象

 public class text {
        public static void main(String[] args) {
            Animal animal = new Dog();//父类引用 引用了子类对象
           if(animal instanceof Bird){
               Bird bird=(Bird) animal;
               System.out.println("anmial 是 Bird类的对象或者子类对象");
           }
            System.out.println("anmial 不是 Bird类的对象或者子类对象");
        }
        public static void main3(String[] args) {
        }
    }

2. 动态绑定

class Animal {
    public void eat(){
        System.out.println("吃");
    }
}
class Dog extends Animal {
    public void eat(){
        System.out.println("汪汪吃骨头");
    }
}
    public class text {
        public static void main(String[] args) {
            Animal animal=new Dog();//父类引用 引用了子类对象
            animal.eat();
        }
}

 子类中对父类的方法进行重写,向上转型访问重写的方法,执行的是子类中重写的方法,这里发生了动态绑定

动态绑定:1.向上转型 2.通过向上转型调用重写方法

也就是父类调用重写方法---执行子类里的方法

把一个方法与其所在的类/对象关联起来叫做方法的绑定。

编译时多态(静态绑定):利用方法的重载实现,根据参数不同来确定执行哪一个方法

运行时多态(动态绑定):利用子类对父类的重写,在运行期间通过具体执行代码确定执行哪一个方法

父类里含有构造方法

class Animal {
    public Animal(){
        eat();//调用的eat方法是父类的还是子类的---子类
    }
    public void eat(){
        System.out.println("吃食物");
    }
}
class Dog extends Animal {
  
    public void eat(){//对父类的eat方法重写
        System.out.println("狗狗吃骨头");
    }
}
    public class text {
        public static void main(String[] args) {
           Dog dog= new Dog();//调用了父类的构造方法
            }
}

main方法中,创建Dog实例的时候,会调用子类的构造方法,子类的构造方法一定会调用父类的构造方法。

父类的构造方法里调用了eat方法,而eat方法在子类里面重写了,发生动态绑定,调用的是子类的eat方法(从父类调用重写方法---动态绑定)

尽量不要在构造方法里面调用方法,一旦这个方法被子类重写了,就会触发动态绑定,产生意料之外的结果

3.多态的概念

Java中,多态指不同类的对象在调用同一个方法时呈现的多种不同行为

class Draw {
    public void draw() {
        System.out.println("这是父类");
    }
}
class Flower extends Draw{
    @Override
    public void draw(){
        System.out.println("❀");
    }
}
class Square extends Draw{
    @Override
    public void draw(){
        System.out.println("■");
    }
}
class Triangle extends Draw{
    @Override
    public void draw(){
        System.out.println("🔺");
    }
}
public class text {
    public static void Draw(Draw Draw) {
        Draw.draw();
    }
    public static void main(String[] args) {
        Draw(new Flower());
        Draw(new Square());
        Draw(new Triangle());
    }
}

在子类内部都对父类的draw()方法进行了重写,调用  Draw()方法,将子类对象向上转型并调用重写方法,发生了动态绑定,导致同一个方法产生了不同的结果,这就是多态

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值