第4章 对象与类

4.1 面向对象程序设计概述

4.1.1 类

  • 类(class)是构造对象的模版或蓝图。由类构造(construct)对象的过程称为创建类的实例(instance)。
  • 标准Java库提供几千个类供使用,但还是需要创建自己的类,以描述应用程序所对应的问题域中的对象。
  • 封装(encapsulation,也称为数据隐藏),对对象的使用者隐藏了数据的实现方式。实现封装的关键就是绝不能让其他类的方法访问本类的实例域。封装给对象赋予了黑盒特性。这是提高重用性和可靠性的关键。
  • 对象状态:每个特定对象都有一组特定的实例域(instance field)值,这些值的集合就是这个对象的当前状态。

4.1.2 对象

  • 对象的三个主要特征

1)对象的行为(behavior)

2)对象的状态(state)  ---对象状态的改变,必须通过调用方法实现

3)对象的标识(identity)

4.1.3 识别类

  • 名次对应类
  • 动词对应类的方法

4.1.4 类之间的关系

  • 依赖 dependence(uses-a):如果一个类的方法操作另一个类的对象,我们就说一个类依赖于另一个类。

1)应尽可能将相互依赖的类减至最小。即类之前的耦合度最小。

2)如果类A不知道B的存在,B的改变不会引起A的错误。

  • 聚合aggregation(has-a):类A的对象包含类B的对象。

1)继承inheritance(is-a):用于标识一种特殊与一般的关系。

4.2 使用预定义类

4.2.1 对象与对象变量

  • 首先构造对象 -> 指定其初始状态 -> 对对象应用方法
  • 使用构造器(constructor)构造新实例。用来构造和初始化对象。
  • new操作符返回的也是一个对象的引用。
  • 方法中的局部变量不会自动地初始化为null,而必须通过调用new或将他们设置为null进行初始化。

4.2.2 Java类库中的Gregorian-Calendar类

  • 标准Java类库分别包含了两个类:一个是用来表示时间点的Date类,另一个是用来表示日历表示法的GregorianCalendar

4.2.3 更改器方法和访问器方法

  • 对实例域进行修改的方法称为更改器方法。
  • 仅访问实例域而不进行修改的方法称为访问器方法。

4.3 用户自定义类

  • 在一个Java源文件中,只能有一个public类,但可以有任意多个非公有类。源文件的文件名必须和public类的类名相同。
  • 实例域通常标记为private
  • 类通常包括类型属于某个类类型的实例域
  • 构造器与类同名,并在构造类的对象时,将实例域初始化为希望的状态。
  • 每个类可以有一个以上的构造器
  • 构造器可以有0个、1个及1个以上的参数
  • 构造器没有返回值
  • 构造器总是伴随着new操作一起调用
  • 在类的所有方法中(包括构造器),不要命名与实例域同名的变量,否则在方法内部,会屏蔽掉实例域。
  • 隐式参数与显示参数

public void raiseSalary(double byPercent)

{

double raise = this.salary * byPercent / 100;

this.salary += raise;

}

//raiseSalary方法有两个参数。第一个参数为隐式(implicit)参数,表示该对象本身,第二个参数是在方法名后的参数列表中的数值,称为显示(explicit)参数。在一个方法中,关键字this表示隐式参数。使用this可以将实例域和局部变量明显的区分开来。

  • 不要编写返回引用可变对象的访问器方法,否则会破坏封装性。

class Employee

{

private Date hireDay;

.....

public Date getHireDay(){

return hireDay;

}

}

如果需要返回一个可变对象的引用,应该首先对它进行克隆(clone),对象克隆是指存放在另一个位置上的对象副本。

class Employee

{

......

public Date getHireDay(){

return hireDay.clone();

}

}

  • 基于类的访问权限

方法可以访问所调用对象的私有权限,一个方法可以访问所属类的所有对象的私有数据。

class Employee

{

..........

public  boolean  equals(Employee other){

return name.equals(other.name);

}

}

典型的调用方法,if(harry.equals(boss))....

这个方法访问了harry的私有域,而且还访问了boss的私有域,这是合法的,因为boss是Employee对象,而Employee类的方法可以访问Employee类的任何一个对象的私有域。

  • 只要方法是私有的,类的设计者可以确信,它不会被外部的其他类操作调用,可以将其删除。如果方法是公有的,就不能将其删除,因为其他的代码很可能已经依赖它了。
  • final实例域

可以将实例域定义为final,构建对象时必须初始化这样的域。即,必须确保在每个构造器执行完后,这个域的值被设置。且在后面的操作中不能再对它进行修改。

