面向对象程序设计(Java版)(txt+pdf+epub+mobi电子书下载)


发布时间:2020-07-23 18:34:57

点击下载

作者:武春岭 沈廷杰

出版社:人民邮电出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

面向对象程序设计(Java版)

面向对象程序设计(Java版)试读:

前言

根据我们针对计算机相关岗位招聘需求信息的调研,关于编程语言,高职院校的计算机相关专业学生应至少掌握或接触过一门面向对象的高级程序设计语言。学生掌握相关知识技能后,才能更好地胜任对应的工作岗位。而面向对象程序设计语言,从最近3年的TIOBE编程语言排行榜来看,Java一直处于前几名。所以,本书选取的编程语言是Java。本书在编写的过程中,“学习目标”是来自近期的实际岗位需求信息,由此梳理和整合的相关知识技能会更贴近岗位需求。

本书是针对Java的面向对象程序设计教材,既适合高职院校学生学习使用,也适合高职教师授课时参考,同时还可作为Java编程语言的初学者用书。本书的使用思路:根据所在高职院校学生现状和专业人才培养方案,对照本书学习目标,选取本书合适的章节进行教学大纲、教学计划等设计;选取对应章节合适的知识作为教学点,进行教学方案设计;选取对应章节的实训案例,指导学生练习。学生除了可以根据教师教授的内容进行复习和练习外,还可以挑选一些感兴趣的技术点学习,并就对应的案例进行练习。其他Java初学者,可以参考本书的目录按序学习和练习。

本书由重庆电子工程职业学院武春岭、沈廷杰任主编并执笔,朱崇来任副主编。内容共分10章,其中,沈廷杰编写第1章~第4章;武春岭编写第5章~第7章;朱崇来编写第8章~第10章。全书涵盖初识Java、控制结构、方法与数组应用、类与对象应用、反射机制与常用类应用、数据结构应用、集合应用、文件操作应用、线程应用、网络编程应用和软件测试应用。项目贯穿所有章节知识点,以“学习目标→任务引导→相关知识→任务实施→综合训练”为脉络,多方位提高学生的编程技术和能力,让学生得以掌握整个项目设计实施过程。其中,“学习目标”是当前行业实际岗位需求中的主流要求;“任务引导”是章节知识与技能的概要性导入;“相关知识”是章节目标对应所需的技能基础;“任务实施”是强化训练的案例题目与动手操作;“综合训练”是对重要知识的再梳理。全书内容精简、重点突出。

由于作者水平有限,书中难免存在不足之处,恳请广大读者不吝指正,我们将在再版时及时改进。若您在学习过程中遇到困难或疑问,可发送电子邮件至zhangtianyi@ptpress.com.cn。编者第1章 初识Java学习目标

• 能够搭建Java开发环境。

• 掌握Java注解方法。

• 能够利用Java基本数据类型进行表达式运算。任务引导

Java是一种可以开发跨平台应用软件的面向对象程序设计语言。Sun公司(已被Oracle收购)于1995年5月推出了Java程序设计语言和Java平台。在这二十多年的时间里,Java技术因为其具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于个人计算机、数据中心、游戏控制台、科学超级计算机、移动电话和互联网,因而拥有广大的开发者群体。在全球云计算和移动互联网的产业环境下,Java更具备了显著优势和广阔前景。

Java的基础知识包括Java的基本数据类型、常量和变量以及运算符和表达式。如果把程序比作房子,那么这些基础知识就类似于砖、瓦和水泥,对这些基础知识的深刻理解是编写高质量程序的基础。相关知识1.1 计算机语言

计算机语言是指用于人与计算机之间通信的语言。为了使计算机完成各项工作,就需要有一套用于编写计算机程序的数字、字符和语法规则,由这些字符和语法规则组成的计算机的各种指令(或各种语句),就是计算机能理解的语言。1.1.1 机器语言

机器语言是指一台计算机全部的指令集合。

机器语言是通常所说的第一代计算机语言,由二进制数“0”和“1”组成,并将这一串串由“0”和“1”组成的指令序列,交给计算机执行。

因而使用机器语言时,程序员就需要知道每个指令对应的“0”“1”序列,而这单靠记忆几乎是不可能完成的。在程序运行过程中,如果出错需要修改,那更是难上加难。

另外,每种类型的计算机,其指令系统各不相同。针对不同类型的计算机,完成相同功能的程序需要使用不同的指令系统编写。其实不少高级语言仍然没有解决类似的问题,但是Java的出现,在相当大的范围内解决了此问题,这就是Java的特性之一,即“一次编译,处处运行”。

上面提到了机器语言的诸多问题,不过正是因为这些问题,也说明了机器语言的一大好处——当面向特定类型的计算机时,机器语言的运行效率最高。1.1.2 汇编语言

