好久没有写博客了。今天开始每周更新一盘。

       今天写写Java中啥子叫做类:

 

对于面向对象的程序设计语言来说,类毫无疑问是其最重要的基础。抽象、封装、继承、多态这四大特性都离不开类,只有存在类,才能体现面向对象编程的特点,今天我们就来了解一些类与继承的相关知识。首先,我们讲述一下与类的初始化相关的东西,然后再从几个方面阐述继承这一大特性。以下是本文的目录大纲:

  一.你了解类吗?

  二.你了解继承吗?

  三.常见的面试笔试题

一.你了解类吗?

  在Java中,类文件是以.java为后缀的代码文件,在每个类文件中最多只允许出现一个public类,当有public类的时候,类文件的名称必须和public类的名称相同,若不存在public,则类文件的名称可以为任意的名称(当然以数字开头的名称是不允许的)。

  在类内部,对于成员变量,如果在定义的时候没有进行显示的赋值初始化,则Java会保证类的每个成员变量都得到恰当的初始化:

  1)对于  char、short、byte、int、long、float、double等基本数据类型的变量来说会默认初始化为0(boolean变量默认会被初始化为false);

  2)对于引用类型的变量,会默认初始化为null。

  如果没有显示地定义构造器,则编译器会自动创建一个无参构造器,但是要记住一点,如果显示地定义了构造器,编译器就不会自动添加构造器。注意,所有的构造器默认为static的。

  下面我们着重讲解一下 初始化 顺序:

  当程序执行时,需要生成某个类的对象,Java执行引擎会先检查是否加载了这个类,如果没有加载,则先执行类的加载再生成对象,如果已经加载,则直接生成对象。

  在类的加载过程中,类的static成员变量会被初始化,另外,如果类中有static语句块,则会执行static语句块。static成员变量和static语句块的执行顺序同代码中的顺序一致。记住,在Java中,类是按需加载,只有当需要用到这个类的时候,才会加载这个类,并且只会加载一次。看下面这个例子就明白了

 

4.super

  super主要有两种用法:

  1)super.成员变量/super.成员方法;

  2)super(parameter1,parameter2....)

  第一种用法主要用来在子类中调用父类的同名成员变量或者方法;第二种主要用在子类的构造器中显示地调用父类的构造器,要注意的是,如果是用在子类构造器中,则必须是子类构造器的第一个语句。

三.常见的面试笔试题

1.下面这段代码的输出结果是什么?

public class Test {
   public static void main(String[] args)  {
       new Circle();
   }
}

class Draw {

   public Draw(String type) {
       System.out.println(type+" draw constructor");
   }
}

class Shape {
   private Draw draw = new Draw("shape");

   public Shape(){
       System.out.println("shape constructor");
   }
}

class Circle extends Shape {
   private Draw draw = new Draw("circle");
   public Circle() {
       System.out.println("circle constructor");
   }
}

输出结果:

shape draw constructor
shape constructor
circle draw constructor
circle constructor

这道题目主要考察的是类继承时构造器的调用顺序和初始化顺序。要记住一点:父类的构造器调用以及初始化过程一定在子类的前面。由于Circle类的父类是Shape类,所以Shape类先进行初始化,然后再执行Shape类的构造器。接着才是对子类Circle进行初始化,最后执行Circle的构造器。

2.下面这段代码的输出结果是什么?

public class Test {
   public static void main(String[] args)  {
       Shape shape = new Circle();
       System.out.println(shape.name);
       shape.printType();
       shape.printName();
   }
}

class Shape {
   public String name = "shape";

   public Shape(){
       System.out.println("shape constructor");
   }

   public void printType() {
       System.out.println("this is shape");
   }

   public static void printName() {
       System.out.println("shape");
   }
}

class Circle extends Shape {
   public String name = "circle";

   public Circle() {
       System.out.println("circle constructor");
   }

   public void printType() {
       System.out.println("this is circle");
   }

   public static void printName() {
       System.out.println("circle");
   }
}

输出结果:

shape constructor
circle constructor
shape this is circle
shape

这道题主要考察了隐藏和覆盖的区别(当然也和多态相关,在后续博文中会继续讲到)。

  覆盖只针对非静态方法(终态方法不能被继承,所以就存在覆盖一说了),而隐藏是针对成员变量和静态方法的。这2者之间的区别是:覆盖受RTTI(Runtime type  identification)约束的,而隐藏却不受该约束。也就是说只有覆盖方法才会进行动态绑定,而隐藏是不会发生动态绑定的。在Java中,除了static方法和final方法,其他所有的方法都是动态绑定。因此,就会出现上面的输出结果。