首页 > 编程语言 >Java体系中的继承

Java体系中的继承

时间:2024-09-04 18:24:46浏览次数:12  
标签:体系 Java 构造方法 继承 子类 Base println 父类 public

前言

#继承(Inheritance) 是面向对象编程(OOP)中的一个重要概念,它允许一个类(称为子类或派生类)可以从另一个类(称为父类、基类或超类)继承属性(数据)和方法(行为)。简单来说继承主要用于实现共性的抽取,达到代码的复用。

1 继承


1.1 什么是继承

Java中使用类对实体对象进行描述,而不同的事物间根据不同的业务场景可能存在一些特定联系。因此面向对象编程中,为我们提供了继承(inheritance)机制,它允许操作者在保持原有类的基础上进行扩展、增加新功能,这样产生的类称为派生类/子类。

1.2 为什么需要继承

我们发现很多事物间存在着联系,也就是所谓的共性,那么我们能否将这些共同的特性进行抽取,从而达到代码的复用呢?
拿猫和狗进行举例,猫和狗都是动物

//Dog.java
public class Dog {
	//成员变量
	public String name;
	int age;
	//成员方法
	public void eat() {
		System.out.println(this.name + "正在吃饭...");
	}
	public void sleep() {
		System.out.println(this.name + "正在睡觉...");
	}
	public void bark() {
		System.out.println(this.name + "正在汪汪叫...");
	}
	
}

//Cat.java
public class Cat {
	//成员变量
	public String name;
	int age;
	//成员方法
	public void eat() {
		System.out.println(this.name + "正在吃饭...");
	}
	public void sleep() {
		System.out.println(this.name + "正在睡觉...");
	}
	public void meow() {
		System.out.println(this.name + "正在喵喵叫...");
	}
	
}

从上面的两个Java文件中,我们可以发现猫和狗类中存在着相同的共性
在这里插入图片描述
面对这种情况,面向对象思想中提出了继承概念,用于共性的抽取,实现代码的复用
因此我们可以定义一个Animal类用于共性的抽取:
在这里插入图片描述
Dog和Cat都继承于Animal类,Animal类称为父类/基类/超类,Dog和Cat称为子类/派生类,继承之后子类可以复用父类中的成员,从而实现代码的复用。

1.3 继承的语法

在Java中表示类的继承关系需要借助extends关键字

修饰符 class 子类 extends 父类 {
	//.....
}

那么我们可以借助继承的语法将上述类组装起来:

//Animal.java
public class Animal {
	//成员变量
	public String name;
	int age;
	//成员方法
	public void eat() {
		System.out.println(this.name + "正在吃饭...");
	}
	public void sleep() {
		System.out.println(this.name + "正在睡觉...");
	}
	
}

//Dog.java
public class Dog extends Animal{
	public void bark() {
		System.out.println(this.name + "正在汪汪叫...");
	}
	
}

//Cat.java
public class Cat extends Animal{
	public void meow() {
		System.out.println(this.name + "正在喵喵叫...");
	}
	
}

在组装起来之后,我们可以通过在Test类中实例化相应类来进行代码的理解

//Test.java
public class Test {
	public static void main(String[] args) {
		Dog dog = new Dog();
		System.out.println(dog.name);
		System.out.println(dog.age);
		//我们发现dog类可以访问从Animal中继承来的name和age属性,

		dog.eat();
		dog.sleep();
		//dog类中也可以访问从Animal中继承下来的方法
	}
}

1.4 父类成员的访问

通过子类对象访问成员时:

  • 如果访问的成员变量子类中有,优先访问自己的成员变量。
  • 如果访问的成员变量子类中无,则访问父类继承下来的;如果父类中也没有定义,则编译报错
  • 如果访问的成员变量与父类中成员变量同名,则优先访问自己的
  • 通过子类对象访问父类与子类不同名方法时,优先在子类中找
  • 通过子类对象访问父类与子类同名方法时,如果子类和父类同名方法的参数列表不同(方法重载),根据传递的参数选择合适的方法访问,如果没有则报错
    总的来说,成员变量访问遵循就近原则,自己有优先访问自己的,如果没有则向父类中寻找。
//Base.java
public class Base {
	//成员变量
	public int a;
	public int b;
	public int c;
	
	//成员方法
	public void method() {
		System.out.println("Base中的method()");
	}
	public void methodA() {
		System.out.println("Base中的methodA()");
	}
	public void methodB() {
		System.out.println("Base中的methodB()");
	}
	
}

//Derived.java
public class Derived extends Base{
	//成员变量
	public int a;//与父类成员a同名,相同类型
	public char b;//与父类成员b同名,不同类型
	
