- Java与Android移动应用开发:技术、方法与实践
- 曹化宇
- 2670字
- 2021-03-24 12:19:05
3.1 类与对象
第2章介绍了基本数据类型的使用,这些类型可以处理整数、浮点数、字符和布尔类型的数据。而类(class)则是一种更加复杂的数据类型,它主要包括两种成员,即字段(field)和方法(method)。其中,字段用来存储数据,方法则定义数据的一系列操作。
在Java中,定义类需要使用class关键字。下面通过项目资源管理器中的“源包”右键菜单“新建”→“Java类”项添加一个新的类,如图3-1所示。
本例中,将新建的类命名为CAuto。然后,修改CAuto.java文件的内容,如下所示。
图3-1 添加Java类
代码中,CAuto类定义了两个字段和一个方法,分别是:
□ model字段,表示车的型号,定义为String类型,默认为空字符串。
□ doors字段,表示车门数量,定义为int类型,默认为4。
□ moveTo()方法,用于显示车的移动信息。
String是什么?它也是一个类,这里暂时当作简单的字符串类型使用就可以了。字符串又是什么?可以把它视为文本内容,还要使用一对双引号定义。
代码中使用了String.format()方法,它的功能是将各种类型的数据组合为字符串形式,先照样子敲代码就可以了,第6章会详细讨论字符串的应用。
回到CAuto类,应该如何使用它呢?首先,CAuto是一个类型,可以定义此类型的“变量”,也就是CAuto类的实例(instance)。下面的代码定义了CAuto类型的变量auto。
CAuto auto;
这里,auto称为CAuto类的一个实例,或者CAuto类型的对象,可以简称为auto对象。不过,auto对象暂时还不能使用,因为它还没有实例化,其值默认为null。
实例化一个对象时,需要使用new关键字,如下面的代码所示。
CAuto auto = new CAuto();
接下来,就可以使用auto对象了,如下面的代码所示。
public static void main(String[] args) { CAuto auto = new CAuto(); auto.model = "X9"; auto.moveTo(10, 99); }
代码中,通过圆点运算符(.)调用对象的字段和方法,首先将model字段的值设置为X9,然后调用moveTo()方法。执行代码,可以看到如图3-2所示的结果。
此外,注意,main()是程序的入口方法,它定义在应用的主类中。
图3-2 使用CAuto类的实例
3.1.1 构造函数与对象释放
再看一下auto对象的实例化代码。
CAuto auto = new CAuto();
代码中的CAuto()是方法吗?好像是,不过,这可不是一般的方法,而是在调用CAuto类的构造函数,但并没有定义这个构造函数。
实际上,如果没有在类中没有定义构造函数,则会包含一个空的构造函数。当然,也可以自己创建构造函数。下面的代码在CAuto类中添加一个构造函数。
构造函数虽然看上去和方法差不多,但它的名称与类名相同,而且不需要定义返回值类型,如moveTo()方法中关于void关键字的部分。关于返回值的更多内容,3.2节会详细讨论。
实际开发中,一个类还可以有多个构造函数,只要它们的参数设置能够有效区分就可以。下面的代码在CAuto类中创建三个构造函数。
细心的读者可能会发现一些小问题,例如,这三个构造函数之间并没有什么联系,而且在两个构造函数中出现了重复的代码。这也许不是什么大问题,但还有机会改进代码。下面的代码就是CAuto.java文件修改后的全部代码。
第一个构造函数中使用了两个参数,分别指定model和doors字段的值。重点在接下来的两个构造函数中,首先看下面的版本。
public CAuto(String m){ this(m, 4); }
当看到this关键字时,应该想到当前实例(对象),而这里就是在调用CAuto(String m, int doors)构造函数,其中将车门数设置为4。最后构造函数就比较好理解了,它调用CAuto(String m)版本的构造函数。
实际上,这三个构造函数组成一个构造函数链,通过这种方法可以减少重复代码,提高代码维护效率。
下面的代码分别使用这三个构造函数创建对象。
public static void main(String[] args) { CAuto auto1 = new CAuto(); CAuto auto2 = new CAuto("X9"); CAuto auto3 = new CAuto("XX", 2); System.out.println(auto3.doors); }
图3-3 调用不同的构造函数
代码执行结果如图3-3所示。
通过构造函数,可以进行对象的初始化操作,那么,当对象不再使用时应该怎么做呢?实际上,Java运行环境可以自动回收不再使用的对象,大多情况下并不需要开发者编写代码进行处理。不过,当对象中使用了一些外部资源时,就应该保证这些资源能够正确地关闭,例如,打开文件并进行读写操作后,就应该及时关闭文件。
3.1.2 getter()和setter()方法
这里并不是要创建名为getter()和setter()的方法,而是通过这两种方法控制字段数据的读取和设置操作。
还以CAuto类为例,看一下doors字段的使用,如下面的代码所示。
CAuto auto = new CAuto("X9"); auto.doors = -2; System.out.println(auto.doors);
本例中的车门数量设置为-2,难道是在平行宇宙中?还是回到现实世界中,要控制车门数量的设置操作。
对于这样的问题,可以使用getter()和setter()方法来解决。首先,将字段设置为私有的(private),这样就不能在类的外部访问它。然后,使用setXXX()方法设置字段数据,使用getXXX()方法返回字段数据。
下面的代码展示在CAuto类中修改doors字段的方式。
代码中所做的修改包括以下几个。
□ 将doors字段的public修饰符更改为private,稍后会讨论这两个修饰符的区别。
□ 添加setDoors()方法来设置车门数量,其中,当指定的数据在2到5之间时,就修改doors字段的值,否则使用默认的4门。
□ 添加getDoors()方法来获取车门数量,其中使用return语句返回doors字段的值即可。
□ 构造函数中,对于车门数量的设置,改用setDoors()方法来实现。
下面的代码测试与车门数量相关的操作。
public static void main(String[] args) { CAuto auto = new CAuto("X9", 6); System.out.println(auto.getDoors()); auto.setDoors(2); System.out.println(auto.getDoors()); }
图3-4 使用setter和getter方法
代码执行结果如图3-4所示。
示例中,首先使用构造函数设置车门数量为6,可以看到,实际上doors设置为4。当使用setDoors()方法设置车门数量为2时,doors字段的值才会正确设置。
实际应用中,可以通过setter()方法控制数据的正确性,设置的数据有问题时,可以使用一个默认值,如前面的示例中那样。当然,如果数据无效,也可以抛出一个异常(Exception),让对象的使用者来处理,第5章会讨论异常处理的相关内容。
此外,如果一些数据不需要在类的外部设置,只允许读取,可以只定义getter()方法。
3.1.3 静态成员与静态初始化
前面,在CAuto类中创建的字段和方法,都必须使用CAuto类的实例(对象)来访问,它们称为类的实例成员。开发中,使用static关键字,还可以将成员定义为静态成员,静态成员可以使用类的名称直接访问。
下面的代码(CAutoFactory.java文件)创建了一个汽车工厂类。
在CAutoFactory类中,定义了三个静态成员,分别如下所示。
□ counter字段,生产计数器,表示工厂生产了多少汽车,它定义为私有的,只能在类的内部自动处理。
□ getCounter()方法,以只读方式返回生产计数器的值。
□ createSuv()方法,用于创建SUV车型。
下面的代码测试CAutoFactory类的使用。
public static void main(String[] args) { CAuto suv1 = CAutoFactory.createSuv(); CAuto suv2 = CAutoFactory.createSuv(); System.out.println("汽车生产数量为" + CAutoFactory.getCounter()); }
图3-5 使用静态成员
代码执行结果如图3-5所示。
示例中,使用CAutoFactory类直接调用createSuv()方法,每一次执行后,counter的值都会加1。所以,当创建两辆SUV汽车对象后,CAutoFactory.getCounter()方法返回的数据就是2。
如果需要对静态成员进行初始化,还可以在类中使用static语句定义一个结构来完成,结构中的代码会在第一次调用静态成员时执行一次。下面的代码在CAutoFactory类中添加一个静态初始化结构。
图3-6 调用静态初始化结构
再次执行代码,可以看到如图3-6所示的结果。
本例中,虽然代码中多次调用了CAutoFactory类中的静态成员,但静态初始化代码只会执行一次。
此外,使用汽车工厂生产汽车的方法是否使代码更加直观呢?实际上,这里使用了一种比较常用的代码结构,它的名称正是“工厂方法”。