总结

继承

继承的定义

继承是在一个已有类的基础上构建新类, 新类除了继承已有类的属性和方法, 还可以根据需要增加新的属性和方法.

  • 新类称作子类(或派生类), 已有类称作父类(或超类)
  • 可以说子类继承父类, 也可以说父类派生出子类
1
2
3
class <子类名> extends <父类名> {
...
}

父类可以是自己编写的类, 也可以是已有的类或java类库中的类

子类从父类继承的成员变量和成员方法和子类自己声明的一样

  • 如果一个类没有声明继承某个父类, 那么这个类默认是Object的子类
  • class A {...}class A extends Object{...} 是等价的
  • Java中所有的类都直接或间接的继承Object类, Object所有Java类根父类
  • Java只支持单继承, 不支持多重继承, 一个类只能有一个父类, 但是多个类可以继承同一个父类
  • 子类可以继承父类的实例变量和实例方法

  • 子类不继承父类的构造方法

  • 子类可以继承父类的类变量和类方法.被继承的类变量和类方法, 可以通过子类对象和父类对象访问, 还可以通过子类名或父类名访问

  • 子类从父类继承的成员变量和成员方法的访问权限不变

  • 子类和父类在同一个包中, 那么子类能够继承父类的非private的成员变量和成员方法

  • 子类和父类不在用一个包中, 那么子类只能继承父类的protected和public成员, 不能继承父类友好成员和private成员

子类对象的创建

  • 创建并初始化父类的静态成员变量(如果有, 只在加载父类时执行一次)
  • 创建并初始化子类的静态成员变量(如果有, 只在加载子类时执行一次)
  • 创建并初始化父类的实例成员变量
  • 调用父类的构造方法;
  • 创建并初始化子类的实例成员变量
  • 调用子类的构造方法.
  • 任何子类对象在创建时, 总是从该子类的继承链的最顶端开始依次往下执行: 创建每个父类的成员变量并调用父类的构造方法, 直到创建该子类自己的成员变量并调用自己的构造方法.

成员变量的隐藏和成员方法的重写

  • 当子类和父类有同名成员变量时, 在子类方法中访问的是子类的成员变量, 在父类方法中访问的是父类的成员变量

方法重写

  • 在子类中定义一个方法, 这个方法的名字、参数、返回值类型与从父类继承的某个方法完全相同, 这就是子类对父类方法的重写(或者叫覆盖)
  • 通过子类对象或在子类内部调用同名方法时, 调用的总是子类重写的方法
  • 如果在子类内部想使用被重写的父类方法, 可以使用关键字super
  • 重写父类方法时, 不能降低方法的访问权限
  • 子类拥有名字相同而参数不同的两个方法, 这是方法的重载
  • 静态方法不会被重写

super

super关键字表示当前对象的父类

  1. 在子类的构造方法中, 使用super关键字指定调用父类的某个构造方法
  2. 在子类, 通过super关键字访问父类的成员变量和成员方法
  3. super关键字只能用于构造方法和实例方法, 不能用于类方法

使用super关键字调用父类的构造方法

  • super语句必须是第一条语句
  • 在子类的构造方法中, 通过"super(参数列表);"的形式, 指定调用父类的某个构造方法, 由参数列表确定调用父类哪个构造方法

使用super关键字访问父类的成员变量和成员方法

  • 如果子类想访问父类被隐藏的成员变量或被重写的成员方法, 可以使用super关键字
  • 访问父类的任意成员变量和成员方法, 都可以使用super关键字, 只是在不引起歧义的情况下一般省略super

final类 和 final 方法

  • 用final关键字修饰的类称为final类
  • final类不能被继承, 即不能有子类
  • 用final关键字修饰的方法称为final方法
  • 如果一个方法被修饰为final方法, 则这个方法可以被继承, 但不能被重写, 即不允许子类重写父类的final方法

上转型与多态

上转型:

1
2
3
4
class A {...}
class B extends A {...}
// 上转型 将子类对象赋值给父类变量
A a = new B();
  • 子类对象上转型后, 不能再使用子类新增的属性和方法
  • 只能使用从父类继承的属性和方法
  • 对于父类被子类重写的方法, 实际访问的是子类的方法, 但访问权限还是按照父类方法的访问权限.
  • 把子类对象作为实参传给父类的形参, 这也是上转型
  • 父类不能被子类继承的属性和方法, 则上转型对象不能访问
  • 若存在方法重写, 则访问上转型对象时, 上转型对象原来是哪个类的对象, 则访问的就是哪个类重写的方法
  • 如果两种类型之间没有继承关系, 那么Java编译器不允许在两者间进行类型转换

下转型:

1
2
3
4
// 上转型
A a = new B();
// 下转型
B b = (B) a;
  • 下转型需要强制转换
    • 把一个父类对象强制转换为子类对象, 这是不允许的, 尽管编译能通过, 但不能运行
    • 先将子类对象上转型, 然后再下转型, 这是允许的, 上转型对象通过下转型又转换回原来的子类对象, 可以使用子类的全部属性和方法.
  • 把子类对象赋值给父类变量叫上转型, 上转型不用强制转换;
  • 把父类对象赋值给子类变量叫下转型, 要强制转换.
  • 当出现下转型时, 一定要在此之前先执行过上转型, 然后再执行下转型

多态

Java的多态有两种实现方式: 静态多态, 也就是方法重载;动态多态: 和继承及重写有关.
多态的实现条件: 继承-重写-上转型

抽象类和抽象方法

用关键字abstract修饰的类称为抽象类(abstract类)

1
abstract class A{...}
  • 抽象类不能用来创建实例, 但是可以被继承, 也可以用来声明变量
  • 不允许使用final和abstract同时修饰一个类和方法.
  • 用关键字abstract修饰的成员方法称为抽象方法(abstract方法), 抽象方法只有声明没有实现, 也就是没有方法体
  • 抽象方法必须是实例方法, 可以被子类重写(在子类中实现方法体), 重写的方法不再是抽象方法
  • 如果子类不重写父类的抽象方法, 则继承该抽象方法
  • 有abstract方法的类一定是abstract类, 而abstract类不一定有abstract方法
  • 子类如果不重写abstract父类的abstract方法, 则会继承该abstract方法, 从而子类也成abstract类

内部类(不考)

所谓的内部类, 就是定义在一个类内部的类, 包括常规内部类、匿名内部类、静态内部类(不要求掌握)、局部内部类(不要求掌握).

常规内部类

定义在类体中(不是方法体中)且没有用static修饰的类.

定义常规内部类时可以使用private、protected、public、友好等访问权限, 与用于成员变量和成员方法时的规则相同, 可以将常规内部类看作是外部类的一个成员.

  • 在常规内部类中可以访问外部类的成员,
    • 用"外部类名.this.外部类成员"的形式访问外部类的实例成员,
    • 用"外部类名.外部类成员"的形式访问外部类的静态成员.

在外部类的实例方法和构造方法中可以直接声明内部类的变量、创建内部类的对象:
内部类名 变量名 = new 内部类名(…)
在外部类的实例方法和构造方法之外的地方创建常规内部类的对象:
声明内部类的变量: 外部类名.内部类名 变量名
创建内部类的对象: 外部类对象.new 内部类名(…)
也就是要先创建外部类对象, 然后通过外部类对象创建内部类对象