java继承

1.为什么要有继承?

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

 举例:

工人类的行为有睡觉,吃饭,工作。学生类的行为有吃饭,睡觉,学习。这两个类具有相同的部分——睡觉,吃饭,所以我们可以将相同的部分抽取出来生成另一个类,让学生类与工人类继承它。

工人类:

class Worker{
    public void sleep(){
        System.out.println("睡觉");
    }
    public void eat(){
        System.out.println("吃饭");
    }
    public void work(){
        System.out.println("工作");
    }
}

 学生类:

class Student{
    public void sleep(){
        System.out.println("睡觉");
    }
    public void eat(){
        System.out.println("吃饭");
    }
    public void study(){
        System.out.println("学习");
    }

}

继承:

//新生成的类
class Person{
     public void sleep(){
        System.out.println("睡觉");
    }
    public void eat(){
        System.out.println("吃饭");
    }
}
class Worker extends Person{
   
    public void work(){
        System.out.println("工作");
    }
}
class Student extends Person{
    public void study(){
        System.out.println("学习");
    }
}

2.java的继承是单继承

单继承的意思是一个子类只能有一个父类,但是一个父类可以有若干个子类。不代表Java当中就没有多继承的时候!如果是类与类之间 必须是单继承;如果是接口与接口之间,可以是多继承。C++的继承属于多继承,不太符合实际的社会问题,所以Java更加符合现实编程。

3.父子类成员变量或静态变量的调用顺序

     1.父子类没有静态变量时

          如果只有子类有且非私有 那么就调用子类的

class Test2{
    public static void main(String[] args){
        Son son1=new Son();
        System.out.println(son1.num1);//结果是10
    }
}
class Father{
    int num2=20; 
}
class Son extends Father{
    int num1=10;   
}


          如果只有父类有且非私有 那么就调用父类的

class Test2{
    public static void main(String[] args){
        Son son1=new Son();
        System.out.println(son1.num2);//结果20
    }
}
class Father{
    int num2=20; 
}
class Son extends Father{
    int num1=10;   
}


          如果子父类都有且非私有 那么就调用子类的

class Test2{
    public static void main(String[] args){
        Son son1=new Son();
        System.out.println(son1.num1);//结果10
    }
}
class Father{
    int num1=20; 
}
class Son extends Father{
    int num1=10;   
}

      2.父子类有静态变量时

      查找顺序:子类对象成员->子类静态->父类成员->父类静态

class Test2{
    public static void main(String[] args){
        Son son1=new Son();
        //先在子类对象成员中找--找到了
        System.out.println(son1.num1);

        //先在子类对象成员中找--没找到>>再去子类的静态区找--找到了
        System.out.println(son1.num2);

        //先在子类对象成员中找--没找到>>再去子类的静态区找--没找到>>再去父类对象成员中找--找到了
        System.out.println(son1.num3);

        //先在子类对象成员中找--没找到>>再去子类的静态区找--没找到>>再去父类对象成员中找--没找到>>再去父类静态区中找--找到了
        System.out.println(son1.num4);
    }
}
class Father{
    int num3=20; 
    static int num4=40;
}
class Son extends Father{
    int num1=10;
    static int num2=20;   
}

3.子类成员函数在内部调用变量时 :局部变量->子类对象成员->子类静态->父类成员->父类静态

4.子父类中成员函数的特点:

        如果只有子类有且非私有 那么就调用子类的

class Test4{
    public static void main(String[] args){
        Son son3=new Son();
        son3.show();
    }
}
class Father{
    /*public void show(){
        System.out.println("这是父类");
    }*/
}
class Son extends Father{
    public void show(){
        System.out.println("这是子类");
    }
}
//结果:这是子类


        如果只有父类有且非私有 那么就调用父类的

class Test4{
    public static void main(String[] args){
        Son son3=new Son();
        son3.show();
    }
}
class Father{
    public void show(){
        System.out.println("这是父类");
    }
}
class Son extends Father{
    /*public void show(){
        System.out.println("这是子类");
    }*/
}
//结果:这是父类


        如果子父类都有且非私有 那么就调用子类的(函数重写)

class Test4{
    public static void main(String[] args){
        Son son3=new Son();
        son3.show();
    }
}
class Father{
    public void show(){
        System.out.println("这是父类");
    }
}
class Son extends Father{
    //这里存在着函数的重写
    @Override
    public void show(){
        System.out.println("这是子类");
    }
}
//结果:这是子类

函数重写的意义

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

函数重写是注意的细节

    1.函数重名 但是参数列表不同 不构成重写关系
    2.函数重名 参数列表相同 构成重写关系 返回值类型也必须是一样的
    3.子类重写父类函数时,权限>=父类权限
    4.当然 如果父类函数权限为private 子类压根就继承不到 何谈重写

5. 子父类中构造函数的特点:

子类的构造函数在调用运行的时候 先执行父类的构造函数,因为在子类的构造函数当中,有一句默认的super()隐藏了。
 对super的调用必须是构造器中的第一个。

class Test3{
    public static void main(String[] args){
        Son son2=new Son();
    }
}
class Father{
    Father(){
        System.out.println("父类构造函数!");
    }
}
class Son extends Father{
    //super(); 此处省略了
    Son(){
        System.out.println("子类构造函数!");
    }
}
//结果:
//父类构造函数!
//子类构造函数!

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

例如:

class Test3{
    public static void main(String[] args){
        Son son2=new Son();
    }
}
class Father{
    Father(int num){
        System.out.println("父类构造函数!");
    }
}
class Son extends Father{
    Son(){
        super();
        System.out.println("子类构造函数!");
    }
}
//报错:
/*
Test3.java:13: 错误: 无法将类 Father中的构造器 Father应用到给定类型;
        super();
        ^
  需要: int
  找到: 没有参数
  原因: 实际参数列表和形式参数列表长度不同
1 个错误
*/

解决方法:给super的参数列表添加对应的参数 或者 给Father类添加一个默认的构造函数。

6.super()与this()

1、this关键字值的是对当前对象的引用,super关键字值的是对当前对象的空间的引用

2、this(...)是当前类中 本类构造函数调用本类构造函数的方式。

      super(...)是本类构造函数调用父类构造函数的方式

3、两者都必须在第一行(既然两者都必须在第一行,那么两者是否冲突 )

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

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

class Son extends Father{
    int num1=20;
    static int num2=30;
    
    Son(){
        //本构造函数调用了Son(int num1,int num2),因此存在调用关系,所以第一句是this() 
        this(0,0);
        System.out.println("Son constructor1......");
    }
    Son(int num1){
        //本构造函数调用了Son(int num1,int num2),因此存在调用关系,所以第一句是this()
        this(0,0);
        System.out.println("Son constructor2......");
    }
    Son(int num1,int num2){
        //本构造函没有调用了其他构造函数,因此不存在调用关系,所以第一句是super()
        super();
        System.out.println("Son constructor3......");
    }
}

 

你可能感兴趣的:(继承)