疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Java学习之继承中的执行顺序详解


 

   

  代码块(理解)

  (1)用{}括起来的代码。

  (2)分类:

  A:局部代码块

  用于限定变量的生命周期,及早释放,提高内存利用率。

  B:构造代码块

  把多个构造方法中相同的代码可以放到这里,每个构造方法执行前,首先执行构造代码块。

  C:静态代码块

  static{}对类的数据进行初始化,仅仅只执行一次。

  (3)静态代码块,构造代码块,构造方法的顺序问题?

  静态代码块 > 构造代码块 > 构造方法

  class Student {

  static {

  System.out.println("Student 静态代码块");

  }

  {

  System.out.println("Student 构造代码块");

  }

  public Student() {

  System.out.println("Student 构造方法");

  }

  }

  class StudentDemo {

  static {

  System.out.println("studentDemo静态代码块");

  }

  public static void main(String[] args) {

  System.out.println("我是main方法");

  Student s1 = new Student();

  Student s2 = new Student();

  }

  }

  运行结果如下:

  /*

  写程序的执行结果。

  studentDemo静态代码块

  我是main方法

  Student 静态代码块

  Student 构造代码块

  Student 构造方法

  Student 构造代码块

  Student 构造方法

  */

  继承(掌握)

  (1)把多个类中相同的成员给提取出来定义到一个独立的类中。然后让这多个类和该独立的类产生一个关系,

  这多个类就具备了这些内容。这个关系叫继承。

  (2)Java中如何表示继承呢?格式是什么呢?

  A:用关键字extends表示

  B:格式:

  class 子类名 extends 父类名 {}

  (3)继承的好处:

  A:提高了代码的复用性

  B:提高了代码的维护性

  C:让类与类产生了一个关系,是多态的前提

  (4)继承的弊端:

  A:让类的耦合性增强。这样某个类的改变,就会影响其他和该类相关的类。

  原则:低耦合,高内聚。

  耦合:类与类的关系

  内聚:自己完成某件事情的能力

  B:打破了封装性

  (5)Java中继承的特点

  A:Java中类只支持单继承

  B:Java中可以多层(重)继承(继承体系)

  (6)继承的注意事项:

  A:子类不能继承父类的私有成员

  B:子类不能继承父类的构造方法,但是可以通过super去访问

  C:不要为了部分功能而去继承

  (7)什么时候使用继承呢?

  A:继承体现的是:is a的关系。

  B:采用假设法

  (8)Java继承中的成员关系

  A:成员变量

  a:子类的成员变量名称和父类中的成员变量名称不一样,直接访问

  b:子类的成员变量名称和父类中的成员变量名称一样,这个怎么访问呢?

  子类的方法访问变量的查找顺序:就近原则

  在子类方法的局部范围找,有就使用。

  在子类的成员范围找,有就使用。

  在父类的成员范围找,有就使用。

  找不到,就报错。

  B:构造方法

  a:子类的构造方法默认会去访问父类的无参构造方法

  1:子类中所有的构造方法默认都会访问父类中空参数的构造方法

  2:为什么呢?

  因为子类会继承父类中的数据,可能还会使用父类的数据。

  所以,子类初始化之前,一定要先完成父类数据的初始化。

  注意:子类每一个构造方法的第一条语句默认都是:super();

  class Son extends Father {

  public Son() {

  //super();

  System.out.println("Son的无参构造方法");

  }

  public Son(String name) {

  //super();

  System.out.println("Son的带参构造方法");

  }

  }

  class ExtendsDemo6 {

  public static void main(String[] args) {

  //创建对象

  Son s = new Son();

  System.out.println("------------");

  Son s2 = new Son("林青霞");

  }

  }

  运行结果:

  Father的无参构造方法

  Son的无参构造方法

  ------------

  Father的无参构造方法

  Son的带参构造方法

  b:父类中如果没有无参构造方法,怎么办?

  子类通过super去明确调用带参构造(子类用super();调用父类构造方法只能在构造方法中的第一行调用)

  子类通过this调用本身的其他构造,但是一定会有一个去访问了父类的构造

  习惯:最好每次都让父类提供无参构造

  class Father {

  /*public Father() {

  System.out.println("Father的无参构造方法");

  }

  */

  public Father(String name) {

  System.out.println("Father的带参构造方法");

  }

  }

  class Son extends Father {

  public Son() {

  super("随便给");

  System.out.println("Son的无参构造方法");

  //super("随便给");

  }

  public Son(String name) {

  //super("随便给");

  this();

  System.out.println("Son的带参构造方法");

  }

  }

  class ExtendsDemo7 {

  public static void main(String[] args) {

  Son s = new Son();

  System.out.println("----------------");

  Son ss = new Son("林青霞");

  }

  }

  运行结果:

  Father的带参构造方法

  Son的无参构造方法

  ----------------

  Father的带参构造方法

  Son的无参构造方法

  Son的带参构造方法

  C:成员方法

  a:子类的成员方法和父类中的成员方法名称不一样,直接访问

  b:子类的成员方法和父类中的成员方法名称一样,这个怎么访问呢?

  通过子类对象访问一个方法的查找顺序:就近原则

  在子类中找,有就使用

  在父类中找,有就使用

  找不到,就报错

  (9)两个面试题:

  A:Override和Overload的区别?Overload是否可以改变返回值类型?可以

  B:this和super的区别和各自的作用?

  this代表本类对应的引用。

  super代表父类存储空间的标识(可以理解为父类引用,可以操作父类的成员)

  怎么用呢?

  A:调用成员变量

  this.成员变量 调用本类的成员变量

  super.成员变量 调用父类的成员变量

  B:调用构造方法

  this(..参数.) 调用本类的构造方法

  super(..参数.) 调用父类的构造方法

  C:调用成员方法

  this.成员方法 调用本类的成员方法

  super.成员方法 调用父类的成员方法

  (10)数据初始化的面试题

  A:一个类的初始化过程

  /*

  看程序写结果:

  A:成员变量 就近原则

  B:this和super的问题

  this访问本类的成员

  super访问父类的成员

  C:子类构造方法执行前默认先执行父类的无参构造方法

  D:一个类的初始化过程

  成员变量进行初始化

  默认初始化

  显示初始化

  构造方法初始化

  结果:

  fu

  zi

  30

  20

  10

  */

  class Fu{

  public int num = 10;

  public Fu(){

  System.out.println("fu");

  }

  }

  class Zi extends Fu{

  public int num = 20;

  public Zi(){

  System.out.println("zi");

  }

  public void show(){

  int num = 30;

  System.out.println(num); //30

  System.out.println(this.num); //20

  System.out.println(super.num); //10

  }

  }

  class ExtendsTest {

  public static void main(String[] args) {

  Zi z = new Zi();

  z.show();

  }

  }

  B:子父类的构造执行过程

  /*

  看程序写结果:

  A:一个类的静态代码块,构造代码块,构造方法的执行流程

  静态代码块 > 构造代码块 > 构造方法

  B:静态的内容是随着类的加载而加载

  静态代码块的内容会优先执行

  C:子类初始化之前先会进行父类的初始化

  结果是:

  静态代码块Fu

  静态代码块Zi

  构造代码块Fu

  构造方法Fu

  构造代码块Zi

  构造方法Zi

  */

  class Fu {

  static {

  System.out.println("静态代码块Fu");

  }

  {

  System.out.println("构造代码块Fu");

  }

  public Fu() {

  System.out.println("构造方法Fu");

  }

  }

  class Zi extends Fu {

  static {

  System.out.println("静态代码块Zi");

  }

  {

  System.out.println("构造代码块Zi");

  }

  public Zi() {

  System.out.println("构造方法Zi");

  }

  }

  class ExtendsTest2 {

  public static void main(String[] args) {

  Zi z = new Zi();

  }

  }

  C:分层初始化

  /*

  看程序写结果:

  A:成员变量的问题

  int x = 10; //成员变量是基本类型

  Student s = new Student(); //成员变量是引用类型

  B:一个类的初始化过程

  成员变量的初始化

  默认初始化(给默认的值)

  显示初始化(给我们给变量赋的值)

  构造方法初始化

  C:子父类的初始化(分层初始化)

  先进行父类初始化,然后进行子类初始化。

  结果:

  YXYZ

  问题:

  虽然子类中构造方法默认有一个super()

  初始化的时候,不是按照那个顺序进行的。

  而是按照分层初始化进行的。

  它仅仅表示要先初始化父类数据,再初始化子类数据。

  */

  class X {

  Y b = new Y();

  X() {

  System.out.print("X");

  }

  }

  class Y {

  Y() {

  System.out.print("Y");

  }

  }

  public class Z extends X {

  Y y = new Y();

  Z() {

  //super

  System.out.print("Z");

  }

  public static void main(String[] args) {

  new Z();

  }

  }