目录
一、super的作用
二、基本语法
第一条
第二条
第三条
三、super便利/细节
第一条
第二条
第一种:直接调用
第二种:this
第三种:super
第三条
四、this和super的比较
一、super的作用
super 代表父类的引用, 用于访问父类的属性、 方法、 构造器
二、基本语法
第一条
访问父类的属性,但不能访问父类的private属性
例子:
父类
package com.hspedu.super_;
public class A {
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
//访问父类的属性,但不能访问父类的private属性
public void test100(){
}
protected void test200(){
}
void test300(){
}
private void test400(){
}
}
子类
package com.hspedu.super_;
public class B extends A{
//访问父类的属性,但不能访问父类的private属性
public void hi() {
System.out.println(super.n1 + " " + super.n2 + " " + super.n3 + " " + super.n4);
}
}
在IDEA中super.n4会变成红色报错
'n4' has private access in 'com.hspedu.super_.A'
原因:n4在父类A类中是private属性
第二条
访问父类的方法,但不能访问父类的private方法
同属性一样,private方法也会报错
'test400()' has private access in 'com.hspedu.super_.A'
第三条
访问父类的构造器,super(参数列表):只能放在构造器的第一句,只能出现第一句
在父类中创建三个构造器
package com.hspedu.super_;
public class A {
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) {
}
//访问父类的属性,但不能访问父类的private属性
public void test100(){
}
protected void test200(){
}
void test300(){
}
private void test400(){
}
}
在子类的构造器中访问(只能在构造器中访问,普通方法不能访问),因为必须在第一句,所以只能用一次
报错原因
三个只能用一个
三、super便利/细节
第一条
调用父类的构造器的好处 (分工明确,父类属性由父类初始化,子类的属性由子类初始化)
第二条
当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员必须使用super
如果没有重名,super、this、直接访问是一样的效果(举例说明)
例子:在父类-A类中创建cal方法
public void cal(){
System.out.println("A类的cal()方法");
}
在子类-B类的sum方法中访问
此时有三种方法可以直接访问
第一种:直接调用
public void sum() {
System.out.println("B类的sum()");
cal();
}
访问顺序是:
1)先找本类,如果有,则调用(本类不受访问修饰符限制) 2)如果没有,则找父类,如果有且可以调用则调用 3)如果父类没有,则继续找父类的父类,规则同上,直到Object类 tips:如果查找方法的过程中找到了,但是不能访问,则报private access 如果直到Object类都没找到,则提示方法不存在(无法解析)
创建新对象测试
package com.hspedu.super_;
public class Super01 {
public static void main(String[] args) {
B b = new B();
b.sum();
}
}
运行结果
如果把A类中的cal方法改成private方法,B类会报错,并给出以下提示
如果把A类中的cal方法注销,B类会提示:Cannot resolve method 'cal' in 'B' ,无法解析“B”中的方法“cal”(找不到这个方法)
第二种:this
this.cal()的逻辑完全等价于直接访问
第三种:super
super.cal();直接查找父类,除此之外,其他逻辑同直接调用和this
演示:在子类-B类内创建一个cal()方法
package com.hspedu.super_;
public class B extends A{
//访问父类的属性,但不能访问父类的private属性
public void hi() {
System.out.println(super.n1 + " " + super.n2 + " " + super.n3);
}
//访问父类的方法,但不能访问父类的private方法
public void hello() {
super.test100();
super.test200();
super.test300();
//super.test400();
}
//访问父类的构造器,super(参数列表):只能放在构造器的第一句,只能出现第一句
public void ok(){
//super();//只能在构造器中使用
}
public B() {
//super();
//super("jack");
super("jack",34);
}
public void cal() {
System.out.println("B类的cal()方法");
}
public void sum() {
System.out.println("B类的sum()");
super.cal();//直接查找父类,除此之外,其他逻辑同直接调用和this
}
}
package com.hspedu.super_;
public class Super01 {
public static void main(String[] args) {
B b = new B();
b.sum();
}
}
结果:不会调用子类-B类的cal()方法
如果是直接调用和this则会调用B类的cal
package com.hspedu.super_;
public class B extends A{
//访问父类的属性,但不能访问父类的private属性
public void hi() {
System.out.println(super.n1 + " " + super.n2 + " " + super.n3);
}
//访问父类的方法,但不能访问父类的private方法
public void hello() {
super.test100();
super.test200();
super.test300();
//super.test400();
}
//访问父类的构造器,super(参数列表):只能放在构造器的第一句,只能出现第一句
public void ok(){
//super();//只能在构造器中使用
}
public B() {
//super();
//super("jack");
super("jack",34);
}
public void cal() {
System.out.println("B类的cal()方法");
}
public void sum() {
System.out.println("B类的sum()");
cal();
this.cal();
}
运行结果
在访问属性的时候,规则同上,举例说明:在子类-B类中新建属性n1
子类:
package com.hspedu.super_;
public class B extends A{
public int n1 = 888;
//访问父类的属性,但不能访问父类的private属性
public void hi() {
System.out.println(super.n1 + " " + super.n2 + " " + super.n3);
}
//访问父类的方法,但不能访问父类的private方法
public void hello() {
super.test100();
super.test200();
super.test300();
//super.test400();
}
//访问父类的构造器,super(参数列表):只能放在构造器的第一句,只能出现第一句
public void ok(){
//super();//只能在构造器中使用
}
public B() {
//super();
//super("jack");
super("jack",34);
}
public void cal() {
System.out.println("B类的cal()方法");
}
public void sum() {
System.out.println("B类的sum()");
super.cal();//直接查找父类,除此之外,其他逻辑同直接调用和this
System.out.println(n1);
System.out.println(this.n1);
System.out.println(super.n1);
}
}
父类-A类中也有属性n1
package com.hspedu.super_;
public class A {
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) {
}
//访问父类的属性,但不能访问父类的private属性
public void test100(){
}
protected void test200(){
}
void test300(){
}
private void test400(){
}
public void cal(){
System.out.println("A类的cal()方法");
}
}
运行
package com.hspedu.super_;
public class Super01 {
public static void main(String[] args) {
B b = new B();
b.sum();
}
}
结果:cal()和this.cal()访问的都是本类B类的属性n1,即999
第三条
如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类(上级类)中都有同名的成员,使用super访问遵循就近原则。A->B->C(父类—>爷爷类—>曾祖父类—>......—>Object类),当然也需要遵守访问权限的相关规则(四个访问修饰符)
创建一个新类Base
package com.hspedu.super_;
public class Base {
public int n1 = 999;
public int age = 111;
public void eat(){
System.out.println("Base类中的eat()方法...");
}
public void cal() {
System.out.println("Base类的cal()方法...");
}
}
并且让A类继承Base类
package com.hspedu.super_;
public class A extends Base{
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
public int getN1() {
return n1;
}
//默认无参构造器
public A() {
}
//一个参数的有参构造器
public A(String name) {
}
//两个参数的有参构造器
public A(String name, int age) {
}
//访问父类的属性,但不能访问父类的private属性
public void test100(){
}
protected void test200(){
}
void test300(){
}
private void test400(){
}
public void cal(){
System.out.println("A类的cal()方法");
}
}
在子类B类中新建方法test
package com.hspedu.super_;
public class B extends A{
public int n1 = 888;
public void test() {
//就近原则
System.out.println("super.n1=" + super.n1);
}
}
运行:根据就近原则,此时输出的是A类中的100
package com.hspedu.super_;
public class Super01 {
public static void main(String[] args) {
B b = new B();
b.test();
}
}
如果A类中没有n1,则会输出Base类中的n1,即999
调用方法的规则同访问属性的规则一样
会调用A类的cal方法
如果A类没有,则调用Base类
四、this和super的比较