探究Java中的类和继承--------Java的系列学习之路(15)

前言——

今天是军训的第5天,昨天打了一天的军体拳(哈哈哈,好好看本篇博文,不然博主一套军体拳下去你可能会残疾  :)

明天是最后一天了,今晚继续做自己手头上的事,避免碌碌无为。今天讲解的内容——类和继承,也是跟上一篇一样,基础且重要。

第5天没把这篇文章写完,今天第六天,早上考了军体拳,下午考队列了,趁午休时间赶完这篇文章,晚上可能要去看戏曲表演,不过感觉看戏曲好无聊。。。

欢迎转载,转载请注明来处。

目录

Java中的类

二.继承

三.初始化一个子类对象时,发生了啥


Java中的类

a.Java的类文件

Java中的类是一个.java后缀的class文件。一个class文件最多只允许有一个public类,如果含有public类的话,那么这个class文件名就必须要和public类的类名一致;如果这个类中没有public类,都是包访问权限的类的话,那么class文件名可以随意。如下图所示:

b.类的加载

当我们要用到某个类,或者不严谨地说,当我们new一个类的对象时,如果代码中还未曾使用过该类,那么应该先进行该类的加载,然后再生成对象。类的加载会加载该类中的static变量或者方法,或者static代码块。当类被加载过后,第二次用到该类时就无需再加载了,可以直接生成对象。

如下:

这边Test4类的main方法中第一次用到Code类,所以要先加载Code类,所以会先加载static成员coderName,然后加载static代码块,这边会发现"Loading Jian"只打印一次。

运行结果如下:
loading  Jian
I am going to code

c.生成对象时发生了什么

1.首先Java会对类中每个成员进行一个初始化,如果成员变量在定义时没有进行显示地初始化,那么会被默认初始化。

对于  char、short、byte、int、long、float、double等基本数据类型的变量来说会默认初始化为0(boolean变量默认会被初始化为false);对应引用类型的变量,则会被赋值为null。

这时在Code类当中,coderName这个成员没有被显示初始化,由于其是属于引用类型的变量,所以被默认初始化为null。

2.执行构造函数。如果这个类中没有自定义构造函数,那么编译器会自动生成无参构造函数;如果自定义了构造函数,那么编译器就不会自动生成无参构造函数。

会发现,Code类中自定义了Code(String name)的构造函数后,在Test4的main方法中调用无参构造函数时会报错,此时找不到对应的无参构造函数。

二.继承

在Java中用extends关键字表示继承,而且只允许单继承。一个子类只能继承一个父类,但是一个父类却可以被多个子类继承。

a.子类继承父类的哪些东西?

1.肯定能继承父类的public和protected变量和方法。

2.肯定无法继承父类的private变量和方法。

3.对于父类的包访问权限的变量和方法,如果子类和父类在同一个包下,则子类可以继承,否则子类不能继承。

如下:

在这边Bird类是Pet类的子类,但是二者不在同一个包当中,而父类Pet 中的getType()方法是一个包访问权限的方法,很明显,此时Bird类是没有继承这个getType()方法的。

4.对于子类可以继承的变量和方法,如果子类内部出现了同名的变量或者方法就会发生覆盖。此时如果在子类中想访问父类中的变量或者方法的话,应该用super关键字。

运行结果:
In Bird
In Pet

b.super关键字

有两种用法。

1.super.父类的成员/父类的方法

2.super(参数), 这个语句放在子类的构造函数中的第一行;除了一定得放在第一行之外,这个语句只能在子类的构造函数中出现一次。

在这边,父类由于自定义了构造函数,导致了编译器不会自动添加无参构造函数,父类的构造函数又不能被继承,所以子类的无参的构造函数必须显示地添加super(参数)语句,这样才能调用父类的构造函数。如果父类有无参构造器,则在子类的构造器中用super关键字调用父类构造器不是必须的,因为会自动调用无参构造函数。

三.初始化一个子类对象时,发生了啥

这是从其他博客看到的一个笔试题,感觉特别不错。

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

在这边,主要考察生成子类对象时构造函数和初始的顺序。可以理解为先生成父类部分,再生成子类部分。

父类部分是先初始化父类成员,再调用父类的构造函数;

子类部分是先初始化子类成员,再调用子类的构造函数。

猜你喜欢

转载自blog.csdn.net/CCSGTC/article/details/83032536