Java基础之继承

继承的格式

【修饰符】 class 父类 {
	...
}

【修饰符】 class 子类 extends 父类 {
	...
}

继承特点:成员变量

私有化(private)

  • 父类中的成员,无论是公有(public)还是私有(private),均会被子类继承。

  • 子类虽会继承父类私有(private)的成员,但子类不能对继承的私有成员直接进行访问,可通过继承的公有方法进行访问(setxxx&getxxx)。如图所示:

class Animal {
    // 定义name属性
	private String name; 
    // 定义age属性
    public int age;
	// 定义动物的吃东西方法
	public void eat() {
		System.out.println(age + "岁的" + name + "在吃东西");
	}
}
/*
 * 定义猫类Cat 继承 动物类Animal
 */
class Cat extends Animal {
	// 定义一个猫抓老鼠的方法catchMouse
	public void catchMouse() {
		System.out.println("抓老鼠");
	}
}

/*
 * 定义测试类
 */
public class ExtendDemo01 {
	public static void main(String[] args) {
        // 创建一个猫类对象
		Cat cat = new Cat();
      
        // 为该猫类对象的name属性进行赋值
		//t.name = "Tom";// 编译报错
      
      	// 为该猫类对象的age属性进行赋值
		t.age = 2;
        
        // 调用该猫的catchMouse()方法
		t.catchMouse();
		
      	// 调用该猫继承来的eat()方法
      	t.eat();
	}
}

成员变量不重名

如果子类父类中出现不重名的成员变量,这时的访问是没有影响的

成员变量重名

如果子类父类中出现重名的成员变量,这时的访问是有影响的

class Fu {
	// Fu中的成员变量。
	int num = 3;
}

class Zi extends Fu {
	// Zi中的成员变量
	int num = 4;
	public void show() {
		// 访问的num到底是子类还是父类?
		System.out.println("num = " + num);

	}
}
class ExtendsDemo03 {
	public static void main(String[] args) {
      	// 创建子类对象
		Zi z = new Zi(); 
      	// 调用子类中的show方法
		z.show(); 
	}
}
演示结果:
num = 4

子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用super 关键字,修饰父类成员变量,类似于之前学过的 this  

承接上例子类方法需要修改,代码如下:

class Zi extends Fu {
	// Zi中的成员变量
	int num = 6;
	public void show() {
		//访问父类中的num
		System.out.println("Fu num=" + super.num);
		//访问子类中的num
		System.out.println("Zi num=" + this.num);
	}
}
演示结果:
Fu num = 5
Zi num = 6

继承的特点二:成员方法

成员方法不重名

如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有对应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法

成员方法重名——重写(Override)

如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,叫做方法重写 (Override)。

class Fu {
	public void show() {
		System.out.println("Fu show");
	}
}
class Zi extends Fu {
	//子类重写了父类的show方法
	public void show() {
		System.out.println("Zi show");
	}
}
public class ExtendsDemo05{
	public static void main(String[] args) {
		Zi z = new Zi();
     	// 子类中有show方法,只执行重写后的show方法
		z.show();  // Zi show
	}
}

在父子类的继承关系当中,创建子类对象,访问成员方法的规则:
创建的对象是谁,就优先用谁,如果没有则向上找。

注意事项:
无论是成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类的。

重写(Override)
概念:在继承关系当中,方法的名称一样,参数列表也一样。

重写(Override):方法的名称一样,参数列表【也一样】。覆盖、覆写。
重载(Overload):方法的名称一样,参数列表【不一样】。

方法的覆盖重写特点:创建的是子类对象,则优先用子类方法。

方法覆盖重写的注意事项:见下面

  

重写的应用

子类可以根据需要,定义特定于自己的行为。既沿袭了父类的功能名称,又根据子类的需要重新实现父类方法,从而进行扩展增强。比如新的手机增加来电显示头像的功能,代码如下:

  

class Phone {
	public void sendMessage(){
		System.out.println("发短信");
	}
	public void call(){
		System.out.println("打电话");
	}
	public void showNum(){
		System.out.println("来电显示号码");
	}
}

