《Java核心技术卷一》——4对象与类
重新认识类吧...
4.1 类
类(class)是构造对象的模板或蓝图。由类构造对象的过程称为创建类的实例。
重要概念:
- 封装:将数据和行为组合在一个包中,并对对象的使用者隐藏了数据的实现方式。实现封装的关键在于绝对不能让类中的方法直接第访问其他类的实例域。
- 继承:可以通过拓展一个类来建立另外一个新的类。
类之间的关系
在类之间,最常见的关系有
- 依赖(“use-a”)
- 聚合(“has-a”)
- 继承(“is-a”)
依赖,如果一个类的方法操纵另一个类的对象,我们就说一个依赖于另一个类。
聚合,类A的对象包含类B的对象。
继承,一种用于表示特殊与一般关系的。

关联和聚合是一个意思,只是UML符号表示不同。聚类的符号更易区分一点。
4.4 各种修饰符
实例域的修饰符
修饰符 | 作用 |
---|---|
public | 如果一个实例域被public修饰,那它可以被所有类获得、修改,应该避免用public修饰。 |
private | 可以被本类的访问器获取、修改器修改。 |
final | 只能在初始化时设置值,在后面的操作中不能对它进行修改。 |
static | 所有本类的实例共享被static修饰的实例域。即使没有一个实例对象,静态域也存在。它属于类,而不属于任何独立的对象。 |
方法的修饰符
修饰符 | 作用 |
---|---|
public | 任何类的任何方法都可以调用这些方法。 |
private | 不会被外部其他类调用,可以删除它(意味着没有类依赖于该方法)。 |
static | 可以认为staic方法是没有this参数的方法。静态方法不能访问实例域,因为它不能操作对象。但是静态方法啊可以访问自身类中的静态域。静态方法属于类而不属于实例,建议使用类名调用静态方法。 |
在下面两种情况下使用静态方法:
- 一个方法不需要访问对象状态,其所需参数都是通过显示参数提供。
- 一个方法只需要访问类的静态域。
main方法也是静态方法,每个类可以有一个main方法。这是一个常用于对类进行单元测试的技巧。
4.6 对象构造
重载
如果多个方法有相同的名字、不同的参数,便产生了重载。编译器必须挑选出具体执行哪个方法,它通过用各个方法给出的参数类型与特定方法调用所使用的值类型进行匹配来挑选出相应的方法。如果编译器找不到匹配的参数,就会产生编译时错误。

默认域初始化
如果在构造器中没有显示地给域赋予初值,那么就会被自动地赋为默认值:数值为0、布尔值为false、对象引用为null。然而,只有缺少程序设计经验的人才会这样做。注意:局部变量必须明确地初始化。
无参数的构造器
如果类中提供了至少一个构造器,但是没有提供无参数的构造器,则在构造对象时如果没有提供参数就会被视为不合法。仅当类没有提供任何构造器的时候,系统才会提供一个默认的构造器。
显式域初始化
初始值不一定是常量值。也可以调用方法对域进行初始化。

参数名
不好的命名方式:只有阅读代码才能够了解参数n和参数s的含义。
public Employee(String n, double s)
{
name = n;
salary = s;
}
建议的命名方式:
public Employee(String aName, double aSalary)
{
name = aName;
salary = aSalary;
}
还有一种方式:参数变量用同样的名字将实例域屏蔽起来。
public Employee(String name, double salary)
{
this.name = name;
this.salary = salary;
}
调用另一个构造器
如果构造器的第一个语句形如this,这个构造器将调用同一个类的另一个构造器。
public Employee(double s)
{
// calls Employee(String, double)
this("Employee #" + nextId, s)
nextId++;
}
4.7 包
Java允许使用包(package)将类组织起来。借助于包可以方便地组织自己的代码,并将自己的代码与别人提供的代码库分开管理。
所有标准的Java包都处于java和javax包层次中。
使用包的主要原因是确保类名的唯一性。事实上,为了确保包名的绝对唯一,Sun公司建议将公司的因特网域名以逆序的形式作为包名,并且对于不同的项目使用不同的子包。对于我自己,可以使用如org.shijiatongxue.corejava。
在C++中,与包机制类似的是命名空间(namespace)。在Java中,package与import语句类似于C++中的namespace和using指令。
静态导入
import语句不仅可以导入类,还增加了导入静态方法和静态域的功能。
例如:
import static java.lang.System.*;
就可以使用System类的静态方法和静态域,而不必加类名前缀:
out.println("Goodbye, World!");
exit(0);
另外,还可以导入特定的方法或域:
import static java.lang.System.out;
包作用域
如果没有指定public或private,这个部分(类、方法或变量)可以被同一个包中的所有方法访问。
对于变量来说,必须显示地标记为private,不然的话默认为包可见。显然,这样做会破坏封装性。
4.9 文档注释
类注释
类注释必须放在import语句之后,类定义之前。
/**
*A {@code Card} object represents a playing card...
*...
*...
*/
public class Card
{
...
}
方法注释
/**
* Raises the salary of an emplyee.
* @param byPercent the percentage by which to raise the salary(e.g. 10 means 10%)
* @return the amount of the raise
*/
public double raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
return raise;
}
域注释
只需要对公有域(通常指的是静态常量)建立文档。例如,
/**
* The "Hearts" card suit
*/
public static final int HEART = 1;
4.10 类设计技巧
- 一定要保证数据私有
- 一定要对数据初始化
Java不对局部变量初始化,但是会对对象的实例域进行初始化。最好不要依赖于系统的默认值。而是应该显式低初始化所有的数据。具体的初始化方式可以是提供默认值。也可以是在所有的构造器中设置默认值。 - 不要在类中使用过多的基本类型
就是说,用其他的类替代多个相关的基本类型的使用。这样会使类更加易于理解且易于修改。 - 不是所有的域都需要独立的域访问器和域更改器
- 将职责过多的类进行分解
- 类名和方法名要能够体现它们的职责
命名类名的良好习惯是采用一个名词(Order)、前面有形容词修饰的名词(RushOrder)或动名词修饰名词(BillingAddress)。对于方法来说,习惯是访问器方法用小写get开头,更改器方法用小写的set开头。 - 优先使用不可变类
更改对象的问题在于,如果多个线程视图同时更新一个对象,就会发生并发更改。其结果是不可预料的。如果类是不可变的,就可以安全地在多个线程间共享其对象。
本章完。