生活中我们提及继承,不难想到继承家业、继承财产等关键词,而且往往它们都是发生在父与子之间的。那么在Java中,什么是继承呢?
当下是一个讲究万物互联的时代,跨学科的思维显得愈发重要,计算机语言也是由程序员开发创造出来的,而程序员也是人,人的思维必然立足于生活,所以在Java语言的一些语法规则中,也必然会体现一些生活中的逻辑(也是我们常说的约定俗成)。
在学习java的过程中,我们往往可以从生活中的现象汲取灵感,从常见的一般化到特殊化,寻找Java语言的异同之处,理解更加深刻与通透。
目录
一、从一张图中走进继承
1.逆向
假定我是一个大二的学生,我现在被归为大二类中。
↓( √ ) ↓( × )
我同样也可以被归为在大学生类中 我不能被归于大一类中
↓( √ ) ↓( × )
我还可以被归在学生类中 我更不能被归为中学生/小学生类中
即我可以说我是一名大二学生,也可以说我是一名大学生,还可以说我是一名学生。
但是我不能说我是一名大一学生或者中学生了。
2.正向
假设现在已知的信息只有我是一名学生,那么我就可以随便胡诌我是大学生、中学生或者小学生也好,更不用说我是大一学生还是大二学生了。
这里不妨和数学中的集合思维进行结合,但就不做过多阐述了,逐渐养成一个将学过的知识结合起来的习惯(我习惯称之为mix+思维)。
3.结论
1)上级类是下面所有类的父类(大学生类是大一类、大二类的父类,在例子中学生类为最高级)
2)语法上:只允许一个子类直系继承一个父类
→ 理解:一个父亲可以有多个孩子,但一个孩子只能有一个父亲,但同时这个孩子可能还有爷爷。
3)一个对象可以拥有多重身份,且拥有的身份之间需要有继承关系
→ 理解:我可以是一名大二学生的身份,我也可以是一名学生的身份,但在Java中我们需要通过extends关键字来实现它们之间的继承。
二、继承extends
继承是Java面向对象的三大特征(继承、多态、封装)之一。
它可以使得子类具有父类的属性和方法,同时还可以在子类中重新定义,追加新的属性和方法(
子类可以重写override已继承的方法,实现多态性)。
1.继承可以继承什么
1)在类中我们可以定义什么
常见:属性、方法、构造方法、主函数main |
不常见:(静态)代码块、静态属性、静态方法(如主函数)、(匿名)内部类 |
子类可以继承父类的所有的属性和方法吗?
答案自然是肯定不能。
如果你的父亲是一名商人,你作为它的儿子可以继承他的财富但不能继承他的勤奋。
其中静态属性子类和父类共用同一个
→ 理解:儿子继承了父亲的房子,但父亲还是与儿子住在一起。
总的来说父类与子类必有不同,在Java中还可以通过override重写已继承的方法,可以理解为一种“推陈出新”的思想。
对于一些不常见的属性和方法可以参考后续代码示例。
2) 静态属性与一般属性的异同
1.0 存储位置
静态属性存储在类的静态存储区域中,只会在类加载时初始化一次,并且所有该类的实例共享相同的静态属性值。一般属性存储在每个类的实例(对象)中,每个对象都有自己的一般属性副本,并且属性的值独立于其他对象。 |
2.0 初始化时机
静态属性在类加载时被初始化,即使没有创建类的实例,静态属性也会被赋予初始值。 一般属性属于对象的状态的一部分,只有在创建对象实例时才会为其分配内存并初始化。 |
3.0 使用方式
静态属性可以通过类名直接访问,也可以被所有实例共享,通常用于表示与类本身相关的信息,如常量、计数器等。 一般属性只能通过对象实例来访问,每个对象有自己的一般属性值,通常用于表示对象的特定状态或特征。 |
3)super关键字的用途
1.0 调用父类的构造方法
class Parent {
public Parent() {
System.out.println("Parent class constructor");
}
}
class Child extends Parent {
public Child() {
super(); // 调用父类的无参构造方法
System.out.println("Child class constructor");
}
}
public class Main {
public static void main(String[] args) {
Child child = new Child();
}
}
输出:
Parent class constructor
Child class constructor
2.0 访问父类的成员
class Parent {
public String name = "Parent";
public void display() {
System.out.println("Parent class method");
}
}
class Child extends Parent {
public String name = "Child";
public void display() {
System.out.println(super.name); // 访问父类字段
super.display(); // 调用父类方法
System.out.println("Child class method");
}
}
public class Main {
public static void main(String[] args) {
Child child = new Child();
child.display();
}
}
输出:
Parent
Parent class method
Child class method
3.0 在构造方法中初始化父类特定的属性
在调用构造方法的时候,super()必须放在子类构造方法中的第一行
class Parent {
private int value;
public Parent(int value) {
this.value = value;
}
public void display() {
System.out.println("Parent value: " + this.value);
}
}
class Child extends Parent {
public Child(int value) {
super(value); // 调用父类的带参构造方法
}
}
public class Main {
public static void main(String[] args) {
Child child = new Child(10);
child.display();
}
}
输出:
Parent value: 10
2.代码示例
1)父类代码
public class Student {
static String name;//静态属性
public void setName(String name){
this.name=name;
}
public Student(){
System.out.println("父类-构造方法");
readName();
wzGlory();
}
{
System.out.println("父类-构造代码块");
}
static {
System.out.println("父类-静态构造代码块,只执行一次");
}//不创建对象只有主函数入口一样会正常输出
public static void readName(){
System.out.println("父类-静态方法,可被类名调用");
}
public void wzGlory(){
System.out.println("父类-铂金段位");
}
public static void main(String[] args){
Student stu = new Student();
stu.setName("三水气象台");
System.out.println("父类-name:"+name);
System.out.println("——————————————————————————");
Student stu2 = new Student();
stu2.setName("三水点一灯");
System.out.println("父类-name:"+name);
}
}
输出:
父类-静态构造代码块,只执行一次
父类-构造代码块
父类-构造方法
父类-静态方法,可被类名调用
父类-铂金段位
父类-name:三水气象台
——————————————————————————
父类-构造代码块
父类-构造方法
父类-静态方法,可被类名调用
父类-铂金段位
父类-name:三水点一灯
2)子类代码
public class uniStudent extends Student{
public uniStudent(){
System.out.println("子类-构造方法");
}
{
System.out.println("——————————————————————————");
System.out.println("子类-构造代码块");
}
@Override //用于检测方法重写是否正确
public void wzGlory(){
super.wzGlory();
System.out.println("子类-星耀段位");
}
public static void main(String[] args) {
uniStudent uniStu = new uniStudent();
uniStu.setName("子类-紫川秀");
System.out.println(name);
}
}
输出:
父类-静态构造代码块,只执行一次
父类-构造代码块
父类-构造方法
父类-静态方法,可被类名调用
父类-铂金段位
子类-星耀段位
——————————————————————————
子类-构造代码块
子类-构造方法
子类-紫川秀