//智能手机类
class NewPhone extends Phone {
	
	//重写父类的来电显示号码功能,并增加自己的显示姓名和图片功能
	public void showNum(){
		//调用父类已经存在的功能使用super
		super.showNum();
		//增加自己特有显示姓名和图片功能
		System.out.println("显示来电姓名");
		System.out.println("显示头像");
	}
}

public class ExtendsDemo06 {
	public static void main(String[] args) {
      	// 创建子类对象
      	NewPhone np = new NewPhone();
        
        // 调用父类继承而来的方法
        np.call();
      
      	// 调用子类重写的方法
      	np.showNum();

	}
}

注意事项

  1. 必须保证父子类之间方法的名称相同,参数列表也相同。 @Override:写在方法前面,用来检测是不是有效的正确覆盖重写。 这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。

  2. 子类方法的返回值类型必须【小于等于】父类方法的返回值类型(小于其实就是是它的子类)。 小扩展提示:java.lang.Object类是所有类的公共最高父类(祖宗类),java.lang.String就是Object的子类。

    注意:如果返回值类型是基本数据类型和void,那么必须是相同

  3. 子类方法的权限必须【大于等于】父类方法的权限修饰符。 小扩展提示:public > protected > 缺省 > private 备注:缺省不是汉字缺省,而是什么都不写,留空。

  4. 几种特殊的方法不能被重写

    • 静态方法不能被重写

    • 私有等在子类中不可见的方法不能被重写

    • final方法不能被重写

继承的特点三:构造方法

首先我们要回忆两个事情,构造方法的定义格式和作用。

  1. 构造方法的名字是与类名一致的。所以子类是无法继承父类构造方法的。

  2. 构造方法的作用是初始化成员变量的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个super() ,表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。代码如下:

class Fu {
  private int n;
  Fu(){
    System.out.println("Fu()");
  }
}
class Zi extends Fu {
  Zi(){
    // super(),调用父类构造方法
    super();
    System.out.println("Zi()");
  } 
}
public class ExtendsDemo07{
  public static void main (String args[]){
    Zi zi = new Zi();
  }
}
输出结果:
Fu()
Zi()

如果父类没有无参构造怎么办?

此时子类代码报错。

解决办法:在子类构造器中,用super(实参列表),显示调用父类的有参构造解决。

构造器的知识回顾

1、要创建一个类的实例对象,必须调用一个对象的构造器,来完成类的实例初始化过程。实例初始化过程就是为实例变量赋初始值的过程。
2,当一个对象被创建时候,构造方法用来初始化该对象,给对象的成员变量赋初始值。
3,无论你与否自定义构造方法,所有的类都有构造方法,因为Java自动提供了一个无参数构造方法,一旦自己定义了构造方法,Java自动提供的默认无参数构造方法就会失效。 

示例

public class Person {
	private String name;
	private int age;
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	//其他成员方法省略
}


public class Student extends Person{
	private int score;

	public Student(String name, int age) {
		super(name, age);
	}
	public Student(String name, int age, int score) {
		super(name, age);
		this.score = score;
	}
	
	//其他成员方法省略
}

super

父类空间优先于子类对象产生

在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身。目的在于子类对象中包含了其对应的父类空间,便可以包含其父类的成员,如果父类成员非private修饰,则子类可以随意使用父类成员。代码体现在子类的构造方法调用时,一定先调用父类的构造方法

public class Person {
	private String name;
	private int age;
	//其他代码省略
}
public class Student extends Person{
	private int score;
	//其他成员方法省略
}
public class Test{
    public static void main(String[] args){
    	Student stu = new Student();
    }
}

  

super和this的含义

  • super :代表父类的存储空间标识(可以理解为父亲的引用)。

    • 通过super找成员变量和成员方法时,直接从父类空间(包含父类的父类继承的)找

    • super()或super(实参列表)只能从直接父类找

    • 通过super只能访问父类在子类中可见的(非private,跨包还不能是缺省的)

  • this :代表当前对象的引用

    • 通过this找成员变量和成员方法时,先从当前类中找,没有的会往上找父类的。

    • 但是this()或this(实参列表)只会在本类中找

