4 对象与类
4.1 面向对象程序设计概述
4.1.1 类
类构造对象的过程为创建类的实例。
封装。实例域。方法。状态。
4.1.2 对象
对象的行为。对象的状态。对象的标识。
4.1.3 识别类
4.1.4 类之间的关系
- 依赖 uses-a
- 聚合 has-a
- 继承 is-a
uml 统一建模语言。
4.2 使用预定义类
4.2.1 对象与对象变量
在Java中,使用构造器构造新实例。
一个对象变量并没有实际包含一个对象,而仅仅引用一个对象。
4.2.2 Java类库中的GregorianCalendar类
Date类表示时间点;日历表示法GregorianCalendar类;更加通用的Calendar类。
4.2.3 更改器方法与访问器方法
public class CalendarTest { public static void main(String[] args) { // construct d as current date GregorianCalendar d = new GregorianCalendar(); int today = d.get(Calendar.DAY_OF_MONTH); int month = d.get(Calendar.MONTH); // set d to start date of the month d.set(Calendar.DAY_OF_MONTH, 1); int weekday = d.get(Calendar.DAY_OF_WEEK); // get first day of week (Sunday in the U.S.) int firstDayOfWeek = d.getFirstDayOfWeek(); // determine the required indentation for the first line int indent = 0; while (weekday != firstDayOfWeek) { indent++; d.add(Calendar.DAY_OF_MONTH, -1); weekday = d.get(Calendar.DAY_OF_WEEK); } // print weekday names String[] weekdayNames = new DateFormatSymbols().getShortWeekdays(); do { System.out.printf("%4s", weekdayNames[weekday]); d.add(Calendar.DAY_OF_MONTH, 1); weekday = d.get(Calendar.DAY_OF_WEEK); } while (weekday != firstDayOfWeek); System.out.println(); for (int i = 1; i <= indent; i++) System.out.print(" "); d.set(Calendar.DAY_OF_MONTH, 1); do { // print day int day = d.get(Calendar.DAY_OF_MONTH); System.out.printf("%3d", day); // mark current day with * if (day == today) System.out.print("*"); else System.out.print(" "); // advance d to the next day d.add(Calendar.DAY_OF_MONTH, 1); weekday = d.get(Calendar.DAY_OF_WEEK); // start a new line at the start of the week if (weekday == firstDayOfWeek) System.out.println(); } while (d.get(Calendar.MONTH) == month); // the loop exits when d is day 1 of the next month // print final end of line if necessary if (weekday != firstDayOfWeek) System.out.println(); } }
4.3 用户自定义类
4.3.1 Employee类
import java.util.Date; import java.util.GregorianCalendar; public class EmployeeTest { public static void main(String[] args) { Employee[] staff = new Employee[3]; staff[0] = new Employee("Kate", 74000, 1987, 2, 1); staff[1] = new Employee("Lucy", 13000, 1984, 2, 12); staff[2] = new Employee("Ann", 12000, 1990, 4, 21); for (Employee e : staff) { System.out.println("name =" + e.getName() + ", salary = " + e.getSalary() + ", hireDay = " + e.getHireDay()); } } } class Employee { private String name; private double salary; private Date hireDay; public Employee(String n, double s, int year, int month, int day) { name = n; salary = s; GregorianCalendar calendar = new GregorianCalendar(year, month - 1, day); hireDay = calendar.getTime(); } public String getName() { return name; } public void setName(String n) { name = n; } public double getSalary() { return salary; } public void setSalary(double s) { salary = s; } public Date getHireDay() { return hireDay; } public void setHireDay(int year, int month, int day) { GregorianCalendar calendar = new GregorianCalendar(year, month - 1, day); hireDay = calendar.getTime(); } }
4.3.2 多个源文件的使用
两种编译源文件的方法:
javac Employee*.java;
java EmplyeeTest.java;
4.3.3 剖析Employee类
4.3.4 从构造器开始
- 构造器与类同名;
- 每个类可以有一个以上的构造器;
- 构造器可以有0,1,或多个参数;
- 构造器没有返回值;
- 构造器总是伴随着new操作一起调用
4.3.5 隐式参数与显式参数
在每一个方法中,关键词this表示隐式参数。
4.3.6 封装的优点
设置实例域,需要提供下面三项内容
- 一个私有的数据域;
- 一个公有的域访问方法;
- 一个公有的域更改器方法;
4.3.7 基于类的访问权限
if(harry.equals(boss)).
同类的方法可以访问任何一个类实例的私有域。
4.3.8 私有方法
在Java 中,实现一个私有方法,只需将public改成private;
4.3.9 final实例域
在每一个构造器执行以后,这个域的值将被设置,并且在后面的操作中,不能够对它进行修改。
class Employee{ private final String name; ... }
4.4 静态域与静态方法
4.4.1 静态域
将域定义为static,这个域属于类,而不属于任何独立的对象。
4.4.2 静态常量
public static final double PI = 3.1415926;
4.4.3 静态方法
静态方法是一种不能向对象实施操作的方法。
可以认为静态方法是没有this参数的方法。
在下面两种情况下使用静态方法:
- 一个方法不需要访问对象状态,其所需要的参数都是通过显式参数提供的。
- 一个方法只需要访问类的静态域。
4.4.4 工厂方法
静态方法还有一种常见的用途,使用工厂方法产生不同风格的格式对象。
- 无法命名构造器,希望得到的实例采用不同的名称;
- 当使用构造器,无法改变所构造的对象类型。
4.4.5 main方法
main方法也是一个静态方法。
4.5 方法参数
按值调用,call by value,方法接受的是调用者提供的值。按引用调用,call by reference,表示方法接受的是调用者提供的变量地址。一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。
- 一个方法不能修改一个基本数据类型的参数。
- 一个方法可以改变一个对象参数的状态。
- 一个方法不能让对象参数引用一个新的对象。
4.6 对象构造
4.6.1 重载
一个类有多个构造器,这种特征叫重载。跳出具体的执行方法,称之为重载解析。
4.6.2 默认域初始化
如果构造器没有显式的赋予初值,那么就会自动赋予默认值,数值为0,布尔值为false,对象引用为null。
4.6.3 无参数的构造器
如果没有编写构造器,系统会提供一个无参数构造器。
如果至少编写了一个构造器,没有提供参数会被认视为不合法。
4.6.4 显式域初始化
当一个类的所有构造器都希望把相同的值赋予某个特定的实例域时,这个方法特别有用。
初始值不一定是常量。
4.6.5 参数名
public Employee(String aName, double aSalary) { name = aName; scary = aSalary;}
4.6.6 调用另外一个构造器
用关键词this调用同一个类的另一个构造器。
4.6.7 初始化块
Java还有第三种机制,称为初始化块。
- 所有数据域被初始化为默认值(0,false或者null)
- 按照类声明中出现的次序,依次执行所有域初始化语句和初始化块。
- 如果构造器第一行调用了第二个构造器,则执行第二个构造器主体。
- 执行这个构造器的主体。
静态的初始化块
static { Random generator = new Random(); nextId = generator.nextInt(10000);}
4.6.8 对象构析与finalize方法
可以给任何一个类添加finalize方法,在垃圾回收器清除对象之前调用。
4.7 包
允许用包将类组织起来。使用包的主要原因是确保类名的唯一性。
4.7.1 类的导入
import java.util.*;
4.7.2 静态导入
import static java.lang.System.*;
4.7.3 将类放入包中
package com.ayor.corejava;
4.7.4 包作用域
没有指定private或者public,这个部分(类,方法或者变量)可以被同一个包中所有方法访问。
4.8 类路径
jar,Java归档文件。
4.9文档注释
javadoc,可以由源文件生成一个HTML文档。联机文档api,就是通过对标准类库的源代码运行javadoc生成的。
4.9.1 注释的插入
javadoc从下面几个特性中抽取信息
- 包
- 公有类及接口
- 公有的和受保护的构造器及方法
- 公有的和受保护的域
4.9.2 类注释
类注释必须在import语句之后,类定义之前。
4.9.3 方法注释
@param 变量描述
@return描述
@throws类描述
4.9.4 域注释
4.9.5 通用注释
@author姓名
@verison文本
@since文本
@deprecated文本
@see引用
4.9.6 包与概述注释
4.9.7 注释的抽取
javadoc -d docDirectory nameOfPackage;
javadoc -d docDirectory *.java;
省略docDirectory选项,html文件会被提取到当前目录下,不推荐。
使用 -author ,-version 选项,可以提取@author,@version标记。
4.10 类设计技巧
- 一定要保证数据私有;
- 一定要对数据初始化;
- 不要在类中使用过多的基本数据类型;
- 不是所有域都需要独立的域访问器和域更改器;
- 将指责过多的类进行分解;
- 类名和方法名要体现它们的职责;

浙公网安备 33010602011771号