《面向对象的思考过程(原书第4版)》一3.3 作用域的重要性

简介: 单个类可以实例化出多个对象。每个对象有唯一的标识和状态。这点很关键。会给每个单独构造的对象会分配独立的内存。然而,一个类实例化的多个对象可以共享类中一些属性和方法,从而共享为这些属性和方法分配的内存。

本节书摘来自华章出版社《面向对象的思考过程(原书第4版)》一书中的第3章,第3.3节,[美] 马特·魏斯费尔德(Matt Weisfeld) 著黄博文 译更多章节内容可以访问云栖社区“华章计算机”公众号查看。

3.3 作用域的重要性

单个类可以实例化出多个对象。每个对象有唯一的标识和状态。这点很关键。会给每个单独构造的对象会分配独立的内存。然而,一个类实例化的多个对象可以共享类中一些属性和方法,从而共享为这些属性和方法分配的内存。
共享方法
构造函数是一个被类的所有实例共享的方法,这是共享方法的一个好例子。
方法代表了对象的行为,属性代表了对象的状态。对象有三种属性:
局部属性。
对象属性。
类属性。

3.3.1 局部属性?

局部属性由特定的方法拥有。请看以下代码:
q1

方法method1包含了一个名为count的局部变量。只能在method1中访问该整数。method2甚至不知道整数count的存在。?
基于该点,我们引入了一个非常重要的概念:作用域。属性(和方法)存在于特定的作用域中。在本例中,整数count存在于method1的作用域中。在Java、C#、C++和Objective-C中,使用花括号({})来定义作用域。在Number类中,通过匹配花括号可以得到几个作用域。
类自身拥有作用域。类的每个实例(即每个对象)也有自己的作用域。method1和method2也拥有各自的作用域。因为count存活于method1的花括号中,所以当调用method1时,会创建count的一个副本。当method1终结时,会删除count的这个副本。
为了让事情更有趣,请看以下代码:
q2
在本例中有两个count的副本存在于该类中。请记住,method1和method2拥有各自的作用域。因此编译器可以简单通过分辨count所在的方法来确定对count的可访问性。你可以这样认为:
q3
就编译器来说,即使这两个属性的名字是一样的,也很容易区分彼此。这就好比两个人拥有相同的名,但是他们的姓不一样,所以他们是独立的个体。

3.3.2 对象属性

在很多设计场景中,可以在同一个对象中的多个方法中共享属性。例如图3-6,从单个类中构造出了三个对象。请看以下代码:
q4_1
![q4_2](https://yqfile.alicdn.com/b7b72badb3089cc
de59ba1f51227afe6c819718a.png)
注意,该类中对属性count的声明放在方法method1和method2的作用域之外。然而,它在该类的作用域之内。因此,count对于method1和method2都是可见的。(基本上,该类中的所有方法都可以访问这个属性)。请注意,两个方法中的代码都指定了count的值。整个对象只有一份count副本,所以两个赋值行为操作的是内存中的同一份副本。然而,不同的对象并不共享count的副本。


7e6a7f5290c1b0b8892d3e2691ab61cd3489782f



我们创建了Number类的三个实例副本来进行演示:
q5
number1、number2、number3这三个对象都是单独构造的,而且都单独分配了自己的资源。整数count有三个独立的实例。当number1修改了自身的属性count时,不会影响对象number2和number3中的count副本。因此整数count是对象属性。
可以通过以下代码来理解作用域:
q6

每个对象对于count有三个完全独立的内存位置。对象Number拥有一份副本,method1()和method2()也各自拥有一份副本。
为了从其中一个方法(比如method1())访问对象属性,可以使用一个基于C语言的名为this的指针:
q7
请注意,一些代码有些奇怪:
q9

以上代码需要使用this关键字。我们必须使用它。这里使用this关键字指导编译器访问对象属性count,而不是方法体中的局部变量count。
注意
关键字this是对当前对象的一个引用。

3.3.3 类属性

正如之前提到的一样,两个或多个对象之间可以共享属性。在Java、C#、C++和Objective-C中,可以把属性设置为static:
q10
声明count为static类型,那么从该类中实例化的所有对象只会为该属性分配一块单独的内存。即该类的所有对象对count使用同一块内存位置。事实上,每个类只有一个副本,该类的所有对象共享该副本(如图3-7所示)。这与我们在面向对象设计中所说的全局数据很相似。


08e7f83188b9970fdaa20fc1cb1c141529d04616



类属性具有很多实用的用途;然而,你必须要了解潜在的同步问题。我们来初始化两个Count对象:
q11
为便于讨论,Count1对象使用count来记录计算机屏幕上的像素。如果Count2对象决定使用属性count来记录绵羊个数就会出问题。Count2记下了第一只羊的瞬间,Count1保存的数据会丢失掉。
相关文章
|
5天前
|
存储 JavaScript 前端开发
块级作用域和函数作用域的区别在哪些方面会对性能产生影响?
【10月更文挑战第29天】块级作用域和函数作用域在变量查找效率、内存管理、闭包、代码执行顺序以及作用域链维护等方面的区别,都会在不同程度上对性能产生影响。在实际开发中,需要根据具体的代码逻辑、应用场景和性能需求,合理地选择和运用这两种作用域,以达到最佳的性能和代码质量平衡。
|
28天前
|
存储 前端开发 JavaScript
前端必备知识:闭包的概念、作用与应用
前端必备知识:闭包的概念、作用与应用
16 1
|
6月前
|
设计模式 存储 安全
【C++ 基本概念】C++编程三剑客:模板、多态与泛型编程的交织与差异
【C++ 基本概念】C++编程三剑客:模板、多态与泛型编程的交织与差异
374 0
|
6月前
|
自然语言处理 JavaScript 前端开发
JavaScript开发基础问题:如何理解闭包及其作用?
JavaScript开发基础问题:如何理解闭包及其作用?
58 5
代码中变量的重要性
代码中变量的重要性
68 0
|
人工智能 大数据 Scala
函数的必要性和学习方法|学习笔记
快速学习函数的必要性和学习方法。
101 0
函数的必要性和学习方法|学习笔记
|
Java
一个小例子体会Java反射的动态性
一个小例子体会Java反射的动态性
108 0
|
敏捷开发 前端开发 测试技术
用“实例化需求”,让需求澄清更高效(下)
用“实例化需求”,让需求澄清更高效(下)
335 0
用“实例化需求”,让需求澄清更高效(下)
|
测试技术 领域建模 数据安全/隐私保护
用“实例化需求”,让需求澄清更高效(上)
用“实例化需求”,让需求澄清更高效(上)
626 0
用“实例化需求”,让需求澄清更高效(上)
下一篇
无影云桌面