目录
- 基本介绍
super代表父类的引用,用于访问父类的属性、构造器、方法。
一、基本语法
1.访问父类的属性,但不能访问父类的private属性 super.属性名;
2.访问父类的方法,但不能访问父类的private方法 super.方法名(参数列表);
3.访问父类的构造器 super(参数列表);只能放在构造器的第一句并且只能出现一句
二、super给编程带来的好处/细节
1.调用父类构造器的好处(分工明确,父类属性由父类初始化,子类属性由子类初始化)
2.当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名,使用super、this、直接访问是一样的效果
3.super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类(上级类)中都有同名的成员,使用super访问遵循就近原则。
三、super和this的比较
| 区别点 | this | super | |
|---|---|---|---|
| 访问属性 | 访问本类中的属性,如果本类没有 此属性则从父类中继续查找 | 从父类开始查找属性 | |
| 调用方法 | 访问本类中的方法,如果本类没有 此方法则从父类中继续查找 | 从父类开始查找方法 | |
| 调用构造器 | 调用本类构造器,必须放在构造器的首行 | 调用父类构造器,必须放在 子类构造器的首行 | |
| 特殊 | 表示当前对象 | 子类中访问父类对象 (父类的引用) |
super课堂讲解代码
public class super01 {
public static void main(String[] args) {
B b = new B();//子类对象
//b.sum();
b.Test();
}
}
public class Base { //父类的父类
public int n1 = 999;
public int age = 20;
public void cal(){
System.out.println("Base类的cal方法....");
}
public void eat(){
System.out.println("Base类的eat方法....");
}
}
public class A extends Base{ //父类
//属性
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
//构造器
public A(){}
public A(String name){}
public A(String name, int age){}
//方法
public void test100(){}
protected void test200(){}
void test300(){}
private void test400(){}
//细节补充代码
public void cal(){
System.out.println("A类的cal方法....");
}
}
public class B extends A{ //子类
//访问父类的属性,但不能访问父类的private属性 super.属性名;
public void hi(){
System.out.println(super.n1 + " " + super.n2 + " " + super.n3);
}
//访问父类的方法,但不能访问父类的private方法 super.方法名(形参列表);
public void ok(){
super.test100();
super.test200();
super.test300();
}
//访问父类的构造器 super(参数列表); 只能放在构造器第一句,只能出现一句
public B(){
//super();
super("jack",10);
}
//细节补充代码
public int n1 = 888;
public void cal(){
System.out.println("B类的cal方法...");
}
public void sum(){
System.out.println("B类的sum方法....");
//希望调用父类A的cal方法
//因为子类B没有cal方法,因此可以使用下面三种方式
//找cal方法时(cal() 和 this.cal()),顺序如下
// 1.先找本类,如果有,则调用
// 2.如果本类没有,则找父类(如果有,并且可以调用,则调用)
// 3.如果父类没有,则继续找父类的父类,直到找到Object类
// 提示:如果查找方法的过程中找到了,但是不能访问,则报错
// 如果查找方法的过程中没有找到,则提示方法不存在
//cal();
//this.cal();//等价与 cal();
//找cal方法(super.cal())的顺序是直接查找父类,其他规则一样
super.cal();
//访问属性的规则与找方法的规则一致
System.out.println(n1);
System.out.println(this.n1);
System.out.println(super.n1);
}
//编写测试方法Test
public void Test(){
//super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,
//也可以使用super去访问爷爷类的成员;如果多个基类(上级类)中都有同名的成员,
// 使用super访问遵循就近原则。A->B->C,当然也要遵守访问权限的相关规则
System.out.println("super.n1=" + super.n1);
super.cal();
}
}
四、方法重写/覆盖
1.基本介绍
方法重写(覆盖)就是子类有一个方法和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的方法。当父类中的方法无法满足子类需求或子类具有特有功能的时候,需要方法重写。
子类可以根据需要,定义特定于自己的行为。既延续了父类的功能名称,又根据子类的需要重新实现父类方法,从而进行扩展增强。
入门案例
public class Animal {
public String name; // 名字
public int age; // 年龄
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getInfo() {
return "我叫" + name + ",今年" + age + "岁了。";
}
}
public class Cat extends Animal {
private String hobby;
public Cat(String name, int age, String hobby) {
super(name, age);
this.hobby = hobby;
}
public String getInfo() {
return "喵!大家好!我叫" + this.name + ",我今年" + this.age + "岁了,我爱吃" + hobby + "。";
}
public static void main(String[] args) {
Animal animal = new Cat("小白", 2, "鱼");
System.out.println(animal.getInfo());
}
}如上述代码,在 Animal 类中定义了一个返回值类型为 String、名称为 getInfo() 的方法,而 Cat 类继承自该类,因此 Cat 类同样含有与 Animal 类中相同的 getInfo() 方法。但是我们在 Cat 类中又重新定义了一个 getInfo() 方法,即重写了父类中的 getInfo() 方法。在 main() 方法中,创建了 Cat 类的对象 animal,并调用了 getInfo() 方法。
2.注意事项和使用细节
①子类方法的形参列表,方法名称要和父类的形参列表、方法名称完全一样
②子类方法的返回类型和父类方法的返回类型要一样,或者是父类返回类型的子类。比如:父类返回类型是Object,子类的返回类型是String
③子类方法不能缩小父类方法的访问权限(可以相等或者扩大)
public→protected→默认→private
3.重载和重写的比较
| 名称 | 发生范围 | 方法名 | 形参列表 | 返回类型 | 修饰符 |
|---|---|---|---|---|---|
| 重载 | 本类 | 必须相同 | 类型、个数或者顺序至少有一个不同 | 无要求 | 无要求 |
| 重写 | 父子类 | 必须相同 | 必须相同 | 子类重写的方法 返回的类型和父类 返回的类型必须一致,或者是其子类 | 子类方法不能缩小父类方法的访问范围 |
方法重写练习题
package com.learn.override;
public class OverrideExercise {
public static void main(String[] args) {
//在 main 中,分别创建 Person 和 Student 对象,调用 say 方法输出自我
Person person = new Person("jack", 10);
System.out.println(person.say());
Student student = new Student("smith",18,12345,88.8);
System.out.println(student.say());
}
}
//编写一个 Person 类,包括属性/private(name、age),构造器、方法 say(返回自我介绍的字符串)
public class Person {
//属性
private String name;
private int age;
//构造器
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//方法
public String say(){
return "name=" + name + " age=" + age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
//编写一个 Student 类,继承 Person 类,增加 id、score 属性/private,以及构造器,
//定义 say 方法(返回自我介绍的信息)
public class Student extends Person{
//属性
private int id;
private double score;
//构造器
public Student() {
}
public Student(String name, int age, int id, double score) {
super(name, age);//调用父类的方法
this.id = id;
this.score = score;
}
//方法
public String say(){
return super.say() + " id=" + id + " score=" + score;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
}