目录
继承
继承指的是共性的抽取,从而实现代码的复用。Java中用类表示实体,每个实体间可能会存在某种关系,比方说猫和狗都是动物,我们可以将一样的地方抽取出来,实现继承的思想。A继承了B后,我们可以在B的基础上添加A特有的内容。A可以称为子类(派生类),B可以称为父类(基类或者超类)。A可以调用父类中的成员,也可以有自己特有的。
语法
修饰符class 子类名 extends 父类名 {
}
我们在这编写一个例子(动物类和狗类)
class Animal {
String name;
int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat() {
System.out.println("吃饭");
}
}
class Dog extends Animal {
public Dog() {
super("你好",18);
}
}
public class JavaSE730 {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat();
System.out.println(dog.name);
System.out.println(dog.age);
}
}
- 上述Dog类中并没有定义成员变量和普通成员方法,只有一个构造方法,但由于继承了Animal类,在main方法中通过子类对象可以访问到父类的内容。
- 继承后,父类的成员都可以继承到子类中,子类可以进行访问。
使用子类方法(或对象)访问到的究竟是子类中的内容还是父类中的呢?
访问成员变量
总而言之,子类会优先访问自己的,自己没有才去访问父类继承下来的。
- 如果父类的成员变量和子类的成员变量名字不同的时候,直接用子类对象调用即可。
- 如果父类的成员变量名字和子类的名字相同,则用子类对象调用的时候会调用子类的成员变量。(子类有,就不必麻烦父类了,优先访问自己的)
- 如果访问的成员变量子类中有,则优先访问子类的。如果子类中没有才去父类中寻找。
访问成员方法
同理,子类会优先访问自己的,自己没有才去访问父类继承下来的。
- 如果子类和父类中没有相同名字的成员方法,会看访问的成员方法子类中有没有,如果有访问子类的,如果没有则访问继承父类中的,如果父类中也没用就会报错。
- 对于方法名字相同的时候(没有发生重载时),子类对象访问时,也是遵循子类优先原则。
- 但是还有一种情况,如果子类和父类相同的方法发生了重载,访问的时候会根据传递的参数来决定访问父类的还是访问子类的。
访问父类成员
上面我们已经知道了具体的访问规则,那么我们就是想要获取到子类父类有相同名称的变量,方法(没有重载)的时候父类中的成员的时候怎么办呢?
super关键字
这个关键字的主要作用是在子类方法中访问父类的成员
super和this只可以在非静态方法中使用。(静态方法也可以称为类方法,类加载的时候就会执行,而this指当前对象的引用,super指子类对象中从父类继承下来部分成员的引用,两者均依赖于对象的创建。而对象的创建晚于类加载,所以不可以在静态方法中用this或者super)
class Animal {
String name;
int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat() {
System.out.println("吃饭");
}
}
class Dog extends Animal {
String name = "hh";
int age = 22;
public Dog() {
super("你好",18);
}
public void print() {
//在子类的方法访问了父类的两个成员变量
System.out.println(super.name);
System.out.println(super.age);
}
}
构造方法
在上一篇文章中我们已经介绍了类的构造方法,那么在继承的时候构造方法有什么不同呢?
既然继承,那么可以理解为是父子关系,父子嘛,肯定现有父再有子嘛,所以当我们实例化子类的时候,会先调用父类的构造方法,完成父类的创建后再调用子类的构造方法,完成子类的创建。
- 如果我们在编写代码的时候并没有为子类和父类编写构造方法,计算机在编译的时候会默认提供的。
//父类会默认提供这样的构造方法
public Student() {
}
//子类则和之前默认提供的构造方法稍有不同
public A() {
//会多这一句,这个作用是调用父类无参的构造方法
super();
}
- 如果我们不想用默认提供的,我们可以根据自己的需要去改,只不过需要注意的是,super这个语句必须在子类构造方法的第一句。
举个例子:
//父类会提供这样的构造方法
public Student(int num, int age) {
this.num = num;
this.age = age;
}
//子类
public A() {
//会多这一句,这个作用是调用父类含两个参数的构造方法
super(15,22);
}
- super和this不可以同时使用。
- 在构造方法中,super()只可以出现一次
super和this
- 相同点
(1)两者必须在非静态方法中使用,而且访问的是非静态的成员方法和成员变量。
(2)两者都为Java中的关键字。
(3)在构造方法中使用的时候,必须为构造方法的第一句,且二者不可同时存在。 - 不同点
(1)this 是当前对象的引用,而super相当于是子类对象继承父类的部分成员的引用。
(2)在非静态方法中,this用来访问当前对象的成员,super用来访问从父类继承下来的成。
(3)构造方法中,this()调用当前类的构造方法,super()调用父类的构造方法,两者不可同时存在。
(4)构造方法一定存在super()的调用,我们不写编译器也会加上,但是this不写就真的没有了。
继承的时候代码块的执行顺序
在上一篇文章中,我们介绍了代码块的执行顺序,那么继承关系的时候,代码块执行顺序是啥呢?
这里补充一下:实例代码块是写在类里面的{},Student student = new Student();这个语句如果也写在了类里面,这个也可以称为实例代码块。
class Animal {
int age;
static String name;
static {
System.out.println("父类的静态代码块");
}
{
System.out.println("父类的实例代码块");
}
public Animal() {
System.out.println("父类构造方法");
}
}
class Dog extends Animal{
static {
System.out.println("子类的静态代码块");
}
{
System.out.println("子类的实例代码块");
}
public Dog() {
System.out.println("子类构造方法");
}
}
public class JavaSE730 {
public static void main(String[] args) {
Dog dog = new Dog();
}
}
注意!静态代码块还是只执行一次,再次实例化子类对象的时候不会再执行子类和父类的静态代码块。
继承方式
Java中继承方式有好几种,下面我们来介绍一下。
- 单继承
public class A extends B {
}
class B {
}
- 不同的类继承同一个父类
class A {
}
class B extends A {
}
class C extends A {
}
- 多层继承
class A {
}
class B extends A {
}
class C extends B {
}
注意
- Java中没有多继承,A extends B,A extends C,多继承就是一个类可以继承多个类。
- 我们在编写代码的时候,我们不希望出现多重继承超过三层。
- 我们可以通过final关键字限定类是否可以被继承。
final关键字
final关键字可以修饰变量,方法和类
- 修饰变量的时候,表示常量,不可再进行更改。
- 修饰类的时候,表示不可以再被继承。
- 修饰方法的时候表示不可以再被重写。
组合
组合和继承类似,也可以实现代码的复用,只不过此时并不是通过继承来复用的,而是通过将某个类作为另一个类的字段来复用。实际生活中,我们常用组合来实现代码复用。
继承是is-a的关系,狗是动物
组合而是has-a的关系,汽车有轮胎…
//轮胎类
class Tire {
int num;
}
//汽车类
class Car {
Tire tire;//可以将类用在另外的类中,当一个字段。这样也可以复用Tire类的代码
public void make() {
tire.num = 10;
}
}