注意:super和this都不能出现在静态方法和静态代码块中,因为super和this都是存在与对象中的

super的用法

1、super.成员变量

在子类对象中访问父类空间的成员变量,即访问从父类继承的在子类中仍然可见的成员变量

1)子类没有与父类重名的成员变量  

public class Test{
    public static void main(String[] args){
        Son s = new Son();
        s.test();
    }
}
class Father{
    int a = 10;
}
class Son extends Father{
    public void test(){
        System.out.println(super.a);//10
        System.out.println(this.a);//10
        System.out.println(a);//10
    }
}
View Code

2)子类有与父类重名的成员变量

public class Test{
    public static void main(String[] args){
        Son s = new Son();
        s.test();
    }
}
class Father{
    int a = 10;
}
class Son extends Father{
    int a = 20;
    public void test(){
        System.out.println(super.a);//10
        System.out.println(this.a);//20
        System.out.println(a);//20
    }
}
View Code

3)方法有局部变量与成员变量重名

public class Test{
    public static void main(String[] args){
        Son s = new Son();
        s.test(30);
    }
}
class Father{
    int a = 10;
}
class Son extends Father{
    int a = 20;
    public void test(int a){
        System.out.println(super.a);//10
        System.out.println(this.a);//20
        System.out.println(a);//30
    }
}
View Code

2、super.成员方法

在子类对象中访问从父类继承的在子类中仍然可见的成员方法

1)子类没有重写方法  

public class Test{
    public static void main(String[] args){
        Son s = new Son();
        s.test();
    }
}
class Father{
    public void method(){
        System.out.println("aa");
    }
}
class Son extends Father{
    public void test(){
        method();//aa
        this.method();//aa
        super.method();//aa
    }
}
View Code

2)子类重写父类的方法

public class Test{
    public static void main(String[] args){
        Son s = new Son();
        s.test();
    }
}
class Father{
    public void method(){
        System.out.println("aa");
    }
}
class Son extends Father{
    public void method(){
        System.out.println("bb");
    }
    public void test(){
        method();//bb
        this.method();//bb
        super.method();//aa
    }
}
View Code

super()或super(实参列表)

this(...)    	--    本类的构造方法
super(...)   	--    父类的构造方法

子类的每个构造方法中均有默认的super(),调用父类的空参构造。手动调用父类构造会覆盖默认的super()。

super() 和 this() 都必须是在构造方法的第一行,所以不能同时出现。

  

final

1、修饰类

表示这个类不能被继承,没有子类

final class Eunuch{//太监类
	
}

2、修饰方法

表示这个方法不能被子类重写

class Father{
	public final void method(){
		System.out.println("father");
	}
}

3、声明常量

某个变量如果使用final修饰,那么它的值就不能被修改,即常量

final可以修饰成员变量(静态的类变量和非静态的实例变量)和局部变量

如果某个成员变量用final修饰后,没有set方法,并且必须有显式赋值语句,不能使用成员变量默认值

被final修饰的常量名称,一般都有书写规范,所有字母都大写

public class Test{
    public static void main(String[] args){
        final int MIN_SCORE = 0;
        final int MAX_SCORE = 100;
    }
}
class Chinese{
    public static final String COUNTRY = "中华人民共和国";    
    private final String BLOODTYPE = "A";//显示赋值
    private final String CARDID;//如果没有显示赋值,必须保证在
    private String name;
    public Chinese(String cardId, String name) {
        super();
        this.CARDID = cardId;
        this.name = name;
    }
    public Chinese() {
        super();
        CARDID = "000000000000000000";//必须在所有构造器中进行赋值
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    //final修饰的没有set方法
    public static String getCountry() {
        return COUNTRY;
    }
    public String getCardId() {
        return cardId;
    }
    public String getBloodType() {
        return bloodType;
    }
}
View Code

 

posted @ 2021-03-12 23:00  亚洲哈登  阅读(53)  评论(0编辑  收藏  举报