本文总结源自《Java语言程序设计》原书第五版,作者为Y.daniel Liang,习题及编程练习均参照此书。
主要内容
面向对象程序设计把数据和属于它们的操作放入一个叫做对象(object)
的整体中,所有对象都与属性和活动联系在一起,这样做使程序更容易开发和维护。
本章将介绍面向对象程序设计的基本知识:声明类、创建对象、处理对象以及组织对象协调工作。
对象和类
- 对象代表现实世界中可以明确表示的一个整体。对戏那个有自己独特的特性、状态和行为。对象的
状态(state)
是由具有当前值的数据域(data field,又称为属性)
的集合构成的。对象的行为(behavior)
是方法(methed)
的集合定义的。 类(class)
是定义同一类型对象的结构。在Java的类中,数据用来描述属性,方法用来定义行为。
类提供构造方法(constructor)
,调用它可以创建类的对象。构造方法是用来进行初始化操作的。- 包含main方法的类称为
主类(main class)
。
构造方法
- 构造方法必须与定义它的类有完全相同的名字。构造方法可以重载,方便使用不同的初始数据值来构造对象。
- 构造方法没有返回类型,甚至连
void
也没有。 - 构造方法分为
有参构造方法
和无参构造方法
。后者在类中没有明确声明构造方法时会自动生成,以避免程序出错。无参构造方法称为默认构造方法
。 - 构造方法的调用是在创建一个对象时使用
new
操作符进行的。
类是一个蓝本,定义对象的数据和方法。一个对象是类的一个实例。可以从一个类中创建多个实例。创建的一个实例被称为实例化(instantiation)
。对象(object)
和实例(instance)
两个词语经常互换使用。
对象的访问
新创建的对象在内存中占用空间,通过访问对象的
引用变量
来访问,该变量仅包含对象的引用地址。
一个类所定义的类型被称为引用类型(reference type)
。1String str;访问新创建的对象的数据和方法:
12objectRefVar.data------引用对象的数据。objectRefVar.method------引用对象的方法。当创建一个对象,但不赋给这个对象任何引用变量,那么这样创建的对象称为
匿名(anonymous)
对象。- 基本数据类型变量和引用类型变量的区别
- 基本数据类型在内存中存储时就是基本类型的数据,但是引用类型在内存中存储的是一个引用,指向对象的存储地址。
- 将一个基本数据类型变量赋值给另一个变量时,这个变量也有了相同的值。但将一个引用类型变量赋值给另一个变量时,这个变量仅拥有原来对象的引用。
可见性修饰符、访问器和修改器
Java提供了几个修饰符,用来控制对数据、方法和类的访问。
- public 使类、方法和数据域可以在任何类中访问。
- private 使方法和数据域只能从它自己所在类中访问。
- 默认情况下,类、方法和数据域可以从同一个包里的任何类中访问,这时也被称为
包私有的(package-private)
或者包内访问的(package-access)
。 - 一个对象不能访问自己类中的私有成员。但是,如果对象是在自己类内声明的则可以。1234567891011121314151617181920212223// 对象在自己类中声明,正确public class Foo {private boolean x;public static void main(String[] args) {Foo foo = new Foo();System.out.println(foo.x);System.out.println(foo.convert(foo.x));}private int convert(boolean b) {return x?1:-1;}}//对象不在自己类中声明,无法访问私有成员public class Test {public static void main(String[] args) {Foo foo = new Foo();System.out.println(foo.x);System.out.println(foo.convert(foo.x));}}
- 修饰符private只修饰数据和方法,不修饰整个类(内部类除外)。
- 大多数情况下,构造方法应该是公用的(public)。但是,如果不想让用户创建某个类的实例,可以使用私有的构造方法。例如:Math类。
数据域的封装(data field encapsulation)
- 为了避免通过对象引用直接修改属性,应该使用private修饰符声明私有域。
- get()方法称为读取器(getter)或访问器(accessor),set()方法称为设置器(setter)或修改器(mutator)。
- 使用数据域封装使类更加容易维护。
永久对象和类
- 如果一个对象一旦被创建,它的内容就不能再改变,那么该对象就称为
永久对象(immutable object)
,它的类称为永久类(immutable class)
。 - 一个类的所有数据都是私有的并且没有修改器,但它不一定是永久类。1//todo
要使一个类成为永久类,必须将所有数据域说明为私有的,并且不含返回引用非永久对象数据域的修改器和访问器。
给方法传递对象参数
- 传递对象实际上是传递对象的引用(copy referance);传递基本数据类型的参数时,传递的是实参的值。(copy value)
静态变量、常量和静态方法
- 实例变量不能被同一个类中的多个对象共享,
静态变量(static variavle,又称为类变量)
可以让一个类中的所有实例共享数据。 - 静态变量存储在类的公用内存中,如果某个对象修改了静态变量的值,同一类中的所有对象都会受到影响。
- 使用修饰符
static
声明静态变量或静态方法。
变量的作用域
- 类的实例变量和静态变量称为
类属变量(class's variavble,常称为类变量)
或数据域(data field)
。
定义在方法内部的变量称为局部变量。 - 类属变量的作用域是整个类,局部变量的作用域是方法体内。
- 如果局部变量和一个类属变量具有相同的名字,那么局部变量优先,同名的类属变量将会被隐藏。(就近原则)
this关键字
有时需要在方法中引用类属的隐藏变量(hidden variable)
。
- 隐藏的静态变量可以通过“类名.静态变量”的方式引用。隐藏的实例变量需要使用关键字
this
来引用。
对象数组
数组中的元素可以为对象,要初始化对象数组,可以使用for循环。123for(int i=0; i < 10; i++) { Objects[i] = new Object();}
类的抽象和封装
类抽象(class abstraction)
是将类的实现和使用分离。类的创建者提供了类的描述,让使用者明白如何使用类。从类外可以访问的方法和数据域的全体,以及对这些成员如何使用的描述,合称为类的合约(class's contract)
。类的封装(class encapsulation)
是将类的实现细节包装好,对用户隐藏起来,用户不需要知道如何实现的,仅需要知道如何使用即可。
内部类
内部类(inner class)
或者叫嵌入类(nested class)
,是一种在其他类的内部定义的类。- 内部类可以引用包含在它的外部类中的数据和方法。
- 内部类只是用来支持其外部类的工作。
- 内部类可以声明为public、protected或private,其意义与用在类的其他成员上相同。
- 内部类可以声明为静态的static。可以使用外部类的类名来访问静态的内部类,静态内部类不能访问外部类的非静态成员。
从另外的类中创建内部类的对象:
如果内部类是非静态的,必须先创建外部类的实例,然后使用如下语法:
1外部类.内部类 内部类对象名 = 外部类对象.new 内部类();如果内部类是静态的,使用如下语法:
1外部类.内部类 内部类对象名 = new 外部类对象.内部类();
复习小结
- 在面向过程程序设计语言中,数据和方法是分离的,但是在面向对象语言中,数据和方法定义在同一个类当中。
- 引用型数据的默认值是
null
,数值型的默认值是0
,boolean型的默认值是false
,char型的默认值是‘\u0000’
。 - 通过引用变量引用一个对象之前,必须先创建该对象。如果引用一个没有创建的对象,会引起运行错误
NullPointerException
。 - 通过数据域的封装,原类中的数据不会被改变,仅在外部类调用时临时修改。
- 如何判断一个变量或方法定义为实例的还是静态的?
如果一个变量或方法依赖于类的具体实例,应该定义为实例变量或实例方法。如果一个变量或方法不依赖羽类的具体实例,就该定义为静态变量或静态方法。 - 如何在内存中区分对象和类?
- 类是静态的概念,位于代码区
- 对象是new出来的,位于堆内存。类的每个成员变量在不同的对象中都有不同的值(除了静态变量),而方法只有一份,执行的时候才占用内存。
堆内存是程序运行时动态分配的内存。
- 非静态方法是依据不同的对象进行调用。
- 静态成员变量存在于
data seg
区。
编程练习
习题6.1 6.3 6.5 6.7 6.8 6.11 6.12 6.13源代码见我的Github: chapter6