zl程序教程

您现在的位置是:首页 >  后端

当前栏目

面向对象的三大特征-继承

继承 面向对象 三大 特征
2023-06-13 09:12:13 时间

1、继承概述

1.1、什么是继承

继承是面向对象的核心特性,是面向对象的学习重点。同时继承是代码复用的重要方式,可以表示类与类之间的关系,是所有面向对象语言不可缺少的组成部分。

1.2、继承由来

1.2.1、子类与父类

当一个类的属性与行为均与现有类相似,属于现有类的一种时,这一个类可以定义为现有类的子类。

或者换成相反的角度来看,如果多个类具有相同的属性和行为,我们可以抽取出共性的内容定义父类,这时再创建相似的类时只要继承父类即可。

1.2.2、子类与父类关系

子类拥有父类的所有属性与方法,无需重新定义。并且可以直接使用非私有的父类成员。

从类与类之间的设计关系来看,子类必须属于父类的一种时,才会继承。

我们在完成一个庞大项目体系的时候,都是将共性的内容抽取出,后续构建过程是从各种父类“向外”扩散的。

2、继承定义及使用

2.1、继承定义

格式:

class 子类 extends 父类{
		//父类的非私有方法与属性均继承过来
}

案例:

class Person{
		private String name;

		public void eat(){
			System.out.println(“吃饭”);
		}
		//get/set方法
}

子类继承父类的定义:

class ChinesePerson extends Person{}

2.2、继承使用

继承关系的产生通常是为了定义出功能更为具体、更为强大的子类。所以,定义子类后,一般创建子类对象使用。子类可以直接使用父类非私有的成员变量与成员方法(注:如果成员变量没有使用private修饰,则子类也可直接访问。)

class PersonDemo{
		public static void main(String[] args) {
		ChinesePerson  c = new ChinesePerson();
		c.setName("张大力");
		String name = c.getName();
		System.out.println(name);//打印结果为张大力
		c.eat();  //打印结果吃饭
}

3、继承关系

动物类可以有姓名、年龄的成员变量,可以有吃饭、睡觉的方法。

所有猫科与犬科均有动物的成员变量与成员方法,且猫科与犬科均属于动物,所以猫科与犬科均可以继承动物类。

猫科可以在动物的基础上再添加抓老鼠的方法

犬科可以在动物的基础上再添加看门的方法

犬科与猫科仍可以继续出现子类,如波斯猫、巴厘猫、沙皮狗、斑点狗等,而其子类仍可以再出现该品种的特性。

案例:

/*
 * Animal的类
 * 属性
 *  name
  *  age
 * 行为
 *  吃
 *  睡
*/
public class Animal {
    //成员变量
    private String name;
    private int age;
    //吃
    public  void eat(){
        System.out.println("吃");
    }
    //睡
    public void sleep(){
        System.out.println("睡");
    }
    //-----------get/set-------------------
    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;
    }
}
/*
 *定义一个猫类
 * 属性
 *  name  
 *  age
 *  kind
 * 行为
 *  吃
 *  睡
 *  抓老鼠
 */
public class Cat extends Animal {
    private String kind;
    @Override
    public void eat(){
	  System.out.println("猫吃鱼");
    }

    //猫特有的功能  抓老鼠
    public void catchMouse(){
        System.out.println("抓耗子");
    }

    public String getKind() {
        return kind;
    }
    public void setKind(String kind) {
        this.kind = kind;
    }
}
/*
 *定义一个狗类
 * 属性
 *  name  
 *  age
 *  kind
 * 行为
 *  吃
 *  睡
 *  看门
 */
public class Dog extends Animal {
    private String kind;

    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }

    //狗特有功能  看门
    public void lookDoor() {
        System.out.println("看门");
    }

    public String getKind() {
        return kind;
    }

    public void setKind(String kind) {
        this.kind = kind;
    }
}
/*
 * 自定义类型 家
 * 地址
 * 行为
 * 在家吃饭
 */
public class Home {
    private String address;

    //动物在家吃饭
    //在所有使用父类类型的地方均可以传入其子类对象。
    public void eatAtHome(Animal a) {
        //调用Animal的eat方法
        a.eat();
    }

    //狗在在家吃饭
    public void eatAtHome(Dog dog) {
        System.out.println("狗在家吃了");
        //调用狗的eat方法
        dog.eat();
    }

