目录
super关键字的基本介绍
基本介绍 :
super代表父类的引用,用于访问父类的属性、方法、构造器
基本语法
1.访问父类的属性,但不能访问父类的private属性
super.属性名;
2.访问父类的方法,不能访问父类的private方法
super.方法名(参数列表);
3.访问父类的构造器(这点前面用过):
super(参数列表);只能放在构造器的第一句,只能出现一句!
代码演示:
1.在下面的代码中我们可以看到,super(),表示的是去访问父类的中的属性或者方法,如果如果要查找的属性在父类中没有话,那么会去一直向上查找,一直查找到顶级父类Object,如果一直查找不到就会报错
2.使用super关键之去访问父类的属性和方法,也需要遵守访问修饰符的权限
3.如果要希望指定去调用父类的哪一个构造器,那么需要在子类的构造器中,显示的声明一下,否则默认调用的时候,调用的是父类的无参构造器,如果父类的无参构造器被覆盖了,那么在使用子类创建对象的时候,子类的构造器中,就必须指定调用父类的哪一个构造器,否则会编译错误
package com.idea.super_;
/**
* 演示super关键字的基本使用
*/
public class super01 {
public static void main(String[] args) {
//super关键字的作用
//super代表父类的引用,用于访问父类的属性、方法、构造器
//基本语法
//1.访问父类的属性,但不能访问父类的private属性 super.属性名;
//2.访问父类的方法,不能访问父类的private方法 super.方法名(参数列表);
//3.访问父类的构造器(这点前面用过): super(参数列表);只能放在构造器的第一句,只能出现一句!
Dog dog = new Dog();
System.out.println();
Dog dog1 = new Dog("jack");
//dog.hi();
}
}
class Animal {//父类
//私有的名字属性
private String name;
//公有的年龄属性
public int age;
//有参构造器
public Animal(String name, int age) {
System.out.println("父类的有参构造器被调用");
this.name = name;
this.age = age;
}
//无参构造器
public Animal() {
System.out.println("父类的无参构造器被调用");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void cry(String name) {
System.out.println("hello,word" + " " + name);
}
}
class Dog extends Animal {
public Dog() {
//3.访问父类的构造器(这点前面用过): super(参数列表);只能放在构造器的第一句,只能出现一句!
super();//表示去访问父类的无参构造器
//这样是错误的,只能有一个super,并且只能出现在构造器中的第一行,否则会报错
//super("jack",10);
System.out.println("子类的无参构造器被调用");
}
public Dog(String name){
super("jack",10);//表示去访问父类的有参构造器
System.out.println("子类的带一个参数有参构造器被调用");
}
public void hi() {
//1.访问父类的属性,但不能访问父类的private属性 super.属性名;
//可以访问父类的public属性
System.out.println(super.age);
//这样是错误的,不可以访问父类的private属性
//System.out.println(super.name);
//如果想要访问父类的私有属性,需要调用父类提供的公共方法
System.out.println(super.getName());
//2.访问父类的方法,不能访问父类的private方法 super.方法名(参数列表);
//使用super去访问父类的方法,同理如果方法是私有的也不能直接访问,需要父类提供公共的方法才可以
super.cry("jack");
}
}
super关键字细节
1.调用父类的构造器的好处(分工明确,父类的属性由父类初始化,子类的属性由子类初始化)
2.当子类有和父类中的成员(属性和方法)重名是,为了访问父类的成员,必须通过super,通过没有重写,使用super、this 直接方法也是一样的效果
3.super的访问不限于父类,如果爷爷类和本类都有同名的成员,也可以使用super去访问爷爷类的成员:如果多个基类(上级类)中都有同名的成员,使用super方法遵守就近原则
代码演示:
package idea.super_;
/**
* 演示super关键字的注意事项和使用细节
*/
public class superDetail {
public static void main(String[] args) {
//1.调用父类的构造器的好处(分工明确,父类的属性由父类初始化,子类的属性由子类初始化)
//2.当子类有和父类中的成员(属性和方法)重名是,为了访问父类的成员,必须通过super,通过没有重写,使用super、this 直接方法也是一样的效果
//3.super的访问不限于父类,如果爷爷类和本类都有同名的成员,也可以使用super去访问爷爷类的成员:如果多个基类(上级类)中都有同名的成员,使用super方法遵守就近原则
B b = new B();
b.test();
}
}
class Base { //父类是Object
public int n1 = 999;
public int age = 111;
public void cal() {
System.out.println("Base类的cal() 方法...");
}
public void eat() {
System.out.println("Base类的eat().....");
}
}
class A extends Base {
//4个属性 不同权限的属性
//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 cal() {
// System.out.println("A类的cal() 方法...");
// }
//四个不同权限的方法
public void test100() {
}
protected void test200() {
}
void test300() {
}
private void test400() {
}
}
class B extends A {
public int n1 = 888;
//编写测试方法
public void test() {
//super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;
// 如果多个基类(上级类)中都有同名的成员,使用super访问遵循就近原则。A->B->C
System.out.println("super.n1=" + super.n1);//super表示去访问父类的成员,因为在我们的父类中n1所以输出的也就是父类中的n1
System.out.println(this.n1);//如果使用的是this,那么输出的就是本类中的属性,如果本类中没有这个属性,那么就回去父类中查找,规则一样
super.cal();
}
//访问父类的属性 , 但不能访问父类的private属性 [案例]super.属性名
public void hi() {
System.out.println(super.n1 + " " + super.n2 + " " + super.n3);
}
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类
// 提示:如果查找方法的过程中,找到了,但是不能访问, 则报错, cannot access
// 如果查找方法的过程中,没有找到,则提示方法不存在
//cal();
this.cal(); //等价 cal()
//找cal方法(super.call()) 的顺序是直接从父类开始查找,其他的规则一样
//super.cal();
//演示访问属性的规则
//n1 和 this.n1 查找的规则是
//(1) 先找本类,如果有,则调用
//(2) 如果没有,则找父类(如果有,并可以调用,则调用)
//(3) 如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到 Object类
// 提示:如果查找属性的过程中,找到了,但是不能访问, 则报错, cannot access
// 如果查找属性的过程中,没有找到,则提示属性不存在
System.out.println(n1);
System.out.println(this.n1);
//找n1 (super.n1) 的顺序是直接查找父类属性,其他的规则一样
System.out.println(super.n1);
}
//访问父类的方法,不能访问父类的private方法 super.方法名(参数列表);
public void ok() {
super.test100();
super.test200();
super.test300();
//super.test400();//不能访问父类private方法
}
//访问父类的构造器(这点前面用过):super(参数列表);只能放在构造器的第一句,只能出现一句!
public B() {
//super();
//super("jack", 10);
super("jack");
}
}
super和this的区别
看一张表格
NO | 区别点 | this | super |
---|---|---|---|
1 | 访问属性 | 访问本类中的属性,如果本类没有此属性则到父类中继续查找 | 从父类开始查找属性 |
2 | 调用方法 | 访问本类中的方法如果本类中没有此方法则到父类中继续查找 | 从父类开始查找方法 |
3 | 调用构造器 | 调用本类构造器,必须放在构造器的首行 | 调用父类构造器,必须放在子类构造器的首行 |
4 | 特殊 | 表示当前对象 | 子类中访问父类对象 |
方法重写
基本介绍
简单的说:方法覆盖(重写)就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的那个方法
方法重写使用事项注意细节
1.子类的方法的形参列表,方法名称,要和父类方法的形参列表,方法名称完全一样。
2.子类方法的返回类型和父类方法返回类型一样,或者是父类返回类型的子类比如 父类 返回类型是 Object,子类方法返回类型是String
3.子类方法不能缩小父类方法的访问权限 public >protected >默认>private
代码演示:
package idea.override_;
/**
* 演示重写的注意事项和使用细节
*/
public class override01 {
public static void main(String[] args) {
}
}
class Animal {
public void cry() {
System.out.println("动物在叫");
}
public Object hi() {
return null;
}
public Object ok() {
return null;
}
protected void eat() {
}
}
class Dog extends Animal {
//1.子类的方法的形参列表,方法名称,要和父类方法的形参列表,方法名称完全一样。
//怎么理解这句话
//1. 因为Dog 是 Animal子类
//2. Dog的 cry方法和 Animal的 cry定义形式一样(名称、返回类型、参数)
//3. 这时我们就说 Dog的cry方法,重写了Animal的cry方法
@Override
public void cry() {
System.out.println("小狗在叫");
}
//2.子类方法的返回类型和父类方法返回类型一样,或者是父类返回类型的子类比如 父类 返回类型是 Object,子类方法返回类型是String
//因为父类的hi()方法的返回类型是Object ,而子类的hi()方法返回类型是String ,因此这样也构成重写,因为Object是所以类的父类
@Override
public String hi() {
return null;
}
//注意如果子类的返回类型,如果不是父类的子类,那么就会报错
//看演示
// @Override
// public String ok() {//这样是错误的,因为String不是Object的子类
// return null;
// }
//3.子类方法不能缩小父类方法的访问权限 public >protected >默认>private
//父类中的方法访问修饰符是,protected 我们重写之后的方法,访问修饰符,只能是和父类一样,或者比父类的还要大
//举例
//这样是正确的,但是只能同时存在一个
@Override
public void eat() {
}
//
// @Override
// protected void eat() {
//
// }
//这样是错误的,因为缩小了,父类方法的访问权限
// @Override
// void eat() {
//
// }
// @Override
// private void eat() {
//
// }
}
重载和重写的区别
名称 | 发生范围 | 方法名 | 形参列表 | 返回类型 | 修饰符 |
---|---|---|---|---|---|
重载(OverLoad) | 本类 | 必须一样 | 类型个数,或者顺序至少一个不同 | 无需求 | 无需求 |
重写(Override) | 父子类 | 必须一样 | 相同 | 子类重写的方法返回的类型和父类返回的类型一致,或者是其子类 | 子类方法不能缩小父类方法的访问权限 |