类(class)

声明类(class)

声明成员变量(field)

声明构造函数(constructor)

声明方法(method)

类(class)

在面向对象编程概念中介绍面向对象概念时,使用了自行车类,公路自行车、山地自行车和双人自行车子类。以下示例代码是Bicycle类的可能实现,提供了类的声明概述。后续章节会逐步解释类的声明,现在先忽略这些细节。

public class Bicycle {

    // Bicycle类拥有三个成员变量
    public int cadence;
    public int gear;
    public int speed;

    // Bicycle类拥有一个构造函数
    public Bicycle(int startCadence, int startSpeed, int startGear) {
        gear = startGear;
        cadence = startCadence;
        speed = startSpeed;
    }

    // Bicycle类拥有四个方法
    public void setCadence(int newValue) {
        cadence = newValue;
    }

    public void setGear(int newValue) {
        gear = newValue;
    }

    public void applyBrake(int decrement) {
        speed -= decrement;
    }

    public void speedUp(int increment) {
        speed += increment;
    }

}

Bicycle类的MountainBike子类声明如下:

public class MountainBike extends Bicycle {

    // MountainBike子类拥有一个成员变量
    public int seatHeight;

    // MountainBike子类拥有一个构造函数
    public MountainBike(int startHeight, int startCadence, int startSpeed, int startGear) {
        super(startCadence, startSpeed, startGear);
        seatHeight = startHeight;
    }

    // MountainBike子类拥有一个方法
    public void setHeight(int newValue) {
        seatHeight = newValue;
    }

}

MountainBike子类继承了Bicycle父类的所有成员变量和方法,并且添加了seatHeight成员变量和setHeight方法。

声明类(class)

类的声明方式如下:

class MyClass {
    // 声明成员变量、构造函数、方法
}

类体({}之间的区域)中包含了类对象生命周期的所有代码:

1. 构造函数:用于初始化新对象;

2.成员变量:提供类和对象的状态;

3.方法:实现类和对象的行为。

前面声明的类只包含类声明所需组件的最小声明,类声明中还可以包含类继承的父类,以及类实现的接口等信息。例如:

class MyClass extends MySuperClass implements YourInterface {
    // 声明成员变量、构造函数、方法
}

MyClass类是MySuperClass类的子类,MyClass类实现了YourInterface接口。

可以在类声明的开头添加public或private修饰符,这样类声明就变得复杂起来。

public和private修饰符决定了哪些类可以访问MyClass类,这些将在后续讨论。接口和继承中将会解释如何以及为什么在类声明中使用extends和implements关键字,现在不必在意这些细节。

通常,类声明可以包含以下组件,顺序如下:

1. modifier:声明public、private和其他修饰符,private修饰符只能用于嵌套类。

2. class:声明类名,首字母大写。

3. extends:声明类继承的父类(超类、基类),一个类只能继承一个父类。

4. implements:声明类实现的接口,一个类可以实现多个接口,用逗号分隔。

5. {}:声明类体。

声明成员变量(field)

Java中存在三种变量类型:

1. field:类中声明的成员变量。

2. local variable:方法或代码块中声明的局部变量。

4. parameter:方法中声明的参数。

Bicycle类中定义了以下成员变量:

public int cadence;
public int gear;
public int speed;

成员变量的声明包含以下三个组件,顺序如下:

1. modifier:声明0个或多个修饰符,例如:public或private。

2. type:声明成员变量的类型。

3. name:声明成员变量的名称。

Bicycle类的成员变量名称为cadence、gear和speed,这些成员变量的数据类型都是int(整型)。public关键字表示这些成员变量都是公共成员,任何可以访问Bicycle类的对象都可以访问这些成员变量。

访问修饰符

最左边的第一个修饰符用于控制哪些类可以访问成员变量。现在只需要考虑public和private,其他访问修饰符在后续讨论。

1. public修饰符:所有类都可以访问成员变量。

2. private修饰符:只能在成员变量所属的类中访问成员变量。

本着封装的原则,通常都会把成员变量设置为private。这意味着只能在Bicycle类中直接访问Bicycle类的成员变量。但是其他类仍然需要访问Bicycle类的成员变量,可以添加public方法来获取Bicycle类的成员变量值,间接访问Bicycle类的成员变量:

public class Bicycle {

    private int cadence;
    private int gear;
    private int speed;

    public Bicycle(int startCadence, int startSpeed, int startGear) {
        gear = startGear;
        cadence = startCadence;
        speed = startSpeed;
    }

    public int getCadence() {
        return cadence;
    }

    public void setCadence(int newValue) {
        cadence = newValue;
    }

    public int getGear() {
        return gear;
    }

    public void setGear(int newValue) {
        gear = newValue;
    }

    public int getSpeed() {
        return speed;
    }

    public void applyBrake(int decrement) {
        speed -= decrement;
    }

    public void speedUp(int increment) {
        speed += increment;
    }

}

变量类型

所有变量(成员变量、局部变量、参数)都必须具有类型,变量类型可以是:

1. primitive type(原始类型、基础类型):int, float, boolean等;

2. reference type(引用类型):字符串、数组、对象等。

