类是一份蓝图
到目前为止,你的代码都写在方法里,传来传去的都是普通的值。类让你把相关的数据和操作这些数据的行为打包成一个有名字的类型。类是蓝图,你真正使用的是根据它创建出的对象。
类声明两种成员:字段(每个对象保存的数据)和方法(每个对象能做的事)。
new Dog() 在内存中创建一个对象,并给你一个指向它的引用。d.name 和 d.bark() 访问的就是这个特定的对象。
每个对象都有自己的状态
类的意义就在于,你可以创建出许多相互独立的对象,每个对象都带着自己的字段值。修改其中一个,永远不会影响另一个。
rex 和 bella 是两个独立的对象。每个对象都有自己的 name,所以每次 bark() 打印的值都不同。这种属于每个对象的数据叫作实例状态。
字段和方法协同工作
类中的方法可以直接读取和更新对象自己的字段,无需把字段作为参数传进去。方法本来就“属于”它所操作数据的那个对象。
注意 increment() 不接收任何参数。它操作的是你调用它的那个 Counter 的字段。这就是类方法和独立的静态方法的区别:方法有一个隐含的对象可以操作。
this 关键字
在方法内部,this 是指向调用该方法的对象的引用。通常你不需要写它:写 count 就已经表示 this.count。但当参数名和字段名冲突时,this 就必不可少了,而这种情况在 setter 和构造方法中经常出现。
初学者常犯的一个错误是在 move 里写 x = x;。这只是把参数赋给它自己,字段完全没动:编译器不会警告你,对象会悄悄保留旧值。this.x = x; 才是真正更新字段的写法。
字段默认值与 null 引用
创建对象时,它的字段不会是垃圾值,Java 会把它们初始化为默认值:数字为 0,boolean 为 false,String 这样的对象引用为 null。这个 null 默认值是一种经典崩溃的根源。
u.name 是 null,因为没人设置过它,所以对它调用 .length() 会抛出 NullPointerException。在使用对象的字段之前,一定要先给它们赋上有意义的值,而这正是构造方法要解决的问题。
围绕类组织代码
真实的程序会把业务领域建模成类,把数据和对数据的操作放在一起。下面这个 BankAccount 类保存余额,并管控余额的变化方式:
数据(balance)和修改它的规则(deposit、withdraw)集中在一处。其他地方的代码是请账户去做事,而不是直接去改它的数字,这是整洁、易维护设计的基础。
下一步:构造方法
在 new 之后手动设置每个字段既繁琐又容易忘,而且正如你刚才看到的,忘记设置的字段会留下一个随时导致崩溃的 null。构造方法让你在对象创建的那一刻就要求并初始化它的字段,这样 BankAccount 就绝不会在没有户主的情况下存在。这就是下一页的内容。
常见问题
Java 中的类是什么?
类是一份蓝图,定义了某种对象将拥有的数据(字段)和行为(方法)。类本身只是模板,真正的对象要用 new 从它创建出来。例如,Dog 类描述了每只狗都有一个 name,并且会 bark(),而每个 new Dog() 都是一只拥有自己名字的独立的狗。
Java 中类和对象有什么区别?
类是定义;对象是用 new 根据这个定义创建出的具体实例。一个 Person 类可以创建出许多 Person 对象,每个对象都保存着自己的字段值。可以把类想象成饼干模具,把对象想象成一块块饼干:修改一个对象的字段,永远不会影响另一个对象。
Java 类中的 this 关键字有什么作用?
this 指向当前对象,也就是正在运行其方法的那个实例。你用它访问对象自己的字段,尤其是当参数和字段同名时(this.name = name;)。没有 this,这条赋值语句只是把参数赋给它自己,字段保持不变。