程序员使用机器语言编写程序是非常痛苦的,其中一个原因就是难以记住每个指令对应的“0”“1”序列。为了让程序员从大量的记忆工作中解脱出来。人们进行了一种有益的改进,用一些简洁的、有一定含义的英文字符串来替代特定指令的“0”“1”序列。例如,用“MOV”代表数据传递、“DEC”代表数据减法运算。对于计算机而言,这些冰冷的机器是不懂“MOV”这类汇编语言的,计算机只认识“0”“1”序列。这样,在计算机上就需要有一个专门的程序,负责把汇编语言翻译成二进制的机器语言,这种翻译程序就是汇编程序。

对程序员而言,从机器语言到汇编语言,犹如人们从结绳计数发展到使用数字符号计数,工作效率得到极大提高。因而汇编语言也被称为第二代计算机语言。

汇编语言实质上和机器语言是相同的,都是直接对硬件操作,只不过汇编语言的指令采用了英文缩写的标识符,更易于识别和记忆。

不论是机器语言还是汇编语言,所发出的每一个指令只能对应实际操作过程中的一个细微动作,例如移动、自增等,要实现一个相对复杂的功能就需要非常多的步骤。例如,要完成“小张去传达室取回信件”的编程任务,这两种语言只能将任务分解成“向前n米”“向后n米”“左转”“右转”“上n个台阶”“下n个台阶”“伸手”等细微动作之后,再发出相应的指令,因而完成这样的一个任务,就得要几十个步骤,工作量很大。1.1.3 高级语言

从最初与计算机交流的痛苦经历中,人们意识到,应该设计一种这样的语言,其接近于数学语言或人的自然语言,同时又不依赖于计算机硬件,编出的程序能在所有计算机上运行。

经过努力,1954年,第一个完全脱离计算机硬件的高级语言——FORTRAN诞生。目前,影响较大、使用较广泛的高级语言有Java、C语言、C++、C#。另外还有一些其他类型的语言,比如智能化语言(LISP、Prolog、CLIPS……)、动态语言(Python、PHP、Ruby……)等。1.C语言

提到高级语言,必须要重点介绍一下C语言。

C语言是一种计算机程序设计语言,它既具有高级语言的特点,又具有汇编语言的特点。1972年由美国贝尔实验室推出C语言。1978年以后,C语言先后被移植到大型、中型、小型及微型机上。C语言功能非常强大,使用C语言既可以编写不依赖计算机硬件的应用程序,也可以编写操作系统(在操作系统及需要对硬件进行操作的场合,使用C语言明显优于其他高级语言)。C语言的应用范围广泛,单片机、嵌入式系统、二维动画、三维动画、游戏开发、数据业务处理等多方面都能看到它的身影。

为了方便和Java进行比较,下面简要介绍C语言的一些重要特点。(1)C语言(习惯上称为中级语言)把高级语言的基本结构和语句与低级语言的实用性结合起来,它可以像汇编语言一样对位、字节和地址进行操作。(2)C语言使用指针直接进行靠近硬件的操作,对于程序员而言显得更加灵活,但同时也给程序带来了安全隐患。在构建Java时,参考了C语言的诸多优势,但为了安全性,就取消了指针操作。2.C++

C++是具有面向对象特性的C语言。

面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。当今,程序开发思想已经全面从面向过程(C语言)分析、设计和编程发展到面向对象的模式。

通过面向对象的方式,将现实世界的事务抽象成类和对象,帮助程序员实现对现实世界的抽象与建模。通过面向对象的方法,采用更利于人理解的方式对复杂系统进行分析、设计与编程。3.C#

C#是一种面向对象的、运行于.NET Framework之上的高级程序设计语言。C#与Java惊人的相似(单一继承、接口、编译成中间代码再运行),就如同Java和C语言在基本语法上类似一样。在语言层面,C#是微软公司.NET Windows网络框架的主角。

和汇编语言相比,高级语言(第三代计算机语言)将许多硬件相关的机器指令合并成完成具体任务的单条高级语言,与具体操作相关的细节(如寄存器、堆栈等)被透明化。程序员只要会操作单条高级语句即可,即使没有深入掌握操作系统级别的细节,也可以开发出程序。1.2 Java发展史1.2.1 Java的诞生

1995年5月23日,在Sun World大会上,Sun公司第一次公开发布Java和HotJava浏览器。在这个会议上,网景公司(当时该公司浏览器占据浏览器市场份额的领先地位)宣布将在其浏览器中支持Java,随后一系列公司表示了对Java的支持,使Java很快成为一个极具发展潜力的高级语言。1.2.2 JDK 1.0发布

1995年,Sun公司推出的Java只是一种语言,而要想开发复杂的应用程序,必须要有一个强大的开发支持库。