变量名称

所有变量(成员变量、局部变量、参数)都必须遵循语言基础中变量命名的规则和约定。 这里的方法和类使用了相同的命名规则和约定,除了:

1. 类名的第一个字母应该大写;

2. 方法名的第一个单词应该是动词。

声明构造函数(constructor)

类包含了用于根据类的蓝图来创建对象的构造函数。构造函数的声明类似于方法的声明,但是构造函数使用的是类名,并且构造函数没有返回类型。例如,Bicycle类拥有一个构造函数:

public Bicycle(int startCadence, int startSpeed, int startGear) {
    gear = startGear;
    cadence = startCadence;
    speed = startSpeed;
}

要创建一个名为myBike的新Bicycle对象,需要使用new操作符来调用构造函数:

Bicycle myBike = new Bicycle(30, 0, 8);

new Bicycle(30, 0, 8)在内存中为对象开创了空间,并初始化对象的成员变量。 虽然Bicycle类拥有一个构造函数,但是它可以拥有其他构造函数,包括无参构造函数:

public Bicycle() {
    gear = 1;
    cadence = 10;
    speed = 0;
}

Bicycle yourBike = new Bicycle() 调用无参构造函数来创建一个名为yourBike的新Bicycle对象。 Bicycle类中可以声明这两个构造函数,因为这两个构造函数具有不同的参数列表。跟方法一样,Java平台根据参数数量和类型来区分构造函数。不能在同一个类中编写两个具有相同参数数量和类型的构造函数,因为平台无法区分这两个构造函数,这样会导致编译期错误。 可以不需要给类提供构造函数,编译器会自动给没有构造函数的类提供一个默认的无参构造函数,这个默认的构造函数会调用父类的无参构造函数。这种情况下,如果父类没有无参构造函数的话,编译器就会报错,所以必须验证父类是否具有无参构造函数。如果一个类没有显式父类的话,那么这个类就有一个隐式父类Object,Object父类确实具有一个无参构造函数。 可以使用父类的构造函数,之前的MountainBike类就是这么做的,接口和继承章节会讨论这个问题。 可以在构造函数的声明中使用访问修饰符来控制哪些类可以调用这个构造函数。 注意:如果一个类不能调用MyClass类的构造函数,那么这个类就无法直接创建MyClass对象。

声明方法(method)

下面是声明方法的典型示例:

public double calculateAnswer(double wingSpan, int numberOfEngines, double length, double grossTons) {

}

方法声明的必要元素是方法的返回类型、名称、小括号(),以及大括号{}之间的方法体。

方法声明包括以下组件,顺序如下:

1. modifier:声明public、private,以及其他修饰符。

2. type:声明方法的返回类型,方法没有返回值时,返回类型为void。

3. name:声明方法名,成员变量的命名规则适用于方法名,只是约定略微不同。

4. ():声明参数列表,使用逗号分隔,参数声明包括参数类型和参数名称,方法没有参数时,使用空的小括号()。 5. throws:声明异常列表,使用逗号分隔。

6. {}:声明方法体,用于放置局部变量声明等方法代码。 方法签名的组成:方法名和方法的参数类型。 上面声明的calculateAnswer方法的签名为:

calculateAnswer(double, int, double, double)

命名方法

尽管方法名可以是任意合法的标识符,但是代码约定限制了方法命名。按照约定,方法名应该是一个小写的动词,或者以一个小写的动词开头,后面紧跟着形容词、名词等。具有多个单词的方法名中,第二个单词之后的所有单词的第一个字母都应该大写。以下是一些示例方法名:

run
runFast
getBackground
getFinalData
compareTo
setX
isEmpty

通常一个类中的方法名是惟一的,但是因为方法可以重载,所以一个类中可以包含其他同名方法。

重载方法

Java编程语言支持重载(overload)方法,Java可以区分具有不同方法签名的方法。这意味着一个类中的可以包含同名方法,但是这些同名方法必须具有不同的参数列表。接口和继承章节会讨论方法重载的一些限制条件。 假设有一个类可以使用书法来描绘各种类型的数据(字符串、整数等),这个类包含了描绘各种数据类型的方法。每个方法都要使用新的方法名是一件很麻烦的事情,例如:drawString、drawInteger、drawFloat等等。Java编程语言中,所有描绘方法都可以使用相同的方法名,但是每个方法必须具有不同的参数列表。这样的话,数据描绘类可能会声明4个名为draw的方法,每个方法都具有不同的参数列表。

public class DataArtist {

    public void draw(String s) {

    }

    public void draw(int i) {

    }

    public void draw(double f) {

    }

    public void draw(int i, double f) {

    }

}

重载方法根据方法的参数数量和类型进行区分。示例代码中,`draw(String s)`和`draw(int i)`是两个不同的方法,因为它们具有不同的参数类型。 不能使用相同方法名称、相同参数数量和类型来声明多个方法,编译器无法区分这些方法。 区分方法时编译器不会考虑返回类型,即使两个方法具有不同的返回类型,也不能声明两个具有相同签名的方法。 注意:应该小心使用重载方法,因为重载方法会降低代码的可读性。