继承,重写与多态

一,继承

1.继承的由来:当我们在定义若干个类的时候,发现某一些类中具有相同的属性和行为,那么,我们就可以将这些相同的部分进行抽取,独立生成另外一个类,那么这个生成出来的类我们称之为是父类,其他的被抽取内容的类称之为子类

2.我们将被继承的类称为父类;继承的类称为子类     使用extends关键字实现继承关系

3.java中的继承是一种单继承关系         一个子类只能有一个父类,一个父类可以有多个子类

在C++中,继承是多继承的,不太符合实际的社会问题,所以Java更加符合现实编程;

当然Java当中也有多继承的时候,-----如果是类与类之间 必须是单继承;如果是接口与接口之间,可以是多继承

既然有了继承,那么在Java当中就有了继承体系:A----->B------>C------>D   :  A是B的子类,B是C的子类,C是D的子类

在Java继承体系当中,所有类的最终父类都是Object,Object不存在父类;如果我们在定义一个类的时候,没有显著声明父类的时候 那么该类的父类默认是Object

4.子类可以使用父类的属性和方法,但父类不能访问子类独有的属性和方法

5.创建子类对象时,默认先执行父类的构造方法,再执行子类的构造方法

6.子类如果想要调用父类的构造方法时,使用super关键字调用       super 与this相对       

super父类的引用---超类的引用    用法和this关键字类似

局部变量和成员变量如果重名了 this区分-----  this.成员变量=局部变量(将局部变量的值赋给成员变量)

子类的局部变量/成员变量和父类变量重名了 super区别  -----一旦成员变量前面加上super,则代表调用的父类对应的变量

class Extends{
    public static void main(String[] args){
        Zi zi=new Zi();
        System.out.println(zi.num1);
    }
}
class Fu{
    int num1=20;
    static int num2=40;
    static int num3=50;
}
class Zi extends Fu{
    int num1=30;
    static int num2=30;
    void show(){
        System.out.println(num1+","+num2+","+num3);//30,30,50
        //局部变量/成员变量和父类变量重名了 super区别 
        System.out.println(super.num1+","+super.num2+","+super.num3);//20,40,50
    }
}

7.如果在父类中加入静态代码块 在子类中也加入静态代码块 那么创建子类对象时,它的执行顺序为:父类的静态代码块--子类的静态代码块--父类的构造函数--子类的构造函数

子父类中成员变量/静态变量的特点(相当于就近原则):
        如果只有子类有且非私有 那么就调用子类的
        如果只有父类有且非私有 那么就调用父类的
        如果子父类都有且非私有 那么就调用子类的
        (成员变量之间 是不存在重写关系的!!!)
        子类.属性 顺序:子类对象成员->子类静态->父类成员->父类静态
        子类成员函数在内部调用变量时 局部变量->子类对象成员->子类静态->父类成员->父类静态


public class Animal{
    public String name;
    public int legnum;
    static{
        System.out.println("this is static Animal");
    }
    public Animal(String name,int legnum){
        this.name=name;
        this.legnum=legnum;
        System.out.println("this is animal");
    }
    public void happy(){
        System.out.println("叫");//方法体
    }
    public void setName(String name){
        this.name=name;
    }
    public String getName(){
        return name;
    }
    public void setLegnum(int legnum){
        this.legnum=legnum;
    }
    public int getLegnum(){
        return legnum;
    }
}
public class Dog extends Animal{
    public Dog(String name,int legnum){
        super(name,legnum);//原因是先要调用父类的构造函数
        System.out.println("this is dog");
    }
    static{
        System.out.println("this is static dog");
    }
    public void f(){//dog里面的方法
        System.out.println(name);//访问name这个属性
        System.out.println(legnum);
    }
    public void happy(){
        System.out.println("叫");
    }
}
public class Cat extends Animal{
    public Cat(String name,int legnum){
        super(name,legnum);
    }
    public void happy(){
        System.out.println("叫");
    }
}
public class Testa{
    public static void main(String[] args){
    Animal a=new Animal("哈哈",4);
    Dog d=new Dog("花花---",4);//创建子类的时候先要调用父类的构造方法
    System.out.println(d.getName());
    
    }
    
}

8.子父类中构造函数的特点:现象:子类的构造函数在调用运行的时候 先执行父类的构造函数

