第7章 类


92 第 7 章 类 什么是类?类有什么用处?为什么它会是面向对象编程的一个典型特征?带着这些问 题,本章将会结合大量的实例为读者一一讲解。 类是面向对象编程中最基本、也是最重要的特征之一。从本章开始,将介绍如何进行面 向对象的程序开发,以及程序开发的过程中,所需要具备的重要思想是什么?编程思想是很 多学习编程的人,学习时间长却学不好的一个主要原因。 7.1 JDK 5 和 JDK 6 特性 本节介绍什么是 JDK,以 及 Java 开发工具集中两个不同的版本。本节的讲解比较简单, 希望有兴趣的读者查看其他的相关书籍。 7.1.1 什么是 JDK JDK 的意思是 Java 开发工具包(Java Development Kit,JDK),JDK 是 Sun 公司免费提 供的 Java 语言工具,是 Java 应用程序开发的基础。通常第三方开发工具“JBuilder9.0”、 “IBM VisualAge for Java”等都是基于 JDK 进行开发。 7.1.2 JDK 5 的特点 JDK 5 其实就是 JDK1.5,JDK1.5(开发代号猛虎)的一个重要主题就是通过新增一些 特性来简化开发,包括泛型、for-else 循环、自动装包/拆包、枚举、可变参数、静态导入。 使用这些特性有助于编写更加清晰、精悍、安全的代码。下面简单介绍下这些新特性。 泛型(Generic) C++通过模板技术可以指定集合的元素类型,而 Java 在 1.5 之前一直没有相对应的功能。 在 C++中,一个集合可以存放任何类型的对象,相应地从集合里面拿对象的时候,也不得不 对他们进行强制得类型转换。JDK1.5 引入了泛型,并且允许指定集合里元素的类型,这样 可得到强类型在编译时刻进行类型检查的好处。 For-Each 循环。For-Each 循环的加入简化了集合的遍历。 自动装包/拆包(Autoboxing/unboxing) 自动装包/拆包大大方便了基本类型数据和其包装类的使用。自动装包就是基本类型自 动转为包装类。自动拆包就是包装类自动转为基本类型。在 JDK1.5 之前,总是对集合不能 存放基本类型而耿耿于怀,现在自动转换机制解决了问题。 枚举(Enums) JDK1.5 加入了一个全新类型的“类”-枚举类型。 可变参数(Varargs) 93 可变参数的出现,使程序员可以声明一个接受可变参数数目的方法,注意的是可变参数 必须是函数声明中的最后一个参数。 静态导入(Static Imports) 要使用静态成员(方法和变量),必须给出提供这个方法的类。使用静态导入可以使被 导入类的所有静态变量和静态方法,在当前类直接可见,从而使用这些静态成员无需再给出 他们的类名。 7.1.3 JDK 6 的特点 浏览了 JDK6 的新特性,感觉“Compiler API”的应用有很大空间。JDK6 提供对代码 的编译功能,可以实现代码编辑、编译及加载运行,可以在系统运行中动态配置和扩展用户 自定义的功能,甚至可以把 Java 语句作为脚本,内嵌到原有系统中扩充功能集。 7.1.4 JDK 5 与 JDK 6 的比较 2006 年底,Sun 公司发布了 Java Standard Edition 6(Java SE 6)的最终正式版,代号 “Mustang(野马)”,跟“Tiger(Java SE 5)”相比,“Mustang”在性能方面有了不错 的提升。从与“Tiger”在 API 类库的比较来讲,有了大幅度加强,虽然“Mustang”在 API 库方面的新特性显得不太多,但其提供了许多实用和方便的功能:在脚本、Web Service、 XML、编译器 API 数据库、JMX、网络方面都有不错的新特性和功能加强。 随着不断的发展和进步,相信 JDK 6 会有不错的表现。 7.2 用比较法阐述类的概念 现实生活中的有一个例子。造房子的砖头有红色的砖、有方砖、有圆砖,此时,在现实 生活中各种各样的砖头都可以称作是对象。红色的砖可以称为一个对象,圆砖可以称为一个 对象,它们有共同点,但也有不同的方面,这些不同的方面使得它们不可能是同一个对象。 然而,砖头就是所有种类的总称,所有的砖都是由它派生而来,所以这个砖可以称为是一个 类。 类就是模板,也可以说类其实就是创建对象的基地,它能产生很多不同的对象。再举个 例,汽车就是一个类,而卡车、轿车等等都是从汽车这个类中派生出来的,也就是说,这些 都是属于汽车这个类。其实类是个很灵活的概念,也可以将轿车作为一个类,在轿车这个类 中,再创建各种品牌的轿车对象出来,有桑塔纳、红旗、奔驰,而每种轿车都是一个对象。 类与对象的关系,有点像一个母亲与子女的关系。 本章重点讲述类的知识,至于对象的知识将在下一章给大家详细讲述。 7.3 Java 中已有的类 目前,Java 中已经存在了很多由前辈开发出来的类,可以被开发人员直接使用,将这些 94 有共同特征的类组合在一起形成了类库。在 Java 中包含大量用于不同目的的类库,这些类 库是开发 Java 软件的基础。即使是需要设计自己的类,也有可能使用到 Java 类库中的很多 类。 可以打开 API 文档,查看一些已经存在的类库,能发现 Java 类库非常丰富。鉴于读者 都是初学者,所以暂时只介绍一些简单的 API 类库,随着学习的深入,后面读者会接触到 更多的类。 7.3.1 Java 的数学运算处理类 Math 看到“Math”这个单词,立刻就能明白这个类一定跟数学有关。其包含了丰富的数学 函数,可以使用这个类的方法,而不用管内部是如何实现的。通过查看 API 文档,知道“Math” 类中的所有方法和字段都是可以直接访问的,在 Java 中,称之为静态方法和静态字段。有 关静态方法和静态字段的概念,后面章节有介绍,现在只需要知道,这些方法和字段可以直 接去使用。 那么如何访问其中的方法和字段呢?因为这些成员是静态成员,所以可通过“类名.方 法名称”和“类名.字段”来访问方法和字段。在 Math 类中,由于都是静态成员,就可以使 用“Math.方法名称或常量名”。下面把这个类中经常使用到的方法和属性值列举出来,以 提供给大家参考。 Math 类中包含了两个静态常量: Math.PI-----------------------------------------------表示数学常量π。 Math.E------------------------------------------------表示和 e 的最可能接近的近似值。 Math 类提供了常用的三角函数: Math.sin----------------------------------------------表示正弦函数 Math.cos----------------------------------------------表示余弦函数 Math.tan----------------------------------------------表示正切函数 Math.asin----------------------------------------------表示反正弦函数 Math.acos----------------------------------------------表示反余弦函数 Math.atan----------------------------------------------表示反正切函数 Math.atan2---------------------------------------------表示反余切函数 Math 类还提供了幂函数、指数函数和自然对数函数: Math.pow-----------------------------------------------返回 a的 b 次方 Math.exp-----------------------------------------------返回 e的 a 次方 Math.log-----------------------------------------------返回 a的常用对数值 Math 类提供了一个常用的数学运算函数: Math.abs-----------------------------------------------返回绝对值 Math.sqrt-----------------------------------------------返回平方根 Math.max-----------------------------------------------返回最大值 Math.min-----------------------------------------------返回最小值 Math 类提供了角度与弧度相关的转换运算方法: Math.toDegrees(double angrad)------------------将弧度转换成角度值 Math toRadians(double angdeg)------------------将角度值转换成弧度 Math 类提供了四舍五入的运算及截断运算: Math.round(double e)------------------------------四舍五入运算 Math.floor(double e )------------------------------返回不大于 e 的最大整数 Math 类提供了一个专门用来产生随机数的函数: Math.random()----------------------------------------用来产生随机数的函数 以上是在 Math 类中常用的方法函数。下面将通过举例来熟悉这些函数。 95 首先通过下列程序代码来熟悉数学运算函数的用法: public class Math1 { public static void main(String[] args) { int x=9; int y=16; System.out.println(Math.sqrt(x));--------------------------计算 x 的平方根的结果 System.out.println(Math.abs(x)); --------------------------计算 x 的绝对值的结果 System.out.println(Math.max(x,y)); -----------------------计算 x 与 y 的最大值 System.out.println(Math.min(x,y)); ------------------------计算 x 与 y 的最小值 } } 运行结果: 3.0 9 16 9 在运用这些函数方法的时候,希望能注意到函数所带的参数,“Math.sqrt”、 “Math.abs”带的是一个参数。“Math.max”、“Math.min”带的是两个参数,这一点 必须记住。 再通过下列程序代码来熟悉四舍五入函数的用法: public class Math1 { public static void main(String[] args) { double x=4.51; System.out.println(Math.round(x));-------------------返回的是四舍五入的值 System.out.println(Math.floor(x));--------------------返回的是不大于 x 的最大整数 } } 运行结果: 5 4.0 通过以上两个例子可以看出,函数方法的使用很简单,关键是要注意其参数。纵观类库, 其实就是一个方法和属性的集合。至于类库的学习方法,关键是多练习,只要熟悉了类库中 各种方法的使用,也就掌握了类库。 7.3.3 测试时间和日期的类-Date 类 下面要介绍另一个比较重要的类:Date 类。Date 类包括了有关日期和时间操作的一些 方法。Date 类提供相应的方法,可将日期分解为年、月、日、时、分、秒。Data 类还可以 将日期转换成一个字符串,甚至可以执行反向的操作。 因为 Math 类中的方法和字段属性都是静态的,所以可以直接使用它。而 Date 类中的方 法和字段属性不是静态的,所以不能直接用“类.方法名或字段名”,必须使用“对象名.方 法名或字段名”。 如何将类变成对象呢?因为类是模板,对象是实物。在 Java 中,从模板中创建一个实 物是使用关键字“new”来实现的(在下一章会详细介绍创建对象方面的知识)。针对非静 96 态的类或方法,就要使用对象来操作,不能使用类来操作。 下面演示如何从类中产生一个对象: new Date() 这个表达式构造了一个日期对象,并把这个对象初始化为当前的日期和时间,其实可以 从一个类中,产生多个不同种的对象。Date 类可创建很多种不同的对象,如: Date(int year,int month,int date), Date(int year,int month,int date,int hrs,int min); 但是如果在程序中需要将时间显示出来,应该使用什么方法呢? 这里有两种方法:第一种方法是将 Date 对象作为一个参数,传给“println”方法。 import java.util.Date; public class Math1 { public static void main(String[] args) { System.out.println(new Date()); } } 运行结果: Fri Jun 29 14:33:30 CST 2007 这个程序代码段是显示当前的日期和时间。它将 Date()作为当前时间日期,然后将此对 象传给“println”方法。 另一种方法就是使用 Date 类中的一个方法:“toString”(有关这一点在前面已经介绍 过),它可以直接将时间日期,按照字符串的形式显示出来。 import java.util.Date; public class Math1 { public static void main(String[] args) { System.out.println(new Date()); System.out.println(new Date().toString()); } } 运行结果: Fri Jun 29 14:33:30 CST 2007 Fri Jun 29 14:33:30 CST 2007 这个例子将两种方法作了对比,其实从输出结果来看,是一模一样的。只是使用的方法 不同而已。下列代码段说明 Date 类中函数的用法: import java.util.Date; public class Math1 { public static void main(String[] args) { System.out.println(new Date().getDay()); System.out.println(new Date().getHours()); } } 运行结果: 5 15 97 7.3.4 测试日历的类--GregorianCalendar 类 在对 Date 类的介绍中,读者会发现 Date 类所表示的是一个时间点,也就是在创建对象 当时的时间点,而这对于进行日期的相关操作及运算,是非常不方便的。为此,前辈们在 Java 类库中,为开发者提供了一个方便操作日期的类:GregorianCalendar 类。其实 GregorianCalendar 类是 Calendar 类的一个扩展而已,Calendar 类是从总体上描述历法的类。 Date 类中也有用于得到日期的方法函数,如“getDay”、“getMonth”等方法函数,但 是这些方法已经不被推荐使用了,在程序中尽量不要使用不被推荐(deprecated)的方法函 数。相比之下,GregorianCalendar 类拥有更多的对日期操作的方法函数,GregorianCalendar 类的常用方法: Public int get(int field) 这里的“field”指的 Calendar 类中定义的常数,返回与“field”相关的日期。举个具体 的例子: import java.util.*; public class GregorianCalendar { public static void main(String[] args) { GregorianCalendar gc=new GregorianCalendar(); int X=gc.get(Calendar.MONTH); System.out.println(X); } } 运行结果: 5 “public void set(int field,int value)”将“field”所表示的日期替换成“value”的值, 举个具体的例子: import java.util.*; public class GregorianCalendar1 { public static void main(String[] args) { GregorianCalendar gc=new GregorianCalendar(); gc.set(Calendar.YEAR,2009); System.out.println(gc.get(Calendar.YEAR)); } } 运行结果: 2009 下面是有一些有关如何设置系统时间的方法。 “public final void set(int year,int month,int date)” “public final void set(int year,int month,int date,int hour,int minute)” “public final void set(int year,int month,int date,int hour,int minute,int second)” 这里的“final”在后面一章会讲述。上面的三个方法函数是指如何设定时间和日期。看 下列代码段,就可以明白以上这三个方法函数是什么含义: import java.util.*; public class Math1 { public static void main(String[] args) 98 { GregorianCalendar gc=new GregorianCalendar(); gc.set(2009,06,18); System.out.println(gc.get(Calendar.YEAR)); System.out.println(gc.get(Calendar.MONTH)); System.out.println(gc.get(Calendar.DATE)); } } 运行结果: 2009 6 18 在上面的例子里,先通过“set”方法设置年份为 2009 年,然后设置日期为 6 月,最后 设置日期是 18 号,然后再通过“get”访问器的方法取出值。 7.3.5 日历处理的实例解析 对于月历类来说,最重要的参数是年、月、日、小时、分、秒、毫秒,所以 Calendar 类提供了这些参数: YEAR(年)、MONTH(月)、DATE(日)、HOUR(小时)、MINUTE(分钟)、SECOND(秒)、MILLISECOND(毫 秒)。 另外一年还有十二个月的参数,所以 Calendar 类提供了: JANUARY(一月)、FEBRUARY(二月)、MARCH(三月)、APRIL(四月)、MAY(五月)、 JUNE(六月)、JULY(七月)、AUGUST(八月)、SEPTEMBER(九月)、OCTOBER(十月)、 NOVEMBER(十一月)、DECEMBER(十二月)。依次表示 1-12 个月份,需要注意的是它们从零 开始计算的。 例如: get(Calendar.MONTH)+1 另外,一周的每一天使得 Calendar 类提供了: SUNDAY(=1)、MONDAY(=2)、TUESDAY(=3)、WEDNESDAY(=4)、THURSDAY(=5)、 FRIDAY(=6)、SATURDAY(=7)。 如果获取星期或改变星期时使用: DAY_OF_WEEK。 如果表示上午/下午: AM_PM 上面介绍了很多常用函数和属性常量,下面看一个实例。 import java.util.*; public class calendar1 { public static void main(String args[]) { GregorianCalendar gc=new GregorianCalendar(); String now=gc.get(Calendar.YEAR)+" 年 "+(gc.get(Calendar.MONTH)+1)+" 月 "+gc.get(Calendar.DATE)+" 日 "+gc.get(Calendar.HOUR)+" 时 "+gc.get(Calendar.MINUTE)+" 分 "+gc.get(Calendar.SECOND)+"秒"; System.out.println("当前时间是:"+now); } } 运行结果 99 当前时间是:2007 年 7 月 12 日 4 时 30 分 12 秒 这个程序段很简单,对这个类中每一种函数,都展示了其用法。下面来编写一个稍微复 杂的实例,然后来仔细分析这个程序段的编程思路。有个人的生日是阳历 7 月 20 日,请输 出 2007—2020 年之间,这个人每年的生日究竟是星期几。 import java.util.*; public class calendar2 { public static void main(String[] args) { GregorianCalendar gc=new GregorianCalendar(); final char[] kor_week={'日','一','二','三','四','五','六'}; for(int i=2007;i<=2020;i++) { gc.set(i,Calendar.JULY,20); char week=kor_week[gc.get(Calendar.DAY_OF_WEEK)-1]; System.out.println(i+"年的生日是星期"+week); } } } 运行结果 2007 年的生日是星期五 2008 年的生日是星期日 2009 年的生日是星期一 2010 年的生日是星期二 2011 年的生日是星期三 2012 年的生日是星期五 2013 年的生日是星期六 2014 年的生日是星期日 2015 年的生日是星期一 2016 年的生日是星期三 2017 年的生日是星期四 2018 年的生日是星期五 2019 年的生日是星期六 2020 年的生日是星期一 这个程序的具体代码,很容易读懂。在此,需要讲述的是一个编程的思路问题。当拿到 这个程序的要求时,首先分析是要求输出“2007—2020”年之间每年的生日究竟是星期几, 这时就要考虑使用循环语句。 通过“set”函数将年份依次改为 2007—2020 年,这样就可以通过“get”函数返回此年 份月份和日子到底是星期几,如果是这样分析,编写它就不难了,剩下的只不过是一些细节 问题。 7.4 用实例分析设计一个类的流程 下面将会通过一个综合实例,来为读者总结本章中的一些比较重要的知识,从而为读者 总结一下编程思想。 100 7.4.1 如何在现实程序设计中提取一个类 在现实程序开发过程中,需要根据客户提供的要求来编写程序。在编写程序之前,要分 析客户的要求,这是很关键的一步。针对客户的要求,程序员要学会从客户要求中提取出类, 然后根据类再创建对象,在对象中规划出方法和属性值,最后,由这些方法和属性值共同完 成客户提供的要求。 下面举一个实例,通过这个实例来证明以上所讲述的步骤。 对于一个班的学生,开发一个学生信息的程序段。其要求如下所示: (1)男生有 10 名,女生有 15 名。请输出他们的姓名和性别、学号。 (2)其中张杰是男生,也是班长,请输出其信息。 (3)对所有学生的成绩信息进行输出。 (4)通过班上的成绩,选出最好的学生和最差的学生。 这个实例看起来有点复杂。其实仔细的分析应该不是很难。编写程序最关键是程序员的 思路,思路清晰了,代码自然很好解决,下面看看如何分析这个实例。 对于这个实例,从所有的要求看来,都是围绕着学生,所以提取一个类,就是学生类。 如下: class student { private name; private code; private sexy; private duty; private achievement; } 这个类中的变量是根据实例要求而定义的,这些变量就是类中的属性。再来分析实例中 需要程序员做什么事情,而要做的事情就是类中的方法。观察以上的 4 个要求,主要需要做 的事情是输出和排序,那么类的方法中必须要有输出方法和排序方法。 对于第一个要求输出的信息。可以编写下列方法函数。 Void print() { } 下面再来观察第二个要求、第三个要求,其实也是围绕着学生信息这个数组来输出的。 而第四个要求中,要求将所有的数据进行排序,选择出最大的数据和最小的数据。 好了,现在可以开始编写程序了,先来看看此程序的流程图。 101 学生类 学生对象1 学生对象2 学生对象3 设置器和访问器 设置器和访问器 设置器和访问器 将数据输出 图 7.1 有关类的创建的实例 看下面的代码。 ///这是一个学生类 ///通过带参数的构造器来构造对象 ///通过设置器来设置对象的属性 ///通过访问器来访问对象的属性 ///tostring 是一个将对象以字符串的形式输出的方法 public class student { String name=""; String code=""; String sexy=""; String duty=""; double achievement; public student(String name) { this.name=name; } void set(String name,String code,String sexy,String duty) { this.name=name; this.code=code; this.sexy=sexy; this.duty=duty; } public String getname() { return name; } public String getcode() {return code; } public String getsexy() {return sexy; } public String getduty() 102 {return duty;} public void setachi(double achievement) { this.achievement=achievement; } public double getachi() { return achievement; } public void print() { System.out.println("学生"+name+"的成绩是:"+achievement); } public String tostring() { String infor="学生姓名:"+name+";"+"学生学号:"+code+";"+"学生性别:"+sexy+";"+"学生职 务:"+duty; return infor; } ///这是主运行程序 ///构造出 25 个对象。使用带参数的构造器来构造。 ///再使用设置器来设置对象属性。 ///使用 tostring 方法来将对象信息输出 public static void main(String[] args) { ///构造出学生对象 student st1=new student("王浩"); student st2=new student("李敏"); student st3=new student("李杰"); student st4=new student("王杰"); student st5=new student("王超"); student st6=new student("赵浩"); student st7=new student("钱浩"); student st8=new student("王松"); student st9=new student("朱涛"); student st10=new student("张杰"); student st11=new student("王敏"); student st12=new student("孙洁"); student st13=new student("赵丽"); student st14=new student("王丽"); student st15=new student("钱珍"); student st16=new student("王珍"); student st17=new student("王萍"); student st18=new student("钱萍"); student st19=new student("王燕"); student st20=new student("赵燕"); student st21=new student("孙燕"); student st22=new student("孙丽"); student st23=new student("林丽"); student st24=new student("张丽"); student st25=new student("郑丽"); ///构造一个学生类的对象数组,将所有的对象放到数组内 103 student[]st=new student[]{st1,st2,st3,st4,st5,st6,st7,st8,st9,st10,st11,st12,st13,st14,st15,st16,st17,st18,st19,st20,st 21,st22,st23,st24,st25}; ///通过设置器对几个对象进行赋值 st1.set("王浩","1","男","班员"); st2.set("李敏","2","男","班员"); st3.set("李杰","3","男","班员"); st4.set("王杰","4","男","班员"); st5.set("王超","5","男","班员"); st6.set("赵浩","6","男","班员"); st7.set("钱浩","7","男","班员"); st8.set("王松","8","男","班员"); st9.set("朱涛","9","男","班员"); st10.set("张杰","10","男","班长"); st11.set("王敏","11","女","班员"); st12.set("孙洁","12","女","班员"); st13.set("赵丽","13","女","班员"); st14.set("王丽","14","女","班员"); st15.set("钱珍","15","女","班员"); st16.set("王珍","16","女","班员"); st17.set("王萍","17","女","班员"); st18.set("钱萍","18","女","班员"); st19.set("王燕","19","女","班员"); st20.set("赵燕","20","女","班员"); st21.set("孙燕","21","女","班员"); st22.set("孙丽","22","女","班员"); st23.set("林丽","23","女","班员"); st24.set("张丽","24","女","班员"); st25.set("郑丽","25","女","班员"); System.out.println(st1.tostring()); System.out.println(st2.tostring()); System.out.println(st3.tostring()); System.out.println(st4.tostring()); System.out.println(st5.tostring()); System.out.println(st6.tostring()); System.out.println(st7.tostring()); System.out.println(st8.tostring()); System.out.println(st9.tostring()); System.out.println(st10.tostring()); System.out.println(st11.tostring()); System.out.println(st12.tostring()); System.out.println(st13.tostring()); System.out.println(st14.tostring()); System.out.println(st15.tostring()); System.out.println(st16.tostring()); System.out.println(st17.tostring()); System.out.println(st18.tostring()); System.out.println(st19.tostring()); System.out.println(st20.tostring()); System.out.println(st21.tostring()); System.out.println(st22.tostring()); System.out.println(st23.tostring()); System.out.println(st24.tostring()); 104 System.out.println(st25.tostring()); ///通过设置器给几个对象进行赋值 st1.setachi(87.5); st2.setachi(98); st3.setachi(78); st4.setachi(90); st5.setachi(84); st6.setachi(78); st7.setachi(91); st8.setachi(99.5); st9.setachi(64); st10.setachi(100); st11.setachi(98); st12.setachi(76); st13.setachi(88); st14.setachi(64); st15.setachi(97); st16.setachi(68); st17.setachi(90); st18.setachi(99); st19.setachi(77); st20.setachi(78); st21.setachi(67); st22.setachi(99); st23.setachi(97.5); st24.setachi(92); st25.setachi(88); st1.print(); st2.print(); st3.print(); st4.print(); st5.print(); st6.print(); st7.print(); st8.print(); st9.print(); st10.print(); st11.print(); st12.print(); st13.print(); st14.print(); st15.print(); st16.print(); st17.print(); st18.print(); st19.print(); st20.print(); st21.print(); st22.print(); st23.print(); st24.print(); st25.print(); ///通过循环语句对数组元素进行排序 105 for(int i=0;i
还剩16页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享pdf获得金币 ] 0 人已下载

下载pdf

pdf贡献者

dagf113225

贡献于2016-10-17

下载需要 10 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf