继承

继承

继承在本职上是特殊——一般的关系,即常说的is-a关系。子类继承父类,表明子类是一种特殊的父类,并且具有父类所不具有的 一些属性或方法。

JAVA支持多继承吗?

不支持,java中提供类与类之间提供单继承 。

为什么不支持多继承?

提供多继承会可能出现错误,如:一个类继承了两个父类,而两个父类里面都有show()方法。

为什么接口支持多继承?

接口的方法并没有具体实现,实现需要子类重写接口的方法,所有不存在如上调用的不确定性 。

注意

  • 类优先于接口。 如果一个子类继承的父类和接口有相同的方法实现。 那么子类继承父类的方法
  • 子类中的方法优先于父类型中的方法。
  • 如果以上条件都不满足, 则必须显示覆盖/实现其方法,或者声明成abstract。

继承的好处

  1. 提高代码复用性
  2. 提高程序的扩展性(多态里向上转型的前提)

继承的缺陷

  1. 父类变,子类就必须变。
  2. 继承破坏了封装,对于父类而言,它的实现细节对与子类来说都是透明的。
  3. 继承是一种强耦合关系。

Java 继承语法格式

在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:

class 父类 {
}

class 子类 extends 父类 {
}

权限修饰

  1. 被private修饰的,是不可以被继承的,因为private修饰的只能在本类中可见,子类是不可见的;
  2. 父类被protected或public修饰的,子类是可以继承的;
  3. 被默认修饰符修饰的只能在同包下的子类是可以继承的;

构造器

构造器能被继承吗?

​ 我们知道子类可以继承父类的属性和方法,除了那些private的外还有一样是子类继承不了的—构造器。对于构造器而言,它只能够被调用,而不能被继承。 调用父类的构造方法我们使用super()即可。

为什么需要访问父类的构造器?

​ 对于子类而已,其构造器的正确初始化是非常重要的,而且当且仅当只有一个方法可以保证这点:在构造器中调用父类构造器来完成初始化,而父类构造器具有执行父类初始化所需要的所有知识和能力。

怎么调用父类的构造器?

​ 编译器会默认给子类调用父类的构造器。

​ 但是,这个默认调用父类的构造器是有前提的:父类有默认构造器(无参构造 )。如果父类没有默认构造器,我们就要必须显示的使用super()来调用父类构造器,而且必须是在子类构造器中做的第一件事(第一行代码)。 否则编译器会报错:无法找到符合父类形式的构造器。

static关键字

JAVA静态方法是否可以被继承?

结论:java中静态属性和静态方法可以被继承,但是没有被重写(overwrite)而是被隐藏.

如果在子类重写静态方法加上@Override会直接编译报错,不加@Override重写,用谁的对象/类调用就执行方法,静态方法时属于类的;静态属性同上

原因:

1). 静态方法和属性是属于类的,调用的时候直接通过类名.方法名完成对,不需要继承机制及可以调用。如果子类里面定义了静态方法和属性,那么这时候父类的静态方法或属性称之为"隐藏"。如果你想要调用父类的静态方法和属性,直接通过父类名.方法或变量名完成,至于是否继承一说,子类是有继承静态方法和属性,但是跟实例方法和属性不太一样,存在"隐藏"的这种情况。

2). 多态之所以能够实现依赖于继承、接口和重写、重载(继承和重写最为关键)。有了继承和重写就可以实现父类的引用指向不同子类的对象。重写的功能是:"重写"后子类的优先级要高于父类的优先级,但是“隐藏”是没有这个优先级之分的。

3). 静态属性、静态方法和非静态的属性都可以被继承和隐藏而不能被重写,因此不能实现多态,不能实现父类的引用可以指向不同子类的对象。非静态方法可以被继承和重写,因此可以实现多态。

/**
 * 父类
 */
public class A {

    public static String staticStr = "A静态属性";
    public String nonStaticStr = "A非静态属性";

    public static void staticMethod() {
        System.out.println("A静态方法");
    }

    public void nonStaticMethod() {
        System.out.println("A非静态方法");
    }

}

/**
 * 子类,重写父类的静态属性和静态方法
 */
public class B extends A {

    public static String staticStr = "B改写后的静态属性";
    public String nonStaticStr = "B改写后的非静态属性";

    public static void staticMethod() {
        System.out.println("B改写后的静态方法");
    }

}


/**
 * 子类,直接继承
 */
public class C extends A{

}
/**
 * 测试类
 */
public class Test {

    public static void main(String[] args) {
        C c = new C();
        System.out.println(c.nonStaticStr);
        System.out.println(c.staticStr);
        c.staticMethod();// 输出的结果都是父类中的非静态属性、静态属性和静态方法,推出静态属性和静态方法可以被继承
        System.out.println("-------------------------------");

        A c1 = new C();
        System.out.println(c1.nonStaticStr);
        System.out.println(c1.staticStr);
        c1.staticMethod();// 结果同上,输出的结果都是父类中的非静态属性、静态属性和静态方法,推出静态属性和静态方法可以被继承

        System.out.println("-------------------------------");
        B b = new B();
        System.out.println(b.nonStaticStr);
        System.out.println(b.staticStr);
        b.staticMethod();//(允许在子类中定义同名静态方法,但是没有多态,严格的讲,方法间没有多态就不能称为覆盖)

        System.out.println("-------------------------------");
        A b1 = new B();
        System.out.println(b1.nonStaticStr);
        System.out.println(b1.staticStr);
        b1.staticMethod();// 结果都是父类的静态方法,说明静态方法不可以被重写,不能实现多态
    }
/*    
     A非静态属性
    A静态属性
    A静态方法
    -------------------------------
    A非静态属性
    A静态属性
    A静态方法
    -------------------------------
    B改写后的非静态属性
    B改写后的静态属性
    B改写后的静态方法
    -------------------------------
    A非静态属性
    A静态属性
    A静态方法
*/
}

super 与 this 关键字

  • super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
  • this关键字:指向自己的引用
class Animal {
  void eat() {
    System.out.println("animal : eat");
  }
}

class Dog extends Animal {
  void eat() {
    System.out.println("dog : eat");
  }
  void eatTest() {
    this.eat();   // this 调用自己的方法
    super.eat();  // super 调用父类方法
  }
}

public class Test {
  public static void main(String[] args) {
    Animal a = new Animal();
    a.eat();
    Dog d = new Dog();
    d.eatTest();
  }
}

final关键字

  1. final 关键字修饰类可以把类定义为不能继承的,即最终类;
  2. final 关键字修饰修饰方法,该方法不能被子类重写;

方法的重写(覆盖)

  1. 两同

    即要重写的方法的方法名参数列表必须相同,可以在要重写的方法的上方添加@Override注解,来判断是否正确的进行了重写;

  2. 两小

    即子类的返回值类型抛出的异常类型必须要小于等于父类的类型。

  3. 一大

    重写的方法的权限修饰符必须要大于等于父类方法的权限
    ###代码块

  4. 普通代码块:

    在方法或语句中出现的{}就称为普通代码块。
    普通代码块和一般的语句执行顺序由他们在代码中出现的次序决定–“先出现先执行”

  5. 静态代码块:

    在java中使用static关键字声明的代码块。
    静态块用于初始化类,为类的属性初始化。每个静态代码块只会执行一次。
    由于JVM在加载类时会执行静态代码块,所以静态代码块先于主方法执行。
    如果类中包含多个静态代码块,那么将按照”先定义的代码先执行,后定义的代码后执行”。
    注意:
    1 静态代码块不能存在于任何方法体内。
    2 静态代码块不能直接访问静态实例变量和实例方法,需要通过类的实例对象来访问。

  6. 构造代码块:
    直接在类中定义且没有加static关键字的代码块称为{}构造代码块。
    构造代码块在创建对象时被调用,每次创建对象都会被调用,并且构造代码块的执行次序优先于类构造函数。这个构造代码块的执行顺序不会因为方法所在位置而影响,我特意将他放在构造函数之后。

####面试题

java中关于子类和父类的构造函数,静态代码块,普通代码块,静态成员变量和普通成员变量的初始化顺序

1.父类【静态成员】和【静态代码块】,按在代码中出现的顺序依次执行。
2.子类【静态成员】和【静态代码块】,按在代码中出现的顺序依次执行。

3.父类【构造代码块】和子类的构造代码块

3.父类的【普通成员变量被普通成员方法赋值】和【普通代码块】,按在代码中出现的顺序依次执行。
4.执行父类的构造方法。
5.子类的【普通成员变量被普通成员方法赋值】和【普通代码块】,按在代码中出现的顺序依次执行。

https://blog.csdn.net/lilamei170607/article/details/82590287


转载请注明: Hexo 继承

上一篇
基础增强 基础增强
目录1. Junit单元测试 2. 反射 3. 注解 Junit单元测试:* 测试分类: 1. 黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值。 2. 白盒测试:需要写代码的。关注程序具体的执行流程。 * J
2019-01-01
下一篇
多态 多态
多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。 多态是由方法重载,继承,方法重写,自动转型等技术的组合。 编译时多态:重载 ​运行时多态(编译类型和运行类型不一致): ​
2019-01-01