面向对象的编程思想,力图让程序中对事物的描述与该事物在现实中的形态保持一致。为了做到这一点,面向对象的思想中提出了两个概念——类和对象。其中,类是对某一类事物的抽象描述,而对象用于表示现实中该类事物的个体。接下来通过一个图例来描述类与对象的关系,如图所示。
在图中,可以将人看作是一个类,将每个具体的人(如小韩、小石等)看作对象,从人与具体个人之间的关系便可以看出类与对象之间的关系。类用于描述多个对象的共同特征,它是对象的模板,而对象用于描述现实中的个体,它是类的实例。从图中可以看出,对象是类的具体化,并且一个类可以对应多个对象。
Java对象和类的定义以及语法
在面向对象的思想中,最核心的就是对象。为了在程序中创建对象,首先需要定义一个类。类是对象的抽象,它用于描述一组对象的共同特征和行为,例如人都有姓名、年龄、性别等特征,还有学习、工作、购物等行为。以面向对象的编程思想,就可以将某一类中共同的特征和行为封装起来,把共同特征作为类的属性(也叫成员变量),把共同行为作为类的方法(也叫成员方法)。本节将对Java中类的定义格式、类的成员变量和成员方法进行详细讲解。
1.类的定义格式
Java中的类是通过class关键字来定义的,其语法格式如下:
[修饰符] class 类名 [extends 父类名] [implements 接口名]{
// 类体,包括类的成员变量和成员方法
}在上述语法格式中,class前面的修饰符可以是public,也可以不写(默认);class之后是定义的类名,类名首字母要大写,并且其命名要符合标识符的命名规则;extends和implements是可选项,均为Java中的关键字,其中extends用于说明所定义的类继承于哪个父类,implements关键字用于说明当前类实现了哪些接口(这两个关键字将在下一章详细讲解,这里作为了解即可)。后面大括号{}中的内容是类体,即需要在类中编写的内容,它主要包括类的成员变量和成员方法。
2.声明(定义)成员变量
类的成员变量也被称作类的属性,它主要用于描述对象的特征。例如,一个人的基本属性特征有姓名、年龄、职业、住址等信息,在类中要使用姓名、年龄等信息时,就需要先将它们声明(定义)为成员变量。
声明(定义)成员变量的语法格式如下:
声明(定义)成员变量的语法格式如下:
[修饰符] 数据类型 变量名 [ = 值];在上述语法格式中,修饰符为可选项,用于指定变量的访问权限,其值可以是public、private等;数据类型可以为Java中的任意类型;变量名是变量的名称,必须符合标识符的命名规则,它可以赋予初始值,也可以不赋值。通常情况下,将未赋值(没有被初始化)的变量称之为声明变量,而赋值(初始化)的变量称之为定义变量。
例如,姓名和年龄属性在类中的声明和定义方式如下:
private String name; // 声明一个String类型的name;
private int age = 20; // 定义一个int类型的age,并赋值为20;3.声明(定义)成员方法
成员方法也被称为方法,类似于C语言中的函数,它主要用于描述对象的行为。一个人的基本行为特征有吃饭、睡觉、运动等,这些行为在Java类中,就可以定义成方法。
定义一个方法的语法格式如下:
[修饰符] [返回值类型] 方法名([参数类型 参数名1,参数类型 参数名2,...]){
//方法体
...
return 返回值; //当方法的返回值类型为void时,return及其返回值可以省略
}上面语法格式中,[]中的内容表示可选,各部分的具体说明如下:
● 修饰符:方法的修饰符比较多,有对访问权限进行限定的(如public、protected、private),有静态修饰符static,还有最终修饰符final等,这些修饰符在后面的学习过程中会逐步讲解。
● 返回值类型:用于限定方法返回值的数据类型,如果不需要返回值,可以使用void关键字。
● 参数类型:用于限定调用方法时传入参数的数据类型。
● 参数名:是一个变量,用于接收调用方法时传入的数据。
● return关键字:用于结束方法以及返回方法指定类型的值,当方法的返回值类型为void时,return及其返回值可以省略。
● 返回值:被return语句返回的值,该值会返回给调用者。
在上述语法中,{}之前的内容被称之为方法签名(或方法头),而{}中的执行语句被称为方法体。需要注意的是,方法签名中的“[参数类型 参数名1,参数类型 参数名2,...]”被称作参数列表,它用于描述方法在被调用时需要接收的参数,如果方法不需要接收任何参数,则参数列表为空,即()内不写任何内容。关于上述语法结构中的修饰符内容,将在后面进行逐一的讲解,这里读者只需了解如何定义类、成员变量和成员方法即可。
了解了类及其成员的定义方式后,接下来通过一个具体的案例来演示一下类的定义,如文件1所示。
文件1 Person.java
public class Person {
int age; // 声明int类型的变量age
// 定义 speak() 方法
void speak() {
System.out.println("我今年" + age + "岁了!");
}
}文件1中定义了一个Person类,并在类中定义了类的成员变量和成员方法。其中,Person是类名,age是类的成员变量,speak()是类的成员方法。在成员方法speak()中可以直接访问成员变量age。
脚下留心
在Java中,定义在类中的变量被称为成员变量,定义在方法中的变量被称为局部变量。如果在某一个方法中定义的局部变量与成员变量同名,这种情况是允许的,此时方法中通过变量名访问到的是局部变量,而并非成员变量,请阅读下面的示例代码:
public class Person {
int age = 10; // 类中定义的变量被称作成员变量
void speak() {
int age = 30; // 方法内部定义的变量被称作局部变量
System.out.println("我今年" + age + "岁了!");
}
}上面的代码中,speak()方法中的打印语句所访问的变量age,就是局部变量,也就是说,当有另外一个程序来调用speak()方法时,输出的值为30,而不是10。
Java创建实例对象
应用程序想要完成具体的功能,仅有类是远远不够的,还需要根据类创建实例对象。在Java程序中,可以使用new关键字来创建对象,具体语法格式如下:
类名 对象名称 = new 类名();例如,创建Person类的实例对象代码如下:
Person p = new Person();上面的代码中,“new Person()”用于创建Person类的一个实例对象,“Person p”则是声明了一个Person类型的变量p,中间的等号用于将Person对象在内存中的地址赋值给变量p,这样变量p便持有了对象的引用。为了便于描述,本书接下来的章节,通常会将变量p引用的对象简称为p对象。在内存中变量p和对象之间的引用关系如图1所示。
从图1可以看出,在创建Person对象时,程序会占用两块内存区域,分别是栈内存和堆内存。其中Person类型的变量p被存放在栈内存中,它是一个引用,会指向真正的对象;通过new Person()创建的对象则放在堆内存中,这才是真正的对象。
小提示:
Java将内存分为两种,即栈内存和堆内存。其中栈内存用于存放基本类型的变量和对象的引用变量(如Person p),堆内存用于存放由new创建的对象和数组。
在创建Person对象后,可以通过对象的引用来访问对象所有的成员,具体格式如下:
对象引用.对象成员接下来通过一个案例来学习如何访问对象的成员,如文件1所示。
文件1 Example02.java
public class Example02 {
public static void main(String[] args) {
Person p1 = new Person(); // 创建第一个Person类对象
Person p2 = new Person(); // 创建第二个Person类对象
p1.age = 18; // 为age属性赋值
p1.speak(); // 调用对象的方法
p2.speak();
}
}运行结果如图2所示。
图2 运行结果
文件1中,p1、p2分别引用了Person类的两个实例对象。从图2可以看出,p1和p2对象在调用speak()方法时,打印的age值不同。这是因为p1对象和p2对象是两个完全独立的个体,它们分别拥有各自的age属性,对p1对象的age属性进行赋值并不会影响到p2对象age属性的值。程序运行期间p1、p2引用的对象在内存中的状态如图3所示。

