抽象与封装是面向对象程序设计的两个重要概念。类将数据以及对数据的操作封装在一个抽象数据类型中,为属于该类的所有对象提供了同意的抽象描述。
理解抽象与封装的概念,掌握JAVA中的类与对象的应用,能够运用面向对象思想进行类的设计,正确设计类中的成员方法和成员变量,是我们学习的目标。
面向对象是一种新型的程序设计方法,或者说是一种心的程序设计规范,其基本思想是实用对象、类、继承、封装、消息等基本概念来进行程序设计。从显示世界中客观存在的事务(即对象)出发来构造软件系统,并且在系统构建中尽可能运行人类的自然思维方式。
面向对象的设计方法用对象描述事物,而每个具体的对象又可以用两个特征来描述:描述事物静态属性所需的数据结构以及对这些数据进行的有限操作。也就是说,把数据结构和对数据的操作放在一起构成一个整体,才能完整地反应实际问题。数据结构和对数据的操作实际上是相互以来不可分割的整体。
面向对象程序设计具有抽象、封装、集成和多态4个特点。抽象去掉了被研究对象中与主旨无关的次要部分,而仅仅抽取出与研究工作有关的实质性的内容加以考虑。抽象有两类:一类是过程抽象,另一类是数据抽象。
面向对象程序设计强调数据抽象,数据抽象把系统总需要处理的数据和这些数据上的操作结合在一起,根据功能、性质、作用等因素抽象成不同的抽象数据类型。每个抽象数据类型既包含数据,又包含针对这些数据的操作,是相对于过程抽象更为严格的抽象方法。
封装
封装就是利用抽象数据类型把数据和基于数据的操作封装在一起,数据被保护在抽象数据类型的内部,系统的其他部分只有通过数据的操作,才能够于这个抽象数据类型进行交互,封装包含两层含义。
第一,把对象的全部属性及其行为结合在一起,形成一个不可分割的独立单位(即对象)。
第二,信息隐蔽,即尽可能隐蔽对象的内部细节,对外形成一个边界(或者说形成一道屏障),只保留有限的对外接口,使之与外部发生联系。
封装的原则在软件上的反应是:对象以外的部分不能随意存取对象的内部数据(属性),从而有效地避免了外部错误对他的“交叉感染”,使软件错误能够局部化,大大减少查错和排错难度。
在面向对象的程序设计中,抽象数据类型是用“类”这种面向对象工具表示的,每个类里都防撞了相关的数据和操作。封装性降低了程序开发过程的复杂性,提高了效率和质量,保证了数据的完整性和安全性。同时,封装性提高了抽象数据类型的可重用性,使抽象数据类型称为一个结构完整、能够自行管理的有机整体。
类
把众多的事物归纳、划分成一些类,是人类在认识客观世界时经常采用的思维方法。分类的原则是抽象。类是一组对象的集合,它为属于该类的所有对象提供了统一的抽象描述,其内部包括属性和服务两个主要部分。在面向对象的编程语言中,类是一个独立的程序单位行为。类的实例化结果就是对象,而对一类对象的抽象就是类。
类的定义
类是JAVA的核心和本质,想要在JAVA程序中实现的每个概念,都必须封装自爱类中。类是具有共同属性和行为的对象的抽象,属性描述了对象的状态,以数据的形式存在,在JAVA面向对象程序设计中又贝称为变量。行为描述了对数据进行的操作,可引起对象状态的改变。在JAVA面向对象程序设计中贝称为方法。
JAVA中类的实现包括两个部分:类头和类体。类头定义的格式如下:
[类定义修饰符] class <类名> [extends <父类名>] [implements <接口列表>]
类的定义主要包括关键词 class 和类名。类名是JAVA语言合法的标识符,类名一般具有一定的含义。其中,CLASS为定义类的关键字,extends是用于继承的关键字,implements是用于实现接口的关键字,有关类的修饰符后面将详细阐述。
类体是类的主体部分,它包含了所有实现类功能的JAVA语言程序代码,包括成员变量和成员方法。JAVA类除了继承它的父类中的变量和方法外,一般仍会在类体中明确定义自己的变量和方法。程序中,变量说明应放在定义之前。类体要用{}括起来。类体的格式如下:
class <类名>{
[变量修饰符] <变量内省> <变量名>
[方法修饰符] <方法返回值类型> <方法名>([<参数列表>]){
方法体
}
}
其中,变量名是JAVA语言中的合法标识符,变量的类型可以是JAVA给定的任意数据类型或者用户自定义类。用于说明变量和方法的访问权限等属性。
一个简单的学生类:
//**********Student.java*********
//学生类的定义
import java.io.*; //加载系统输入输出类
public class Strdent{
/*类成员的定义*/
private String name; //成员变量
private String sex; //成员变量
rivate int number; //成员变量
void setValue(String a, String b, int c)//成员方法
{
name = a;
sex = b;
number = c;
}
public int getNumber() //成员方法
{
return number;
}
public static void main(String args[]) //成员方法
{
//打印输出一行字符
System.out.println("这是一个学生类的定义!");
}
}// Student 类结束
//代表JAV语言中的单行注释。
/* */ 之间的部分是多行注释。
类的修饰符
类的修饰符说明类的性质和访问权限,分为访问控制符和非访问控制符,包括
public 、protected 、 private 、abstract 和 final 。
1. public , protected 和 private
public , protected 和 private 说明类的访问权限,属于访问控制符。
用public修饰的类,不仅能贝同一包中其他类访问,还能贝包之外的类和对象使用。
protected 修饰的类为保护类,可贝同包类和异包子类访问。
private 修饰符的类为似有类,外界无法访问。
共有类的定义。
//*******TestPublic.java*******
//共有类的定义
import java.io.*; //加载系统输入输出类
public class TestPublic
{
/*每个类的main()方法是该程序的入口,而包含main方法的类是程序的主类。
main()方法的形式是 public static void main(String args[]) */
public static void main(String args[])
{
System.out.println("这是一个共有类");
}
}
下面定义一个名为TestProtectedAndPrivate的类来测试保护类和似有类。
保护类和似有类的定义:
//*************TestProtectedAndPrivate.java**********
//保护类和似有类的定义
import java.io.*; //加载系统输入输出类
public class TestProtectedAndPrivate{
//主方法
public static void main(String args[]){
//分别创建保护类和似有类的对象t1和t2
TestProtected t1 = new TestProtected();
TestPrivate t2 = new TestPrivate();
//打印输出两行字符
System.out.println(t1.toString());
System.out.println(t2.toString());
}
protected static class TestProtected //保护类
{
public String toString(){
return "保护类的定义:作为潜逃类的内部类";
}
}
private static class TestPrivate //似有类
{
public string toString(){
return "私有类的定义:作为嵌套类的内部类";
}
}
} // TestProtectedAndPrivate 类结束
aabstract
abstract 说明一个类为抽象类,所谓抽象类是指不能直接实例化对象的类。如果一个抽象类贝说明了,则这个类中将包括一个或几个抽象方法。所谓抽象方法是指该方法只有方法说明却没有方法体,即没有具体实现的代码。抽象类本身不具备实际功能,它只用于衍生子类。定义抽象类和抽象方法的目的是建立抽象模型。抽象类中不一定包含抽象方法,但一旦某个类中说明了抽象方法,该类必须说明为抽象类。
不包含抽象方法的抽象类的定义。
//*************TestAbstract.java*************
//不包含抽象方法的抽象类
import java.io.*; //加载系统输入输出类
public abstract class TestAbstract{
//该类不包含抽象方法
//主方法
public static void main(String args]){
//打印输出两行字符
System.out.println("这是一个不包含抽象方法的抽象类!");
System.out.println("抽象类不能创建对象!");
}
} // TestAbstract 类结束
包含抽象方法的抽象类的定义。
//********** Mankind.java **********
//包含抽象方法的抽象类
import java.io.*; //加载系统输入输出类
public abstract class Mankind{
//定义4个抽象方法
public abstract void closing();
public abstract void food();
public abstract void shelter();
public abstract void transportation();
//主方法
public static void main(String args[]){
//打印输出两行字符
System.out.println("这是一个包含抽象方法的抽象类");
System.out.println("抽象方法没有方法体");
}
}// Mankind 类结束
final
final 修饰的类又称为最终类,是指该类不能被继承,不能再有子类。它的目的是为了避免盲目继承。一个final类无法贝继承,意味着此类在一个继承树中是一个叶子类,并且此类的设计已贝认为很具体而不需要进行修改或扩展。对于final类中的成员变量,可以定义其为final,也可以不是final。而对于方法,由于所属类为final的关系,自然也就成了final类型。也可以明确地给final类中的方法加上一个final关键字。下面定义一个名为TestFinal的最终类。
//************* TestFinal.java ***************
//最终类的定义
import java.io.*; //加载系统输入输出类
public final class TestFinal
{
//主方法
public static void main(String args[]){
//打印输出一行字符
System.out.println("这是一个最终类,不能被继承");
}
}//TestFinal类结束
因为抽象类的目的就是为了被继承,而最终类的目的是不让其贝继承,所以一个类是不能用 abstract 和 final 同时修饰的。
对象
对象是具有某些特俗属性(数据)和行为方式(操作)的实体。对象可以是有生命的个体,比如一个人或一只老虎;还可以是无生命的个体,比如一辆汽车或一台计算机;也可以是一个抽象的概念,如天气的变化或鼠标产生的事件。对象有两个特征:属性(property)和行为(Behavior)。例如,一个人的属性有姓名、性别、年龄、身高、体重等;行为有唱歌、打球、骑车和学习等。
类是一个抽象的概念,而对象是一个具体的概念,是类实例化的结果。对象通过消息传递来进行交互。消息传递即激活指定的某个对象的方法以改变其状态或让它产生一定的行为。
对象的生命与引用
同基本内置类型一样,为了声明对象,首先必须写出类型名,然后写出该类型的所有变量的名字,中间用逗号隔开。下面举例说明怎样生命一个类的对象:
Student s1, s2, s3;
上面的生命表示s1\s2\s3是 Student 类型的引用变量,可以用来引用Student型的对象。引用变量的值将对应一个内存地址,这个地址标识的空间用来存放一个Student对象。
声明对象的引用变量,并不等于创建对象,当然更没有为对象分配存储空间。这些需要通过 new 关键词和对引用变量的赋值才能实现。
创建对象与定义构造方法
在JAVA语言中,一个JAVA对象是类的一个实力,创建对象的过程是对类的实例化过程,实例化对象就是创建一个对象。实例化对象意味着给对象分配必要的存储空间,用来保存对象的变量和方法大妈。new 运算符用于创建一个类的实例并返回对象的引用,即用来实现对象的实例化。一般格式为:
<类名> <对象名> = new <类名>(<参数列表>);
创建对象与生命基本数据类型的变量相似,首先说明新建对象所属的类名,然后说明该对象名,赋值号左边的NEW 关键字是用于为新建对象开辟内存空间的运算符。与变量相比,对象占用的内存空间要大得多,因为对象既包含变量又包含方法,多数情况下,变量与方法还不止一个。例如前面定义的学生类 Strdent,假设有一个对象s1,则它就有3个属性和2个方法: s1.name ,s1.sex, s1.number, s1.setValue(), s1.getNumber() 。这些变量和方法保存在一块内存中,这块内存就是对象s1 所占用的内存。如果在新建另一个 Strdent类的对象 s2,则s2对象将在内存中拥有自己的与s1对象不同的位置相同大小的内存空间。
创建对象的同时要调用这个对象的构造方法完成对象的初始化工作,JAVA语言中每一个类都有构造方法,该方法是一种特殊的方法,其特殊性主要体现在以下几个方面。
(1) 构造方法的名称与类的名称相同。
(2) 构造方法不返回任何数据类型,也就没有返回值。
(3) 构造方法的修饰符只能是访问修饰符,即 public ,private,protected 中的任一个。
(4) 构造方法只能由 new 运算符调用,一般不能由编程人员显式地直接调用。
(5) 构造方法不能从父类中继承。而在构造方法中可以调用但前父类和其父类的另一个构造方法,调用语句必须是构造方法的第一条语句。使用当前类的构造方法用this来引用,使用其父类的构造方法用 super 来引用,在构造方法的实现中,可以进行方法的重载。
下面定义一个 Student 类,该类具有两个构造方法,方法的名称都是 Student,与类名相同。
public class Student{
//成员变量
private String name;
private String sex;
private int number;
//成员方法
Student() //构造方法
{
name = "NO name";
sex = "unknown";
number = 0;
}
Student(String a, String b, int c)//构造方法
{
name = a;
sex = b;
number = c;
}
}// Student 类结束
构造方法的重载。
//************* TestConstructor.java ***************
//构造方法的重载
import java.io.*; //加载系统输入输出类
class Constructor{
//成员变量
private int x;
private double y;
//没有参数的构造方法
Constructor()
{
x = 0;
y = 0.0;
}
//一个参数的构造方法
Constructor(int x){
this.x = x; //使用 this 关键字标识成员变量,以区别于同名参数
}
//一个参数的构造方法,参数类型于前一个构造方法不同
Constructor(double y){
this.y = y;
}
//两个参数的构造方法
Constructor(int x, double y){
this.x = x;
this.y = y;
}
// print() 方法显示成员变量
void print()
{
System.out.println("x=" +x+" y="+y);
}
} // Constructor 类结束
// ConstructorTest 类
public class TestConstructor
{
//主方法
public static void main(String args[]){
//创建 Constructor 类的对象 c1 c2 c3 c4 分别使用了不同的构造方法
Constructor c1 = new Constructor();
Constructor c2 = new Constructor(53);
Constructor c3 = new Constructor(6.98);
Constructor c4 = new Constructor(5,7.8);
//在屏幕上输出
c1.print();
c2.print();
c3.print();
c4.print();
}
} // TestConstructor 类结束