1996年1月,Sun公司发布了JDK 1.0,它包括两部分:运行环境(Java Runtime Environment,JRE)和开发环境(Java Development Kit,JDK)。在运行环境中包括了核心应用程序接口(Application Programming Interface,API)、集成API、用户界面API、发布技术和Java虚拟机(Java Virtual Machine,JVM)5个部分,而开发环境还包括了编译Java程序的编译器(java compiler,javac)。在JDK 1.0时代,Java库显得比较单薄,不够完善。随着JDK的逐步升级,它为开发人员提供了一个强大的开发支持库。1.2.3 Java 2问世

1998年12月,Sun公司发布了Java历史上非常重要的一个JDK版本——JDK 1.2,并开始使用“Java 2”这一名称。从JDK 1.2发布开始,Java踏入了飞速发展的时期。

在Java 2时代,Sun公司对Java进行了很多革命性的改变,而这些革命性的变化一直沿用到现在,对Java的发展形成了深远的影响。

Java 2平台包括标准版(Java 2 Standard Edition,J2SE)、企业版(Java 2 Enterprise Edition,J2EE)和微缩版(Java 2 Micro Edition,J2ME)3个版本。

• J2SE:Java 2标准版包含构成Java核心的类,例如数据库连接类、接口定义类、输入/输出类、网络编程类。

• J2EE:Java 2企业版除了包含J2SE中的类外,还包含用于开发企业级应用的类,例如EJB、Servlet、JSP、XML、事务控制。

• J2ME:Java 2微缩版包含J2SE中一部分类,用于消费类电子产品的软件开发,例如寻呼机、智能卡、手机、PDA、机顶盒。

此后,还发布了以下主要版本的Java。

2000年5月,J2SE 1.3发布。

2002年2月,J2SE 1.4发布。1.2.4 JavaSE 5.0发布

2004年9月30日,J2SE 1.5发布,成为Java发展史上的又一里程碑。为了表示该版本的重要性,J2SE 1.5更名为JavaSE 5.0。

在JavaSE 5.0中,主要包含以下主要新特性。

• 泛型。

• 增强for循环。

• 自动拆箱和装箱。

• 类型安全的枚举。

• 静态导入。

• Annotation注解。1.2.5 JDK 7.0发布

2011年7月,JDK 7.0发布,增加了一些新的功能。例如,原来switch结构的条件中只能包含byte、short、int、char类型,从7.0开始,其中可以包含字符串了。1.2.6 JDK 8.0发布

2014年3月,JDK 8.0发布。该版本引入了新的语言特性——Lambda表达式,它可为Java提供匿名函数类型,用户可以将函数作为一个方法的参数,或将代码作为数据。Lambda表达式能够使表达单一方法接口的实例更紧凑;完善重复注释功能,即可以在同一申明类型(类、属性或方法)中多次使用同一个注解,可读性更强;改进了类型注解,使其可以应用在任何地方。Lambda表达式与可插入的类型系统配合使用,使代码的类型检查更加完善,改进了泛型类型推断。使用JDK 7.0版本创建泛型实例时的类型推断是有限制的:只有构造器的参数化类型在上下文中被显著声明,才能使用类型推断,否则不能使用。而JDK 8.0版本支持通过方法上下文推断泛型目标类型,也支持在方法调用链路当中,泛型类型推断传递到最后一个方法,并新增方法参数反射。用户可以将方法参数的元信息存储到编译完的.class文件中,使程序可以在运行时通过反射来获取参数的元信息。1.2.7 JDK 9.0发布

2017年7月,JDK 9.0发布。在JavaSE 9.0中,主要包含以下主要新特性。

• 模块化的源代码。

• 轻量级的JSON API。

• 系统进程管理。

• 完善竞争锁。

• 分段代码缓存。

• 智能Java编译器。1.2.8 JDK 10.0发布

2018年3月,JDK 10.0发布。在JavaSE 10.0中,主要包含以下主要新特性。

• 局部变量类型推断。

• 整合JDK代码仓库。

• 统一的垃圾回收接口。

• 并行全垃圾回收器G1。

• 应用程序类数据共享。

• 线程局部管控。

• 移除Native-Header自动生成工具。

• 额外的Unicode语言标签扩展。

• 备用存储装置上的堆分配。

• 根证书认证。1.3 Java的特点

要想系统地说明Java的特点,需要大篇幅、长时间地介绍。以下是Java的主要特点。

• Java是简单的。

• Java是面向对象的。

• Java是分布式的。

• Java是健壮的。

• Java是安全的。

• Java是平台无关的。

• Java是可移植的。

• Java是解释型的。

• Java是高性能的。

• Java是多线程的。

• Java是动态的。

随着本书内容的深入,会逐步学习到这些具体的内容,这里仅就以下3点做简要介绍。1.3.1 Java是面向对象的

面向对象其实是现实世界模型的自然延伸,现实世界中任何实体都可以看作对象,对象之间通过消息相互作用。

另外,现实世界中任何实体都可归属于某类事物,任何对象都是某一类事物的实例。

传统的过程式编程语言以过程为中心,以算法为驱动(程序=算法+数据)。面向对象编程语言则以对象为中心,以消息为驱动(程序=对象+消息)。

Java是典型的面向对象语言,具体面向对象的概念和应用,会在后面的章节中详细介绍。1.3.2 Java是平台无关的

所谓Java是平台无关的语言,是指用Java编写的应用程序,编译成字节码文件(.class后缀)后,不用修改就可在不同的软/硬件平台上运行。

平台无关有两种:源代码级和目标代码级。C语言和C++具有源代码级平台无关性(没完全做到),表明用C语言或C++写的程序不用修改,在不同的平台上重新编译后,就可以在对应平台上运行。而Java是目标代码级的平台无关,使用JDK编译成的字节码文件,只要在安装有Java虚拟机的平台上就可以运行,这就是通常说的“一次编译,处处运行”。1.3.3 Java语言是健壮的

强类型机制、丢弃指针、垃圾回收机制、异常处理等是Java健壮性的重要保证,对指针的丢弃是Java明智的选择。

Java是强类型的语言。Java要求使用显式的方法声明,这样编译器就可以发现方法调用错误,保证程序的可靠性。

Java丢弃了指针。这样可以避免内存的非法访问,虽然牺牲了程序操作的灵活性,但对程序的健壮性而言,不无裨益。

Java的垃圾回收机制是Java虚拟机提供的管理内存的机制,用于在空闲时间以不定时的方式动态回收无任何引用的对象所占据的内存空间。

Java提供了异常处理机制,程序员可以把一组可能出错的代码放在一个地方,针对可能的错误(异常)编写处理代码,简化错误处理过程,便于恢复。1.4 Java程序工作原理1.4.1 Java虚拟机

Java虚拟机(Java Virtual Machine,JVM)不是一台真实的机器,而是想象中的机器,通过模拟真实机器来运行Java程序。

虽然是模拟出来的机器,但Java虚拟机同样有硬件,如处理器、堆栈、寄存器等,还具有相应的指令系统。

Java虚拟机是Java程序的运行环境,Java程序运行在这个抽象的Java虚拟机上,这也是Java最具吸引力的特性之一。

前文提到过,Java的一个重要特点就是目标代码级的平台无关性,接下来将从原理上进一步说明为什么Java具有这样的平台无关性。实现Java“一次编译,处处运行”的关键就是使用了Java虚拟机。

例如,使用C语言开发一个类似计算器的软件,如果想要这个软件在Windows平台上运行,则需要在Windows平台上编译成目标代码,这个计算器的目标代码只能在Windows平台上运行。而如果想让这个软件能在Linux平台上运行,则必须在对应的平台上编译,产生针对该平台的目标代码,才可以运行。

对Java而言,则完全不是这样的。用Java编写的计算器程序(.java后缀)经过编译器编译成字节码文件,这个字节码文件不是针对具体平台的,而是针对抽象的Java虚拟机的,是在Java虚拟机上运行的。在不同的平台上,安装不同的Java虚拟机,这些不同的Java虚拟机屏蔽了各个不同平台的差异,从而使Java程序(字节码文件)具有平台无关性。也就是说,Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行,具体原理如图1.1所示。图1.1 Java虚拟机

在理解了Java虚拟机的基础上,接下来介绍Java程序工作原理。如图1.2所示,Java字节码文件先后经过Java虚拟机的类装载器、字节码校验器和解码器,最终在操作系统平台上运行。各部分的主要功能描述如下。图1.2 Java程序工作原理

• 类装载器,其主要功能是为执行程序寻找和装载所需要的类,就是把字节码文件装到Java虚拟机中。

• 字节码校验器,其功能是对字节码文件进行校验,保证代码的安全性。字节码校验器负责测试代码段格式并进行规则检查,检查伪造指针、违反对象访问权限或试图改变对象类型的非法代码。

• 解码器,具体的平台并不认识字节码文件,最终起作用的还是这个解码器,它将字节码文件翻译成所在平台能识别的东西。1.4.2 垃圾回收机制

在C++中,程序结束运行之前对象会一直占用内存,且程序员明确释放之前不能将其所占内存分配给其他对象。而Java的处理方式不同,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾。

Java虚拟机提供了一个系统级线程(垃圾回收器线程),它自动跟踪每一块被分配出去的内存空间,自动释放被定义成垃圾的内存。

垃圾回收机制能自动释放内存空间,减轻程序员编程的负担,这是Java虚拟机具有的一个显著优点。在没有垃圾回收机制的时候,可能要花许多时间来解决释放无用内存的问题,而用Java编程的时候,靠垃圾回收机制可大大缩短时间。

垃圾回收机制是一个系统级的线程,它给程序员带来好处的同时,也存在着影响系统性能的问题,因为它要追踪分配的内存,释放没用的内存,而这个过程需要花费系统资源。

程序员可以调用System.gc()这个方法通知Java虚拟机释放无用资源,但Java虚拟机会选择在合适的时候释放无用资源,具体释放的时间,不是程序员调用System.gc()的时刻,而是Java虚拟机决定的,程序员不能精确控制和干预。1.5 Java SE的结构

Java SE是Java的基础,它包含Java基础、JDBC数据库操作、I/O(输入/输出)、网络通信、多线程等技术。

JDK是一个Java应用程序的开发环境。它由两部分组成,下层是处于操作系统层之上的运行环境,上层由编译工具、调试工具和运行Java应用程序所需的工具组成。

JDK主要包含以下基本工具(仅列举部分常用的工具)。

• javac:编译器,将源程序转成字节码文件。

• java:执行器,运行编译后的字节码文件。

• javadoc:文档生成器,从源码注释中自动产生Java文档。

• jar:打包工具,将相关的类文件打包成一个文件。

JDK包含以下常用类库。

• java.lang:系统基础类库,其中包括字符串类String等。

• java.io:输入输出类库,进行文件读写时需要用到。

• java.net:网络相关类库,进行网络通信时会用到其中的类。

• java.util:系统辅助类库,编程中经常用到的集合属于这个类库。

• java.sql:数据库操作类库,连接数据库、执行SQL语句、返回结果集需要用到该类库。

• javax.servlet:JSP、Servlet等使用到的类库,是Java后台技术的核心类库。1.6 标识符和关键字

标识符是编程时使用的名字。使用某个东西时,要用到它的名字来标识它,给这个东西起的名字,也需要有一定的规则,不能随便乱起名字。而关键字是事先定义好的、有特殊意义的标识符。1.6.1 标识符

Java对各种变量、方法和类等要素命名时使用的字符序列称为标识符。

Java标识符有如下命名规则。(1)标识符由字母、数字、下划线“_”、美元符号“$”组成,并且首字符不能是数字。(2)不能把Java关键字作为标识符。(3)标识符没有长度限制。(4)标识符对大小写敏感。

在企业的面试题里,常会出现这样的题目,下面的标识符中哪些是非法的?

stuAge、*stuName、ount、3heartNum、public、x+y、_carSpeed、length10

*stuName是非法的,原因是不能含“*”;3heartNum是非法的,原因是首字符不可以是数字;public是非法的,原因是不可以是Java关键字;x+y是非法的,原因是不能含“+”。其他的标识符都是合法的。

作为一名程序员,写的程序中标识符不仅要合法,而且要简短且能清楚地表明含义,同时还要符合Java标识符的命名规范,这样可以让程序规范、易读。下面列举了不同类型(后面会详细介绍)标识符的命名规则。

• 对于变量名和方法名,要求第一个单词应以小写字母作为开头,后面的每个单词则都要以大写字母开头,例如stuAge、sendMessage。

• 对于类名,它和变量名、方法名的区别在于,第一个单词的首字母也需要大写,如果类名称中包含单词缩写,则这个缩写词的每个字母均应大写,例如XMLModule。另外,由于类是用来代表对象的,所以在命名类时应尽量选择名词。

• 常量标识符应该都使用大写字母,并且指出该常量完整的含义。如果一个常量名称由多个单词组成,则应该用下划线来分割这些单词,例如MAX_VALUE。1.6.2 关键字

Java关键字对Java编译器有特殊的意义,它们用来表示一种数据类型或者表示程序的结构,关键字不能用作变量名、方法名、类名和包名。

大多数的编辑器(例如Eclipse和UltraEdit,不含记事本)和集成开发环境(Eclipse和MyEclipse)都会用特殊的方式(通常用蓝色)把Java关键字标识出来。

Java关键字都是小写的英文字符串,goto这个标识符虽然很少使用,但也作为Java关键字进行保留,需要注意。图1.3列出了所有的Java关键字。图1.3 Java关键字1.7 Java注解1.7.1 Java注解

从JDK 1.5开始,Java引入了源代码中的注解这一机制。注解使得Java源代码不但可以包含功能性的实现代码,还可以添加元数据。注解看起来有点类似于代码中的注释,所不同的是注解不是为了说明代码功能,而是为了实现程序功能。

在介绍注解的概念前,首先介绍元数据的概念。所谓元数据,就是描述数据的数据。举个例子,比如一张图片,图片的内容为主体数据,是需要展现给图片浏览者看到的信息,而图片的创建日期这类信息就是元数据,是用来描述图片内容这个数据的数据。

