Java基础——继承,我继承了什么

类的继承格式

class 父类 {
}
class 子类 extends 父类 {
}

通过extends关键字来实现

一、为什么需要继承

有一些类有共同的地方,容易出现代码冗余,所以我们需要抽取一下,封装继承多态嘛。

子类通过复写方法等方式可以对父类做一些拓展,比如:
笔都有产地和颜色,笔就是父类,钢笔继承自笔,钢笔的产地和颜色是什么,蜡笔呢,毛笔也有,但是毛笔没有笔帽,特殊一点,这就可以做拓展了,为什么没有笔帽,要注意什么。

二、继承到底继承了什么?有什么特点?

一个类里面有4种东西

  • 属性(包括类属性和实例属性)、
  • 方法(包括类方法和实例方法)、
  • 构造器/构造方法
  • 初始化块(包括类的初始化块和实例的初始化块)。

子类继承父类的时候,到底继承了什么?

  • 1、子类继承父类所有的属性(除了private)
  • 2、子类继承父类(除private)所有的方法,(子类方法如果不调用 super.所复写方法名称 ,那么对应父类方法将不会执行)
    • final方法不可以被继承
    • static方法不可以被继承,随着类的加载而加载,继承毛线。但是如果权限允许子类还是可以用。
  • 3、子类可以通过super,表示父类的引用,调用父类的属性或者方法。
    (构造函数和代码块是无法被继承)

对于private这点非常好理解,因为private的访问权限是本类中嘛,就算通过super也不能访问private的private属性。但是可以通过对应的get方法获取,get是public嘛。

如果子类非要访问父类的私有域,那么就反射吧