final修饰符大都应用于基本(primitive)类型域,或不可变类的域。用于可变的类,通常会引起混乱。

  • 不可变(immutable)类的域:如果类中的每个方法都不会改变其对象,这种类就是不可变类。如String类就是不可变类。

4.4 静态域与静态方法

4.4.1 静态域

  • 如果将域定义为static,每个类只有一个这样的域。而每个对象对于所有的实例域却都有自己的一份拷贝。

class Employee

{

private static int nextId = 1; //没这个类的所有实例所共享

private int id;  //每一个雇员对象都有一个自己的id域

public setId(){

id = nextId;

nextId++;

}

}

4.4.2 静态常量

  • 静态变量用的比较少,但静态常量用得比较多

public class Math{

......

public static final double PI = 3.1415926;

......

}

//程序中可以直接采用Math.PI的形式获得这个常量。

  • 另一个经常使用的静态常量是System.out

public class System

{

public static final PrintStream out = ...;

}

4.4.3 静态方法

  • 静态方法是一种不能向对象实施操作的方法。
  • 静态方法没有隐式的参数。
  • 可以认为静态方法是没有this参数的方法。
  • 因为静态方法不能操作对象,所以不能在静态方法中访问实例域。但是静态方法可以访问自身类中的静态域。

public static int getNextId()

{

return nextid; //return static field

}

可以通过类名调用这个方法:

int n= Employee.getNextId();

  • 可以使用对象调用静态方法,但不推荐这样做,容易引起混淆,建议使用类名来调用静态方法。
  • 在下面两种情况下使用静态方法:

1)一个方法不需要访问对象状态,其所需参数都是通过显示参数提供。

2)一个方法只需要访问类的静态域。

4.4.4 工厂方法

  • 静态方法还有一个常见的用途,使用工厂方法产生不同风格的格式对象。

4.4.5 main方法

  • main方法也是一个静态方法。main方法不对任何对象进行操作。事实上,在启动程序时,还没有任何一个对象。静态的main方法将执行并创建程序所需的对象。
  • 每一个类都可以有一个main方法,这是一个常用于对类进行单元测试的技巧。

4.5 方法参数

  • Java总是采用按值调用,即,方法得到的是所有参数值的一个拷贝,特别的,方法不能修改传递给它的任何参数变量的内容。

4.6 对象构造

4.6.1 重载

  • 重载(overloading):多个方法,有相同的名字,不同的参数,便产生了重载。
  • 方法签名(signature):Java允许重载任何方法,而不只是构造器方法。因此完整地描述一个方法,需要指出方法名以及参数类型。这叫做方法签名。
  • 返回类型不是方法签名的一部分,因此,不能有两个名字相同、参数类型也相同,但返回类型不同的方法。

4.6.2 默认域初始化

  • 如果在构造器中,没有显示的给域赋初始值,那么就会被自动地赋予默认值:0、false、null,但这不是好的编程习惯。
  • 但方法中的局部变量,则必须明确的进行初始化,不会像域变量那样被赋予初始值。否则会报错。

4.6.3 无参数的构造器

  • 如果在编写一个类时,没有编写构造器,那么系统就会提供一个无参数的构造器。这个构造器将所有的实例域设置为默认值(0,false,null)。
  • 如果在类中已经提供了至少一个非无参数的构造器,则系统不再自动为该类提供一个无参数的构造器。此时,就不能使用无参数构造器来构造对象。除非自己在类中手动显示地添加一个构造器。

public ClassName()

{

}

//上述构造器构造对象时,会将所有域赋予默认值(0,false,null)

4.6.4 显式域初始化

  • 由于类的构造方法可以重载,所以可以采用多种形式设置类的实例域的初始状态。确保不管怎样调用构造器,每个实例域都可以被设置为一个有意义的初值。
  • 可以在类定义中,直接将一个值赋给任何域。

class Employee

{

private string name = "";

...........

}

//在构造器之前,先执行赋值操作

  • 当一个类的所有构造器,都希望将一个特定的值赋予某个特定的实例域时,这种方式特别有用。

4.6.5 参数名

1) 构造器的参数名用单个字符命名

public Employee(String n, double s)

{

name =  n;

salary = s;

}

//这种方式的缺点是,参数的可读性不佳

2) 构造器的参数名在域名称的基础上加上一个前缀 a

public Employee(String aName,double aSalary)

{

name = aName;

salary = aSalary;

}

3) 构造器的参数名和域名称完全一样

public Employee(String name,double salary)

