Skip to main content

对象与类

特征

封装性

  • 模块化 + 信息隐蔽: 隐藏细节 (private), 只提供受保护的访问接口 (public).
  • 只可通过方法改变对象实例的状态 (State/Instance Field).

继承性

父类和子类共享数据和方法 (提高代码重用率和可维护性):

  • 可继承成员: 公有域, 公有方法.
  • 不可继承成员: 私有域, 静态域, 实例域初始化块, 私有方法, 静态方法, 构造器方法.

多态性

不同的对象收到同一个消息 (method 调用) 可产生不同效果 (由对象内封装的细节决定):

  • 编译时多态: 重载 (Overload).
  • 运行时多态: 覆盖 (Override).
  • 根据对象实例的类型进行动态绑定 (Dynamic Binding).
  • 虚方法调用 (Virtual Method Invoking):
    • 在调用方法时, 程序会正确地调用子类对象的方法.
    • 无法进行虚方法调用情况.
  • static 方法: 以声明类型 (标识符前的类型) 为准, 无关实例类型.
  • final/private 方法: 子类无法覆盖/继承父类同名方法, 不存在虚化问题.

Design

Data Encapsulation

保持封装性

Data Initialization

不依赖实例域默认值, 且应进行数据合法化检查

Instance Field Encapsulation

过多相关的基本类型实例域可封装成一个轻型类

Constructor Diversity

最低标准为显式无参构造器+一个带参数(包括合法化检查)构造器

Clear Responsibility

一个类的方法应与类本身紧密相关, 且不过少也不过多

JavaBean

JavaBean 是一种符合命名规范的 class, 它通过 gettersetter 来定义属性:

import java.beans.*;

public class Main {
public static void main(String[] args) throws Exception {
BeanInfo info = Introspector.getBeanInfo(Person.class);
for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
System.out.println(pd.getName());
System.out.println(" " + pd.getReadMethod());
System.out.println(" " + pd.getWriteMethod());
}
}
}

class Person {
private String name;
private 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;
}
}

Class

[public] [abstract|final] class className[extends superclassName]
[implements interfaceNameList] {

//成员变量声明, 可为多个:
//实例域一般添加private修饰符, 保持封装性
[public | protected | private] [static] [final] [transient] [volatile]type variableName;

//方法(包括构造方法)定义及实现, 可为多个
[public | protected | private] [static] [final | abstract] [native] [synchronized]
returnType methodName( [paramList] ) [throws exceptionList]{
statements;
}
}

class Class_Name{
int/String characteristic; //状态(State): 变量(实例域 instance field)
constructor(){}; //标识(Identity): 构造器(constructor)
void function(){}; //行为(Behavior): 函数(方法method)
}

Accessor

只访问实例域不进行修改的方法 (accessor method):

returnType get() {
//保持封装性
//返回引用类型对象时, 必须返回克隆体对象引用而不是实例域对象引用
return instanceFieldVariable.clone();
}

Mutator

修改实例域的方法 (mutator method): e.g. add、set.

Methods

Parameters

Java 所有普通方法的参数传递方式: 值传递.

  • 基本类型: 传递值的拷贝.

方法中无法更改原变量的值.

  • 引用类型: 传递引用的拷贝.

方法中无法更改原变量的引用 (指针指向), 只可更改引用对象的状态 (State).

Signature

Signature:

  • 方法名称.
  • 方法参数.

方法返回值类型不是方法标签 (不存在同名同参而不同返回值的方法).

Constructor

构造器方法完整定义:

ClassName (ClassPropertiesVariableTable) {
//进行输入参数合法化检查
Property n = Variable;
Statement Block;
}

Definition

  • 未定义任何构造器方法. 系统会自动产生一个构造器方法, 称为无参空默认构造器方法 (default constructor), 并将所有实例域初始化为默认值.
  • 注意事项:
    • 不应在构造器中定义实例域同名变量.
    • 在构造器中尽量只调用 final/private 方法 (不会(继承后)被子类方法覆盖).
    • this() 可调用此类的其他构造方法, this() 必须位于构造器方法首行.

Execution

  • 构造器方法前语句/语句块将先于构造器执行.
  • 编译器会在编译时在每个构造器方法内首行自动添加 super(); (若父类没有无参构造器方法编译出错)/人工显式调用父类构造器方法, 直至实现 Object 类(超类)的构造器方法, 再执行构造器方法语句.

