JAVA那些事(六)类的继承和多态机制

发布时间:2023年12月28日

目录

类的继承

继承的实现

类对父类构造方法的调用

父类成员的访问权限

?super与this

super

this

类的继承

在 Java 中,类是一个层次结构,其中Object为超类或基类,所有类都直接或间接地继承自Object类;

它允许一个类(称为子类或派生类)继承另一个类(称为父类或基类)的属性和方法。通过继承,子类可以复用父类的代码,并且可以在不修改父类代码的情况下添加新的功能或修改现有功能。

在类的继承中,被继承的类称为父类,继承而来的类则称为子类。有多个子类共同继承一个父类,那么这个父类就是多个类的基类。

Object类可以被称之为祖父类,它是所有类的父类,是Java类层中的最高层类,实质上Java中任何一个类都是它的子类。当创建类的时候,如果没有指定,那么它就是从java.lang.Object类继承而来的(如StringInteger等类都是继承于Object类;除此之外自定义的类也都继承于Object类。由于所有类都是Object子类,所以在定义类时,省略了extends Object关键字。)

继承的实现

定义子类的形式

[访问权限]   class 类名  extends    父类名
{
    类体
}

继承是通过extends关键字来实现的,在定义类时使用extends关键字指明新定义类的父类。新定义的类称为子类,它可以从父类那里继承属性和方法。

类的继承原则:

1.子类继承父类的成员变量,包括实例成员变量和类成员变量。

2。子类继承父类除构造方法以外成员方法,包括实例成员方法和类成员方法。

3.子类不能继承父类的构造方法,因为父类的构造方法用来创建父类对象,子类需定义自己的构造方法,用来创建子类自己的对象。

????????Java中,子类并不直接继承父类的构造方法。这是因为构造方法的主要目的是初始化特定类的对象,而每个类都有自己的特性和需要初始化的内容。

4.子类可以重新定义父类成员。

类对父类构造方法的调用

父类的有参构造方法并不能被自动调用,只能用super关键字显示调用。

如果在子类构造方法中用super显示调用父类的有参构造方法,则不会再自动调用父类的无参构造方法。(同时会根据super传入的参数类型和数量找到对应的父类的构造方法)

e.g动物、哺乳动物和人类的层级继承结构

class Animal {
    private String species;

    public Animal() {
        System.out.println("这是一个动物的基本信息。");
    }

    public Animal(String species1) {
        species = species1;
        System.out.println("这个动物的物种是:" + species);
    }
}

class Mammal extends Animal {
    private String habitat;

    public Mammal() {
        super();
        System.out.println("这是一个哺乳动物的基本信息。");
    }

    public Mammal(String species1, String habitat1) {
        super(species1);
        habitat = habitat1;
        System.out.println("这个哺乳动物的栖息地是:" + habitat);
    }
}

public class Human extends Mammal {
    private String occupation;

    public Human() {
        System.out.println("这是一个人类的基本信息。");
    }

    public Human(String species1, String habitat1, String occupation1) {
        super(species1, habitat1);
        occupation = occupation1;
        System.out.println("这个人的职业是:" + occupation);
    }

    public static void main(String[] args) {
//        Human h = new Human(" Homo sapiens ", "全球", "教师");
        Human h = new Human();
    }
}

在这个示例中,如果你使用无参构造方法创建 Human 对象,输出将是:

这是一个动物的基本信息。
这是一个哺乳动物的基本信息。
这是一个人类的基本信息。

这是因为你使用了 Human 类的无参构造方法,它依次调用了父类(MammalAnimal)的无参构造方法。

而如果你使用带参数的构造方法创建 Human 对象,例如:

Human h = new Human(" Homo sapiens ", "全球", "教师");

输出将是:

这个动物的物种是: Homo sapiens
这个哺乳动物的栖息地是:
全球 这个人的职业是:教师

这是因为你使用了 Human 类的带参数构造方法,它依次调用了父类(MammalAnimal)的带参数构造方法,并且初始化了 specieshabitatoccupation 成员变量,并打印出相关信息。

父类成员的访问权限

子类虽然继承了父类的成员变量和成员方法,但对这些继承来的成员的访问权限是有限制的。

  • 如果父类中的成员被声明为?private,那么子类无法直接访问这些变量。这是因为?private?访问修饰符限制了变量只能在其所属的类内部访问。
  • 如果父类中的成员被声明为?protected?或默认(没有指定访问修饰符,对于同一个包内的其他类可见),子类可以访问这些变量。
  • 如果父类中的成员被声明为?public,子类当然可以访问这些变量。
public class Person1{ 
	private String name;
	protected int age;
	
	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;
	}

	public void print_p()
	 {
	   System.out.println("Name:"+name+"   Age:"+age);
	 }
}
public class Teacher1 extends Person1{
	protected String department;