{

this.name = name;

this.salary = salary;

}

//这种方式会使参数将实例域在构造器内部屏蔽起来,但可以采用this.salary的形式访问实例域。this指示的是方法调用的隐式对象,也就是被构造的对象。

4.6.6 调用另一个构造器

  • 如果构造器的第一个语句形如this(...),这个构造器将调用同一个类的另一个构造器。

public Employee(double salary)

{

this("emp" + nextId, salary);

nextId++;

}

  • 一般都是参数个少的构造器调用参数个数多的构造器。
  • 采用这种方式非常有用,这样对公共的构造器代码编写一次即可。

4.6.7 初始化块

  • 第三种初始化域的机制,初始化块(initialization block),在一个类声明中,可以包含多个代码块,只要构造类的对象,这些块就会被执行。

class Employee

{

private static int nextId;

private int id;

private String name;

private int salary;

{

id = nextId;

nextId++;

}

public Employee(String n, double s)

{

name = n;

salary =s;

}

public Employee()

{

name = "";

salary = 0;

}

}

//无论使用哪个构造器构造对象,id域都在对象初始化块中被初始化。首先运行初始化块,然后再运行构造器的主体部分。

4.6.8 对象析构与finalize方法

  • 由于Java有自动的垃圾回收器,不需要人工回收内存,所以Java不支持析构器。
  • 但,某些对象使用了内存之外的其他资源,如文件或系统资源的另一个对象的句柄。在这种情况下,当资源不再需要时,将其回收或再利用显得十分的重要。
  • 可以为任何一个类添加finalize方法。finalize方法将在垃圾回收器清除对象之前调用。在实际应用中,不要依赖于使用finalize方法回收任何短缺的资源。这是因为很难知道这个方法什么时候才能够调用。
  • 如果某个资源需要在使用完毕后立刻被关闭,那么就需要由人工来管理。对象用完时,可以应用close方法来完成相应的清理操作。

4.7 包

  • Java允许使用包(package)将类组织起来。借助于包可以方便地组织自己的代码,并将自己的代码与别人提供的代码库分开管理。
  • 所有标准的Java包都处于java和javax包层次中。
  • 使用包的主要原因是确保类名的唯一性。Sun公司建议将公司的英特网域名(显然是独一无二的)以逆序的形式作为包名,并且对于不同的项目使用不同的子包。
  • 从编译器的角度来看,嵌套的包之前没有任何关系。如:java.util和java.util.jar包毫无关系,每一个都拥有独立的类集合。

4.7.1 类的导入

  • 一个类能够使用所属包中的所有类,以及其他包中的公有类(public class)。
  • import语句是一种引用包含在包中的类的简明描述。一旦使用了import语句,在使用类时,就不必写出包的全名了。

4.7.2 静态导入

  • import语句不仅可以导入类,还增加了导入静态方法和静态域的功能。

4.7.3 将类放入包中

  • 想将一个类放入包中,就必须将包的名字放在源文件的开头,包中定义类的代码之前。

package com.horstmann.corejava;

public class Employee

{

.....

}

  • 如果没有在源文件中放置package语句,这个源文件中的类就被放置在一个默认包(default package)中。默认包是一个没有名字的包。
  • 将包中的源文件放到与完整的包名匹配的子目录中。例如,com.horstmann.corejava包中的所有源文件应该被放置到com/horstmann.corejava目录中。编译器将class类文件也放在相同的目录结构中。

4.7.4 包作用域

  • 在默认情况下,包不是一个封闭的实体。也就是说,任何人都可以向包中添加更多的类。
  • 可以通过包密封(package sealing)机制将一个包密封起来,就不能向这个包添加类了。
  • 制作包含密封包的JAR文件的方法。

4.8 类路径--目的是让Java程序在运行时,JVM能够顺利找到各个.class类文件

  • 类存储在文件系统的子目录中,类的路径必须和包名匹配
  • 类文件也可以存储在JAR(Java归档)文件中,在一个JAR文件中,可以包含多个压缩形式的类文件和子目录。在程序中用到第三方(third-party)库文件时,通常给出一个或多个需要包含的JAR文件。
  • JDK也提供了许多JAR文件。在jre/lib/rt.jar中包含数千个类库文件。
  • 为了使类能被多个程序共享,需要做到下面几点:

1)把类放到一个目录中,如home/user/classdir,这个目录是包树状结构的基目录

2)将JAR文件放在一个目录中,例如:/home/user/archives

3)设置类路径,类路径是所有包含类文件的路径的集合。

UNIX环境(用冒号分割):

