DUFQ_2020.12.8-杜飞强-继承

包是管理类和接口的,还可以解决命名冲突,类和接口需要定义在包中。

包 = 目录

类 = 文件

包的定义

定义包必须是java源文件的第一行代码

包名必须是小写

使用关键字package定义包,eg:package com.dufq.pack

使用包

使用包就是将包中的类导入到使用的地方

使用import关键字导入包

eg:import java.util.Arrays;

importjava.util.Scanner;

import java.util.*;

系统包

java.long.*:此包的类默认都导入了。eg:String、system、Math。

java.util.*:工具包,Scanner Random Arrays

java.io.*:输入输出 File FileInputStream

java.text.*:国际化程序支持包SimpleDateFormat

PS:声明包的含义是声明当前类所在的包

导入包的含义是声明当前类要使用到的其他类所在的包

static关键字

static修饰属性

使用static修饰的属性称为静态属性或类变量,没有使用static修饰的属性称为实例变量。

使用static修饰的属性属于类,不属于具体的某个对象。

类属性在类名首次出现时初始化,即使没有创建对象,类属性也是存在的。

static的使用

static可以修饰内部类、属性和方法、定义静态块,eg:

public class Person {
    public static int live = 1;//static 修饰属性

    public static void sayHello() {//static 修饰方法

    }
    static class Student{//static修饰内部类
        String name;
    }
    static {//静态块1

    }
    static {//静态块2

    }
}

静态与实例的区别

实例:instancesnew出来的对象

image-20201208202751509

修饰规则

(1)静态成员是实例成员分配内存的时机

​ 静态成员是在类名首次出现时,最先分配内存的,静态属性分配在方法区中,然后调用静态块,多个静态块按照定义的顺序从上到下调用。

​ 实例成员是在实例化时分配内存的,如果没有实例化对象,那么实例成员就没有分配内存。

(2)静态成员和实例成员分配内存的次数

​ 静态成员只分配一次内存,因此静态成员只有一份。

​ 实例成员分配内存的次数由实例化的次数决定,每实例化一次就分配一次内存

(3)静态成员和实例化成员额调用

​ 静态成员由类名调用,也可以由对象名调用,但是不推荐使用对象名调用。

​ 实例成员由对象名调用,不能使用类名调用。

​ 即、静态属于类成员,因此静态成员也称为类成员(类变量、类方法)

​ 实例属于对象成员

(4)静态块的作用

​ 实例属性可以通过构造函数初始化

​ 静态属性可以通过静态块初始化,因为类名首次出现时先为静态变量分配内存,然后就调用静态块。

java中的常量

值不可以更改的变量称为常量

使用static final修饰的变量是类常量

使用final修饰变量是实例常量

final是java的关键字,翻译为最终。final可以修饰类、属性、方法。修饰类时不能被继承,修饰方法时不能被子类重写,修饰属性时属性不能改值。eg:类常量和实例常量

public class Book {
    public static final String NAME;//定义类常量
    public final int price ;//定义实例常量
    public Book(int price) {
        this.price = price;//在构造函数中实例常量初始化
    }
    static {
        NAME="thinking in java";//在静态块中类常量初始化
    }
}

继承

继承是面向对象的三大特征之一

继承的定义

继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。

继承的作用

提高代码复用,减少代码冗余,增强代码的扩展性

继承的应用

使用extends关键字实现继承

eg:

class Person {
     String name;
     public Person (){
         System.out.println("execute Person()");
     }

    public Person (String nme){
        System.out.println("ecxecuite Person(name)");
    }
}
class Student extends Person {//Student继承Person类
     String school;//学校
    public  Student(){
        System.out.println("execute studengt()");
    }

子类继承父类后,子类就继承了父类中的成员,导致子类无需再次创建,简化了子类的设计。

super与this关键字

super表示父类

this表示子类

super的用法1

在子类构造方法中调用父类构造方法

public Student(String name ,String school) {
    super(name);//显示调用父类有参加构造方法,将不执行无参构造方法
    this.school = school;
    System.out.println("execute Student(name,school)");
}

注意:super调用父类构造函数时,必须写在子类构造函数的第一行。

​ 通常父类定义的属性有父类负责初始化,子类定义的属性由子类负责初始化。子类通过super(参数列表)的方式将子类构造函数中的参数传递给父类,让父类初始化。

super的用法2

在子类的方法中调用父类的方法

public String toString() {
    return super.toString()+"count="+ count;
}

继承中属性的初始化问题

建议谁定义的属性,由谁初始化

class A{
    int a;
    public A(int a) {
        this.a = a;
    }
}
class B extends A{
    int b;
    public B(int a,int b) {
        super(a);
        this.b = b;
    }
}
class C extends B{
    int c;
    public C(int a,int b,int c) {
        super(a,b);
        this.c = c;
    }
}
public class D {
    public static void main(String[] args) {
        C c = new C(1, 2, 3);
    }
}

调试程序,观察初始化的过程

当前类的构造函数得到的参数中,留下自己定义的函数需要的参数,其余的参数通过super传递给父类初始化。

继承中对象实例化的顺序问题

观察下面的代码
class A{
    int a;
    public A(int a) {
        this.a = a;
    }
}
class B extends A{
    int b;
    public B(int a,int b) {
        super(a);
        this.b = b;
    }
}
class C extends B{
    int c;
    public C(int a,int b,int c) {
        super(a,b);
        this.c = c;
    }
}
public class D {
    public static void main(String[] args) {
        C c = new C(1, 2, 3);
        c.a= 1;
    }
}

问题:main方法中创建对象c时,jvm到底创建了多少个对象?

答:当实例化一个对象时,该对象的所有父类也都被实例化了。

问题:这些被实例化的对象实例化的顺序是什么?

答:实例化顺序是从父类到子类。

问题:继承中构造函数的调用顺序是?

答:从子类到父类调用

问题:继承中构造函数的执行顺序是?

答:从父类到子类

评论