    //猫在家吃饭
    public void eatAtHome(Cat cat) {
        System.out.println("猫在家吃了");
        //调用猫的eat方法
        cat.eat();
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}
/**
 * 测试家类
*/
public class Test {
    public static void main(String[] args) {
        //  创建Home对象
        Home home = new Home();
        Animal a = new Animal();
        home.eatAtHome(a);
        //在所有使用父类类型的地方均可以传入其子类对象。
        Dog d = new Dog();
        home.eatAtHome(d);
        Cat c = new Cat();
        home.eatAtHome(c);
    }
}

运行结果:

4、继承注意事项

4.1、Java只支持单继承,不支持多继承。即只能有一个父类。

//单继承
class A extends B{}
class B extends C{}

//多继承,错误
class A extends B{}
class A extends C{}

4.2、父类可以继续有父类。

class A extends B{}
class B extends C{}

4.3、所有类均有父类,只有Object类没有父类。

class A{}
//相当于
class A extends Object{}//所有类都继承了Object类,继承Object类可以省略

4.4、在所有使用父类类型的地方均可以传入其子类对象。

class B{}
class A extends B{}
//测试类
class C{
  public void c(B b){}
  public static void main(String args[]){
    new C().c(new A());
  }
}

5、方法重写

5.1、什么是方法重写

当子类继承父类后,拥有了父类的成员并可以直接调用父类非私有方法。如果子类认为父类提供的方法不够强大,子类可以按照子类自身的逻辑重新定义继承过来的父类方法,这个重新定义一个方法的过程叫做方法重写。(注:在学习完多态和抽象类后我们会对方法重写有更深的理解)

5.2、方法重写格式

子类中定义与父类一样的方法便将父类的方法重写了。此时,当创建子类对象,调用方法时,会调用子类重写后的方法。

案例1:

父类

public class Person{
    private String name;
    public void eat(){
        System.out.println("吃饭");
    }
    //get/set

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

子类

public class ChinesePerson extends Person{
    @Override  //@Override是用于强制规定当前定义的方法一定为重写的方法
    public void eat() {
        System.out.println("按照中国的习惯,使用筷子吃");
    }
}

子类使用

public class PersonDemo{
    public static void main(String[] args) {
        ChinesePerson  c = new ChinesePerson();
        c.setName("张大力"); //父类继承方法直接调用
        String name = c.getName(); //父类继承方法直接调用
        System.out.println(name); //打印结果为张大力
        c.eat(); //方法重写后调用的为重写后的方法
        //打印结果:按照中国的习惯,使用筷子吃
    }
}

运行结果:

案例2:

public class Person{
    private String name;
    String address;//增加了一个地址成员,可初始化
    public void eat(){
        System.out.println("吃饭");
    }
    //get/set

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
/*
	 * 定义类型  学生类
	 *
	 * 姓名  年龄
	 *
	 * 继承
	 *   概念1   
 *   
 *   方法重写
 *    子类继承父类后,可以直接使用父类的非私有成员,但是如果觉得父类的成员方法不够强大,子类可以按照自身的逻辑
 *    将继承过来的父类方法,进行重写(方法重写,方法复写,方法覆盖)
 *   
 *   可以使用@Override来验证你的方法是不是重写方法。
 */
public class Student extends Person{
    private String number;

    public void method(){
        System.out.println(address);
        System.out.println(getName());
    }

    //重写父类eat方法
    @Override
    public void eat(){
        System.out.println("学生吃学生套餐");
    }
    public String getNumber() {
        return number;
    }
    public void setNumber(String number) {
        this.number = number;
    }
} 
/*
 * 测试继承后的Studnet
 */
public class StudentDemo {
    public static void main(String[] args) {
        //创建Studnet对象
        Student s = new Student();

        s.setName("柳柳");
        s.setNumber("0900112");
        s.eat();

        String name = s.getName();
        System.out.println(name);
        System.out.println(s.getNumber());
        System.out.println("-----------------");
        //子类调用自己特有的方法
        s.method();
    }
}

运行结果:

5.3、方法重写规则

子类重写方法时,在声明前加@Override可检测该方法是否为重写的方法

访问权限相同或子类方法访问权限更大(访问权限顺序public>默认)

class Fu{
  void show(){}
  public void method(){}
}
class Zi extends Fu{
	public void show(){}  //编译运行没问题
  void method(){}      //编译错误
}

方法名称必须相同

参数列表必须相同

返回值为基本类型时必须相同

返回值为引用类型时相同或子类小(了解)

案例:

/*
 * 方法重写的注意事项
 *  子类重写方法时,在声明前加@Override可检测该方法是否为重写的方法
 *  访问权限相同或子类方法访问权限更大(访问权限顺序public>默认)
 *  方法名称必须相同
 *  参数列表必须相同
 *  返回值为基本类型时必须相同
 *  返回值为引用类型时相同或子类小(了解)
 */
public class Fu {
 public void method(){
	 System.out.println(" 父类方法");
 }   
 public int sum(){
	 return 0;
 }
   
 public Person get(){
	 return null;
 }
} 
public class Zi extends Fu{ 
	//访问权限相同或子类方法访问权限更大(访问权限顺序public>默认)
	@Override
	 public void method(){
		System.out.println("子类方法");
	} 
	//返回值为基本类型时必须相同
	@Override
	public int sum(){
		return 100;
	}
	//返回值为引用类型时相同或子类小(了解)
	@Override
	public Student get(){
		return null;
	}
}