元数据有什么用呢?还是以图片创建日期为例,假设我现在想找一张2013年8月1日拍的照片,在计算机中就可以根据这个创建日期查找到该照片。再举一个例子,在编写Java注释的时候,如果按照某种特定的规范编写Java注释,则可以通过javadoc工具将这些注释自动生成帮助文档,这些按规定编写的Java注释就属于元数据,用来描述程序。我们可以用元数据来创建文档、跟踪代码,执行编译时检查格式,并可以用其代替原系统中原有的配置文件。

Java注解是Java代码里的特殊标记,为我们在代码中添加用Java程序无法表达的额外信息提供了一种形式化的方法,使我们可以在未来某个时刻方便地使用这些被注解修饰的程序元素(这些程序元素包括类、属性、方法等)。

注解看起来有些像注释,但其和注释还是有显著区别的。虽然注解和注释都属于对代码的描述,但注释的作用只是简单地描述程序信息,方便开发者再次阅读,不会被程序所读取,而注解则是Java代码中的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理,两者作用相差很大。

通过使用注解,程序开发人员可以在不改变程序原有逻辑的情况下,在源代码中加入一些补充信息,代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证和部署。下面的代码展示了注释和注解。

刚才介绍了Java注解的基本概念,现在来看一下Java注解的语法。使用注解时要在其前面加一个“@”符号,表明后面的内容为注解。Java注解有3种形式。

• 不带参数的注解:@Annotation,例如@Override。

• 带一个参数的注解:@Annotation(参数),例如@SuppressWarings(value="unused")。

• 带多个参数的注解:@Annotiation({参数1,参数2,参数3...}),例如@MyTag(name:="jhon", age=20)。1.7.2 内建注解

在Java的java.lang包中,预定义了3个注解,它们分别是限定重写父类方法的@Override注解,标记已过时的@Deprecated注解和抑制编译器警告的@SuppressWarnings注解,通常称这3个注解为内建注解或基本注解。@Override注解

@Override注解被用于标注方法,被该注解标注的方法是重写了父类的方法,起到了确定的作用。下面通过一个例子演示@Override注解的作用。

假设“租车系统”中Vehicle类和Truck类的代码如下,其中Truck类继承自Vehicle类,且重写了Vehicle类的drive()方法(根据需求这个方法必须要重写)。

注:“租车系统”是贯穿全书的一个案例,是围绕车辆的特性和行为进行的类的设计和实现,以下代码仅演示@Override注解的作用。本书3.6节将详细介绍“租车系统”的相关知识。

编译、运行Truck类,程序可以按用户需求执行。但是有可能程序员在写Truck类的代码时,误将drive()写成了driver(),然而在执行t1.drive();语句时,因为drive()方法并未被重写,因此t1.drive()调用的还是Vehicle类的drive()方法。不幸的是,这种错误程序编译时是不会报错的,即使在运行时如果不跟踪代码也不容易发现这个错误,这样最终会为以后修复这个错误带来很大的困难。

@Override注解就是为了解决类似的问题,我们可以在子类重写父类的方法前加上@Override,表示这个方法是覆盖了父类的方法。如果该方法不是覆盖了父类的方法,例如将drive()写成了driver(),此时如果在driver()方法前加上@Override注解的话,则代码编译不会通过,将提示被@Override注解的方法必须在父类中存在同样的方法,程序才能编译通过。

需要补充一句,@Override注解只能用来修饰方法,不能用来修饰其他元素。@Deprecated注解

如果读者之前使用Eclipse等集成开发环境编写过Java程序,会经常在属性或方法提示中看到@Deprecated。如果某个类成员的提示中出现了@Deprecated,就表示这个类成员已经过时,在未来的JDK版本中可能被删除,不建议使用。之所以现在还保留,是因为给那些已经使用了这些类成员的程序一个缓冲期,否则如果现在就删除这个类成员,那么这些程序就无法在新的环境下编译运行了。

在第8章介绍多线程的时候,我们会提到终止一个线程可以调用这个线程的stop()方法,但该方法已被废弃,不建议使用。通过查看JDK API,我们可以看到Thread类的stop()方法是被@Deprecated注解标注的,所以准确来说,这个stop()方法是因为过时而不建议使用。

简化前面Truck类的代码,并在drive()方法前使用@Deprecated注解标注。如果集成开发环境换成Eclipse,则在方法定义处、方法引用处及成员列表中都有变化,如图1.4所示。