	//成员方法
	public void methodA(int a) {
		System.out.println("Derived中的methodA()");
	}
	public void methodB() {
		System.out.println("Derived中的methodB()");
	}
	//在methodC()中探讨成员变量的继承问题
	public void methodC() {
		a = 10;//访问子类自己的a
		b = 100;//访问子类自己的b
		c = 1000;//子类中没有c,访问父类继承下来的c
	}
	//在methodD()中探讨成员变量的继承问题
	public void methodD() {
		method();//访问从父类继承的method()方法
		methodA();//没有传递参数,根据参数列表访问父类的
		methodA(10);//传递参数int,访问子类中的methodA()方法
		methodB();//直接访问则永远访问的是子类的methodB()方法
		methodC();//访问子类自己的methodC()方法
	}
}

在继承关系中,我们可以将子类对象中存在的成员方法和变量看成两部分构成,一部分是从父类继承来的,一部分是子类自己的:
在这里插入图片描述
#方法重写(Override) 当子类继承父类并且子类中定义了与父类同名、参数列表相同的方法时,子类的方法会覆盖(取代)父类中的方法。这意味着,通过子类对象调用这个方法时,会执行子类中的方法实现,而不会执行父类中的方法。

1.5 superthis关键字

通过上述演示,我们知道子类和父类中存在同名成员时,成员的访问中遵循着就近原则,那么当我们想访问父类中的同名成员时,应该怎么操作呢?

super关键字:在子类方法中访问父类成员
也就是说在上述的methodC()方法中,我们可以通过super.a来访问父类中的a;

public void methodC() {
	super.a = 10;//访问父类中的a
	a = 100;//访问子类中的a	
}

在methodD()方法中

public void methodD() {
	//如果想要在子类中访问重写的父类方法,则需要借助
	//`super`关键字
	methodB();//直接访问则永远访问的是子类的methodB()方法
	super.methodB();//访问父类的methodD();
}

1.5.1 再谈this关键字

  • this关键字是当前对象的引用,super相当于是子类对象从父类继承下来的成员的引用
  • 在非静态方法中,this一般用来对本类的方法和属性访问,super用来访问父类继承下来的方法和属性
  • 在构造方法中:this(...)用来调用本类的构造方法,super(...)用来调用父类的构造方法
  • 当父类存在无参的构造方法时,子类的构造方法中一定会存在super()的调用,用户没有写编译器也会隐式为你增加,但用户不写则没有this()

1.6子类构造方法和初始化

1.6.1 构造方法

子类对象中成员是由两部分组成的,父类继承下来的和子类新增的部分,父子父子,如字面意思,肯定是先有父再有子,因此在构造子类对象的时候,我们会==先调用父类的构造方法,将从父类继承下来的成员构造完整,然后再调用子类自己的构造方法==,将子类自己新增的成员初始化完整。

//Base.java
public class Base {
	public Base() {
		System.out.println("Base()");
	}
}

//Derived.java
public class Derived extends Base {
	public Derived() {
		//super();子类构造方法默认调用父类无参构造方法
		//用户没写时编译器隐式添加,且super()是子类构造第一条语句
		System.out.println("Derived()");
	}
}

//Main.java
public class Main {
	public static void main(String[] args) {
		Derived derived = new Derived();
	}
}

结果打印:
Base();
Derived();

注意:

  1. 父类显示定义无参或者默认无参构造方法时,子类构造方法第一行默认隐含Super();
  2. 当父类构造方法带有参数时,此时需要子类显示调用父类的构造方法,否则编译失败
  3. 在构造方法中,super(…)和this(…)都只能出现在第一行,所以在构造方法中不能同时存在
  4. 最后superthis关键字都依赖于对象,所以只能在类的非静态方法中直接使用

1.6.2 初始化

一般在类中我们存在着几个重要的代码快:实例代码块和静态代码块

//Base.java
public class Base {
	//被static修饰的代码快叫静态代码块
	static {
		System.out.println("Base静态代码块执行了");
	}
	//没有被修饰的代码快叫实例代码块代码块
	{
		System.out.println("Base实例代码块执行了");
	}
	public Base() {
		System.out.println("Base()构造方法执行了");
	}
}

//Derived.java
public class Derived extends Base {
	static {
		System.out.println("Derived静态代码块执行了");
	}
	//.....
	{
		System.out.println("Derived实例代码块执行了");
	}
	public Derived() {
		//super();子类构造方法默认调用父类无参构造方法
		//用户没写时编译器隐式添加,且super()是子类构造第一条语句
		System.out.println("Derived()构造方法执行了");
	}
}

//Main.java
public class Main {
	public static void main(String[] args) {
		//代码段1
		//Base base1 = new Base();
		//System.out.println("= = = = = = = = = =");
		//Base base2 = new Base(); 
		
		

		//代码段2
		//Derived derived1 = new Derived();
		//System.out.println("= = = = = = = = = =");
		//Derived derived2 = new Derived();
		
	}
}

