Java面向对象
Java的面向对象编程(OOP)是一种编程范式,它使用“对象”来设计应用程序和计算机程序。面向对象编程的核心概念包括类、对象、继承、封装、多态和抽象。
继承
- 继承是一种机制,子类可以继承父类的属性和方法,而无需重新编写代码。
- 子类可以扩展或修改它继承的属性和方法的功能。
封装
- 封装是将数据(属性)和代码(方法)绑定在一起的过程,形成一个独立的对象,并对对象的详情进行隐藏。
- 封装的一个重要方面是,对象应该不允许外部直接访问其内部状态。这通常通过将属性设置为私有(private)来实现,并提供公共(public)方法(如getters和setters)来访问和修改这些属性。
为什么要先调用父类的构造方法
-
初始化继承的属性:
父类的构造函数负责初始化它自己的属性。由于子类继承了这些属性,确保这些属性在子类对象使用之前已经被正确初始化是非常重要的。调用父类的构造函数是初始化这些继承属性的一种有效方式。 -
执行继承的行为:
父类的构造函数可能包含一些基本行为,这些行为对于子类的实例来说也是必须的。执行父类的构造函数可以确保这些行为被执行,以便子类的实例在创建时就处于有效的状态。 -
遵守构造协议:
在面向对象设计中,每个类都应该负责自己的初始化。通过首先调用父类的构造函数,子类的构造函数遵守了这一协议,确保了所有的初始化步骤都得到了适当的处理。 -
避免重复代码:
如果子类需要执行父类的初始化代码,而不先调用父类的构造函数,那么初始化代码就需要在每个子类中重复。这违反了DRY(Don’t Repeat Yourself)原则。通过调用父类的构造函数,可以避免这种重复。 -
构造链:
Java支持多层继承,这意味着一个父类也可以有自己的父类。因此,构造函数需要形成一个调用链,以保证从最顶层的基类开始,所有类的构造函数都被按顺序调用,确保整个继承层次结构中的每个类都能正确地完成初始化。
在Java中,如果子类的构造函数没有显式地通过super()
调用父类的构造函数,编译器会自动插入对无参父类构造函数的调用。如果父类没有无参构造函数,子类的构造函数必须通过super
关键字显式调用一个可用的父类构造函数,否则编译器将报错。
方法重写与重载的区别
方法重写(Overriding)和方法重载(Overloading)是Java中两种不同的概念,它们允许程序员在不同情况下使用相同的方法名。它们的主要区别如下:
方法重载(Overloading):
- 发生在同一个类中,也可以在子类中发生。
- 涉及创建多个具有不同参数列表的同名方法。
- 参数列表必须不同,可以是参数数量不同,参数类型不同,或参数的顺序不同。
- 返回类型可以相同,也可以不同,并且对重载不是决定性因素。
- 主要是增加方法的可读性和代码的清晰度。
例如:
public class DataPrinter {
public void print(String data) { ... }
public void print(int data) { ... }
public void print(String data, int times) { ... }
}
方法重写(Overriding):
- 发生在存在继承关系的类之间,子类重写父类的方法。
- 子类中的方法必须和父类中被重写的方法具有相同的方法名、返回类型和参数列表。
- 子类的访问权限不能比父类中被重写的方法更严格。
- 重写的方法可以根据需要在子类中提供特定的实现。
- 用于实现运行时多态和动态方法调度。
例如:
public class Animal {
public void sound() { ... }
}
public class Dog extends Animal {
@Override
public void sound() {
// 特定于Dog的实现
}
}
总结:
- 重载是编译时多态性的一种形式,因为编译器必须确定要调用哪个方法。
- 重写是运行时多态性的一种形式,因为具体调用哪个方法取决于对象的实际类型。
- 重载发生在一个类的内部或继承关系中,而重写只发生在继承关系中。
- 重载方法允许不同的参数,而重写方法要求参数完全相同。
JavaBean
JavaBean 是一种特别的 Java 类,主要用于封装多个对象或数据项成为一个单一的对象(Bean)。它遵循了某些编码规范,使得这些 Java 类可以轻易被重用、替换和连接。这些规范包括:
-
可序列化:
JavaBean 必须实现Serializable
接口,这样的对象可以方便地保存和恢复其状态。 -
无参构造函数:
JavaBean 必须有一个无参的构造函数,这样的构造函数使得JavaBean可以在初始化时不需要任何参数。 -
私有属性(Private Fields):
JavaBean 的属性通常需要设置为私有(private),这样可以通过公共(public)的 getter 和 setter 方法来访问这些属性,这是一种封装数据的方法。 -
getter 和 setter 方法:
为了获取和设置属性值,需要为每个属性提供公共的 getter 和 setter 方法。这些方法通常以get<PropertyName>
和set<PropertyName>
的形式命名。 -
可选的业务逻辑:
尽管主要目的是封装数据,JavaBeans 也可以包含一些其他的方法,以提供更多的功能和业务逻辑处理。
一个典型的 JavaBean 示例可能如下所示:
import java.io.Serializable;
public class PersonBean implements Serializable {
private String name;
private int age;
// 无参构造函数
public PersonBean() {}
// getter 和 setter 方法
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 String getPersonInfo() {
return "Name: " + name + ", Age: " + age;
}
}
JavaBeans 在很多Java技术中都有应用,例如在Java EE平台中,它们经常用于封装数据。此外,很多框架和工具都使用 JavaBeans 作为配置对象,比如在 JavaServer Faces(JSF)和 JavaBeans Activation Framework(JAF)中。JavaBeans 也是 Java 内省(Introspection)的基础,这是一种可以在运行时了解对象属性、方法和事件的技术。