继承和多态的深度剖析

发布于:2023-01-21 ⋅ 阅读:(391) ⋅ 点赞:(0)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

1.继承的使用

2.重写

3.多态


1.继承的使用:当不同类当中存在相同的成员变量和成员方法时我们往往把他们单独拿出来,形成一个类,我们把这个类叫做父类,也叫做基类或超类。其他类可以去继承这个类我们把这个类称之为子类、派生类。

2.继承使用关键字extends

class Animal
{
    public int age = 2;
    public String name = "wang";
    public void eat()
    {
        System.out.println(name + "正在吃饭");
    }
}
class Dog extends Animal
{
    public String silly;
    public void bark()
    {
        System.out.println(name + "正在叫");
    }
}
class Cat extends Animal
{
    public void cath()
    {
        System.out.println(name + "正在抓老鼠");
    }
}

在这里面Animal就是父类,Dog和Cat分别是子类然后分别继承了Animal这个父类。

 当创建子类对象的时候,直接把父类的成员拿过来。

当父类被final修饰时此时的话就不能被继承

 如图所示,此时继承Animal会被报错

4.父类的成员访问

1.当子类和父类的成员变量不同时,可以直接访问父类的变量属性:

class Animal
        {
            public int age=3;
            public String name="wang";
            //public String name;
            
        }
        class Dog extends Animal
        {
            public String silly;
            public Dog()
            {

                this.silly = "笨";
            }


        }
          public class text {
            public static void main(String[] args) {
                Dog dog = new Dog();
               
                System.out.println(dog.age);
                System.out.println(dog.name);
            }
      






      

 2.当在子类方法中访问的成员变量子类和父类相同时,优先访问子类的

class Animal
{
    public int age=3;
    public String name="wang";
    //public String name;
    
}
class Dog extends Animal
{
    public int age=4;
    public String silly;
    public void dayin()
      {
           System.out.println(dog.age);
}
    public Dog()
    {

        this.silly = "笨";
    }


}

public class text {
    public static void main(String[] args) {
        Dog dog=new Dog();
       dog.dayin();
        
    }
    
}

大家可以猜一下打印的age的是几?因为优先访问子类的,所以结果肯定是4.

 那如果非要在子类方法中访问父类的那么需要用到关键字super  改成super.age,

class Animal
{
    public int age=3;
    public String name="wang";
    //public String name;

}
class Dog extends Animal
{
    public int age=4;
    public String silly;
    public void dayin()
    {
        System.out.println(super.age);   //在这里用super关键字修饰age就可以访问到父类的age
    }
    public Dog()
    {

        this.silly = "笨";
    }


}

public class text {
    public static void main(String[] args) {
        Dog dog=new Dog();
       dog.dayin();

    }

}

 当父类和子类的成员变量相同时如果非要访问的父类的,我们要使用super这个关键字,但是注意super关键字只能在非静态的方法当中使用

3.当去访问成员变量时优先 访问自己的,没有再去父类找

四.子类构造方法:

子类构造对象时先调用父类的构造方法,然后执行子类的构造方法。

1.无参构造

class Animal
{
    public int age;
    //public String name="wang";
    public String name;
    public Animal()
    {


        System.out.println("给父类初始化");
    }

    public void eat()
    {
        System.out.println(name + "正在吃饭");
    }
    public void dance()
    {
        System.out.println("狗在跳舞");
    }
}
class Dog extends Animal
{
    public String silly;
    public Dog()
    {
        super();//默认调用父类的无参构造方法,且必须放在第一行,
        //this.silly = "聪明";
        System.out.println("给子类初始化");
    }

    //public String name;

    public void bark()
    {
        super.dance();
        System.out.println(name + "正在叫");
    }


}
public class text{
    public static void main(String[] args) {
        Dog dog = new Dog();
        System.out.println(dog.age);
        System.out.println(dog.name);


    }
}

 2.有参的构造方法:

public class text {
            public static void main(String[] args) {
                Dog dog = new Dog();
                //System.out.println(dog.silly);
                System.out.println(dog.age);
                System.out.println(dog.name);
            }
            package text;
            class Animal
            {
                public int age;
                //public String name="wang";
                public String name;
                public Animal(String name, int age)
                {
                    this.name = name;
                    this.age = age;
                    System.out.println("给父类初始化");
                }

                public void eat()
                {
                    System.out.println(name + "正在吃饭");
                }
                public void dance()
                {
                    System.out.println("狗在跳舞");
                }
            }
            class Dog extends Animal
            {
                public String silly;
                public Dog(String name, int age)
                {
                    super(name, age);
                    this.silly = "聪明";
                    System.out.println("给子类初始化");
                }

                //public String name;

                public void bark()
                {
                    super.dance();
                    System.out.println(name + "正在叫");
                }

            }
            
            public class text {
                public static void main(String[] args) {
                    Dog dog = new Dog("xiao", 3);
                    System.out.println(dog.silly);
                     System.out.println(dog.age);
                     System.out.println(dog.name);

                    

                }






            }





五.继承关系上的先后顺序:

先执行父类的静态代码块、子类的静态代码块、父类的实例代码块、构造方法,然后是子类的实例代码块、构造方法,且静态代码块只能被执行一次。

package text;
            class Animal
            {
                public int age;
                //public String name="wang";
                public String name;
                static
                {
                    int month;
                    System.out.println("静态代码块2");
                }
                {
                    System.out.println("实例代码块2");
                }
                public Animal(String name, int age)
                {
                    this.name = name;
                    this.age = age;
                    System.out.println("构造方法2");
                }
               

                public void eat()
                {
                    System.out.println(name + "正在吃饭");
                }
                public void dance()
                {
                    System.out.println("狗在跳舞");
                }
            }
            class Dog extends Animal
            {
                public String silly;
                static
                {
                    System.out.println("静态代码块1");
                }
                {
                    System.out.println("实例代码块1");
                }
                public Dog()
                {
                    super("hao", 7);
                    this.silly = "聪明";
                    System.out.println("构造方法1");
                }
                public void eat()
                {
                    System.out.println(name + "跳着吃饭");
                }



       
            public class text {
                public static void main(String[] args) {

                    Dog dog1 = new Dog();
                    Dog dog2 = new Dog();
                }

protected 关键字:

访问修饰限定符:同一包中的同一类;同一包中的不同类;不同包中的子类。

同一包中的同一类

public class Cat {
    protected int age=2;
    public void fun()
    {
        System.out.println(age);
    }
}
同一包中的不同类


public class text {
    public static void main(String[] args) {
        Cat b=new Cat();
        System.out.println(b.age);

    }
}
不同包中的子类


public class text2 extends Cat {
    public void fun()
    {
        System.out.println(super.age);
    }
}
class text3
{
    public static void main(String[] args) {
        text2 b=new text2();
        b.fun();
    }
}

final 关键字

1.final int a=10;

final 修饰变量表示常量,不能被修改。

2.修饰类表示这个类不能被继承,final修饰的类也叫做最终类。

3.修饰的方法不能被重写 ,final修饰的方法叫做密封方法。

二.多态

1.什么是多态

多态是指当引用的对象不同时,同一个方法会出现不同的效果

多态实现的条件:

1.必须在继承条件下

2.子类必须对父类的方法进行重写

3.通过父类的引用调用重写的方法

2.什么是重写

重写是指将父类的方法写到子类中,其参数列表(数据类型、个数、顺序)、函数名、返回值要相等,返回值如果不相等,那么应该是父类和子类的关系,实现内容不同

当父类被static、private修饰的方法、构造方法都不能被重写。

重写和重载的区别:

1.重载要求函数名必须相等,重写也要求函数名必须相等

2.重载要求参数列表不同,重写要求参数列表必须相同

3.重载对于返回值不做要求,重写一般要求返回值要相同,如果不相同的话,必须函数名要构成父子关系

4.重写要求发生在继承关系的类上,而重载则不做要求。

我们建Animal、Cat、Dog三个类让Cat、Dog继承Animal

public class Aniaml {
    String name;

    public Aniaml(String name) {
        this.name = name;
    }

    public void eat()
    {
        System.out.println(this.name+"正在吃饭");
    }
}
public class Cat extends Animal{
    String colour;

    public Cat(String name, String colour) {
        super(name);
        this.colour = colour;
    }

    public void eat()
    {
        System.out.println(this.name+"正在吃猫粮");
    }
}
public class Dog extends Animal{
    String silly;

    public Dog(String name, String silly) {
        super(name);
        this.silly = silly;
    }
    public void eat()
    {
        System.out.println(this.name+"正在吃狗粮");
    }
}

 

 

3.向上转型:是指将子类对象赋给父类,由父类对象引用子类,这时候父类引用只能访问父类的属性和方法,以及子类中重写父类的方法。

1.直接赋值:

public static void main1(String[] args) {
        Animal animal=new Cat("小众","绿色");
        animal.eat();
    }

 

  

这时候我们发现通过父类引用我们调用的不是父类的eat()方法,而是Cat类中重写的eat()方法,我们来看一下底层的汇编。

 

我们发现编译的时候还是Animal的eat()方法,但是在实际运行的时候就变成了子类的,我们称这个过程为动态绑定。

那可能有人会问那什么是静态绑定呢?

public static void sweep(String name,int age)
    {
        System.out.println("两个参数");
    }
    public static void sweep(String name)
    {
        System.out.println("一个参数");
    }
    public static void sweep()
    {
        System.out.println("无参数");
    }
    public static void main(String[] args) {
        sweep();
        sweep("小海");
        sweep("小中",8);
    }

像这段代码我们给sweep()传不同个数的参数,它会调用参数相匹配的sweep()方法,我们称这个过程为静态绑定。

 

 

 

2.方法传叁

public static void fun(Animal animal)
    {
        animal.eat();
    }
    public static void main(String[] args) {
        fun(new Cat("小众","红色"));
        fun(new Dog("小凯","傻狗"));

    }

 

我们可以看到此时Animal这个引用,调用同一个方法,但因为引用的对象不一样,导致调用这个方法所表现出来的行为不一样,就叫做多态。 

3.返回值

  public static Animal funtion()
    {
        return new Dog("小孙","傻");
    }
    public static void main(String[] args) {
        Animal animal=funtion();
        animal.eat();
    }

 

 

4.向下转型是指当实行向上转型性,通过父类没法引用子类的特有的方法,此时我们需要再将父类强转成子类对象,这个过程就是向下转型,我们一般不用,因为向下转型不安全。

 public static void main1(String[] args) {
        Animal animal=new Cat("小众","绿色");
        
    }

像这样如果我们想访问Cat类中的colour,通过父类引用我们是办不到的,这时候我们需要将父类强转成子类对象,通过子类对象去访问。

public static void main4(String[] args) {
        Animal animal=new Cat("小众","绿色");
        Cat cat=(Cat)animal;
        System.out.println(cat.colour);

    }

像下转型往往是不安全的,

 public static void main6(String[] args) {
        Animal animal=new Cat("小众","绿色");
        Dog dog=(Dog)animal;
        System.out.println(dog.silly);
    }

当父类引用指向Cat类时,这时如果我们再如果将父类强转成Dog,这时候运行时会报错。

 

这时候会报错Cat类不能强转成Dog类。

public static void main(String[] args) {
        Animal animal=new Cat("小众","绿色");
        //判断父类是否引用了Dog类
        if(animal instanceof Dog)
        {
            Dog dog=(Dog)animal;
            System.out.println(dog.silly);

        }
    }

 这时候我们可以用instanceof 语句判断一下父类引用的是不是Dog,如果不是就不会执行if语句里面的代码,这样也就安全一些。