第九章
9.1 引言
9.2 为对象定义类
类:
类可以储存同类型的对象,例如圆就是一个类
(ClassName: Circle)
对象:
创建对象的过程被称为实例化,一个对象有自己的数据域(字段),例如圆的数据域是半径
(ClassName: Circle - Circle Object: 01 - Data Fields: radius)
方法:
方法可以要求对象完成某个动作,例如求圆的周长和面积
构造方法:
调用构造方法可以创建一个新对象,设计构造方法是为了初始化动作:例如,初始化圆的数据域(半径)
UML(统一建模语言)类图:
数据域:dataFieldName: dataFieldType
构造方法:ClassName(parameterName: parameterType)
方法:methodName(parameterName: parameterType): returnType
9.3 示例:定义类和创建对象
面向对象编程中,main主类的唯一目的就是测试定义类(例如:圆类),这种其他类被称为主类的客户
Java编译器在编译**.java文件时,会生成一个主类.class文件和一个定义类.class**文件
可以创建若干个对象,并通过自定义的变量进行引用
对象有独立的数据域,但是可以使用相同的方法
可以通过对象的引用.数据域来访问对象的数据域,可以通过对象的引用.方法来调用对象的方法
9.4 使用构造方法构造对象
构造方法语法:
public ClassName() {
}
调用构造方法语法:
ClassName ObjectRefVar = new ClassName(arguments);
构造方法在使用new操作符创建对象的时候被调用(初始化对象)
当类中没有明确定义任何构造方法时,编译器会自动生成一个默认构造方法,它没有参数,因为也被称为无参构造方法
9.5 通过引用变量访问对象
新创建的对象在内存中被分配空间
9.5.1 引用变量和引用类型
本质上来说,类是一种引用类型(referencetype), 这意味着该类类型的变量都可以引用该类的一个实例,例如
Circle myCircle = new Circle();
引用变量myCircle中放的是一个Circle对象的引用
严格意义上讲,对象的引用变量和对象是不同的,但是这种差异是可以忽略的,因此可以简单地说,myCircle是一个Circle对象
9.5.2 访问对象的数据和方法
对象的数据和方法可以运用点操作符(.)通过对象的引用变量进行访问
引用对象数据域
objectRefVar.dataField
调用对象方法
objectRefVar.method(arguments)
匿名对象
//一个对象在创建之后不需要引用,这种对象称为匿名对象
System.out.println("Area is " + new Circle(5).getArea());
数据域radius称作实例变量(instance variable), 因为它依赖于某个具体的实例。
基于同样的原因,getArea方法称为实例方法(instance method), 因为只能在具体的实例上调用它。
调用对象上的实例方法的过程称为调用对象(calling object)。
Math类中,所有的方法都是静态方法,因此可以直接用类名调用,例如Math.pow()
但是对于实例方法而言,实例方法是非静态的,必须使用objectRefVar.method(arguments)的方式去调用
9.5.3 引用数据域和null值
数组是对象,String是类,类是一种引用类型
数据域的引用变量也可以是String引用类型的
9.5.4 基本类型变量和引用类型变量的区别
每个变量都代表一个存储值的内存位置
如图所示,对基本类型变量来说,对应内存所存储的值是基本类型值;对引用类型变量来说,对应内存所存储的值是一个引用,是对象的存储地址
如果所示,将一个变量赋值给另一个变量时,对基本类型变量而言,就是将一个变量的实际值赋给另一个变量;对引用类型变量而言,就是将一个变量的引用赋给另一个变量
现在,c1以前引用的对象就会成为垃圾,会被Java运行系统自动回收
所以,如果不再需要每个对象,可以显式的给对象的引用变量赋值null。如 果该对象没有被任何引用变量所引用,Java虚拟机将自动回收它所占的空间。
9.6 使用Java库中的类
java.util.Date
java.util.Random
javafx.geometry.Point2D
9.7 静态变量、常量和方法
9.7.1 静态变量
对于实例变量(如Circle类中的radius),是绑定到某个特定实例的,每个实例都储存在不同的内存位置
对于静态变量(或称类变量),是所有实例共享的,储存在一个公共的内存地址
无static的字段就是实例变量,static字段就是静态变量
创建静态变量语法:
static variableType name;
创建静态变量例子:
static int numberOfObjects;
调用静态变量可以使用类名.静态变量名
,例如
CircleWithStaticMembers.numberOfObjects
虽然可以使用实例变量名.静态变量名
(但是最好不要这么写,因为静态变量并不属于实例变量,只是编译器可以自动转化为类名.静态变量名
)
c1.numberOfObjects
9.7.2 静态方法
静态方法不能访问类中的实例成员,无须创建类的实例就可以调用静态方法
静态方法内部,无法访问this
变量,也无法访问实例字段,它只能访问静态字段
创建静态方法语法:
static variableType methodName() {
return staticVariableName
}
例子:
static int getNumberObjects() {
return numberOfObjects;
}
调用静态方法使用类名.方法名(参数)
,例如
CircleWithStaticMembers.getNumberOfObjects()
最好通过类名去访问静态方法和静态变量,不要通过实例变量去访问静态变量和静态方法,否则会得到一个编译警告,编译器自动帮我们把实例变量改写成类名
通过类名只能访问静态方法和静态变量,不可以访问实例变量和实例方法
//最好不要这样
c1.getNumberOfObjects()
也可以使用
CircleWithStaticMembers.getNumberOfObjects
实例方法可以调用实例方法和静态方法,以及访问实例数据域或者静态数据域。
静态方法可以调用静态方法以及访问静态数据域。然而,静态方法不能调用实例方法或者访问实例数据域
9.7.3 常量
常量应该使用final static修饰,是被该类当中所有的对象共享的
声明常量语法举例
final static double PI = 3.14159265
9.8 可见性修饰符
9.8.1 public修饰符
可以在类、方法和数据域前使用public修饰符,表示它们可以被任何其他的类访问
如果没有使用可见性修饰符 ,那么则默认类 、方法和数据域是可以被同一个包中的任何一个类访问的。这称作包私有(package private)或包内访问(package access)
**包可以用来组织类。**为了完成这个目标,需要在程序中首先出现下面这行语句,在这行语句之前不能有注释也不能有空白:
package packageName;
如果定义类时没有声明包,就表示把它放在默认包中。Java建议最好将类放入包中,而不要使用默认包。
9.8.2 private修饰符
private修饰符限定方法和数据域只能在它自己的类中被访问。
在同一个包内,不管有没有public修饰符,都可以在不同的类中,实现数据域和方法的访问;
在不同的包中,只有显式的标识public修饰符的字段和方法,才可以被另一个类访问
在同一个包内,不管有没有public修饰符,类和类之间都可以互相访问
在不同的包中,只有显式的标识public修饰符类,才可以被另一个类访问
修饰符private只能应用在类的成员上。修饰符public可以应用在类或类的成员上。在局部变量上使用修饰符public和private都会导致编译错误。
9.9数据域封装
为了避免对数据域的直接修改,应该使用private修饰符将数据域声明为私有的,这称为数据域封装
为了能够访问私有数据域,可以提供一个get方法返回数据域的值,也可以提供一个set方法给数据域设置新值。get方法也被称为访问器(accessor), 而set方法称为修改器(mutator)。
get方法签名:
public returnType getPropertyName()
//如果返回值类型是boolean型,习惯上如下定义get方法:
public boolean isPropertyName()
set方法签名:
public void setPropertyName(dataType propertyValue)
9.10 向方法传递对象参数
传递基本数据类型参数时,传递的是实参的值,可以认为,方法复制了参数,双方各自的后续修改,互不影响
传递引用类型的参数时,传递的是对象的引用,方法内部和对象引用变量都指向一个对象,所以修改其中一个,就会牵一发而动全身
9.11 对象数组
数组既可以储存基本类型值,也可以储存对象
当使用new操作符创建对象数组后 ,这个数组中的每个元素都是默认值为null的对象的引用变量
如果引用变量是null,访问其字段或引用其方法会导致空指针异常NPE
9.12 不可变对象和类
要使一个类成为不可变的,它必须满足下面的要求:
·所有数据域都是私有的。
·没有修改器方法。
·没有一个返回指向可变数据域的引用的访问器方法。
9.13 变置的作用域
—个类的实例变量和静态变量称为类变量(class’s variables)或数据域(data field)。无论在何处声明,类变量的作用域都是整个类。
方法内部定义的变量称为局部变量。
类的变量和方法可以在类中以任意顺序出现,只有一种情况例外,如下图
类变量只能声明一次,如果一个局部变量和一个类变量具有相同的名字,那么局部变量优先,而同名的类变量将被隐藏
9.14 this引用
this关键字有两个作用
使用this引用隐藏数据域
当类变量(或数据域)与局部变量命名冲突时,会优先考虑局部变量,同名的类变量会被隐藏
而在set方法中,很容易定义一个与类变量(或数据域)同名的局部变量,此时类变量就会被隐藏,此时如果想给类变量赋值,就可以使用this定位到相应的对象
使用this调用构造方法
为了易于代码的阅读和维护,如果一个类有多个构造方法,应该尽可能在参数较少的构造方法中使用this,来调用参数较多的构造方法(要注意,java要求,this应该出现在构造方法中其他可执行语句之前)