	public Teacher1(String na, int ag, String de)
	{	
		setName(na);
		setAge(ag);
		this.department = de;
	}
	
	public void print_s()
	{
		print_p();
		System.out.println("Department:"+department);
	}
	
	public static void main(String arg[])
	{
		Teacher1 t = new Teacher1("Wang",40,"Computer Science");
		t.print_s();
		t.setName("Wang Gang");
		t.age = 50;         //直接访问父类中protected成员变量age,但不能访问其private成员变量name                       
		t.print_s();     //试试t.print_p()
    }
 }

在这段代码中,虽然可以直接访问父类中受保护的成员变量 age,但不能直接访问其私有成员变量 name。这是因为私有成员只能在其所属的类内部访问。如果需要修改 name,应使用 setName() 方法。在最后一行的注释中提到的 t.print_p() 可以正常调用,因为它是一个公共方法,可以从子类中访问。

?super与this

super

  • super?关键字用于访问父类的成员(包括变量和方法)。
  • 在构造方法中,使用?super()?可以调用父类的无参数构造方法。
  • 使用?super(param1, param2, ...)?可以调用父类的带有参数的构造方法。
  • 在普通方法中,使用?super.member?可以访问父类的成员变量。
  • 使用?super.method(param1, param2, ...)?可以调用父类的非私有方法。
class Person2{ 
	protected String name;
	protected int age;
	
	public Person2(String na, int ag)
	{ 
		name = na;
		age = ag;
	} 
	
	public void print()
	{
		System.out.println("Parent:Name="+name+"   Age="+age);
	}
  }
public class Teacher2 extends Person2{
	String department; 
	String name;
	
	public Teacher2(String na, int ag, String de, String na1)
	{
		super(na, ag);		
		department = de;
		name = na1;
	}
	public void setName_p(String na)
	{
		super.name = na;
	} 
	public void setName_s(String na1)
	{	name = na1; 
	} 
	public void print()
	{
		super.print();
		System.out.println("Son:Name="+name+"  Department="+department);
	}
	public static void main(String arg[])
	{
		Teacher2 t = new Teacher2("Wang",40,"Computer Science","Gu");
		t.print();
		
		t.setName_p("Wang Qiang");
		t.setName_s("Gu Li");
		t.print();
	}
} 

结果:
Parent:Name=Wang Age=40 Son:Name=Gu Department=Computer Science Parent:Name=Wang Qiang Age=40 Son:Name=Gu Li Department=Computer Science

首先,通过 Teacher2 t = new Teacher2("Wang",40,"Computer Science","Gu"); 创建了一个 Teacher2 对象 t,并使用构造方法初始化其姓名、年龄、部门和名字。

第一次调用 t.print() 方法时,输出如下:

  • Parent:Name=Wang Age=40:这是父类?Person2?的?print()?方法输出的姓名和年龄。
  • Son:Name=Gu Department=Computer Science:这是子类?Teacher2?的?print()?方法输出的名字和部门。

接下来,使用 t.setName_p("Wang Qiang") 修改了父类中的 name 变量,使用 t.setName_s("Gu Li") 修改了子类中的 name 变量。

第二次调用 t.print() 方法时,输出如下:

  • Parent:Name=Wang Qiang Age=40:这是父类?Person2?的?print()?方法输出的修改后的姓名和年龄。
  • Son:Name=Gu Li Department=Computer Science:这是子类?Teacher2?的?print()?方法输出的修改后的名字和部门。

this

this 是Java中的一个关键字,它主要用于引用当前对象本身.

引用当前对象:在类的方法或构造方法中,使用?this?可以明确地引用当前对象。这在需要区分局部变量和成员变量时特别有用。

public class MyClass {
    private int myVariable;

    public void myMethod(int localVariable) {
        this.myVariable = localVariable; // 使用this引用成员变量
    }
}

调用本类的构造方法:在类的构造方法中,可以使用?this(param1, param2, ...)?调用本类的其他构造方法。这通常用于避免代码重复。

public class MyClass {
    private int myVariable;

    public MyClass() {
        this(10); // 调用本类的另一个构造方法
    }

    public MyClass(int value) {
        this.myVariable = value;
    }
}

返回当前对象:在一些情况下,方法可能需要返回当前对象本身,以便进行链式调用。这时可以使用?return this;

public class MyClass {
    public MyClass setMyVariable(int value) {
        this.myVariable = value;
        return this; // 返回当前对象,支持链式调用
    }
}

作为方法参数:在某些情况下,你可能需要将当前对象作为参数传递给其他方法。这时可以使用?this

public class MyClass {
    public void callAnotherMethod(MyClass obj) {
        obj.anotherMethod();
    }

    public void myMethod() {
        this.callAnotherMethod(this); // 将当前对象作为参数传递
    }

    public void anotherMethod() {
        // ...
    }
}

文章来源:https://blog.csdn.net/Miraitowain/article/details/135255487
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。