这个例子中,Truck类的drive()方法被@Deprecated注解标注,提醒程序员这是一个过时的方法,尽量不要使用,避免以后出现问题。假设有个BigTruck类继承Truck类,并且重写了这个过时的drive()方法,又会怎样呢?编译程序,编译器会报错,提示“注意:BigTruck.java使用或覆盖了已过时的API。”和“注意:要了解详细信息,请使用-Xlint:deprecation重新编译。”图1.4 @Deprecated注解的使用@SuppressWarnings注解

这个世界总是这么奇妙,既然有可以使编译器产生警告信息的注解,那么通常也会有抑制编译器产生警告信息的注解,@SuppressWarnings注解就是为了这样一个目的而存在的。先看看下面的代码。

编译程序,编译器会抛出警告信息“注意:TestZuChe.java使用了未经检查或不安全的操作。”和“注意:要了解详细信息,请使用Eclipse保存。”。显示结果如图1.5所示。图1.5 编译器警告信息

这个警告信息提示List类必须使用泛型才是安全的,才可以进行类型检查,现在未做检查,所以存在不安全因素。如果想取消这些警告信息,可使用如下代码。

再次编译程序,警告被抑制。当然,编译器发出警告,是要提醒程序员有哪些地方需要注意,抑制警告不是目的,正确的解决办法是使用泛型对集合中的元素进行约束,使对集合的操作可以被检查,如代码中被注释的部分那样。

@SuppressWarnings注解和前面两个注解不同之处在于,这个注解带一个参数,或者说有—个属性。注解@SuppressWarnings(value="unchecked")的含义为抑制不检查的警告。当然还可以同时抑制其他警告,例如@SuppressWarnings( value={"unchecked", "unused"})就同时抑制了不检查和未被使用的警告。下面列举了@SuppressWarnings注解相关属性值的含义。

• deprecation:使用了过时的程序元素。

• unchecked:执行了未检查的转换。

• unused:有程序元素未被使用。

• fallthrough:switch程序块直接通往下一种情况而没有break。

• path:在类路径中有不存在的路径。

• serial:在可序列化的类上缺少serialVersionUID定义。

• finally:任何finally子句不能正常完成。

• all:所有情况。1.7.3 自定义注解

本节主要介绍自定义注解。不过要想让自定义注解真正起作用,必须要了解Java提供的4个元注解(用于修饰注解的注解):@Target、@Retention、@Documented和@Inherited。

注解之所以强大,能被众多框架所使用的主要原因在于,它可以允许程序员自定义注解,使Java程序变成自描述的。注解的语法形式和接口差不多,只是在interface前面多了“@”符号。

上面的代码是一个比较简单的注解,这个注解没有属性。我们可以在自定义注解时定义属性,在注解类型的定义中以无参方法的形式来声明,其方法名和返回值分别定义了该属性的名字和类型,其代码如下所示。

可以按如下格式使用MyAnnotation注解。

接下来修改自定义注解MyAnnotation,使其含两个属性,具体代码如下所示。

在注解中可以定义属性,也可以给属性赋默认值,具体代码如下所示。

定义了注解之后,接下来就可以在程序中使用注解,使用注解的代码如下所示。

请注意注释的描述,使用带属性的注解时,需要给属性赋值。不过如果在定义注解时给属性赋了默认值,则可使用不带属性值的注解,也就是让注解使用自己的默认值。

前文虽然讲解了自定义注解,但是肯定有不少读者觉得学完之后,心里空空的,不知道自定义注解到底有什么用?下面就来解决这个问题。

在自定义注解时,注解看起来和类、接口比较类似,尤其看起来更像接口。注解可以理解为和接口一样,是程序的一个基本组成部分。既然可以对类、接口、方法和属性等进行注解,那么当然也可以对注解进行注解。

使用不同注解对注解进行注解的方法,和对类、接口进行注解的方法一样,所不同的是,Java为注解单独提供了4种元注解,即@Target、@Retention、@Documented和@Inherited、下面分别介绍这4种元注解。@Target注解

@Target元注解很容易理解,Target中文含义为目标,使用@Target注解的目的是用于指定被修饰的注解能用于修饰哪些程序元素。如果注解定义中不存在@Target元注解,则此注解可以用在任一程序元素上,如果存在这样的元注解,则编译器强制实施指定的使用限制。

此注解类型有唯一的value作为成员变量,其定义为public abstract ElementType[]value。接下来看这样的案例,将之前自定义的注解用@Target进行注解,以限制此注解只能使用在属性上。此时如果将此注解使用在方法上,编译器会报出“注释类型不适用于该类型的声明”的错误。案例具体代码如下所示。

@Target注解的属性value可以为如下值,被@Target注解的注解只能用来注解对应的目标。

• ElementType.ANNOTATION_TYPE:注解类型声明。

• ElementType.CONSTRUCTOR:构造方法声明。

• ElementType.FIELD:字段声明(包括枚举常量)。

• ElementType.LOCAL_VARIABLE:局部变量声明。

