Java:继承

继承
概述

多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
格式:

class 子类名 extends 父类名{}
//例:
/*
猫和狗都有进食、奔跑的能力,也都有名称和年龄
对于大部分动物来说,进食和奔跑是他们共有的功能,名称和年龄是他们共有的属性
对于这些共有内容我们可以将其向上抽取形成一个新的类(Animal类),让Dog类和Cat类继承Animal类
这些类就获取了Animal类的成员,不用在每个类中都写一遍,这样做提高了代码的复用性。
在创建Dog类和Cat类对象时,可以使用Animal中的成员
具体代码如下:
*/
class Animal {
    String name;
    int age;
    //进食方法
    public void eat()
    {
        System.out.println("eat...");
    }
    //奔跑方法
    public void run()
    {
        System.out.println("run...");
    }
}
class Dog extends Animal{
    //看门方法
    public void guardEntrance()
    {
        System.out.println("guard entrance...");
    }
}
class Cat extends Animal{
    //抓老鼠方法
    public void catchMouse()
    {
        System.out.println("catch mouse...");
    }
}
/*
需要注意的是,Dog类和Cat类也有其特有的成员
比如:狗会看门,猫会抓老鼠
对于这些特有成员我们不能将其向上抽取,更不能为了继承部分功能而继承
*/

继承的优点:提高了代码的复用性和维护性,让类与类之间产生了关系,是多态的前提
继承的弊端:类的耦合性增强了

开发的原则:高内聚,低耦合
耦合:类与类的关系
内聚:一个类独立完成某件事的能力
即要尽量加强一个类独立完成功能的能力,降低与其他类的关系

继承体系
Java只支持单继承,不支持多继承。即一个类的父类只有一个,但一个类可以有多个子类
多继承存在安全隐患:当多个父类中定义了相同功能,但功能内容不同时,子类无法确定运行哪一个
但Java保留了这种机制,用多实现这种表现形式来完成。
Java支持多层继承,这是Java的继承体系

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

在具体调用时,要创建最子类的对象

  • 有可能父类不能创建对象。
  • 创建子类对象可以使用更多的功能,包括父类的也包括自己特有的。

继承的注意事项

  1. 子类只能继承父类所有非私有的成员
  2. 子类不能继承父类的构造方法,但是可以通过super关键字去访问父类的构造方法
  3. 不要为了部分功能而去继承

继承思想:将共性内容向上抽取封装成一个新的类,将这个类作为父类
继承是一个“is a”的关系,即子类是父类中的一员,比如猫和狗是动物

继承中成员变量的关系
当子类中的成员变量和父类中的成员变量名称一样时,访问顺序采取就近原则
例:

class Cat extends Animal{
    int age=20;
    public void showAge(int age)
    {
        System.out.println(age);
    }
}
public class Test {
    public static void main(String[] args) {
        Cat cat=new Cat();
        cat.showAge(50);
    }
}
/*
运行结果:
50
访问变量的查找顺序为:
showAge方法-->Cat类中-->Animal类中
会先在子类的的方法中找,找到就使用
没有的话,在子类的成员变量中寻找,找到就使用
还是没有,在父类的成员变量中寻找,找到就使用
如果父类中没有,就会报错
*/

Object类
Object类是层次结构的根类,每个类都使⽤Object类作为超类
该类中定义的是所有对象都具备的功能
所有类如果没有表明继承什么类,那么会默认在类名后加上extends Object

class A extends Object	//extends Object是不显示出来的
{
}
子父类出现后,类成员的特点
super关键字

super:用于子类局部范围访问父类成员变量和方法
super和this类似
this代表的是本类对象的引用
super代表的是父类对象的引用

子父类变量的特点

内存中的加载方式

class Fu{
	int num;
	public void test(){}
}
class Zi{
	int num;
	public void method(){}
}
class Demo
{
	 public static void main(String[] args) {
	 	Zi z=new Zi();
	 }
}
  1. 当执行new Zi()时,会先加载Fu.class文件,然后再加载Zi.class文件。
  2. 在方法区中的一个空间存储父类的方法及静态变量,另一个空间存储子类的方法及静态变量
  3. 在堆内存中开辟空间存储该对象,并给这个空间分配一个地址值。
  4. 在空间中分配两个属性空间,一个是父类的空间,一个是子类的空间,两个空间里都有num变量,初始化值为0
  5. 将这个地址值赋值给栈内存中的变量z,z指向这个对象。
    在这里插入图片描述
子父类中变量的特点
/*
我们知道我们可以用this来区分同名的成员变量和局部变量
那我们同样可以用super来区分同名的父类成员变量、子类成员变量和局部变量
我们再回到上一个问题
如何在showAge方法中输出父类中的age和子类中的age
如下所示:
*/
class Animal {
	int age=10;
}
class Cat extends Animal{
    int age=20;
    public void showAge(int age)
    {
        System.out.println(age);		//50
        System.out.println(this.age);	//20
        System.out.println(super.age);	//10
    }
}
public class Test {
    public static void main(String[] args) {
        Cat cat=new Cat();
        cat.showAge(50);
    }
}
子父类中成员函数的特点

