对象和类
面向对象编程可以有效地帮助开发大规模的软件以及图形用户界面。
面向对象程序设计有助于更有效地开发 GUI (图形用户界面) 和大型软件系统。
为对象定义类
类为对象定义属性和方法。
面向对象程序设计 (OOP) 就是使用对象进行程序设计。对象 (object) 代表现实世界中可以明确标识的一个实体。
每个对象都有自己独特的标识、状态和行为.
- 一个对象的状态 (state,也称为特征 (property) 或属性 (attribute) ) 是由具有当前值的数据域来表示的。
- 一个对象的行为 (behavior, 也称为动作 (action) ) 是由方法定义的。调用对象的一个方法就是要求对象完成一个动作。
使用一个通用类来定义同一类型的对象。类是一个模板、蓝本或者说是合约,用来定义对象的数据域以及方法。一个对象是类的一个实例,可以从一个类中创建多个实例。创建实例的过程称为实例化 (instantiation)。对象 (object) 和实例 (instance) 经常是可以互换的。
Java 类使用变量定义数据域,使用方法定义动作。除此之外,类还提供了一种称为构造方法 (constructor) 的特殊类型的方法,调用它可以创建一个新对象。构造方法本身是可以完成任何动作的,但是设计构造方法是为了完成初始化动作。例如:初始化对象的数据域。
包含 main 方法的类称为主类 (main class) 。
类的模板和对象的图示可以使用统一建模语言 (UML)的图形符号进行标准化。
这种表示方法称为 UML 类图 (UML class diagram), 或简称为类图 (class diagram)。在类图中,数据域表示为:
dataFieldName: dataFieldType
构造方法可以表示为:
ClassName(parameterName: parameterType)
方法可以表示为:
methodNameCparameterName: parameterType): returnType
定义类和创建对象
类是对象的定义,对象从类创建。
可以把两个类放在同一个文件中,但是文件中只能有一个类是公共 (public) 类。此外,公共类必须与文件同名。
使用这样的类的程序通常称为该类的客户 (client) 。运行这个程序时,Java 运行系统会调用这个主类的 main 方法。
使用构造方法构造对象
构造方法在使用 new 操作符创建对象的时候被调用。
构造方法是一种特殊的方法。它们有以下三个特殊性:
- 构造方法必须具备和所在类相同的名字。
- 构造方法没有返回值类型,甚至连 void 也没有。
- 造方法是在创建一个对象使用 new 操作符时调用的。构造方法的作用是初始化对象。
构造方法具有和定义它的类完全相同的名字。和所有其他方法一样,构造方法也可以重载 (可以有多个同名的构造方法,但它们要有不同的签名) ,这样更易于用不同的初始数据值来构造对象。
错误: 将关键字 void 放在构造方法的前面。
构造方法是用来构造对象的。为了能够从一个类构造对象,使用 new 操作符调用这个类的构造方法,如下所示:
new ClassName(arguments);
通常,一个类会提供一个没有参数的构造方法。这样的构造方法称为无参构造方法(no-arg 或 no-argument constructor) 。一个类可以不定义构造方法。在这种情况下,类中隐含定义一个方法体为空的无参构造方法。这个构造方法称为默认构造方法 (default constructor),当且仅当类中没有明确定义任何构造方法时才会自动提供它。
通过引用变量访问对象
对象的数据和方法可以用点操作符 (.) 通过对象的引用变量进行访问。
新创建的对象在内存中被分配空间。它们可以通过引用变量来访问。
引用变量和引用类型
对象是通过对象引用变量 (reference variable) 来访问的,该变量包含对对象的引用,使用如下语法格式声明这样的变量:
ClassName objectRefVar;
本质上来说,一个类是一个程序员定义的类型。类是一种引用类型 (reference type),这意味着该类类型的变量都可以引用该类的一个实例。
从表面上看,对象引用变量中似乎存放了一个对象,但事实上,它只是包含了对该对象的引用。严格地讲,对象引用变量和对象是不同的,但是多数情况下,这种差异是可以忽略的。
在 Java 中,数组被看作是对象。数组是用 new 操作符创建的。一个数组变量实际上是一个包含数组引用的量。
访问对象的数据和方法
在面向对象编程中,对象成员可以引用该对象的数据域和方法。在创建一个对象之后,它的数据和方法可以使用点操作符 (.) 来访问和调用,该操作符也称为对象成员访问操作符 (object member access operator) :
- objectRefVar.dataField 引用对象的数据域。
- objectRefVar.method(arguments) 调用对象的方法。
实例变量 (instance variable) 依赖于某个具体的实例。实例方法 (instance method) 只能在具体的实例上调用它。调用对象上的实例方法的过程称为调用对象 (calling object) 。
通常,我们创建一个对象,然后将它赋值给一个变量,之后就可以使用这个变量来引用对象。有时候,一个对象在创建之后并不需要引用。在这种情况下,可以创建一个对象,而并不将它明确地赋值给一个变量。这种方式创建的对象称为匿名对象 (anonymous object) 。
引用数据域和 null 值
数据域也可能是引用型的。
如果一个引用类型的数据域没有引用任何对象,那么这个数据域就有一个特殊的 Java 值 null 。null 同 true 和 false 一样都是直接量。true 和 false 是 boolean 类型直接量,而 null 是引用类型直接量。
引用类型数据域的默认值是 null , 数值类型数据域的默认值是 0 , boolean 类型数据域的默认值是 false , 而 char 类型数据域的默认值是 ‘\u000’ 。但是,Java 没有给方法中的局部变置赋默认值。
警告: NullPointerException 是一种常见的运行时错误,当调用值为 null 的引用变量上的方法时会发生此类异常。在通过引用变量调用一个方法之前,确保先将对象引用赋值给这个变量。
基本类型变量和引用类型变量的区别
每个变量都代表一个存储值的内存位置。声明一个变量时,就是在告诉编译器这个变量可以存放什么类型的值。对基本类型变量来说,对应内存所存储的值是基本类型值。对引用类型变量来说,对应内存所存储的值是一个引用,是对象的存储地址。
基本类型变量在内存中存储的是一个基本类型值,而引用类型变量存储的是一个引用,它指向对象在内存中的位置。
将一个变量赋值给另一个变量时,另一个变量就被赋予同样的值。对基本类型变量而言,就是将一个变量的实际值陚给另一个变量。对引用类型变量而言,就是将一个变量的引用赋给另一个变量。
引用类型的对象就不再有用,就会成为垃圾 (garbage) 。垃圾会占用内存空间。Java 运行系统会检测垃圾并自动回收它所占的空间,这个过程称为垃圾回收 (garbage collection) 。如果不再需要某个对象时,可以显式地给该对象的引用变量赋 null 值。如该对象没有被任何引用变量所引用,Java 虚拟机将自动回收它所占的空间。
使用 Java 库中的类
Java API 包含了丰富的类的集合,用于开发 Java 程序。
Date 类
使用 System.currentTimeMillis() 来获得当前时间。使用除法和求余运算分解出当前的秒数、分钟数和小时数。Java 在 java.util.Date 类中还提供了与系统无关的对日期和时间的封装。
可以使用 Date 类中的无参构造方法为当前的日期和时间创建一个实例,它的 getTime() 方法返回自从 GMT 时间 1970 年 1 月 1 日算起至今流逝的时间,它的 toSting() 方法返回日期和时间的字符串。
Date 类还有另外一个构造方法:Date(long elapseTime) , 可以用它创建一个 Date 对象。该对象有一个从 GMT 时间 1970 年 1 月 1 日算起至今流逝的以毫秒为单位的给定时间。
Random 类
可以使用 Math .random() 获取一个 0.0 到1.0 (不包括1.0) 之间的随机 double 型值。另一种产生随机数的方法是使用java.util.Random 类,它可以产生一个 int、long、double、float 和 boolean 型值。
创建一个 Random 对象时,必须指定一个种子或者使用默认的种子。种子是一个用于初始化一个随机数字生成器的数字。无参构造方法使用当前已经逝去的时间作为种子,创建一个 Random 对象。如果这两个 Random 对象有相同的种子,那它们将产生相同的数列。
产生相同随机值序列的能力在软件测试以及其他许多应用中是很有用的。在软件测试中,经常需要从一组固定顺序的随机数中来重复生成测试案例。
Point2D 类
Java AP丨在 javafx.geometry 包中有一个便于使用的 Point2D 类,用于表示二维平面上
的点。
可以为给定 x 和 y 坐标的点来创建一个 Point2D 对象,使用 distance 方法计算该点到另外一个点之间的距离,并且使用 toString() 方法来返回该点的字符串表示。
这个类是 Eclipse 的 JRE 带的,但并不属于 Java 的公开 API 。(JavaSE 1.8 以上版本可用)
静态变量、常量和方法
静态变量被类中的所有对象所共享。静态方法不能访问类中的实例成员,包括实例变量和实例方法。
实例变量是绑定到类的某个特定实例的,它是不能被同一个类的不同对象所共享的。
属于实例的实例变置存储在互不相关的内存中,静态变量是被同一个类的所有实例所共享的。
让一个类的所有实例共享数据,就要使用静态变量 (static variable), 也称为类变量 (class variable) 。静态变量将变量值存储在一个公共的内存地址。因为它是公共的地址,所以如果某一个对象修改了静态变量的值,那么同一个类的所有对象都会受到影响。
Java 支持静态方法和静态变量,无须创建类的实例就可以调用静态方法 (static method) 。
要声明一个静态变量或定义一个静态方法,就要在这个变量或方法的声明中加上修饰符 static 。
注意: 在 UML 类图中,静态变量和静态方法都是以下划线标注的。
类中的常量是被该类的所有对象所共享的。因此,常量应该声明为 final static 。
Math 类中的所有方法都是用关键字 static 定义的静态方法。main 方法也是静态方法。
实例方法和实例数据都是属于实例的,所以它们在实例创建之后才能使用。它们是通过引用变量来访问的。静态方法和静态数据可以通过引用变量或它们的类名来调用。
静态变量和方法可以不在创建对象的情况下访问。
使用 “类名.方法名(参数)” 的方式调用静态方法,使用 “类名.静态变量” 的方式访问静态变量。这会提高可读性,因为可以很容易地识别出类中的静态方法和数据。
实例方法可以调用实例方法和静态方法,以及访问实例数据域或者静态数据域。静态方法可以调用静态方法以及访问静态数据域。然而,静态方法不能调用实例方法或者访问实例数据域,因为静态方法和静态数据域不属于某个特定的对象。
设计指南: 如何判断一个变量或方法应该是实例的还是静态的?
如果一个变量或方法依赖于类的某个具体实例,那就应该将它定义为实例变量或实例方法。如果一个变量或方法不依赖于类的某个具体实例,就应该将它定义为静态变量或静态方法。
在 Math 类中没有一个方法是依赖于一个特定实例的,例如:random、pow、sin 和 cos。因此,这些方法都是静态方法。main 方法也是静态的,可以从类中直接调用。
警告: 一个常见的设计错误就是将一个本应该声明为静态的方法声明为实例方法。
可见性修饰符
可见性修饰符可以用于确定一个类以及它的成员的可见性。
可以在类、方法和数据域前使用 public 修饰符,表示它们可以被任何其他的类访问。如果没有使用可见性修饰符,那么则默认类、方法和数据域是可以被同一个包中的任何一个类访问的。这称作包私有 (package-private) 或包内访问 (package-access)。
注意:包可以用来组织类。为了完成这个目标,需要在程序中首先出现下面这行语句,在这行语句之前不能有注释也不能有空白:
package packageName:
如果定义类时没有声明包,就表示把它放在默认包中。Java 建议最好将类放入包中,而不要使用默认包。
除了 public 和默认可见性修饰符,Java 还为类成员提供 private 和 protected 修饰符。
private 修饰符限定方法和数据域只能在它自己的类中被访问。
如果一个对象是在它自己的类中定义的,那么这个对象可以访问它的私有成员。
私有的修饰符将访问权限限定在它自己的类内,默认修饰符将访问权限限定在包内,而公共的修饰符可以无限制的访问。
如果一个类没有被定义为公共类,那么它只能在同一个包内被访问。
可见性修饰符指明类中的数据域和方法是否能在该类之外被访问。在该类之内,对数据域和方法的访问是没有任何限制的。
警告: 修饰符 private 只能应用在类的成员上。修饰符 public 可以应用在类或类的成员上。在局部变量上使用修饰符 public 和 private 都会导致编译错误。
注意:大多数情况下,构造方法应该是公共的。但是,如果想防止用户创建类的实例,就该使用私有构造方法。
数据域封装
将数据域设为私有保护数据,使类易于维护。
这样做原因有两点:
- 首先,数据不会被篡改。
- 其次,它使类变得易于维护,同时不容易出现错误。
为了避免对数据域的直接修改,应该使用 private 修饰符将数据域声明为私有的,这称为数据域封装 (data field encapsulation)。
在定义私有数据域的类外的对象是不能访问这个数据域的。
但是经常会有客户端需要存取、修改数据域的情况。为了能够访问私有数据域,可以提供一个 get 方法返回数据域的值。为了能够更新一个数据域,可以提供一个 set 方法给数据域设置新值。
get 方法也被称为访问器 (accessor) , 而 set 方法称为修改器 (mutator) 。
- get 方法有如下签名:
public returnType getPropertyName();
- set 方法有如下签名:
public void setPropertyName(dataType propertyValue);
设计指南: 为防止數据被篡改以及使类更易于维护,最好将数据域声明为私有的。
向方法传递对象参数
给方法传递一个对象,是将对象的引用传递给方法。
可以将对象传递给方法。同传递数组一样,传递对象实际上是传递对象的引用。
Java 只有一种参数传递方式:值传递 (pass-by-value) 。
执行程序的过程中的调用堆找。注意,方法是存储再栈中的,对象是存储在堆中的。
当传递基本数据类型参数时,传递的是实参的值。
传递引用类型的参数时,传递的是对象的引用。引用上的传值在语义上最好描述为传共享 (passby-sharing) ,也就是说,在方法中引用的对象和传递的对象是一样的。
对象数组
数组既可以存储基本类型值,也可以存储对象。
对象的数组实际上是引用变量的数组。
当使用 new 操作符创建对象教组后,这个数组中的每个元素都是默认值为 null 的引用变量。
不可变对象和类
可以定义不可变类来产生不可变对象。不可变对象的内容不能被改变。
通常,创建一个对象后,它的内容是允许之后改变的。有时候也需要创建一个一旦创建其内容就不能再改变的对象。我们称这种对象为一个不可变对象 (immutable object) , 而它的类就称为不可变类 (immutable class) 。例如:String 类就是不可变的。
如果一个类是不可变的,那么它的所有数据域必须都是私有的,而且没有对任何一个数据域提供公共的 set 方法。一个类的所有数据都是私有的且没有修改器并不意味着它一定是不可变类。
要使一个类成为不可变的,它必须满足下面的要求:
- 所有数据域都是私有的。
- 没有修改器方法。
- 没有一个返回指向可变数据域的引用的访问器方法。
变置的作用域
实例变量和静态变量的作用域是整个类,无论变量是在哪里声明的。
局部变量的声明和使用都在一个方法的内部。
一个类的实例变量和静态变量称为类变量 (class’s variables) 或数据域 (data field) 。在方法内部定义的变量称为局部变量。
无论在何处声明,类变量的作用域都是整个类。类的变量和方法可以在类中以任意顺序出现。但是当一个数据域是基于对另一个数据域的引用来进行初始化时则不是这样。在这种情况下,必须首先声明另一个数据域。为保持一致性,在类的开头就声明数据域。
类变量只能声明一次,但是在一个方法内不同的非嵌套块中,可以多次声明相同的变量名。
如果一个局部变量和一个类变量具有相同的名字,那么局部变量优先. 而同名的类变量将被隐藏 (hidden) 。
提示: 为避免混淆和错误,除了方法中的参数,不要将实例变量或静态变量的名字作为局部变量名。
this 引用
关键字 this 引用对象自身。它也可以在构造方法内部用于调用同一个类的其他构造方法。
关键字 this 是指向调用对象本身的引用名。可以用 this 关键字引用对象的实例成员。
this引用通常是省略掉的。然而,在引用隐藏数据域以及调用一个重载的构造方法的时候,this 引用是必须的。
使用 this 引用隐藏数据域
this 关键字可以用于引用类的隐藏数据域。
例如,在数据域的 set 方法中,经常将数据域名用作参数名。在这种情况下,这个数据域在 set 方法中被隐藏。为了给它设置新值,需要在方法中引用隐藏的数据域名。
- 隐藏的静态变量可以简单地通过 “类名.静态变量” 的方式引用。
- 隐藏的实例变量就需要使用关键字 this 来引用。
关键字 this 给出一种引用调用实例方法的对象的方法。
使用 this 调用构造方法
关键字 this 可以用于调用同一个类的另一个构造方法。
Java 要求在构造方法中,语句 this(参数列表)应在任何其他可执行语句之前出现。
如果一个类有多个构造方法,最好尽可能使用 this(参数列表)实现它们。通常,无参数或参数少的构造方法可以用 this(参数列表)调用参数多的构造方法。这样做通常可以简化代码,使类易于阅读和维护。
面向对象编程在Java中至关重要,对象代表现实世界的实体,类则是对象的模板。类定义了对象的状态(数据域)和行为(方法),通过构造方法创建对象。对象通过引用变量访问,使用点操作符来调用数据和方法。Java库提供了丰富的预定义类,如Date和Random,用于方便地处理日期、时间和随机数。静态变量和方法属于类本身,不受对象影响,而实例变量和方法与特定对象关联。封装是OOP的重要原则,通过使数据域私有并提供访问器和修改器方法来实现。对象数组允许存储和操作多个对象。不可变对象的类不允许其内容被修改,提供安全性。this关键字用于在类中引用当前对象。

被折叠的 条评论
为什么被折叠?