• ElementType.METHOD:方法声明。

• ElementType.PACKAGE:包声明。

• ElementType.PARAMETER:参数声明。

• ElementType.TYPE:类、接口(包括注解类型)或枚举声明。@Retention注解

@Retention元注解用于指定被修饰的注解可以保留多长时间。如果注解定义中不存在@Retention元注解,则保留策略默认为RetentionPolicy.CLASS。

@Retention包含一个RetentionPolicy类型的value属性,使用此注解时必须为该value属性指定值。@Retention注解的value属性允许的值及含义整理如下。

• RetentionPolicy.CLASS:编译器把注解记录在class文件中,当运行Java程序时,虚拟机不再保留注解。

• RetentionPolicy.RUNTIME:编译器把注解记录在class文件中,当运行Java程序时,虚拟机保留注解,程序可以通过反射获取该注解。

• RetentionPolicy.SOURCE:编译器将直接丢弃被修饰的注解。

接下来通过一个案例,演示通过反射获取注解,具体代码如下。案例中提供了较为详细的注释。

代码中getObjectInfo()方法有两个注解,@MyAnnotation和@Deprecated,其中自定义注解@MyAnnotation的元注解@Retention的值为RetentionPolicy.RUNTIME,含义为当运行Java程序时,虚拟机保留注解,所以在运行时可以通过反射机制获取该注解。程序运行结果如图1.6所示。@Deprecated为内建注解,通过运行结果可以看出@Deprecated的元注解@Retention的值也是RetentionPolicy.RUNTIME。图1.6 通过反射机制获取注解@Documented注解

一看这个元注解的名字,就知道它和文档有关。默认的情况下使用javadoc工具自动生成文档时,注解将被忽略掉。如果想在文档中也包含注解,必须使用@Documented为文档注解。@Documented注解类型中没有成员变量。如果定义注解时使用了@Documented修饰,则所有使用该注解修饰的程序元素的API文档中都将包含该注解说明。

使用javadoc生成文档,产生的文档对TestAnnotation类的描述如下。

如果取消对@Documented的注释,使其起作用,将会出现另一个结果。@Inherited注解

继承是面向对象的特性之一,Java是典型的面向对象语言,所以继承是Java的典型特性。前文讲过,注解是程序的一个基本组成部分,那么父类的注解是否被子类继承呢?默认情况下,父类的注解不被子类继承,如果要想继承父类注解,就必须使用@Inherited元注解。接下来通过下面的代码,介绍@Inherited注解的含义。

通过以上的代码,Truck类和Vehicle类一样都被MyAnnotation注解了。1.8 变量和常量1.8.1 变量

变量是一段有名字的连续存储空间(存储在计算机内存中)。在Java代码中通过定义变量来申请并命名这样的存储空间,并通过变量的名字来使用这段存储空间。通过给变量赋值可以改变变量的值,所以称之为变量。变量是程序中数据的临时存放场所,变量中可以存放字符串、数值、日期和对象等。

Java变量的核心要素是变量类型、变量名和变量值,其声明格式如下。

其中type表示Java的数据类型(1.9节会详细介绍Java的基本数据类型),其含义为这个变量里存的是什么类型的数据。varName是变量名,通过这个变量名使用这个变量。value是变量值,在声明变量的时候可以不初始化变量值。通过varName=newValue,可以给这个变量赋新的变量值。

对于内存而言,“type varName”是声明变量,相当于根据数据类型向内存申请一块空间,而“=value”相当于把变量值放到这个内存空间中。例如int stuAge=22(省略分号,以下同),可以拆分成int stuAge和stuAge=22两条语句,其中int stuAge相当于向内存申请一块可以存储int型变量的空间(实际为4字节,32位),而stuAge=22相当于把22放到了这块内存空间中。接下来还可以通过stuAge=27这条语句把27放到刚才的内存空间中,原来的22就不存在了。

在使用变量时,要避免出现未赋值就使用的情况。虽然在后面的章节中,会看到一些变量即使不赋值也会有默认值,但作为程序员,为了避免程序出错,也要做到变量先赋值后使用。1.8.2 常量

在Java语言中,利用final关键字来定义Java常量,其本质为值不可变的变量。

因为Java常量的本质是值不可变的变量,所以在声明的时候,就必须要进行初始化。和变量不同的是,Java常量在程序中将无法再进行赋值,如果强行赋值,程序会抛出错误信息,并拒绝接受这一个新的值。例如,执行下面的程序(为了节省篇幅,代码中省去了部分注释)。

程序运行结果如图1.7所示。图1.7 改变常量的值1.9 Java数据类型

变量声明包括变量的数据类型和变量名,那什么是数据类型呢?什么是Java的数据类型和Java基本数据类型呢?

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载