Java面向对象程序设计中很重要的一些东西

来源:互联网 发布:java二叉树非递归遍历 编辑:程序博客网 时间:2024/05/22 19:56
 

面向对象具有多方面的吸引力。对于管理人员,它实现了更快和更廉价的开发与维护过程。对于分析与设计人员,能生成清晰、易于维护的设计方案。对于程序开发人员,对象的理解又是如此浅显。此外,面向对象的工具以及类库的功能使编程成为一项更使人愉悦的任务,每个人都可以从中受益。

 

封装:

封装是指按照信息屏蔽的原则,把对象的属性和操作结合到一起,构成一个独立的对象。外部对象不能直接操作对象的属性,只能使用对象提供的服务。也就是说隐藏属性、方法或实现细节的过程,仅对外公开接口。

封装性是保证软件具有良好的模块性的基础。面向对象中的类就是封装良好的模块,对象就是封装的最基本单位。封装的最大优点如下:

1. 便于使用者正确、方便地理解和使用,防止使用者错误的修改系统属性;

2. 清楚的体现了系统之间的松散耦合关系,提高系统的独立性;

3. 提高软件的可重用性;

4. 降低大型系统的构建风险:即使整个系统不成功,个别的独立子系统仍然有可用价值。

 

继承:

在面向对象编程中,我们通常使用继承的机制,来设计两个或多个不同、但又具有很多相同特性的对象。其方法是:首先,我们定义一个包含很多对象共同特征的公共类,然后再定义一个新类,作为公共类的扩展,这个新类从公共类中继承所有的东西,我们把公共类称为父类,把所有从它哪里继承的类称为子类。继承表达了对象的一般与特殊的关系。特殊类的对象即具有一般类的全部属性和行为。

继承在面向对象变成中是一个重要的特征,是软件重用的一种形式。这种形式不仅节省程序的开发时间,还促进了高质量软件的重用。通过继承,子类不仅仅展示了其父类的行为和特征,而且还展示了特定于自身的行为和特征。子类与父类相比,其代表了一组更为专业化的对象。

 

多态:

不同的对象,收到同一消息可以产生不同的结果,这种现象成为多态性。简单的理解,就是相同的操作,不同的实现。

多态性允许每个对象以适合自身的方式去响应共同的消息,从而增强了软件的灵活性和重用性。

多态是面向对象思想中的重要概念之一,从而也成为现在程序设计语言的一个主要特性。从应用角度来说,多态是构建高灵活性、低耦合度的现代应用程序架构所不可忽视的能力。从概念的角度来说,多态使得程序员可以不必关心某个对象的具体类型,就可以使用这个对象的某一部分功能,这个某一部分功能可以使用父类来呈现,也可以使用接口来呈现。后者显得更为重要——接口是使程序具有可扩展性的重要特征,而接口的实现依赖于语言对多态的实现,或者直接就象征这语言对多态的实现。

 

何时使用继承:

如果使用得当,继承会是一种强大的工具,因此,我们需要知道在什么时候使用继承。正确的思路是集中观察正在设计的所有对象,并确定这些对象的共同和特有的属性和行为。

对象之间的共同属性和行为被成为共性,他们属于共同的父类。其它非共性的属性和行为,它们属于不同的子类。

 

继承关系的准则:

下面列出了在设计继承关系时需要牢记在心的准则:

1. 总是让子类执行父类可执行的所有行为;

2. 确保子类包含父类的所有信息;

3. 向子类中添加属性和行为,从而定义父类不具备但子类具备的特殊行为;

4. 将共同特性迁移到父类中;

5. 允许同一父类的不同子类执行相同的行为,但具体的实现方式不同。

 

构造函数:

在构建基本数据类型时,首先为其分配了所需要的内存,并将值赋值给该内存区域。
而在构造类时,会执行以下几部操作:
1. 为类分配内存;
2. 创建并初始化类变量;
3. 调用合适的构造方法来进行附加的初始化;
4. 返回引用,该引用指向第一步中分配的内存位置。

在创建未初始化的类变量时,所有的数值型(整型、单精度型、长整型)和字符型都被赋予初始值0.所有的逻辑型值都被初始化为false,所有的引用类型都被初始化为null。

关于构造函数要注意的一点是,如果未指定任何构造函数,类则会提供一个默认的构造函数,而默认构造函数不会接收任何变量,也不会执行任何操作。但如果提供了一个或多个构造函数,并且希望有一个默认构造函数存在,那就必须自己定义一个无参数的构造函数。

 

静态类成员:

我们为类定义的静态变量只有一个副本,静态变量很适合用于常量和对类的所有对象都公开的全局性变量。

静态方法也非常有用,因为它们不要求创建类的实例,这就是可以调用System.out.println()而不必创建System对象的原因。out变量也是System类的静态变量,因此可使用System.out的方式来访问out变量。

由于静态类成员要先于非静态类成员加载,所以静态方法不能访问非静态的方法和属性,只能访问静态成员,反之则可以。

 

静态导入:

当我们在使用静态成员(方法和变量)时,必须给出提供这个方法和变量的类。使用静态导入可以使被导入类的所有静态变量和静态方法在当前类中直接可见,使用这些静态成员无需再给出它们的类名。导入方法如下:

import static java.lang.Math.*;

代码使用如下,PI和sin方法可以直接使用,无需使用“Math.PI”的方式:

System.out.println(PI * sin(30));

 

final类:

将类定义为final意味着该类不能派生任何子类,也就是说不能扩展该类,使用关键字final类型,例如:

public final class MyClass {
}

一般来说,当不希望其他任何人对类进行扩展时,可将类定义为final类型。这包括两种情形:

1. 类封装了所需使用的所有功能方法;

2. 类包含了不希望对其他人呢(无论计划授予该用户何种权限)公开的核心代码。

 

抽象类:

将类定义为abstract类型意味着该类必须带有子类,而该类本身不能被实例化:

public abstract class MyClass {
}

抽象类通常至少包含一个抽象方法。抽象方法是在声明中使用abstract来标识的,并且不包含方法体,改用分号结束声明:

public abstract void MyMethod();

抽象类可包含非抽象成员和抽象成员,抽象类自身不能实例化,因为该类存在没有实现的抽象方法,并且其所有子类必须为抽象方法提供实现,或者声明成abstract类型,但这时子类也必须为抽象类。

 

子类的创建:

Java运行时环境利用继承创建类的步骤如下:

1. 创建子类;

2. 初始化所有父类的类变量;

3. 初始化所有子类的类变量;

4. 执行父类的构造函数;

5. 执行子类的构造函数。

 

垃圾收集:

当某个对象不再需要时,Java中会出现什么情况呢?在C++中,在使用对象结束后必须明确删除该对象,否则,在关闭该程序之前该对象将不会释放所占用的内存。Java的设计者非常重视这个问题,并认为内存释放这一繁琐的操作不应由程序员类负责。因此设计了一种新的编程范例,这就是垃圾回收机制。在Java中,当我们不再需要某个对象时,可为该对象引用赋值null值,使该对象引用能够引用内存中的不同区域(或者将该变量指派给其它对象或创建新对象)。当内存中出现不再访问的区域时,就需要进行垃圾回收。Java有一个在后台运行的程序可查找这些对象,但该进程只有在应用程序运行内存不足时才工作。在内存不再使用时,系统就可以回收内存。总之,Java可为程序员清理所有的内存。

如果想请求垃圾回收,可以调用System类的gc()静态方法,该方法调用运行垃圾收集的请求。但是没有任何方法强制Java虚拟机执行垃圾收集程序。

System.gc();

 

终结器:

由Java管理内存时,在从内存中删除对象之前有什么方法清除对象或者进行一些资源回收工作吗?Java本身没有像C++一样的析构函数,但具有与之类似的结构,即终结器。类可以定义finalize()方法,当从内存中删除对象时可调用该方法。终结器必须通过调用System类的runFinalization()方法来显示启用该方法,指示垃圾收集程序在回收内存之前对要执行垃圾收集操作的对象调用finalize()方法。父类的终结器必须是子类终结器所调用的最后一个方法。可通过super变量访问并调用父类的finalize()方法:

public class MyClass extendsMySuperClass {
    protectedvoid finalize() {
        ....
        super.finalize();
    }
}

但是,我们无法控制垃圾收集器何时运行。也无法判断是否已调用终结器。但考虑到无需担心内存的管理,这也算是不错的折衷。我们可以粗略的勾勒出Java对象的生命周期:

1. 为对象分配内存;

2. 初始化属性;

3. 调用合适的构造函数;

4. 在程序中使用对象;

5. 在内存中分离对象的引用和对象;

6. 在某个时刻,运行Java的垃圾收集程序并查看哪些内存不再使用;

7. 垃圾收集程序释放内存。

 

定义接口:

定义接口的一般语法如下:

[public]interface iname [extendsi2name]

1. 接口可以继承其它接口;

2. 可包含关键字abstract,但通常是隐式使用;

3. 可包含关键字public,但通常是隐式使用;

4. 可包含static、final关键字,但通常是隐式使用。

所有接口都是public和abstract类型,如果接口包含属性,则所有属性都是static和final类型。

 

实现接口:

类采用关键字implements来实现接口:

[public] [qualifiers]class classNameimplements iname [, i2name]

1. 类可以实现任意数量的接口;

2. 类可以是abstract或final类型;

3. 类可以扩展类一个类,同时实现任意多个接口。

 

使用借口实现多重继承:

使用接口可以有不同的原因,其中之一是Java缺乏对多重继承的支持。描述多重继承问题的一个经典示例是神话中的Pegasus(飞马)。飞马是一匹有翅膀的马,能够像鸟一样飞翔。因此,如果想创建一个Pegasus类,是从马继承呢,还是从鸟继承?飞马同时具备马和鸟的本领。

在Java中,实现Pegasus类最好的办法是:定义两个分别封装了马和鸟的功能的接口:HorseLike和BirdLike。然后,定义Pegasus类来实现这两个接口。

 

使用接口添加外部性能:

接口另一个常见的用法是为现有类添加外部性能,在决定将那些功能添加到类中,那些方法添加到接口中,要考虑的不仅仅是如何在概念上进行区分,更应该从严格的面向对象角度来考虑,原则是使类尽可能“单纯”。

应该这样设计类:让类封装所代表对象的属性和行为。对象外部的功能可通过接口来实现。这仅仅是概念上的区分,但如果遵循此准则,则设计出的类将具备更好的重用性,用来实现接口的方法也具备更佳的通用性。

 

接口和抽象类的对比:

又是我们会对何时使用接口以及何时仅仅创建抽象方法并将其置于父类中感到迷惑不解。下面给出几条准则:

1. 如果功能与对象自身密切相关,则在父类中使用抽象的基类方法;

2. 如果该功能只是对象的辅助行为,则可以使用接口;

3. 如果该功能可被全局性的应用到其它无关对象,则可使用接口。

原创粉丝点击