• 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
    本文为原创文章,转载请标明出处
  • 相关阅读:
    Docker--Dockerfile引用及指令集的功能用法
    Docker容器的启动与停止
    Docker--删除容器实例和镜像
    CentOS安装Docker
    Docker运行简单的Demo
    VMware安装的Windows10下Docker的安装
    ASP.NET Core使用EPPlus操作Excel
    只有程序员才懂的幽默(转)
    iOS 简单代理(delegate)实现
    iOS设计模式——委托(delegate)
  • 原文地址:https://www.cnblogs.com/harden13/p/14526918.html
Copyright © 2020-2023  润新知