方法对实例变量的使用:对象行为方式

对象行为与状态之间的互动(状态影响行为,行为亦影响状态)。我们已然知道对象有着 状态行为,分别由 实例变量方法 所表示。但直到现在,我们仍对二者之间是如何关联起来的一无所知。我们已经知道某个类的各个实例(也就是某个特定类型的各个对象),对于其实例变量,都可以有独特的值。Dog A 的名字可以是 Fido,重量是 70 磅,Dog B 的名字是 Killer,重量是 9 磅。如果 Dog 类有一个 makeNoise() 方法,那么 70 磅的狗子发出的声音肯定要比 9 磅的狗子低沉一些。幸运的是,这就是对象的应有之义 -- 其行为取决于其状态。换句话说,就是 方法使用到实例变量的值。比如”如果狗子重量大于14磅,那么就会发出嚎叫声,相反则会发出呜呜声“,或者“重量每增加5磅,发出的声音就低一些”。

类描述了对象知道什么,和做些什么(A class describes what an object knows and what it does)

类是对象的蓝图(A class is the blueprint for an object)。 在编写某个类的时候,实际上实在告诉JVM,怎样去构造那个类型的对象。我们已经知道某个类型的各个对象,可以有着不同的实例变量值,那么在方法上呢?

某个类型的各个对象,可以有着不同的方法行为吗?

答案是:...当然可以

特定类的各个实例,有着同样的方法,但根据各自实例变量的值,这些方法可以行事各异。

  • 可以向方法传递值方法使用参数,调用者传递参数(A method use parameters. A caller passes arguments)

  • 又可以从某个方法,得到返回值

  • Java 是值传递的,也就是说传递的是拷贝(Java is pass-by-value. That means pass-by-copy)

  • 在往方法传递对象引用变量(某个类的类型变量),而不是原生类型变量时,情况就比较复杂了。但是仍然是值传递。Java中的参数传递,全都是值传递,传递的是对象地址(指针)的一个拷贝。

  • 方法只能声明一个返回值。对于同一类型的几个值,可以返回一个数组。对于要返回不同类型的几个值,情况则稍微复杂。后续章节中讲到 ArrayList 时,会讲到这个问题。

  • 可以返回任何的可 隐式 提升到所声明的返回值类型的值(Anything could be implicitly prometed to the type declared, can be returned as the return value)。因此就可以把一个 byte 类型的值,作为 int 类型,返回给调用者。函数调用者不会 care 这个,因为 byte 类型恰好与 int 是兼容的,调用者就会把其作为返回赋值。在所声明的类型比返回值的空间要大的时候,就要 显式 的进行截取了。

  • 可以不理会被调用方法的返回值。不必接收返回值。

  • GettersSetters,访问器与修改器,从对象中获取或设置实例变量(对象属性,attributes)。访问器的唯一目的,就是取得某个实例变量的值。

  • 封装(encapsulation),特指类的封装。定义/编写类/类型(class/type)的时候,将实例变量标记为 private,将访问器和修改器标记为 public。避免外部直接接触到对象的实例变量(instance variables, 属性,attributes)。

  • 封装给对象的实例变量装上了金钟罩,从此就没有人能把 不恰当(inappropriate) 的值设置给他们了。

  • 大多数实例变量,都硬编码了其值的范围确定的具体条件。比如说,如果允许负数出现,那么所有事情都将崩溃。淋浴房的数量、飞机的航速、生日、杠铃重量、手机号码、微波炉功率等等....

  • 通过强制其他代码通过修改器(setter)检查,来为实例变量设置边界。修改器可以对参数进行检查,从而确定是否可行。也许修改器会拒绝而什么也不干,或者将抛出一个例外(Exception,比如对于某个信用卡应用来说无效的社保编号),或者修改器会把传递进来的参数,按照最接近的可接受值进行保留取值。关键是,可以在修改器方法中,做任何想要的操作。相反如果实例变量是 public 的话,就什么也做不了了。

  • 修改器的要点(同时访问器也是),就是 可以在不破坏外部代码的情况下,于后期改变主意!封装的价值就在于,你可以改变主意,没有人会受伤害。直接去使用实例变量所能得到的性能优势,相对使用封装所带来的好处,简直不值一提。

实例变量总是会获得一个默认值,在没有显示地给某个实例变量赋值,也没有调用修改器的时候,实例变量仍然有着一个值!

类型默认值
整数0
浮点数0.0
逻辑值false
引用(references)null

实例变量与本地变量的不同之处

  • 实例变量是在类中、方法之外声明的。
  • 本地变量是在方法中所声明的。
  • 本地变量在使用前必须被初始化!

本地变量不会获取到一个默认值!在变量尚未初始化之前就使用加以使用,编译器就会报出错误。

变量的比较(包括原生变量与引用变量)

使用 == 来比较两个原生变量

== 可用于比较任何类型的原生变量,只是简单的对数据位(bits)进行比较。if (a==b){...}就是去查看ab中的数据位,如果二者的位模式一致,就返回 true(他不会关心变量的尺寸,因此变量左侧的那些额外的0就没有关系)。

int a = 3;
byte b = 3;
if (a==b) {// true}

要检查两个引用变量是否同样(就是说他们是否是内存堆上同一对象的引用),也是使用 ==

对于原生变量和引用变量来说,==运算符都是只关心变量中的数据位模式。因此在两个引用变量都是指向同一个对象时,将返回 true!就算我们不知道引用变量的位模式(bit pattern)具体是怎样的(因为这取决于 JVM,对我们是隐藏的),但我们是知道他看起来是怎样的,两个指向同一对象的引用,将是相同的

Foo a = new Foo ();
Foo b = new Foo ();
Foo c = a;

if (a == b) { // false }
if (a == c) { // true } 
if (b == c) { // false }
问题答案
类可以有着任意数量的。实例变量,访问器,修改器,方法
方法只能有一个的。return
可以隐式提升的(This can be implicitly promoted)。return, argument
优先使用私有的实例变量(Prefer instance variables private)。封装
就是要“生成一份拷贝”(It really means 'make a copy')。值传递
只能由修改器来更新。实例变量
方法可以后多个的。参数
根据定义返回一些东西。访问器(getter)
不应和实例便利一起使用的。public
可以有多个参数方法
有助于建立良好封装的。访问器,修改器,public, private
总是独行的(I always fly solo)。return
Last change: 2023-03-27, commit: 27da5d6