用super调用父类方法

class Animal {
    //奔跑方法
    public void run()
    {
        System.out.println("run...");
    }
}
class Cat extends Animal{
    //抓老鼠方法
    public void catchMouse()
    {
    	//在抓老鼠方法中调用父类中的奔跑方法,代表猫在抓老鼠的过程中会奔跑
    	super.run();			
        System.out.println("catch mouse...");
    }
}

重写(覆盖)

class Fu
{
	void show()
	{
		System.out.println(“fu show”);
	}
}
class Zi extends Fu
{
	@override
	void show()
	{
		System.out.println(“zi show”);
	}
}
class ExtendsDemo
{
	public static void main(String[] args)
	{
		Zi z=new Zi();
		z.show();        
	}
}
//我们可以用一个标签@override来检测该方法是否是重写,如果不是重写会报错
/*
运行结果:
zi show
*/

子类和父类中有同名方法时,当子类对象调用该方法时,会执行子类中的方法,这种情况叫做重写(覆盖)
作用:当⼦类继承⽗类,沿袭⽗类的功能到⼦类中,但是⼦类虽具备该功能,当功能的内容与⽗类不⼀致,这时没有必 要定义新的功能,⽽是使⽤覆盖特性,保留⽗类的功能定义,并重写功能内容。
即当对⼀个功能进⾏更新升级时,不⽤去改动源代码,直接⽤继承去覆盖之前的功能

class Phone {
    public void show()
    {
        System.out.println("号码");
    }    
}
class Phone2 extends Phone{
    public void show()
    {
        super.show();
        System.out.println("姓名");
        System.out.println("头像");
    }
}
/*
我们开始有一个Phone类,该类中的show方法可以显示号码
过了一段时间我们对手机进行升级,出现一个类Phone2继承Phone类,代表该手机的2.0版本
子类中的show方法中,我们不仅可以显示号码,还可以显示姓名和头像
我们无需将父类中show方法中显示号码的代码再写一遍,直接用super.show();调用父类中的show方法
*/

注意事项:

  1. 子类覆盖父类,必须保证子类权限大于或等于父类权限,才可以覆盖,否则编译失败。
  2. 静态只能覆盖静态(其实静态方法不能算作重写,因为静态属于类)
  3. 当父类的方法被private修饰时,子类无法重写。
    因为私有方法只在本类中使用,子类都没有继承私有方法,如何去重写

我们要区别方法的重载和重写(覆盖)
重载:发生在一个类中的同名方法间,方法的方法名相同但是参数列表不同,与返回值类型无关
重写:发生在子父类中的同名方法间,子父类方法要一样,把包括返回值类型,子父类中不允许存在返回值类型不同的同名方法

子父类中构造方法的特点
class Animal {
    String name;
    int age;
    public Animal() {
    	System.out.println("父类无参构造方法");
    }
}
class Cat extends Animal{
	public Cat(){
		System.out.println("子类无参构造方法");
	}
}
/*
运行结果:
父类无参构造方法
子类无参构造方法
子类中所有的构造方法中第一行都有一条隐式语句:super();
即访问父类中空参数的构造方法
因为子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,要先完成父类数据的初始化。
*/
//父类没有无参构造方法,要手动让子类通过super去调用父类其他的带参的构造方法,否则会报错
class Animal {
    String name;
    int age;
    public Animal(int age) {
    	System.out.println("父类无参构造方法");
    }
}
class Cat extends Animal{
	public Cat(){
		super(age);
		System.out.println("子类无参构造方法");
	}
}

通过this调用本类其他构造方法时

class Animal {
    String name;
    int age;
    public Animal(int age) {
    	System.out.println("父类有参构造方法");
    }
}
class Cat extends Animal{
	public Cat(){
		super(5);
		System.out.println("子类无参构造方法");
	}
	public Cat(int age){
		this();
		System.out.println("子类有参构造方法");
	}
}
/*
当子类构造方法中出现this();即通过this调用本类其他构造方法时,该构造方法第一行没有super();
因为super(…)或者this(….)必须出现在第一条语句上,不会同时存在
注意:必须有一个子类构造方法调用父类构造方法!
*/
final关键字

final(最终)关键字,是一个修饰符
可以修饰类、函数、变量

  • 被final修饰的类不能被继承
    继承打破了封装,因为被继承的类可以被访问被覆盖,用final修饰可以让一些类不被继承
  • 被final修饰的函数不能被覆盖
    一个类中,一部分方法可能涉及到底层虚拟机,用final修饰可以防止被覆盖,且该类还可被继承
  • 被final修饰的变量是一个常量,只能赋值⼀次,既可以修饰成员变量,也可以修饰局部变量
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值