图3 P1、P2对象在内存中的状态
小提示:
在实际情况下,除了可以使用文件3-2中介绍的对象引用来访问对象成员外,还可以直接使用创建的对象本身来引用对象成员,具体格式如下:
new 类名().对象成员这种方式是在通过new关键字创建实例对象的同时就访问了对象的某个成员,并且在创建后只能访问其中某一个成员,而不能像对象引用那样可以访问多个对象成员。同时,由于没有对象引用的存在,在完成某一个对象成员的访问后,该对象就会变成垃圾对象。所以,在实际开发中,创建实例对象时多数会使用对象引用。
在文件1中,通过“p1.age=18”将p1对象的age属性赋值为18,但并没有对p2对象的age属性进行赋值,按理说p2对象的age属性应该是没有值的。但从图2可以看出,p2对象的age属性也是有值的,其值为0。这是因为在实例化对象时,Java虚拟机会自动为成员变量进行初始化,针对不同类型的成员变量赋予不同的初始值,如表1所示。
表1 成员变量的初始化值

当对象被实例化后,在程序中可以通过对象的引用变量来访问该对象的成员。需要注意的是,当没有任何变量引用这个对象时,它将成为垃圾对象,不能再被使用。接下来通过两段程序代码来分析对象是如何成为垃圾的。
第一段程序代码:
{
Person p1 = new Person(); ......
}上面的代码中,使用变量p1引用了一个Person类型的对象。当这段代码运行完毕时,变量p1就会超出其作用域而被销毁,这时Person类型的对象将因为没有被任何变量所引用而变成垃圾。
第二段程序代码:
{
Person p2 = new Person(); ......
p2 = null; ......
}上面的代码中,使用变量p2引用了一个Person类型的对象,接着将变量p2的值置为null,则表示该变量不指向任何一个对象,被p2所引用的Person对象就会失去引用,成为垃圾对象,过程如图4所示。