执行结果:

执行代码块1
Base静态代码块执行了
Base实例代码块执行了
Base()构造方法执行了
= = = = = = = = = =
Base实例代码块执行了
Base()构造方法执行了

观察发现:

  1. 静态代码块先执行,且只在类加载阶段执行
  2. 当有对象创建时,才会执行实例代码块,最后执行构造方法

执行代码块2
Derived静态代码块执行了
Derived实例代码块执行了
Derived()构造方法执行了
= = = = = = = = = =
Derived实例代码块执行了
Derived()构造方法执行了

通过分析执行结果,我们发现:

  1. 父类静态代码块优于子类静态代码块执行,且最早执行
  2. 父类实例代码块和父类构造方法紧接着执行
  3. 子类实例化代码块和子类构造方法再紧接着执行
  4. 静态代码块只在类加载的时候执行,在第二次实例子类对象时,父类和子类的静态代码块将不在执行

#projected关键字 为了进一步实现封装特性,Java中引入了访问权限修饰符,限定:类或者类中成员能否在类外或者其他包中被访问。projected关键字修饰的权限只能在同一个包下或者不同包的子类中访问。

标签:体系,Java,构造方法,继承,子类,Base,println,父类,public
From: https://blog.csdn.net/2302_79249715/article/details/141892043

相关文章

  • 基于java+springboot+vue的美发管理系统
    ......
  • java中的锁
    关键字:synchronized介绍synchronized是Java语言中的一个关键字,用于实现线程同步,以确保在多线程环境下对共享资源的访问是安全且一致的。它通过提供一种互斥机制来防止多个线程同时执行特定的代码区域,从而避免了数据不一致性和其他并发问题。以下是关于synchronized的一些关......
  • JavaWeb
    JavaWeb1.Servlet<?xmlversion="1.0"encoding="UTF-8"?><web-appxmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="......
  • 关于Java链表的一些操作以及力扣原题刷刷刷——反转链表、删除链表的倒数第N个节点
    1、反转链表1.1环境准备,可以自己先尝试实现/***@AuthorMiku*@Date2024/09/0209:54*@DescriptionTODO*@Version1.0*/publicclassSolution{staticclassListNode{intval;ListNodenext;ListNode(intval){......
  • 探秘JavaScript深度领域:精通面向对象编程、虚拟DOM等核心技术
    JaScript作为前端开发的核心技术之一,凭借其强大的灵活性和广泛的应用场景,吸引了大量开发者深入学习。在探秘JaScript的深度领域时,面向对象编程和虚拟DOM等核心技术无疑是两个重要的学习方向。面向对象编程(OOP)在JaScript中扮演着重要角色。虽然JaScript是一种基于原型的语言,而非传......
  • 深入理解JavaScript类与对象:揭秘类字段和静态属性的妙用,js静态属性和实例属性
    在深入理解JaScript类与对象的过程中,类字段和静态属性是两个关键的概念,掌握它们的用法可以让你在实际开发中更加得心应手。虽然JaScript在ES6之前并没有类的概念,但通过ES6及以后的版本,引入了类语法糖,使得我们能够更直观地定义和使用类。类字段是指在类中直接定义的属性,而不是在构......
  • java JRMP学习
    JavaJRMP反序化RMI依赖的通信协议为JRMP(JavaRemoteMessageProtocol,Java远程消息交换协议),该协议为Java定制,基于TCP/IP之上,RMI协议之下,当需要进行RMI远程方法调用通信的时候要求服务端与客户端都为Java编写。、这个协议就像HTTP协议一样,规定了客户端和服务端通信要满足的......
  • 新修订的《中华人民共和国保守国家秘密法》进步完善了责任追究体系,在法律责任中增加“
    新修订的《中华人民共和国保守国家秘密法》进步完善了责任追究体系,在法律责任中增加“()”的规定,将行为人因从事违法行为而获得的经济利益强制收归国有,为追究行为人因违反保密法而非法获利的法律责任提供了依据。查看全部完整试题答案A.罚款B.加重处罚C.没收违法所得D.拘留......
  • java常用关键字
    类别关键字说明访问控制private私有的protected受保护的public公共的default默认类、方法和变量修饰符abstract声明抽象class类extends扩充、继承final最终值、不可改变的implements实现(接口)interface接口native本地、原......
  • java 二次反序列化
    java二次反序列化SignedObject该类是java.security下一个用于创建真实运行时对象的类,更具体地说,SignedObject包含另一个Serializable对象。先看其构造函数方法。看到参数接受一个可序列化的对象,然后又进行了一次序列化,继续看到该类的getObject方法(这是个getter方法......