/home/user/classdir:.:/home/user/archives/archive.jar

Windows环境(用分号分割):

c:\classdir;.;c:\archives\archive.jar

上述,句点(.)表示当前目录

  • 可以在JAR文件目录中,指定通配符:表示在归档目录中的所有JAR文件(不包含.class文件)都包含在类路径中。

/home/user/classdir:.:/home/user/archives/‘*‘

c:\classdir;.;c:\archives\*

  • 由于运行时库文件(rt.jar和在jre/lib与jre/lib/ext目录下的一些其他的JAR文件)会被自动搜索,所以不必将他们显示的列在类路径中。
  • javac编译器总是在当前目录中查找文件,但Java虚拟机仅在类路径中有“.”时才查看当前目录。如果没有设置类路径,那也不会产生什么问题,默认的类路径包含“.”目录。但如果设置了类路径,却忘记包含“.”目录,则程序任然可以编译通过,但不能运行。
  • 类路径所列出的目录和归档文件是搜索类的起点。假设虚拟机要寻找某个类com.hostmann.corejava.Employee类文件:

1)首先查看存储在jre/lib和jre/lib/ext目录下的归档文件中所存放的系统类文件。若没找到,则再依次查看类路径:

2)/home/user/classdir/com/hostmann/corejava/Employee.class

3)com/hostmann/corejava/Employee.class 从当前目录开始

4)com/hostmann/corejava/Employee.class inside /home/user/archives/archive.jar

  • 设置类路径

1)最好采用-classpath(或-cp)选项指定类路径:

java -classpath /home/user/classdir:.:/home/user/archives/archive.jar MyProg

java -classpath c:\classidr;.;c:\archives\archive.jar MyProg

2)也可以通过设置classpath环境变量完成这个操作

export CLASSPATH=/home/user/classdir:.:/home/user/archives/archive.jar

set CLASSPATH=c:\classidr;.;c:\archives\archive.jar

知道shell退出,类路径都有效。

4.9 文档注释

  • JDK提供了javadoc工具,用于有源文件生成一个HTML文档。
  • 如果在源文件中添加了以专用的定界符/**开始的注释,就可以很容易的生产一个专业的文档。

4.9.1 注释的插入

  • javadoc工具从下面几个特性中抽取信息

1)包

2)公有类和接口

3)公有的和受保护的构造器和方法

4)公有的和受保护的域

  • 注释以/**开始,以*/结束
  • 每个/**.....*/文档注释在标记之后紧跟着自由格式文本,标记由@开始,如@author 或 @param

4.9.2 类注释

  • 必须放在import语句之后,类定义之前

4.9.3 方法注释

  • 必须放在所描述的方法之前,除了通用的标记外,还可以使用如下标记

1)@param 变量描述

2)@return 描述

3)@throws 类描述

4.9.4 域注释

  • 只需要对公有域(通常指的是静态常量)建立文档

4.9.5 通用注释

  • @author姓名
  • @version文本
  • @since文本
  • @deprecated文本
  • @see 引用

4.9.6 包与概述注释

4.9.7 注释的抽取

4.10 类的设计技巧

  • 一定要保证数据私有,绝对不要破坏封装性
  • 一定要对数据初始化
  • 不要在类中使用过多的基本类型
  • 不是所有的域都需要独立的域访问器和域更改器
  • 将职责过多的类进行分解
  • 类名和方法名要能够体现他们的职责

类名命名的良好习惯:采用一个名词(Order),前面有形容词修饰的名次(RushOrder),或动名词修饰的名次(BuildingAddress)

时间: 2024-08-02 23:00:05

第4章 对象与类的相关文章

第九章 对象和类

对象和类 一 对象和类 类是模子,确定对象将会拥有的特征(属性)和行为(方法): 类是相同属性和方法的一组对象的集合: 类是对象的类型: 1. 属性 特定的值或特征. 2. 方法 对象执行的操作,就是能做什么. 3. 定义类 JAVA程序都以类class为组织单元: 组成:属性和方法: 4. 成员变量与局部变量的区别 作用域不同: 初始值不同:Java会给成员变量默认一个初始值,而局部变量则不会: 同一个方法中不允许存在同名的局部变量名,而在不同方法中则可以: 就近原则:局部与成员同名了,优先取

Java第二章----对象和类

