第3章 面向对象程序设计
教学目标:通过本章的学习,理解面向对象编程的思想、类和对象的概念,掌握面向对象编程的基本特征,能正确定义类并创建相应的对象,掌握抽象类与接口的用法,理解包的含义与用法,逐步掌握面向对象编程的方法,最终达到通过面向对象技术编写Java程序的目的。
案例 银行账户信息处理解析 多数用户对去银行办理存款、取款等业务并不陌生,自然想到程序是如何实现的。现在我们来看银行账户信息处理程序的基本框架。 package bank; //创建程序包 import java.util.*; //引入程序包 class BankCount //定义类 { int id; String name,date; float money; public BankCount(int id,String name,String date,float money) //构造方法 // 方法体 }
class BCOption { Vector vec=new Vector( ); //对象声明与实例化 static int count=0; //类中静态变量的定义 public void kaihu(BankCount bc) //实例方法 // 方法体,实现开户功能 } public void moneyOut(int id, float outmoney) //方法体,实现取钱功能 public void moneyIn(int id, float inmoney) //方法体,实现存钱功能
public void query(int id) { //方法体,查询并输出账户信息 } public static void main(String args[ ]) // 实现账户的相关操作 从程序的基本框架来看,本程序涉及了如下知识点。 (1) 类的相关知识。 (2) 对象的基本用法。 (3) 类的静态成员的用法。 (4) 程序包的创建与引入。
3.1 类 和 对 象 3.1.1 类的创建 类的概念:类封装了一类对象的状态和方法。类是现实世界中实体的抽象集合,是封装了数据和数据操作的复杂抽象数据类型。 1.类的定义 (1) 类定义的语法格式: [修饰符] class 类名 [extends 父类名] [implements 接口名] { 类体 } (2) 成员变量定义的语法格式: [修饰符] 数据类型 变量名; 成员变量的修饰符有public、protected、private、final、static等。
(3) 方法定义的语法格式: [修饰符] 返回值类型 方法名([参数列表]) { 方法体 } 例:定义一个圆类 class Circle double radius=1.0; double CalculateArea( ) return radius*radius*3.14159;
2.成员变量和局部变量 在类中,变量按定义位置分为如下两种。 (1) 在成员变量定义部分所定义的变量称为类的成员变量。成员变量在类内有效。 (2) 在方法中定义的变量或方法的参数变量称为局部变量。局部变量在方法内有效。 例:成员变量定义与使用。 public class Exam2 { int x; float y=30.5f; //定义成员变量时提供初值 double c; c=40.65; //非法,赋值表达式仅允许出现在方法中 public void setX(int a) x=a; } public int getX( ) return x;
3.1.2 对象的创建 对象的概念:代表现实世界中可以明确标识的任何事物。 对象和类的关系:类是用来定义对象的数据和方法的模板。可以用一个类定义许多实例,即对象。创建一个对象被称为实例化对象。 1.创建对象 创建对象包括对象的声明和为对象分配内存两个步骤。 (1) 声明对象。 为了声明一个对象,必须用一个变量表示它,语法如下: 类名 对象名; 例如:Person zhangsan; (2) 为对象分配内存。 要真正创建对象zhangsan,需要用操作符new告知计算机为Person创建一个对象,并且为它分配适当的存储空间。 对象名=new 类名( ); 例如:zhangsan=new Person( );
2.对象的内存模型 (1) 执行语句:Person zhangsan;。 用Person类声明一个变量zhangsan即对象zhangsan时,内存模型如图 (2) 执行语句:zhangsan=new Person( );。 系统会完成如下两件事。 ① 为zhangsan的各个成员变量分配内存。当成员变量在声明时没有指定初值时,如果成员变量为整型,则自动提供默认值0;如果是浮点型,则自动提供默认值0.0;对于boolean型,则提供默认值false;对于引用型(对象类型),则提供默认值null。
分配实体的对象 ② 此时系统会给出一个信息,确保这些变量是属于对象zhangsan的,即这些内存单元将由zhangsan使用。 通过zhangsan访问各个成员变量对应的单元
3.对象成员的访问 当一个对象被创建后,可以通过使用“.”运算符实现对自己的成员变量与方法的访问。 访问成员变量的语法格式: 对象名.成员变量 访问成员方法的语法格式: 对象名.方法( ) 例: class Person { String name,sex; int age; float height,weight;
public void outValue( ) { System.out.println("name:"+name); System.out.println("sex:"+sex); System.out.println("age:"+age); System.out.println("height:"+height); System.out.println("weight:"+weight); } public static void main(String args[ ]) Person zhangsan=new Person( ); zhangsan.name="zhangsan"; zhangsan.sex="male"; zhangsan.age=19; zhangsan.height=1.76f; zhangsan.weight=76; zhangsan.outValue( );
4.对象的初始化 构造方法可完成初始化对象的各成员变量的数据。 5.类的静态成员 在定义变量时,若类型前以static修饰,则定义的变量称为静态变量或类变量,没有用static修饰的变量称为实例变量。在定义方法时,若在方法的返回值类型前以static修饰,则定义的方法称为类的静态方法或类方法,没有用static修饰的方法称为实例方法。 (实例略) 6.简单数据类型和对象类型变量的赋值 (1) 简单类型变量的赋值。 有如下语句: int x=3,y=4; x=y;
(2) 对象类型变量的赋值。 Person zhangsan,lisi; zhangsan=new Person( ); lisi=zhangsan; 7.垃圾回收 Java运行系统监测垃圾并自动收回垃圾对象占用的空间,这个过程叫做垃圾回收(garbage collection)。
3.2 类 的 继 承 子类与父类继承关系图
3.2.1 创建子类 1.子类的创建 创建子类的语法格式如下: class 子类名 extends 父类名 { 类体 } 子类继承父类时,有如下约定。 (1) 子类可以继承父类的成员变量,包括实例成员变量和类成员变量。 (2) 子类可以继承父类除构造方法以外的成员方法,包括实例成员方法和类成员方法。 (3) 子类可以重定义父类成员。 子类不能继承父类的构造方法是因为父类构造方法创建的是父类对象,子类必须定义自己的构造方法,创建子类自己的对象。
2.类的封装性 通过对象的封装,实现了模块化和信息隐藏。通过对类的成员施以一定的访问权限,实现了类中成员的信息隐藏。 Java语言中有4种不同的限定词,提供了4种不同的访问权限。 (1) private。 类中限定为private的成员,只能被这个类本身访问。 (2) default。 类中不加任何访问权限限定的成员属于默认的(default)访问状态,可以被这个类本身和同一个包中的类所访问。 (3) protected。 类中限定为protected的成员,可以被这个类本身、它的子类(包括同一个包中以及不同包中的子类)和同一个包中的所有其他的类访问。 (4) public。 类中限定为public的成员,可以被所有的类访问。
3.2.2 this、super引用 1.使用关键字this (1) 用关键字this可以访问隐藏的实例变量。 在类中若成员变量名与方法中的变量相同,在方法中若直接使用同名的变量,则使用的是方法中定义的变量,即局部变量,此时成员变量被隐藏。若想在方法中使用同名变量中的成员变量,则需借助this关键字。 (2) 在构造方法中使用关键字this。 在构造方法中调用类中的另一个构造方法,可借助语句this( ),this( )语句必须出现在构造方法中的第一行。 2.使用关键字super 关键字super指的是使用super所在类的父类。这个关键字的用法如下。 (1) 调用父类的构造方法如下: super([参数]);
(2) 调用父类的实例方法。 关键字super也可以用来引用父类中构造方法之外的其他方法,语法如下: super.方法名([参数]); (3) 调用父类被隐藏的成员变量的方法如下: super.变量名
3.3 类的多态性 方法重载也称为编译时多态,方法覆盖也称为运行时多态。 3.3.1 方法重载 3.3 类的多态性 方法重载也称为编译时多态,方法覆盖也称为运行时多态。 3.3.1 方法重载 方法重载是指同一个类中多个方法享有相同的名字,但是这些方法的参数必须不同,参数不同是指参数个数不同,或参数类型不同。返回值类型不能用来区分重载的方法。 参数类型的区分度一定要足够。例如,不能是同一简单类型的参数,如int与long。 在编译阶段,具体调用哪个被重载的方法,编译器会根据参数的不同来静态确定调用相应的方法,所以也称方法重载为编译时多态。 方法重载分为两种:①构造方法重载;②实例方法重载。
(1) 构造方法重载。 当类中的构造方法有多个时,在创建对象时,系统会根据参数不同决定调用其中的某个构造方法。 (2) 实例方法重载。 当类中有多个同名的实例方法时,通过对象调用方法时,会根据参数不同决定调用其中的某个同名实例方法。 3.3.2 方法覆盖 在类层次结构中,如果子类中的一个方法与父类中的方法有相同的方法名,并具有相同数量和类型的参数列表,这种情况称为方法覆盖。 在介绍方法覆盖的具体应用之前,先来介绍一下上转型对象。所谓上转型对象是指有父类A与子类B,当用子类B创建一个对象,并把这个对象的引用赋给A类对象时,则把父类对象称为B类对象的上转型对象。
对象的上转型对象的实体是由子类负责创建的,但上转型对象会失去原对象的一些属性和功能。 (1) 上转型对象不能操作子类新增的成员变量与成员方法。 (2) 上转型对象可以操作子类继承或重写的成员变量与方法。 (3) 如果子类重写父类的某个方法后,通过上转型对象调用的该方法一定是调用了重写的方法。 当一个覆盖方法通过父类引用被调用时,Java根据当前被引用对象的类型来决定执行哪一个方法。 说明:(1) 在子类覆盖父类的某个方法时,不能降低方法的访问权限。 (2) 子类不能覆盖父类中声明为final或static的方法。 (3) 可以通过super关键字调用父类中被覆盖的成员。
3.4 抽象类与接口 3.4.1 抽象类 在Java语言中,用abstract 关键字来修饰一个类时,这个类叫做抽象类,用abstract 关键字来修饰一个方法时,这个方法叫做抽象方法。 定义抽象类的格式如下: abstract class 类名 { //类体 } 定义抽象方法的格式如下: abstract 返回值类型 方法名([参数]) 定义的抽象方法只有声明而无具体实现。抽象类必须被继承,抽象方法必须被重写,若子类没有重写继承的抽象方法,则子类也必须声明为抽象类。抽象类不能被实例化。
3.4.2 接口 接口是一种与类相似的结构,但只包含常量和抽象方法。接口是一种完全抽象的类。 Java把接口当做一种特殊的类,每个接口都被编译为一个独立的字节码文件,就像常规的类一样。和一个抽象类一样,不能用new运算符为接口创建实例,但可以用接口作为变量的数据类型,作为转换的结果。 1.接口的定义 创建接口的语法如下: [修饰符] interface 接口名 [extends 父接口列表] { [修饰符]类型 属性名=值; 返回值类型 方法名(参数列表); }
2.接口的实现 实现接口的语法如下: class 类名 implements 接口名[,接口名......] 3.接口回调 接口回调是指可以把实现某一接口的类创建的对象的引用,赋给该接口声明的接口变量,那么该接口变量就可以调用被类实现接口中的方法。实际上,当接口变量调用被类实现的接口中的方法时,就是通知相应的对象调用接口的方法。 3.4.3 内部类 内部类,顾名思义,即类内嵌套定义类。 1.实例内部类 实例内部类是外部类的一部分,在内部类中可以访问外部类的属性和方法。在静态方法中定义内部类变量时,一定要先定义外部类对象,通过外部类对象再去创建内部类对象。
外部类与内部类的访问原则是:在外部类中,通过内部类对象可以访问内部类的成员,但内部类可以直接引用它的外部类成员。 2.静态内部类 在定义的内部类前以static加以声明,则定义的内部类即为静态内部类。 无论是实例内部类,还是静态内部类,在定义时都可用权限修饰符public、protected、private修饰。但在外部类定义时要么用public修饰,要么不用,不能使用其他的权限修饰符。 3.匿名类 匿名类就是没有名字的类。大部分的匿名类只是为了实现某个接口或继承某个类,并覆盖或实现其中的某个方法
3.5 程 序 包 类被完整定义后,可以被很多应用程序使用。将解决一般问题的类代码集中管理是一种好的处理方法。代码的复用性是软件开发中最关注的特点。在Java中,能被复用的代码被存放到一起,称为“包”。Java中的包就是操作系统中的文件夹。 3.5.1 Java类库 Java类库是系统提供的类的集合,又称为应用程序编程接口(API,Application Programming Interface)。根据类的功能的不同,把这些类放在不同的包中。
提供了创建图形用户界面及管理图形、图像的类 Java中的常用包 包 包 中 的 类 java.applet 提供了创建Applet所需的类 java.awt 提供了创建图形用户界面及管理图形、图像的类 java.io 提供了输入输出流及文件操作等类 java.lang Java编程语言的基本类库 java.math 提供了数学运算的基本函数 java.net 提供了网络通信所需的类 java.sql 提供了访问数据源数据的类 java.util 包括集合类、日期时间工具等类 java.swing 提供了轻量级的图形用户界面组件
StringBuffer类的方法功能表 类别 方 法 定 义 功 能 构 造 方 法 public StringBuffer( ) 功 能 构 造 方 法 public StringBuffer( ) 构造一个其中不带字符的字符串缓冲区,其初始容量为 16 个字符 public StringBuffer(int length) 构造一个不带字符,但具有指定初始容量的字符串缓冲区 public StringBuffer(String s) 构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容 实 例 public StringBuffer append(String s) 将指定的字符串s追加到字符序列后 public StringBuffer insert(int x, String s2) 将字符串插入到字符序列的位置x处 public in length( ) 返回长度(字符数) public void setLength(int newLength) 设置字符序列的新长度 public void setCharAt(int x, char c) 将给定索引处的字符设置为 ch public StringBuffer replace(int start, int end, String s2) 使用给定String中的字符替换此序列从start到end的子字符串
min、max、abs、round和random方法与功能表 2. Math类 min、max、abs、round和random方法与功能表 方 法 定 义 功 能 public static type max(a, b) 返回a和b的最大值 public static type min(a, b) 返回a和b的最小值 public static type abs(a) 返回a的绝对值 public static int round(double a) 返回最接近参数的 int值,即返回四舍五入后的值 public static double random( ) 返回值是一个伪随机数,值介于0~1之间
3. Object类 Object类是java.lang中的类,是Java程序中所有类的直接和间接父类,也是类库中所有类的父类,包含了所有Java类的公共属性,这里介绍Object类的两个常用方法。 (1) equals( )方法的使用。 public boolean equals(Object obj) 该方法判断两个对象的引用是否相等。若相等则返回true,否则返回false。 初学者往往都会对“equals(Object)”与“==”的区别讨论一番。在比较对象时,常常用到“==”和“equals(Object)”。 (2) toString( )方法。 toString( )方法被用来将一个对象转换成String表达式。
4. 数据类型类 数据类型类又称为包装类,与基本数据类型(如int、double、char、long等)密切相关,每一个基本数据类型都对应一个包装类,均包含在java.lang包中 ,例:Integer类的用法 类 别 方 法 定 义 功 能 举 例 构 造 方 法 public Integer(int value) 根据一个整型数生成一个整型对象 Integer i=new Integer(6); public Integer(String s) 根据一个整数形式的数字字符序列生成一个整型对象 Integer j=new Integer("138"); 实 例 public static int intValue( ) 将包装类对象转换成整型数据 int j=i.intValue( ); public static int parseInt(String s) 将字符串转化为整型数据 int i=Integer.parseInt("123"); public static Integer valueOf(String s) 它将一个字符串转化成Integer对象 Integer i=Integer.valueOf("123"); public String toString( ) 返回一个表示该 Integer 值的 String 对象 String s= Integer.valueOf("123").toString( );
5. ArrayList类 ArrayList类包含在java.util包中,ArrayList 对象是数据的列表,是长度可变的对象引用数组,使用方法类似于动态数组。
ArrayList类的方法与功能表 类 别 方 法 定 义 功 能 构 造 方 法 public ArrayList( ) 功 能 构 造 方 法 public ArrayList( ) 构造一个初始容量为10 的空列表 public ArrayList(int size) 使用给定大小创建一个数组列表。向数组列表添加元素时,此大小自动增加 实 例 public int size( ) 返回此列表中的元素数 public get(int index) 返回此列表中指定位置上的元素。E代表取出元素的类型 public int indexOf(object x) 返回元素在列表中首次出现的位置 public int lastIndexOf(object x) 返回元素在列表中最后一次出现的位置 public boolean add(E o) 将指定的元素加入列表的尾部。若加入成功,则返回true;否则,返回false(如果此列表不允许有重复元素,并且已经包含了指定的元素,则返回 false) public boolean remove(Object o) 从此列表中移除指定元素的单个实例。如果移除成功,则返回true,否则返回false
Vector 类包含在java.util包中,是可以实现可增长的对象数组。但是,Vector 的大小可以根据需要增大或缩小 别 方 法 定 义 功 能 构 造 方 法 public Vector( ) 创建一个空Vector对象 public Vector(int initialCap) 创建一个空Vector,其初始大小由 initialCap 指定,容量增量为0 public Vector (int initialCap, int inc) 创建一个空Vector,初始容量由 initialCap 指定,容量增量由 inc 指定 实 例 public void addElement(Object x) 将元素x加入到向量数组的尾部 public void insertElementAt(Object x, int index) 把对象加入到向量数组的指定位置 public E elementAt(int index) 返回指定位置的元素 public int size( ) 返回数组中的对象个数
3.5.2 自定义包 在前面编写的程序中,生成的类都是放在默认包中,有时需要把类放到自定义的包中。 1.建立自定义包 在Java 中,用下面的方式来创建包: package <包名> 2.导入包 在程序中如果使用包中的类,则必须在源程序中用import语句导入。import语句的格式为: import <包名1>[.<包名2>.....]|*;
本 章 小 结 本章首先以案例的基本框架引出了本章的知识点。然后分别讲解了类的定义及类中成员变量与成员方法的定义,讲述了构造方法的定义与作用,应能熟练定义类;讲述了对象的创建、通过对象如何引用类的成员变量与成员方法,应能熟练运用;介绍了类的三种基本特征,即类的继承、封装与多态性,应理解相关的概念与用法;介绍了抽象类与接口,应理解抽象类与接口的用法;讲述了包的含义与用法,并介绍了系统包中几个常用的类,应能在编程中灵活运用;最后通过案例“银行账户信息处理实现”把本章内容进行了综合运用。