在子类的构造函数当中,有一句默认的super(...)隐藏了,而且这句代码必须是在第一行------ 对super的调用必须是构造器中的第一个

既然子类继承自父类 那么必然会继承到父类当中的一些数据 ,所以,在子类构造函数之中,必须先让父类把这些数据进行一些初始化才能继承给子类

注意:父类的构造函数被调用,但不代表父类就被创建对象了!所以this是当前对象的引用,而super不是父类对象的引用,而是父类空间的引用

class Extends{
    public static void main(String[] args){
        Zi zi=new Zi();
        System.out.println(zi.num1);
    }
}
class Fu{
    int num1=20;
    static int num2=40;
    static int num3=50;
    Fu(){
        System.out.println("这是父类的构造方法");
    }
}
class Zi extends Fu{
    int num1=30;
    static int num2=30;
    Zi(){
        //隐藏了  super();
        System.out.println("这是子类的构造方法");
    }
    void show(){
        System.out.println(num1+","+num2+","+num3);
        //局部变量/成员变量和父类变量重名了 super区别 
        System.out.println(super.num1+","+super.num2+","+super.num3);
    }
}

 并且注意super(...) 如果父类没有默认无参构造函数 那么子类构造函数中super()失效了,所以在调用父类构造函数时,一定要注意父类构造函数的参数情况!适时修改super(...)

 this(...)是当前类中 本类构造函数调用本类构造函数的方式, super(...)是本类构造函数调用父类构造函数的方式

如果本类构造函数当中不存在调用关系 那么每一个本类构造函数第一句都是super(...)

如果本类构造函数当中存在调用关系,那么最后被调用的那个构造函数第一句绝对是super(...)

this(...)的调用是单向的,那么最后被调用的第一句绝对就是super(...)

class Extends{
    public static void main(String[] args){
        Zi zi=new Zi();//创建Zi类,调用子类的无参构造函数
    }
}
class Fu{
    int num1=20;
    static int num2=40;
    static int num3=50;
    Fu(){
        System.out.println("这是父类的构造方法");
    }
}
class Zi extends Fu{
    int num1=30;
    static int num2=30;
    Zi(){
        this(0,0);
        System.out.println("这是子类的构造方法1");
    }
    Zi(int num1){
        this(0,0);
        System.out.println("这是子类的构造方法");
    }
    Zi(int num1,int num2){
        super();
        this.num1=num1;
        this.num2=num2;
        System.out.println("这是子类的构造方法2");
    }
    void show(){
        System.out.println(num1+","+num2+","+num3);
        //局部变量/成员变量和父类变量重名了 super区别 
        System.out.println(super.num1+","+super.num2+","+super.num3);
    }
}

/*打印结果为:
这是父类的构造方法
这是子类的构造方法2
这是子类的构造方法1
*/

 

子父类中成员函数的特点:
        如果只有子类有且非私有 那么就调用子类的
        如果只有父类有且非私有 那么就调用父类的
        如果子父类都有且非私有 那么就调用子类的(函数重写)

二,重写

    1. 满足条件:

  1. )一定发生在两个类中这两个类一定是继承关系
  2. )访问修饰符相同 返回类型相同 方法名字相同 方法体不同      子类的访问修饰符不能比父类更严格     父类更抽象,子类更具体
  3. )重写是多态的表现特征之一                                                                                                                                                 具体实例如下    happy()方法:

public class Animal{
    
    public Animal(){
     
    }
    /**
    描述动物开心
    子类更具体,父类更抽象
     */
     
     //方法
    public void happy(){
        System.out.println("叫");//方法体
    }
    
}
public class Dog extends Animal{
    public Dog(){
        super();//原因是先要调用父类的构造函数
    }
    
    public void f(){//dog里面的方法
        
    }
    
     public void happy(){
         System.out.println("汪汪!!!!");//方法体--方法体一定要在方法内部
     }
}
public class Testa{
    public static void main(String[] args){
    Dog d=new Dog();//创建子类的时候先要调用父类的构造方法
    d.happy();
    
    }
    
}

2.重写的意义:在于子类继承了父类的函数声明(功能),但是子类可以将该函数的具体实现进行优化或更改

3.(1.)保留父类的功能声明 子类可以进一步优化
   (2.)保留父类的功能声明 子类可以重新定义