继承有什么特点:

  • Java只可以单继承,不能多继承

  • 继承的好处是是可以提高效率,抽取封装,缺点是提高了代码耦合。

  • Object是所有类的直接或者间接父类,Object是万类之祖。

  • 继承中的this和super

    • super关键字
      我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。

    • this关键字
      指向自己的引用。

  • 继承与final

    • final 类
      final class 类名 {//类体}

      不能继承的,即最终类
      被声明为 final 类的方法自动地声明为 final,但是实例变量并不是 final

    • final方法
      修饰符(public/private/default/protected) final 返回值类型 方法名(){//方法体}

      该方法不能被子类重写

  • final实例变量

    final修饰的变量称为常量,这些变量只能赋值一次,final 的变量不能被修改
    final修饰的引用类型变量,表示该变量的引用不能变,而不是该变量的值不能变;

  • 如果子类方法签名和父类签名完全一致,那就必须写上@Override的注解,也就是必须复写,不然的话,报错。

  • 调用被覆盖的父类方法:使用super.方法名(实参);

三、子类的初始化

类的初始化分为 类初始化 和 对象初始化。

三、1.类初始化

先执行父类的 类成员(static成员) 和 类代码块(static代码块),后执行子类的类成员(static成员) 和 类代码块(static代码块)。

static成员和static代码块仅会在类加载的时候加载一次。

三、2.对象初始化

1、先初始化父类的属性和代码块,后初始化子类的属性和代码块。
2、接着初始化父类的构造函数,然后是子类

关于子类能从父类继承到什么和继承中的类初始化,我们看一下下面的代码就清楚了:

AClass

public class AClass {
    int normalVar = 10;
    // 父类私有变量,子类无法继承,但可以get到
    private int priVar = 20;
    {
        System.out.println("AClass 普通代码块");
    }
    
    static{
        System.out.println("AClass static代码块");
    }
    
    public AClass(){
        System.out.println("AClass 无参构造方法");
    }
    
    public AClass(String str){
        System.out.println("AClass 带参构造方法!");
        
    }
    public void aMethodOne(){
        normalVar = 55;
        System.out.println("aMethodOne");
    }
    
    public void aMethodTwo(){
        normalVar = 66;
        System.out.println("aMethodTwo");
    }
    
    public int getPriVar() {
        return priVar;
    }
    
    public void setNormalVar(int normalVar) {
        this.normalVar = normalVar;
    }
}

.
.
BClass

public class BClass extends AClass{
    {
        System.out.println("BClass 普通代码块");
    }
    
    static{
        System.out.println("BClass static代码块");
    }
    

    public BClass(){
        System.out.println("BClass 无参构造方法");
    }
    
    public BClass(String str){
        System.out.println("BClass 带参构造方法!");
    }
    
    @Override
    public void aMethodOne() {
        super.aMethodOne();
        System.out.println("子类Override的aMethodOne方法 并且调用super.aMethodOne();");
    }

    @Override
    public void aMethodTwo() {
        //super.aMethodTwo();
        System.out.println("子类Override的aMethodTwo方法 不调用super.aMethodTwo();");
    }
    
    public void getFatherVar(){
        System.out.println("调用父类的非私有变量:"+normalVar);
        //int a = priVar; // 父类的私有变量子类无法继承,本句会报错
    }
}

.
.
TrtExt

public class TrtExt{
    public static void main(String[] args) {
        BClass bClass1 = new BClass();
        
        System.out.println("=========");
        BClass bClassZs = new BClass("张三"); 
        bClassZs.getFatherVar();
        bClassZs.setNormalVar(88); // 子类bClass2对象改变父类的变量,不会影响其他子类
        
        System.out.println("====================");
        BClass bClassLs = new BClass("李四"); 
        bClassLs.getFatherVar();// 
        
        System.out.println("====================");
        BClass bClassWw = new BClass("王五"); 
        bClassWw.getFatherVar();// 父类的原始值
        bClassWw.aMethodOne(); // BClass的aMethodOne方法有super.aMethodOne();所以会调父类的aMethodOne()
        bClassWw.getFatherVar();
        
        System.out.println("====================");
        BClass bClassAl = new BClass("阿六"); 
        bClassAl.getFatherVar();//  父类的原始值
        bClassAl.aMethodTwo();// BClass的aMethodTwo方法 没有super.aMethodOne();所以不调父类aMethodTwo
        bClassAl.getFatherVar();
    }
}

.
.
输出:

AClass static代码块
BClass static代码块
AClass 普通代码块
AClass 无参构造方法
BClass 普通代码块
BClass 无参构造方法
=========
AClass 普通代码块
AClass 无参构造方法
BClass 普通代码块
BClass 带参构造方法!
调用父类的非私有变量:10
====================
AClass 普通代码块
AClass 无参构造方法
BClass 普通代码块
BClass 带参构造方法!
调用父类的非私有变量:10
====================
AClass 普通代码块
AClass 无参构造方法
BClass 普通代码块
BClass 带参构造方法!
调用父类的非私有变量:10
aMethodOne
子类Override的aMethodOne方法 并且调用super.aMethodOne();
调用父类的非私有变量:55
====================
AClass 普通代码块
AClass 无参构造方法
BClass 普通代码块
BClass 带参构造方法!
调用父类的非私有变量:10
子类Override的aMethodTwo方法 不调用super.aMethodTwo();
调用父类的非私有变量:10

通过这个例子,我们可以清楚地看到

  • 1、静态代码块只会随着类的加载加载一次,优先于对象

  • 2、子类只可以继承父类的非private的变量方法,无法继承代码块构造方法

  • 3、当子类被实例化时,会先调用父类的无参构造方法。

  • 子类从父类继承的变量和方法是独立的,不会受到其他子类的影响。
    (bClass2改变父类的变量不会影响bClass3继承到的变量)

  • 4、子类复写父类的方法,如果不调用 super.所复写方法名称 那么对应父类方法将不会执行,也就是说,这个方法就相当一个普通的方法,没有从父类继承到什么。
    (绝大多数情况下是需要调用 super.所复写方法名称 的,但是有时候我们个别子类不想要父类方法的初始化逻辑,我们可以灵活选择是否保留 )

四、overload和override

方法重载(overload)
1.必须是同一个类
2方法名一样
3参数类型不一样或参数数量不一样

方法的重写/复写(override)

子类对父类方法的复写

两同两小一大原则:

两同:
方法名相同,参数类型相同

两小:
子类返回类型小于等于父类方法返回类型,若为基本类型或者void则必须相同
子类抛出异常小于等于父类方法抛出异常,

一大:
子类访问权限大于等于父类方法访问权限。

实例一下:

AClass

public class AClass {
    public int number = 10;
    protected void changeNumber(int i){
        setNumber(100);
        System.out.println("父类 changeNumber:  "+number);
        
    }
    
    public int setNumber(int i) {
        number = i;
        System.out.println("父类 number:  "+number);
        return number;
    }
}

.
.
BClass

public class BClass extends AClass{

    // 这个复写方法的访问权限比父类大,也就是两者访问权限不一致,但是也是对那个方法的复写
    @Override
    public void changeNumber(int i) {
        super.changeNumber(i);
        setNumber(i);
    }
}

.
.
TrtExt

public class TrtExt{
    public static void main(String[] args) {
        BClass bClass2 = new BClass(); 
        bClass2.changeNumber(70);
    }
}

输出:


父类 number:  100
父类 changeNumber:  100
父类 number:  70

我们看到,其实并不是复写的方法就需要和父类方法完全一致的。

你可能感兴趣的:(Java基础——继承,我继承了什么)