Enum

// enum
public class Main {
public static void main(String[] args) {
Weekday day = Weekday.SUN;
if (day.dayValue == 6 || day.dayValue == 0) {
System.out.println("Today is " + day + ". Work at home!");
} else {
System.out.println("Today is " + day + ". Work at office!");
}
}
}

enum Weekday {
MON(1, "星期一"), TUE(2, "星期二"), WED(3, "星期三"), THU(4, "星期四"), FRI(5, "星期五"), SAT(6, "星期六"), SUN(0, "星期日");

public final int dayValue;
private final String chinese;

private Weekday(int dayValue, String chinese) {
this.dayValue = dayValue;
this.chinese = chinese;
}

@Override
public String toString() {
return this.chinese;
}
}

Record

record 类:

  • 使用 record 定义的是不变类.
  • 可以编写 Compact Constructor 对参数进行验证.
  • 可以定义静态方法.
public record Point(int x, int y) {
public Point {
if (x < 0 || y < 0) {
throw new IllegalArgumentException();
}
}

public static Point of() {
return new Point(0, 0);
}

public static Point of(int x, int y) {
return new Point(x, y);
}
}

对象包装器与自动装箱

基本类型对应的引用类型
voidjava.lang.Void
booleanjava.lang.Boolean
charjava.lang.Character
bytejava.lang.Byte
shortjava.lang.Short
intjava.lang.Integer
longjava.lang.Long
floatjava.lang.Float
doublejava.lang.Double

父类

Number.

Final 类

所有的包装类型都是不变类 (强不可变类):

  • 无子类, 不可改变数.
  • 对于较小的数, Integer.valueOf() 静态工厂方法始终返回相同的实例.
  • Byte.valueOf() 静态工厂方法返回的实例全部是缓存实例.

编译器特性

  • 自动装箱 (auto-boxing)
Integer I = 10;
myArrayList.add(10);
  • 自动拆箱 (auto-unboxing)
int i= I;
  • 自动装箱+拆箱
Integer I = 0;I++;

// 实际译为:
Integer I = Integer.valueOf(10);
myArrayList.add(Integer.valueOf(10));
Int I = I.intValue();

APIs

  • Boolean.TRUE/Boolean.FALSE.
  • Long.SIZE/Long.BYTES.
  • Integer.MAX_VALUE/Integer.MIN_VALUE.
  • Integer.parseInt().
  • Integer.toString()/Integer.toHexString()/Integer.toOctalString()/Integer.toBinaryString().

Reflection

Mechanism

  • 运行中分析 类的能力
  • 运行中查看对象
  • 实现通用的数组操作代码
  • 利用 Method 对象

Functions

  • 分析类的能力
  • 分析对象
  • 泛型数组实现
  • 函数指针: 调用任意方法

对象克隆

Interface

标签接口(tagging interface)之一: 无方法

Object

浅拷贝: 无法克隆目标对象实例域中的对象成员

Custom

鉴于默认 clone 方法的局限性, 需自定义用户需要的 clone 方法

  • 实现接口: implements Cloneable
  • 改变可见性&抛出异常: public <returnType> clone() throws CloneNotSupportedException {};
  • 自定义克隆体: 克隆子对象

内部类

  • 定义: 应使用 private 关键字
  • 访问实例域/方法:
    • 内部类: this.fieldName/methodName
    • 外部类: OuterClass.this.fieldName/methodName
  • 声明与构造(实例化):
OuterClass.InnerClass variableName = OuterClass/this.new InnerClass();

局部

  • 定义在方法中的内部类
  • 修饰符: 无/abstract/final
  • 可访问外围类成员/final 局部变量

匿名

在实际构造父类/实现接口时定义在构造器方法中的内部类

  • 外围为父类: 内部类需要扩展该父类
new SuperType (construction parameters)
{
inner class methods and data{}; //直接定义实例域和方法, 构造器参数传递给父类构造器
}
  • 外围为接口: 内部类需要实现该接口
new InterfaceType () //一对括号
{
Inner class methods and data{}; //需实现接口中的所有抽象方法
}
  • 例子: 积分、线程、回调函数(HookFunction)、事件处理(ActionListener)

静态

  • 只可访问外围类的静态域/静态方法(可视作不可访问外围类)
  • 实例化: new OuterClass.InnerClass()