目录
在 Java 中,类是一个层次结构,其中Object为超类或基类,所有类都直接或间接地继承自Object类;
它允许一个类(称为子类或派生类)继承另一个类(称为父类或基类)的属性和方法。通过继承,子类可以复用父类的代码,并且可以在不修改父类代码的情况下添加新的功能或修改现有功能。
在类的继承中,被继承的类称为父类,继承而来的类则称为子类。有多个子类共同继承一个父类,那么这个父类就是多个类的基类。
Object类可以被称之为祖父类,它是所有类的父类,是Java类层中的最高层类,实质上Java中任何一个类都是它的子类。当创建类的时候,如果没有指定,那么它就是从java.lang.Object类继承而来的(如String、Integer等类都是继承于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
类的无参构造方法,它依次调用了父类(Mammal
和Animal
)的无参构造方法。而如果你使用带参数的构造方法创建
Human
对象,例如:
Human h = new Human(" Homo sapiens ", "全球", "教师");
输出将是:
这个动物的物种是: Homo sapiens
这个哺乳动物的栖息地是:
全球 这个人的职业是:教师这是因为你使用了
Human
类的带参数构造方法,它依次调用了父类(Mammal
和Animal
)的带参数构造方法,并且初始化了species
、habitat
和occupation
成员变量,并打印出相关信息。
子类虽然继承了父类的成员变量和成员方法,但对这些继承来的成员的访问权限是有限制的。
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
?关键字用于访问父类的成员(包括变量和方法)。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
是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() {
// ...
}
}