4.重写当中应该注意到的一些细节:
    1.)函数重名 但是参数列表不同 不构成重写关系
    2.)函数重名 参数列表相同 构成重写关系 返回值类型也必须是一样的
    3.)子类重写父类函数时,权限>=父类权限
    4.)当然 如果父类函数权限为private 子类压根就继承不到   就不可能重写父类的方法

三,多态

1.多态是面向对象的特征之一   ----- 多态顾名思义:就是指一个对象可以有多种状态(他在继承体系中的位置变化)---位置的变化只能是向上变 但不能低于自身   eg:A-->B-->C-->--D:对B而言可以当C看,也可以当D看

2.多态的好处:对代码的功能进行了可扩展性;换句话说就是:子类对象可以当做父类对象去使用 但是有限制 ,只能调用父类函数或重写的函数,不能使用子类特有的方法

3.父类引用指向子类对象是多态最主要的表现之一

  eg:


    Animal a=new Dog("dog",4);
    Animal acat=new Cat("cat",4);
   

4.多态当中 成员变量的特点:只能访问父类中的成员变量
5.多态当中 成员函数的特点:
        如果子类没有重写 且父类中有 调用父类的
        如果子类有重写 调用子类重写的
        如果不存在重写 父类没有 那就报错了!

四,数据类型转换(向上转型和向下转型)

向上转型对应着:自动转换

public class Testa{
    public static void main(String[] args){
    Animal a=new Animal("哈哈",4);
    Dog d=new Dog("花花---",4);
    a=d;
    System.out.println(a.getName());//输出为花花----  
    }
    
}

向下转型对应着:强制转换

public class Testa{
    public static void main(String[] args){
//父类引用指向子类对象
    Animal a=new Dog("dog",4);
    Dog d=new Dog("花花---",4);//创建子类的时候先要调用父类的构造方法
    d=(Dog)a;
    System.out.println(d.getName());//输出为   dog 
    }
    
}

满足条件:两者之间要存在继承或者是实现关系(接口)

五,抽象类(在类名前加abstract)

1.抽象类:顾名思义就是模糊不清的类 不具体的类

2.当我们在抽取一个父类的时候,发现子类当中的一些共同方法在父类中无法进行具体的实现,并且这些方法只能在子类中具体实现时,父类当中的这些函数就只保留函数声明即可,不必写函数体 -----那么此时这个函数就是 抽象函数! 有抽象函数的类 就是抽象类!

3.特点:
    1.)抽象类不能创建对象------ 对象本身是一个具体的东西 而抽象类中含有不具体的内容
    2.)抽象类必须作为父类存在----- 抽象类就等着被继承呢!
    3.)抽象类和一般类的区别!抽象类就是一般类的特殊情况,唯一的区别只在于抽象类中有抽象函数!
    4.)抽象类中不一定有抽象函数, AWT界面开发会有
    5.)abstract这个关键字不能和那些关键字共存?
        private 一旦加了private子类就不会访问到这个方法,更不要说重写-----而抽象函数存在就是等着子类重写该方法
        static  静态是优先于对象存在的,在加载静态数据的时候 肯定是具体的数据
     

class Test{
    public static void main(String[] args){   
        Dog d=new Dog();
        Cat c=new Cat();
        Pig p=new Pig();
        feed(d);
        feed(c);
        feed(p);
    }
    public static void feed(Animal a){
        a.eat();
        //判断对象的本质类型 instanceOf
        if(a instanceof Pig){
            Pig pp=(Pig)a;
            pp.gongBaiCai();
        }
    }
    
}
abstract class Animal{
    abstract void eat();
    abstract void jiao();
}
class Pig extends Animal{
    void eat(){
        System.out.println("猪啥都吃......");
    }
    void jiao(){
        System.out.println("猪哼哼哼......");
    }
    void gongBaiCai(){
        System.out.println("猪拱白菜......");
    }
}
class Dog extends Animal{
    void eat(){
        System.out.println("狗吃狗粮......");
    }
    void jiao(){
        System.out.println("狗汪汪汪......");
    }
    void lookDoor(){
        System.out.println("狗看家~......");
    }
}
class Cat extends Animal{
    void eat(){
        System.out.println("猫吃鱼......");
    }
    void jiao(){
        System.out.println("猫喵喵喵......");
    }
    void catchMouse(){
        System.out.println("猫捉老鼠~......");
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值