继承的实现
继承通俗的讲就是子类继承父类的一些特性,在父类的基础上子类可以进行行为的扩充
其语法格式如下:
class 子类名 extends 父类名 {
类体
}
extends
是继承的关键字,其后跟父类名,如果没得父类,则默认继承的是java.lang.Object,所以说所有class生成的类都是Object的子类。
- java中继承只支持单继承,即只能有一个父类,但类之间的继承具有传递性。
- 子类可以访问父类中权限为
public, protected, default
的成员,但不能访问被private
修饰的成员变量跟方法
package com.test;
class Person {
public String name = "LiHua";
private String sex; // 私有成员
public void eat() {
System.out.println("吃东西!");
}
// 父类私有方法
private void say() {
System.out.println("说话!");
}
}
class Student extends Person {
public String school;
// 子类构造方法
Student() {
this.school = "ZhongHua";
}
// 了类成员方法
public void study() {
System.out.println("学习!");
}
}
public class Test {
public static void main(String[] args) {
Person person = new Person();
Student student = new Student();
System.out.println(student.school); // ZhongHua * 子类的新增成员
// System.out.println(student.sex); // 编译时报错 * 不能继承父类的私有成员
student.eat(); // 吃东西! *访问继承而来的eat()方法
student.study(); // 学习 * 子类的新增方法
System.out.println(student.name); // LiHua *访问继承而来的name变量
}
}
//运行结果:
// 父类构造方法
// ZhongHua
// 吃东西!
// 学习!
// LiHua
上面例子可以看出,子类会继承父类除私有成员
以及构造方法外
的所有成员,同时在子类实例化的过程中,会优先初始化父类,这样子类才能获取到父类初始化的成员(如上例中的student.age)。
同时子类是不能继承父类的构造方法的,子类自能重写构造方法,或者不写构造方法让系统默认生成一个无参构造方法
继承与重写
既然子类是对父类的功能扩充,子类除了继承父类的特性外还可以拥有自己的成员以及对继承属性的修改。
在继承过程中,如果子类新增的变量与方法跟父类中的同名,则子类会重写继承而来的同名变量或方法。
对变量的重写要求变量名跟类型相同,同时对方法的重写要求返回值类型、方法名、参数列表的完全相同。
class Person {
public String name = "Person";
public void eat(String food) {
System.out.println("吃"+food);
}
}
class Student extends Person {
// 重写父类的name变量
public String name;
// 子类构造方法
Student() {
this.name = "Student";
}
// 重写父类的eat()方法 *返回值类型、方法名、参数列表的完全相同
@Override
public void eat(String food) {
System.out.println("学生吃"+food);
}
}
public class Test {
public static void main(String[] args) {
Student student = new Student();
System.out.println(student.name); // Student
student.eat("水果"); // 学生吃东西!
}
}
super关键字
了类访问父类的成员:super
关键字
子类除了能继承父类的成员外还能访问父类的成员,但也只能访问没有被private关键字修饰的成员
子类访问父类的方式是通过supper
关键字,因为继承中不能继承父类的构造方法,所以子类也能通过super访问父类的构造方法,基本格式如下:
访问父类成员变量:super.成员变量名
访问父类成员方法:super.成员方法名.([参数列表])
访问构造方法:super([参数列表])
但要注意的是:子类只能在其自己的构造方法中访问父类的构造方法
class Person {
public String name = "Person";
// 父类构造方法
Person() {
System.out.println("父类的构造方法!");
}
public void eat(String food) {
System.out.println("吃"+food);
}
}
class Student extends Person {
Student() {
super(); // 调用父类的无参构造方法
}
void visitFather() {
System.out.println(super.name); // Person *访问父类的name变量
super.eat("水果"); // 吃水果 *调用父类的eat()方法
}
}
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.visitFather();
}
}
//运行结果:
// 父类的构造方法!
// Person
// 吃水果
其实这里的super()
语句可以省略,因为在子类的构造方法中系统会自动调用父类无参的构造方法
注意的是:系统只是自动调用父类的无参构造方法,而有参的构造方法则不会自动调用
为什么要这样呢?:因为在子类的构造过程中必须调用父类的构造方法
举例:
当父类只有有参的构造方法时:
class Person {
int age;
Person(int n) {
this.age = n;
}
}
class Student extends Person {
Student() {
super(5); // 调用父类的有参构造函数
}
}
public class Test {
public static void main(String[] args) {
Student student = new Student();
}
}
在这个例子中,super(5)
这个语句不能没有,第一因为父类的构造函数是由参数的,系统不会自动调用,第二根据先初始化父类数据的原则,必须要在子类中手动调用父类的有参构造函数,否则会报错。
this关键字
直接看例子:
class Person {
int age = 5;
Person() {
int age = 10;
System.out.println(age); // 10
}
}
public class Test {
public static void main(String[] args) {
Person person = new Person();
}
}
可以看到这里输出的是构造函数中的局部变量age为10的值,而不是成员变量age为5的值。
其实在方法中访问成员变量由两种方式,第一种是直接访问,第二种则是通过this关键字访问
class Person {
int age = 5;
Person() {
System.out.println(age); // 5
System.out.println(this.age); // 5
}
}
public class Test {
public static void main(String[] args) {
Person person = new Person();
}
}
但是,通过第一种方式访问成员变量,当要访问的成员变量与局部变量同名时则优先获取的是局部变量
这种方式的变量访问规则:局部变量(包括参数) -> 全局变量(成员变量)
因此直接访问成员变量会与局部变量发生冲突,因此在方法中不建议用这种方式
而this关键实质是就是类对象,通过this关键字访问的变量只能是成员变量,在this关键字中会跳过访问局部变量
class Person {
int age = 5;
Person() {
int age = 10;
System.out.println(this.age); // 5
}
}
public class Test {
public static void main(String[] args) {
Person person = new Person();
}
}