从第一章到第二章整整隔了一个月的时间,这速度也是慢的无语了.因为这个月负责开发公司一个SaaS类型APP,忙的昏天暗地终于上线了,这才有时间写个博客.本章还是以概念为主,有点枯燥重在理解. 第一节:对象 名词解释 OOA-Object Oriented Analysis-面向对象分析 OOD-Object Oriented Design-面向对象设计 OOP-Object Oriented Programming-面向对象程序设计 面向对象基本特性 万物皆可为对象:任何一件事物都可以表示为程序中

《C++ Primer Plus》第10章 对象和类 学习笔记

面向对象编程强调的是程序如何表示数据.使用 OOP 方法解决编程问题的第一步是根据它与程序之间的接口来描述数据,从而指定如何使用数据.然后,设计一个类来实现该接口.一般来说,私有数据成员存储信息,公有成员函数(又称为方法)提供访问数据的唯一途径.类将数据和方法组合成一个单元,其私有性实现数据隐藏.通常,将类声明分成两部分组成,这两部分通常保存在不同的文件中.类声明(包括由函数原型表示的方法)应放到头文件中.定义成员函数的源代码放在方法文件中.这样便将接口描述与实现细节分开了.从理论上说,只需知道

《Java开发手册》学习进程之第6章对象和类

传统的过程化程序设计通过设计一系列的过程——算法来求解问题.这些过程一旦被确定,下一步就要开始寻找存储数据的方式,即“程序 = 算法 + 数据结构”.而面向对象的程序设计(即OOP,Object Oriented Programming)调换了这个次序,将数据放在第一位,之后再考虑操纵数据的算法. 在OOP中,程序被看作是相互协作的对象集合,每个对象都是某个类的实例.所有类构成了一个通过继承关系相联系的层次结构. 由于面向过程的编程模式是先将一系列过程(即函数)设计好再通过参数输入求解的,所以对

第03章 对象、类型和值

本章介绍数据的存储和使用. 为了读取用户的输入,需要在内存中开辟出一块区域,存放用户数据,一般地我们称这块区域为对象.一个对象就是具有某种类型的存储区域,类型指定该区域可以放置什么样的数据.为了引用该区域,我们将该区域命名,称为变量. 一个变量就是内存中的一块具有特定类型的区域. 在C++中,整数放在int变量中,字符串放在string变量中,int, string就是类型. 一.输入 试看一个读取输入的程序: 1 #include <iostream> 2 using namespace s

Java核心技术第四章----对象与类重难点总结

一.类之间的关系 类和类之间的关系,耦合度从高到低: is -a.继承.实现 has-a.组合.聚合.关联 user-a.依赖. 要求是:高内聚.低耦合. 继承("is-a") 继承(Inheritance),即"is-a"关系,是一种用于表示特殊与一般关系的.表示类与类(或者接口与接口)之间的父子关系.一般而言,如果类A扩展类B,类A不但包含从类B继承的方法,还会拥有一些额外的功能.在JAVA中,用关键字extends表示继承关系 实现(Implementatio

第 4 章 对象与类

目录 4.1 面向对象程序设计概述 4.1.2 对象,93 4.1.4 类之间的关系,94 4.2 使用预定义类 4.2.2 Java 类库中的 LocalDate 类,98 4.3 用户自定义类 4.3.1 Employee 类,103 4.3.2 多个源文件使用,105 4.3.4 构造器,106 4.3.5 隐式参数与显式参数,108 4.3.8 私有方法,111 4.4 静态域与静态方法 4.4.1 静态域,112 4.4.2 静态常量,113 4.4.3 静态方法,114 4.4.4

java学习笔记(Core Java)4 对象与类

第四章 对象与类oop三个特征:对象的行为.状态.标识类之间关系:依赖,聚合,继承依赖:一个类的方法操纵另一个类的对象.(尽量减少这种耦合情况)聚合(has-a)一个类作为另一个类的变量而存在继承(is-a) 如果只声明一个类变量,而没有在堆空间中开辟没存,那么这个变量就不能调用类中的方法因为这个变量没有引用对象 !!一个对象的变量并没有实际包含一个对象,而仅仅引用了一个对象 Data data;等同于:Data *data; //它只代表一个指针,而不拥有对象数据 get/set 访问器 一个

第1章 类和对象——定义类和创建对象

1.1     定义类.创建对象 在编程时,要定义类,然后在创建这个类的对象(实例). 1.1.1 定义类 定义类的语法个式如下: 访问修饰符 Class 类名 {     类的成员1:     ................     类的成员n:       } 各项的含义如下. 1)  “访问修饰符”用来限制类的作用范围或访问级别,类的修饰符只有public和internal两种(嵌套类除外).其中,声明为public的类可以被任何其他类访问:声明为internal的类智只能从同一个程序集