diff --git a/guide/README.md b/guide/README.md index 5bbfe51..1a3a237 100644 Binary files a/guide/README.md and b/guide/README.md differ diff --git a/guide/enum.lyx b/guide/enum.lyx index f849706..685ff93 100644 --- a/guide/enum.lyx +++ b/guide/enum.lyx @@ -827,7 +827,17 @@ cSignal增加了value属性以表明不同颜色交通信号灯所代表的意 \end_inset 或者“hold on”时,只需要修改TrafficSignal类的定义即可,其他引用TrafficSignal的类都不需要修改,也就是说,我们的代码可以很好的适 -用未来的变化:用尽量小的代价应对未来的需求变化,软件的可维护性就大大提高了。 +用未来的变化:用尽量小的代价应对未来的 +\begin_inset Flex Emph +status open + +\begin_layout Plain Layout +需求变化 +\end_layout + +\end_inset + +,软件的可维护性就大大提高了。 \begin_inset Flex Emph status open @@ -872,7 +882,7 @@ reference "Month.java" \end_layout \begin_layout Exercise -定义一个enum Planet表示太阳系各行星的名称、质量和半径。 +定义一个enum Planet表示太阳系各行星的名称、质量和半径,并设计一个方法计算在这个星球上的物体的重量。 \begin_inset CommandInset label LatexCommand label name "exer:定义一个enum-Planet表示太阳系各行星的名称、质量和半径" diff --git a/guide/imgs/intro/duke.png b/guide/imgs/intro/duke.png new file mode 100644 index 0000000..878543f Binary files /dev/null and b/guide/imgs/intro/duke.png differ diff --git a/guide/imgs/io/input-from-keyboard-stream.jpeg b/guide/imgs/io/input-from-keyboard-stream.jpeg new file mode 100644 index 0000000..7a91932 Binary files /dev/null and b/guide/imgs/io/input-from-keyboard-stream.jpeg differ diff --git a/guide/imgs/io/inputstream.dia.autosave b/guide/imgs/io/inputstream.dia.autosave new file mode 100644 index 0000000..6706e91 Binary files /dev/null and b/guide/imgs/io/inputstream.dia.autosave differ diff --git a/guide/imgs/io/inputstream.jpeg b/guide/imgs/io/inputstream.jpeg new file mode 100644 index 0000000..35ac891 Binary files /dev/null and b/guide/imgs/io/inputstream.jpeg differ diff --git a/guide/imgs/io/reader-writer.jpeg b/guide/imgs/io/reader-writer.jpeg new file mode 100644 index 0000000..682652f Binary files /dev/null and b/guide/imgs/io/reader-writer.jpeg differ diff --git a/guide/imgs/tests/oopbasic-model.jpeg b/guide/imgs/tests/oopbasic-model.jpeg new file mode 100644 index 0000000..61f5d35 Binary files /dev/null and b/guide/imgs/tests/oopbasic-model.jpeg differ diff --git a/guide/intro.lyx b/guide/intro.lyx index e3718d6..5ffe3f9 100644 --- a/guide/intro.lyx +++ b/guide/intro.lyx @@ -1,5 +1,5 @@ -#LyX 2.2 created this file. For more info see http://www.lyx.org/ -\lyxformat 508 +#LyX 2.3 created this file. For more info see http://www.lyx.org/ +\lyxformat 544 \begin_document \begin_header \save_transient_properties true @@ -36,6 +36,8 @@ PackageOptions url hyphens \font_osf false \font_sf_scale 100 100 \font_tt_scale 100 100 +\use_microtype false +\use_dash_ligatures true \graphics default \default_output_format pdf4 \output_sync 0 @@ -75,6 +77,7 @@ PackageOptions url hyphens \suppress_date false \justification true \use_refstyle 1 +\use_minted 0 \boxbgcolor #dad3d7 \index Index \shortcut idx @@ -84,7 +87,10 @@ PackageOptions url hyphens \tocdepth 2 \paragraph_separation indent \paragraph_indentation default -\quotes_language english +\is_math_indent 0 +\math_numbering_side default +\quotes_style english +\dynamic_quotes 0 \papercolumns 1 \papersides 2 \paperpagestyle default @@ -128,6 +134,7 @@ Java在程序设计语言中的霸主地位 \begin_inset CommandInset citation LatexCommand cite key "progamming-lang-stats" +literal "true" \end_inset @@ -148,6 +155,7 @@ http://www.tiobe.com/ LatexCommand cite after "p109" key "code-future" +literal "true" \end_inset @@ -202,6 +210,7 @@ Java程序设计语言是不是天生丽质,一开始就大红大紫呢? \begin_inset CommandInset citation LatexCommand cite key "java-history-wikimedia" +literal "true" \end_inset @@ -218,12 +227,12 @@ lines 0 placement l overhang 0in width "20line%" -status collapsed +status open \begin_layout Plain Layout \align center \begin_inset Graphics - filename imgs/intro/duke.svg + filename imgs/intro/duke.png width 90line% \end_inset @@ -375,7 +384,7 @@ lines 0 placement o overhang 0in width "50col%" -status collapsed +status open \begin_layout Plain Layout \align right @@ -544,6 +553,7 @@ reference "fig:Java简史" \begin_inset CommandInset citation LatexCommand cite key "java-brief-history" +literal "true" \end_inset @@ -1463,6 +1473,7 @@ Idea是 LatexCommand href name "JetBrains" target "https://www.jetbrains.com" +literal "false" \end_inset @@ -2567,6 +2578,7 @@ Eclispe是当下非常流行的Java开发IDE环境,以丰富的插件著称, LatexCommand href name "http://www.eclipse.org" target "http://www.eclipse.org" +literal "false" \end_inset @@ -2817,8 +2829,7 @@ reference "fig:Scanner的常用函数" \begin_layout Standard \noindent \align center -\begin_inset Float figure -placement tbph +\begin_inset Float table wide false sideways false status open diff --git a/guide/io.lyx b/guide/io.lyx index f9d44a8..c26821d 100644 --- a/guide/io.lyx +++ b/guide/io.lyx @@ -4570,10 +4570,19 @@ status open \begin_inset Text +\begin_layout Plain Layout +\begin_inset Flex Code +status open + \begin_layout Plain Layout String toString() \end_layout +\end_inset + + +\end_layout + \end_inset @@ -4590,10 +4599,19 @@ String toString() \begin_inset Text +\begin_layout Plain Layout +\begin_inset Flex Code +status open + \begin_layout Plain Layout Path getFileName() \end_layout +\end_inset + + +\end_layout + \end_inset @@ -4611,10 +4629,19 @@ etFileName实际上会调用返回的Path对象的toString方法。 \begin_inset Text +\begin_layout Plain Layout +\begin_inset Flex Code +status open + \begin_layout Plain Layout Path getName(int index) \end_layout +\end_inset + + +\end_layout + \end_inset @@ -4631,10 +4658,19 @@ Path getName(int index) \begin_inset Text +\begin_layout Plain Layout +\begin_inset Flex Code +status open + \begin_layout Plain Layout int getNameCount() \end_layout +\end_inset + + +\end_layout + \end_inset @@ -4651,10 +4687,19 @@ int getNameCount() \begin_inset Text +\begin_layout Plain Layout +\begin_inset Flex Code +status open + \begin_layout Plain Layout Path subpath(int beginIndex, int endIndex) \end_layout +\end_inset + + +\end_layout + \end_inset @@ -4672,10 +4717,19 @@ Path subpath(int beginIndex, int endIndex) \begin_inset Text +\begin_layout Plain Layout +\begin_inset Flex Code +status open + \begin_layout Plain Layout Path getParent() \end_layout +\end_inset + + +\end_layout + \end_inset @@ -4693,10 +4747,19 @@ Path getParent() \begin_inset Text +\begin_layout Plain Layout +\begin_inset Flex Code +status open + \begin_layout Plain Layout Path getRoot() \end_layout +\end_inset + + +\end_layout + \end_inset @@ -4810,17 +4873,36 @@ status open \begin_inset Text +\begin_layout Plain Layout +\begin_inset Flex Code +status open + \begin_layout Plain Layout URI toUri() \end_layout +\end_inset + + +\end_layout + \end_inset \begin_inset Text \begin_layout Plain Layout -使用Uri方式描述路径。对于本地文件(文件系统)使用file协议,因此URI的形式如file:///path-to-file +使用 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Uri +\end_layout + +\end_inset + +方式描述路径。对于本地文件(文件系统)使用file协议,因此URI的形式如file:///path-to-file \end_layout \end_inset @@ -4830,10 +4912,19 @@ URI toUri() \begin_inset Text +\begin_layout Plain Layout +\begin_inset Flex Code +status open + \begin_layout Plain Layout Path toAbsolutePath() \end_layout +\end_inset + + +\end_layout + \end_inset @@ -4850,11 +4941,20 @@ Path toAbsolutePath() \begin_inset Text +\begin_layout Plain Layout +\begin_inset Flex Code +status open + \begin_layout Plain Layout Path toRealPath(LinkOption... options) throws IOException \end_layout +\end_inset + + +\end_layout + \end_inset diff --git a/guide/lecture_guide/lecture1.lyx b/guide/lecture_guide/lecture1.lyx new file mode 100644 index 0000000..a4b5e8e --- /dev/null +++ b/guide/lecture_guide/lecture1.lyx @@ -0,0 +1,3670 @@ +#LyX 2.3 created this file. For more info see http://www.lyx.org/ +\lyxformat 544 +\begin_document +\begin_header +\save_transient_properties true +\origin unavailable +\textclass ctex-book +\begin_preamble +\input{../../../writing-common/book-preamble.tex} +\end_preamble +\use_default_options true +\begin_modules +tip-inset +note-inset +warning-inset +coderemarks +logicalmkup +theorems-bytype +theorems-chap-bytype +\end_modules +\maintain_unincluded_children false +\begin_local_layout +PackageOptions url hyphens +\end_local_layout +\language chinese-simplified +\language_package default +\inputencoding utf8-plain +\fontencoding global +\font_roman "default" "DejaVu Sans" +\font_sans "default" "DejaVu Serif" +\font_typewriter "default" "DejaVu Sans Mono" +\font_math "auto" "auto" +\font_default_family default +\use_non_tex_fonts true +\font_sc false +\font_osf false +\font_sf_scale 100 100 +\font_tt_scale 100 100 +\use_microtype false +\use_dash_ligatures true +\graphics default +\default_output_format pdf4 +\output_sync 0 +\bibtex_command default +\index_command default +\float_placement tbph +\paperfontsize default +\spacing single +\use_hyperref true +\pdf_bookmarks true +\pdf_bookmarksnumbered false +\pdf_bookmarksopen false +\pdf_bookmarksopenlevel 3 +\pdf_breaklinks true +\pdf_pdfborder true +\pdf_colorlinks true +\pdf_backref false +\pdf_pdfusetitle true +\papersize default +\use_geometry false +\use_package amsmath 1 +\use_package amssymb 1 +\use_package cancel 1 +\use_package esint 1 +\use_package mathdots 1 +\use_package mathtools 1 +\use_package mhchem 1 +\use_package stackrel 1 +\use_package stmaryrd 1 +\use_package undertilde 1 +\cite_engine basic +\cite_engine_type default +\biblio_style plain +\use_bibtopic false +\use_indices false +\paperorientation portrait +\suppress_date false +\justification true +\use_refstyle 1 +\use_minted 0 +\boxbgcolor #dad3d7 +\index Index +\shortcut idx +\color #008000 +\end_index +\secnumdepth 3 +\tocdepth 2 +\paragraph_separation indent +\paragraph_indentation default +\is_math_indent 0 +\math_numbering_side default +\quotes_style english +\dynamic_quotes 0 +\papercolumns 1 +\papersides 2 +\paperpagestyle default +\tracking_changes false +\output_changes false +\html_math_output 0 +\html_css_as_file 0 +\html_be_strict false +\end_header + +\begin_body + +\begin_layout Standard +\align center + +\size larger +\bar under +山东理工大学教案 +\end_layout + +\begin_layout Standard +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +第一次课 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +教学课型:理论课□√ 实验课□√ 习题课□ 实践课□ 技能课□ 其它□ +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +主要教学内容 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Java在程序设计语言中的霸主地位" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:Java在程序设计语言中的霸主地位" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Java简史" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:Java简史" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Java的特点" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:Java的特点" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Java开发环境的搭建" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:Java开发环境的搭建" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:初识Java的输入输出" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:初识Java的输入输出" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +重点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +Java的开发环境如何搭建 +\end_layout + +\begin_layout Enumerate +如何创建简单的Java应用程序 +\end_layout + +\begin_layout Enumerate +对Java的输入输出有个初步的印象 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +难点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Java的输入输出 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +课程目标及要求 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +课程目标:课程目标1 +\end_layout + +\begin_layout Plain Layout +要求: +\end_layout + +\begin_layout Enumerate +了解Java语言的来历和特点; +\end_layout + +\begin_layout Enumerate +掌握Java开发环境的搭建方法和基本用法; +\end_layout + +\begin_layout Enumerate +熟悉Java的输入输出方法。 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +教学方法和手段 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +板书和多媒体相结合,边讲边练,当堂消化。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +讨论、思考题 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +Java为什么能够异军突起,在众多程序设计语言中发展的这么好? +\end_layout + +\begin_layout Enumerate +在大数据、人工智能蓬勃发展的今天,Java是否依然是主流程序设计语言,为什么? +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +参考资料 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Chapter +初识Java +\begin_inset CommandInset label +LatexCommand label +name "chap:初识Java" + +\end_inset + + +\end_layout + +\begin_layout Standard +\align center +\begin_inset Graphics + filename ../imgs/intro/java-concept.png + width 100col% + +\end_inset + + +\end_layout + +\begin_layout Section +Java在程序设计语言中的霸主地位 +\begin_inset CommandInset label +LatexCommand label +name "sec:Java在程序设计语言中的霸主地位" + +\end_inset + + +\end_layout + +\begin_layout Standard +自从发明了计算机,程序设计语言就成了一门专门的技艺,至今人类已经发明了上千种程序设计语言 +\begin_inset CommandInset citation +LatexCommand cite +key "progamming-lang-stats" +literal "true" + +\end_inset + +。从权威统计机构TIOBE +\begin_inset Foot +status open + +\begin_layout Plain Layout +http://www.tiobe.com/ +\end_layout + +\end_inset + +的最新流行度统计结果可以看出,Java程序设计语言在最近的十五年几乎牢牢的占据了头名座椅。此后的10年、20年,Java的霸主地位会动摇吗?根据ruby之父松本 +行弘的自述,ruby从开始开发到发布用了3年左右的时间,在程序员圈子中拥有一定的知名度则又花了4年的时间,再到通过Ruby on Rails而走红,则又花了5年 +的时间 +\begin_inset CommandInset citation +LatexCommand cite +after "p109" +key "code-future" +literal "true" + +\end_inset + +。可见,程序设计语言的发展和进化是相对缓慢的一个过程,因此笔者大胆推断,至少在未来10年,Java和C仍然会是主流的程序设计语言。学好Java是IT职业生涯的不 +二敲门砖。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/intro/tiobe_top_langs.pdf + width 100line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +最近15年top 10程序设计语言 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +Java简史 +\begin_inset CommandInset label +LatexCommand label +name "sec:Java简史" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java程序设计语言是不是天生丽质,一开始就大红大紫呢? +\end_layout + +\begin_layout Standard +让我们穿越到1990年,了解一下Java的前生和今世,看一看它当年是如何降临人间的 +\begin_inset CommandInset citation +LatexCommand cite +key "java-history-wikimedia" +literal "true" + +\end_inset + +。 +\end_layout + +\begin_layout Subsection +Java的前生:Oak的诞生 +\end_layout + +\begin_layout Standard +\begin_inset Wrap figure +lines 0 +placement l +overhang 0in +width "20line%" +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/intro/duke.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java的吉祥物 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java的吉祥物" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +1990年12月,当时的 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Sun公司 +\end_layout + +\end_inset + +Sun公司开始了一个叫做“Stealth计划”的内部项目,由帕特里克.诺顿领衔,起因是公司自己开发的C++和C语言编译器很难用,帕特里克被搞的焦头烂额。“Stea +lth计划”后来改名为“Green计划”, +\begin_inset Index idx +status open + +\begin_layout Plain Layout +詹姆斯.高斯林 +\end_layout + +\end_inset + +詹姆斯.高斯林(人称“Java之父”,见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:詹姆斯.高斯林" + +\end_inset + +)和麦克.舍林丹加入到了帕克里克的工作小组。Sun公司预计未来的家用电器必将向智能化方向发展,于是“Green计划”的目标是打造一款智能家电程序设计语言及其平台。 +\end_layout + +\begin_layout Standard +团队最初考虑使用C++语言,但是很多成员包括Sun的首席科学家比尔.乔伊,发现C++在嵌入式系统上存在很大问题。因为嵌入式系统可以使用的资源有限,而C++缺乏垃圾 +回收机制以及可移植的安全性、分布式程序设计和多线程等特性。于是,乔伊决定开发一种集C语言和Mesa语言大成的新语言,乔伊把它叫做“未来”。他提议Sun公司的工程 +师应该在C++的基础上,开发一种新的面向对象的程序设计语言。最初,高斯林试图修改和扩展C++的功能,他自己称这种新语言为C++ ++ –:多么糟糕的命名啊,高斯 +林自己后来也放弃了这个名字。直到某一天,高斯林把这种新的语言命名为“Oak +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Oak +\end_layout + +\end_inset + +”(橡树),这是他办公室外的一棵橡树。 +\end_layout + +\begin_layout Standard +就像很多开发新技术的秘密工程一样,Green团队没日没夜的工作到了1992的夏天,终于能够演示新平台的一部分了,包括Green操作系统、Oak程序设计语言、类库 +及其硬件。Green的最初设想是用于一种叫做Star7的类PDA设备,这种设备在当时由鲜艳的图形界面和被称为“Duke”(Duke后来称为Java的吉祥物,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java的吉祥物" + +\end_inset + +)的智能代理来帮助用户。1992年12月3日,Star7正式面世。 +\end_layout + +\begin_layout Standard +同年11月,Green计划的成果转化成为“FirstPerson有限公司”,这是一个Sun公司 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Sun公司 +\end_layout + +\end_inset + +的全资子公司。FirstPerson团队对于打造高度互动的设备感兴趣,当时代华纳发布了一个电视机顶盒的征求提议书时,FirstPerson决定响应时代华纳的提议 +,提出了一个机顶盒平台方案。但是当时的有线电视界觉得FirstPerson的平台给予了用户过多的控制权,最终FirstPerson输给了SGI。FirstPer +son与3DO公司的另外一笔关于机顶盒的交易也没有成功,也就是说,FirstPerson公司在电视工业没有取得任何效益,Sun公司不得不收回了FirstPers +on公司。幸运的是, +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Oak +\end_layout + +\end_inset + +Oak语言的命运并没有就此止步。 +\end_layout + +\begin_layout Subsection +Java拥抱互联网,横空出世 +\end_layout + +\begin_layout Standard +\begin_inset Wrap figure +lines 0 +placement o +overhang 0in +width "50col%" +status open + +\begin_layout Plain Layout +\align right +\begin_inset Graphics + filename ../imgs/intro/James_Gosling_2008.jpg + lyxscale 30 + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +詹姆斯.高斯林 +\begin_inset CommandInset label +LatexCommand label +name "fig:詹姆斯.高斯林" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +1994年6月,在经历了一场历时三天的脑力激荡的讨论后,约翰·盖吉、詹姆斯·高斯林、比尔·乔伊、帕特里克·诺顿、韦恩·罗斯因和埃里克·斯库米,团队决定再一次做出 +重大决定,这次他们决定将该技术应用于万维网。他们认为随着Mosaic浏览器 +\begin_inset Foot +status open + +\begin_layout Plain Layout +Mosaic是浏览器的鼻祖,参见 +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://en.wikipedia.org/wiki/Mosaic_(web_browser) +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +的到来,因特网正在向同样的高度互动的远景演变,而这一远景正是他们在有线电视网中看到的。作为原型,帕特里克·诺顿写了一个小型万维网浏览器,WebRunner,后来 +改名为 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +HotJava +\end_layout + +\end_inset + +HotJava。 +\end_layout + +\begin_layout Standard +\align block +1994年10月,HotJava和Java平台为公司高层进行演示。1994年,Java 1.0a版本已经可以提供下载,但是Java和HotJava浏览器的第一次公 +开发布却是在1995年3月23日SunWorld大会上进行的。Sun公司的科学指导约翰·盖吉宣告了Java技术的诞生。这个发布是与网景公司的执行副总裁马克·安德 +森的惊人发布一起进行的:网景宣布将在其浏览器中包含对Java的支持,这在当时引起了很大的轰动。1996年1月,Sun公司成立了Java业务集团,专门开发Java +技术。这一次,詹姆斯.高斯林等终于扬眉吐气了,Java此后的发展虽然也不是一帆风顺,但是到今天,Java可谓如日中天, +\begin_inset Index idx +status open + +\begin_layout Plain Layout +詹姆斯.高斯林 +\end_layout + +\end_inset + +詹姆斯.高斯林也被称为“Java之父”, +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:詹姆斯.高斯林" + +\end_inset + +为詹姆斯.高斯林本尊。 +\end_layout + +\begin_layout Subsection +Sun公司没落,Java易手Oracle +\end_layout + +\begin_layout Standard +然而,天有不测风云,当年像太阳一样耀眼的 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Sun公司 +\end_layout + +\end_inset + +Sun公司,在2002年突然衰落 +\begin_inset Foot +status open + +\begin_layout Plain Layout +关于Sun衰落的原因,网络上有大量的讨论,比如:http://tech.sina.com.cn/it/2011-03-04/16485248026.shtml +\end_layout + +\end_inset + +,从此便江河日下,一下从硅谷最值钱的公司沦为人均市值最低的公司。由于种种原因,2009年4月20日,Sun公司以74亿美元(要知道,2001年,Sun的市值超过 +2000亿美元)整体出售给了 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Oracle +\end_layout + +\end_inset + +Oracle,从此Java易手,Oracle开启了Java发展的新历程。通过 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java简史" + +\end_inset + +我们可以简要的了解Java发展的历程 +\begin_inset CommandInset citation +LatexCommand cite +key "java-brief-history" +literal "true" + +\end_inset + +和各个版本发布的时间 +\begin_inset Foot +status open + +\begin_layout Plain Layout +如果你对Java的历史特别感兴趣,可以参考以下的几个站点: +\end_layout + +\begin_layout Itemize +Oracle庆祝Java 20年: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +http://oracle.com.edgesuite.net/timeline/java/ +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +Java 20年:历史与未来: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +http://www.infoq.com/cn/news/2015/05/java-20-history-future +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +。 +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/intro/java-history.png + width 100line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java简史 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java简史" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Note Note +status open + +\begin_layout Plain Layout +补充一下Java在服务器领域的市场份额 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +Java的特点 +\begin_inset CommandInset label +LatexCommand label +name "sec:Java的特点" + +\end_inset + + +\begin_inset Foot +status open + +\begin_layout Plain Layout +参考自:htp://zh.wikipedia.org/wiki/java +\end_layout + +\end_inset + + +\begin_inset Note Note +status open + +\begin_layout Plain Layout +需要重写,暂时内容来自:https://zh.wikipedia.org/wiki/Java +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +面向对象 +\end_layout + +\begin_layout Standard +Java的特点之一就是 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +面向对象 +\end_layout + +\end_inset + +面向对象,是程序设计方法的一种。“面向对象程序设计语言”的核心之一就是开发者在设计软件的时候可以使用自定义的类型和关联操作。代码和数据的实际集合体叫做“对象”。 +一个对象可以想象成绑定了很多“行为(代码)”和“状态(数据)”的物体。对于数据结构的改变需要和代码进行通信然后操作,反之亦然。面向对象设计让大型软件工程的计划和 +设计变得更容易管理,能增强工程的健康度,减少失败工程的数量。 +\end_layout + +\begin_layout Subsection +跨平台 +\end_layout + +\begin_layout Standard +Java语言的第二个特性就是 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +跨平台 +\end_layout + +\end_inset + +跨平台性,也就是说使用Java语言编写的程序可以在编译后不用经过任何更改,就能在任何硬件设备条件下运行。这个特性经常被称为“一次编译,到处运行”(write + once, run anywhere)。 +\end_layout + +\begin_layout Standard +执行Java应用程序必须安装Java Runtime Environment(JRE +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JRE +\end_layout + +\end_inset + +),JRE内部有一个Java虚拟机(Java Virtual Machine, +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JVM +\end_layout + +\end_inset + +JVM)以及一些标准的类库(Class Library)。通过JVM才能在电脑系统执行Java应用程序(Java Application),这与.Net + Framework的情况一样,所以电脑上如果没有安装JVM,Java应用程序将不能够执行。 +\end_layout + +\begin_layout Standard +实现跨平台性的方法是大多数编译器在进行Java语言程序的编码时候会生成一个用字节码写成的“半成品”,这个“半成品”会在Java虚拟机(解释层)的帮助下运行,虚拟 +机会把它转换成当前所处硬件平台的原始代码。之后,Java虚拟机会打开标准库,进行数据(图片、线程和网络)的访问工作。需要注意的是,尽管已经存在一个进行代码翻译的 +解释层,有些时候Java的字节码代码还是会被JIT编译器进行二次编译。 +\end_layout + +\begin_layout Standard +有些编译器,比如GCJ +\begin_inset Index idx +status open + +\begin_layout Plain Layout +GCJ +\end_layout + +\end_inset + +,可以自动生成原始代码而不需要解释层。但是这些编译器所生成的代码只能应用于特定平台。并且GCJ目前只支持部分的Java API。 +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +甲骨文公司对于Java的许可是“全兼容的”,这也导致了微软和Sun关于微软的程序不支持RMI和JNI接口、并且增加特性为己所用的法律争端。Sun最终赢得了官司, +获得了大约两千万美元的赔偿,法院强制要求微软执行Sun公司关于Java的许可要求。作为回应,微软不再在Windows系统中捆绑Java,最新的Windows版本 +,Windows Vista和Internet Explorer 7.0版本也不再提供对于Java应用程序和控件的支持。但是Sun公司和其他使用Java运行时系统 +的公司在Windows操作系统下对用户提供无偿的第三方插件和程序支持。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Java语言使用解释层最初是为了轻巧性。所以这些程序的运行效率比C语言和C++要低很多,用户也对此颇有微词。很多最近的调查显示Java的程序运行速度比几年前要高 +出许多,有些同样功能的程序的效率甚至超过了C++和C语言编写的程序。 +\end_layout + +\begin_layout Standard +Java语言在最开始应用的时候是没有解释层的,所有需要编译的代码都直接转换成机器的原始代码。这样做的后果就是获得了最佳的性能,但是程序臃肿异常。从 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JIT +\end_layout + +\end_inset + +JIT技术开始,Java的程序都经过一次转换之后才变成机器码。很多老牌的第三方虚拟机都使用一种叫做“动态编译”的技术,也就是说虚拟机实时监测和分析程序的运行行为 +,同时选择性地对程序所需要的部分进行编译和优化。所有这些技术都改善了代码的运行速度,但是又不会让程序的体积变得失常。 +\end_layout + +\begin_layout Standard +程序的轻便性事实上是软件编写很难达到的一个目标,Java虽然成功地实现了“一次编译,到处运行”,但是由于平台和平台之间的差异,所编写的程序在转换代码的时候难免会 +出现微小的、不可察觉的错误和意外。有些程序员对此非常头疼,他们嘲笑Java的程序不是“一次编译,到处运行”,而是“一次编译,到处调试”。以Java + AWT为例,早期Java AWT内提供的按钮、文字区等均是以电脑系统所默认的样式而显示。这令Java程序在有些没有提供图案的电脑系统产生错误(在Microso +ft Windows设有窗口管理器,在一些Linux distribution则没有)。后来SUN公司针对Java AWT一些问题而推出Java + Swing。 +\end_layout + +\begin_layout Standard +平台无关性让Java在 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +服务器端 +\end_layout + +\end_inset + +服务器端软件领域非常成功。很多服务器端软件都使用Java或相关技术建立,比如占据了WWW服务器半壁江山的 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Apache +\end_layout + +\end_inset + +Apache服务器 +\begin_inset Foot +status open + +\begin_layout Plain Layout +http://www.apache.org +\end_layout + +\end_inset + +,当下火爆的大数据平台Hadoop +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Hadoop +\end_layout + +\end_inset + + +\begin_inset Foot +status open + +\begin_layout Plain Layout +http://hadoop.apache.org +\end_layout + +\end_inset + +等,都是使用Java语言开发的。 +\end_layout + +\begin_layout Subsection +自动垃圾回收 +\end_layout + +\begin_layout Standard +C++语言被用户诟病的原因之一是大多数C++编译器不支持垃圾收集机制 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +垃圾收集机制 +\end_layout + +\end_inset + +。通常使用C++编程的时候,程序员于程序中初始化对象时,会在主机内存堆栈上分配一块内存与地址,当不需要此对象时,进行析构或者删除的时候再释放分配的内存地址。如果 +对象是在堆栈上分配的,而程序员又忘记进行删除,那么就会造成 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +内存泄漏 +\end_layout + +\end_inset + +内存泄漏(Memory Leak)。长此以往,程序运行的时候可能会生成很多不清除的垃圾,浪费了不必要的内存空间。而且如果同一内存地址被删除两次的话,程序会变得不 +稳定,甚至崩溃。因此有经验的C++程序员都会在删除之后将指针重置为NULL,然后在删除之前先判断指针是否为NULL。 +\end_layout + +\begin_layout Standard +C++中也可以使用“智能指针”(Smart Pointer)或者使用C++托管扩展编译器的方法来实现自动化内存释放,智能指针可以在标准类库中找到,而C++托管扩 +展被微软的Visual C++ 7.0及以上版本所支持。智能指针的优点是不需引入缓慢的垃圾收集机制,而且可以不考虑线程安全的问题,但是缺点是如果不善使用智能指针的 +话,性能有可能不如垃圾收集机制,而且不断地分配和释放内存可能造成内存碎片,需要手动对堆进行压缩。除此之外,由于智能指针是一个基于模板的功能,所以没有经验的程序员 +在需要使用多态特性进行自动清理时也可能束手无策。 +\end_layout + +\begin_layout Standard +Java语言则不同,上述的情况被自动垃圾收集功能自动处理。对象的创建和放置都是在内存堆栈上面进行的。当一个对象没有任何引用的时候,Java的自动垃圾收集机制就发 +挥作用, +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +自动 +\end_layout + +\end_inset + +删除这个对象所占用的空间,释放内存以避免内存泄漏。 +\end_layout + +\begin_layout Standard +注意程序员不需要修改finalize方法,自动垃圾收集也会发生作用。但是内存泄漏并不是就此避免了,当程序员疏忽大意地忘记解除一个对象不应该有的引用时,内存泄漏仍 +然不可避免。 +\end_layout + +\begin_layout Standard +不同厂商、不同版本的JVM中的内存垃圾回收机制并不完全一样,通常越新版本的内存回收机制越快,IBM、BEA、SUN等等开发JVM的公司都曾宣称过自己制造出了世界 +上最快的JVM,JVM性能的世界纪录也在不断的被打破并提高。 +\end_layout + +\begin_layout Exercise +Java语言可以跨平台的秘诀是什么? +\end_layout + +\begin_layout Section +Java开发环境的搭建 +\begin_inset CommandInset label +LatexCommand label +name "sec:Java开发环境的搭建" + +\end_inset + + +\end_layout + +\begin_layout Standard +学习一门程序设计语言,最佳实践是边读边练,在一个“全浸”的环境中学习,自然就轻松多了。因此,我们从一开始就搭建一个“舒服”的开发环境,学习中的每一步我们都在这个 +舒服的开发环境中验证,这样我们走的每一步都是扎实的,串起来就是一个坚实的学习之旅。 +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Linux +\end_layout + +\end_inset + +Linux是学习程序设计的绝佳搭档,因此笔者建议大家在Linux平台上开始Java的学习之旅。Linux的发布版比较多,根据笔者多年的教学经验,建议大家选择 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Ubantu +\end_layout + +\end_inset + +Ubantu的最新LTS版本即可,下面的Java开发环境的搭建均基于Ubuntu 16.04(写作本书时的最新LTS版本)。 +\end_layout + +\begin_layout Subsection +Java版本的选择 +\end_layout + +\begin_layout Standard +Java分为三个版本: +\end_layout + +\begin_layout Itemize +Java SE(Java Standard Edition):Java的标准版,包含了常见的Java应用程序开发和运行所需的环境。本书此后如没有特别说明,Jav +a都是指Java SE。 +\end_layout + +\begin_layout Itemize +Java EE(Java Enterprise Edition):Java的企业版,包含了Java的一些高级特性,如Servlet,JDBC等。 +\end_layout + +\begin_layout Itemize +Java ME(Java Micro Edition):Java的移动版,包含了开发移动终端应用程序所需的环境。不过,自从Android横空出世,Java + ME几乎就没有多大市场了。 +\end_layout + +\begin_layout Subsection +JDK的概念 +\begin_inset CommandInset label +LatexCommand label +name "subsec:JDK的概念" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JDK +\end_layout + +\end_inset + +JDK(Java Development Kit)是开发Java应用程序的必备,提供了开发Java应用程序的必须工具,比如: +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Index idx +status open + +\begin_layout Plain Layout +java +\end_layout + +\end_inset + +java +\end_layout + +\end_inset + +:Java虚拟机,任何Java应用程序都是通过java这个虚拟机解释执行的。 +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Index idx +status open + +\begin_layout Plain Layout +javac +\end_layout + +\end_inset + +javac +\end_layout + +\end_inset + +:Java编译器,将Java源代码编译为java虚拟机可以理解的字节码文件。 +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Index idx +status open + +\begin_layout Plain Layout +javap +\end_layout + +\end_inset + +javap +\end_layout + +\end_inset + +:反编译工具,可以粗略的认为,javap能够将二进制文件还原为Java源代码,帮助我们了解javac的工作原理。 +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +详细的JDK工具列表在 +\begin_inset CommandInset ref +LatexCommand nameref +reference "subsec:下载和安装JDK" + +\end_inset + +(参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:下载和安装JDK" + +\end_inset + +)之后转到bin目录浏览,在ubuntu下面通过以下命令 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +也许你安装的JDK版本和这里不一致。可以通过这个命令了解你的电脑上安装的是哪个版本的JDK:dpkg -l | grep -i +\begin_inset Quotes eld +\end_inset + +openjdk +\begin_inset Quotes erd +\end_inset + + +\end_layout + +\end_inset + +了解JDK包含了哪些命令和工具: +\end_layout + +\begin_layout Plain Layout +\begin_inset Box Shadowbox +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +$ dpkg -L openjdk-8-jdk-headless | more +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +基础开发环境 +\end_layout + +\begin_layout Standard +在ubuntu环境下,下载和安装 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JDK +\end_layout + +\end_inset + +JDK可以简单的执行下列命令来完成 +\begin_inset Foot +status open + +\begin_layout Plain Layout +如果你使用的是windows,请参考 +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +http://jingyan.baidu.com/article/eae07827a4b4a31fec548535.html +\end_layout + +\end_inset + +了解windows下JDK的安装和设置方法。由于Java是跨平台的,因此JDK安装后的用法都是一样的,本书不再强调windows和Linux中Java的用法区别 +。 +\end_layout + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset Box Shadowbox +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +$ sudo apt-get install openjdk-8-jdk +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +就这些了!是不是很简单? +\end_layout + +\begin_layout Standard +验证一下Java是不是已经安装好了,执行命令: +\end_layout + +\begin_layout Standard +\begin_inset Box Shadowbox +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +$ java -version +\end_layout + +\begin_layout Plain Layout +openjdk version "1.8.0_91" +\end_layout + +\begin_layout Plain Layout +OpenJDK Runtime Environment (build 1.8.0_91-8u91-b14-3ubuntu1~16.04.1-b14) +\end_layout + +\begin_layout Plain Layout +OpenJDK 64-Bit Server VM (build 25.91-b14, mixed mode) +\end_layout + +\begin_layout Plain Layout +$ which java +\end_layout + +\begin_layout Plain Layout +/usr/bin/java +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +可以看出,我们安装的是 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +openjdk +\end_layout + +\end_inset + +openjdk +\begin_inset Foot +status open + +\begin_layout Plain Layout +http://openjdk.java.net/ +\end_layout + +\end_inset + +,不是Oracle官方的 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JDK +\end_layout + +\end_inset + +JDK。对于我们学习Java程序设计而言,openjdk就足够了。如果你介意的话,也可以去下载Oralce官方的JDK,不再赘述。 +\end_layout + +\begin_layout Standard +现在,我们就可以尝试编写HelloWord了!使用任意的文本编辑器编写下面的程序代码并保存为HelloWorld.java: +\end_layout + +\begin_layout Example +使用Java语言向世界问好 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/intro/src/HelloWorld.java" +lstparams "caption={HelloWorld.java},label={HelloWorld.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +打开一个终端,执行下面的命令编译HelloWorld.java: +\end_layout + +\begin_layout Standard +\begin_inset Box Shadowbox +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +$ javac HelloWorld.java +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +执行下面的命令欣赏HelloWorld吧: +\end_layout + +\begin_layout Standard +\begin_inset Box Shadowbox +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +$ java HelloWorld +\end_layout + +\begin_layout Plain Layout +Hello World! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Itemize +注意在编写HelloWorld.java源文件时,文件名HelloWorld和源文件中的HelloWorld要严格一致的。 +\end_layout + +\begin_layout Itemize +执行java的class文件时,java命令后面的参数不要带class字样,即,如果执行HelloWorld.class,则只输入java HelloWorld即 +可,千万不要画蛇添足变成java HelloWorld.class。Java虚拟机会根据HelloWorld自动去寻找HelloWorld.class,如果在终端输 +入java HelloWorld.class,java虚拟机就会去寻找HelloWorld.class.class文件,自然就找不到了。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +请说明JDK中,哪个程序是Java虚拟机?哪个程序是Java编译器? +\end_layout + +\begin_layout Subsection +IDE开发环境 +\end_layout + +\begin_layout Standard +终端界面(命令行方式)对于编写一个简单的程序很方便,但是终端界面毕竟缺少了一些方便程序设计的功能,比如代码自动提示和补全、文件浏览等,因此在实际的学习和开发中, +往往使用所谓的 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +IDE +\end_layout + +\end_inset + +IDE(Integrated Development Enviroment)环境。Java开发中主流的IDE有如下三种: +\end_layout + +\begin_layout Itemize +JetBrain Idea +\end_layout + +\begin_layout Itemize +eclipse +\end_layout + +\begin_layout Itemize +NetBeans +\end_layout + +\begin_layout Standard +笔者推荐大家使用第一种:JetBrain Idea。 +\end_layout + +\begin_layout Subsubsection +Idea +\end_layout + +\begin_layout Standard +JetBrains +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Idea +\end_layout + +\end_inset + +Idea是 +\begin_inset CommandInset href +LatexCommand href +name "JetBrains" +target "https://www.jetbrains.com" +literal "false" + +\end_inset + + +\begin_inset Foot +status open + +\begin_layout Plain Layout +https://www.jetbrains.com +\end_layout + +\end_inset + +公司出品的优秀Java IDE环境,是很多Java高手的最爱,google公司也将android开发的IDE:android studio构建在IDEA的基础之 +上(最早的android集成开发环境是作为eclipse的插件存在的,估计google公司对eclipse的插件效率和管理方式不满意,于是另起炉灶,在IDEA的 +基础上开发了android studio)。 +\end_layout + +\begin_layout Standard +IDEA分为免费的社区版和收费的旗舰版,对于Java初学者而言,社区版的功能已经足以应付。 +\end_layout + +\begin_layout Paragraph* +下载和安装Idea +\end_layout + +\begin_layout Standard +从 +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://www.jetbrains.com/idea/ +\end_layout + +\end_inset + + 选择Community版本下载即可。请根据所使用的操作系统选择不同的压缩格式。作者使用的是Linux操作系统,因此选择的是tar.gz不带JDK的安装包。假设最 +新的idea下载到了~/downloads目录下。作者的习惯是在家目录建立一个devel目录,然后将所有软件开发相关的工具等都放到devel目录下,因此将下载的 +idea安装文件解压缩: +\end_layout + +\begin_layout Standard +\begin_inset Box Shadowbox +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status collapsed + +\begin_layout Plain Layout +$ cd ~/downloads +\end_layout + +\begin_layout Plain Layout +$ tar xzvf ideaIC-2016.3.4-no-jdk.tar.gz -C ~/devel +\end_layout + +\begin_layout Plain Layout +$ cd ~/devel/idea-IC-163.12024.16/bin +\end_layout + +\begin_layout Plain Layout +$ ./idea.sh +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +第一次启动Idea的时候需要进行简单的配置,目前阶段全部选择默认选项既可。 +\end_layout + +\begin_layout Paragraph* +创建新项目 +\end_layout + +\begin_layout Standard +下面以HelloWorld为例说明如何使用Idea创建一个简单的Java应用程序。 +\end_layout + +\begin_layout Enumerate +创建新项目。通过File->New菜单打开创建新项目的窗口,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:新建项目的菜单" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:选择项目类型" + +\end_inset + +所示。 +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/intro/idea-new-project-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +从菜单新建项目 +\begin_inset CommandInset label +LatexCommand label +name "fig:新建项目的菜单" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/intro/idea-new-project-2.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +选择项目类型 +\begin_inset CommandInset label +LatexCommand label +name "fig:选择项目类型" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Enumerate +接着,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:选择从模板创建项目" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:填写项目名称和所在目录" + +\end_inset + +所示,填写项目名称和所在目录,Idea自动创建项目目录和一个默认的Main文件。 +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/intro/idea-new-project-3.png + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +选择从模板创建项目 +\begin_inset CommandInset label +LatexCommand label +name "fig:选择从模板创建项目" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/intro/idea-new-project-4.png + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +填写项目名称和所在目录 +\begin_inset CommandInset label +LatexCommand label +name "fig:填写项目名称和所在目录" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Enumerate +编写源代码。在自动打开的Main文件中,编写源代码,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:编写源代码" + +\end_inset + +所示。 +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/intro/idea-new-project-5.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +编写源代码 +\begin_inset CommandInset label +LatexCommand label +name "fig:编写源代码" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + +源代码编写完毕后,可以将Main这个文件改名字为HelloWorld,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:修改类名" + +\end_inset + +所示,当光标停在Main上面时,两次按Shift+F6修改类名。 +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/intro/idea-new-project-6.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +修改类名 +\begin_inset CommandInset label +LatexCommand label +name "fig:修改类名" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Enumerate +运行应用程序。如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:运行应用程序" + +\end_inset + +所示,在右键单击弹出的菜单中选择“Run”运行 +\begin_inset Foot +status open + +\begin_layout Plain Layout +Ctrl+Shift+F10是运行应用程序的快捷键。 +\end_layout + +\end_inset + +即可。 +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/intro/idea-new-project-7.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +运行应用程序 +\begin_inset CommandInset label +LatexCommand label +name "fig:运行应用程序" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +建议读者在使用Idea完成了第一个HelloWorld项目后,使用资源管理器或者命令行工具打开项目的目录看一下Idea到底创建了哪些目录,哪些文件?尤其要注意到 +,Java应用程序源代码都是使用java作为文件扩展名的,比如HelloWorld. +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +java +\end_layout + +\end_inset + +,编译后的Java字节码文件(即所谓的可执行文件)都是以class作为文件扩展名的,比如HelloWorld. +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +class +\end_layout + +\end_inset + +。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Warning +status open + +\begin_layout Plain Layout +要特别注意,Java是大小写敏感的程序设计语言,Java源代码的文件名和类名必须完全一致!这个规定并非铁板一块,我们将在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:定义Java类" + +\end_inset + +详细讨论Java定义类的细节。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +NetBeans +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +NetBeans +\end_layout + +\end_inset + +NetBeans是一个始于1997年的Xelfi计划,本身是捷克布拉格查理大学Charles University的数学及物理学院的学生计划。此计划延伸而成立了 +一家公司进而发展成为商用版本的NetBeans IDE,直到1999年Sun Microsystems电脑买下此公司。Sun Microsystems于2000 +年6月将NetBeans IDE作为开源项目发展。2010年1月,Sun Microsystems成为甲骨文的子公司。 NetBeans IDE最新版下载量已经 +超过18万次,参与开发人员超过80万。NetBeans项目正在蓬勃发展,并将继续成长。 +\end_layout + +\begin_layout Standard +NetBeans包括开源的开发环境和应用平台,NetBeans IDE可以使开发人员利用Java平台能够快速创建Web、企业、桌面以及移动的应用程序,NetBe +ans IDE已经支持PHP、Ruby、JavaScript、Groovy、Grails和C/C++等开发语言。NetBeans项目由一个活跃的开发社区提供支持 +, NetBean开发环境提供了丰富的产品文档和培训资源以及大量的第三方插件。 NetBeans是开源软件开发集成环境,是一个开放框架,可扩展的开发平台,可以用 +于Java、C/C++,PHP等语言的开发,本身是一个开发平台,可以通过扩展插件来扩展功能。 +\end_layout + +\begin_layout Standard +ubuntu环境下直接执行下面的命令即可安装Netbeans: +\end_layout + +\begin_layout Standard +\begin_inset Box Shadowbox +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +$ sudo apt-get install netbeans +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +上面的命令虽然只是安装了Netbeans的基本组件,但是对于我们学习Java程序设计语言而言已经足够了!如果你希望尝试最新的Netbeans版本,可以从Netb +eans官网 +\begin_inset Foot +status open + +\begin_layout Plain Layout +http://www.netbeans.org +\end_layout + +\end_inset + +下载并安装,此处不再赘述。 +\end_layout + +\begin_layout Standard +如果你已经使用过任何一种IDE开发环境了,Netbeans是很容易上手的。一般的开发步骤如下: +\end_layout + +\begin_layout Enumerate +创建新项目:通过File->New Project打开创建新项目的窗口,填写项目目录即可创建一个新的项目 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +没有并排显示,需要修改 +\end_layout + +\end_inset + +: +\begin_inset Newline newline +\end_inset + + +\begin_inset Newline newline +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "45col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/intro/NewJavaApplication_001.pdf + width 100col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +选择项目类型 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset space \hspace*{\fill} +\end_inset + + +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "45col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/intro/NewJavaApplication_002.pdf + width 100col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +设置项目名称和存储目录 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Caption Standard + +\begin_layout Plain Layout +创建新项目 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Newline newline +\end_inset + + +\end_layout + +\begin_layout Enumerate +编写源文件:在第一步中创建新项目后,已经自动打开了HelloWorld.java文件: +\begin_inset Newline newline +\end_inset + + +\begin_inset Float figure +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/intro/edit-helloworld.png + lyxscale 30 + scale 30 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +编辑HelloWorld.java +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Newline newline +\end_inset + + +\begin_inset Flex Tip +status open + +\begin_layout Itemize +巧用Netbeans的自动代码提示,比如打出System.之后,会自动提示System类有哪些方法可以调用。 +\end_layout + +\begin_layout Itemize +如果代码中有语法错误,Netbeans会给出提示信息和建议的修改方案,一般情况下选择第一个修正方案即可。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Enumerate +运行:在IDE中运行Java应用程序很简单,在打开的java文件中右键可以看到run file菜单: +\begin_inset Newline newline +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "45col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/intro/run-file.png + width 100col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +右键选择Run File菜单 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset space \hspace*{\fill} +\end_inset + + +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "45col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/intro/run-file-console.png + width 100col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +运行结果 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Caption Standard + +\begin_layout Plain Layout +在Netbeans中运行文件 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +Eclipse +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Eclispe +\end_layout + +\end_inset + +Eclispe是当下非常流行的Java开发IDE环境,以丰富的插件著称,详情可以访问Eclipse的官网: +\begin_inset CommandInset href +LatexCommand href +name "http://www.eclipse.org" +target "http://www.eclipse.org" +literal "false" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +安装Eclipse可以有两种方式: +\end_layout + +\begin_layout Enumerate +直接在ubuntu执行命令: +\begin_inset Newline newline +\end_inset + + +\begin_inset Box Shadowbox +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +$ sudo apt-get install eclipse +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Enumerate +在eclipse的官网下载相应于你的环境(32位或者64位)的合适版本,一般下载最新的稳定版即可。eclipse是绿色软件,直接解压缩运行其中的eclipse文 +件即可。 +\end_layout + +\begin_layout Standard +eclipse的具体用法和Netbeans大同小异,不再赘述。 +\end_layout + +\begin_layout Section +初识Java的输入输出 +\begin_inset CommandInset label +LatexCommand label +name "sec:初识Java的输入输出" + +\end_inset + + +\end_layout + +\begin_layout Standard +C语言提供了简单的printf和scanf处理输出和输入,Java的输入输出确实要比C复杂的多。不过,我们在学习C语言的时候也花了不少的时间学习printf的格 +式化输出方式,不是吗?而Java的输出虽然形式上复杂了点,但是却不需要我们学习格式化字符串的语法了。为了学习方便,这里先给出最简单的Java输入输出方法。 +\end_layout + +\begin_layout Subsection +输出到屏幕 +\end_layout + +\begin_layout Standard +在屏幕上输出字符串可以直接调用 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Index idx +status open + +\begin_layout Plain Layout +println +\end_layout + +\end_inset + +println +\end_layout + +\end_inset + +方法(ln是line的缩写): +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +System.out.println(“希望输出的字符串写在这里”); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +我们先不用理会System和out具体是什么意思(在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:面向字节的流" + +\end_inset + +我们会详细研究System以及out的用法), +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +println +\end_layout + +\end_inset + +的意思是输出双引号内的字符串到屏幕上,并自动回车换行,这正是我们需要的。 +\end_layout + +\begin_layout Standard +另外,在输出字符串到屏幕时,一般情况下我们可以忘掉C中printf函数的格式化输出,因为Java提供了更自然的字符串输出方式:直接使用“+”将多个字符串连接起来 +即可 +\begin_inset Foot +status open + +\begin_layout Plain Layout +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:拼接字符串" + +\end_inset + +我们会更具体的讨论如何连接多个字符串。 +\end_layout + +\end_inset + +,比如: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +System.out.println("variable a = " + a + ",variable b = " + b); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +从键盘输入 +\end_layout + +\begin_layout Standard +从键盘输入的简便方式是使用 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Scanner +\end_layout + +\end_inset + +Scanner类: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +Scanner console = new Scanner(System.in); +\end_layout + +\begin_layout Plain Layout + +int quantity = console.nextInt(); +\end_layout + +\begin_layout Plain Layout + +double num = console.nextDouble(); +\end_layout + +\begin_layout Plain Layout + +String str = console.nextLine(); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +同样的,我们在这里先忽略System.in的含义,只需要了解console.nextInt()的意思是从键盘获取一个整数,console.nextDouble的意思是 +从键盘获取一个双精度数字即可。Scanner类的常用函数如表 +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Scanner的常用函数" + +\end_inset + +所示: +\end_layout + +\begin_layout Standard +\noindent +\align center +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\noindent +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +函数名称 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +功能描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +nextInt() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\align left +读入下一个整数 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +nextShort() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\align left +读入下一个短整数 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +nextLong() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\align left +读入下一个长整数 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +nextFloat() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\align left +读入下一个浮点数 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +nextDouble() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\align left +读入下一个双精度浮点数 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +next() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\align left +读入下一个token(空白字符隔开的字符串) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +nextLine() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\align left +读入下一行 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Scanner的常用函数 +\begin_inset CommandInset label +LatexCommand label +name "fig:Scanner的常用函数" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +我们会发现,几乎每个Java类都需要创建一个main方法,Idea提供了“模板”机制帮助我们快速创建main方法:尝试在一个类的内部敲入psvm并按回车键看看, +如下图所示: +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/intro/idea-psvm.png + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +psvm +\end_layout + +\end_inset + +: 分别是public static void main的第一个字母。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +Java的输入输出 +\end_layout + +\begin_layout Example +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "IODemo.java" + +\end_inset + +,我们从键盘输入什么,就在屏幕上打印出什么。 +\end_layout + +\begin_layout Example +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/intro/src/IODemo.java" +lstparams "caption={IODemo.java},label={IODemo.java}" + +\end_inset + + +\end_layout + +\begin_layout Exercise +编写程序,在屏幕打印10行“Hello,Java!”。 +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +编写程序,在屏幕上显示如下的图形 +\begin_inset CommandInset label +LatexCommand label +name "exer:编写程序,在屏幕上显示如下的图形:" + +\end_inset + +[参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +solutionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "solu:的一个实现如下所示:" + +\end_inset + +]: +\begin_inset Newline newline +\end_inset + + +\begin_inset Graphics + filename ../imgs/intro/exe-logo-asterisks.png + scale 20 + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +熟悉一下常用的 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Idea +\end_layout + +\end_inset + +Idea快捷键,具体可以参照 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +appendixname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "chap:Idea的常用快捷键" + +\end_inset + +。记住一些常用快捷键可以大大提高开发和学习的效率,因此下些功夫练习一下还是值得的。 +\end_layout + +\end_body +\end_document diff --git a/guide/lecture_guide/lecture10.lyx b/guide/lecture_guide/lecture10.lyx new file mode 100644 index 0000000..4c0a9aa --- /dev/null +++ b/guide/lecture_guide/lecture10.lyx @@ -0,0 +1,10404 @@ +#LyX 2.3 created this file. For more info see http://www.lyx.org/ +\lyxformat 544 +\begin_document +\begin_header +\save_transient_properties true +\origin unavailable +\textclass ctex-book +\begin_preamble +\input{book-preamble.tex} +\end_preamble +\use_default_options true +\begin_modules +coderemarks +logicalmkup +tip-inset +note-inset +warning-inset +theorems-bytype +theorems-chap-bytype +\end_modules +\maintain_unincluded_children false +\begin_local_layout +PackageOptions url hyphens +\end_local_layout +\language chinese-simplified +\language_package default +\inputencoding utf8-plain +\fontencoding global +\font_roman "default" "DejaVu Sans" +\font_sans "default" "DejaVu Serif" +\font_typewriter "default" "DejaVu Sans Mono" +\font_math "auto" "auto" +\font_default_family default +\use_non_tex_fonts true +\font_sc false +\font_osf false +\font_sf_scale 100 100 +\font_tt_scale 100 100 +\use_microtype false +\use_dash_ligatures true +\graphics default +\default_output_format pdf4 +\output_sync 0 +\bibtex_command default +\index_command default +\float_placement tbph +\paperfontsize default +\spacing single +\use_hyperref true +\pdf_bookmarks true +\pdf_bookmarksnumbered false +\pdf_bookmarksopen false +\pdf_bookmarksopenlevel 3 +\pdf_breaklinks true +\pdf_pdfborder true +\pdf_colorlinks true +\pdf_backref false +\pdf_pdfusetitle true +\papersize default +\use_geometry false +\use_package amsmath 1 +\use_package amssymb 1 +\use_package cancel 1 +\use_package esint 1 +\use_package mathdots 1 +\use_package mathtools 1 +\use_package mhchem 1 +\use_package stackrel 1 +\use_package stmaryrd 1 +\use_package undertilde 1 +\cite_engine basic +\cite_engine_type default +\biblio_style plain +\use_bibtopic false +\use_indices false +\paperorientation portrait +\suppress_date false +\justification true +\use_refstyle 1 +\use_minted 0 +\boxbgcolor #dad3d7 +\index Index +\shortcut idx +\color #008000 +\end_index +\secnumdepth 3 +\tocdepth 2 +\paragraph_separation indent +\paragraph_indentation default +\is_math_indent 0 +\math_numbering_side default +\quotes_style english +\dynamic_quotes 0 +\papercolumns 1 +\papersides 2 +\paperpagestyle default +\tracking_changes false +\output_changes false +\html_math_output 0 +\html_css_as_file 0 +\html_be_strict false +\end_header + +\begin_body + +\begin_layout Standard +\align center + +\size larger +\bar under +山东理工大学教案 +\end_layout + +\begin_layout Standard +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +第十次课 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +教学课型:理论课□√ 实验课□√ 习题课□ 实践课□ 技能课□ 其它□ +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +主要教学内容 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:C的IO回顾" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:C的IO回顾" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Java的IO体系" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:Java的IO体系" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +重点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +Java I/O和C的I/O的比较; +\end_layout + +\begin_layout Enumerate +Java I/O的分类和类层次结构; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +难点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +Java I/O的面向字节和面向字符的接口; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +课程目标及要求 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +课程目标:课程目标1 +\end_layout + +\begin_layout Plain Layout +要求: +\end_layout + +\begin_layout Enumerate +熟练掌握Java I/O的基本概念和实现思路; +\end_layout + +\begin_layout Enumerate +熟练掌握Java I/O的两种分类及其不同的使用场合; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +教学方法和手段 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +板书和多媒体相结合,边讲边练,当堂消化。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +讨论、思考题 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +Java I/O体系复杂吗?是否存在过度设计的嫌疑?你是否有更好的想法? +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +参考资料 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Chapter +Java的IO +\begin_inset CommandInset label +LatexCommand label +name "chap:Java的IO" + +\end_inset + + +\end_layout + +\begin_layout Standard +输入输出(IO)看起来简单,但是却头绪繁多、内容繁杂。这是因为我们要处理的输入输出设备种类众多,导致Java通过面向对象的方式对输入输出设备及其操作的封装也比较 +复杂,因此建议读者在学习本章内容的时候要经常跳出具体的技术细节,回到下图从总体上把握Java IO的体系。 +\end_layout + +\begin_layout Standard +\align center +\begin_inset Graphics + filename ../imgs/io/Java-IO.png + width 100line% + +\end_inset + + +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +内容是否太多?不容易理出一个头绪来 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Section +C的IO回顾 +\begin_inset CommandInset label +LatexCommand label +name "sec:C的IO回顾" + +\end_inset + + +\end_layout + +\begin_layout Standard +在C语言中,输入输出的概念分为两个层面: +\end_layout + +\begin_layout Itemize +输入输出的“源”都被看做设备,使用设备描述符 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +设备描述符 +\end_layout + +\end_inset + +来区分不同的输入输出源。 +\end_layout + +\begin_layout Itemize +从设备输入或者输出的数据通过“流”(stream +\begin_inset Index idx +status open + +\begin_layout Plain Layout +stream +\end_layout + +\end_inset + +)模型来处理,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:C的输入模型" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:C的输出模型" + +\end_inset + +。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +把下图的输入流和输出流画成管道的形状 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/c-input.eps + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +C的输入模型 +\begin_inset CommandInset label +LatexCommand label +name "fig:C的输入模型" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/c-output.eps + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +C的输出模型 +\begin_inset CommandInset label +LatexCommand label +name "fig:C的输出模型" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +所谓的“流”(stream),是一个仅容一个bit数据通过的管道,即数据的有序序列,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:输入流模型" + +\end_inset + +所示。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这个图似乎表达的不是很清楚? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/input-stream.eps + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +输入流模型 +\begin_inset CommandInset label +LatexCommand label +name "fig:输入流模型" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Quotes eld +\end_inset + +流模型”的最大好处是,每个I/O函数都尽力做最好的自己即可,通过“流模型”可以将不同的I/O函数串联起来协同完成更复杂的IO操作。Java的IO体系也借鉴了C中 +的IO设计,只不过C是面向过程的语言,IO的处理是通过函数来完成的,而Java是面向对象的方式来处理IO,IO的操作是通过不同的IO操作类来完成的。 +\end_layout + +\begin_layout Section +Java的IO体系 +\begin_inset CommandInset label +LatexCommand label +name "sec:Java的IO体系" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java继承了C对输入输出的基本认识:无论输入输出来自何处(设备),去往何处(设备),一律当做“流”的方式来处理。流就像一个仅容一个bit数据通过的管道一样,是 +一个有序的数据序列。如果我们按照8位(1个字节)来分割解读流中的数据序列,就是“面向字节的流”,有时也简称“字节流 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +字节流 +\end_layout + +\end_inset + +”;如果我们以16位(2个字节,即1个字符)来分割和解读流中的数据,就是“面向字符的流”,有时也简称“字符流 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +字符流 +\end_layout + +\end_inset + +”。其实,字节流和字符流的区分并没有改变流的数据本质,只是我们以不同的视角解读数据罢了,就像一部红楼,经学家看见《易》,道学家看见淫,才子看见缠绵,革命家看见排 +满,流言家看见宫闱秘事 +\begin_inset Foot +status open + +\begin_layout Plain Layout +出自《鲁迅全集-集外集拾遗补编•<绛洞花主>小引》 +\end_layout + +\end_inset + +。红楼还是那部红楼,不同的人,不同的场合,不同的视角,不同的解读而已。 +\end_layout + +\begin_layout Standard +Java IO相关的类在包java.io中。 +\end_layout + +\begin_layout Subsection +面向字节的流 +\begin_inset CommandInset label +LatexCommand label +name "subsec:面向字节的流" + +\end_inset + + +\end_layout + +\begin_layout Standard +所谓面向字节的流,是指流中的数据按照字节来解释,即每8位(1个字节)为一个解读的单元。Java提供了如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java的InputStream类层次结构" + +\end_inset + +所示的面向字节的流的处理类层次结构。其中的节点流是指直接与输入输出设备打交道处理I/O操作的类,处理流是指对原始数据进行二次加工的类。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/inputstream.eps + width 100line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java的InputStream/OutputStream类层次结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java的InputStream类层次结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java的InputStream类层次结构" + +\end_inset + +中的InputStream/OutputStream的子类有各自的应用场景,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:InputStream/OutputStream子类的适用场景" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +类名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +FileInputStream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读取二进制文件,比如图片、音视频等。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +PipedInputStream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +提供了管道化操作的具体实现:PipedInputStream通常和一个PipedOutputStream关联在一起,即PipedOutputStream的输出送 +给PipedInputStream。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ByteArrayInput\SpecialChar softhyphen +Stream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +将一个字节数组当做一个InputStream来处理。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +SequenceInput\SpecialChar softhyphen +Stream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +将多个InputStream收尾相接组成一个新的InputStream。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +FilterInputStream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +顾名思义,FilterInputStream接受一个InputStream作为参数,然后对这个InputStream中的数据做相应的处理后再输出。即,Filte +rInputStream通常用来对数据进行筛选、变换、编码等处理,FilterInputStream的不同子类已经实现了若干的过滤处理,常见的FilterInp +utStream的子类如下: +\end_layout + +\begin_layout Description +BufferedInputStream: 对于任何InputStream提供了缓存处理功能,提高了输入处理的效率。 +\end_layout + +\begin_layout Description +DataInputStream: 如果我们确定InputStream中存储的是基本类型数据,则可以借助于DataInputStream提供的读取基本类型数据方法 +简化操作,这些方法直接返回所需要的基本类型变量,比如readInt。注意到DataInputStream也实现了DataInput接口,在DataInput接口 +中规范了读取基本类型数据的方法。 +\end_layout + +\begin_layout Description +PushBackInputStream: 通常,我们从InputStream读取一个字节后,这个字节就从InputStream移除了,再次从InputStrea +m读取数据会从下一个字节开始。PushBackInputStream的设计目的是把刚刚读取的字节再次送回InputStream,以便有机会再次读取这个字节的数据 +。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ObjectInputStream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +用于对基本数据类型和对象的序列化处理,通常和ObjectOutputStream联合使用,即ObjectInputStreamream所读取的数据通常是由Obj +ectOutputStream写入的。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +InputStream输入流 +\begin_inset CommandInset label +LatexCommand label +name "tab:InputStream/OutputStream子类的适用场景" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +类名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +FileOutputStream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +写入二进制文件,比如图片、音视频等。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +PipedOutputStream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +通常和一个PipedInputStream关联在一起实现管道化操作 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ByteArrayOutput\SpecialChar softhyphen +Stream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +写入到一个字节数组中 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +FilterOutputStream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +接受一个OutputStream作为参数,在数据写入OutputStream之前进行一定的处理。常见的FilterOutputStream子类如下: +\end_layout + +\begin_layout Itemize +DataOutputStream: 将基本数据类型写入OutputStream,便于使用DataInputStream读入处理。 +\end_layout + +\begin_layout Itemize +BufferedOutputStream:对于任何OutputStream提供了缓存处理功能,提高了输出处理的效率。 +\end_layout + +\begin_layout Itemize +PrintStream: 自动刷新缓冲区的OutputStream。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ObjectOutputStream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +用于对基本数据类型和对象的序列化处理。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +OutputStream输出流 +\begin_inset CommandInset label +LatexCommand label +name "tab:OutputStream子类的适用场景" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +InputStream是个抽象类,是所有字节输入流的父类,其中定义了一些基本的字节输入流的操作方法,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:InputStream的常用方法" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public abstract int read() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从输入流读取下一个字节,字节值为0~255。如果输入流不再有数据则返回-1。该方法是一个阻塞方法,直到有数据可读或者数据流结束,或发生异常才返回。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public int read(byte[] b) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从输入流读取一组数据存入缓冲区b中,返回所读取字节的个数。如果返回-1表示数据流结束。该方法相当于read(b, 0, b.length)。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public int read(byte[] b, int off, int len) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从输入流读取最多len字节数据存入缓冲区b中,存储位置从b的第off个位置开始。该方法返回读取的字节数,如果返回-1表示数据流结束。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public int available() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +返回当前输入流可供读取的字节数。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void mark(int readLimit) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +在输入流中标记当前位置,以后可以调用reset方法返回该位置,以便重复读取从该标记位置开始的数据。readLimit设置调用mark方法后可以读取的最大字节数, +且保持mark标记有效。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void reset() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +重置流的读取位置,回到上次调用mark方法标记的位置。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public boolean markSupported() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +检测输入流是否支持mark和reset方法 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public long skip(long n) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从输入流忽略n字节的数据,返回被忽略的实际字节数。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void close() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +关闭输入流,释放所占用的系统资源。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +InputStream的常用方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:InputStream的常用方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public abstract void write(int b) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +向输出流写入一个字节。写出字节为整数b的低字节,整数b的3个高字节被忽略。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void write(byte[] b) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +把缓冲区b中的全部数据写入输出流 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void write(byte[] b, int off, int len) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +把缓冲区b从b[off]开始的len个字节的数据写入输出流 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +pbulic void flush() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +刷新输出流,强制输出缓冲区的数据立即写出 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void close() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +关闭输出流 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +OutputStream的常用方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:OutputStream的常用方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Java内部的数据都是unicode编码 +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见:http://unicode.org/charts。Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Uni +code 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。un +icode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。我们经常说的UTF-8编码是unicode编码的具体实现(除此之外还 +有UTF-16,UTF-32,但是用的不多),UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节 +长度:对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码,因此对于英语字母,UTF-8编码和ASCII码是相同的。 对于n字节的符号(n +>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。 + +\end_layout + +\end_inset + +的,除ASCII码外都是多字节编码方式,因此面向字节的流处理往往用于处理二进制数据,或者用于适合把数据看做二进制的场合。比如: +\end_layout + +\begin_layout Itemize +在工业控制领域,我们把接收到的数据按照自己制定的数据格式写入文件(不一定是Java语言编写的程序写文件,也许是C/C++写文件),在这种情况下就适合使用面向字节 +的流打开文件读取数据。在C语言中我们也特别强调,为了保证正确读写文件,采用什么方式(主要指面向字节还是面向字符)写入文件,就要采用同样的方式打开文件。 +\end_layout + +\begin_layout Itemize +ASCII文件可以安全的使用面向字节的流读写,因为ASCII字符的长度没有超出8位。 +\end_layout + +\begin_layout Itemize +图片、声音、视频等数据一般是以二进制方式存储的,因此适合使用字节流来处理。 +\end_layout + +\begin_layout Standard +我们之前一直在使用的System.in +\begin_inset Index idx +status open + +\begin_layout Plain Layout +System.in +\end_layout + +\end_inset + +,实际上一个InputStream +\begin_inset Index idx +status open + +\begin_layout Plain Layout +InputStream +\end_layout + +\end_inset + +类型的对象,Sytsem.out +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Sytsem.out +\end_layout + +\end_inset + +实际上是一个PrintStream +\begin_inset Index idx +status open + +\begin_layout Plain Layout +PrintStream +\end_layout + +\end_inset + +类型的对象 +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见openjdk的jdk/src/java.base/share/classes/java/lang/System.java +\end_layout + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + /** +\end_layout + +\begin_layout Plain Layout + + * The "standard" input stream. + This stream is already +\end_layout + +\begin_layout Plain Layout + + * open and ready to supply input data. + Typically this stream +\end_layout + +\begin_layout Plain Layout + + * corresponds to keyboard input or another input source specified by +\end_layout + +\begin_layout Plain Layout + + * the host environment or user. +\end_layout + +\begin_layout Plain Layout + + */ +\end_layout + +\begin_layout Plain Layout + + public static final InputStream in = null; +\end_layout + +\begin_layout Plain Layout + + /** +\end_layout + +\begin_layout Plain Layout + + * The "standard" output stream. + This stream is already +\end_layout + +\begin_layout Plain Layout + + * open and ready to accept output data. + Typically this stream +\end_layout + +\begin_layout Plain Layout + + * corresponds to display output or another output destination +\end_layout + +\begin_layout Plain Layout + + * specified by the host environment or user. +\end_layout + +\begin_layout Plain Layout + + *

+\end_layout + +\begin_layout Plain Layout + + * For simple stand-alone Java applications, a typical way to write +\end_layout + +\begin_layout Plain Layout + + * a line of output data is: +\end_layout + +\begin_layout Plain Layout + + *

+\end_layout
+
+\begin_layout Plain Layout
+
+     *     System.out.println(data)
+\end_layout
+
+\begin_layout Plain Layout
+
+     * 
+\end_layout + +\begin_layout Plain Layout + + *

+\end_layout + +\begin_layout Plain Layout + + * See the println methods in class PrintStream. +\end_layout + +\begin_layout Plain Layout + + * +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println() +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println(boolean) +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println(char) +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println(char[]) +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println(double) +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println(float) +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println(int) +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println(long) +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println(java.lang.Object) +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println(java.lang.String) +\end_layout + +\begin_layout Plain Layout + + */ +\end_layout + +\begin_layout Plain Layout + + public static final PrintStream out = null; +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +输入输出流在使用后为什么要及时关闭呢?这是因为,Java把所有的输入输出流都抽象为文件的操作,如果我们不及时关闭打开的输入输出流,相当于不及时关闭打开的文件,久 +而久之可能造成操作系统打开的文件过多,从而拖慢系统运行速度,甚至超出系统允许打开的文件数。因此,输入输出流使用完毕及时关闭是个好习惯。 +\end_layout + +\begin_layout Plain Layout +我们在 +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:try-with-resources" + +\end_inset + +会看到,使用try-with-resources可以方便的管理输入输出流的关闭,减轻了程序员的负担。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +复制二进制文件 +\begin_inset CommandInset label +LatexCommand label +name "exa:复制二进制文件。" + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "CopyBinary.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/CopyBinary.java" +lstparams "caption={CopyBinary.java},label={CopyBinary.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +要复制的文件从哪里来? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在Idea中运行CopyBinary.main()结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +97321151161141051101031049484810504846525310 +\end_layout + +\begin_layout Plain Layout +97321151161141051101031049484810504846525310 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Standard +本例我们实现了两种文件复制的方式: +\end_layout + +\begin_layout Enumerate +不使用缓冲区的字节流。通过FileInputStream读取文件,通过FileOutputStream写入文件,没有使用缓冲区,每次读取一个字节。显然当文件比较 +大时,读写文件的效率是比较低的。 +\end_layout + +\begin_layout Enumerate +使用缓冲区的字节流。利用BufferedInputStream和BufferedOutputStream构造带缓冲区的字节流,这是编程实践中最常见的情形。 +\end_layout + +\begin_layout Standard +注意到我们使用了try-with-resources的Java新语法。如果使用传统的try-catch接口则要注意输入字节流和输出字节流在使用完毕后都需要关闭, +通常借助于finally代码块实现。 +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Example +FileInputStream/FileOutputStream、BufferedInputStream/BufferedOutputStream、DataIn +putSteam/DataOutputStream的使用 +\end_layout + +\begin_layout Paragraph* +设计要求 +\end_layout + +\begin_layout Standard +假设一个表示气温的文件weather.txt有下列数据 +\begin_inset Foot +status open + +\begin_layout Plain Layout +我们在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:文件操作" + +\end_inset + +还会使用文件相关API重新设计本例。 +\end_layout + +\end_inset + +,试将下列数据使用DataOutputStream重新写入文件weather.dat,然后使用DataInputStream读出weather.dat并求温度的平均 +值。 +\end_layout + +\begin_layout Standard +\begin_inset Box Boxed +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +17.1 24.2 +\end_layout + +\begin_layout Plain Layout +18.9 22.3 +\end_layout + +\begin_layout Plain Layout +17.3 -2.3 15.6 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "Temperature.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/Temperature.java" +lstparams "caption={Temperature.java},label={Temperature.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +在Idea中运行Temperature结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +17.1 +\end_layout + +\begin_layout Plain Layout +24.2 +\end_layout + +\begin_layout Plain Layout +18.9 +\end_layout + +\begin_layout Plain Layout +22.3 +\end_layout + +\begin_layout Plain Layout +17.3 +\end_layout + +\begin_layout Plain Layout +-2.3 +\end_layout + +\begin_layout Plain Layout +15.6 +\end_layout + +\begin_layout Plain Layout +average temperature = 16.157142809459142 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Standard +注意到dos的构造方式:DataOutputStream dos = new DataOutputStream(new BufferedOutputStream +(new FileOutputStream( +\begin_inset Quotes eld +\end_inset + +weather.dat +\begin_inset Quotes erd +\end_inset + +))),可以通过 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:DataStream/BufferedStream/InputS" + +\end_inset + +加深理解。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/datastream-buffer-file.eps + lyxscale 70 + width 90line% + +\end_inset + + +\begin_inset Note Note +status open + +\begin_layout Plain Layout +此图可以通过层技术画的更好 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +DataStream/BufferedStream/InputStream的联合使用 +\begin_inset CommandInset label +LatexCommand label +name "fig:DataStream/BufferedStream/InputS" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +注意weather.txt, weather.dat文件的位置:目前是在项目的根目录下的,这是因为几乎所有的IDE环境,包括Eclipse、NetBeans、Ide +a都把项目的根目录作为字节流的根目录来处理,因此我们在上面的例子中,都是采用了相对路径的方式来读写文件。但是,这种读写文件的方式(主要是对文件路径的定义方式)如 +果离开了IDE环境就失效了,因此在实践中一般不采用此种文件定位方式,一般根据classpath定位文件,参见 +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:读写属性文件" + +\end_inset + +。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +无论是读取还是写入文件,字节流的操作分为以下两种方式: +\end_layout + +\begin_layout Enumerate +按字节处理:每次读取或者写入一个字节; +\end_layout + +\begin_layout Enumerate +按字节数组处理:每次读取或者写入一个字节数组,数组的大小需要事先定义; +\end_layout + +\begin_layout Plain Layout +在字符流中,我们还会看到按行处理的情形,但是在处理字节流时一般不按行处理,其原因是二进制数据一般不进行换行处理。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +使用C语言通过面向字节的方式打开一个文件写入“Hello World!”,然后使用Java语言读取此文件,看看有什么变化? +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +使用C语言通过面向字节的方式打开一个文件写入“你好,世界!”,然后使用Java的面向字节的流读取此文件,看看有什么变化? +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +请将 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +exercisename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:复制二进制文件。" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +改造为从命令行输入源文件和目标文件,然后将源文件复制为目标文件。 +\end_layout + +\begin_layout Subsection +面向字符的流 +\begin_inset CommandInset label +LatexCommand label +name "subsec:面向字符的流" + +\end_inset + + +\end_layout + +\begin_layout Standard +理解了字节流,字符流就不难理解了。字节流是将“流”中的数据按照字节来划分,所谓字符流,只是将“流”中的数据按照2个字节(即一个字符)来划分而已。Java + IO提供了如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:字符流的类层次结构" + +\end_inset + +所示的处理字符流的类层次结构。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/reader-writer.eps + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +字符流的类层次结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:字符流的类层次结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +有必要列出每一个Reader/Writer子类的使用场合吗? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +和字节流非常类似,Reader和Write是两个抽象类,其中封装了操作字符流的基本方法,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Reader的基本方法" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Writer的基本方法" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public int read() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从流读取一个字符并返回,如果没有字符可读则返回-1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public int read(char[] cbuf) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从流读取字符到数组cbuf中,返回读取的字符个数 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public abstract int read(char[] cbuf, int off, int len) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从流读取字符到数组cbuf中,并从cbuf[off]开始存储,最多读取len个字符。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public long skip(long n) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +跳过流中的n个字符 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public boolean ready() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +检测输入字符流是否可读 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void mark(int readAheadLimit) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +标记流的当前位置,readAheadLimit表示在此位置有效期间最多可以读取的字符数 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void reset() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +复位标记过的流 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public abstract void close() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +关闭流 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Reader的基本方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:Reader的基本方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void write(int c) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +写一个字符到流 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void write(char[] cbuf) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +写字符数组cbuf到流 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public abstract void write(char[] cbuf, int off, int len) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +写字符数组cbuf到流,从cbuf[off]开始最多写入len个字符 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void write(String str) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +写字符串str到流 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void write(String str, int off, int len) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +写字符串str到流,从off个字符开始,最多写入len个字符 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public abstract void flush() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +刷新流缓冲区 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public abstract void close() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +关闭流 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Writer的基本方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:Writer的基本方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +从键盘输入数据 +\begin_inset CommandInset label +LatexCommand label +name "sec:从键盘输入数据" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Wrap figure +lines 0 +placement r +overhang 0in +width "40line%" +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/x-memory-layout.eps + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +实数3.125的内存表达 +\begin_inset CommandInset label +LatexCommand label +name "fig:实数3.125的内存表达" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +对于输入输出而言,使用最多的就是从键盘输入数据 +\begin_inset CommandInset citation +LatexCommand cite +after "p104,输入数据" +key "java-chenweijun" +literal "true" + +\end_inset + +,以及在显示器上输出数据。在Java语言中,数据的输出很方便,使用System.out.println就已经很好用了,无论什么类型的数据,都能够自动转换为字符串输出 +(在Java8以后,甚至包括了List、Map类型的数据),这里不再赘述。但是Java从键盘输入数据确实不是太方便,比如考虑下面的情形:从键盘输入一个实数3.12 +5保存到变量x中,该如何完成这个任务呢?如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:实数3.125的内存表达" + +\end_inset + +所示。我们的目标是获得一个单精度浮点类型变量x,其值为3.125,在内存中占用4个字节的内存空间,从高到低的4个字节分别为40、48、00和00(均为16进制数) +。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +浮点数的内存存储方式是哪里讲解的?在这里需要将知识点链接起来 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +从键盘输入数据,我们已经知道必须通过System.in来完成,下面我们再次回顾一下System类的基本内容: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public final class System { +\end_layout + +\begin_layout Plain Layout + + ... +\end_layout + +\begin_layout Plain Layout + + public final static InputStream in = null; +\end_layout + +\begin_layout Plain Layout + + ... +\end_layout + +\begin_layout Plain Layout + + private static void initializeSystemClass() { +\end_layout + +\begin_layout Plain Layout + + ... +\end_layout + +\begin_layout Plain Layout + + FileInputStream fdIn = new FileInputStream(FileDescriptor.in); +\end_layout + +\begin_layout Plain Layout + + setIn0(new BufferedInputStream(fdIn)); +\end_layout + +\begin_layout Plain Layout + + ... +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,in是System类的静态成员变量,在系统初始化的时候,in初始化为一个带缓冲的文件字节流,即 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +in是一个从标准输入设备(FileDescriptor.in)接受二进制数据并实现了缓存处理的字节流 +\end_layout + +\end_inset + +。另外也需要注意到,in是InputStream类型的,但其实在初始化的时候我们看到了,in的真实类型是BufferedInputStream类型的,这是前面讲 +过的多态 +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:多态" + +\end_inset + + +\end_layout + +\end_inset + +的概念:子类对象,父类引用。 +\end_layout + +\begin_layout Standard +如果我们直接使用Sytem.in从键盘读入3.125,比如保存到一个byte数组中: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +byte[] b = new byte[20]; +\end_layout + +\begin_layout Plain Layout + +System.in.read(b); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +则内存中的数据如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:InputStream的read方法" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/inputstream-read.eps + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +InputStream的read方法 +\begin_inset CommandInset label +LatexCommand label +name "fig:InputStream的read方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +可以看出,当从键盘输入3.125时,保存在数组b中的是它们的ASCII值(注意 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:InputStream的read方法" + +\end_inset + +中使用16进制表示内存中的数据),并且包括了回车符和换行符 +\begin_inset Foot +status open + +\begin_layout Plain Layout +如果在Linux下面进行测试的话,从键盘输入是不包含回车符' +\backslash +r'的,只有换行符' +\backslash +n',即在Linux下面通过换行符' +\backslash +n'表示输入结束。 +\end_layout + +\end_inset + +,显然数组b不符合要求,我们很难直接将数组b直接转换为一个float类型的数据。 +\begin_inset Foot +status open + +\begin_layout Plain Layout +并非不能,而是比较麻烦,比如可以这样做: +\end_layout + +\begin_layout Plain Layout +byte[] b = new byte[20]; +\end_layout + +\begin_layout Plain Layout +float f = Float.valueOf(new String(b)); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +既然直接使用字节流不容易达成我们的目标,使用字符流InputStreamReader可以吗?InputStreamReader的构造方法是: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public InputStreamReader(InputStream in); +\end_layout + +\begin_layout Plain Layout + +public InputStreamReader(InputStream in, String enc) throws UnsupportedEncodingE +xception; +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +InputStreamReader的构造方法的参数是InputStream类型的,也就是说,InputStreamReader的功能是把字节流转换为字符流,于是 +我们可以尝试这样解决: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +char[] c = new char[20]; +\end_layout + +\begin_layout Plain Layout + +InputStreamReader sr = new InputStreamReader(System.in); +\end_layout + +\begin_layout Plain Layout + +sr.read(c); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +这段代码的功能是从键盘输入一组数据并保存到字符数组c中,c在内存中的内容如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:InputStreamReader类的read方法" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/inputstreamreader-read.eps + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +InputStreamReader类的read方法 +\begin_inset CommandInset label +LatexCommand label +name "fig:InputStreamReader类的read方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +可以看出,数组c存放的数据与 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:InputStream的read方法" + +\end_inset + +中的数组b是完全一样的,唯一的区别是数据类型发生了变化。b是一个字节类型的数组,每个数组元素只占一个字节;c是一个字符类型的数组,每个数组元素占两个字节。因此, +使用InputStreamReader和使用InputStream输入浮点数会遇到相似的问题:都需要将输入的数据(字节数组或者字符数组)转换为字符串对象然后使用 +Float.valueOf(String s)转换为浮点数。有没有办法从键盘直接获取字符串呢?InputStream和InputStreamReader都没有提供 +这样的功能,即便BufferedInputStream也没有提供直接从键盘获取字符串的功能,这是容易理解的:InputStream、BufferedInputS +tream的目的是原始的二进制字节,InputStreamReader的目的是为了获取原始的二进制字符,这些都和字符串没有关系。BufferedReader提供 +了从键盘获取字符串的功能,其中的readLine方法可以从键盘获取一行字符,并自动删除了末尾的回车换行符,于是我们有了最终的解决方案 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +本节的完整测试代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/io/src/cn/edu/s +dut/softlab/SystemInTest.java +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); +\end_layout + +\begin_layout Plain Layout + +String str = reader.readLine(); +\end_layout + +\begin_layout Plain Layout + +float x = Float.parseFloat(str); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在这段代码中,以System.in对象为输入参数,创建了一个InputStreamReader对象,然后以该对象为参数,创建了一个BufferedReader对象 +,从而形成了这几个类之间的连接关系 +\begin_inset Foot +status open + +\begin_layout Plain Layout +这里BufferedReader、InputStreamReader、System.in(InputStream)使用了设计模式中的装饰器模式,详情参见本系列教程 +的“提高篇”。 +\end_layout + +\end_inset + +,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:从键盘输入数据相关类的关系" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/input-from-keyboard-stream.eps + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +从键盘输入数据相关类的关系 +\begin_inset CommandInset label +LatexCommand label +name "fig:从键盘输入数据相关类的关系" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +这里的基本思路是:InputStream类负责从键盘读入字节流,然后InputStreamReader类将字节流转换为字符流,接着BufferedReader进 +行缓冲并读取一行字符,即把末尾的回车换行符去掉并将数据转化为 +\begin_inset Flex Emph +status open + +\begin_layout Plain Layout +字符串 +\end_layout + +\end_inset + +,最后调用Float类的parseFloat方法把这个字符串转换为相应的实数。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +本节内容中,我们从观察java数据的内存表达深刻理解java的输入输出,常见的IDE都可以帮助我们方便的观察Java数据在内存中的存储格式,比如在Idea中调试 +SystemInTest时可以看到Idea即时的给出了各个变量的当前值: +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/inputstream-read-idea-debug.png + width 85line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Note Note +status open + +\begin_layout Plain Layout +也考虑增加NetBeans/Eclipse的截图 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +如果我们仅仅需要用户从键盘输入一个简单的响应,比如yes或y的话,可以利用System.console方法,代码示例如下: +\end_layout + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +static boolean okayToOverwrite(String file) { +\end_layout + +\begin_layout Plain Layout + + String answer = System.console().readLine("overwrite %s (yes/no)? ", file); +\end_layout + +\begin_layout Plain Layout + + return (answer.equalsIgnoreCase("y") || answer.equalsIgnoreCase("yes")); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +Scanner类 +\begin_inset CommandInset label +LatexCommand label +name "sec:Scanner类" + +\end_inset + + +\end_layout + +\begin_layout Standard +从 +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:从键盘输入数据" + +\end_inset + +一节的描述可以看出,Java在处理键盘输入数据时实在不够友好,于是从Java 1.5开始增加了一个工具类Scanner简化从键盘输入数据的处理。Scanner类也 +是从InputStream接受数据,但是可以根据模式匹配的方法直接将二进制数据转换为相应的基本数据类型。具体的说,Scanner会自动根据分隔符(默认为空白字符 +,包括空格符、回车符、换行符、制表符)从输入数据中分离出一个个字符串(称为token),并转换为要求的整数、实数或者字符串等,从而方便的实现了在同一行读入多个不 +同类型的数据。 +\end_layout + +\begin_layout Standard +Scanner类的常用方法如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Scanner类的常用方法" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public byte nextByte() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读入下一个字节(byte) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public short nextShort() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读入下一个短整数(short) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public int nextInt() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读入下一个整数(int) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public long nextLong() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读入下一个长整数(long) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public float nextFloat() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读入下一个单精度浮点数(float) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public double nextDouble() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读入下一个双精度浮点数(double) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public boolean hasNext() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +是否存在可读的数据? +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public String next() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读入下一个token(即空白字符隔开的独立的字符串) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public String nextLine() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读入下一行 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public Scanner useDelimiter(Pattern pattern) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +使用自定义的token分隔符 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +应该增加一个token的用法示例 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Scanner类的常用方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:Scanner类的常用方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +从键盘输入两个整数,计算其乘积并输出 +\begin_inset CommandInset label +LatexCommand label +name "exa:从键盘输入两个整数,计算其乘积并输出。" + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "Multiply.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/MultiplyTest.java" +lstparams "caption={Multiply.java},label={Multiply.java}" + +\end_inset + + +\end_layout + +\begin_layout Exercise +使用BufferedReader改写 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:从键盘输入两个整数,计算其乘积并输出。" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +使用Scanner读取文件“双城记.txt”,统计该小说有多少个单词 +\begin_inset Foot +status open + +\begin_layout Plain Layout +双城记文本下载地址: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://archive.org/stream/ataleoftwocities00098gut/98.txt +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +? +\end_layout + +\begin_layout Section +*文件操作 +\begin_inset CommandInset label +LatexCommand label +name "sec:文件操作" + +\end_inset + + +\end_layout + +\begin_layout Subsection +什么是Path? +\end_layout + +\begin_layout Standard +在新的文件操作API +\begin_inset Foot +status open + +\begin_layout Plain Layout +JDK 1.7引入了新的文件操作API,即NIO.2,本节内容着重于NIO.2,不再涉及旧的文件API。 +\end_layout + +\end_inset + +中,Path的概念至关重要,类Path是文件操作的入口。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这里简要说明Path的功能 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +无论是Windows操作系统还是Linux操作系统,文件系统都是树状结构的。典型的文件系统如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:目录树示意图" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/linux-directory-tree.eps + width 45line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Linux系统目录树 +\begin_inset CommandInset label +LatexCommand label +name "fig:Linux系统目录树" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\align left +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/windows-directory-tree.eps + width 45line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Windows系统目录树 +\begin_inset CommandInset label +LatexCommand label +name "fig:Windows系统目录树" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +目录树示意图 +\begin_inset CommandInset label +LatexCommand label +name "fig:目录树示意图" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +myfile.txt的路径(Path)在Linux系统表示为: +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +/home/lisi/myfile.txt +\end_layout + +\end_inset + +;而在Windows系统下myfile.txt的路径(Path)表示为: +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +c: +\backslash +users +\backslash +list +\backslash +myfile.txt +\end_layout + +\end_inset + +。这里要特别注意到目录分隔符的区别:Windows操作系统使用反斜杠( +\backslash +) +\begin_inset Foot +status open + +\begin_layout Plain Layout +众所周知,Unix的历史要比Windows久远,Windows的设计从Unix中汲取了很多营养,但是Windows的路径分隔符和Unix系统的路径分隔符截然相反 +,给后来的程序设计带来了一些困扰:你必须正确识别和处理不同操作系统的路径分隔符。你一定会想,要是当初微软在设计Windows的时候使用和Unix相同的路径分隔符 +,该多好!历史没有如果,现实如此残酷!欲知当初微软选择反斜杠作为文件分隔符的原因,请参考:https://blogs.msdn.microsoft.com/larry +osterman/2005/06/24/why-is-the-dos-path-character/。简单的说,Windows操作系统脱胎于Dos操作系统,在D +os操作系统中斜杠(/)已经作为命令行参数的分隔符了,因此Windows只好选用其他的分隔符(反斜杠)作为文件路径分隔符。 +\end_layout + +\end_inset + +作为目录分隔符,而其他所有操作系统(包括Linux、Unix、MacOS)都使用斜杠(/)作为目录分隔符。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +注意到,路径(Path)不仅仅是目录的意思。实际上,路径(Path)包含了以下几种情况: +\end_layout + +\begin_layout Itemize +纯粹文件名,比如:myfile.txt +\end_layout + +\begin_layout Itemize +纯粹目录,比如:/home/sili +\end_layout + +\begin_layout Itemize +绝对路径+文件名,比如:/home/lisi/myfile.txt +\end_layout + +\begin_layout Itemize +相对路径+文件名,比如:./lisi/myfile.txt +\end_layout + +\begin_layout Plain Layout +以上几种情况都是路径(Path)。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +相对路径和绝对路径 +\end_layout + +\begin_layout Standard +从形式上看,相对路径和绝对路径很容易区分:以目录分隔符(Linux系统使用/,windows系统使用 +\backslash +)为起点的路径是绝对路径,其他形式的路径是相对路径。下面是一些示例,都表示文件myfile.txt: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +# 假设当前位于/ +\end_layout + +\begin_layout Plain Layout +/home/lisi/myfile.txt # 绝对路径 +\end_layout + +\begin_layout Plain Layout +home/lisi/myfile.txt # 相对路径 +\end_layout + +\begin_layout Plain Layout +./home/lisi/myfile.txt # 相对路径,.表示当前目录 +\end_layout + +\begin_layout Plain Layout +# 假设当前位于/home +\end_layout + +\begin_layout Plain Layout +/home/lisi/myfile.txt # 绝对路径 +\end_layout + +\begin_layout Plain Layout +lisi/myfile.txt # 相对路径 +\end_layout + +\begin_layout Plain Layout +./lisi/myfile.txt # 相对路径 +\end_layout + +\begin_layout Plain Layout +# 假设当前位于/usr  +\end_layout + +\begin_layout Plain Layout +/home/lisi/myfile.txt # 绝对路径 +\end_layout + +\begin_layout Plain Layout +../home/lisi/myfile.txt # 相对路径,..表示上一级目录 +\end_layout + +\begin_layout Plain Layout +/home/lisi/../zhangsan/myfile.txt # 绝对路径 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +Path类 +\begin_inset CommandInset label +LatexCommand label +name "subsec:Path类" + +\end_inset + + +\end_layout + +\begin_layout Standard +Path类是Java的新文件API的重点和核心,顾名思义,Path类代表了一个路径,一个Path对象包括了文件名和文件所在的目录,因此Path类中包含了处理文件 +和目录的相关方法。 +\end_layout + +\begin_layout Subsubsection +创建Path对象 +\end_layout + +\begin_layout Standard +利用Paths类(注意和Path类的区别)的get方法可以很方便的创建一个Path对象,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "CreatePathTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/CreatePathTest.java" +lstparams "float,caption={CreatePathTest.java},label={CreatePathTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +在Idea中利用调试功能可以方便的观察所创建的Path对象,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:在Ideal中通过调试观察Path对象" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/create-path-debug.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +在Ideal中通过调试观察Path对象 +\begin_inset CommandInset label +LatexCommand label +name "fig:在Ideal中通过调试观察Path对象" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +获取Path信息 +\end_layout + +\begin_layout Standard +Path对象的主要信息是目录分隔符隔开的一个字符串数组,可以通过getName方法返回这个数组的每个元素 +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见本系列教程的“提高篇”,结合lambda表达式操作这个数组更方便,比如: +\end_layout + +\begin_layout Plain Layout +Path path = Paths.get( +\begin_inset Quotes eld +\end_inset + +/home/subaochen/test.txt +\begin_inset Quotes erd +\end_inset + +); +\end_layout + +\begin_layout Plain Layout +path.forEach(p -> System.out.println(p)); +\end_layout + +\end_inset + +,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PathInfoTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathInfoTest.java" +lstparams "float,caption={PathInfoTest.java},label={PathInfoTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PathInfoTest.java" + +\end_inset + +中涉及的主要方法的用法参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "tab:Path信息相关方法" + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +String toString() +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +路径的字符串表达,自动根据不同操作系统使用了不同的目录分隔符 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Path getFileName() +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +路径中的最“远”对象,即Path路径数组的最后一个元素,可能是真实的文件名,也可能是一个子目录名。注意,getFileName方法的返回值是Path,因此打印g +etFileName实际上会调用返回的Path对象的toString方法。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Path getName(int index) +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +返回Path数组的第index个元素。路径中的第一个元素index为0,最后一个元素的index为count-1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +int getNameCount() +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +返回Path中的元素个数 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Path subpath(int beginIndex, int endIndex) +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +非常类似于String类的subString的用法,返回Path中的一部分信息。beginIndex和endIndex分别指定起始index和终止Index。注 +意到,endIndex处的元素不包含在返回的Path中。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Path getParent() +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +当前Path对象的上一级Path,大部分情况下,getParent相当于subpath(0,getNameCount() -1),即将Path数组最后一个元素去 +掉即为上一级Path。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Path getRoot() +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +返回根路径。如果是相对路径,则返回null。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Path信息相关方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:Path信息相关方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +Path转换 +\end_layout + +\begin_layout Standard +Path转换主要通过 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "tab:Path转换方法" + +\end_inset + +中的3个方法实现的。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +URI toUri() +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +使用 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Uri +\end_layout + +\end_inset + +方式描述路径。对于本地文件(文件系统)使用file协议,因此URI的形式如file:///path-to-file +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Path toAbsolutePath() +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +返回绝对路径,这对于了解文件在文件系统的位置很有帮助 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Path toRealPath(LinkOption... + options) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +返回真实的文件路径。该方法会检测文件是否存在,也是唯一一个检测文件是否存在的Path方法。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +really? +\end_layout + +\end_inset + +参数options决定了如何处理符号链接。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Path转换方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:Path转换方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PathConversionTest.java" + +\end_inset + +演示了Path转换的三种情况。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathConversionTest.java" +lstparams "float,caption={PathConversionTest.java},label={PathConversionTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +拼接Path +\end_layout + +\begin_layout Standard +Path类的resolve方法可以拼接路径,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PathResolveTest.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathResolveTest.java" +lstparams "float,caption={PathResolveTest.java},label={PathResolveTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +需要注意的是,如果resolve的参数是一个绝对路径,则拼接的结果只是返回参数中的绝对路径,因此在resolve中应该避免传入一个绝对路径。 +\end_layout + +\begin_layout Plain Layout +拼接Path的另外一个方法是relativize,请参考JDK的相关文档。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +比较Path +\end_layout + +\begin_layout Standard +比较Path主要是通过3个方法,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "tab:比较两个Path的方法" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +boolean equals(Object otherPath) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +重写了Object.equals方法,比较两个Path对象是否相同:两个Path对象代表的路径相同则两个Path对象相同 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +boolean endsWith(Path other) +\end_layout + +\begin_layout Plain Layout +boolean endsWith(String other) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +判断Path对象是否以给定的Path对象或者路径字符串结尾 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +boolean startsWith(Path other) +\end_layout + +\begin_layout Plain Layout +boolean startsWith(String other) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +判断Path对象是否以给定的Path对象或者路径字符串开头 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +比较两个Path的方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:比较两个Path的方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +比较Path的示例参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PathCompareTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathCompareTest.java" +lstparams "float,caption={PathCompareTest.java},label={PathCompareTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Section +*Files类 +\begin_inset CommandInset label +LatexCommand label +name "sec:*Files类" + +\end_inset + + +\end_layout + +\begin_layout Standard +Files +\begin_inset Foot +status open + +\begin_layout Plain Layout +你可能会迷惑,为什么不命名为File类呢?很遗憾的是,File类是旧的(JDK 1.7之前)的Java文件操作API中的文件操作类,新的文件操作类只好叫做File +s了。通常,以单数命名的类用来表示一类事物,复数命名的类是工具辅助类类,比如Path表征路径,Paths是路径的工具辅助类。因此Files并不是一个很好的类的命 +名,这也是Java API无奈的选择。 +\end_layout + +\end_inset + +类是Java文件操作新API(java.nio.file包)中文件操作的核心类。相对于Path类,Files类聚焦于文件相关的操作: +\begin_inset Note Note +status open + +\begin_layout Plain Layout +进一步概括说明Files类的功能 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +检查文件或者目录 +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:Path类" + +\end_inset + +中我们看到,Path类的大多数方法不会检查文件或者目录是否存在,换句话说,Path中的大多数方法只是对给定的路径进行语法上的检查和操作。Files类的exist +s和notExists方法可以用来检查一个Path对象是否存在于实际的文件系统中,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "PathExistTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathExistTest.java" +lstparams "float,caption={PathExistTest.java},label={PathExistTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +exists返回false可能存在两种情况: +\end_layout + +\begin_layout Enumerate +文件或者目录不存在; +\end_layout + +\begin_layout Enumerate +文件或者目录不可见,即当前用户没有权限查看该文件或者目录。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +我们可以使用isReadable、isWritable、isExecutable进一步检查文件是否可读、可写、可执行,比如下面的代码片段: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +Path file = ...; +\end_layout + +\begin_layout Plain Layout + +boolean isRegularExecutableFile = Files.isRegularFile(file) & +\end_layout + +\begin_layout Plain Layout + + Files.isReadable(file) & Files.isExecutable(file); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +删除文件或者目录 +\end_layout + +\begin_layout Standard +Files.delete方法删除文件或者目录。需要注意的是,如果要删除的是目录,则目录必须是空的,否则删除失败。示例代码参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PathDeleteTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathDeleteTest.java" +lstparams "float,caption={PathDeleteTest.java},label={PathDeleteTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Subsection +复制文件或者目录 +\end_layout + +\begin_layout Standard +Files.copy方法可以复制文件或者目录。默认情况下,copy方法不会覆盖目的文件,但是可以通过传递CopyOption参数影响复制的过程: +\end_layout + +\begin_layout Itemize +REPLACE_EXISTING:覆盖目的文件。 +\end_layout + +\begin_layout Itemize +COPY_ATTRIBUTES:也复制文件属性到目的文件。如果不设置此选项,只是复制文件本身,文件属性取决于目的目录的设置。 +\end_layout + +\begin_layout Itemize +NOFOLLOW_LINKS:复制符号链接而非符号链接指向的文件。 +\end_layout + +\begin_layout Standard +示例程序参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "PathCopyTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathCopyTest.java" +lstparams "caption={PathCopyTest.java},label={PathCopyTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +Files.copy也支持复制文件到流,或者从流复制到文件: +\end_layout + +\begin_layout Itemize +copy(InputStream, Path, CopyOption...options) +\end_layout + +\begin_layout Itemize +copy(Path, OutputStream) +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +移动文件或者目录 +\end_layout + +\begin_layout Standard +Files.move可以移动文件或者目录,文件或者目录改名也是要通过move方法,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PathMoveTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathMoveTest.java" +lstparams "caption={PathMoveTest.java},label={PathMoveTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Subsection +操作文件或者目录的属性 +\end_layout + +\begin_layout Standard +我们经常见到元数据(metadata)这个说法。简单的说,元数据是描述数据的数据,或者说,一类事物的元数据描述了一类事物的属性。对照面向对象的概念我们可以看出, +元数据非常像类的属性。Java提供了一组读取或者设置文件属性的方法,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:File操作文件属性的方法" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +文件大小 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +public static long size(Path path) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +获取文件的大小(字节数) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +创建时间 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +没有提供直接的方法获取文件的创建时间,需要首先获取BasicFileAttributeView,然后解析creationTime,比如: +\end_layout + +\begin_layout Plain Layout +Path file = ...; +\end_layout + +\begin_layout Plain Layout +BasicFileAttributes attr = Files.readAttributes(file, BasicFileAttributes.class); +\end_layout + +\begin_layout Plain Layout +System.out.println("creationTime: " + attr.creationTime()); +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +最后修改时间 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +public static FileTime getLastModifiedTime(Path path, LinkOption... + options) throws IOException +\end_layout + +\begin_layout Plain Layout +public static Path setLastModifiedTime(Path path, FileTime time) throws + IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读取和设置文件的最后修改时间。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +属主 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +public static UserPrincipal getOwner(Path path, LinkOption... + options) throws IOException +\end_layout + +\begin_layout Plain Layout +public static Path setOwner(Path path, UserPrincipal owner) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读取或者设置文件的属主 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +所属组 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +没有提供相应的方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +访问控制属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +public static Set getPosixFilePermissions(Path path, + LinkOption... + options) throws IOException +\end_layout + +\begin_layout Plain Layout +public static Path setPosixFilePermissions(Path path, Set + perms) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读取或者设置文件的访问控制属性 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +是否目录 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +public static boolean isDirectory(Path path, LinkOption... + options) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +判断给定的Path是否目录 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +是否普通文件 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +public static boolean isRegularFile(Path path, LinkOption... + options) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +判断给定的Path是否普通文件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +是否符号连接 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +public static boolean isSymbolicLink(Path path) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +判断给定的Path是否符号链接 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +是否隐藏文件 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +public static boolean isHidden(Path path) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +判断给定的Path是否隐藏文件。注意到,Windows和Linux判断隐藏文件的方法是不同的,Linux的隐藏文件以 +\begin_inset Quotes erd +\end_inset + +. +\begin_inset Quotes erd +\end_inset + +开头,而Windows的隐藏文件设置了“隐藏”属性。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +File操作文件属性的方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:File操作文件属性的方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +利用 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:File操作文件属性的方法" + +\end_inset + +中的方法,一次只能读取或者设置一个文件属性,如果要同时读取或者设置多个文件属性显然比较低效,因此Java提供了批量读取或者设置文件属性的方法,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:批量读取文件属性的方法" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static Map readAttributes(Path path, String attributes, + LinkOption... + options) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +批量读取文件属性,参数attributes给出了所要读取的属性列表,*表示所有属性。属性名称和FileAttributes各子类的属性字段定义相同,参见 +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://docs.oracle.com/javase/8/docs/api/java/nio/file/attribute/FileAttributeVie +w.html +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static A readAttributes(Path path, + Class type, LinkOption... + options) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +批量读取文件属性,参数type是BasicFileAttributes的子类,返回结果和请求参数type相同。此方法更加“面向对象”一些,在IDE的帮助下不容易 +出错,因此建议采用此方法批量读取文件属性。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +批量读取文件属性的方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:批量读取文件属性的方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + +不同操作系统的文件系统存在不小的差别,文件和目录的属性也各不相同,Java为了能够隐藏这些差异和细节,将文件和目录的属性做了进一步的封装,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:文件属性接口" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/fileattributes.eps + lyxscale 300 + width 60col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +文件属性接口 +\begin_inset CommandInset label +LatexCommand label +name "fig:文件属性接口" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +BasicFileAttributes及其子接口只是定义了读取文件属性的方法,如何更新(修改)文件属性呢?Java进一步封装了在各种情况下操作文件属性的Attr +ibuteView类,即可以读取文件属性,也可以更新文件属性,同时屏蔽了不同操作系统的差异,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:读取和设置文件属性的View接口" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/FileAttributeView.eps + lyxscale 300 + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +读取和设置文件属性的View接口 +\begin_inset CommandInset label +LatexCommand label +name "fig:读取和设置文件属性的View接口" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +FileAttribes和FileAttributeView的区别,感觉没说清楚? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +读取文件属性,包括:文件大小、最后修改时间、是否普通文件等。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PathMetadataTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathMetadataTest.java" +lstparams "caption={PathMetadataTest.java},label={PathMetadataTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +在Idea中运行结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +creationTime: 2016-12-12T02:49:04Z +\end_layout + +\begin_layout Plain Layout +lastAccessTime: 2016-12-12T02:51:47Z +\end_layout + +\begin_layout Plain Layout +lastModifiedTime: 2016-12-12T02:49:04Z +\end_layout + +\begin_layout Plain Layout +isDirectory: false +\end_layout + +\begin_layout Plain Layout +isOther: false +\end_layout + +\begin_layout Plain Layout +isRegularFile: true +\end_layout + +\begin_layout Plain Layout +isSymbolicLink: false +\end_layout + +\begin_layout Plain Layout +size: 0 +\end_layout + +\begin_layout Plain Layout +now lastModifiedTime is:2016-12-13T23:54:11Z +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Standard +使用 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:File操作文件属性的方法" + +\end_inset + +中的方法一次只能读取或者设置一个文件的属性,因此如果要一次读取或者设置多个文件属性的话,建议使用readAttributes方法较为高效。 +\end_layout + +\begin_layout Subsection +创建、读写文件 +\end_layout + +\begin_layout Subsubsection +读写小文件 +\begin_inset CommandInset label +LatexCommand label +name "subsec:读写小文件" + +\end_inset + + +\end_layout + +\begin_layout Standard +Files类为读写小文件 +\begin_inset Foot +status open + +\begin_layout Plain Layout +多小的文件算是小文件?因为readAllBytes是把文件全部内容读到一个byte数组中,因此文件的尺寸取决于你的内存多少。但是,并不是所有的内存都可以用来保存 +文件内容的,因此使用这里的方法时要考虑到能够处理的文件的最大尺寸限制。 +\end_layout + +\end_inset + +提供了方便的write和readAllBytes方法,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:读写小文件的方便方法" + +\end_inset + +。可以看出, +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:读写小文件的方便方法" + +\end_inset + +中的方法不需要和输入输出流直接打交道。实际上,Files类的方法是对输入输出流的进一步封装,比如readAllBytes方法 +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见openjdk的jdk/src/java.base/share/classes/java/nio/file/Files.java +\end_layout + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + public static byte[] readAllBytes(Path path) throws IOException { + +\end_layout + +\begin_layout Plain Layout + + try (SeekableByteChannel sbc = Files.newByteChannel(path); +\end_layout + +\begin_layout Plain Layout + + InputStream in = Channels.newInputStream(sbc)) { +\end_layout + +\begin_layout Plain Layout + + long size = sbc.size(); +\end_layout + +\begin_layout Plain Layout + + if (size > (long)MAX_BUFFER_SIZE) +\end_layout + +\begin_layout Plain Layout + + throw new OutOfMemoryError("Required array size too large"); +\end_layout + +\begin_layout Plain Layout + + +\end_layout + +\begin_layout Plain Layout + + return read(in, (int)size); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static Path write(Path path, byte[] bytes, OpenOption... + options) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +将bytes数组写入到文件path中。OpenOption在StandardOpenOption这个Enum中定义: +\end_layout + +\begin_layout Itemize +READ:为读打开文件 +\end_layout + +\begin_layout Itemize +WRITE:为写打开文件 +\end_layout + +\begin_layout Itemize +APPEND:如果可写则追加写入内容到文件末尾 +\end_layout + +\begin_layout Itemize +CREATE:如果文件不存在则创建 +\end_layout + +\begin_layout Itemize +CREATE_NEW:创建新文件;如果文件已经存在则失败,优先级高于CREATE +\end_layout + +\begin_layout Itemize +TRUNCATE_EXISTING:如果文件可写并且已经存在则截断文件尺寸为0 +\end_layout + +\begin_layout Itemize +DELETE_ON_CLOSE:文件操作结束(close)后自动删除文件,这对于临时文件很有用 +\end_layout + +\begin_layout Itemize +DSYNC:自动同步文件的内容到存储介质 +\end_layout + +\begin_layout Itemize +SYNC:自动同步文件的内容和原信息到存储介质 +\end_layout + +\begin_layout Itemize +SPARSE:创建稀疏文件 +\begin_inset Foot +status open + +\begin_layout Plain Layout +稀疏文件是指创建文件的时候并不真正分配空间,只有真正写入文件的时候才逐步分配空间。 +\end_layout + +\end_inset + +,如果文件系统支持的话 +\end_layout + +\begin_layout Plain Layout +默认是CREATE, TRUNCATE_EXISTING和WRITE,即如果文件不存在则创建,如果文件已存在则截断长度为0。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static Path write(Path path, Iterable lines, + Charset cs, OpenOption... + options) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +将文本lines写入文件path中。lines以System.getProperty( +\begin_inset Quotes eld +\end_inset + +line.separator +\begin_inset Quotes erd +\end_inset + +)为行分隔符,并使用给定的(cs)编码 +\begin_inset Foot +status open + +\begin_layout Plain Layout +Java 1.7之后引入了StandCharsets类定义了常见的编码方式,参见:https://docs.oracle.com/javase/8/docs/api/ +java/nio/charset/StandardCharsets.html +\end_layout + +\end_inset + +为byte数组。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static byte[] readAllBytes(Path path) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从path读取所有内容到byte数组。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static List readAllLines(Path path) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读文件path的所有行到List中,行分隔符为 +\backslash +r +\backslash +n(windows下)或 +\backslash +r(Mac下)或 +\backslash +n(Linux下)。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static List readAllLines(Path path, Charset cs) throws IOExceptio +n +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读文件path的所有行到List中,并使用cs编码将byte解码为字符串。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +读写小文件的方便方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:读写小文件的方便方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Example +读写小文件 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "PathCreateTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathCreateTest.java" +lstparams "caption={PathCreateTest.java},label={PathCreateTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +在Idea中运行结果如下,只是简单的输出了文件的内容: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +test string +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Subsubsection +带缓存的文本文件处理方法 +\end_layout + +\begin_layout Standard +处理文本文件时,通常需要借助于缓存提高效率,我们在 +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:面向字符的流" + +\end_inset + +中已经讨论过。Files类提供了如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "tab:Files中带缓存的文本读写方法" + +\end_inset + +的方法更进一步简化了文本文件的处理。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static BufferedWriter newBufferedWriter(Path path, OpenOption... + options) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从path创建一个BufferedReader用于读取文件内容,使用UTF-8解码。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static BufferedReader newBufferedReader(Path path, Charset cs) throws + IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从path创建一个BufferedReader用于读取文件内容,文件内容以cs方式解码,默认使用UTF-8解码。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static BufferedWriter newBufferedWriter(Path path, OpenOption... + options) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从path创建一个BufferedWriter用于写入文件内容,使用UTF-8编码。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static BufferedWriter newBufferedWriter(Path path, Charset cs, OpenOption... + options) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从path创建一个BufferedWriter用于写入文件内容,文件内容以cs方式编码,默认使用UTF-8编码。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Files中带缓存的文本读写方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:Files中带缓存的文本读写方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +下面的代码片段演示了newBufferedReader的用法: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +Charset charset = Charset.forName("UTF-8");// or Charset charset = StandCharsets.U +TF-8; +\end_layout + +\begin_layout Plain Layout + +try (BufferedReader reader = Files.newBufferedReader(file, charset)) { +\end_layout + +\begin_layout Plain Layout + + String line = null; +\end_layout + +\begin_layout Plain Layout + + while ((line = reader.readLine()) != null) { +\end_layout + +\begin_layout Plain Layout + + System.out.println(line); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} catch (IOException x) { +\end_layout + +\begin_layout Plain Layout + + System.err.format("IOException: %s%n", x); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +等价于下面的代码片段(如果文件是UTF-8编码的话): +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +try (BufferedReader reader = Files.newBufferedReader(file)) { +\end_layout + +\begin_layout Plain Layout + + String line = null; +\end_layout + +\begin_layout Plain Layout + + while ((line = reader.readLine()) != null) { +\end_layout + +\begin_layout Plain Layout + + System.out.println(line); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} catch (IOException x) { +\end_layout + +\begin_layout Plain Layout + + System.err.format("IOException: %s%n", x); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +使用不带缓存的输入输出流 +\end_layout + +\begin_layout Standard +Files同样封装了不带缓存的输入输出流,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "tab:Files中不带缓存的输入输出流" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static InputStream newInputStream(Path path, OpenOption... + options) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从path创建一个InputStream用于读取文件内容 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static OutputStream newOutputStream(Path path, OpenOption... + options) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从path创建一个OutputStream用于写入文件内容 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Files中不带缓存的输入输出流 +\begin_inset CommandInset label +LatexCommand label +name "tab:Files中不带缓存的输入输出流" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +Files对不带缓存的输入流的封装 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PathWithoutBufferTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathWithoutBufferTest.java" +lstparams "caption={PathWithoutBufferTest.java},label={PathWithoutBufferTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +在Idea中运行的结果如下(简单的打印出了之前写入的内容): +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Hello World! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Standard +newInputStream返回一个不带缓存的输入流,但是这个例子又根据这个不带缓存的输入流构造了一个BufferedReader以便以行的方式读入文本。你可能 +会问,为什么不直接使用带缓存的newBufferedReader方法呢?是的,在这个例子中,使用newBufferedReader直接返回一个BufferedR +eader更方便,本例只是演示如何构造一个不带缓存的输入流。 +\end_layout + +\begin_layout Subsubsection +channel方式读写文件 +\begin_inset CommandInset label +LatexCommand label +name "subsec:channel方式读写文件" + +\end_inset + + +\end_layout + +\begin_layout Standard +流(stream)是按照字节为单位读写文件的,channel +\begin_inset Note Note +status open + +\begin_layout Plain Layout +如何翻译?通道? +\end_layout + +\end_inset + +是按照缓冲区为单位读写文件的,也就是说,channel是自然带缓冲的,可以一次处理一个缓冲区。SeekableByteChannel内部维护着一个表示当前位置的 +指针,通过移动该指针可以实现随机文件读写,参见 +\begin_inset CommandInset ref +LatexCommand formatted +reference "subsec:随机读写文件" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +Files类的Channel读写文件方法见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Files类的Channel读写文件方法" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +public static SeekableByteChannel newByteChannel(Path path, OpenOption... + options) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从path创建一个 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +SeekableByteChannel +\end_layout + +\end_inset + +用于读写文件内容,默认是只读打开Channel的。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +public static SeekableByteChannel newByteChannel(Path path, Set options, FileAttribute... + attrs) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从path创建一个 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +SeekableByteChannel +\end_layout + +\end_inset + +用于读写文件内容,attrs设置文件的属性。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Files类的Channel读写文件方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:Files类的Channel读写文件方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +使用Channel读写文件 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "FileRandomAccessTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/FileChannelTest.java" +lstparams "caption={FileChannelTest.java},label={FileChannelTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +打印出myfile.txt的内容,不再列出。 +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Standard +和Stream不同,使用Channel读写文件的要点是一次处理一个buffer,因此如何使用Buffer就称为用好Channel的关键。可以借助于Java的Bu +ffer类,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:Buffer的类层次结构" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/buffer.eps + lyxscale 200 + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Caption Standard + +\begin_layout Plain Layout +Buffer的类层次结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:Buffer的类层次结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +下面的讨论以ByteBuffer为例,其他类型的Buffer用法类似。 +\end_layout + +\begin_layout Standard +ByteBuffer实际上是一块可以写入和读取数据的内存,Java提供了若干方便的方法操作这块内存,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:ByteBuffer的用法" + +\end_inset + +,我们假设创建了一个大小为8个字节的ByteBuffer。要理解ByteBuffer的用法,需要首先理解ByteBuffer的三个基本属性: +\end_layout + +\begin_layout Itemize +capacity:ByteBuffer的大小,即占用多少个字节的内存空间。每个ByteBuffer在创建时需要指定capacity,一旦设定不允许改变,这里ca +pacity=8。 +\end_layout + +\begin_layout Itemize +limit:下一次读或者写允许操作的字节数。在写模式下,limit表示当前最多能够向Buffer写多少数据。在读模式下,limit表示当前最多能够读到多少数据。 +\end_layout + +\begin_layout Itemize +position:下一个可以读或者写的字节的位置索引,position的最大值为capacity - 1。在写模式下,position的初始值为0,当写入数据( +字节)后,position移动到下一个可写入的位置,比如在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:ByteBuffer的用法" + +\end_inset + +中,在写入3个字节的数据后,当前position=3。如果此时切换这个ByteBuffer到读模式,则position需要指向下一个可读的字节位置,显然应该将p +osition置为0,limit置为3(即当前position的值),即从Buffer的开头开始能够一次读3个字节的数据,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:ByteBuffer的用法" + +\end_inset + +的“读模式”所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/buffer-usage.eps + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +ByteBuffer的用法 +\begin_inset CommandInset label +LatexCommand label +name "fig:ByteBuffer的用法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Buffer通过flip方法从写模式切换到读模式,通常对Buffer的操作流程为: +\end_layout + +\begin_layout Enumerate +写入数据到Buffer,在这里是通过Channel的read方法写入数据到Buffer,也可以通过Buffer提供的各种put方法写入数据。 +\end_layout + +\begin_layout Enumerate +调用flip方法切换到读模式。 +\end_layout + +\begin_layout Enumerate +从Buffer中读取数据。 +\end_layout + +\begin_layout Enumerate +调用clear或者compact方法清空缓冲区。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +使用Idea可以方便的观察和学习Buffer中capacity、limit、position的变化情况,如下图所示。 +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/buffer-idea-debug.png + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +读写文件的方法很多,何时使用InputStream/OutputStream/InputReader/OutputReader,何时使用Files方法读写文件? +一般的原则是什么? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +创建文件和临时文件 +\end_layout + +\begin_layout Standard +Files也提供了创建文件和临时文件的方便API,见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Files创建文件和临时文件的方法" + +\end_inset + +。createFile和createTempFile被设计为“原子操作”,即首先检查文件是否存在(存在则抛出异常),然后创建一个空文件病设置为指定或者默认的属性 +,因此createFile的安全性要比其他方法高些。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +其他方法是哪些方法?stream?Channel?是否可以对比说明? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +public static Path createFile(Path path, FileAttribute... + attrs) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据path创建属性为attrs的文件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +public static Path createTempFile(Path dir, String prefix, String suffix, + FileAttribute... + attrs) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据dir创建属性为attrs的临时文件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +public static Path createTempFile(String prefix, String suffix, FileAttribute... + attrs) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据dir创建属性为attrs的临时文件 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Files创建文件和临时文件的方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:Files创建文件和临时文件的方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +使用createFile创建文件 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "FileCreateTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/FileCreateTest.java" +lstparams "caption={FileCreateTest.java},label={FileCreateTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行应用程序后检查所创建文件的属性如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +~/test$ ls -l testcreate.txt +\end_layout + +\begin_layout Plain Layout +-rw-rw-r-- 1 subaochen subaochen 0 12月 16 08:20 testcreate.txt +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Standard +createFile时如果没有给出文件属性则默认创建664属性的文件,即用户自己、所属组都可读写,其他所有人均只读。可以通过给出FileAttribute灵活设 +置属性,比如下面的代码片段设置为只对用户自己可读写: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +Path file = ...; +\end_layout + +\begin_layout Plain Layout + +Set perms = +\end_layout + +\begin_layout Plain Layout + + PosixFilePermissions.fromString("rw-------"); +\end_layout + +\begin_layout Plain Layout + +FileAttribute> attr = +\end_layout + +\begin_layout Plain Layout + + PosixFilePermissions.asFileAttribute(perms); +\end_layout + +\begin_layout Plain Layout + +Files.createFile(file, attr); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +编写程序,在/tmp创建一个临时文件temp.log,并观察此临时文件的属性 +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +编写程序,创建一个对所有人只读的文件,并验证所创建文件的属性 +\end_layout + +\begin_layout Subsection +随机读写文件 +\begin_inset CommandInset label +LatexCommand label +name "subsec:随机读写文件" + +\end_inset + + +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:读写小文件" + +\end_inset + +中其实我们已经看到,SeekableByteChannel已经具有随机读写文件的能力了:SeekableByteChannel的下列方法帮助我们确定读写的起始位 +置和数量: +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +long position() throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +返回文件的当前位置,即读和写的起始位置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +SeekableByteChannel position(long newPosition) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +设置Channel的当前位置,返回这个Channel(便于函数式编程) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +long size() throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +返回这个Channel的大小 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +SeekableByteChannel truncate(long size) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +截断这个Channel到给定的大小 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +int read(ByteBuffer dst) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从Channel读数据到dst +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +int write(ByteBuffer src) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +将dst的数据写入Channel +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +SeekableByteChannel的随机读写方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:SeekableByteChannel的随机读写方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +为了更方便的操作文件,JDK提供了对SeekableByteChannel的进一步封装:FileChannel,除SeekableByteChannel中的方法 +外,FileChannel增加了一些高级特性,比如可以将文件的指定区域映射到内存中以便快速访问,锁定文件的指定区域(不允许其他线程进行操作),从任意位置直接读写 +文件等。我们有两种方式获取一个FileChannel: +\end_layout + +\begin_layout Enumerate +通过Path.newByteChannel获得一个SeekableByteChannel,然后强制类型转换为FileChannel。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这种类型转换安全吗? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Enumerate +通过FileInputStream.getChannel获取一个FileChannel。 +\end_layout + +\begin_layout Enumerate +通过FileChannel.open方法直接获得一个FileChannel。推荐采用此种方式。 +\end_layout + +\begin_layout Example +使用FileChannel读写文件,假设文件myfile.txt原来有如下的内容: +\end_layout + +\begin_layout Example +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Java programming language is good! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "FileRandomAccessTest.java" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/FileRandomAccessTest.java" +lstparams "caption={FileRandomAccessTest.java},label={FileRandomAccessTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph +运行结果 +\end_layout + +\begin_layout Standard +在Idea中运行结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +I was here! +\end_layout + +\begin_layout Plain Layout +ming language is good!Java programI was here! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,在文件的开头写入了 +\begin_inset Quotes erd +\end_inset + +I was here! +\backslash +n +\begin_inset Quotes erd +\end_inset + +,然后把文件开头原先的 +\begin_inset Quotes erd +\end_inset + +Java program +\begin_inset Quotes erd +\end_inset + +移动到了文件的最后,并在最后追加了 +\begin_inset Quotes erd +\end_inset + +I was here! +\backslash +n +\begin_inset Quotes erd +\end_inset + +。 +\end_layout + +\begin_layout Standard +本程序可以反复运行,结果完全一致。 +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Standard +FileChannel提供的文件随机读写概念,重要的是理解两个position的用法: +\end_layout + +\begin_layout Itemize +FileChannel的position,用于确定从什么地方开始读写文件; +\end_layout + +\begin_layout Itemize +ByteBuffer的position,用于确定从什么地方开始读写ByteBuffer; +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +FileChannel、InputStream/OutputStream、ByteBuffer之间的关系和用法可以形象的用下图表示: +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/file-channel-stream-buffer.eps + width 90col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +简单的说,ByteBuffer处于“中心”的位置,无论是从文件系统、网络读入的数据,还是准备写入文件系统、网络的数据,都是通过ByteBuffer的。因此,其他 +数据类型如何转换为ByteBuffer以及ByteBuffer如何转换为其他数据类型就显得非常重要,上图的大部分篇幅展示了这种相互转换的方法。 +\end_layout + +\begin_layout Plain Layout +我们可以看出,ByteBuffer转换为其他数据类型已经非常方便了,但是从其他数据类型转换为ByteBuffer的通道却不是很流畅,比如从short[]转换为一 +个ByteBuffer,目前没有直接的方法,只能通过遍历这个short数组,然后将数组的每个元素放入ByteBuffer这种稍微曲折的方法: +\end_layout + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +ByteBuffer bb; +\end_layout + +\begin_layout Plain Layout + +... +\end_layout + +\begin_layout Plain Layout + +for(short s:short_array) { +\end_layout + +\begin_layout Plain Layout + + bb.putShort(s); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +相信JDK的未来版本会提供更丰富和合理的ByteBuffer和其他数据类型的相互转换方法。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +目录操作 +\end_layout + +\begin_layout Standard +目录是一种特殊的文件,我们前面介绍的很多API(所有接受Path作为参数的API)即可以操作文件,也可操作目录。但是毕竟目录的操作有其特殊性,比如下面的情形: +\end_layout + +\begin_layout Itemize +创建一个空目录 +\end_layout + +\begin_layout Itemize +列出目录下的所有子目录 +\end_layout + +\begin_layout Itemize +列出目录下的所有文件 +\end_layout + +\begin_layout Itemize +根据给定的规则列出目录下的文件和目录 +\end_layout + +\begin_layout Standard +JDK的Files类同样给出了目录操作的方便方法,分述如下。 +\end_layout + +\begin_layout Subsubsection +创建目录 +\end_layout + +\begin_layout Standard +Files类创建目录主要是两个方法,createDirectory用于创建一级目录,createDirectories用于创建多级目录,见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:创建目录的方法" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +public static Path createDirectory(Path dir, FileAttribute... + attrs) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据dir和attrs创建一个目录。如果没有attrs参数则创建默认属性的目录。如果目录已经存在则抛出FileAlreadyExistsException异常。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +public static Path createDirectories(Path dir, FileAttribute... + attrs) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据dir创建多级目录 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +创建目录的方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:创建目录的方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +创建目录 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "CreateDirectoryTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/CreateDirectoryTest.java" +lstparams "caption={CreateDirectoryTest.java},label={CreateDirectoryTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Standard +第一次运行时终端没有任何显示,但是当我们去往test目录查看时,应该可以看到test目录下面多了一个新目录a。 +\end_layout + +\begin_layout Standard +当第二次运行该程序时,终端显示: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +java.nio.file.FileAlreadyExistsException: /home/subaochen/test/a +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,如果dir目录已经存在,则createDirectory方法抛出FileAlreadyExistsException异常。 +\end_layout + +\begin_layout Standard +我们删除a目录,但是创建一个文件名字叫做a,即在test目录执行下列命令: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +~/test$ rmdir a; touch a +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +再次执行本程序,终端显示: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +java.nio.file.FileAlreadyExistsException: /home/subaochen/test/a +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +即,如果要创建的目录和文件重名也是不允许的,同样抛出FileAlreadyExistsException。 +\end_layout + +\begin_layout Exercise +使用Files.createDirectories创建目录test/a/b/c +\end_layout + +\begin_layout Subsubsection +列出目录 +\begin_inset CommandInset label +LatexCommand label +name "subsec:列出目录" + +\end_inset + + +\end_layout + +\begin_layout Standard +Files的newDirectoryStream方法可以很方便的列出目录下的内容,包括子目录、文件、隐藏文件等,但是需要注意的是,newDirectoryStr +eam不是一个递归的过程,即不能深入到当前目录的子目录查找内容。 +\end_layout + +\begin_layout Example +利用newDirectoryStream方法列出当前目录下的文件、子目录等。 +\begin_inset CommandInset label +LatexCommand label +name "exa:列出当前目录下的文件、子目录等。" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "ListDirectoryTest.java" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/ListDirectoryTest.java" +lstparams "caption={ListDirectoryTest.java},label={ListDirectoryTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Standard +要注意到newDirectoryStream返回的是一个stream,因此和InputStream等用法类似,一定要记得用完后close这个stream。try +-with-resources结构能够自动关闭stream,如果使用try-catch结构,则要在finanlly块中执行stream.close()方法关闭st +ream。 +\end_layout + +\begin_layout Exercise +如何利用newDirectoryStream方法递归的列出当前目录下的内容,包括子目录下的文件及其子目录? +\end_layout + +\begin_layout Subsubsection +根据规则列出目录 +\end_layout + +\begin_layout Standard +newDirectoryStream允许传入Glob +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +appendixname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:什么是Glob?" + +\end_inset + + +\end_layout + +\end_inset + +过滤规则作为参数。 +\end_layout + +\begin_layout Example +列出当前目录下的所有java源代码和java class文件。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "ListDirectoryWithGlobTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/ListDirectoryWithGlobTest.java" +lstparams "caption={ListDirectoryWithGlobTest.java},label={ListDirectoryWithGlobTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计和分析 +\end_layout + +\begin_layout Standard +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:列出当前目录下的文件、子目录等。" + +\end_inset + +相比,我们看到newDirectoryStream方法只是多了一个参数:表明如何过滤本目录下的内容。 +\end_layout + +\begin_layout Subsection +遍历目录:FileVisitor接口 +\end_layout + +\begin_layout Standard +在 +\begin_inset CommandInset ref +LatexCommand formatted +reference "subsec:列出目录" + +\end_inset + +中我们看到了,可以利用Files.newDirectoryStream列出当前目录下的内容,但是newDirectoryStream不是递归处理的,因此Files +类提供了遍历目录的另外方式:使用FileVisitor接口可以更方便的遍历目录。 +\end_layout + +\begin_layout Standard +首先实现FileVisitor接口,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "PrintFiles.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PrintFiles.java" +lstparams "caption={PrintFiles.java},label={PrintFiles.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +然后可以在主类中使用FileVisitor接口遍历目录了,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "WalkFileTreeTest.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/WalkFileTreeTest.java" +lstparams "caption={WalkFileTreeTest.java},label={WalkFileTreeTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +这里的关键是,walkFileTree方法会递归的遍历给定的目录,但是对于递归过程中遇到的每一个项目如何处理呢?我们看到walkFileTree的第二个参数是一 +个实现了FileVisitor接口的对象,这个对象决定了如何处理这些遇到的目录项目,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:FileVisitor接口方法" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs) throws + IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +在访问(操作)目录之前的动作,比如准备将目录复制到另外的目录中等。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +FileVisitResult postVisitDirectory(T dir, IOException exc) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +在访问(操作)目录之后的动作,比如访问目录后可以将目录删除等。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +FileVisitResult visitFile(T file, BasicFileAttributes attrs) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +访问目录中的文件。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +FileVisitResult visitFileFailed(T file, IOException exc) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +如果访问文件失败则调用此方法。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +FileVisitor接口方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:FileVisitor接口方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +*访问属性文件 +\begin_inset CommandInset label +LatexCommand label +name "sec:读写属性文件" + +\end_inset + + +\end_layout + +\begin_layout Standard +属性文件通常用来保存应用程序的配置信息,这样当应用程序的配置改变时,只需要修改属性文件(配置文件)即可,不需要修改应用程序的源代码,维护比较方便。属性文件的内容 +通常是以key、value对的形式出现,即key=value的形式,比如数据库相关的应用程序中通常将数据库服务器的IP地址、用户名、密码等信息保存到如下的属性文 +件中: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +hostname=192.168.1.200 +\end_layout + +\begin_layout Plain Layout +username=postgres +\end_layout + +\begin_layout Plain Layout +password=password +\end_layout + +\begin_layout Plain Layout +database=mydb +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Java的Properties类提供了方便的API读写这样的属性文件。 +\end_layout + +\begin_layout Example +访问属性文件 +\begin_inset CommandInset label +LatexCommand label +name "exa:访问属性文件" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PropertyFileTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PropertyFileTest.java" +lstparams "caption={PropertyFileTest.java},label={PropertyFileTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行本应用程序结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +hostname=localhost +\end_layout + +\begin_layout Plain Layout +password=password +\end_layout + +\begin_layout Plain Layout +database=mydb +\end_layout + +\begin_layout Plain Layout +username=postgres +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计和分析 +\end_layout + +\begin_layout Standard +本例中,我们使用了FileInputStrem和FileOutputStream构造了一个文件输入输出流,FileInpoutStream和FileOutput +Stream的参数是文件名,注意到该文件名是相对于项目根目录的。 +\end_layout + +\begin_layout Standard +实际上, +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +Java在定位文件时,有如下的几种策略 +\end_layout + +\end_inset + + +\begin_inset Foot +status open + +\begin_layout Plain Layout +参考了: +\end_layout + +\begin_layout Itemize +http://www.cnblogs.com/yinger/archive/2011/09/08/2171831.html +\end_layout + +\begin_layout Itemize +官方教程:https://docs.oracle.com/javase/tutorial/essential/environment/properties.html +\end_layout + +\end_inset + +: +\end_layout + +\begin_layout Itemize +绝对路径:在FileInputStream、FileOutputStream中如果参数的路径使用路径分隔符(windows下是 +\backslash +,Linux下是/)开头则是绝对路径。 +\end_layout + +\begin_layout Itemize +相对于项目的路径:在FileInputStream、FileOutputStream中如果参数的路径没有使用路径分隔符(windows下是 +\backslash +,Linux下是/)开头则是项目于项目根目录的相对路径。 +\end_layout + +\begin_layout Itemize +相对于当前class文件的路径:如果使用Class.getResourceAsStream方法,则获得相对于当前class文件的路径,比如: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +InputStream path = PropertyFileTest.class.getResourceAsStream(database-config.prope +rties); +\end_layout + +\end_inset + +path对象指向的文件database-config.properties和class文件在同一个目录下,即database-config.properties位于 +src/cn/edu/sdut/softlab目录下。 +\begin_inset Newline newline +\end_inset + +但是,如果参数是绝对路径,则获得是相对于包的文件路径,比如: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +InputStream path = PropertyFileTest.class.getResourceAsStream(/database-config.prop +erties); +\end_layout + +\end_inset + +则文件database-config.properties位于src目录下。 +\end_layout + +\begin_layout Itemize +相对于包的路径:如果使用Class.getClassLoader().getResourceAsStream方法,则获得是相对于包路径的文件,比如: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +InputStream path = PropertyFileTest.class.getClassLoader().getResourceAsStream(data +base-config.properties); +\end_layout + +\end_inset + +即文件database-config.properties位于src目录下。 +\begin_inset Newline newline +\end_inset + +同时需要注意到,Class.getClassLoader.getResourceAsStream的参数不允许使用绝对路径,否则返回的InputStream为null +。 +\end_layout + +\begin_layout Standard + +\end_layout + +\end_body +\end_document diff --git a/guide/lecture_guide/lecture11.lyx b/guide/lecture_guide/lecture11.lyx new file mode 100644 index 0000000..82537a8 --- /dev/null +++ b/guide/lecture_guide/lecture11.lyx @@ -0,0 +1,10427 @@ +#LyX 2.3 created this file. For more info see http://www.lyx.org/ +\lyxformat 544 +\begin_document +\begin_header +\save_transient_properties true +\origin unavailable +\textclass ctex-book +\begin_preamble +\input{book-preamble.tex} +\end_preamble +\use_default_options true +\begin_modules +coderemarks +logicalmkup +tip-inset +note-inset +warning-inset +theorems-bytype +theorems-chap-bytype +\end_modules +\maintain_unincluded_children false +\begin_local_layout +PackageOptions url hyphens +\end_local_layout +\language chinese-simplified +\language_package default +\inputencoding utf8-plain +\fontencoding global +\font_roman "default" "DejaVu Sans" +\font_sans "default" "DejaVu Serif" +\font_typewriter "default" "DejaVu Sans Mono" +\font_math "auto" "auto" +\font_default_family default +\use_non_tex_fonts true +\font_sc false +\font_osf false +\font_sf_scale 100 100 +\font_tt_scale 100 100 +\use_microtype false +\use_dash_ligatures true +\graphics default +\default_output_format pdf4 +\output_sync 0 +\bibtex_command default +\index_command default +\float_placement tbph +\paperfontsize default +\spacing single +\use_hyperref true +\pdf_bookmarks true +\pdf_bookmarksnumbered false +\pdf_bookmarksopen false +\pdf_bookmarksopenlevel 3 +\pdf_breaklinks true +\pdf_pdfborder true +\pdf_colorlinks true +\pdf_backref false +\pdf_pdfusetitle true +\papersize default +\use_geometry false +\use_package amsmath 1 +\use_package amssymb 1 +\use_package cancel 1 +\use_package esint 1 +\use_package mathdots 1 +\use_package mathtools 1 +\use_package mhchem 1 +\use_package stackrel 1 +\use_package stmaryrd 1 +\use_package undertilde 1 +\cite_engine basic +\cite_engine_type default +\biblio_style plain +\use_bibtopic false +\use_indices false +\paperorientation portrait +\suppress_date false +\justification true +\use_refstyle 1 +\use_minted 0 +\boxbgcolor #dad3d7 +\index Index +\shortcut idx +\color #008000 +\end_index +\secnumdepth 3 +\tocdepth 2 +\paragraph_separation indent +\paragraph_indentation default +\is_math_indent 0 +\math_numbering_side default +\quotes_style english +\dynamic_quotes 0 +\papercolumns 1 +\papersides 2 +\paperpagestyle default +\tracking_changes false +\output_changes false +\html_math_output 0 +\html_css_as_file 0 +\html_be_strict false +\end_header + +\begin_body + +\begin_layout Standard +\align center + +\size larger +\bar under +山东理工大学教案 +\end_layout + +\begin_layout Standard +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +第十一次课 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +教学课型:理论课□√ 实验课□√ 习题课□ 实践课□ 技能课□ 其它□ +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +主要教学内容 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:从键盘输入数据" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:从键盘输入数据" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Scanner类" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:Scanner类" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:文件操作" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:文件操作" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +重点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +Java从键盘输入的深刻理解; +\end_layout + +\begin_layout Enumerate +Java文件操作的基本API; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +难点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +深刻理解Java从键盘接收输入的过程; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +课程目标及要求 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +课程目标:课程目标1 +\end_layout + +\begin_layout Plain Layout +要求: +\end_layout + +\begin_layout Enumerate +从键盘输入入手,深刻理解Java的I/O类是如何相互协作的; +\end_layout + +\begin_layout Enumerate +掌握Java的文件操作API; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +教学方法和手段 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +板书和多媒体相结合,边讲边练,当堂消化。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +讨论、思考题 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +猜测一下,Scanner类是如何封装输入操作的?找到JDK源代码研读一下,验证自己的想法。 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +参考资料 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Chapter +Java的IO +\begin_inset CommandInset label +LatexCommand label +name "chap:Java的IO" + +\end_inset + + +\end_layout + +\begin_layout Standard +输入输出(IO)看起来简单,但是却头绪繁多、内容繁杂。这是因为我们要处理的输入输出设备种类众多,导致Java通过面向对象的方式对输入输出设备及其操作的封装也比较 +复杂,因此建议读者在学习本章内容的时候要经常跳出具体的技术细节,回到下图从总体上把握Java IO的体系。 +\end_layout + +\begin_layout Standard +\align center +\begin_inset Graphics + filename ../imgs/io/Java-IO.png + width 100line% + +\end_inset + + +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +内容是否太多?不容易理出一个头绪来 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Section +C的IO回顾 +\begin_inset CommandInset label +LatexCommand label +name "sec:C的IO回顾" + +\end_inset + + +\end_layout + +\begin_layout Standard +在C语言中,输入输出的概念分为两个层面: +\end_layout + +\begin_layout Itemize +输入输出的“源”都被看做设备,使用设备描述符 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +设备描述符 +\end_layout + +\end_inset + +来区分不同的输入输出源。 +\end_layout + +\begin_layout Itemize +从设备输入或者输出的数据通过“流”(stream +\begin_inset Index idx +status open + +\begin_layout Plain Layout +stream +\end_layout + +\end_inset + +)模型来处理,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:C的输入模型" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:C的输出模型" + +\end_inset + +。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +把下图的输入流和输出流画成管道的形状 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/c-input.eps + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +C的输入模型 +\begin_inset CommandInset label +LatexCommand label +name "fig:C的输入模型" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/c-output.eps + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +C的输出模型 +\begin_inset CommandInset label +LatexCommand label +name "fig:C的输出模型" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +所谓的“流”(stream),是一个仅容一个bit数据通过的管道,即数据的有序序列,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:输入流模型" + +\end_inset + +所示。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这个图似乎表达的不是很清楚? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/input-stream.eps + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +输入流模型 +\begin_inset CommandInset label +LatexCommand label +name "fig:输入流模型" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Quotes eld +\end_inset + +流模型”的最大好处是,每个I/O函数都尽力做最好的自己即可,通过“流模型”可以将不同的I/O函数串联起来协同完成更复杂的IO操作。Java的IO体系也借鉴了C中 +的IO设计,只不过C是面向过程的语言,IO的处理是通过函数来完成的,而Java是面向对象的方式来处理IO,IO的操作是通过不同的IO操作类来完成的。 +\end_layout + +\begin_layout Section +Java的IO体系 +\begin_inset CommandInset label +LatexCommand label +name "sec:Java的IO体系" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java继承了C对输入输出的基本认识:无论输入输出来自何处(设备),去往何处(设备),一律当做“流”的方式来处理。流就像一个仅容一个bit数据通过的管道一样,是 +一个有序的数据序列。如果我们按照8位(1个字节)来分割解读流中的数据序列,就是“面向字节的流”,有时也简称“字节流 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +字节流 +\end_layout + +\end_inset + +”;如果我们以16位(2个字节,即1个字符)来分割和解读流中的数据,就是“面向字符的流”,有时也简称“字符流 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +字符流 +\end_layout + +\end_inset + +”。其实,字节流和字符流的区分并没有改变流的数据本质,只是我们以不同的视角解读数据罢了,就像一部红楼,经学家看见《易》,道学家看见淫,才子看见缠绵,革命家看见排 +满,流言家看见宫闱秘事 +\begin_inset Foot +status open + +\begin_layout Plain Layout +出自《鲁迅全集-集外集拾遗补编•<绛洞花主>小引》 +\end_layout + +\end_inset + +。红楼还是那部红楼,不同的人,不同的场合,不同的视角,不同的解读而已。 +\end_layout + +\begin_layout Standard +Java IO相关的类在包java.io中。 +\end_layout + +\begin_layout Subsection +面向字节的流 +\begin_inset CommandInset label +LatexCommand label +name "subsec:面向字节的流" + +\end_inset + + +\end_layout + +\begin_layout Standard +所谓面向字节的流,是指流中的数据按照字节来解释,即每8位(1个字节)为一个解读的单元。Java提供了如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java的InputStream类层次结构" + +\end_inset + +所示的面向字节的流的处理类层次结构。其中的节点流是指直接与输入输出设备打交道处理I/O操作的类,处理流是指对原始数据进行二次加工的类。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/inputstream.eps + width 100line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java的InputStream/OutputStream类层次结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java的InputStream类层次结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java的InputStream类层次结构" + +\end_inset + +中的InputStream/OutputStream的子类有各自的应用场景,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:InputStream/OutputStream子类的适用场景" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +类名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +FileInputStream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读取二进制文件,比如图片、音视频等。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +PipedInputStream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +提供了管道化操作的具体实现:PipedInputStream通常和一个PipedOutputStream关联在一起,即PipedOutputStream的输出送 +给PipedInputStream。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ByteArrayInput\SpecialChar softhyphen +Stream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +将一个字节数组当做一个InputStream来处理。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +SequenceInput\SpecialChar softhyphen +Stream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +将多个InputStream收尾相接组成一个新的InputStream。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +FilterInputStream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +顾名思义,FilterInputStream接受一个InputStream作为参数,然后对这个InputStream中的数据做相应的处理后再输出。即,Filte +rInputStream通常用来对数据进行筛选、变换、编码等处理,FilterInputStream的不同子类已经实现了若干的过滤处理,常见的FilterInp +utStream的子类如下: +\end_layout + +\begin_layout Description +BufferedInputStream: 对于任何InputStream提供了缓存处理功能,提高了输入处理的效率。 +\end_layout + +\begin_layout Description +DataInputStream: 如果我们确定InputStream中存储的是基本类型数据,则可以借助于DataInputStream提供的读取基本类型数据方法 +简化操作,这些方法直接返回所需要的基本类型变量,比如readInt。注意到DataInputStream也实现了DataInput接口,在DataInput接口 +中规范了读取基本类型数据的方法。 +\end_layout + +\begin_layout Description +PushBackInputStream: 通常,我们从InputStream读取一个字节后,这个字节就从InputStream移除了,再次从InputStrea +m读取数据会从下一个字节开始。PushBackInputStream的设计目的是把刚刚读取的字节再次送回InputStream,以便有机会再次读取这个字节的数据 +。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ObjectInputStream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +用于对基本数据类型和对象的序列化处理,通常和ObjectOutputStream联合使用,即ObjectInputStreamream所读取的数据通常是由Obj +ectOutputStream写入的。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +InputStream输入流 +\begin_inset CommandInset label +LatexCommand label +name "tab:InputStream/OutputStream子类的适用场景" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +类名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +FileOutputStream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +写入二进制文件,比如图片、音视频等。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +PipedOutputStream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +通常和一个PipedInputStream关联在一起实现管道化操作 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ByteArrayOutput\SpecialChar softhyphen +Stream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +写入到一个字节数组中 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +FilterOutputStream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +接受一个OutputStream作为参数,在数据写入OutputStream之前进行一定的处理。常见的FilterOutputStream子类如下: +\end_layout + +\begin_layout Itemize +DataOutputStream: 将基本数据类型写入OutputStream,便于使用DataInputStream读入处理。 +\end_layout + +\begin_layout Itemize +BufferedOutputStream:对于任何OutputStream提供了缓存处理功能,提高了输出处理的效率。 +\end_layout + +\begin_layout Itemize +PrintStream: 自动刷新缓冲区的OutputStream。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ObjectOutputStream +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +用于对基本数据类型和对象的序列化处理。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +OutputStream输出流 +\begin_inset CommandInset label +LatexCommand label +name "tab:OutputStream子类的适用场景" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +InputStream是个抽象类,是所有字节输入流的父类,其中定义了一些基本的字节输入流的操作方法,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:InputStream的常用方法" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public abstract int read() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从输入流读取下一个字节,字节值为0~255。如果输入流不再有数据则返回-1。该方法是一个阻塞方法,直到有数据可读或者数据流结束,或发生异常才返回。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public int read(byte[] b) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从输入流读取一组数据存入缓冲区b中,返回所读取字节的个数。如果返回-1表示数据流结束。该方法相当于read(b, 0, b.length)。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public int read(byte[] b, int off, int len) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从输入流读取最多len字节数据存入缓冲区b中,存储位置从b的第off个位置开始。该方法返回读取的字节数,如果返回-1表示数据流结束。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public int available() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +返回当前输入流可供读取的字节数。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void mark(int readLimit) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +在输入流中标记当前位置,以后可以调用reset方法返回该位置,以便重复读取从该标记位置开始的数据。readLimit设置调用mark方法后可以读取的最大字节数, +且保持mark标记有效。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void reset() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +重置流的读取位置,回到上次调用mark方法标记的位置。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public boolean markSupported() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +检测输入流是否支持mark和reset方法 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public long skip(long n) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从输入流忽略n字节的数据,返回被忽略的实际字节数。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void close() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +关闭输入流,释放所占用的系统资源。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +InputStream的常用方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:InputStream的常用方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public abstract void write(int b) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +向输出流写入一个字节。写出字节为整数b的低字节,整数b的3个高字节被忽略。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void write(byte[] b) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +把缓冲区b中的全部数据写入输出流 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void write(byte[] b, int off, int len) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +把缓冲区b从b[off]开始的len个字节的数据写入输出流 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +pbulic void flush() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +刷新输出流,强制输出缓冲区的数据立即写出 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void close() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +关闭输出流 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +OutputStream的常用方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:OutputStream的常用方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Java内部的数据都是unicode编码 +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见:http://unicode.org/charts。Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Uni +code 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。un +icode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。我们经常说的UTF-8编码是unicode编码的具体实现(除此之外还 +有UTF-16,UTF-32,但是用的不多),UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节 +长度:对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码,因此对于英语字母,UTF-8编码和ASCII码是相同的。 对于n字节的符号(n +>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。 + +\end_layout + +\end_inset + +的,除ASCII码外都是多字节编码方式,因此面向字节的流处理往往用于处理二进制数据,或者用于适合把数据看做二进制的场合。比如: +\end_layout + +\begin_layout Itemize +在工业控制领域,我们把接收到的数据按照自己制定的数据格式写入文件(不一定是Java语言编写的程序写文件,也许是C/C++写文件),在这种情况下就适合使用面向字节 +的流打开文件读取数据。在C语言中我们也特别强调,为了保证正确读写文件,采用什么方式(主要指面向字节还是面向字符)写入文件,就要采用同样的方式打开文件。 +\end_layout + +\begin_layout Itemize +ASCII文件可以安全的使用面向字节的流读写,因为ASCII字符的长度没有超出8位。 +\end_layout + +\begin_layout Itemize +图片、声音、视频等数据一般是以二进制方式存储的,因此适合使用字节流来处理。 +\end_layout + +\begin_layout Standard +我们之前一直在使用的System.in +\begin_inset Index idx +status open + +\begin_layout Plain Layout +System.in +\end_layout + +\end_inset + +,实际上一个InputStream +\begin_inset Index idx +status open + +\begin_layout Plain Layout +InputStream +\end_layout + +\end_inset + +类型的对象,Sytsem.out +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Sytsem.out +\end_layout + +\end_inset + +实际上是一个PrintStream +\begin_inset Index idx +status open + +\begin_layout Plain Layout +PrintStream +\end_layout + +\end_inset + +类型的对象 +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见openjdk的jdk/src/java.base/share/classes/java/lang/System.java +\end_layout + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + /** +\end_layout + +\begin_layout Plain Layout + + * The "standard" input stream. + This stream is already +\end_layout + +\begin_layout Plain Layout + + * open and ready to supply input data. + Typically this stream +\end_layout + +\begin_layout Plain Layout + + * corresponds to keyboard input or another input source specified by +\end_layout + +\begin_layout Plain Layout + + * the host environment or user. +\end_layout + +\begin_layout Plain Layout + + */ +\end_layout + +\begin_layout Plain Layout + + public static final InputStream in = null; +\end_layout + +\begin_layout Plain Layout + + /** +\end_layout + +\begin_layout Plain Layout + + * The "standard" output stream. + This stream is already +\end_layout + +\begin_layout Plain Layout + + * open and ready to accept output data. + Typically this stream +\end_layout + +\begin_layout Plain Layout + + * corresponds to display output or another output destination +\end_layout + +\begin_layout Plain Layout + + * specified by the host environment or user. +\end_layout + +\begin_layout Plain Layout + + *

+\end_layout + +\begin_layout Plain Layout + + * For simple stand-alone Java applications, a typical way to write +\end_layout + +\begin_layout Plain Layout + + * a line of output data is: +\end_layout + +\begin_layout Plain Layout + + *

+\end_layout
+
+\begin_layout Plain Layout
+
+     *     System.out.println(data)
+\end_layout
+
+\begin_layout Plain Layout
+
+     * 
+\end_layout + +\begin_layout Plain Layout + + *

+\end_layout + +\begin_layout Plain Layout + + * See the println methods in class PrintStream. +\end_layout + +\begin_layout Plain Layout + + * +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println() +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println(boolean) +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println(char) +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println(char[]) +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println(double) +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println(float) +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println(int) +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println(long) +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println(java.lang.Object) +\end_layout + +\begin_layout Plain Layout + + * @see java.io.PrintStream#println(java.lang.String) +\end_layout + +\begin_layout Plain Layout + + */ +\end_layout + +\begin_layout Plain Layout + + public static final PrintStream out = null; +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +输入输出流在使用后为什么要及时关闭呢?这是因为,Java把所有的输入输出流都抽象为文件的操作,如果我们不及时关闭打开的输入输出流,相当于不及时关闭打开的文件,久 +而久之可能造成操作系统打开的文件过多,从而拖慢系统运行速度,甚至超出系统允许打开的文件数。因此,输入输出流使用完毕及时关闭是个好习惯。 +\end_layout + +\begin_layout Plain Layout +我们在 +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:try-with-resources" + +\end_inset + +会看到,使用try-with-resources可以方便的管理输入输出流的关闭,减轻了程序员的负担。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +复制二进制文件 +\begin_inset CommandInset label +LatexCommand label +name "exa:复制二进制文件。" + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "CopyBinary.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/CopyBinary.java" +lstparams "caption={CopyBinary.java},label={CopyBinary.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +要复制的文件从哪里来? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在Idea中运行CopyBinary.main()结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +97321151161141051101031049484810504846525310 +\end_layout + +\begin_layout Plain Layout +97321151161141051101031049484810504846525310 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Standard +本例我们实现了两种文件复制的方式: +\end_layout + +\begin_layout Enumerate +不使用缓冲区的字节流。通过FileInputStream读取文件,通过FileOutputStream写入文件,没有使用缓冲区,每次读取一个字节。显然当文件比较 +大时,读写文件的效率是比较低的。 +\end_layout + +\begin_layout Enumerate +使用缓冲区的字节流。利用BufferedInputStream和BufferedOutputStream构造带缓冲区的字节流,这是编程实践中最常见的情形。 +\end_layout + +\begin_layout Standard +注意到我们使用了try-with-resources的Java新语法。如果使用传统的try-catch接口则要注意输入字节流和输出字节流在使用完毕后都需要关闭, +通常借助于finally代码块实现。 +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Example +FileInputStream/FileOutputStream、BufferedInputStream/BufferedOutputStream、DataIn +putSteam/DataOutputStream的使用 +\end_layout + +\begin_layout Paragraph* +设计要求 +\end_layout + +\begin_layout Standard +假设一个表示气温的文件weather.txt有下列数据 +\begin_inset Foot +status open + +\begin_layout Plain Layout +我们在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:文件操作" + +\end_inset + +还会使用文件相关API重新设计本例。 +\end_layout + +\end_inset + +,试将下列数据使用DataOutputStream重新写入文件weather.dat,然后使用DataInputStream读出weather.dat并求温度的平均 +值。 +\end_layout + +\begin_layout Standard +\begin_inset Box Boxed +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +17.1 24.2 +\end_layout + +\begin_layout Plain Layout +18.9 22.3 +\end_layout + +\begin_layout Plain Layout +17.3 -2.3 15.6 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "Temperature.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/Temperature.java" +lstparams "caption={Temperature.java},label={Temperature.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +在Idea中运行Temperature结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +17.1 +\end_layout + +\begin_layout Plain Layout +24.2 +\end_layout + +\begin_layout Plain Layout +18.9 +\end_layout + +\begin_layout Plain Layout +22.3 +\end_layout + +\begin_layout Plain Layout +17.3 +\end_layout + +\begin_layout Plain Layout +-2.3 +\end_layout + +\begin_layout Plain Layout +15.6 +\end_layout + +\begin_layout Plain Layout +average temperature = 16.157142809459142 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Standard +注意到dos的构造方式:DataOutputStream dos = new DataOutputStream(new BufferedOutputStream +(new FileOutputStream( +\begin_inset Quotes eld +\end_inset + +weather.dat +\begin_inset Quotes erd +\end_inset + +))),可以通过 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:DataStream/BufferedStream/InputS" + +\end_inset + +加深理解。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/datastream-buffer-file.eps + lyxscale 70 + width 90line% + +\end_inset + + +\begin_inset Note Note +status open + +\begin_layout Plain Layout +此图可以通过层技术画的更好 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +DataStream/BufferedStream/InputStream的联合使用 +\begin_inset CommandInset label +LatexCommand label +name "fig:DataStream/BufferedStream/InputS" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +注意weather.txt, weather.dat文件的位置:目前是在项目的根目录下的,这是因为几乎所有的IDE环境,包括Eclipse、NetBeans、Ide +a都把项目的根目录作为字节流的根目录来处理,因此我们在上面的例子中,都是采用了相对路径的方式来读写文件。但是,这种读写文件的方式(主要是对文件路径的定义方式)如 +果离开了IDE环境就失效了,因此在实践中一般不采用此种文件定位方式,一般根据classpath定位文件,参见 +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:读写属性文件" + +\end_inset + +。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +无论是读取还是写入文件,字节流的操作分为以下两种方式: +\end_layout + +\begin_layout Enumerate +按字节处理:每次读取或者写入一个字节; +\end_layout + +\begin_layout Enumerate +按字节数组处理:每次读取或者写入一个字节数组,数组的大小需要事先定义; +\end_layout + +\begin_layout Plain Layout +在字符流中,我们还会看到按行处理的情形,但是在处理字节流时一般不按行处理,其原因是二进制数据一般不进行换行处理。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +使用C语言通过面向字节的方式打开一个文件写入“Hello World!”,然后使用Java语言读取此文件,看看有什么变化? +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +使用C语言通过面向字节的方式打开一个文件写入“你好,世界!”,然后使用Java的面向字节的流读取此文件,看看有什么变化? +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +请将 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +exercisename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:复制二进制文件。" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +改造为从命令行输入源文件和目标文件,然后将源文件复制为目标文件。 +\end_layout + +\begin_layout Subsection +面向字符的流 +\begin_inset CommandInset label +LatexCommand label +name "subsec:面向字符的流" + +\end_inset + + +\end_layout + +\begin_layout Standard +理解了字节流,字符流就不难理解了。字节流是将“流”中的数据按照字节来划分,所谓字符流,只是将“流”中的数据按照2个字节(即一个字符)来划分而已。Java + IO提供了如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:字符流的类层次结构" + +\end_inset + +所示的处理字符流的类层次结构。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/reader-writer.eps + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +字符流的类层次结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:字符流的类层次结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +有必要列出每一个Reader/Writer子类的使用场合吗? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +和字节流非常类似,Reader和Write是两个抽象类,其中封装了操作字符流的基本方法,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Reader的基本方法" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Writer的基本方法" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public int read() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从流读取一个字符并返回,如果没有字符可读则返回-1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public int read(char[] cbuf) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从流读取字符到数组cbuf中,返回读取的字符个数 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public abstract int read(char[] cbuf, int off, int len) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从流读取字符到数组cbuf中,并从cbuf[off]开始存储,最多读取len个字符。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public long skip(long n) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +跳过流中的n个字符 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public boolean ready() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +检测输入字符流是否可读 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void mark(int readAheadLimit) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +标记流的当前位置,readAheadLimit表示在此位置有效期间最多可以读取的字符数 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void reset() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +复位标记过的流 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public abstract void close() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +关闭流 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Reader的基本方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:Reader的基本方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void write(int c) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +写一个字符到流 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void write(char[] cbuf) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +写字符数组cbuf到流 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public abstract void write(char[] cbuf, int off, int len) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +写字符数组cbuf到流,从cbuf[off]开始最多写入len个字符 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void write(String str) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +写字符串str到流 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public void write(String str, int off, int len) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +写字符串str到流,从off个字符开始,最多写入len个字符 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public abstract void flush() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +刷新流缓冲区 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public abstract void close() throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +关闭流 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Writer的基本方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:Writer的基本方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +从键盘输入数据 +\begin_inset CommandInset label +LatexCommand label +name "sec:从键盘输入数据" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Wrap figure +lines 0 +placement r +overhang 0in +width "40line%" +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/x-memory-layout.eps + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +实数3.125的内存表达 +\begin_inset CommandInset label +LatexCommand label +name "fig:实数3.125的内存表达" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +对于输入输出而言,使用最多的就是从键盘输入数据 +\begin_inset CommandInset citation +LatexCommand cite +after "p104,输入数据" +key "java-chenweijun" +literal "true" + +\end_inset + +,以及在显示器上输出数据。在Java语言中,数据的输出很方便,使用System.out.println就已经很好用了,无论什么类型的数据,都能够自动转换为字符串输出 +(在Java8以后,甚至包括了List、Map类型的数据),这里不再赘述。但是Java从键盘输入数据确实不是太方便,比如考虑下面的情形:从键盘输入一个实数3.12 +5保存到变量x中,该如何完成这个任务呢?如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:实数3.125的内存表达" + +\end_inset + +所示。我们的目标是获得一个单精度浮点类型变量x,其值为3.125,在内存中占用4个字节的内存空间,从高到低的4个字节分别为40、48、00和00(均为16进制数) +。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +浮点数的内存存储方式是哪里讲解的?在这里需要将知识点链接起来 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +从键盘输入数据,我们已经知道必须通过System.in来完成,下面我们再次回顾一下System类的基本内容: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public final class System { +\end_layout + +\begin_layout Plain Layout + + ... +\end_layout + +\begin_layout Plain Layout + + public final static InputStream in = null; +\end_layout + +\begin_layout Plain Layout + + ... +\end_layout + +\begin_layout Plain Layout + + private static void initializeSystemClass() { +\end_layout + +\begin_layout Plain Layout + + ... +\end_layout + +\begin_layout Plain Layout + + FileInputStream fdIn = new FileInputStream(FileDescriptor.in); +\end_layout + +\begin_layout Plain Layout + + setIn0(new BufferedInputStream(fdIn)); +\end_layout + +\begin_layout Plain Layout + + ... +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,in是System类的静态成员变量,在系统初始化的时候,in初始化为一个带缓冲的文件字节流,即 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +in是一个从标准输入设备(FileDescriptor.in)接受二进制数据并实现了缓存处理的字节流 +\end_layout + +\end_inset + +。另外也需要注意到,in是InputStream类型的,但其实在初始化的时候我们看到了,in的真实类型是BufferedInputStream类型的,这是前面讲 +过的多态 +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:多态" + +\end_inset + + +\end_layout + +\end_inset + +的概念:子类对象,父类引用。 +\end_layout + +\begin_layout Standard +如果我们直接使用Sytem.in从键盘读入3.125,比如保存到一个byte数组中: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +byte[] b = new byte[20]; +\end_layout + +\begin_layout Plain Layout + +System.in.read(b); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +则内存中的数据如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:InputStream的read方法" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/inputstream-read.eps + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +InputStream的read方法 +\begin_inset CommandInset label +LatexCommand label +name "fig:InputStream的read方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +可以看出,当从键盘输入3.125时,保存在数组b中的是它们的ASCII值(注意 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:InputStream的read方法" + +\end_inset + +中使用16进制表示内存中的数据),并且包括了回车符和换行符 +\begin_inset Foot +status open + +\begin_layout Plain Layout +如果在Linux下面进行测试的话,从键盘输入是不包含回车符' +\backslash +r'的,只有换行符' +\backslash +n',即在Linux下面通过换行符' +\backslash +n'表示输入结束。 +\end_layout + +\end_inset + +,显然数组b不符合要求,我们很难直接将数组b直接转换为一个float类型的数据。 +\begin_inset Foot +status open + +\begin_layout Plain Layout +并非不能,而是比较麻烦,比如可以这样做: +\end_layout + +\begin_layout Plain Layout +byte[] b = new byte[20]; +\end_layout + +\begin_layout Plain Layout +float f = Float.valueOf(new String(b)); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +既然直接使用字节流不容易达成我们的目标,使用字符流InputStreamReader可以吗?InputStreamReader的构造方法是: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public InputStreamReader(InputStream in); +\end_layout + +\begin_layout Plain Layout + +public InputStreamReader(InputStream in, String enc) throws UnsupportedEncodingE +xception; +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +InputStreamReader的构造方法的参数是InputStream类型的,也就是说,InputStreamReader的功能是把字节流转换为字符流,于是 +我们可以尝试这样解决: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +char[] c = new char[20]; +\end_layout + +\begin_layout Plain Layout + +InputStreamReader sr = new InputStreamReader(System.in); +\end_layout + +\begin_layout Plain Layout + +sr.read(c); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +这段代码的功能是从键盘输入一组数据并保存到字符数组c中,c在内存中的内容如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:InputStreamReader类的read方法" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/inputstreamreader-read.eps + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +InputStreamReader类的read方法 +\begin_inset CommandInset label +LatexCommand label +name "fig:InputStreamReader类的read方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +可以看出,数组c存放的数据与 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:InputStream的read方法" + +\end_inset + +中的数组b是完全一样的,唯一的区别是数据类型发生了变化。b是一个字节类型的数组,每个数组元素只占一个字节;c是一个字符类型的数组,每个数组元素占两个字节。因此, +使用InputStreamReader和使用InputStream输入浮点数会遇到相似的问题:都需要将输入的数据(字节数组或者字符数组)转换为字符串对象然后使用 +Float.valueOf(String s)转换为浮点数。有没有办法从键盘直接获取字符串呢?InputStream和InputStreamReader都没有提供 +这样的功能,即便BufferedInputStream也没有提供直接从键盘获取字符串的功能,这是容易理解的:InputStream、BufferedInputS +tream的目的是原始的二进制字节,InputStreamReader的目的是为了获取原始的二进制字符,这些都和字符串没有关系。BufferedReader提供 +了从键盘获取字符串的功能,其中的readLine方法可以从键盘获取一行字符,并自动删除了末尾的回车换行符,于是我们有了最终的解决方案 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +本节的完整测试代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/io/src/cn/edu/s +dut/softlab/SystemInTest.java +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); +\end_layout + +\begin_layout Plain Layout + +String str = reader.readLine(); +\end_layout + +\begin_layout Plain Layout + +float x = Float.parseFloat(str); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在这段代码中,以System.in对象为输入参数,创建了一个InputStreamReader对象,然后以该对象为参数,创建了一个BufferedReader对象 +,从而形成了这几个类之间的连接关系 +\begin_inset Foot +status open + +\begin_layout Plain Layout +这里BufferedReader、InputStreamReader、System.in(InputStream)使用了设计模式中的装饰器模式,详情参见本系列教程 +的“提高篇”。 +\end_layout + +\end_inset + +,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:从键盘输入数据相关类的关系" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/input-from-keyboard-stream.eps + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +从键盘输入数据相关类的关系 +\begin_inset CommandInset label +LatexCommand label +name "fig:从键盘输入数据相关类的关系" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +这里的基本思路是:InputStream类负责从键盘读入字节流,然后InputStreamReader类将字节流转换为字符流,接着BufferedReader进 +行缓冲并读取一行字符,即把末尾的回车换行符去掉并将数据转化为 +\begin_inset Flex Emph +status open + +\begin_layout Plain Layout +字符串 +\end_layout + +\end_inset + +,最后调用Float类的parseFloat方法把这个字符串转换为相应的实数。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +本节内容中,我们从观察java数据的内存表达深刻理解java的输入输出,常见的IDE都可以帮助我们方便的观察Java数据在内存中的存储格式,比如在Idea中调试 +SystemInTest时可以看到Idea即时的给出了各个变量的当前值: +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/inputstream-read-idea-debug.png + width 85line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Note Note +status open + +\begin_layout Plain Layout +也考虑增加NetBeans/Eclipse的截图 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +如果我们仅仅需要用户从键盘输入一个简单的响应,比如yes或y的话,可以利用System.console方法,代码示例如下: +\end_layout + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +static boolean okayToOverwrite(String file) { +\end_layout + +\begin_layout Plain Layout + + String answer = System.console().readLine("overwrite %s (yes/no)? ", file); +\end_layout + +\begin_layout Plain Layout + + return (answer.equalsIgnoreCase("y") || answer.equalsIgnoreCase("yes")); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +Scanner类 +\begin_inset CommandInset label +LatexCommand label +name "sec:Scanner类" + +\end_inset + + +\end_layout + +\begin_layout Standard +从 +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:从键盘输入数据" + +\end_inset + +一节的描述可以看出,Java在处理键盘输入数据时实在不够友好,于是从Java 1.5开始增加了一个工具类Scanner简化从键盘输入数据的处理。Scanner类也 +是从InputStream接受数据,但是可以根据模式匹配的方法直接将二进制数据转换为相应的基本数据类型。具体的说,Scanner会自动根据分隔符(默认为空白字符 +,包括空格符、回车符、换行符、制表符)从输入数据中分离出一个个字符串(称为token),并转换为要求的整数、实数或者字符串等,从而方便的实现了在同一行读入多个不 +同类型的数据。 +\end_layout + +\begin_layout Standard +Scanner类的常用方法如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Scanner类的常用方法" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public byte nextByte() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读入下一个字节(byte) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public short nextShort() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读入下一个短整数(short) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public int nextInt() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读入下一个整数(int) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public long nextLong() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读入下一个长整数(long) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public float nextFloat() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读入下一个单精度浮点数(float) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public double nextDouble() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读入下一个双精度浮点数(double) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public boolean hasNext() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +是否存在可读的数据? +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public String next() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读入下一个token(即空白字符隔开的独立的字符串) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public String nextLine() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读入下一行 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public Scanner useDelimiter(Pattern pattern) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +使用自定义的token分隔符 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +应该增加一个token的用法示例 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Scanner类的常用方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:Scanner类的常用方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +从键盘输入两个整数,计算其乘积并输出 +\begin_inset CommandInset label +LatexCommand label +name "exa:从键盘输入两个整数,计算其乘积并输出。" + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "Multiply.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/MultiplyTest.java" +lstparams "caption={Multiply.java},label={Multiply.java}" + +\end_inset + + +\end_layout + +\begin_layout Exercise +使用BufferedReader改写 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:从键盘输入两个整数,计算其乘积并输出。" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +使用Scanner读取文件“双城记.txt”,统计该小说有多少个单词 +\begin_inset Foot +status open + +\begin_layout Plain Layout +双城记文本下载地址: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://archive.org/stream/ataleoftwocities00098gut/98.txt +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +? +\end_layout + +\begin_layout Section +*文件操作 +\begin_inset CommandInset label +LatexCommand label +name "sec:文件操作" + +\end_inset + + +\end_layout + +\begin_layout Subsection +什么是Path? +\end_layout + +\begin_layout Standard +在新的文件操作API +\begin_inset Foot +status open + +\begin_layout Plain Layout +JDK 1.7引入了新的文件操作API,即NIO.2,本节内容着重于NIO.2,不再涉及旧的文件API。 +\end_layout + +\end_inset + +中,Path的概念至关重要,类Path是文件操作的入口。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这里简要说明Path的功能 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +无论是Windows操作系统还是Linux操作系统,文件系统都是树状结构的。典型的文件系统如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:目录树示意图" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/linux-directory-tree.eps + width 45line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Linux系统目录树 +\begin_inset CommandInset label +LatexCommand label +name "fig:Linux系统目录树" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\align left +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/windows-directory-tree.eps + width 45line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Windows系统目录树 +\begin_inset CommandInset label +LatexCommand label +name "fig:Windows系统目录树" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +目录树示意图 +\begin_inset CommandInset label +LatexCommand label +name "fig:目录树示意图" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +myfile.txt的路径(Path)在Linux系统表示为: +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +/home/lisi/myfile.txt +\end_layout + +\end_inset + +;而在Windows系统下myfile.txt的路径(Path)表示为: +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +c: +\backslash +users +\backslash +list +\backslash +myfile.txt +\end_layout + +\end_inset + +。这里要特别注意到目录分隔符的区别:Windows操作系统使用反斜杠( +\backslash +) +\begin_inset Foot +status open + +\begin_layout Plain Layout +众所周知,Unix的历史要比Windows久远,Windows的设计从Unix中汲取了很多营养,但是Windows的路径分隔符和Unix系统的路径分隔符截然相反 +,给后来的程序设计带来了一些困扰:你必须正确识别和处理不同操作系统的路径分隔符。你一定会想,要是当初微软在设计Windows的时候使用和Unix相同的路径分隔符 +,该多好!历史没有如果,现实如此残酷!欲知当初微软选择反斜杠作为文件分隔符的原因,请参考:https://blogs.msdn.microsoft.com/larry +osterman/2005/06/24/why-is-the-dos-path-character/。简单的说,Windows操作系统脱胎于Dos操作系统,在D +os操作系统中斜杠(/)已经作为命令行参数的分隔符了,因此Windows只好选用其他的分隔符(反斜杠)作为文件路径分隔符。 +\end_layout + +\end_inset + +作为目录分隔符,而其他所有操作系统(包括Linux、Unix、MacOS)都使用斜杠(/)作为目录分隔符。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +注意到,路径(Path)不仅仅是目录的意思。实际上,路径(Path)包含了以下几种情况: +\end_layout + +\begin_layout Itemize +纯粹文件名,比如:myfile.txt +\end_layout + +\begin_layout Itemize +纯粹目录,比如:/home/sili +\end_layout + +\begin_layout Itemize +绝对路径+文件名,比如:/home/lisi/myfile.txt +\end_layout + +\begin_layout Itemize +相对路径+文件名,比如:./lisi/myfile.txt +\end_layout + +\begin_layout Plain Layout +以上几种情况都是路径(Path)。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +相对路径和绝对路径 +\end_layout + +\begin_layout Standard +从形式上看,相对路径和绝对路径很容易区分:以目录分隔符(Linux系统使用/,windows系统使用 +\backslash +)为起点的路径是绝对路径,其他形式的路径是相对路径。下面是一些示例,都表示文件myfile.txt: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +# 假设当前位于/ +\end_layout + +\begin_layout Plain Layout +/home/lisi/myfile.txt # 绝对路径 +\end_layout + +\begin_layout Plain Layout +home/lisi/myfile.txt # 相对路径 +\end_layout + +\begin_layout Plain Layout +./home/lisi/myfile.txt # 相对路径,.表示当前目录 +\end_layout + +\begin_layout Plain Layout +# 假设当前位于/home +\end_layout + +\begin_layout Plain Layout +/home/lisi/myfile.txt # 绝对路径 +\end_layout + +\begin_layout Plain Layout +lisi/myfile.txt # 相对路径 +\end_layout + +\begin_layout Plain Layout +./lisi/myfile.txt # 相对路径 +\end_layout + +\begin_layout Plain Layout +# 假设当前位于/usr  +\end_layout + +\begin_layout Plain Layout +/home/lisi/myfile.txt # 绝对路径 +\end_layout + +\begin_layout Plain Layout +../home/lisi/myfile.txt # 相对路径,..表示上一级目录 +\end_layout + +\begin_layout Plain Layout +/home/lisi/../zhangsan/myfile.txt # 绝对路径 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +Path类 +\begin_inset CommandInset label +LatexCommand label +name "subsec:Path类" + +\end_inset + + +\end_layout + +\begin_layout Standard +Path类是Java的新文件API的重点和核心,顾名思义,Path类代表了一个路径,一个Path对象包括了文件名和文件所在的目录,因此Path类中包含了处理文件 +和目录的相关方法。 +\end_layout + +\begin_layout Subsubsection +创建Path对象 +\end_layout + +\begin_layout Standard +利用Paths类(注意和Path类的区别)的get方法可以很方便的创建一个Path对象,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "CreatePathTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/CreatePathTest.java" +lstparams "float,caption={CreatePathTest.java},label={CreatePathTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +在Idea中利用调试功能可以方便的观察所创建的Path对象,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:在Ideal中通过调试观察Path对象" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/create-path-debug.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +在Ideal中通过调试观察Path对象 +\begin_inset CommandInset label +LatexCommand label +name "fig:在Ideal中通过调试观察Path对象" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +获取Path信息 +\end_layout + +\begin_layout Standard +Path对象的主要信息是目录分隔符隔开的一个字符串数组,可以通过getName方法返回这个数组的每个元素 +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见本系列教程的“提高篇”,结合lambda表达式操作这个数组更方便,比如: +\end_layout + +\begin_layout Plain Layout +Path path = Paths.get( +\begin_inset Quotes eld +\end_inset + +/home/subaochen/test.txt +\begin_inset Quotes erd +\end_inset + +); +\end_layout + +\begin_layout Plain Layout +path.forEach(p -> System.out.println(p)); +\end_layout + +\end_inset + +,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PathInfoTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathInfoTest.java" +lstparams "float,caption={PathInfoTest.java},label={PathInfoTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PathInfoTest.java" + +\end_inset + +中涉及的主要方法的用法参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "tab:Path信息相关方法" + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +String toString() +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +路径的字符串表达,自动根据不同操作系统使用了不同的目录分隔符 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Path getFileName() +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +路径中的最“远”对象,即Path路径数组的最后一个元素,可能是真实的文件名,也可能是一个子目录名。注意,getFileName方法的返回值是Path,因此打印g +etFileName实际上会调用返回的Path对象的toString方法。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Path getName(int index) +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +返回Path数组的第index个元素。路径中的第一个元素index为0,最后一个元素的index为count-1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +int getNameCount() +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +返回Path中的元素个数 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Path subpath(int beginIndex, int endIndex) +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +非常类似于String类的subString的用法,返回Path中的一部分信息。beginIndex和endIndex分别指定起始index和终止Index。注 +意到,endIndex处的元素不包含在返回的Path中。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Path getParent() +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +当前Path对象的上一级Path,大部分情况下,getParent相当于subpath(0,getNameCount() -1),即将Path数组最后一个元素去 +掉即为上一级Path。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Path getRoot() +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +返回根路径。如果是相对路径,则返回null。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Path信息相关方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:Path信息相关方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +Path转换 +\end_layout + +\begin_layout Standard +Path转换主要通过 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "tab:Path转换方法" + +\end_inset + +中的3个方法实现的。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +URI toUri() +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +使用 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Uri +\end_layout + +\end_inset + +方式描述路径。对于本地文件(文件系统)使用file协议,因此URI的形式如file:///path-to-file +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Path toAbsolutePath() +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +返回绝对路径,这对于了解文件在文件系统的位置很有帮助 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Path toRealPath(LinkOption... + options) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +返回真实的文件路径。该方法会检测文件是否存在,也是唯一一个检测文件是否存在的Path方法。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +really? +\end_layout + +\end_inset + +参数options决定了如何处理符号链接。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Path转换方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:Path转换方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PathConversionTest.java" + +\end_inset + +演示了Path转换的三种情况。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathConversionTest.java" +lstparams "float,caption={PathConversionTest.java},label={PathConversionTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +拼接Path +\end_layout + +\begin_layout Standard +Path类的resolve方法可以拼接路径,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PathResolveTest.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathResolveTest.java" +lstparams "float,caption={PathResolveTest.java},label={PathResolveTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +需要注意的是,如果resolve的参数是一个绝对路径,则拼接的结果只是返回参数中的绝对路径,因此在resolve中应该避免传入一个绝对路径。 +\end_layout + +\begin_layout Plain Layout +拼接Path的另外一个方法是relativize,请参考JDK的相关文档。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +比较Path +\end_layout + +\begin_layout Standard +比较Path主要是通过3个方法,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "tab:比较两个Path的方法" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +boolean equals(Object otherPath) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +重写了Object.equals方法,比较两个Path对象是否相同:两个Path对象代表的路径相同则两个Path对象相同 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +boolean endsWith(Path other) +\end_layout + +\begin_layout Plain Layout +boolean endsWith(String other) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +判断Path对象是否以给定的Path对象或者路径字符串结尾 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +boolean startsWith(Path other) +\end_layout + +\begin_layout Plain Layout +boolean startsWith(String other) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +判断Path对象是否以给定的Path对象或者路径字符串开头 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +比较两个Path的方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:比较两个Path的方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +比较Path的示例参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PathCompareTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathCompareTest.java" +lstparams "float,caption={PathCompareTest.java},label={PathCompareTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Section +*Files类 +\begin_inset CommandInset label +LatexCommand label +name "sec:*Files类" + +\end_inset + + +\end_layout + +\begin_layout Standard +Files +\begin_inset Foot +status open + +\begin_layout Plain Layout +你可能会迷惑,为什么不命名为File类呢?很遗憾的是,File类是旧的(JDK 1.7之前)的Java文件操作API中的文件操作类,新的文件操作类只好叫做File +s了。通常,以单数命名的类用来表示一类事物,复数命名的类是工具辅助类类,比如Path表征路径,Paths是路径的工具辅助类。因此Files并不是一个很好的类的命 +名,这也是Java API无奈的选择。 +\end_layout + +\end_inset + +类是Java文件操作新API(java.nio.file包)中文件操作的核心类。相对于Path类,Files类聚焦于文件相关的操作: +\begin_inset Note Note +status open + +\begin_layout Plain Layout +进一步概括说明Files类的功能 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +检查文件或者目录 +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:Path类" + +\end_inset + +中我们看到,Path类的大多数方法不会检查文件或者目录是否存在,换句话说,Path中的大多数方法只是对给定的路径进行语法上的检查和操作。Files类的exist +s和notExists方法可以用来检查一个Path对象是否存在于实际的文件系统中,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "PathExistTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathExistTest.java" +lstparams "float,caption={PathExistTest.java},label={PathExistTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +exists返回false可能存在两种情况: +\end_layout + +\begin_layout Enumerate +文件或者目录不存在; +\end_layout + +\begin_layout Enumerate +文件或者目录不可见,即当前用户没有权限查看该文件或者目录。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +我们可以使用isReadable、isWritable、isExecutable进一步检查文件是否可读、可写、可执行,比如下面的代码片段: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +Path file = ...; +\end_layout + +\begin_layout Plain Layout + +boolean isRegularExecutableFile = Files.isRegularFile(file) & +\end_layout + +\begin_layout Plain Layout + + Files.isReadable(file) & Files.isExecutable(file); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +删除文件或者目录 +\end_layout + +\begin_layout Standard +Files.delete方法删除文件或者目录。需要注意的是,如果要删除的是目录,则目录必须是空的,否则删除失败。示例代码参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PathDeleteTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathDeleteTest.java" +lstparams "float,caption={PathDeleteTest.java},label={PathDeleteTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Subsection +复制文件或者目录 +\end_layout + +\begin_layout Standard +Files.copy方法可以复制文件或者目录。默认情况下,copy方法不会覆盖目的文件,但是可以通过传递CopyOption参数影响复制的过程: +\end_layout + +\begin_layout Itemize +REPLACE_EXISTING:覆盖目的文件。 +\end_layout + +\begin_layout Itemize +COPY_ATTRIBUTES:也复制文件属性到目的文件。如果不设置此选项,只是复制文件本身,文件属性取决于目的目录的设置。 +\end_layout + +\begin_layout Itemize +NOFOLLOW_LINKS:复制符号链接而非符号链接指向的文件。 +\end_layout + +\begin_layout Standard +示例程序参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "PathCopyTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathCopyTest.java" +lstparams "caption={PathCopyTest.java},label={PathCopyTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +Files.copy也支持复制文件到流,或者从流复制到文件: +\end_layout + +\begin_layout Itemize +copy(InputStream, Path, CopyOption...options) +\end_layout + +\begin_layout Itemize +copy(Path, OutputStream) +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +移动文件或者目录 +\end_layout + +\begin_layout Standard +Files.move可以移动文件或者目录,文件或者目录改名也是要通过move方法,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PathMoveTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathMoveTest.java" +lstparams "caption={PathMoveTest.java},label={PathMoveTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Subsection +操作文件或者目录的属性 +\end_layout + +\begin_layout Standard +我们经常见到元数据(metadata)这个说法。简单的说,元数据是描述数据的数据,或者说,一类事物的元数据描述了一类事物的属性。对照面向对象的概念我们可以看出, +元数据非常像类的属性。Java提供了一组读取或者设置文件属性的方法,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:File操作文件属性的方法" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +文件大小 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +public static long size(Path path) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +获取文件的大小(字节数) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +创建时间 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +没有提供直接的方法获取文件的创建时间,需要首先获取BasicFileAttributeView,然后解析creationTime,比如: +\end_layout + +\begin_layout Plain Layout +Path file = ...; +\end_layout + +\begin_layout Plain Layout +BasicFileAttributes attr = Files.readAttributes(file, BasicFileAttributes.class); +\end_layout + +\begin_layout Plain Layout +System.out.println("creationTime: " + attr.creationTime()); +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +最后修改时间 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +public static FileTime getLastModifiedTime(Path path, LinkOption... + options) throws IOException +\end_layout + +\begin_layout Plain Layout +public static Path setLastModifiedTime(Path path, FileTime time) throws + IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读取和设置文件的最后修改时间。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +属主 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +public static UserPrincipal getOwner(Path path, LinkOption... + options) throws IOException +\end_layout + +\begin_layout Plain Layout +public static Path setOwner(Path path, UserPrincipal owner) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读取或者设置文件的属主 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +所属组 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +没有提供相应的方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +访问控制属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +public static Set getPosixFilePermissions(Path path, + LinkOption... + options) throws IOException +\end_layout + +\begin_layout Plain Layout +public static Path setPosixFilePermissions(Path path, Set + perms) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读取或者设置文件的访问控制属性 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +是否目录 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +public static boolean isDirectory(Path path, LinkOption... + options) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +判断给定的Path是否目录 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +是否普通文件 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +public static boolean isRegularFile(Path path, LinkOption... + options) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +判断给定的Path是否普通文件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +是否符号连接 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +public static boolean isSymbolicLink(Path path) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +判断给定的Path是否符号链接 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +是否隐藏文件 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +public static boolean isHidden(Path path) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +判断给定的Path是否隐藏文件。注意到,Windows和Linux判断隐藏文件的方法是不同的,Linux的隐藏文件以 +\begin_inset Quotes erd +\end_inset + +. +\begin_inset Quotes erd +\end_inset + +开头,而Windows的隐藏文件设置了“隐藏”属性。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +File操作文件属性的方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:File操作文件属性的方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +利用 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:File操作文件属性的方法" + +\end_inset + +中的方法,一次只能读取或者设置一个文件属性,如果要同时读取或者设置多个文件属性显然比较低效,因此Java提供了批量读取或者设置文件属性的方法,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:批量读取文件属性的方法" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static Map readAttributes(Path path, String attributes, + LinkOption... + options) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +批量读取文件属性,参数attributes给出了所要读取的属性列表,*表示所有属性。属性名称和FileAttributes各子类的属性字段定义相同,参见 +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://docs.oracle.com/javase/8/docs/api/java/nio/file/attribute/FileAttributeVie +w.html +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static A readAttributes(Path path, + Class type, LinkOption... + options) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +批量读取文件属性,参数type是BasicFileAttributes的子类,返回结果和请求参数type相同。此方法更加“面向对象”一些,在IDE的帮助下不容易 +出错,因此建议采用此方法批量读取文件属性。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +批量读取文件属性的方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:批量读取文件属性的方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + +不同操作系统的文件系统存在不小的差别,文件和目录的属性也各不相同,Java为了能够隐藏这些差异和细节,将文件和目录的属性做了进一步的封装,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:文件属性接口" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/fileattributes.eps + lyxscale 300 + width 60col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +文件属性接口 +\begin_inset CommandInset label +LatexCommand label +name "fig:文件属性接口" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +BasicFileAttributes及其子接口只是定义了读取文件属性的方法,如何更新(修改)文件属性呢?Java进一步封装了在各种情况下操作文件属性的Attr +ibuteView类,即可以读取文件属性,也可以更新文件属性,同时屏蔽了不同操作系统的差异,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:读取和设置文件属性的View接口" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/FileAttributeView.eps + lyxscale 300 + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +读取和设置文件属性的View接口 +\begin_inset CommandInset label +LatexCommand label +name "fig:读取和设置文件属性的View接口" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +FileAttribes和FileAttributeView的区别,感觉没说清楚? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +读取文件属性,包括:文件大小、最后修改时间、是否普通文件等。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PathMetadataTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathMetadataTest.java" +lstparams "caption={PathMetadataTest.java},label={PathMetadataTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +在Idea中运行结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +creationTime: 2016-12-12T02:49:04Z +\end_layout + +\begin_layout Plain Layout +lastAccessTime: 2016-12-12T02:51:47Z +\end_layout + +\begin_layout Plain Layout +lastModifiedTime: 2016-12-12T02:49:04Z +\end_layout + +\begin_layout Plain Layout +isDirectory: false +\end_layout + +\begin_layout Plain Layout +isOther: false +\end_layout + +\begin_layout Plain Layout +isRegularFile: true +\end_layout + +\begin_layout Plain Layout +isSymbolicLink: false +\end_layout + +\begin_layout Plain Layout +size: 0 +\end_layout + +\begin_layout Plain Layout +now lastModifiedTime is:2016-12-13T23:54:11Z +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Standard +使用 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:File操作文件属性的方法" + +\end_inset + +中的方法一次只能读取或者设置一个文件的属性,因此如果要一次读取或者设置多个文件属性的话,建议使用readAttributes方法较为高效。 +\end_layout + +\begin_layout Subsection +创建、读写文件 +\end_layout + +\begin_layout Subsubsection +读写小文件 +\begin_inset CommandInset label +LatexCommand label +name "subsec:读写小文件" + +\end_inset + + +\end_layout + +\begin_layout Standard +Files类为读写小文件 +\begin_inset Foot +status open + +\begin_layout Plain Layout +多小的文件算是小文件?因为readAllBytes是把文件全部内容读到一个byte数组中,因此文件的尺寸取决于你的内存多少。但是,并不是所有的内存都可以用来保存 +文件内容的,因此使用这里的方法时要考虑到能够处理的文件的最大尺寸限制。 +\end_layout + +\end_inset + +提供了方便的write和readAllBytes方法,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:读写小文件的方便方法" + +\end_inset + +。可以看出, +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:读写小文件的方便方法" + +\end_inset + +中的方法不需要和输入输出流直接打交道。实际上,Files类的方法是对输入输出流的进一步封装,比如readAllBytes方法 +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见openjdk的jdk/src/java.base/share/classes/java/nio/file/Files.java +\end_layout + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + public static byte[] readAllBytes(Path path) throws IOException { + +\end_layout + +\begin_layout Plain Layout + + try (SeekableByteChannel sbc = Files.newByteChannel(path); +\end_layout + +\begin_layout Plain Layout + + InputStream in = Channels.newInputStream(sbc)) { +\end_layout + +\begin_layout Plain Layout + + long size = sbc.size(); +\end_layout + +\begin_layout Plain Layout + + if (size > (long)MAX_BUFFER_SIZE) +\end_layout + +\begin_layout Plain Layout + + throw new OutOfMemoryError("Required array size too large"); +\end_layout + +\begin_layout Plain Layout + + +\end_layout + +\begin_layout Plain Layout + + return read(in, (int)size); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static Path write(Path path, byte[] bytes, OpenOption... + options) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +将bytes数组写入到文件path中。OpenOption在StandardOpenOption这个Enum中定义: +\end_layout + +\begin_layout Itemize +READ:为读打开文件 +\end_layout + +\begin_layout Itemize +WRITE:为写打开文件 +\end_layout + +\begin_layout Itemize +APPEND:如果可写则追加写入内容到文件末尾 +\end_layout + +\begin_layout Itemize +CREATE:如果文件不存在则创建 +\end_layout + +\begin_layout Itemize +CREATE_NEW:创建新文件;如果文件已经存在则失败,优先级高于CREATE +\end_layout + +\begin_layout Itemize +TRUNCATE_EXISTING:如果文件可写并且已经存在则截断文件尺寸为0 +\end_layout + +\begin_layout Itemize +DELETE_ON_CLOSE:文件操作结束(close)后自动删除文件,这对于临时文件很有用 +\end_layout + +\begin_layout Itemize +DSYNC:自动同步文件的内容到存储介质 +\end_layout + +\begin_layout Itemize +SYNC:自动同步文件的内容和原信息到存储介质 +\end_layout + +\begin_layout Itemize +SPARSE:创建稀疏文件 +\begin_inset Foot +status open + +\begin_layout Plain Layout +稀疏文件是指创建文件的时候并不真正分配空间,只有真正写入文件的时候才逐步分配空间。 +\end_layout + +\end_inset + +,如果文件系统支持的话 +\end_layout + +\begin_layout Plain Layout +默认是CREATE, TRUNCATE_EXISTING和WRITE,即如果文件不存在则创建,如果文件已存在则截断长度为0。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static Path write(Path path, Iterable lines, + Charset cs, OpenOption... + options) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +将文本lines写入文件path中。lines以System.getProperty( +\begin_inset Quotes eld +\end_inset + +line.separator +\begin_inset Quotes erd +\end_inset + +)为行分隔符,并使用给定的(cs)编码 +\begin_inset Foot +status open + +\begin_layout Plain Layout +Java 1.7之后引入了StandCharsets类定义了常见的编码方式,参见:https://docs.oracle.com/javase/8/docs/api/ +java/nio/charset/StandardCharsets.html +\end_layout + +\end_inset + +为byte数组。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static byte[] readAllBytes(Path path) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从path读取所有内容到byte数组。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static List readAllLines(Path path) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读文件path的所有行到List中,行分隔符为 +\backslash +r +\backslash +n(windows下)或 +\backslash +r(Mac下)或 +\backslash +n(Linux下)。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static List readAllLines(Path path, Charset cs) throws IOExceptio +n +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +读文件path的所有行到List中,并使用cs编码将byte解码为字符串。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +读写小文件的方便方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:读写小文件的方便方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Example +读写小文件 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "PathCreateTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathCreateTest.java" +lstparams "caption={PathCreateTest.java},label={PathCreateTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +在Idea中运行结果如下,只是简单的输出了文件的内容: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +test string +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Subsubsection +带缓存的文本文件处理方法 +\end_layout + +\begin_layout Standard +处理文本文件时,通常需要借助于缓存提高效率,我们在 +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:面向字符的流" + +\end_inset + +中已经讨论过。Files类提供了如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "tab:Files中带缓存的文本读写方法" + +\end_inset + +的方法更进一步简化了文本文件的处理。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static BufferedWriter newBufferedWriter(Path path, OpenOption... + options) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从path创建一个BufferedReader用于读取文件内容,使用UTF-8解码。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static BufferedReader newBufferedReader(Path path, Charset cs) throws + IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从path创建一个BufferedReader用于读取文件内容,文件内容以cs方式解码,默认使用UTF-8解码。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static BufferedWriter newBufferedWriter(Path path, OpenOption... + options) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从path创建一个BufferedWriter用于写入文件内容,使用UTF-8编码。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static BufferedWriter newBufferedWriter(Path path, Charset cs, OpenOption... + options) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从path创建一个BufferedWriter用于写入文件内容,文件内容以cs方式编码,默认使用UTF-8编码。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Files中带缓存的文本读写方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:Files中带缓存的文本读写方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +下面的代码片段演示了newBufferedReader的用法: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +Charset charset = Charset.forName("UTF-8");// or Charset charset = StandCharsets.U +TF-8; +\end_layout + +\begin_layout Plain Layout + +try (BufferedReader reader = Files.newBufferedReader(file, charset)) { +\end_layout + +\begin_layout Plain Layout + + String line = null; +\end_layout + +\begin_layout Plain Layout + + while ((line = reader.readLine()) != null) { +\end_layout + +\begin_layout Plain Layout + + System.out.println(line); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} catch (IOException x) { +\end_layout + +\begin_layout Plain Layout + + System.err.format("IOException: %s%n", x); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +等价于下面的代码片段(如果文件是UTF-8编码的话): +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +try (BufferedReader reader = Files.newBufferedReader(file)) { +\end_layout + +\begin_layout Plain Layout + + String line = null; +\end_layout + +\begin_layout Plain Layout + + while ((line = reader.readLine()) != null) { +\end_layout + +\begin_layout Plain Layout + + System.out.println(line); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} catch (IOException x) { +\end_layout + +\begin_layout Plain Layout + + System.err.format("IOException: %s%n", x); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +使用不带缓存的输入输出流 +\end_layout + +\begin_layout Standard +Files同样封装了不带缓存的输入输出流,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "tab:Files中不带缓存的输入输出流" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static InputStream newInputStream(Path path, OpenOption... + options) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从path创建一个InputStream用于读取文件内容 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static OutputStream newOutputStream(Path path, OpenOption... + options) throws IOException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从path创建一个OutputStream用于写入文件内容 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Files中不带缓存的输入输出流 +\begin_inset CommandInset label +LatexCommand label +name "tab:Files中不带缓存的输入输出流" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +Files对不带缓存的输入流的封装 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PathWithoutBufferTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PathWithoutBufferTest.java" +lstparams "caption={PathWithoutBufferTest.java},label={PathWithoutBufferTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +在Idea中运行的结果如下(简单的打印出了之前写入的内容): +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Hello World! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Standard +newInputStream返回一个不带缓存的输入流,但是这个例子又根据这个不带缓存的输入流构造了一个BufferedReader以便以行的方式读入文本。你可能 +会问,为什么不直接使用带缓存的newBufferedReader方法呢?是的,在这个例子中,使用newBufferedReader直接返回一个BufferedR +eader更方便,本例只是演示如何构造一个不带缓存的输入流。 +\end_layout + +\begin_layout Subsubsection +channel方式读写文件 +\begin_inset CommandInset label +LatexCommand label +name "subsec:channel方式读写文件" + +\end_inset + + +\end_layout + +\begin_layout Standard +流(stream)是按照字节为单位读写文件的,channel +\begin_inset Note Note +status open + +\begin_layout Plain Layout +如何翻译?通道? +\end_layout + +\end_inset + +是按照缓冲区为单位读写文件的,也就是说,channel是自然带缓冲的,可以一次处理一个缓冲区。SeekableByteChannel内部维护着一个表示当前位置的 +指针,通过移动该指针可以实现随机文件读写,参见 +\begin_inset CommandInset ref +LatexCommand formatted +reference "subsec:随机读写文件" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +Files类的Channel读写文件方法见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Files类的Channel读写文件方法" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +public static SeekableByteChannel newByteChannel(Path path, OpenOption... + options) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从path创建一个 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +SeekableByteChannel +\end_layout + +\end_inset + +用于读写文件内容,默认是只读打开Channel的。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +public static SeekableByteChannel newByteChannel(Path path, Set options, FileAttribute... + attrs) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从path创建一个 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +SeekableByteChannel +\end_layout + +\end_inset + +用于读写文件内容,attrs设置文件的属性。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Files类的Channel读写文件方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:Files类的Channel读写文件方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +使用Channel读写文件 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "FileRandomAccessTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/FileChannelTest.java" +lstparams "caption={FileChannelTest.java},label={FileChannelTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +打印出myfile.txt的内容,不再列出。 +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Standard +和Stream不同,使用Channel读写文件的要点是一次处理一个buffer,因此如何使用Buffer就称为用好Channel的关键。可以借助于Java的Bu +ffer类,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:Buffer的类层次结构" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/buffer.eps + lyxscale 200 + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Caption Standard + +\begin_layout Plain Layout +Buffer的类层次结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:Buffer的类层次结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +下面的讨论以ByteBuffer为例,其他类型的Buffer用法类似。 +\end_layout + +\begin_layout Standard +ByteBuffer实际上是一块可以写入和读取数据的内存,Java提供了若干方便的方法操作这块内存,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:ByteBuffer的用法" + +\end_inset + +,我们假设创建了一个大小为8个字节的ByteBuffer。要理解ByteBuffer的用法,需要首先理解ByteBuffer的三个基本属性: +\end_layout + +\begin_layout Itemize +capacity:ByteBuffer的大小,即占用多少个字节的内存空间。每个ByteBuffer在创建时需要指定capacity,一旦设定不允许改变,这里ca +pacity=8。 +\end_layout + +\begin_layout Itemize +limit:下一次读或者写允许操作的字节数。在写模式下,limit表示当前最多能够向Buffer写多少数据。在读模式下,limit表示当前最多能够读到多少数据。 +\end_layout + +\begin_layout Itemize +position:下一个可以读或者写的字节的位置索引,position的最大值为capacity - 1。在写模式下,position的初始值为0,当写入数据( +字节)后,position移动到下一个可写入的位置,比如在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:ByteBuffer的用法" + +\end_inset + +中,在写入3个字节的数据后,当前position=3。如果此时切换这个ByteBuffer到读模式,则position需要指向下一个可读的字节位置,显然应该将p +osition置为0,limit置为3(即当前position的值),即从Buffer的开头开始能够一次读3个字节的数据,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:ByteBuffer的用法" + +\end_inset + +的“读模式”所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/buffer-usage.eps + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +ByteBuffer的用法 +\begin_inset CommandInset label +LatexCommand label +name "fig:ByteBuffer的用法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Buffer通过flip方法从写模式切换到读模式,通常对Buffer的操作流程为: +\end_layout + +\begin_layout Enumerate +写入数据到Buffer,在这里是通过Channel的read方法写入数据到Buffer,也可以通过Buffer提供的各种put方法写入数据。 +\end_layout + +\begin_layout Enumerate +调用flip方法切换到读模式。 +\end_layout + +\begin_layout Enumerate +从Buffer中读取数据。 +\end_layout + +\begin_layout Enumerate +调用clear或者compact方法清空缓冲区。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +使用Idea可以方便的观察和学习Buffer中capacity、limit、position的变化情况,如下图所示。 +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/buffer-idea-debug.png + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +读写文件的方法很多,何时使用InputStream/OutputStream/InputReader/OutputReader,何时使用Files方法读写文件? +一般的原则是什么? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +创建文件和临时文件 +\end_layout + +\begin_layout Standard +Files也提供了创建文件和临时文件的方便API,见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Files创建文件和临时文件的方法" + +\end_inset + +。createFile和createTempFile被设计为“原子操作”,即首先检查文件是否存在(存在则抛出异常),然后创建一个空文件病设置为指定或者默认的属性 +,因此createFile的安全性要比其他方法高些。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +其他方法是哪些方法?stream?Channel?是否可以对比说明? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +public static Path createFile(Path path, FileAttribute... + attrs) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据path创建属性为attrs的文件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +public static Path createTempFile(Path dir, String prefix, String suffix, + FileAttribute... + attrs) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据dir创建属性为attrs的临时文件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +public static Path createTempFile(String prefix, String suffix, FileAttribute... + attrs) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据dir创建属性为attrs的临时文件 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Files创建文件和临时文件的方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:Files创建文件和临时文件的方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +使用createFile创建文件 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "FileCreateTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/FileCreateTest.java" +lstparams "caption={FileCreateTest.java},label={FileCreateTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行应用程序后检查所创建文件的属性如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +~/test$ ls -l testcreate.txt +\end_layout + +\begin_layout Plain Layout +-rw-rw-r-- 1 subaochen subaochen 0 12月 16 08:20 testcreate.txt +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Standard +createFile时如果没有给出文件属性则默认创建664属性的文件,即用户自己、所属组都可读写,其他所有人均只读。可以通过给出FileAttribute灵活设 +置属性,比如下面的代码片段设置为只对用户自己可读写: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +Path file = ...; +\end_layout + +\begin_layout Plain Layout + +Set perms = +\end_layout + +\begin_layout Plain Layout + + PosixFilePermissions.fromString("rw-------"); +\end_layout + +\begin_layout Plain Layout + +FileAttribute> attr = +\end_layout + +\begin_layout Plain Layout + + PosixFilePermissions.asFileAttribute(perms); +\end_layout + +\begin_layout Plain Layout + +Files.createFile(file, attr); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +编写程序,在/tmp创建一个临时文件temp.log,并观察此临时文件的属性 +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +编写程序,创建一个对所有人只读的文件,并验证所创建文件的属性 +\end_layout + +\begin_layout Subsection +随机读写文件 +\begin_inset CommandInset label +LatexCommand label +name "subsec:随机读写文件" + +\end_inset + + +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:读写小文件" + +\end_inset + +中其实我们已经看到,SeekableByteChannel已经具有随机读写文件的能力了:SeekableByteChannel的下列方法帮助我们确定读写的起始位 +置和数量: +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +long position() throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +返回文件的当前位置,即读和写的起始位置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +SeekableByteChannel position(long newPosition) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +设置Channel的当前位置,返回这个Channel(便于函数式编程) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +long size() throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +返回这个Channel的大小 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +SeekableByteChannel truncate(long size) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +截断这个Channel到给定的大小 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +int read(ByteBuffer dst) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +从Channel读数据到dst +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +int write(ByteBuffer src) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +将dst的数据写入Channel +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +SeekableByteChannel的随机读写方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:SeekableByteChannel的随机读写方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +为了更方便的操作文件,JDK提供了对SeekableByteChannel的进一步封装:FileChannel,除SeekableByteChannel中的方法 +外,FileChannel增加了一些高级特性,比如可以将文件的指定区域映射到内存中以便快速访问,锁定文件的指定区域(不允许其他线程进行操作),从任意位置直接读写 +文件等。我们有两种方式获取一个FileChannel: +\end_layout + +\begin_layout Enumerate +通过Path.newByteChannel获得一个SeekableByteChannel,然后强制类型转换为FileChannel。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这种类型转换安全吗? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Enumerate +通过FileInputStream.getChannel获取一个FileChannel。 +\end_layout + +\begin_layout Enumerate +通过FileChannel.open方法直接获得一个FileChannel。推荐采用此种方式。 +\end_layout + +\begin_layout Example +使用FileChannel读写文件,假设文件myfile.txt原来有如下的内容: +\end_layout + +\begin_layout Example +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Java programming language is good! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "FileRandomAccessTest.java" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/FileRandomAccessTest.java" +lstparams "caption={FileRandomAccessTest.java},label={FileRandomAccessTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph +运行结果 +\end_layout + +\begin_layout Standard +在Idea中运行结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +I was here! +\end_layout + +\begin_layout Plain Layout +ming language is good!Java programI was here! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,在文件的开头写入了 +\begin_inset Quotes erd +\end_inset + +I was here! +\backslash +n +\begin_inset Quotes erd +\end_inset + +,然后把文件开头原先的 +\begin_inset Quotes erd +\end_inset + +Java program +\begin_inset Quotes erd +\end_inset + +移动到了文件的最后,并在最后追加了 +\begin_inset Quotes erd +\end_inset + +I was here! +\backslash +n +\begin_inset Quotes erd +\end_inset + +。 +\end_layout + +\begin_layout Standard +本程序可以反复运行,结果完全一致。 +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Standard +FileChannel提供的文件随机读写概念,重要的是理解两个position的用法: +\end_layout + +\begin_layout Itemize +FileChannel的position,用于确定从什么地方开始读写文件; +\end_layout + +\begin_layout Itemize +ByteBuffer的position,用于确定从什么地方开始读写ByteBuffer; +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +FileChannel、InputStream/OutputStream、ByteBuffer之间的关系和用法可以形象的用下图表示: +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/io/file-channel-stream-buffer.eps + width 90col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +简单的说,ByteBuffer处于“中心”的位置,无论是从文件系统、网络读入的数据,还是准备写入文件系统、网络的数据,都是通过ByteBuffer的。因此,其他 +数据类型如何转换为ByteBuffer以及ByteBuffer如何转换为其他数据类型就显得非常重要,上图的大部分篇幅展示了这种相互转换的方法。 +\end_layout + +\begin_layout Plain Layout +我们可以看出,ByteBuffer转换为其他数据类型已经非常方便了,但是从其他数据类型转换为ByteBuffer的通道却不是很流畅,比如从short[]转换为一 +个ByteBuffer,目前没有直接的方法,只能通过遍历这个short数组,然后将数组的每个元素放入ByteBuffer这种稍微曲折的方法: +\end_layout + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +ByteBuffer bb; +\end_layout + +\begin_layout Plain Layout + +... +\end_layout + +\begin_layout Plain Layout + +for(short s:short_array) { +\end_layout + +\begin_layout Plain Layout + + bb.putShort(s); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +相信JDK的未来版本会提供更丰富和合理的ByteBuffer和其他数据类型的相互转换方法。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +目录操作 +\end_layout + +\begin_layout Standard +目录是一种特殊的文件,我们前面介绍的很多API(所有接受Path作为参数的API)即可以操作文件,也可操作目录。但是毕竟目录的操作有其特殊性,比如下面的情形: +\end_layout + +\begin_layout Itemize +创建一个空目录 +\end_layout + +\begin_layout Itemize +列出目录下的所有子目录 +\end_layout + +\begin_layout Itemize +列出目录下的所有文件 +\end_layout + +\begin_layout Itemize +根据给定的规则列出目录下的文件和目录 +\end_layout + +\begin_layout Standard +JDK的Files类同样给出了目录操作的方便方法,分述如下。 +\end_layout + +\begin_layout Subsubsection +创建目录 +\end_layout + +\begin_layout Standard +Files类创建目录主要是两个方法,createDirectory用于创建一级目录,createDirectories用于创建多级目录,见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:创建目录的方法" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +public static Path createDirectory(Path dir, FileAttribute... + attrs) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据dir和attrs创建一个目录。如果没有attrs参数则创建默认属性的目录。如果目录已经存在则抛出FileAlreadyExistsException异常。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +public static Path createDirectories(Path dir, FileAttribute... + attrs) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据dir创建多级目录 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +创建目录的方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:创建目录的方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +创建目录 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "CreateDirectoryTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/CreateDirectoryTest.java" +lstparams "caption={CreateDirectoryTest.java},label={CreateDirectoryTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Standard +第一次运行时终端没有任何显示,但是当我们去往test目录查看时,应该可以看到test目录下面多了一个新目录a。 +\end_layout + +\begin_layout Standard +当第二次运行该程序时,终端显示: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +java.nio.file.FileAlreadyExistsException: /home/subaochen/test/a +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,如果dir目录已经存在,则createDirectory方法抛出FileAlreadyExistsException异常。 +\end_layout + +\begin_layout Standard +我们删除a目录,但是创建一个文件名字叫做a,即在test目录执行下列命令: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +~/test$ rmdir a; touch a +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +再次执行本程序,终端显示: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +java.nio.file.FileAlreadyExistsException: /home/subaochen/test/a +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +即,如果要创建的目录和文件重名也是不允许的,同样抛出FileAlreadyExistsException。 +\end_layout + +\begin_layout Exercise +使用Files.createDirectories创建目录test/a/b/c +\end_layout + +\begin_layout Subsubsection +列出目录 +\begin_inset CommandInset label +LatexCommand label +name "subsec:列出目录" + +\end_inset + + +\end_layout + +\begin_layout Standard +Files的newDirectoryStream方法可以很方便的列出目录下的内容,包括子目录、文件、隐藏文件等,但是需要注意的是,newDirectoryStr +eam不是一个递归的过程,即不能深入到当前目录的子目录查找内容。 +\end_layout + +\begin_layout Example +利用newDirectoryStream方法列出当前目录下的文件、子目录等。 +\begin_inset CommandInset label +LatexCommand label +name "exa:列出当前目录下的文件、子目录等。" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "ListDirectoryTest.java" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/ListDirectoryTest.java" +lstparams "caption={ListDirectoryTest.java},label={ListDirectoryTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析和说明 +\end_layout + +\begin_layout Standard +要注意到newDirectoryStream返回的是一个stream,因此和InputStream等用法类似,一定要记得用完后close这个stream。try +-with-resources结构能够自动关闭stream,如果使用try-catch结构,则要在finanlly块中执行stream.close()方法关闭st +ream。 +\end_layout + +\begin_layout Exercise +如何利用newDirectoryStream方法递归的列出当前目录下的内容,包括子目录下的文件及其子目录? +\end_layout + +\begin_layout Subsubsection +根据规则列出目录 +\end_layout + +\begin_layout Standard +newDirectoryStream允许传入Glob +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +appendixname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:什么是Glob?" + +\end_inset + + +\end_layout + +\end_inset + +过滤规则作为参数。 +\end_layout + +\begin_layout Example +列出当前目录下的所有java源代码和java class文件。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "ListDirectoryWithGlobTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/ListDirectoryWithGlobTest.java" +lstparams "caption={ListDirectoryWithGlobTest.java},label={ListDirectoryWithGlobTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计和分析 +\end_layout + +\begin_layout Standard +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:列出当前目录下的文件、子目录等。" + +\end_inset + +相比,我们看到newDirectoryStream方法只是多了一个参数:表明如何过滤本目录下的内容。 +\end_layout + +\begin_layout Subsection +遍历目录:FileVisitor接口 +\end_layout + +\begin_layout Standard +在 +\begin_inset CommandInset ref +LatexCommand formatted +reference "subsec:列出目录" + +\end_inset + +中我们看到了,可以利用Files.newDirectoryStream列出当前目录下的内容,但是newDirectoryStream不是递归处理的,因此Files +类提供了遍历目录的另外方式:使用FileVisitor接口可以更方便的遍历目录。 +\end_layout + +\begin_layout Standard +首先实现FileVisitor接口,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "PrintFiles.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PrintFiles.java" +lstparams "caption={PrintFiles.java},label={PrintFiles.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +然后可以在主类中使用FileVisitor接口遍历目录了,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "WalkFileTreeTest.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/WalkFileTreeTest.java" +lstparams "caption={WalkFileTreeTest.java},label={WalkFileTreeTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +这里的关键是,walkFileTree方法会递归的遍历给定的目录,但是对于递归过程中遇到的每一个项目如何处理呢?我们看到walkFileTree的第二个参数是一 +个实现了FileVisitor接口的对象,这个对象决定了如何处理这些遇到的目录项目,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:FileVisitor接口方法" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs) throws + IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +在访问(操作)目录之前的动作,比如准备将目录复制到另外的目录中等。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +FileVisitResult postVisitDirectory(T dir, IOException exc) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +在访问(操作)目录之后的动作,比如访问目录后可以将目录删除等。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +FileVisitResult visitFile(T file, BasicFileAttributes attrs) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +访问目录中的文件。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +FileVisitResult visitFileFailed(T file, IOException exc) throws IOException +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +如果访问文件失败则调用此方法。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +FileVisitor接口方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:FileVisitor接口方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +*访问属性文件 +\begin_inset CommandInset label +LatexCommand label +name "sec:读写属性文件" + +\end_inset + + +\end_layout + +\begin_layout Standard +属性文件通常用来保存应用程序的配置信息,这样当应用程序的配置改变时,只需要修改属性文件(配置文件)即可,不需要修改应用程序的源代码,维护比较方便。属性文件的内容 +通常是以key、value对的形式出现,即key=value的形式,比如数据库相关的应用程序中通常将数据库服务器的IP地址、用户名、密码等信息保存到如下的属性文 +件中: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +hostname=192.168.1.200 +\end_layout + +\begin_layout Plain Layout +username=postgres +\end_layout + +\begin_layout Plain Layout +password=password +\end_layout + +\begin_layout Plain Layout +database=mydb +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Java的Properties类提供了方便的API读写这样的属性文件。 +\end_layout + +\begin_layout Example +访问属性文件 +\begin_inset CommandInset label +LatexCommand label +name "exa:访问属性文件" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "PropertyFileTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/io/src/cn/edu/sdut/softlab/io/PropertyFileTest.java" +lstparams "caption={PropertyFileTest.java},label={PropertyFileTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行本应用程序结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +hostname=localhost +\end_layout + +\begin_layout Plain Layout +password=password +\end_layout + +\begin_layout Plain Layout +database=mydb +\end_layout + +\begin_layout Plain Layout +username=postgres +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计和分析 +\end_layout + +\begin_layout Standard +本例中,我们使用了FileInputStrem和FileOutputStream构造了一个文件输入输出流,FileInpoutStream和FileOutput +Stream的参数是文件名,注意到该文件名是相对于项目根目录的。 +\end_layout + +\begin_layout Standard +实际上, +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +Java在定位文件时,有如下的几种策略 +\end_layout + +\end_inset + + +\begin_inset Foot +status open + +\begin_layout Plain Layout +参考了: +\end_layout + +\begin_layout Itemize +http://www.cnblogs.com/yinger/archive/2011/09/08/2171831.html +\end_layout + +\begin_layout Itemize +官方教程:https://docs.oracle.com/javase/tutorial/essential/environment/properties.html +\end_layout + +\end_inset + +: +\end_layout + +\begin_layout Itemize +绝对路径:在FileInputStream、FileOutputStream中如果参数的路径使用路径分隔符(windows下是 +\backslash +,Linux下是/)开头则是绝对路径。 +\end_layout + +\begin_layout Itemize +相对于项目的路径:在FileInputStream、FileOutputStream中如果参数的路径没有使用路径分隔符(windows下是 +\backslash +,Linux下是/)开头则是项目于项目根目录的相对路径。 +\end_layout + +\begin_layout Itemize +相对于当前class文件的路径:如果使用Class.getResourceAsStream方法,则获得相对于当前class文件的路径,比如: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +InputStream path = PropertyFileTest.class.getResourceAsStream(database-config.prope +rties); +\end_layout + +\end_inset + +path对象指向的文件database-config.properties和class文件在同一个目录下,即database-config.properties位于 +src/cn/edu/sdut/softlab目录下。 +\begin_inset Newline newline +\end_inset + +但是,如果参数是绝对路径,则获得是相对于包的文件路径,比如: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +InputStream path = PropertyFileTest.class.getResourceAsStream(/database-config.prop +erties); +\end_layout + +\end_inset + +则文件database-config.properties位于src目录下。 +\end_layout + +\begin_layout Itemize +相对于包的路径:如果使用Class.getClassLoader().getResourceAsStream方法,则获得是相对于包路径的文件,比如: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +InputStream path = PropertyFileTest.class.getClassLoader().getResourceAsStream(data +base-config.properties); +\end_layout + +\end_inset + +即文件database-config.properties位于src目录下。 +\begin_inset Newline newline +\end_inset + +同时需要注意到,Class.getClassLoader.getResourceAsStream的参数不允许使用绝对路径,否则返回的InputStream为null +。 +\end_layout + +\begin_layout Standard + +\end_layout + +\end_body +\end_document diff --git a/guide/lecture_guide/lecture12.lyx b/guide/lecture_guide/lecture12.lyx new file mode 100644 index 0000000..a85e74c --- /dev/null +++ b/guide/lecture_guide/lecture12.lyx @@ -0,0 +1,9753 @@ +#LyX 2.3 created this file. For more info see http://www.lyx.org/ +\lyxformat 544 +\begin_document +\begin_header +\save_transient_properties true +\origin unavailable +\textclass ctex-book +\begin_preamble +\input{../../../writing-common/book-preamble.tex} +\end_preamble +\use_default_options true +\begin_modules +tip-inset +note-inset +warning-inset +theorems-bytype +theorems-chap-bytype +logicalmkup +coderemarks +\end_modules +\maintain_unincluded_children false +\begin_local_layout +PackageOptions url hyphens +\end_local_layout +\language chinese-simplified +\language_package default +\inputencoding utf8-plain +\fontencoding global +\font_roman "default" "DejaVu Sans" +\font_sans "default" "DejaVu Serif" +\font_typewriter "default" "DejaVu Sans Mono" +\font_math "auto" "auto" +\font_default_family default +\use_non_tex_fonts true +\font_sc false +\font_osf false +\font_sf_scale 100 100 +\font_tt_scale 100 100 +\use_microtype false +\use_dash_ligatures true +\graphics default +\default_output_format pdf4 +\output_sync 0 +\bibtex_command default +\index_command default +\float_placement tbph +\paperfontsize default +\spacing single +\use_hyperref true +\pdf_bookmarks true +\pdf_bookmarksnumbered false +\pdf_bookmarksopen false +\pdf_bookmarksopenlevel 3 +\pdf_breaklinks true +\pdf_pdfborder true +\pdf_colorlinks true +\pdf_backref false +\pdf_pdfusetitle true +\papersize default +\use_geometry false +\use_package amsmath 1 +\use_package amssymb 1 +\use_package cancel 1 +\use_package esint 1 +\use_package mathdots 1 +\use_package mathtools 1 +\use_package mhchem 1 +\use_package stackrel 1 +\use_package stmaryrd 1 +\use_package undertilde 1 +\cite_engine basic +\cite_engine_type default +\biblio_style plain +\use_bibtopic false +\use_indices false +\paperorientation portrait +\suppress_date false +\justification true +\use_refstyle 1 +\use_minted 0 +\boxbgcolor #dad3d7 +\index Index +\shortcut idx +\color #008000 +\end_index +\secnumdepth 3 +\tocdepth 2 +\paragraph_separation indent +\paragraph_indentation default +\is_math_indent 0 +\math_numbering_side default +\quotes_style english +\dynamic_quotes 0 +\papercolumns 1 +\papersides 2 +\paperpagestyle default +\tracking_changes false +\output_changes false +\html_math_output 0 +\html_css_as_file 0 +\html_be_strict false +\end_header + +\begin_body + +\begin_layout Standard +\align center + +\size larger +\bar under +山东理工大学教案 +\end_layout + +\begin_layout Standard +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +第十二次课 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +教学课型:理论课□√ 实验课□√ 习题课□ 实践课□ 技能课□ 其它□ +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +主要教学内容 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Java的图形用户界面(GUI)设计概述" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:Java的图形用户界面(GUI)设计概述" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Swing入门" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:Swing入门" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:GUI的顶级容器类" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:GUI的顶级容器类" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Swing控件" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:Swing控件" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +重点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +Swing的含义和基本构成; +\end_layout + +\begin_layout Enumerate +Swing的顶级容器; +\end_layout + +\begin_layout Enumerate +Swing的基本控件; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +难点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +Swing控件的类层次关系; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +课程目标及要求 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +课程目标:课程目标1 +\end_layout + +\begin_layout Plain Layout +要求: +\end_layout + +\begin_layout Enumerate +熟练掌握Swing的基本概念和常见控件; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +教学方法和手段 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +板书和多媒体相结合,边讲边练,当堂消化。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +讨论、思考题 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +了解Java GUI的历史,考虑一下是什么促使Java的GUI类库从AWT发展到了Swing?还有哪些第三方的Java GUI类库? +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +参考资料 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Chapter +图形用户界面设计 +\end_layout + +\begin_layout Standard +\align center +\begin_inset Graphics + filename ../imgs/gui/gui.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Section +Java的图形用户界面(GUI)设计概述 +\begin_inset CommandInset label +LatexCommand label +name "sec:Java的图形用户界面(GUI)设计概述" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java的图形用户界面( +\begin_inset Index idx +status open + +\begin_layout Plain Layout +GUI +\end_layout + +\end_inset + +GUI)是由 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JFC +\end_layout + +\end_inset + +JFC(Java Foundation Classes)支撑的,JFC包括了以下几个方面: +\end_layout + +\begin_layout Itemize +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Swing +\end_layout + +\end_inset + +Swing GUI组件:包含了图形用户界面设计中的人机交互组件,从最简单的按钮到复杂的图表等无所不包,这是我们学习的重点内容。 +\end_layout + +\begin_layout Itemize +可插拔的Look-and-Feel支持:Java图形用户界面支持可配置的Look-and-Feel切换,可以很容易的实现不同操作系统下的界面统一。 +\end_layout + +\begin_layout Itemize +辅助API:支持读屏幕等操作。 +\end_layout + +\begin_layout Itemize +Java 2D API:完善的2D绘图API。 +\end_layout + +\begin_layout Itemize +\begin_inset Index idx +status open + +\begin_layout Plain Layout +国际化 +\end_layout + +\end_inset + +国际化支持:秉承Java一贯的国际化支持,能够方便的在GUI中处理各种编码的文字。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +Swing是在早期的Java GUI应用程序设计接口AWT的基础上发展起来的,目前是Java GUI应用程序设计的官方标准。除了Swing之外,Eclipse( +www.eclipse.org)组织也发布了一套Java图形用户界面的设计库SWT(Standard Widget Toolkit),主要配合Eclipse的RCP +(Rich Client Program)应用程序开发,详情可参考:https://www.eclipse.org/swt/ +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +Swing入门 +\begin_inset CommandInset label +LatexCommand label +name "sec:Swing入门" + +\end_inset + + +\end_layout + +\begin_layout Standard +本节以JetBrain Idea为例说明如何创建和运行简单的 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Swing +\end_layout + +\end_inset + +Swing应用程序。 +\end_layout + +\begin_layout Example +使用Idea创建一个简单的Swing应用程序,将人民币转换为美元。 +\end_layout + +\begin_layout Paragraph* +步骤1 +\end_layout + +\begin_layout Standard +创建一个新的Java项目,见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:新建一个Java项目" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/getting-started-1.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +新建一个Java项目 +\begin_inset CommandInset label +LatexCommand label +name "fig:新建一个Java项目" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤2 +\end_layout + +\begin_layout Standard +在接下来的项目配置窗口中,可以不选择从模板创建项目,因为我们要创建一个GUI应用程序,命令行应用的模板没有实质用处,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:跳过从模板创建项目" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/getting-started-2.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +跳过从模板创建项目 +\begin_inset CommandInset label +LatexCommand label +name "fig:跳过从模板创建项目" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤3 +\end_layout + +\begin_layout Standard +给项目起个名字,这里叫做“gui”,并选择项目所在的目录,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:给项目起个名字" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/getting-started-3.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +给项目起个名字 +\begin_inset CommandInset label +LatexCommand label +name "fig:给项目起个名字" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤4 +\end_layout + +\begin_layout Standard +在项目的“project视图”中,右键点击src,在弹出的菜单中选择New->GUI Form,新建一个Form表单 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Form表单 +\end_layout + +\end_inset + +,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:准备新建一个Form表单" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-1.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +准备新建一个Form表单 +\begin_inset CommandInset label +LatexCommand label +name "fig:准备新建一个Form表单" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +如果在菜单中没有出现GUI Form子菜单,系没有安装Form Designer +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Form Designer +\end_layout + +\end_inset + +插件所致,请在系统设置中激活Form Designer即可,方法是在File->Settings...菜单中搜索“UI Designer”插件并安装激活,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:安装并激活UI-Designer插件" + +\end_inset + +所示。 +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/active-ui-designer.png + width 60line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +安装并激活UI Designer插件 +\begin_inset CommandInset label +LatexCommand label +name "fig:安装并激活UI-Designer插件" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +图片和文字可能不在一个页面,应该想办法处理一下 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤5 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:给Form起个名字" + +\end_inset + +所示,给将要创建的Form起个名字,这里叫做“RMB2DollarConverter”,选择布局管理器(此处先认可默认设置,随后可以更改)。注意要勾选(默认已经 +勾选了) +\begin_inset Quotes erd +\end_inset + +create bound class +\begin_inset Quotes erd +\end_inset + +选项,即同时创建和这个Form绑定在一起的Java类。这个Java类我们将来用于显示和操作这个Form。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-2.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +给Form起个名字 +\begin_inset CommandInset label +LatexCommand label +name "fig:给Form起个名字" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤6 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:空白的Form设计窗口" + +\end_inset + +所示,在新建Form后会呈现一个空白的Form设计窗口,其主要组成部分为: +\end_layout + +\begin_layout Itemize +界面组件关系图:在这个窗口中展示了组件的“父子”关系,目前只有一个JPanel组件,随后我们会加入更多组件,可以通过这个窗口直观的查看组件之间的关系。也可以通过 +这个窗口快捷的选择某个组件进行操作。 +\end_layout + +\begin_layout Itemize +组件属性窗:当在主设计界面或者界面组件关系窗口中选择了某个组件时,组件属性窗的内容将随之改变。可以通过这个窗口方便的了解界面组件拥有哪些属性,当然,更重要的是, +可以设置界面组件的属性值。 +\end_layout + +\begin_layout Itemize +主设计界面:可以拖放“组件面板”中的组件导主设计界面,主设计界面会根据使用的布局管理器的不同,自动摆放组件。 +\end_layout + +\begin_layout Itemize +组件面板:列出了各种Swing界面组件,可以方便的拖放到主设计界面。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-3.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +空白的Form设计窗口 +\begin_inset CommandInset label +LatexCommand label +name "fig:空白的Form设计窗口" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤7 +\end_layout + +\begin_layout Standard +首先在“界面组件关系窗口”中选择目前唯一的组件Panel,然后在组件属性窗口中编辑“field name”属性,设置其值为“mainPanel +\begin_inset Quotes erd +\end_inset + +。这里的值是什么并不重要的,重要的是必须给主Panel设置一个名字,否则将来无法显示这个Panel。 +\end_layout + +\begin_layout Standard +在这里,我们也将mainPanel的 +\begin_inset Quotes erd +\end_inset + +Layout Manager +\begin_inset Quotes erd +\end_inset + +(布局管理器)修改为更为简单的 +\begin_inset Quotes erd +\end_inset + +FlowLayout +\begin_inset Quotes erd +\end_inset + +,我们将在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:布局管理器" + +\end_inset + +一节详细的阐述各种布局管理器 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +布局管理器 +\end_layout + +\end_inset + +的用法。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-4.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +给主Panel起个名字 +\begin_inset CommandInset label +LatexCommand label +name "fig:给主Panel起个名字" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤8 +\end_layout + +\begin_layout Standard +在“组件面板”窗口选择JLabel组件拖放到主设计界面,可以看到在“界面组件关系”窗口中,JLabel包含在mainPanel中。这里只是简单的设置这个JLab +el的text属性为“人民币:”即可。JLabel的目的是显示一个标签 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +标签 +\end_layout + +\end_inset + +,我们将在 +\begin_inset CommandInset ref +LatexCommand formatted +reference "subsec:JLabel" + +\end_inset + +一节详细讨论Jlabel的用法。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-5.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +添加一个简单的Label +\begin_inset CommandInset label +LatexCommand label +name "fig:添加一个简单的Label" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤9 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:添加JTextField组件" + +\end_inset + +所示,接着添加一个JTextField +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JTextField +\end_layout + +\end_inset + +组件到主设计界面。这个JTextField我们用来输入人民币数额,因此要设置其 +\begin_inset Quotes erd +\end_inset + +field name +\begin_inset Quotes erd +\end_inset + +属性。为了更好的显示这个输入框,也设置了这个JTextField的默认宽度(preferedSize->width)和默认显示的文字(text属性)。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-6.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +添加JTextField组件 +\begin_inset CommandInset label +LatexCommand label +name "fig:添加JTextField组件" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤10 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:添加转换按钮" + +\end_inset + +所示,再增加一个“转换”按钮 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +按钮 +\end_layout + +\end_inset + +,设置这个按钮的field name和text属性。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-7.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +添加转换按钮 +\begin_inset CommandInset label +LatexCommand label +name "fig:添加转换按钮" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤11 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:添加显示转换结果的JLabel" + +\end_inset + +所示,在界面中再添加一个用于显示转换结果的JLabel。由于我们要通过程序设置这个JLabel的text属性,因此要设置这个JLabel的field + name属性。为了能够更好的显示转换后的结果,也有设置这个JLabel的宽度,这里设置为100(像素值)。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-8.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +添加显示转换结果的JLabel +\begin_inset CommandInset label +LatexCommand label +name "fig:添加显示转换结果的JLabel" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤12 +\begin_inset CommandInset label +LatexCommand label +name "par:步骤12" + +\end_inset + + +\end_layout + +\begin_layout Standard +界面的设计工作基本就绪,下面我们为按钮设计处理代码。如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:准备创建Listener" + +\end_inset + +所示,在主设计界面的“转换”按钮上点击右键,在弹出的菜单中选择“create Listener”,准备创建一段点击此按钮的响应代码。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-9.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +准备创建Listener +\begin_inset CommandInset label +LatexCommand label +name "fig:准备创建Listener" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤13 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:选择Listener的类型" + +\end_inset + +所示,在接下来的窗口中选择Listener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Listener +\end_layout + +\end_inset + +的类型为“ActionListener”。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-10.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +选择Listener的类型 +\begin_inset CommandInset label +LatexCommand label +name "fig:选择Listener的类型" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤14 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:选择需要覆盖的方法" + +\end_inset + +所示,在接下来的窗口中,选择ActionListener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +ActionListener +\end_layout + +\end_inset + +需要覆盖的方法。这里只有一个选项,已经自动选中了。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-11.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +选择需要覆盖的方法 +\begin_inset CommandInset label +LatexCommand label +name "fig:选择需要覆盖的方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +点击 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:选择需要覆盖的方法" + +\end_inset + +中的“OK”按钮后,在所绑定的方法中自动添加了一个构造方法 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +构造方法 +\end_layout + +\end_inset + +,内容如下(行5-7是自己编写的): +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + public RMB2DollarConverter() { +\end_layout + +\begin_layout Plain Layout + + convertButton.addActionListener(new ActionListener() { +\end_layout + +\begin_layout Plain Layout + + @Override +\end_layout + +\begin_layout Plain Layout + + public void actionPerformed(ActionEvent actionEvent) { +\end_layout + +\begin_layout Plain Layout + + // 获取文本输入框的文字内容并转换为double +\end_layout + +\begin_layout Plain Layout + + Double rmb = Double.valueOf(rmbTextField.getText()); +\end_layout + +\begin_layout Plain Layout + + dollarLabel.setText(String.valueOf(rmb / 7.0)); // 假设当前人民币和美元汇率为7.0 +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + }); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +这是GUI应用程序事件处理的基本方法,我们将在 +\begin_inset CommandInset ref +LatexCommand formatted +reference "sec:JAVA图形用户界面的事件机制" + +\end_inset + +一节中具体讨论。 +\end_layout + +\begin_layout Paragraph* +步骤15 +\end_layout + +\begin_layout Standard +最后一步,我们需要在类RMB2DollarConverter中增加一个main方法并初始化和显示应用程序窗口,JetBrain Idea提供了自动化的代码生成工 +具,只需要在代码的合适位置(希望插入main方法的位置)按下Alt+Insert +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Alt+Insert +\end_layout + +\end_inset + +组合键,在如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:准备插入main方法" + +\end_inset + +所示的窗口中选择 +\begin_inset Quotes erd +\end_inset + +Form main() +\begin_inset Quotes erd +\end_inset + +即可自动创建main方法如下: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + public static void main(String[] args) { +\end_layout + +\begin_layout Plain Layout + + JFrame frame = new JFrame("RMB2DollarConverter"); +\end_layout + +\begin_layout Plain Layout + + frame.setContentPane(new RMB2DollarConverter().mainPanel); +\end_layout + +\begin_layout Plain Layout + + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); +\end_layout + +\begin_layout Plain Layout + + frame.pack(); +\end_layout + +\begin_layout Plain Layout + + frame.setVisible(true); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-12.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +准备插入main方法 +\begin_inset CommandInset label +LatexCommand label +name "fig:准备插入main方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +经过了以上的15个步骤,现在终于可以运行这个应用程序了 +\begin_inset Foot +status open + +\begin_layout Plain Layout +本例的完整代码请参见:https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui +\end_layout + +\end_inset + +。和运行其他Java应用程序的方法一样,运行RMB2DollarConverter类结果如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand formatted +reference "fig:RMB2DollarConverter的运行结果" + +\end_inset + +所示。可以在输入框输入人民币数额,然后点击“转换”按钮获得相应的美元数。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/RMB2DollarConverter-output.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +RMB2DollarConverter的运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:RMB2DollarConverter的运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +虽然在上面我们使用了15个步骤创建了一个简单的GUI应用程序,其实关键的步骤是4个,如下图所示: +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset include +LatexCommand input +filename "../imgs/gui/basic-gui-flow.pgf" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status collapsed + +\begin_layout Plain Layout +你可能会问,在类RMB2DollarConverter中的几个私有属性(对象):mainPanel、rmbTextField等是什么时候初始化的?很好的问题! +\end_layout + +\begin_layout Plain Layout +实际上,Idea通过一个xml文件(RMB2DollarConvert.form)保存了界面中所包含的组件及其属性和相互关系,在编译的时候,Idea会自动读取这个 +界面配置文件并生成创建界面中的组件的构造方法,也就是说,mainPanel等对象其实是Idea帮我们创建了的,我们可以直接拿来就用。 +\end_layout + +\begin_layout Plain Layout +可以通过反编译class文件看到这一点,在构造方法中的setupUI方法创建了各个界面组件对象(部分删减,请自行运行jad RMB2DollarConverte +r获得完整的反编译后的文件): +\end_layout + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class RMB2DollarConverter +\end_layout + +\begin_layout Plain Layout + +{ +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + public static void main(String args[]) +\end_layout + +\begin_layout Plain Layout + + { +\end_layout + +\begin_layout Plain Layout + + JFrame frame = new JFrame("RMB2DollarConverter"); +\end_layout + +\begin_layout Plain Layout + + frame.setContentPane((new RMB2DollarConverter()).mainPanel); +\end_layout + +\begin_layout Plain Layout + + frame.setDefaultCloseOperation(3); +\end_layout + +\begin_layout Plain Layout + + frame.pack(); +\end_layout + +\begin_layout Plain Layout + + frame.setVisible(true); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + public RMB2DollarConverter() +\end_layout + +\begin_layout Plain Layout + + { +\end_layout + +\begin_layout Plain Layout + + setupUI(); +\end_layout + +\begin_layout Plain Layout + + convertButton.addActionListener(new ActionListener() { +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + public void actionPerformed(ActionEvent actionEvent) +\end_layout + +\begin_layout Plain Layout + + { +\end_layout + +\begin_layout Plain Layout + + Double rmb = Double.valueOf(rmbTextField.getText()); +\end_layout + +\begin_layout Plain Layout + + dollarLabel.setText(String.valueOf(rmb.doubleValue() / 7D)); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + }); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + private void setupUI() +\end_layout + +\begin_layout Plain Layout + + { +\end_layout + +\begin_layout Plain Layout + + JPanel jpanel; +\end_layout + +\begin_layout Plain Layout + + JLabel jlabel; +\end_layout + +\begin_layout Plain Layout + + jpanel = new JPanel(); +\end_layout + +\begin_layout Plain Layout + + mainPanel = jpanel; +\end_layout + +\begin_layout Plain Layout + + jpanel.setLayout(new FlowLayout(1, 5, 5)); +\end_layout + +\begin_layout Plain Layout + + jlabel = new JLabel(); +\end_layout + +\begin_layout Plain Layout + + jlabel.setText(" +\backslash +u4EBA +\backslash +u6C11 +\backslash +u5E01 +\backslash +uFF1A"); +\end_layout + +\begin_layout Plain Layout + + jpanel.add(jlabel); +\end_layout + +\begin_layout Plain Layout + + JTextField jtextfield; +\end_layout + +\begin_layout Plain Layout + + jtextfield = new JTextField(); +\end_layout + +\begin_layout Plain Layout + + rmbTextField = jtextfield; +\end_layout + +\begin_layout Plain Layout + + jtextfield.setMinimumSize(new Dimension(14, 29)); +\end_layout + +\begin_layout Plain Layout + + jtextfield.setPreferredSize(new Dimension(60, 29)); +\end_layout + +\begin_layout Plain Layout + + jtextfield.setText("#.##"); +\end_layout + +\begin_layout Plain Layout + + jtextfield.setToolTipText(" +\backslash +u8BF7 +\backslash +u8F93 +\backslash +u5165 +\backslash +u4EBA +\backslash +u6C11 +\backslash +u5E01 +\backslash +u6570 +\backslash +u989D"); +\end_layout + +\begin_layout Plain Layout + + jpanel.add(jtextfield); +\end_layout + +\begin_layout Plain Layout + + JButton jbutton; +\end_layout + +\begin_layout Plain Layout + + jbutton = new JButton(); +\end_layout + +\begin_layout Plain Layout + + convertButton = jbutton; +\end_layout + +\begin_layout Plain Layout + + jbutton.setText(" +\backslash +u8F6C +\backslash +u6362"); +\end_layout + +\begin_layout Plain Layout + + jpanel.add(jbutton); +\end_layout + +\begin_layout Plain Layout + + JLabel jlabel1; +\end_layout + +\begin_layout Plain Layout + + jlabel1 = new JLabel(); +\end_layout + +\begin_layout Plain Layout + + dollarLabel = jlabel1; +\end_layout + +\begin_layout Plain Layout + + jlabel1.setPreferredSize(new Dimension(100, 21)); +\end_layout + +\begin_layout Plain Layout + + jlabel1.setText(" +\backslash +u7F8E +\backslash +u5143 +\backslash +uFF1A"); +\end_layout + +\begin_layout Plain Layout + + jpanel.add(jlabel1); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + private JPanel mainPanel; +\end_layout + +\begin_layout Plain Layout + + private JTextField rmbTextField; +\end_layout + +\begin_layout Plain Layout + + private JButton convertButton; +\end_layout + +\begin_layout Plain Layout + + private JLabel dollarLabel; +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status collapsed + +\begin_layout Plain Layout +在Idea的Form Designer中,我们看到可以直接拖放各种控件到应用程序界面中,并且可以直观的通过“属性查看器”查看和修改控件的属性,其中一个重要的属性 +是field name属性,即属性的名称。什么时候需要给控件的field name属性赋值,什么时候不需要理会field name属性呢?简单的说,如果我们在程 +序中需要获得这个控件的其他属性,比如输入的文字,或者需要在程序运行期间通过程序改变这个控件的状态,则需要给这个控件的field name赋值。比如常见的JLab +el控件一般是不需要field name属性的,而JTextField则需要field name属性。 +\end_layout + +\begin_layout Plain Layout +进一步的观察我们可以发现,只有给控件一个field name属性值,Idea才能在绑定的类中自动创建私有的属性对象(变量)表示这个控件,变量的名字就是field + name属性的值。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +GUI的顶级容器类 +\begin_inset CommandInset label +LatexCommand label +name "sec:GUI的顶级容器类" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java的图形用户界面也是“面向对象”的,比如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java图形用户界面应用程序的大致布局" + +\end_inset + +是常见的一个窗口应用程序,我们从Java的观点来看,可以分为如下的几部分: +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/swing-app-outline.png + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java图形用户界面应用程序的大致布局 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java图形用户界面应用程序的大致布局" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +整个应用程序框架使用JFrame +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JFrame +\end_layout + +\end_inset + +来表示,在JFrame内部布置了菜单栏(JMenuBar)、工具栏(JToolBar)、内容区(ContentPane),我们最经常操作的区域是ContentP +ane,即几乎所有的界面设计工作集中在ContentPane上面。 +\end_layout + +\begin_layout Standard +所以,JFrame是一个顶层的容器 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +容器 +\end_layout + +\end_inset + +,其他所有的界面组件都放置在顶层容器 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +顶层容器 +\end_layout + +\end_inset + +之中,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java-GUI应用程序的基本结构" + +\end_inset + +所示。除了JFrame之外,Java也提供了JDialog、JApplet +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JApplet +\end_layout + +\end_inset + +顶层容器,分别用于对话框的设计和Applet +\begin_inset Foot +status open + +\begin_layout Plain Layout +一种已经没落的技术。 +\end_layout + +\end_inset + +的设计。本章重点介绍基于JFrame的Java图形用户界面设计,JDialog +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JDialog +\end_layout + +\end_inset + +的用法于此类似。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jframe-overview.eps + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java GUI应用程序的基本结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java-GUI应用程序的基本结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +不介绍分层的面板会有影响吗? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +下面的代码展示了 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java-GUI应用程序的基本结构" + +\end_inset + +中的组件间的关系: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +JFrame frame = new JFrame("标题栏内容"); +\end_layout + +\begin_layout Plain Layout + +frame.getContentPane().add(new JLabel("a label", BorderLayout.TOP)); +\end_layout + +\begin_layout Plain Layout + +frame.getContentPane().add(new JTextField("##.##", BorderLayout.BOTTOM)); +\end_layout + +\begin_layout Plain Layout + +JPanel panel = new JPanel(); +\end_layout + +\begin_layout Plain Layout + +panel.add(new JLabel("another label")); +\end_layout + +\begin_layout Plain Layout + +panel.add(new JCheckBox(...)); +\end_layout + +\begin_layout Plain Layout + +frame.add(panel, BorderLayout.CENTER); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +Swing控件 +\begin_inset CommandInset label +LatexCommand label +name "sec:Swing控件" + +\end_inset + + +\end_layout + +\begin_layout Subsection +JLabel +\begin_inset CommandInset label +LatexCommand label +name "subsec:JLabel" + +\end_inset + + +\end_layout + +\begin_layout Standard +Label(文本标签)也许是最简单的Swing控件了,一般用来表示界面上的几个字符或者一段提示性文字、展示输出结果、图标等。 +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JLabel +\end_layout + +\end_inset + +JLabel的主要属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:JLabel的主要属性" + +\end_inset + +所示(每个属性对应一对get/set方法),请参照Form Designer +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Form Designer +\end_layout + +\end_inset + +的属性对话框了解属性值的可能取值范围。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +说明 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +icon +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label所使用的图片 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +text +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label显示的文字 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label的水平对齐方式 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +verticalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label的纵向对齐方式 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalTextPosition +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label文字的水平位置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +verticalTextPosition +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label文字的垂直位置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +textGap +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label文字和图片之间的间隙(像素值) +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JLabel的主要属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:JLabel的主要属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +JLabel示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整的代码请参见:https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/sr +c/cn/edu/sdut/softlab/,双击JLabelDemo.form即可打开Form Designer查看界面设计效果。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +我们在内容区增加了三个JLabel:最上面的Label同时包含了文字和图片,中间的Label只包含了文字,最下面的Label只包含了图片,其属性对话框的设置分别 +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:顶部Label属性框设置" + +\end_inset + + +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:中间Label属性框设置" + +\end_inset + + +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:下面Label属性框设置" + +\end_inset + +所示,其中修改过的属性已经黑体加重标注了,没有使用黑体标注的属性无需设置。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +当拖放第一个JLabel到内容区的时候,Form Designer自动在这个JLabel的下面增加了一个垂直占位符,以保证这个JLabel能够在希望的顶部展示。 +由于我们还要增加下面的两个Label,因此这里可以删除这个垂直占位符。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/gui/jlabel-demo-1.png + width 30line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +顶部Label属性框设置 +\begin_inset CommandInset label +LatexCommand label +name "fig:顶部Label属性框设置" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/gui/jlabel-demo-2.png + width 30line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +中间Label属性框设置 +\begin_inset CommandInset label +LatexCommand label +name "fig:中间Label属性框设置" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/gui/jlabel-demo-3.png + width 30line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +下面Label属性框设置 +\begin_inset CommandInset label +LatexCommand label +name "fig:下面Label属性框设置" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JLabel的属性对话框 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行此示例,初始状态如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:运行的初始状态" + +\end_inset + +所示,可以尝试缩放窗口,比如水平放大窗口可以更明显的看出效果,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:水平方法后的窗口" + +\end_inset + +所示。请任意缩放窗口请注意观察这三个Label位置的变化,体会水平对齐 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +水平对齐 +\end_layout + +\end_inset + +、垂直对齐 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +垂直对齐 +\end_layout + +\end_inset + +等的效果。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jlabel-demo-4.png + height 30theight% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +运行的初始状态 +\begin_inset CommandInset label +LatexCommand label +name "fig:运行的初始状态" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jlabel-demo-5.png + height 30theight% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +水平放大后的窗口 +\begin_inset CommandInset label +LatexCommand label +name "fig:水平方法后的窗口" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JLabelDemo运行结果 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +注意以下几点: +\end_layout + +\begin_layout Itemize +这三个 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JLabel +\end_layout + +\end_inset + +JLabel都无需设置field name属性值。 +\end_layout + +\begin_layout Itemize +特别注意观察Horizental Align属性的不同效果,可以尝试不同的水平对齐方式观察效果(通过Idea的Form Designer提供的预览工具更方便,在 +Form Designer界面直接右键选择“preview”即可)。 +\end_layout + +\begin_layout Itemize +在组合使用文本和图片时,还要注意horizentalTextPosition +\begin_inset Index idx +status open + +\begin_layout Plain Layout +horizentalTextPosition +\end_layout + +\end_inset + +和verticalTextPosition +\begin_inset Index idx +status open + +\begin_layout Plain Layout +verticalTextPosition +\end_layout + +\end_inset + +这两个属性的效果。 +\end_layout + +\begin_layout Subsection +文本控件 +\begin_inset CommandInset label +LatexCommand label +name "subsec:JTextField" + +\end_inset + + +\end_layout + +\begin_layout Standard +Swing的文本控件是指能够输入文本的控件,比如文本框(JTextField +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JTextField +\end_layout + +\end_inset + +)、文本域(JTextArea +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JTextArea +\end_layout + +\end_inset + +)、富文本编辑器(JEdtiorPane +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JEdtiorPane +\end_layout + +\end_inset + +)等。Swing的文本控件类的关系如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:文本输入控件" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/text-input-controls.eps + lyxscale 40 + scale 40 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +文本输入控件 +\begin_inset CommandInset label +LatexCommand label +name "fig:文本输入控件" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +单行纯文本控件:用于输入一行纯文本字符串。根据场合不同,可以选择使用JTextField,输入简单的单行字符串;或者JFormattedTextField +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JFormattedTextField +\end_layout + +\end_inset + +,输入格式化的单行字符串,比如表示日期的“2017-3-12”等;或者JPasswordField +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JPasswordField +\end_layout + +\end_inset + +,输入密码(默认不显示输入的密码)。 +\end_layout + +\begin_layout Itemize +多行纯文本控件:用于输入多行纯文本字符串。如果需要输入的字符串比较长,可以采用JTextArea +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JTextArea +\end_layout + +\end_inset + +,会显示一个多行的文本编辑区域供输入。 +\end_layout + +\begin_layout Itemize +多行富文本控件:用于输入带格式的文本字符串,通常用于输入HTML等格式的字符串。 +\end_layout + +\begin_layout Standard +文本控件的常见属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:文本控件的常见属性" + +\end_inset + +所示,请参照Form Designer中的属性对话框了解这些属性的取值范围。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +说明 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +text +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +文本框的内容 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +editable +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +是否可编辑 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +columns +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +文本框的长度(多少个字符),仅仅作为计算默认显示宽度的依据 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +字符在文本框内的对齐方式,可以选择:JTextField.LEADING, JTextField.CENTER, JTextField.TRAILING +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +文本控件的常见属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:文本控件的常见属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +文本控件示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +我们设计一个同时展示三种TextField的Panel,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:文本控件示例" + +\end_inset + +所示 +\begin_inset Foot +status open + +\begin_layout Plain Layout +详情请参见:https://github.com/subaochen/java-tutorial-examples/blob/master/gui/src/cn/ +edu/sdut/softlab/TextControlDemo.form +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +.当在文本框中输入一些字符后(失去焦点后),在最下面的 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Label +\end_layout + +\end_inset + +Label中显示输入的内容。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/textfield-demo-1.png + width 95line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +文本控件示例 +\begin_inset CommandInset label +LatexCommand label +name "fig:文本控件示例" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行此应用程序的界面如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:文本控件示例运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/textfield-demo-2.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +文本控件示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:文本控件示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +这个简单的示例我们要注意以下三点: +\begin_inset Note Note +status open + +\begin_layout Plain Layout +示例代码的布局要说明吗? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +可以通过 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Panel +\end_layout + +\end_inset + +Panel进一步组织控件,这是一种常见的手段。在例中,我们把三个 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +TextField +\end_layout + +\end_inset + +TextField控件放到一个Panel中,在把这Panel添加到mainPanel中。并且,放置三个TextField的Panel添加了标题(title):“ +单行纯文本控件”,以更清晰的表达这个Panel的意义,这也是一种常见的手段。 +\end_layout + +\begin_layout Itemize +请参照 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "par:步骤12" + +\end_inset + +为三个TextField添加FocusListener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +FocusListener +\end_layout + +\end_inset + +,这里我们重点监听了失去焦点的事件。 +\end_layout + +\begin_layout Itemize +本例也可以监听ActionListener(当在输入框按下回车键时触发该事件)获得当前输入框的内容,请读者自行完成相关代码并运行测试。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +焦点 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +焦点 +\end_layout + +\end_inset + +(Focus)通常是指文本输入框是否正在接受输入。获得焦点即文本输入框可以输入文字,失去焦点即文本输入框不再能够输入文字,即光标已经离开了此输入框。失去焦点往往 +意味着用户结束了输入,因此,我们可以通过监听失去焦点事件来获得文本输入框中的内容。 +\end_layout + +\begin_layout Plain Layout +如果焦点的概念用于窗口(应用程序),则获得焦点意味着当前窗口是活动窗口,即可操作的窗口;失去焦点意味着其他窗口获得了焦点,当前窗口不可操作。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +JButton +\begin_inset CommandInset label +LatexCommand label +name "subsec:JButton" + +\end_inset + + +\end_layout + +\begin_layout Standard +按钮(Button +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Button +\end_layout + +\end_inset + +)是一种常见的交互控件,在Swing中最常见的按钮通过JButton +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JButton +\end_layout + +\end_inset + +来描述。按钮用法很直接,通常涉及到以下三个方面: +\end_layout + +\begin_layout Itemize +给按钮一个合适的名称,包括显示在按钮上面的文字。 +\end_layout + +\begin_layout Itemize +有的时候希望在按钮上面也显示图标以更明确的表达按钮的意思,可以通过按钮的icon +\begin_inset Index idx +status open + +\begin_layout Plain Layout +icon +\end_layout + +\end_inset + +属性来设置图标。 +\end_layout + +\begin_layout Itemize +给按钮添加鼠标点击的响应代码( +\begin_inset Index idx +status open + +\begin_layout Plain Layout +ActionListener +\end_layout + +\end_inset + +ActionListener或者MouseListener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +MouseListener +\end_layout + +\end_inset + +)。 +\end_layout + +\begin_layout Standard +JButton的常见属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:JButton的常见属性" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +说明 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +enabled +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +是否允许点击 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +icon +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +在按钮上面要显示的图标 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +text +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +在按钮上面要显示的文字 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalTextPosition +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +水平方向的文字位置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +verticalTextPosition +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +垂直方向的文字位置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +水平方向的对齐方式 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +virticalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +垂直方向的对齐方式 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JButton的常见属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:JButton的常见属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +JButton示例 +\begin_inset CommandInset label +LatexCommand label +name "exa:JButton示例" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +我们设计一个包含三个按钮的Panel,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Button示例Panel" + +\end_inset + +所示 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整的代码请参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/button-demo-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Button示例Panel +\begin_inset CommandInset label +LatexCommand label +name "fig:Button示例Panel" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +依然参照 +\begin_inset CommandInset ref +LatexCommand formatted +reference "par:步骤12" + +\end_inset + +为这三个Button 添加三个ActionListener,分别响应鼠标左键单击事件。 +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +在运行时点击各个按钮,观察发生了什么?比如点击“紧急呼叫”按钮,弹出了一个消息框,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Button示例运行结果" + +\end_inset + +所示。点击“被禁止的按钮”,会怎样? +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/button-demo-2.png + width 50line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Button示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:Button示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +请仔细查看三个按钮的属性对话框以了解这三个按钮是如何实现这样的效果的: +\end_layout + +\begin_layout Itemize +第一个按钮演示了按钮上是可以图文并茂的(设置icon +\begin_inset Index idx +status open + +\begin_layout Plain Layout +icon +\end_layout + +\end_inset + +属性即可),并且通过设置horizentalTextPosition +\begin_inset Index idx +status open + +\begin_layout Plain Layout +horizentalTextPosition +\end_layout + +\end_inset + +属性为Leading(在开头),将图片放到了文字的后面。 +\end_layout + +\begin_layout Itemize +第二个按钮演示了如何将按钮上的文字和图片上下布局:首先让按钮上的内容水平居中(horizentalTextPosition +\begin_inset Index idx +status open + +\begin_layout Plain Layout +horizentalTextPosition +\end_layout + +\end_inset + +属性为Center),然后设置verticalTextPosition +\begin_inset Index idx +status open + +\begin_layout Plain Layout +verticalTextPosition +\end_layout + +\end_inset + +属性为Bottom即可。 +\end_layout + +\begin_layout Itemize +第三个按钮设置enabled为false即可,即去掉默认选中的enabled选项。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +默认的,JButton的actionListener是响应鼠标左键单击事件的,比如在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +example +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:JButton示例" + +\end_inset + +中,我们给按钮增加了响应鼠标左键单击的actionListener,那么如何响应鼠标右键、中键的单击事件呢?参见下面的代码: +\end_layout + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +// 响应右键单击事件 +\end_layout + +\begin_layout Plain Layout + +emegencyCallButton.addMouseListener(new MouseAdapter() { +\end_layout + +\begin_layout Plain Layout + + @Override +\end_layout + +\begin_layout Plain Layout + + public void mouseClicked(MouseEvent mouseEvent) { +\end_layout + +\begin_layout Plain Layout + + super.mouseClicked(mouseEvent); +\end_layout + +\begin_layout Plain Layout + + if(SwingUtilities.isRightMouseButton(mouseEvent) && mouseEvent.getClickCou +nt() == 1) { +\end_layout + +\begin_layout Plain Layout + + JOptionPane.showMessageDialog(null,"右键单击急呼叫按钮"); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +}); +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +JCheckBox +\begin_inset CommandInset label +LatexCommand label +name "subsec:JCheckBox" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JCheckBox +\end_layout + +\end_inset + +JCheckBox通常叫做“复选框”,即可以同时打开或关闭多个选项 +\begin_inset Foot +status open + +\begin_layout Plain Layout +对比一下JRadioButton(单选框),JRadionButton只能在一组选项中选中一项。 +\end_layout + +\end_inset + +。当选项被选中时,该复选框的“选择”状态为true,否则为false。 +\end_layout + +\begin_layout Standard +JCheckBox的常见属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:JCheckBox的常见属性" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +说明 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +text +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +CheckBox的提示文字 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +icon +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +CheckBox的提示图片 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +enabled +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +是否启用这个控件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +selected +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +CheckBox默认的选中状态 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +文字的水平对齐方式 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalTextPosition +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +文字的水平位置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +verticalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +文字的垂直对齐方式 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +virticalTextPosition +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +文字的垂直位置 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JCheckBox的常见属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:JCheckBox的常见属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +JCheckBox示例 +\begin_inset CommandInset label +LatexCommand label +name "exa:JCheckBox示例" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +我们设计一个包含4个CheckBox(业余爱好)的Panel +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +,当鼠标点击某个爱好时显示选中的CheckBox的状态;当鼠标移动到某个爱好上面时,同步显示表示这个业余爱好的图片,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JCheckBox运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/checkbox-demo-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JCheckBox示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:JCheckBox示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +在运行时,注意观察鼠标在各个CheckBox上面和离开CheckBox时界面的不同反应,选中或者反选选项时不同的消息提示,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JCheckBox运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/checkbox-demo-2.png + width 20line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +运行初始状态 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/checkbox-demo-3.png + width 20line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +鼠标移动到“足球”选项 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/checkbox-demo-4.png + width 45line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +选中“足球”选项 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JCheckBox运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:JCheckBox运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +我们为每个JCheckBox添加了两个事件监听器,一个ActionListener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +ActionListener +\end_layout + +\end_inset + +用于监听鼠标左键单击选项选择或者反选时产生的事件,一个MouseListener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +MouseListener +\end_layout + +\end_inset + +用于监听当鼠标进入或者离开选项所在区域时产生的事件。 +\end_layout + +\begin_layout Paragraph +延伸阅读 +\end_layout + +\begin_layout Standard +其实,JButton +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JButton +\end_layout + +\end_inset + +, JCheckBox +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JCheckBox +\end_layout + +\end_inset + +, JRadionButton +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JRadionButton +\end_layout + +\end_inset + +等都从 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +AbstractButton +\end_layout + +\end_inset + +AbstractButton继承下来的,即JButton一族的类层次关系如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Button类层次关系" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/button-overview.eps + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Button类层次关系 +\begin_inset CommandInset label +LatexCommand label +name "fig:Button类层次关系" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +因此,JButtron、JCheckBox、JRadionButton等的共性就不难理解了。 +\end_layout + +\begin_layout Subsection +JRadioButton +\begin_inset CommandInset label +LatexCommand label +name "subsec:JRadioButton" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JRadioButton +\end_layout + +\end_inset + +JRadioButton通常叫做“单选框”,即通过JRadionButton可以展示一组选项,但是只能有一个选项处于“选中”状态。当选择另外一个选项时,原先被选 +中的选项自动失效。 +\end_layout + +\begin_layout Standard +JRadionButton的常见属性和JCheckBox基本相同,只有一点需要注意:JRadioButton的buttonGroup属性是必须设置的,即每个JR +adioButton都需要设置buttonGroup属性,表明这个JRadioButton是属于哪个“组”的,以便Java根据用户的选择情况设置当前组的Radi +oButton哪个有效,哪个失效。 +\end_layout + +\begin_layout Example +JRadionButton示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +类似于 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:JCheckBox示例" + +\end_inset + +,我们设计一个图形用户应用程序 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整的代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +,根据选项决定显示哪种运动的图片,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JRadioButton示例设计" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jradiobutton-demo-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JRadioButton示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:JRadioButton示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +点击不同的选项,将显示不同的运动图片,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JRadionButton示例运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jradiobutton-demo-2.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JRadionButton示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:JRadionButton示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +本例中,我们手工创建了ActionListener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +ActionListener +\end_layout + +\end_inset + +,通常JRadioButton的ActionListener需要手工创建更合适,因为JRadioButton一般需要设置为属于某个ButtonGroup,整个B +uttonGroup设计一个ActionListener就可以了,没有必要每个JRadioButton都独立设计一个ActionListener,如下列代码所示 +: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + public RadioButtonDemo() { +\end_layout + +\begin_layout Plain Layout + + swimming.setActionCommand("swimming"); +\end_layout + +\begin_layout Plain Layout + + swimming.addActionListener(this); +\end_layout + +\begin_layout Plain Layout + + tennis.setActionCommand("tennis"); +\end_layout + +\begin_layout Plain Layout + + tennis.addActionListener(this); +\end_layout + +\begin_layout Plain Layout + + basketball.setActionCommand("basketball"); +\end_layout + +\begin_layout Plain Layout + + basketball.addActionListener(this); +\end_layout + +\begin_layout Plain Layout + + football.setActionCommand("football"); +\end_layout + +\begin_layout Plain Layout + + football.addActionListener(this); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + @Override +\end_layout + +\begin_layout Plain Layout + + public void actionPerformed(ActionEvent actionEvent) { +\end_layout + +\begin_layout Plain Layout + + sportLabel.setIcon(new ImageIcon(RadioButtonDemo.class.getResource("/images +/" +\end_layout + +\begin_layout Plain Layout + + + actionEvent.getActionCommand() + ".png"))); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在以上代码中,我们在构造方法中为每个JRadioButton指定了actionCommand +\begin_inset Index idx +status open + +\begin_layout Plain Layout +actionCommand +\end_layout + +\end_inset + +以便在监听器代码中获取actionCommand拼装图片的路径。 +\end_layout + +\begin_layout Standard +另外需要注意的是,我们需要将这组JRadionButton设置一个共同的ButtonGroup,即在Form Designer中如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:设置ButtonGroup" + +\end_inset + +所示,创建一个新的ButtonGroup +\begin_inset Index idx +status open + +\begin_layout Plain Layout +ButtonGroup +\end_layout + +\end_inset + +,并将所有JRadioButton的ButtonGroup属性都设置为这个新建的ButtonGroup。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jradiobutton-demo-3.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +设置ButtonGroup +\begin_inset CommandInset label +LatexCommand label +name "fig:设置ButtonGroup" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +JComboBox +\begin_inset CommandInset label +LatexCommand label +name "subsec:JComboBox" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JcomboBox +\end_layout + +\end_inset + +JcomboBox表示“下列选择框”,通常在空间比较紧张或者选项很多时采用下拉选择框比较合适。 +\end_layout + +\begin_layout Example +下拉选择框示例 +\begin_inset CommandInset label +LatexCommand label +name "exa:下拉选择框示例" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:JCheckBox示例" + +\end_inset + +类似,我们设计一个下拉选择框来提供运动项目选项 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +,当选中某个运动项目时则显示相应的图片,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JComboBox示例设计" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jcombobox-demo-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JComboBox示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:JComboBox示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +注意到,下拉选择框sports需要设置在其中要显示的条目,可以通过属性对话框的model属性来设置,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JComboBox的model属性设置" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jcombobox-demo-2.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JComboBox的model属性设置 +\begin_inset CommandInset label +LatexCommand label +name "fig:JComboBox的model属性设置" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +该示例的运行结果如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JComboBox示例的运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jcombobox-demo-3.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JComboBox示例的运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:JComboBox示例的运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +其他常见控件 +\end_layout + +\begin_layout Subsubsection* +Spinner +\begin_inset CommandInset label +LatexCommand label +name "subsec:Spinner" + +\end_inset + + +\end_layout + +\begin_layout Standard +Spinner是一种便捷填写数字的控件,详情请参见示例代码: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + +及其注释。 +\end_layout + +\begin_layout Subsubsection* +Slider +\begin_inset CommandInset label +LatexCommand label +name "subsec:Slider" + +\end_inset + + +\end_layout + +\begin_layout Standard +Slider是一种通过滑动选择数字的控件,详情请参见示例代码: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + +及其注释。 +\end_layout + +\begin_layout Subsubsection* +Tabbed Pane +\begin_inset CommandInset label +LatexCommand label +name "subsec:Tabbed-Pane" + +\end_inset + + +\end_layout + +\begin_layout Standard +Tabbed Pane可以实现“标签页”,详情请参见示例代码: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + +及其注释。 +\end_layout + +\begin_layout Section +布局管理器 +\begin_inset CommandInset label +LatexCommand label +name "sec:布局管理器" + +\end_inset + + +\end_layout + +\begin_layout Standard +在图形用户界面应用程序的设计中,界面中的控件如何布局总是一个容易让人困扰的问题,有过WEB界面设计经历的读者可能对此有更深刻的体会。比如当窗口大小或者分辨率发生 +改变的时候,如何保证界面布局符合当初的设计(期望)呢?通常有两种常见的界面布局思路:绝对布局和相对布局。绝对布局是指使用绝对(像素)坐标确定控件在界面的位置,很 +显然,当窗口大小发生改变时,绝对布局的界面不会随窗口发生改变,于是导致了不能充分利用放大了的窗口或者无法适应缩小了的窗口,因此绝对布局在实际的编程中很少用到,也 +不建议使用绝对布局,本节主要阐述各种相对布局的基本思路和方法。 +\end_layout + +\begin_layout Subsection +BorderLayout +\end_layout + +\begin_layout Standard +BorderLayout很像“麻将桌”,将界面分为5个部分: +\end_layout + +\begin_layout Itemize +PAGE_START:界面的顶部 +\end_layout + +\begin_layout Itemize +PAGE_END:界面的底部 +\end_layout + +\begin_layout Itemize +LINE_START:界面的左边 +\end_layout + +\begin_layout Itemize +LINE_END:界面的右边 +\end_layout + +\begin_layout Itemize +CENTER:界面的中间 +\end_layout + +\begin_layout Standard +BorderLayout的特点是,当窗口缩放时,四周的控件只占用尽可能小的空间,中间的控件将随窗口占用尽可能多的空间。 +\end_layout + +\begin_layout Example +BorderLayout示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:BorderLayout示例" + +\end_inset + +所示,5个按钮分别位于界面的4边和中间 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见:https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/ +cn/edu/sdut/softlab +\end_layout + +\end_inset + +。注意到我们将主Panel的Layout Manager修改为了BorderLayout,而不是默认的GridBagLayout。 +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/borderlayout-demo-0.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +BorderLayout示例 +\begin_inset CommandInset label +LatexCommand label +name "fig:BorderLayout示例" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:BorderLayout示例运行结果" + +\end_inset + +所示的运行结果是放大窗口后的效果。建议读者在不同的窗口大小情况下观察BorderLayout的布局效果,以加深对BorderLayout的理解。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/borderlayout-demo-1.png + width 50line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +BorderLayout示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:BorderLayout示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +这个示例很简单,我们只是修改了Panel的Layout Manager为BorderLayout,然后将5个按钮依次放到界面的合适位置即可。 +\end_layout + +\begin_layout Exercise +尝试将 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:BorderLayout示例运行结果" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +中“Center”按钮所在的位置替换为另外一个“麻将桌”,即如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:BorderLayout练习1" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +示的效果。 +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/BorderLayout-exe1.1.png + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +BorderLayout练习1 +\begin_inset CommandInset label +LatexCommand label +name "fig:BorderLayout练习1" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +FlowLayout +\end_layout + +\begin_layout Standard +流式布局(FlowLayout)是一种很自然的布局方式,即各个控件按照加入的顺序在窗口从左向右依次排开,各自只占用尽量小的空间。 +\end_layout + +\begin_layout Example +FlowLayout示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:FlowLayout示例设计" + +\end_inset + +所示,设计一个包含若干按钮和RadioButton的应用程序 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见:https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/ +cn/edu/sdut/softlab +\end_layout + +\end_inset + +,控件使用FlowLayout布局。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/flowlayout-demo-1.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +FlowLayout示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:FlowLayout示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +默认的运行结果如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:FlowLayout示例运行结果" + +\end_inset + +所示。请尝试改变窗口的大小观察FlowLayout的布局效果。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/flowlayout-demo-2.png + width 50line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +FlowLayout示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:FlowLayout示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +本例重点有两个: +\end_layout + +\begin_layout Itemize +mainPanel采用了FlowLayout布局管理器。 +\end_layout + +\begin_layout Itemize +mainPanel的preferedSize修改为300x200,以便更好的展现FlowLayout的布局效果。 +\end_layout + +\begin_layout Subsection +CardLayout +\end_layout + +\begin_layout Example +CardLayout示例 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:CardLayout示例设计" + +\end_inset + +所示 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见:https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/ +cn/edu/sdut/softlab +\end_layout + +\end_inset + +,主界面使用默认的GridLayout,界面的上半部分放置了一个下拉选择框,根据不同的选择展示不同的card。下半部分是一个Panel,此Panel(cardP +anel)使用CardLayout,在其中添加了两个card,分别是buttonPanel和textFieldPanel。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/cardlayout-demo-1.png + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +CardLayout示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:CardLayout示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +根据选择的不同,可以看到显示了不同card的内容,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:CardLayout示例运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/gui/cardlayout-demo-2.png + width 45line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +默认运行结果 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/gui/cardlayout-demo-3.png + width 45line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +选择Card with JTextField +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +CardLayout示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:CardLayout示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +增加代码的分析,因为CardLayout的代码不是特别直观 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +CardLayout的show方法可以有选择的显示指定的card,注意到show方法的第二个参数是指定的card的name(字符串),因此在Form + Designer中要设置每个card的name属性。为了和下拉选择框的设置一致,在本例中card的name属性设置为了下拉选择框的相应文字。 +\end_layout + +\begin_layout Standard +注意到mainPanel的布局管理器我们使用了Idea默认的GridBLayout,可以尝试换为BorderLayout或者FlowLayout看看效果如何? +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +在本例中我们使用了一个常见的Java GUI界面设计技巧:通过Panel在局部组织控件,然后对Panel使用合适的布局管理器进行管理。也就是说,通常一个Java + GUI的界面设计是分为两个层面的:第一个层面,对整个界面进行合理的大体的界面划分(使用Panel);第二个层面,在每个Panel内部进行控件的合理布局。我们在 +Java GUI的综合应用举例中还会看到这种布局策略。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +GridLayout +\end_layout + +\begin_layout Standard +网格布局(GridLayout)是将整个界面划分为表格,表格的每个单元格可以放置一个控件(或者Panel),从而实现了规整的界面布局。影响GridLayout效 +果的除了表格单元格的个数之外,常见的属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:GridLayout的常见属性" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +说明 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +默认值 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizental gap +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +单元格的水平间隔的像素值,-1代表使用父容器的此设置,或者内置的10px +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +virtical gap +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +单元格的垂直间隔的像素值,-1代表使用父容器的此设置,或者内置的5px +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +same size horizentally +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +如果是true的话,所有控件在水平方向大小一致 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +false +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +same size vitically +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +如果是true的话,所有控件在垂直方向大小一致 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +false +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +margin +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +容器和控件之间的四周间隔大小 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0,0,0,0 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridLayout的常见属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:GridLayout的常见属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +GridLayout示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +使用GridLayout设计一个3x2的表格,其中放置5个按钮 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见:https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/ +cn/edu/sdut/softlab +\end_layout + +\end_inset + +,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:GridLayout示例设计" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridlayout-demo-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridLayout示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:GridLayout示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:GridLayout示例运行结果" + +\end_inset + +所示,GridLayout的用法简洁明了,请自行在Form Designer中修改相应的参数,比如virticalGap(水平间隔),horizentalGap +(垂直间隔)等观察这些参数对布局的影响。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridlayout-demo-2.png + width 50line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridLayout示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:GridLayout示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +使用Idea设计GridLayout界面 +\begin_inset Foot +status open + +\begin_layout Plain Layout +我们使用了Idea提供的GridLayoutManager,详情请参考: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://www.formdev.com/jformdesigner/doc/layouts/intellijgridlayout/ +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +的小技巧:Idea的Form Designer通常能够智能的判断应该使用多少格子来放置控件,但是我们也必须给出明确的“指令”。比如我们希望设计如下的界面: +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridlayout-tip-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +第一步,先添加三个JTextField,然后在第一个JTextField上面放置一个JLabel,如下图所示: +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridlayout-tip-2.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +第二步,需要首先将三个JTextField调整到一个水平面上,即如下图所示: +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridlayout-tip-3.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +第三步,添加另外的两个JLabel。 +\end_layout + +\begin_layout Plain Layout +如果没有在第二步首先将三个JTextField调整到一个水平面上,则继续添加JLabel时Form Designer可能会错误的领会我们的意思,从而错误的计算单 +元格的数量,读者可自行尝试和认真体会。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +GridBagLayout +\end_layout + +\begin_layout Standard +网格袋布局(GridBagLayout)显然是GridLayout的扩展:GridLayout只允许控件放置在一个单元格中,而GridBagLayout允许一个 +控件占用多个单元格,因而GridBaglayout更加灵活,控制选项(属性)也比较多,常见的属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:GridBagLayout的常见属性" + +\end_inset + +所示 +\begin_inset Foot +status open + +\begin_layout Plain Layout +本书以JetBrain Idea提供的Form Designer为蓝本说明GridBagLayout的常见属性,和标准的Java Swing的GridBagLa +yout的属性略有出入。 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +说明 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +默认值 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +grid x +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +控件所占单元格的起始x坐标(左上角) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +grid y +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +控件所占单元格中的起始y坐标(左上角) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +grid width +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +控件横向占用的单元格数 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +grid height +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +控件纵向占用的单元格数 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizental align +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +横向的对齐方式,Fill意味着充满可能的横向空间(受weight x设置的影响) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Fill +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +virtical align +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +纵向的对齐方式,Fill意味着充满可能的纵向空间(受weight y设置的影响) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Center +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +weight x +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +横向扩展的权重。如果值为0则横向不扩展,即控件只占用可能小的空间;通常此值在0-1之间设置。 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0.0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +weight y +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +纵向扩展的权重。如果值为0则纵向不扩展,即控件只占用可能小的空间;通常此值在0-1之间设置。 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0.0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +insets +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +控件的外边距 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0,0,0,0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ipad x +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +横向的内边距素数,决定了控件距离单元格的边线有多远 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ipad y +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +纵向的内边距素数,决定了控件距离单元格的边线有多远 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridBagLayout的常见属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:GridBagLayout的常见属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +在Idea的Form Designer中,grid x/grid y/grid width/grid height属性是通过拖放控件自动设置的,无需手工设置。实 +际上,Form Designer的属性对话框没有提供编辑这4个属性的功能。 +\end_layout + +\begin_layout Plain Layout +如果熟悉CSS的盒子模型的话,insets相当于CSS盒子模型的margin,ipadx/ipady相当于CSS盒子模型的padding。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +GridBagLayout示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:GridBagLayout示例设计" + +\end_inset + +所示,我们设计一个包含几个按钮的界面,使用GridBagLayout布局管理器。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridbaglayout-demo-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridBagLayout示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:GridBagLayout示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:GridBagLayout示例运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridbaglayout-demo-2.png + scale 70 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridBagLayout示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:GridBagLayout示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +本例中各控件的属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:GridBagLayout示例应用中的控件属性" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +控件 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +属性设置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ButtonA +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 0,grid y = 0 +\end_layout + +\begin_layout Plain Layout +grid width = 1, grid height = 1 +\end_layout + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ButtonB +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 1,grid y = 0 +\end_layout + +\begin_layout Plain Layout +grid width = 1, grid height = 1 +\end_layout + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +Another Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 2,grid y = 0 +\end_layout + +\begin_layout Plain Layout +grid width = 1, grid height = 1 +\end_layout + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +A Long Name Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 0,grid y = 1 +\end_layout + +\begin_layout Plain Layout +grid width = 3, grid height = 1 +\end_layout + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ButtonC +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 0,grid y = 2 +\end_layout + +\begin_layout Plain Layout +grid width = 1, grid height = 1 +\end_layout + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ButtonD +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 0,grid y = 3 +\end_layout + +\begin_layout Plain Layout +grid width = 1, grid height = 1 +\end_layout + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +Last Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 1,grid y = 2 +\end_layout + +\begin_layout Plain Layout +grid width = 2, grid height = 2 +\end_layout + +\begin_layout Plain Layout +h align = Center, v align = Fill +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridBagLayout示例应用中的控件属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:GridBagLayout示例应用中的控件属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +请读者尝试 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:控件属性的各种组合方式" + +\end_inset + +的控件属性组合方式,观察GridBagLayout在界面布局中的灵活性。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +测试场景 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +控件 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +属性设置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +只设置ButtonA的属性,其他控件属性不变 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +ButtonA +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +h align = Center, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 1, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +只设置Last Button的属性,其他控件属性不变 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Last Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +h align = Center, v align = Fill +\end_layout + +\begin_layout Plain Layout +weight x = 1, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +只设置Last Button的属性,其他控件属性不变 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Last Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +h align = Fill, v align = Fill +\end_layout + +\begin_layout Plain Layout +weight x = 1, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +只设置Last Button的属性,其他控件属性不变 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Last Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +h align = Fill, v align = Fill +\end_layout + +\begin_layout Plain Layout +weight x = 1, weight y = 1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +只设置Last Button的属性,其他控件属性不变 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Last Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 1, weight y = 1 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +控件属性的各种组合方式 +\begin_inset CommandInset label +LatexCommand label +name "tab:控件属性的各种组合方式" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +JAVA图形用户界面的事件机制 +\begin_inset CommandInset label +LatexCommand label +name "sec:JAVA图形用户界面的事件机制" + +\end_inset + + +\end_layout + +\begin_layout Subsection +事件机制的基本原理 +\end_layout + +\begin_layout Standard +事件机制是指代码如何对界面的点击、输入等事件做出响应,我们在前面的例子中已经多次使用了Swing的事件机制。Swing事件机制的三个要点是: +\end_layout + +\begin_layout Itemize +事件源(Event Source):即触发事件的控件,比如按钮、文本框等。 +\end_layout + +\begin_layout Itemize +事件对象(Event Object):描述事件的封装对象,其中包括了事件源、事件发生事件、事件相关参数(比如鼠标事件包括鼠标点击的坐标、鼠标点击次数等)等。 +\end_layout + +\begin_layout Itemize +监听器(Listener):当事件发生时Java会自动调用的方法被称为监听器。 +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Swing事件机制" + +\end_inset + +说明了按钮事件的处理过程 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这里对“注册”的原理没有展开说明,需要说明Event Loop的过程吗?需要说明注册和Java虚拟机的关系吗? +\end_layout + +\end_inset + + +\begin_inset Note Note +status open + +\begin_layout Plain Layout +是否可以在这里增加一个设计模式的示例?比如设计一个Container模拟OS,设计一个Listener模拟按钮、checkbox等 +\end_layout + +\end_inset + +,其他类型的事件处理过程与此类似。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/swing-event-model.eps + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Swing事件机制(以按钮为例) +\begin_inset CommandInset label +LatexCommand label +name "fig:Swing事件机制" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +控件的常见监听器 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整的Java GUI控件和事件监听器的对照表参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +http://docs.oracle.com/javase/tutorial/uiswing/events/eventsandcomponents.html +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:控件的常见监听器" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +控件 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +常用监听器 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +JButton +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +ActionListener:响应鼠标左键单击和回车事件 +\end_layout + +\begin_layout Plain Layout +MouseListener:响应除左键单击外的其他的各种鼠标事件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +JTextField +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +ActionListener:响应在输入框回车事件 +\end_layout + +\begin_layout Plain Layout +FocusListener:响应获得和失去焦点事件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +JRadioButton +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +ActionListener:响应选项选择事件 +\end_layout + +\begin_layout Plain Layout +MouseListener:响应各种鼠标事件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +JCheckBox +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +ActionListener:响应选项选择事件 +\end_layout + +\begin_layout Plain Layout +MouseListener:响应各种鼠标事件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +JComboBox +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +ActionListener:响应选项选择事件 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +控件的常见监听器 +\begin_inset CommandInset label +LatexCommand label +name "tab:控件的常见监听器" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +监听器类的几种情形 +\end_layout + +\begin_layout Standard +注意到注册监听器的方法:src.addXxxListener(listenerObject)的参数是一个实现了监听器接口的对象,即通过这个方法告诉Java虚拟机, +当src(事件源)对象产生了一个Xxx类型的事件时,需要调用listenerObject中的相关方法进行事件处理。在实现监听器时,通常有如下的几种策略,以按钮的 +单击事件actionEvent为例: +\end_layout + +\begin_layout Itemize +主类直接实现XxxListener接口或者扩展XxxHandler类,比如: +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class FrameDemo implements ActionListener { +\end_layout + +\begin_layout Plain Layout + + private JButton button; +\end_layout + +\begin_layout Plain Layout + + public FrameDemo() { +\end_layout + +\begin_layout Plain Layout + + button = new JButton("OK"); +\end_layout + +\begin_layout Plain Layout + + button.addActionListener(this); // 注册事件监听器。由于FrameDemo本身实现ActionListener接 +口,因此这里直接使用this作为实现了事件监听器接口的对象。 +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + public void actionPerformed(ActionEvent event) { +\end_layout + +\begin_layout Plain Layout + + // 事件处理代码 +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +使用匿名内部类实现监听器接口,比如: +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class FrameDemo { +\end_layout + +\begin_layout Plain Layout + + private JButton button; +\end_layout + +\begin_layout Plain Layout + + public FrameDemo() { +\end_layout + +\begin_layout Plain Layout + + button = new JButton("OK"); +\end_layout + +\begin_layout Plain Layout + + button.addActionListener(new ActionListener() { // 匿名内部类实现ActionListener接 +口 +\end_layout + +\begin_layout Plain Layout + + @Override +\end_layout + +\begin_layout Plain Layout + + public void actionPerformed(ActionEvent event) { +\end_layout + +\begin_layout Plain Layout + + // 事件处理代码 +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + }); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +使用独立的类实现监听器接口,比如: +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class FrameDemo { +\end_layout + +\begin_layout Plain Layout + + private JButton button; +\end_layout + +\begin_layout Plain Layout + + public FrameDemo() { +\end_layout + +\begin_layout Plain Layout + + button = new JButton("OK"); +\end_layout + +\begin_layout Plain Layout + + button.addActionListener(new ButtonListener()); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +// 独立的事件监听器类,实现了ActionListener接口 +\end_layout + +\begin_layout Plain Layout + +class ButtonListener implements ActionListener { +\end_layout + +\begin_layout Plain Layout + + @Override +\end_layout + +\begin_layout Plain Layout + + public void actionPerformed(ActionEvent event) { +\end_layout + +\begin_layout Plain Layout + + // 事件处理代码 +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在大多数情况下,我们建议使用匿名内部类实现监听器接口,代码更简洁,封装性更好。 +\end_layout + +\begin_layout Section +Java GUI综合应用举例 +\begin_inset CommandInset label +LatexCommand label +name "sec:Java-GUI综合应用举例" + +\end_inset + + +\end_layout + +\begin_layout Example +计算器 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +这是一个典型的可以使用GridBagLayout进行界面设计的应用场合,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:计算器的界面设计" + +\end_inset + +所示。为了更好的适应窗口大小,界面中的所有控件设置了如下属性: +\end_layout + +\begin_layout Itemize +horizental align:Fill +\end_layout + +\begin_layout Itemize +virtical align: Fill +\end_layout + +\begin_layout Itemize +weight x : 1.0 +\end_layout + +\begin_layout Itemize +weight y : 1.0 +\end_layout + +\begin_layout Standard +完整的代码参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "Caculator.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/gui/src/cn/edu/sdut/softlab/Caculator.java" +lstparams "caption={Caculator.java},label={Caculator.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/caculator-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +计算器的界面设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:计算器的界面设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:计算器的运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/caculator-2.png + width 60line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +计算器的运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:计算器的运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +本例为了简化起见,表达式的求值借用了JDK内置的JavaScript引擎,有兴趣的读者可以自行实现一个表达式求值的引擎或者方法。 +\end_layout + +\begin_layout Exercise +请尝试使用GridLayout重新设计计算器(提示:首先使用GridLayout将界面分为上下两部分,上部分是一个Panel显示计算结果,使用任意的Layout +即可;下部分是一个显示计算按钮的Panel,使用GridLayout布局)。 +\end_layout + +\end_body +\end_document diff --git a/guide/lecture_guide/lecture13.lyx b/guide/lecture_guide/lecture13.lyx new file mode 100644 index 0000000..b03b32c --- /dev/null +++ b/guide/lecture_guide/lecture13.lyx @@ -0,0 +1,9852 @@ +#LyX 2.3 created this file. For more info see http://www.lyx.org/ +\lyxformat 544 +\begin_document +\begin_header +\save_transient_properties true +\origin unavailable +\textclass ctex-book +\begin_preamble +\input{../../../writing-common/book-preamble.tex} +\end_preamble +\use_default_options true +\begin_modules +tip-inset +note-inset +warning-inset +theorems-bytype +theorems-chap-bytype +logicalmkup +coderemarks +\end_modules +\maintain_unincluded_children false +\begin_local_layout +PackageOptions url hyphens +\end_local_layout +\language chinese-simplified +\language_package default +\inputencoding utf8-plain +\fontencoding global +\font_roman "default" "DejaVu Sans" +\font_sans "default" "DejaVu Serif" +\font_typewriter "default" "DejaVu Sans Mono" +\font_math "auto" "auto" +\font_default_family default +\use_non_tex_fonts true +\font_sc false +\font_osf false +\font_sf_scale 100 100 +\font_tt_scale 100 100 +\use_microtype false +\use_dash_ligatures true +\graphics default +\default_output_format pdf4 +\output_sync 0 +\bibtex_command default +\index_command default +\float_placement tbph +\paperfontsize default +\spacing single +\use_hyperref true +\pdf_bookmarks true +\pdf_bookmarksnumbered false +\pdf_bookmarksopen false +\pdf_bookmarksopenlevel 3 +\pdf_breaklinks true +\pdf_pdfborder true +\pdf_colorlinks true +\pdf_backref false +\pdf_pdfusetitle true +\papersize default +\use_geometry false +\use_package amsmath 1 +\use_package amssymb 1 +\use_package cancel 1 +\use_package esint 1 +\use_package mathdots 1 +\use_package mathtools 1 +\use_package mhchem 1 +\use_package stackrel 1 +\use_package stmaryrd 1 +\use_package undertilde 1 +\cite_engine basic +\cite_engine_type default +\biblio_style plain +\use_bibtopic false +\use_indices false +\paperorientation portrait +\suppress_date false +\justification true +\use_refstyle 1 +\use_minted 0 +\boxbgcolor #dad3d7 +\index Index +\shortcut idx +\color #008000 +\end_index +\secnumdepth 3 +\tocdepth 2 +\paragraph_separation indent +\paragraph_indentation default +\is_math_indent 0 +\math_numbering_side default +\quotes_style english +\dynamic_quotes 0 +\papercolumns 1 +\papersides 2 +\paperpagestyle default +\tracking_changes false +\output_changes false +\html_math_output 0 +\html_css_as_file 0 +\html_be_strict false +\end_header + +\begin_body + +\begin_layout Standard +\align center + +\size larger +\bar under +山东理工大学教案 +\end_layout + +\begin_layout Standard +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +第十三次课 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +教学课型:理论课□√ 实验课□√ 习题课□ 实践课□ 技能课□ 其它□ +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +主要教学内容 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:布局管理器" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:布局管理器" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:BorderLayout" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "subsec:BorderLayout" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:FlowLayout" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "subsec:FlowLayout" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:CardLayout" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "subsec:CardLayout" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:GridLayout" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "subsec:GridLayout" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:GridBagLayout" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "subsec:GridBagLayout" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +重点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +Java布局管理器的意义; +\end_layout + +\begin_layout Enumerate +常见的Java布局管理器及其使用场合; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +难点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +常见布局管理器的综合运用; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +课程目标及要求 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +课程目标:课程目标1 +\end_layout + +\begin_layout Plain Layout +要求: +\end_layout + +\begin_layout Enumerate +熟练掌握Swing的布局管理器的基本设计思想; +\end_layout + +\begin_layout Enumerate +基本能够综合使用布局管理器设计常见的用户界面; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +教学方法和手段 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +板书和多媒体相结合,边讲边练,当堂消化。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +讨论、思考题 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +使用布局管理器设计界面有什么好处? +\end_layout + +\begin_layout Enumerate +设计复杂的界面时,一般要遵循什么原则?即如何综合运用布局管理器设计复杂的用户界面? +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +参考资料 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Chapter +图形用户界面设计 +\end_layout + +\begin_layout Standard +\align center +\begin_inset Graphics + filename ../imgs/gui/gui.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Section +Java的图形用户界面(GUI)设计概述 +\begin_inset CommandInset label +LatexCommand label +name "sec:Java的图形用户界面(GUI)设计概述" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java的图形用户界面( +\begin_inset Index idx +status open + +\begin_layout Plain Layout +GUI +\end_layout + +\end_inset + +GUI)是由 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JFC +\end_layout + +\end_inset + +JFC(Java Foundation Classes)支撑的,JFC包括了以下几个方面: +\end_layout + +\begin_layout Itemize +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Swing +\end_layout + +\end_inset + +Swing GUI组件:包含了图形用户界面设计中的人机交互组件,从最简单的按钮到复杂的图表等无所不包,这是我们学习的重点内容。 +\end_layout + +\begin_layout Itemize +可插拔的Look-and-Feel支持:Java图形用户界面支持可配置的Look-and-Feel切换,可以很容易的实现不同操作系统下的界面统一。 +\end_layout + +\begin_layout Itemize +辅助API:支持读屏幕等操作。 +\end_layout + +\begin_layout Itemize +Java 2D API:完善的2D绘图API。 +\end_layout + +\begin_layout Itemize +\begin_inset Index idx +status open + +\begin_layout Plain Layout +国际化 +\end_layout + +\end_inset + +国际化支持:秉承Java一贯的国际化支持,能够方便的在GUI中处理各种编码的文字。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +Swing是在早期的Java GUI应用程序设计接口AWT的基础上发展起来的,目前是Java GUI应用程序设计的官方标准。除了Swing之外,Eclipse( +www.eclipse.org)组织也发布了一套Java图形用户界面的设计库SWT(Standard Widget Toolkit),主要配合Eclipse的RCP +(Rich Client Program)应用程序开发,详情可参考:https://www.eclipse.org/swt/ +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +Swing入门 +\begin_inset CommandInset label +LatexCommand label +name "sec:Swing入门" + +\end_inset + + +\end_layout + +\begin_layout Standard +本节以JetBrain Idea为例说明如何创建和运行简单的 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Swing +\end_layout + +\end_inset + +Swing应用程序。 +\end_layout + +\begin_layout Example +使用Idea创建一个简单的Swing应用程序,将人民币转换为美元。 +\end_layout + +\begin_layout Paragraph* +步骤1 +\end_layout + +\begin_layout Standard +创建一个新的Java项目,见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:新建一个Java项目" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/getting-started-1.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +新建一个Java项目 +\begin_inset CommandInset label +LatexCommand label +name "fig:新建一个Java项目" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤2 +\end_layout + +\begin_layout Standard +在接下来的项目配置窗口中,可以不选择从模板创建项目,因为我们要创建一个GUI应用程序,命令行应用的模板没有实质用处,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:跳过从模板创建项目" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/getting-started-2.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +跳过从模板创建项目 +\begin_inset CommandInset label +LatexCommand label +name "fig:跳过从模板创建项目" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤3 +\end_layout + +\begin_layout Standard +给项目起个名字,这里叫做“gui”,并选择项目所在的目录,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:给项目起个名字" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/getting-started-3.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +给项目起个名字 +\begin_inset CommandInset label +LatexCommand label +name "fig:给项目起个名字" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤4 +\end_layout + +\begin_layout Standard +在项目的“project视图”中,右键点击src,在弹出的菜单中选择New->GUI Form,新建一个Form表单 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Form表单 +\end_layout + +\end_inset + +,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:准备新建一个Form表单" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-1.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +准备新建一个Form表单 +\begin_inset CommandInset label +LatexCommand label +name "fig:准备新建一个Form表单" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +如果在菜单中没有出现GUI Form子菜单,系没有安装Form Designer +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Form Designer +\end_layout + +\end_inset + +插件所致,请在系统设置中激活Form Designer即可,方法是在File->Settings...菜单中搜索“UI Designer”插件并安装激活,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:安装并激活UI-Designer插件" + +\end_inset + +所示。 +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/active-ui-designer.png + width 60line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +安装并激活UI Designer插件 +\begin_inset CommandInset label +LatexCommand label +name "fig:安装并激活UI-Designer插件" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +图片和文字可能不在一个页面,应该想办法处理一下 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤5 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:给Form起个名字" + +\end_inset + +所示,给将要创建的Form起个名字,这里叫做“RMB2DollarConverter”,选择布局管理器(此处先认可默认设置,随后可以更改)。注意要勾选(默认已经 +勾选了) +\begin_inset Quotes erd +\end_inset + +create bound class +\begin_inset Quotes erd +\end_inset + +选项,即同时创建和这个Form绑定在一起的Java类。这个Java类我们将来用于显示和操作这个Form。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-2.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +给Form起个名字 +\begin_inset CommandInset label +LatexCommand label +name "fig:给Form起个名字" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤6 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:空白的Form设计窗口" + +\end_inset + +所示,在新建Form后会呈现一个空白的Form设计窗口,其主要组成部分为: +\end_layout + +\begin_layout Itemize +界面组件关系图:在这个窗口中展示了组件的“父子”关系,目前只有一个JPanel组件,随后我们会加入更多组件,可以通过这个窗口直观的查看组件之间的关系。也可以通过 +这个窗口快捷的选择某个组件进行操作。 +\end_layout + +\begin_layout Itemize +组件属性窗:当在主设计界面或者界面组件关系窗口中选择了某个组件时,组件属性窗的内容将随之改变。可以通过这个窗口方便的了解界面组件拥有哪些属性,当然,更重要的是, +可以设置界面组件的属性值。 +\end_layout + +\begin_layout Itemize +主设计界面:可以拖放“组件面板”中的组件导主设计界面,主设计界面会根据使用的布局管理器的不同,自动摆放组件。 +\end_layout + +\begin_layout Itemize +组件面板:列出了各种Swing界面组件,可以方便的拖放到主设计界面。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-3.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +空白的Form设计窗口 +\begin_inset CommandInset label +LatexCommand label +name "fig:空白的Form设计窗口" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤7 +\end_layout + +\begin_layout Standard +首先在“界面组件关系窗口”中选择目前唯一的组件Panel,然后在组件属性窗口中编辑“field name”属性,设置其值为“mainPanel +\begin_inset Quotes erd +\end_inset + +。这里的值是什么并不重要的,重要的是必须给主Panel设置一个名字,否则将来无法显示这个Panel。 +\end_layout + +\begin_layout Standard +在这里,我们也将mainPanel的 +\begin_inset Quotes erd +\end_inset + +Layout Manager +\begin_inset Quotes erd +\end_inset + +(布局管理器)修改为更为简单的 +\begin_inset Quotes erd +\end_inset + +FlowLayout +\begin_inset Quotes erd +\end_inset + +,我们将在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:布局管理器" + +\end_inset + +一节详细的阐述各种布局管理器 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +布局管理器 +\end_layout + +\end_inset + +的用法。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-4.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +给主Panel起个名字 +\begin_inset CommandInset label +LatexCommand label +name "fig:给主Panel起个名字" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤8 +\end_layout + +\begin_layout Standard +在“组件面板”窗口选择JLabel组件拖放到主设计界面,可以看到在“界面组件关系”窗口中,JLabel包含在mainPanel中。这里只是简单的设置这个JLab +el的text属性为“人民币:”即可。JLabel的目的是显示一个标签 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +标签 +\end_layout + +\end_inset + +,我们将在 +\begin_inset CommandInset ref +LatexCommand formatted +reference "subsec:JLabel" + +\end_inset + +一节详细讨论Jlabel的用法。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-5.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +添加一个简单的Label +\begin_inset CommandInset label +LatexCommand label +name "fig:添加一个简单的Label" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤9 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:添加JTextField组件" + +\end_inset + +所示,接着添加一个JTextField +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JTextField +\end_layout + +\end_inset + +组件到主设计界面。这个JTextField我们用来输入人民币数额,因此要设置其 +\begin_inset Quotes erd +\end_inset + +field name +\begin_inset Quotes erd +\end_inset + +属性。为了更好的显示这个输入框,也设置了这个JTextField的默认宽度(preferedSize->width)和默认显示的文字(text属性)。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-6.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +添加JTextField组件 +\begin_inset CommandInset label +LatexCommand label +name "fig:添加JTextField组件" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤10 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:添加转换按钮" + +\end_inset + +所示,再增加一个“转换”按钮 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +按钮 +\end_layout + +\end_inset + +,设置这个按钮的field name和text属性。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-7.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +添加转换按钮 +\begin_inset CommandInset label +LatexCommand label +name "fig:添加转换按钮" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤11 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:添加显示转换结果的JLabel" + +\end_inset + +所示,在界面中再添加一个用于显示转换结果的JLabel。由于我们要通过程序设置这个JLabel的text属性,因此要设置这个JLabel的field + name属性。为了能够更好的显示转换后的结果,也有设置这个JLabel的宽度,这里设置为100(像素值)。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-8.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +添加显示转换结果的JLabel +\begin_inset CommandInset label +LatexCommand label +name "fig:添加显示转换结果的JLabel" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤12 +\begin_inset CommandInset label +LatexCommand label +name "par:步骤12" + +\end_inset + + +\end_layout + +\begin_layout Standard +界面的设计工作基本就绪,下面我们为按钮设计处理代码。如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:准备创建Listener" + +\end_inset + +所示,在主设计界面的“转换”按钮上点击右键,在弹出的菜单中选择“create Listener”,准备创建一段点击此按钮的响应代码。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-9.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +准备创建Listener +\begin_inset CommandInset label +LatexCommand label +name "fig:准备创建Listener" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤13 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:选择Listener的类型" + +\end_inset + +所示,在接下来的窗口中选择Listener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Listener +\end_layout + +\end_inset + +的类型为“ActionListener”。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-10.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +选择Listener的类型 +\begin_inset CommandInset label +LatexCommand label +name "fig:选择Listener的类型" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤14 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:选择需要覆盖的方法" + +\end_inset + +所示,在接下来的窗口中,选择ActionListener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +ActionListener +\end_layout + +\end_inset + +需要覆盖的方法。这里只有一个选项,已经自动选中了。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-11.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +选择需要覆盖的方法 +\begin_inset CommandInset label +LatexCommand label +name "fig:选择需要覆盖的方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +点击 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:选择需要覆盖的方法" + +\end_inset + +中的“OK”按钮后,在所绑定的方法中自动添加了一个构造方法 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +构造方法 +\end_layout + +\end_inset + +,内容如下(行5-7是自己编写的): +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + public RMB2DollarConverter() { +\end_layout + +\begin_layout Plain Layout + + convertButton.addActionListener(new ActionListener() { +\end_layout + +\begin_layout Plain Layout + + @Override +\end_layout + +\begin_layout Plain Layout + + public void actionPerformed(ActionEvent actionEvent) { +\end_layout + +\begin_layout Plain Layout + + // 获取文本输入框的文字内容并转换为double +\end_layout + +\begin_layout Plain Layout + + Double rmb = Double.valueOf(rmbTextField.getText()); +\end_layout + +\begin_layout Plain Layout + + dollarLabel.setText(String.valueOf(rmb / 7.0)); // 假设当前人民币和美元汇率为7.0 +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + }); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +这是GUI应用程序事件处理的基本方法,我们将在 +\begin_inset CommandInset ref +LatexCommand formatted +reference "sec:JAVA图形用户界面的事件机制" + +\end_inset + +一节中具体讨论。 +\end_layout + +\begin_layout Paragraph* +步骤15 +\end_layout + +\begin_layout Standard +最后一步,我们需要在类RMB2DollarConverter中增加一个main方法并初始化和显示应用程序窗口,JetBrain Idea提供了自动化的代码生成工 +具,只需要在代码的合适位置(希望插入main方法的位置)按下Alt+Insert +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Alt+Insert +\end_layout + +\end_inset + +组合键,在如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:准备插入main方法" + +\end_inset + +所示的窗口中选择 +\begin_inset Quotes erd +\end_inset + +Form main() +\begin_inset Quotes erd +\end_inset + +即可自动创建main方法如下: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + public static void main(String[] args) { +\end_layout + +\begin_layout Plain Layout + + JFrame frame = new JFrame("RMB2DollarConverter"); +\end_layout + +\begin_layout Plain Layout + + frame.setContentPane(new RMB2DollarConverter().mainPanel); +\end_layout + +\begin_layout Plain Layout + + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); +\end_layout + +\begin_layout Plain Layout + + frame.pack(); +\end_layout + +\begin_layout Plain Layout + + frame.setVisible(true); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-12.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +准备插入main方法 +\begin_inset CommandInset label +LatexCommand label +name "fig:准备插入main方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +经过了以上的15个步骤,现在终于可以运行这个应用程序了 +\begin_inset Foot +status open + +\begin_layout Plain Layout +本例的完整代码请参见:https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui +\end_layout + +\end_inset + +。和运行其他Java应用程序的方法一样,运行RMB2DollarConverter类结果如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand formatted +reference "fig:RMB2DollarConverter的运行结果" + +\end_inset + +所示。可以在输入框输入人民币数额,然后点击“转换”按钮获得相应的美元数。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/RMB2DollarConverter-output.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +RMB2DollarConverter的运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:RMB2DollarConverter的运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +虽然在上面我们使用了15个步骤创建了一个简单的GUI应用程序,其实关键的步骤是4个,如下图所示: +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset include +LatexCommand input +filename "../imgs/gui/basic-gui-flow.pgf" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status collapsed + +\begin_layout Plain Layout +你可能会问,在类RMB2DollarConverter中的几个私有属性(对象):mainPanel、rmbTextField等是什么时候初始化的?很好的问题! +\end_layout + +\begin_layout Plain Layout +实际上,Idea通过一个xml文件(RMB2DollarConvert.form)保存了界面中所包含的组件及其属性和相互关系,在编译的时候,Idea会自动读取这个 +界面配置文件并生成创建界面中的组件的构造方法,也就是说,mainPanel等对象其实是Idea帮我们创建了的,我们可以直接拿来就用。 +\end_layout + +\begin_layout Plain Layout +可以通过反编译class文件看到这一点,在构造方法中的setupUI方法创建了各个界面组件对象(部分删减,请自行运行jad RMB2DollarConverte +r获得完整的反编译后的文件): +\end_layout + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class RMB2DollarConverter +\end_layout + +\begin_layout Plain Layout + +{ +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + public static void main(String args[]) +\end_layout + +\begin_layout Plain Layout + + { +\end_layout + +\begin_layout Plain Layout + + JFrame frame = new JFrame("RMB2DollarConverter"); +\end_layout + +\begin_layout Plain Layout + + frame.setContentPane((new RMB2DollarConverter()).mainPanel); +\end_layout + +\begin_layout Plain Layout + + frame.setDefaultCloseOperation(3); +\end_layout + +\begin_layout Plain Layout + + frame.pack(); +\end_layout + +\begin_layout Plain Layout + + frame.setVisible(true); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + public RMB2DollarConverter() +\end_layout + +\begin_layout Plain Layout + + { +\end_layout + +\begin_layout Plain Layout + + setupUI(); +\end_layout + +\begin_layout Plain Layout + + convertButton.addActionListener(new ActionListener() { +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + public void actionPerformed(ActionEvent actionEvent) +\end_layout + +\begin_layout Plain Layout + + { +\end_layout + +\begin_layout Plain Layout + + Double rmb = Double.valueOf(rmbTextField.getText()); +\end_layout + +\begin_layout Plain Layout + + dollarLabel.setText(String.valueOf(rmb.doubleValue() / 7D)); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + }); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + private void setupUI() +\end_layout + +\begin_layout Plain Layout + + { +\end_layout + +\begin_layout Plain Layout + + JPanel jpanel; +\end_layout + +\begin_layout Plain Layout + + JLabel jlabel; +\end_layout + +\begin_layout Plain Layout + + jpanel = new JPanel(); +\end_layout + +\begin_layout Plain Layout + + mainPanel = jpanel; +\end_layout + +\begin_layout Plain Layout + + jpanel.setLayout(new FlowLayout(1, 5, 5)); +\end_layout + +\begin_layout Plain Layout + + jlabel = new JLabel(); +\end_layout + +\begin_layout Plain Layout + + jlabel.setText(" +\backslash +u4EBA +\backslash +u6C11 +\backslash +u5E01 +\backslash +uFF1A"); +\end_layout + +\begin_layout Plain Layout + + jpanel.add(jlabel); +\end_layout + +\begin_layout Plain Layout + + JTextField jtextfield; +\end_layout + +\begin_layout Plain Layout + + jtextfield = new JTextField(); +\end_layout + +\begin_layout Plain Layout + + rmbTextField = jtextfield; +\end_layout + +\begin_layout Plain Layout + + jtextfield.setMinimumSize(new Dimension(14, 29)); +\end_layout + +\begin_layout Plain Layout + + jtextfield.setPreferredSize(new Dimension(60, 29)); +\end_layout + +\begin_layout Plain Layout + + jtextfield.setText("#.##"); +\end_layout + +\begin_layout Plain Layout + + jtextfield.setToolTipText(" +\backslash +u8BF7 +\backslash +u8F93 +\backslash +u5165 +\backslash +u4EBA +\backslash +u6C11 +\backslash +u5E01 +\backslash +u6570 +\backslash +u989D"); +\end_layout + +\begin_layout Plain Layout + + jpanel.add(jtextfield); +\end_layout + +\begin_layout Plain Layout + + JButton jbutton; +\end_layout + +\begin_layout Plain Layout + + jbutton = new JButton(); +\end_layout + +\begin_layout Plain Layout + + convertButton = jbutton; +\end_layout + +\begin_layout Plain Layout + + jbutton.setText(" +\backslash +u8F6C +\backslash +u6362"); +\end_layout + +\begin_layout Plain Layout + + jpanel.add(jbutton); +\end_layout + +\begin_layout Plain Layout + + JLabel jlabel1; +\end_layout + +\begin_layout Plain Layout + + jlabel1 = new JLabel(); +\end_layout + +\begin_layout Plain Layout + + dollarLabel = jlabel1; +\end_layout + +\begin_layout Plain Layout + + jlabel1.setPreferredSize(new Dimension(100, 21)); +\end_layout + +\begin_layout Plain Layout + + jlabel1.setText(" +\backslash +u7F8E +\backslash +u5143 +\backslash +uFF1A"); +\end_layout + +\begin_layout Plain Layout + + jpanel.add(jlabel1); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + private JPanel mainPanel; +\end_layout + +\begin_layout Plain Layout + + private JTextField rmbTextField; +\end_layout + +\begin_layout Plain Layout + + private JButton convertButton; +\end_layout + +\begin_layout Plain Layout + + private JLabel dollarLabel; +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status collapsed + +\begin_layout Plain Layout +在Idea的Form Designer中,我们看到可以直接拖放各种控件到应用程序界面中,并且可以直观的通过“属性查看器”查看和修改控件的属性,其中一个重要的属性 +是field name属性,即属性的名称。什么时候需要给控件的field name属性赋值,什么时候不需要理会field name属性呢?简单的说,如果我们在程 +序中需要获得这个控件的其他属性,比如输入的文字,或者需要在程序运行期间通过程序改变这个控件的状态,则需要给这个控件的field name赋值。比如常见的JLab +el控件一般是不需要field name属性的,而JTextField则需要field name属性。 +\end_layout + +\begin_layout Plain Layout +进一步的观察我们可以发现,只有给控件一个field name属性值,Idea才能在绑定的类中自动创建私有的属性对象(变量)表示这个控件,变量的名字就是field + name属性的值。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +GUI的顶级容器类 +\begin_inset CommandInset label +LatexCommand label +name "sec:GUI的顶级容器类" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java的图形用户界面也是“面向对象”的,比如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java图形用户界面应用程序的大致布局" + +\end_inset + +是常见的一个窗口应用程序,我们从Java的观点来看,可以分为如下的几部分: +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/swing-app-outline.png + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java图形用户界面应用程序的大致布局 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java图形用户界面应用程序的大致布局" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +整个应用程序框架使用JFrame +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JFrame +\end_layout + +\end_inset + +来表示,在JFrame内部布置了菜单栏(JMenuBar)、工具栏(JToolBar)、内容区(ContentPane),我们最经常操作的区域是ContentP +ane,即几乎所有的界面设计工作集中在ContentPane上面。 +\end_layout + +\begin_layout Standard +所以,JFrame是一个顶层的容器 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +容器 +\end_layout + +\end_inset + +,其他所有的界面组件都放置在顶层容器 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +顶层容器 +\end_layout + +\end_inset + +之中,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java-GUI应用程序的基本结构" + +\end_inset + +所示。除了JFrame之外,Java也提供了JDialog、JApplet +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JApplet +\end_layout + +\end_inset + +顶层容器,分别用于对话框的设计和Applet +\begin_inset Foot +status open + +\begin_layout Plain Layout +一种已经没落的技术。 +\end_layout + +\end_inset + +的设计。本章重点介绍基于JFrame的Java图形用户界面设计,JDialog +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JDialog +\end_layout + +\end_inset + +的用法于此类似。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jframe-overview.eps + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java GUI应用程序的基本结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java-GUI应用程序的基本结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +不介绍分层的面板会有影响吗? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +下面的代码展示了 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java-GUI应用程序的基本结构" + +\end_inset + +中的组件间的关系: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +JFrame frame = new JFrame("标题栏内容"); +\end_layout + +\begin_layout Plain Layout + +frame.getContentPane().add(new JLabel("a label", BorderLayout.TOP)); +\end_layout + +\begin_layout Plain Layout + +frame.getContentPane().add(new JTextField("##.##", BorderLayout.BOTTOM)); +\end_layout + +\begin_layout Plain Layout + +JPanel panel = new JPanel(); +\end_layout + +\begin_layout Plain Layout + +panel.add(new JLabel("another label")); +\end_layout + +\begin_layout Plain Layout + +panel.add(new JCheckBox(...)); +\end_layout + +\begin_layout Plain Layout + +frame.add(panel, BorderLayout.CENTER); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +Swing控件 +\begin_inset CommandInset label +LatexCommand label +name "sec:Swing控件" + +\end_inset + + +\end_layout + +\begin_layout Subsection +JLabel +\begin_inset CommandInset label +LatexCommand label +name "subsec:JLabel" + +\end_inset + + +\end_layout + +\begin_layout Standard +Label(文本标签)也许是最简单的Swing控件了,一般用来表示界面上的几个字符或者一段提示性文字、展示输出结果、图标等。 +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JLabel +\end_layout + +\end_inset + +JLabel的主要属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:JLabel的主要属性" + +\end_inset + +所示(每个属性对应一对get/set方法),请参照Form Designer +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Form Designer +\end_layout + +\end_inset + +的属性对话框了解属性值的可能取值范围。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +说明 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +icon +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label所使用的图片 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +text +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label显示的文字 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label的水平对齐方式 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +verticalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label的纵向对齐方式 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalTextPosition +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label文字的水平位置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +verticalTextPosition +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label文字的垂直位置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +textGap +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label文字和图片之间的间隙(像素值) +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JLabel的主要属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:JLabel的主要属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +JLabel示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整的代码请参见:https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/sr +c/cn/edu/sdut/softlab/,双击JLabelDemo.form即可打开Form Designer查看界面设计效果。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +我们在内容区增加了三个JLabel:最上面的Label同时包含了文字和图片,中间的Label只包含了文字,最下面的Label只包含了图片,其属性对话框的设置分别 +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:顶部Label属性框设置" + +\end_inset + + +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:中间Label属性框设置" + +\end_inset + + +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:下面Label属性框设置" + +\end_inset + +所示,其中修改过的属性已经黑体加重标注了,没有使用黑体标注的属性无需设置。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +当拖放第一个JLabel到内容区的时候,Form Designer自动在这个JLabel的下面增加了一个垂直占位符,以保证这个JLabel能够在希望的顶部展示。 +由于我们还要增加下面的两个Label,因此这里可以删除这个垂直占位符。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/gui/jlabel-demo-1.png + width 30line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +顶部Label属性框设置 +\begin_inset CommandInset label +LatexCommand label +name "fig:顶部Label属性框设置" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/gui/jlabel-demo-2.png + width 30line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +中间Label属性框设置 +\begin_inset CommandInset label +LatexCommand label +name "fig:中间Label属性框设置" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/gui/jlabel-demo-3.png + width 30line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +下面Label属性框设置 +\begin_inset CommandInset label +LatexCommand label +name "fig:下面Label属性框设置" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JLabel的属性对话框 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行此示例,初始状态如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:运行的初始状态" + +\end_inset + +所示,可以尝试缩放窗口,比如水平放大窗口可以更明显的看出效果,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:水平方法后的窗口" + +\end_inset + +所示。请任意缩放窗口请注意观察这三个Label位置的变化,体会水平对齐 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +水平对齐 +\end_layout + +\end_inset + +、垂直对齐 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +垂直对齐 +\end_layout + +\end_inset + +等的效果。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jlabel-demo-4.png + height 30theight% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +运行的初始状态 +\begin_inset CommandInset label +LatexCommand label +name "fig:运行的初始状态" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jlabel-demo-5.png + height 30theight% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +水平放大后的窗口 +\begin_inset CommandInset label +LatexCommand label +name "fig:水平方法后的窗口" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JLabelDemo运行结果 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +注意以下几点: +\end_layout + +\begin_layout Itemize +这三个 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JLabel +\end_layout + +\end_inset + +JLabel都无需设置field name属性值。 +\end_layout + +\begin_layout Itemize +特别注意观察Horizental Align属性的不同效果,可以尝试不同的水平对齐方式观察效果(通过Idea的Form Designer提供的预览工具更方便,在 +Form Designer界面直接右键选择“preview”即可)。 +\end_layout + +\begin_layout Itemize +在组合使用文本和图片时,还要注意horizentalTextPosition +\begin_inset Index idx +status open + +\begin_layout Plain Layout +horizentalTextPosition +\end_layout + +\end_inset + +和verticalTextPosition +\begin_inset Index idx +status open + +\begin_layout Plain Layout +verticalTextPosition +\end_layout + +\end_inset + +这两个属性的效果。 +\end_layout + +\begin_layout Subsection +文本控件 +\begin_inset CommandInset label +LatexCommand label +name "subsec:JTextField" + +\end_inset + + +\end_layout + +\begin_layout Standard +Swing的文本控件是指能够输入文本的控件,比如文本框(JTextField +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JTextField +\end_layout + +\end_inset + +)、文本域(JTextArea +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JTextArea +\end_layout + +\end_inset + +)、富文本编辑器(JEdtiorPane +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JEdtiorPane +\end_layout + +\end_inset + +)等。Swing的文本控件类的关系如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:文本输入控件" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/text-input-controls.eps + lyxscale 40 + scale 40 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +文本输入控件 +\begin_inset CommandInset label +LatexCommand label +name "fig:文本输入控件" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +单行纯文本控件:用于输入一行纯文本字符串。根据场合不同,可以选择使用JTextField,输入简单的单行字符串;或者JFormattedTextField +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JFormattedTextField +\end_layout + +\end_inset + +,输入格式化的单行字符串,比如表示日期的“2017-3-12”等;或者JPasswordField +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JPasswordField +\end_layout + +\end_inset + +,输入密码(默认不显示输入的密码)。 +\end_layout + +\begin_layout Itemize +多行纯文本控件:用于输入多行纯文本字符串。如果需要输入的字符串比较长,可以采用JTextArea +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JTextArea +\end_layout + +\end_inset + +,会显示一个多行的文本编辑区域供输入。 +\end_layout + +\begin_layout Itemize +多行富文本控件:用于输入带格式的文本字符串,通常用于输入HTML等格式的字符串。 +\end_layout + +\begin_layout Standard +文本控件的常见属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:文本控件的常见属性" + +\end_inset + +所示,请参照Form Designer中的属性对话框了解这些属性的取值范围。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +说明 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +text +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +文本框的内容 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +editable +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +是否可编辑 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +columns +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +文本框的长度(多少个字符),仅仅作为计算默认显示宽度的依据 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +字符在文本框内的对齐方式,可以选择:JTextField.LEADING, JTextField.CENTER, JTextField.TRAILING +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +文本控件的常见属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:文本控件的常见属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +文本控件示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +我们设计一个同时展示三种TextField的Panel,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:文本控件示例" + +\end_inset + +所示 +\begin_inset Foot +status open + +\begin_layout Plain Layout +详情请参见:https://github.com/subaochen/java-tutorial-examples/blob/master/gui/src/cn/ +edu/sdut/softlab/TextControlDemo.form +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +.当在文本框中输入一些字符后(失去焦点后),在最下面的 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Label +\end_layout + +\end_inset + +Label中显示输入的内容。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/textfield-demo-1.png + width 95line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +文本控件示例 +\begin_inset CommandInset label +LatexCommand label +name "fig:文本控件示例" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行此应用程序的界面如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:文本控件示例运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/textfield-demo-2.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +文本控件示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:文本控件示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +这个简单的示例我们要注意以下三点: +\begin_inset Note Note +status open + +\begin_layout Plain Layout +示例代码的布局要说明吗? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +可以通过 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Panel +\end_layout + +\end_inset + +Panel进一步组织控件,这是一种常见的手段。在例中,我们把三个 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +TextField +\end_layout + +\end_inset + +TextField控件放到一个Panel中,在把这Panel添加到mainPanel中。并且,放置三个TextField的Panel添加了标题(title):“ +单行纯文本控件”,以更清晰的表达这个Panel的意义,这也是一种常见的手段。 +\end_layout + +\begin_layout Itemize +请参照 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "par:步骤12" + +\end_inset + +为三个TextField添加FocusListener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +FocusListener +\end_layout + +\end_inset + +,这里我们重点监听了失去焦点的事件。 +\end_layout + +\begin_layout Itemize +本例也可以监听ActionListener(当在输入框按下回车键时触发该事件)获得当前输入框的内容,请读者自行完成相关代码并运行测试。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +焦点 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +焦点 +\end_layout + +\end_inset + +(Focus)通常是指文本输入框是否正在接受输入。获得焦点即文本输入框可以输入文字,失去焦点即文本输入框不再能够输入文字,即光标已经离开了此输入框。失去焦点往往 +意味着用户结束了输入,因此,我们可以通过监听失去焦点事件来获得文本输入框中的内容。 +\end_layout + +\begin_layout Plain Layout +如果焦点的概念用于窗口(应用程序),则获得焦点意味着当前窗口是活动窗口,即可操作的窗口;失去焦点意味着其他窗口获得了焦点,当前窗口不可操作。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +JButton +\begin_inset CommandInset label +LatexCommand label +name "subsec:JButton" + +\end_inset + + +\end_layout + +\begin_layout Standard +按钮(Button +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Button +\end_layout + +\end_inset + +)是一种常见的交互控件,在Swing中最常见的按钮通过JButton +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JButton +\end_layout + +\end_inset + +来描述。按钮用法很直接,通常涉及到以下三个方面: +\end_layout + +\begin_layout Itemize +给按钮一个合适的名称,包括显示在按钮上面的文字。 +\end_layout + +\begin_layout Itemize +有的时候希望在按钮上面也显示图标以更明确的表达按钮的意思,可以通过按钮的icon +\begin_inset Index idx +status open + +\begin_layout Plain Layout +icon +\end_layout + +\end_inset + +属性来设置图标。 +\end_layout + +\begin_layout Itemize +给按钮添加鼠标点击的响应代码( +\begin_inset Index idx +status open + +\begin_layout Plain Layout +ActionListener +\end_layout + +\end_inset + +ActionListener或者MouseListener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +MouseListener +\end_layout + +\end_inset + +)。 +\end_layout + +\begin_layout Standard +JButton的常见属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:JButton的常见属性" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +说明 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +enabled +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +是否允许点击 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +icon +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +在按钮上面要显示的图标 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +text +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +在按钮上面要显示的文字 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalTextPosition +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +水平方向的文字位置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +verticalTextPosition +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +垂直方向的文字位置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +水平方向的对齐方式 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +virticalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +垂直方向的对齐方式 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JButton的常见属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:JButton的常见属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +JButton示例 +\begin_inset CommandInset label +LatexCommand label +name "exa:JButton示例" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +我们设计一个包含三个按钮的Panel,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Button示例Panel" + +\end_inset + +所示 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整的代码请参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/button-demo-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Button示例Panel +\begin_inset CommandInset label +LatexCommand label +name "fig:Button示例Panel" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +依然参照 +\begin_inset CommandInset ref +LatexCommand formatted +reference "par:步骤12" + +\end_inset + +为这三个Button 添加三个ActionListener,分别响应鼠标左键单击事件。 +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +在运行时点击各个按钮,观察发生了什么?比如点击“紧急呼叫”按钮,弹出了一个消息框,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Button示例运行结果" + +\end_inset + +所示。点击“被禁止的按钮”,会怎样? +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/button-demo-2.png + width 50line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Button示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:Button示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +请仔细查看三个按钮的属性对话框以了解这三个按钮是如何实现这样的效果的: +\end_layout + +\begin_layout Itemize +第一个按钮演示了按钮上是可以图文并茂的(设置icon +\begin_inset Index idx +status open + +\begin_layout Plain Layout +icon +\end_layout + +\end_inset + +属性即可),并且通过设置horizentalTextPosition +\begin_inset Index idx +status open + +\begin_layout Plain Layout +horizentalTextPosition +\end_layout + +\end_inset + +属性为Leading(在开头),将图片放到了文字的后面。 +\end_layout + +\begin_layout Itemize +第二个按钮演示了如何将按钮上的文字和图片上下布局:首先让按钮上的内容水平居中(horizentalTextPosition +\begin_inset Index idx +status open + +\begin_layout Plain Layout +horizentalTextPosition +\end_layout + +\end_inset + +属性为Center),然后设置verticalTextPosition +\begin_inset Index idx +status open + +\begin_layout Plain Layout +verticalTextPosition +\end_layout + +\end_inset + +属性为Bottom即可。 +\end_layout + +\begin_layout Itemize +第三个按钮设置enabled为false即可,即去掉默认选中的enabled选项。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +默认的,JButton的actionListener是响应鼠标左键单击事件的,比如在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +example +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:JButton示例" + +\end_inset + +中,我们给按钮增加了响应鼠标左键单击的actionListener,那么如何响应鼠标右键、中键的单击事件呢?参见下面的代码: +\end_layout + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +// 响应右键单击事件 +\end_layout + +\begin_layout Plain Layout + +emegencyCallButton.addMouseListener(new MouseAdapter() { +\end_layout + +\begin_layout Plain Layout + + @Override +\end_layout + +\begin_layout Plain Layout + + public void mouseClicked(MouseEvent mouseEvent) { +\end_layout + +\begin_layout Plain Layout + + super.mouseClicked(mouseEvent); +\end_layout + +\begin_layout Plain Layout + + if(SwingUtilities.isRightMouseButton(mouseEvent) && mouseEvent.getClickCou +nt() == 1) { +\end_layout + +\begin_layout Plain Layout + + JOptionPane.showMessageDialog(null,"右键单击急呼叫按钮"); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +}); +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +JCheckBox +\begin_inset CommandInset label +LatexCommand label +name "subsec:JCheckBox" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JCheckBox +\end_layout + +\end_inset + +JCheckBox通常叫做“复选框”,即可以同时打开或关闭多个选项 +\begin_inset Foot +status open + +\begin_layout Plain Layout +对比一下JRadioButton(单选框),JRadionButton只能在一组选项中选中一项。 +\end_layout + +\end_inset + +。当选项被选中时,该复选框的“选择”状态为true,否则为false。 +\end_layout + +\begin_layout Standard +JCheckBox的常见属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:JCheckBox的常见属性" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +说明 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +text +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +CheckBox的提示文字 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +icon +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +CheckBox的提示图片 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +enabled +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +是否启用这个控件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +selected +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +CheckBox默认的选中状态 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +文字的水平对齐方式 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalTextPosition +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +文字的水平位置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +verticalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +文字的垂直对齐方式 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +virticalTextPosition +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +文字的垂直位置 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JCheckBox的常见属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:JCheckBox的常见属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +JCheckBox示例 +\begin_inset CommandInset label +LatexCommand label +name "exa:JCheckBox示例" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +我们设计一个包含4个CheckBox(业余爱好)的Panel +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +,当鼠标点击某个爱好时显示选中的CheckBox的状态;当鼠标移动到某个爱好上面时,同步显示表示这个业余爱好的图片,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JCheckBox运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/checkbox-demo-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JCheckBox示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:JCheckBox示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +在运行时,注意观察鼠标在各个CheckBox上面和离开CheckBox时界面的不同反应,选中或者反选选项时不同的消息提示,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JCheckBox运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/checkbox-demo-2.png + width 20line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +运行初始状态 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/checkbox-demo-3.png + width 20line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +鼠标移动到“足球”选项 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/checkbox-demo-4.png + width 45line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +选中“足球”选项 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JCheckBox运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:JCheckBox运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +我们为每个JCheckBox添加了两个事件监听器,一个ActionListener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +ActionListener +\end_layout + +\end_inset + +用于监听鼠标左键单击选项选择或者反选时产生的事件,一个MouseListener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +MouseListener +\end_layout + +\end_inset + +用于监听当鼠标进入或者离开选项所在区域时产生的事件。 +\end_layout + +\begin_layout Paragraph +延伸阅读 +\end_layout + +\begin_layout Standard +其实,JButton +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JButton +\end_layout + +\end_inset + +, JCheckBox +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JCheckBox +\end_layout + +\end_inset + +, JRadionButton +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JRadionButton +\end_layout + +\end_inset + +等都从 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +AbstractButton +\end_layout + +\end_inset + +AbstractButton继承下来的,即JButton一族的类层次关系如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Button类层次关系" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/button-overview.eps + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Button类层次关系 +\begin_inset CommandInset label +LatexCommand label +name "fig:Button类层次关系" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +因此,JButtron、JCheckBox、JRadionButton等的共性就不难理解了。 +\end_layout + +\begin_layout Subsection +JRadioButton +\begin_inset CommandInset label +LatexCommand label +name "subsec:JRadioButton" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JRadioButton +\end_layout + +\end_inset + +JRadioButton通常叫做“单选框”,即通过JRadionButton可以展示一组选项,但是只能有一个选项处于“选中”状态。当选择另外一个选项时,原先被选 +中的选项自动失效。 +\end_layout + +\begin_layout Standard +JRadionButton的常见属性和JCheckBox基本相同,只有一点需要注意:JRadioButton的buttonGroup属性是必须设置的,即每个JR +adioButton都需要设置buttonGroup属性,表明这个JRadioButton是属于哪个“组”的,以便Java根据用户的选择情况设置当前组的Radi +oButton哪个有效,哪个失效。 +\end_layout + +\begin_layout Example +JRadionButton示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +类似于 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:JCheckBox示例" + +\end_inset + +,我们设计一个图形用户应用程序 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整的代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +,根据选项决定显示哪种运动的图片,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JRadioButton示例设计" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jradiobutton-demo-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JRadioButton示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:JRadioButton示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +点击不同的选项,将显示不同的运动图片,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JRadionButton示例运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jradiobutton-demo-2.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JRadionButton示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:JRadionButton示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +本例中,我们手工创建了ActionListener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +ActionListener +\end_layout + +\end_inset + +,通常JRadioButton的ActionListener需要手工创建更合适,因为JRadioButton一般需要设置为属于某个ButtonGroup,整个B +uttonGroup设计一个ActionListener就可以了,没有必要每个JRadioButton都独立设计一个ActionListener,如下列代码所示 +: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + public RadioButtonDemo() { +\end_layout + +\begin_layout Plain Layout + + swimming.setActionCommand("swimming"); +\end_layout + +\begin_layout Plain Layout + + swimming.addActionListener(this); +\end_layout + +\begin_layout Plain Layout + + tennis.setActionCommand("tennis"); +\end_layout + +\begin_layout Plain Layout + + tennis.addActionListener(this); +\end_layout + +\begin_layout Plain Layout + + basketball.setActionCommand("basketball"); +\end_layout + +\begin_layout Plain Layout + + basketball.addActionListener(this); +\end_layout + +\begin_layout Plain Layout + + football.setActionCommand("football"); +\end_layout + +\begin_layout Plain Layout + + football.addActionListener(this); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + @Override +\end_layout + +\begin_layout Plain Layout + + public void actionPerformed(ActionEvent actionEvent) { +\end_layout + +\begin_layout Plain Layout + + sportLabel.setIcon(new ImageIcon(RadioButtonDemo.class.getResource("/images +/" +\end_layout + +\begin_layout Plain Layout + + + actionEvent.getActionCommand() + ".png"))); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在以上代码中,我们在构造方法中为每个JRadioButton指定了actionCommand +\begin_inset Index idx +status open + +\begin_layout Plain Layout +actionCommand +\end_layout + +\end_inset + +以便在监听器代码中获取actionCommand拼装图片的路径。 +\end_layout + +\begin_layout Standard +另外需要注意的是,我们需要将这组JRadionButton设置一个共同的ButtonGroup,即在Form Designer中如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:设置ButtonGroup" + +\end_inset + +所示,创建一个新的ButtonGroup +\begin_inset Index idx +status open + +\begin_layout Plain Layout +ButtonGroup +\end_layout + +\end_inset + +,并将所有JRadioButton的ButtonGroup属性都设置为这个新建的ButtonGroup。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jradiobutton-demo-3.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +设置ButtonGroup +\begin_inset CommandInset label +LatexCommand label +name "fig:设置ButtonGroup" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +JComboBox +\begin_inset CommandInset label +LatexCommand label +name "subsec:JComboBox" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JcomboBox +\end_layout + +\end_inset + +JcomboBox表示“下列选择框”,通常在空间比较紧张或者选项很多时采用下拉选择框比较合适。 +\end_layout + +\begin_layout Example +下拉选择框示例 +\begin_inset CommandInset label +LatexCommand label +name "exa:下拉选择框示例" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:JCheckBox示例" + +\end_inset + +类似,我们设计一个下拉选择框来提供运动项目选项 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +,当选中某个运动项目时则显示相应的图片,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JComboBox示例设计" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jcombobox-demo-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JComboBox示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:JComboBox示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +注意到,下拉选择框sports需要设置在其中要显示的条目,可以通过属性对话框的model属性来设置,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JComboBox的model属性设置" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jcombobox-demo-2.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JComboBox的model属性设置 +\begin_inset CommandInset label +LatexCommand label +name "fig:JComboBox的model属性设置" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +该示例的运行结果如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JComboBox示例的运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jcombobox-demo-3.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JComboBox示例的运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:JComboBox示例的运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +其他常见控件 +\end_layout + +\begin_layout Subsubsection* +Spinner +\begin_inset CommandInset label +LatexCommand label +name "subsec:Spinner" + +\end_inset + + +\end_layout + +\begin_layout Standard +Spinner是一种便捷填写数字的控件,详情请参见示例代码: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + +及其注释。 +\end_layout + +\begin_layout Subsubsection* +Slider +\begin_inset CommandInset label +LatexCommand label +name "subsec:Slider" + +\end_inset + + +\end_layout + +\begin_layout Standard +Slider是一种通过滑动选择数字的控件,详情请参见示例代码: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + +及其注释。 +\end_layout + +\begin_layout Subsubsection* +Tabbed Pane +\begin_inset CommandInset label +LatexCommand label +name "subsec:Tabbed-Pane" + +\end_inset + + +\end_layout + +\begin_layout Standard +Tabbed Pane可以实现“标签页”,详情请参见示例代码: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + +及其注释。 +\end_layout + +\begin_layout Section +布局管理器 +\begin_inset CommandInset label +LatexCommand label +name "sec:布局管理器" + +\end_inset + + +\end_layout + +\begin_layout Standard +在图形用户界面应用程序的设计中,界面中的控件如何布局总是一个容易让人困扰的问题,有过WEB界面设计经历的读者可能对此有更深刻的体会。比如当窗口大小或者分辨率发生 +改变的时候,如何保证界面布局符合当初的设计(期望)呢?通常有两种常见的界面布局思路:绝对布局和相对布局。绝对布局是指使用绝对(像素)坐标确定控件在界面的位置,很 +显然,当窗口大小发生改变时,绝对布局的界面不会随窗口发生改变,于是导致了不能充分利用放大了的窗口或者无法适应缩小了的窗口,因此绝对布局在实际的编程中很少用到,也 +不建议使用绝对布局,本节主要阐述各种相对布局的基本思路和方法。 +\end_layout + +\begin_layout Subsection +BorderLayout +\begin_inset CommandInset label +LatexCommand label +name "subsec:BorderLayout" + +\end_inset + + +\end_layout + +\begin_layout Standard +BorderLayout很像“麻将桌”,将界面分为5个部分: +\end_layout + +\begin_layout Itemize +PAGE_START:界面的顶部 +\end_layout + +\begin_layout Itemize +PAGE_END:界面的底部 +\end_layout + +\begin_layout Itemize +LINE_START:界面的左边 +\end_layout + +\begin_layout Itemize +LINE_END:界面的右边 +\end_layout + +\begin_layout Itemize +CENTER:界面的中间 +\end_layout + +\begin_layout Standard +BorderLayout的特点是,当窗口缩放时,四周的控件只占用尽可能小的空间,中间的控件将随窗口占用尽可能多的空间。 +\end_layout + +\begin_layout Example +BorderLayout示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:BorderLayout示例" + +\end_inset + +所示,5个按钮分别位于界面的4边和中间 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见:https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/ +cn/edu/sdut/softlab +\end_layout + +\end_inset + +。注意到我们将主Panel的Layout Manager修改为了BorderLayout,而不是默认的GridBagLayout。 +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/borderlayout-demo-0.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +BorderLayout示例 +\begin_inset CommandInset label +LatexCommand label +name "fig:BorderLayout示例" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:BorderLayout示例运行结果" + +\end_inset + +所示的运行结果是放大窗口后的效果。建议读者在不同的窗口大小情况下观察BorderLayout的布局效果,以加深对BorderLayout的理解。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/borderlayout-demo-1.png + width 50line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +BorderLayout示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:BorderLayout示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +这个示例很简单,我们只是修改了Panel的Layout Manager为BorderLayout,然后将5个按钮依次放到界面的合适位置即可。 +\end_layout + +\begin_layout Exercise +尝试将 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:BorderLayout示例运行结果" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +中“Center”按钮所在的位置替换为另外一个“麻将桌”,即如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:BorderLayout练习1" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +示的效果。 +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/BorderLayout-exe1.1.png + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +BorderLayout练习1 +\begin_inset CommandInset label +LatexCommand label +name "fig:BorderLayout练习1" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +FlowLayout +\begin_inset CommandInset label +LatexCommand label +name "subsec:FlowLayout" + +\end_inset + + +\end_layout + +\begin_layout Standard +流式布局(FlowLayout)是一种很自然的布局方式,即各个控件按照加入的顺序在窗口从左向右依次排开,各自只占用尽量小的空间。 +\end_layout + +\begin_layout Example +FlowLayout示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:FlowLayout示例设计" + +\end_inset + +所示,设计一个包含若干按钮和RadioButton的应用程序 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见:https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/ +cn/edu/sdut/softlab +\end_layout + +\end_inset + +,控件使用FlowLayout布局。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/flowlayout-demo-1.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +FlowLayout示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:FlowLayout示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +默认的运行结果如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:FlowLayout示例运行结果" + +\end_inset + +所示。请尝试改变窗口的大小观察FlowLayout的布局效果。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/flowlayout-demo-2.png + width 50line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +FlowLayout示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:FlowLayout示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +本例重点有两个: +\end_layout + +\begin_layout Itemize +mainPanel采用了FlowLayout布局管理器。 +\end_layout + +\begin_layout Itemize +mainPanel的preferedSize修改为300x200,以便更好的展现FlowLayout的布局效果。 +\end_layout + +\begin_layout Subsection +CardLayout +\begin_inset CommandInset label +LatexCommand label +name "subsec:CardLayout" + +\end_inset + + +\end_layout + +\begin_layout Example +CardLayout示例 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:CardLayout示例设计" + +\end_inset + +所示 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见:https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/ +cn/edu/sdut/softlab +\end_layout + +\end_inset + +,主界面使用默认的GridLayout,界面的上半部分放置了一个下拉选择框,根据不同的选择展示不同的card。下半部分是一个Panel,此Panel(cardP +anel)使用CardLayout,在其中添加了两个card,分别是buttonPanel和textFieldPanel。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/cardlayout-demo-1.png + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +CardLayout示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:CardLayout示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +根据选择的不同,可以看到显示了不同card的内容,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:CardLayout示例运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/gui/cardlayout-demo-2.png + width 45line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +默认运行结果 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/gui/cardlayout-demo-3.png + width 45line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +选择Card with JTextField +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +CardLayout示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:CardLayout示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +增加代码的分析,因为CardLayout的代码不是特别直观 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +CardLayout的show方法可以有选择的显示指定的card,注意到show方法的第二个参数是指定的card的name(字符串),因此在Form + Designer中要设置每个card的name属性。为了和下拉选择框的设置一致,在本例中card的name属性设置为了下拉选择框的相应文字。 +\end_layout + +\begin_layout Standard +注意到mainPanel的布局管理器我们使用了Idea默认的GridBLayout,可以尝试换为BorderLayout或者FlowLayout看看效果如何? +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +在本例中我们使用了一个常见的Java GUI界面设计技巧:通过Panel在局部组织控件,然后对Panel使用合适的布局管理器进行管理。也就是说,通常一个Java + GUI的界面设计是分为两个层面的:第一个层面,对整个界面进行合理的大体的界面划分(使用Panel);第二个层面,在每个Panel内部进行控件的合理布局。我们在 +Java GUI的综合应用举例中还会看到这种布局策略。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +GridLayout +\begin_inset CommandInset label +LatexCommand label +name "subsec:GridLayout" + +\end_inset + + +\end_layout + +\begin_layout Standard +网格布局(GridLayout)是将整个界面划分为表格,表格的每个单元格可以放置一个控件(或者Panel),从而实现了规整的界面布局。影响GridLayout效 +果的除了表格单元格的个数之外,常见的属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:GridLayout的常见属性" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +说明 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +默认值 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizental gap +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +单元格的水平间隔的像素值,-1代表使用父容器的此设置,或者内置的10px +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +virtical gap +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +单元格的垂直间隔的像素值,-1代表使用父容器的此设置,或者内置的5px +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +same size horizentally +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +如果是true的话,所有控件在水平方向大小一致 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +false +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +same size vitically +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +如果是true的话,所有控件在垂直方向大小一致 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +false +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +margin +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +容器和控件之间的四周间隔大小 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0,0,0,0 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridLayout的常见属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:GridLayout的常见属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +GridLayout示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +使用GridLayout设计一个3x2的表格,其中放置5个按钮 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见:https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/ +cn/edu/sdut/softlab +\end_layout + +\end_inset + +,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:GridLayout示例设计" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridlayout-demo-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridLayout示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:GridLayout示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:GridLayout示例运行结果" + +\end_inset + +所示,GridLayout的用法简洁明了,请自行在Form Designer中修改相应的参数,比如virticalGap(水平间隔),horizentalGap +(垂直间隔)等观察这些参数对布局的影响。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridlayout-demo-2.png + width 50line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridLayout示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:GridLayout示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +使用Idea设计GridLayout界面 +\begin_inset Foot +status open + +\begin_layout Plain Layout +我们使用了Idea提供的GridLayoutManager,详情请参考: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://www.formdev.com/jformdesigner/doc/layouts/intellijgridlayout/ +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +的小技巧:Idea的Form Designer通常能够智能的判断应该使用多少格子来放置控件,但是我们也必须给出明确的“指令”。比如我们希望设计如下的界面: +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridlayout-tip-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +第一步,先添加三个JTextField,然后在第一个JTextField上面放置一个JLabel,如下图所示: +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridlayout-tip-2.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +第二步,需要首先将三个JTextField调整到一个水平面上,即如下图所示: +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridlayout-tip-3.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +第三步,添加另外的两个JLabel。 +\end_layout + +\begin_layout Plain Layout +如果没有在第二步首先将三个JTextField调整到一个水平面上,则继续添加JLabel时Form Designer可能会错误的领会我们的意思,从而错误的计算单 +元格的数量,读者可自行尝试和认真体会。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +GridBagLayout +\begin_inset CommandInset label +LatexCommand label +name "subsec:GridBagLayout" + +\end_inset + + +\end_layout + +\begin_layout Standard +网格袋布局(GridBagLayout)显然是GridLayout的扩展:GridLayout只允许控件放置在一个单元格中,而GridBagLayout允许一个 +控件占用多个单元格,因而GridBaglayout更加灵活,控制选项(属性)也比较多,常见的属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:GridBagLayout的常见属性" + +\end_inset + +所示 +\begin_inset Foot +status open + +\begin_layout Plain Layout +本书以JetBrain Idea提供的Form Designer为蓝本说明GridBagLayout的常见属性,和标准的Java Swing的GridBagLa +yout的属性略有出入。 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +说明 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +默认值 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +grid x +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +控件所占单元格的起始x坐标(左上角) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +grid y +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +控件所占单元格中的起始y坐标(左上角) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +grid width +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +控件横向占用的单元格数 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +grid height +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +控件纵向占用的单元格数 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizental align +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +横向的对齐方式,Fill意味着充满可能的横向空间(受weight x设置的影响) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Fill +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +virtical align +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +纵向的对齐方式,Fill意味着充满可能的纵向空间(受weight y设置的影响) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Center +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +weight x +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +横向扩展的权重。如果值为0则横向不扩展,即控件只占用可能小的空间;通常此值在0-1之间设置。 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0.0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +weight y +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +纵向扩展的权重。如果值为0则纵向不扩展,即控件只占用可能小的空间;通常此值在0-1之间设置。 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0.0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +insets +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +控件的外边距 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0,0,0,0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ipad x +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +横向的内边距素数,决定了控件距离单元格的边线有多远 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ipad y +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +纵向的内边距素数,决定了控件距离单元格的边线有多远 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridBagLayout的常见属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:GridBagLayout的常见属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +在Idea的Form Designer中,grid x/grid y/grid width/grid height属性是通过拖放控件自动设置的,无需手工设置。实 +际上,Form Designer的属性对话框没有提供编辑这4个属性的功能。 +\end_layout + +\begin_layout Plain Layout +如果熟悉CSS的盒子模型的话,insets相当于CSS盒子模型的margin,ipadx/ipady相当于CSS盒子模型的padding。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +GridBagLayout示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:GridBagLayout示例设计" + +\end_inset + +所示,我们设计一个包含几个按钮的界面,使用GridBagLayout布局管理器。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridbaglayout-demo-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridBagLayout示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:GridBagLayout示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:GridBagLayout示例运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridbaglayout-demo-2.png + scale 70 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridBagLayout示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:GridBagLayout示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +本例中各控件的属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:GridBagLayout示例应用中的控件属性" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +控件 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +属性设置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ButtonA +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 0,grid y = 0 +\end_layout + +\begin_layout Plain Layout +grid width = 1, grid height = 1 +\end_layout + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ButtonB +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 1,grid y = 0 +\end_layout + +\begin_layout Plain Layout +grid width = 1, grid height = 1 +\end_layout + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +Another Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 2,grid y = 0 +\end_layout + +\begin_layout Plain Layout +grid width = 1, grid height = 1 +\end_layout + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +A Long Name Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 0,grid y = 1 +\end_layout + +\begin_layout Plain Layout +grid width = 3, grid height = 1 +\end_layout + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ButtonC +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 0,grid y = 2 +\end_layout + +\begin_layout Plain Layout +grid width = 1, grid height = 1 +\end_layout + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ButtonD +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 0,grid y = 3 +\end_layout + +\begin_layout Plain Layout +grid width = 1, grid height = 1 +\end_layout + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +Last Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 1,grid y = 2 +\end_layout + +\begin_layout Plain Layout +grid width = 2, grid height = 2 +\end_layout + +\begin_layout Plain Layout +h align = Center, v align = Fill +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridBagLayout示例应用中的控件属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:GridBagLayout示例应用中的控件属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +请读者尝试 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:控件属性的各种组合方式" + +\end_inset + +的控件属性组合方式,观察GridBagLayout在界面布局中的灵活性。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +测试场景 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +控件 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +属性设置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +只设置ButtonA的属性,其他控件属性不变 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +ButtonA +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +h align = Center, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 1, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +只设置Last Button的属性,其他控件属性不变 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Last Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +h align = Center, v align = Fill +\end_layout + +\begin_layout Plain Layout +weight x = 1, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +只设置Last Button的属性,其他控件属性不变 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Last Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +h align = Fill, v align = Fill +\end_layout + +\begin_layout Plain Layout +weight x = 1, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +只设置Last Button的属性,其他控件属性不变 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Last Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +h align = Fill, v align = Fill +\end_layout + +\begin_layout Plain Layout +weight x = 1, weight y = 1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +只设置Last Button的属性,其他控件属性不变 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Last Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 1, weight y = 1 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +控件属性的各种组合方式 +\begin_inset CommandInset label +LatexCommand label +name "tab:控件属性的各种组合方式" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +JAVA图形用户界面的事件机制 +\begin_inset CommandInset label +LatexCommand label +name "sec:JAVA图形用户界面的事件机制" + +\end_inset + + +\end_layout + +\begin_layout Subsection +事件机制的基本原理 +\begin_inset CommandInset label +LatexCommand label +name "subsec:事件机制的基本原理" + +\end_inset + + +\end_layout + +\begin_layout Standard +事件机制是指代码如何对界面的点击、输入等事件做出响应,我们在前面的例子中已经多次使用了Swing的事件机制。Swing事件机制的三个要点是: +\end_layout + +\begin_layout Itemize +事件源(Event Source):即触发事件的控件,比如按钮、文本框等。 +\end_layout + +\begin_layout Itemize +事件对象(Event Object):描述事件的封装对象,其中包括了事件源、事件发生事件、事件相关参数(比如鼠标事件包括鼠标点击的坐标、鼠标点击次数等)等。 +\end_layout + +\begin_layout Itemize +监听器(Listener):当事件发生时Java会自动调用的方法被称为监听器。 +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Swing事件机制" + +\end_inset + +说明了按钮事件的处理过程 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这里对“注册”的原理没有展开说明,需要说明Event Loop的过程吗?需要说明注册和Java虚拟机的关系吗? +\end_layout + +\end_inset + + +\begin_inset Note Note +status open + +\begin_layout Plain Layout +是否可以在这里增加一个设计模式的示例?比如设计一个Container模拟OS,设计一个Listener模拟按钮、checkbox等 +\end_layout + +\end_inset + +,其他类型的事件处理过程与此类似。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/swing-event-model.eps + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Swing事件机制(以按钮为例) +\begin_inset CommandInset label +LatexCommand label +name "fig:Swing事件机制" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +控件的常见监听器 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整的Java GUI控件和事件监听器的对照表参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +http://docs.oracle.com/javase/tutorial/uiswing/events/eventsandcomponents.html +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:控件的常见监听器" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +控件 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +常用监听器 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +JButton +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +ActionListener:响应鼠标左键单击和回车事件 +\end_layout + +\begin_layout Plain Layout +MouseListener:响应除左键单击外的其他的各种鼠标事件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +JTextField +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +ActionListener:响应在输入框回车事件 +\end_layout + +\begin_layout Plain Layout +FocusListener:响应获得和失去焦点事件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +JRadioButton +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +ActionListener:响应选项选择事件 +\end_layout + +\begin_layout Plain Layout +MouseListener:响应各种鼠标事件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +JCheckBox +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +ActionListener:响应选项选择事件 +\end_layout + +\begin_layout Plain Layout +MouseListener:响应各种鼠标事件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +JComboBox +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +ActionListener:响应选项选择事件 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +控件的常见监听器 +\begin_inset CommandInset label +LatexCommand label +name "tab:控件的常见监听器" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +监听器类的几种情形 +\begin_inset CommandInset label +LatexCommand label +name "subsec:监听器类的几种情形" + +\end_inset + + +\end_layout + +\begin_layout Standard +注意到注册监听器的方法:src.addXxxListener(listenerObject)的参数是一个实现了监听器接口的对象,即通过这个方法告诉Java虚拟机, +当src(事件源)对象产生了一个Xxx类型的事件时,需要调用listenerObject中的相关方法进行事件处理。在实现监听器时,通常有如下的几种策略,以按钮的 +单击事件actionEvent为例: +\end_layout + +\begin_layout Itemize +主类直接实现XxxListener接口或者扩展XxxHandler类,比如: +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class FrameDemo implements ActionListener { +\end_layout + +\begin_layout Plain Layout + + private JButton button; +\end_layout + +\begin_layout Plain Layout + + public FrameDemo() { +\end_layout + +\begin_layout Plain Layout + + button = new JButton("OK"); +\end_layout + +\begin_layout Plain Layout + + button.addActionListener(this); // 注册事件监听器。由于FrameDemo本身实现ActionListener接 +口,因此这里直接使用this作为实现了事件监听器接口的对象。 +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + public void actionPerformed(ActionEvent event) { +\end_layout + +\begin_layout Plain Layout + + // 事件处理代码 +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +使用匿名内部类实现监听器接口,比如: +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class FrameDemo { +\end_layout + +\begin_layout Plain Layout + + private JButton button; +\end_layout + +\begin_layout Plain Layout + + public FrameDemo() { +\end_layout + +\begin_layout Plain Layout + + button = new JButton("OK"); +\end_layout + +\begin_layout Plain Layout + + button.addActionListener(new ActionListener() { // 匿名内部类实现ActionListener接 +口 +\end_layout + +\begin_layout Plain Layout + + @Override +\end_layout + +\begin_layout Plain Layout + + public void actionPerformed(ActionEvent event) { +\end_layout + +\begin_layout Plain Layout + + // 事件处理代码 +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + }); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +使用独立的类实现监听器接口,比如: +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class FrameDemo { +\end_layout + +\begin_layout Plain Layout + + private JButton button; +\end_layout + +\begin_layout Plain Layout + + public FrameDemo() { +\end_layout + +\begin_layout Plain Layout + + button = new JButton("OK"); +\end_layout + +\begin_layout Plain Layout + + button.addActionListener(new ButtonListener()); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +// 独立的事件监听器类,实现了ActionListener接口 +\end_layout + +\begin_layout Plain Layout + +class ButtonListener implements ActionListener { +\end_layout + +\begin_layout Plain Layout + + @Override +\end_layout + +\begin_layout Plain Layout + + public void actionPerformed(ActionEvent event) { +\end_layout + +\begin_layout Plain Layout + + // 事件处理代码 +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在大多数情况下,我们建议使用匿名内部类实现监听器接口,代码更简洁,封装性更好。 +\end_layout + +\begin_layout Section +Java GUI综合应用举例 +\begin_inset CommandInset label +LatexCommand label +name "sec:Java-GUI综合应用举例" + +\end_inset + + +\end_layout + +\begin_layout Example +计算器 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +这是一个典型的可以使用GridBagLayout进行界面设计的应用场合,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:计算器的界面设计" + +\end_inset + +所示。为了更好的适应窗口大小,界面中的所有控件设置了如下属性: +\end_layout + +\begin_layout Itemize +horizental align:Fill +\end_layout + +\begin_layout Itemize +virtical align: Fill +\end_layout + +\begin_layout Itemize +weight x : 1.0 +\end_layout + +\begin_layout Itemize +weight y : 1.0 +\end_layout + +\begin_layout Standard +完整的代码参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "Caculator.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/gui/src/cn/edu/sdut/softlab/Caculator.java" +lstparams "caption={Caculator.java},label={Caculator.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/caculator-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +计算器的界面设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:计算器的界面设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:计算器的运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/caculator-2.png + width 60line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +计算器的运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:计算器的运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +本例为了简化起见,表达式的求值借用了JDK内置的JavaScript引擎,有兴趣的读者可以自行实现一个表达式求值的引擎或者方法。 +\end_layout + +\begin_layout Exercise +请尝试使用GridLayout重新设计计算器(提示:首先使用GridLayout将界面分为上下两部分,上部分是一个Panel显示计算结果,使用任意的Layout +即可;下部分是一个显示计算按钮的Panel,使用GridLayout布局)。 +\end_layout + +\end_body +\end_document diff --git a/guide/lecture_guide/lecture14.lyx b/guide/lecture_guide/lecture14.lyx new file mode 100644 index 0000000..56afde2 --- /dev/null +++ b/guide/lecture_guide/lecture14.lyx @@ -0,0 +1,9802 @@ +#LyX 2.3 created this file. For more info see http://www.lyx.org/ +\lyxformat 544 +\begin_document +\begin_header +\save_transient_properties true +\origin unavailable +\textclass ctex-book +\begin_preamble +\input{../../../writing-common/book-preamble.tex} +\end_preamble +\use_default_options true +\begin_modules +tip-inset +note-inset +warning-inset +theorems-bytype +theorems-chap-bytype +logicalmkup +coderemarks +\end_modules +\maintain_unincluded_children false +\begin_local_layout +PackageOptions url hyphens +\end_local_layout +\language chinese-simplified +\language_package default +\inputencoding utf8-plain +\fontencoding global +\font_roman "default" "DejaVu Sans" +\font_sans "default" "DejaVu Serif" +\font_typewriter "default" "DejaVu Sans Mono" +\font_math "auto" "auto" +\font_default_family default +\use_non_tex_fonts true +\font_sc false +\font_osf false +\font_sf_scale 100 100 +\font_tt_scale 100 100 +\use_microtype false +\use_dash_ligatures true +\graphics default +\default_output_format pdf4 +\output_sync 0 +\bibtex_command default +\index_command default +\float_placement tbph +\paperfontsize default +\spacing single +\use_hyperref true +\pdf_bookmarks true +\pdf_bookmarksnumbered false +\pdf_bookmarksopen false +\pdf_bookmarksopenlevel 3 +\pdf_breaklinks true +\pdf_pdfborder true +\pdf_colorlinks true +\pdf_backref false +\pdf_pdfusetitle true +\papersize default +\use_geometry false +\use_package amsmath 1 +\use_package amssymb 1 +\use_package cancel 1 +\use_package esint 1 +\use_package mathdots 1 +\use_package mathtools 1 +\use_package mhchem 1 +\use_package stackrel 1 +\use_package stmaryrd 1 +\use_package undertilde 1 +\cite_engine basic +\cite_engine_type default +\biblio_style plain +\use_bibtopic false +\use_indices false +\paperorientation portrait +\suppress_date false +\justification true +\use_refstyle 1 +\use_minted 0 +\boxbgcolor #dad3d7 +\index Index +\shortcut idx +\color #008000 +\end_index +\secnumdepth 3 +\tocdepth 2 +\paragraph_separation indent +\paragraph_indentation default +\is_math_indent 0 +\math_numbering_side default +\quotes_style english +\dynamic_quotes 0 +\papercolumns 1 +\papersides 2 +\paperpagestyle default +\tracking_changes false +\output_changes false +\html_math_output 0 +\html_css_as_file 0 +\html_be_strict false +\end_header + +\begin_body + +\begin_layout Standard +\align center + +\size larger +\bar under +山东理工大学教案 +\end_layout + +\begin_layout Standard +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +第十四次课 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +教学课型:理论课□√ 实验课□√ 习题课□ 实践课□ 技能课□ 其它□ +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +主要教学内容 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:JAVA图形用户界面的事件机制" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:JAVA图形用户界面的事件机制" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:事件机制的基本原理" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "subsec:事件机制的基本原理" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:监听器类的几种情形" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "subsec:监听器类的几种情形" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Java-GUI综合应用举例" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:Java-GUI综合应用举例" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +重点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +Java事件处理机制的基本原理; +\end_layout + +\begin_layout Enumerate +常见的Java监听类; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +难点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +Java事件处理机制背后隐含的设计模式:监听器模式; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +课程目标及要求 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +课程目标:课程目标1 +\end_layout + +\begin_layout Plain Layout +要求: +\end_layout + +\begin_layout Enumerate +深刻理解Java的事件处理机制背后的原理; +\end_layout + +\begin_layout Enumerate +熟练掌握常见的事件监听类; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +教学方法和手段 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +板书和多媒体相结合,边讲边练,当堂消化。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +讨论、思考题 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +Java的事件处理过程是否需要和JVM打交道?为什么? +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +参考资料 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Chapter +图形用户界面设计 +\end_layout + +\begin_layout Standard +\align center +\begin_inset Graphics + filename ../imgs/gui/gui.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Section +Java的图形用户界面(GUI)设计概述 +\begin_inset CommandInset label +LatexCommand label +name "sec:Java的图形用户界面(GUI)设计概述" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java的图形用户界面( +\begin_inset Index idx +status open + +\begin_layout Plain Layout +GUI +\end_layout + +\end_inset + +GUI)是由 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JFC +\end_layout + +\end_inset + +JFC(Java Foundation Classes)支撑的,JFC包括了以下几个方面: +\end_layout + +\begin_layout Itemize +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Swing +\end_layout + +\end_inset + +Swing GUI组件:包含了图形用户界面设计中的人机交互组件,从最简单的按钮到复杂的图表等无所不包,这是我们学习的重点内容。 +\end_layout + +\begin_layout Itemize +可插拔的Look-and-Feel支持:Java图形用户界面支持可配置的Look-and-Feel切换,可以很容易的实现不同操作系统下的界面统一。 +\end_layout + +\begin_layout Itemize +辅助API:支持读屏幕等操作。 +\end_layout + +\begin_layout Itemize +Java 2D API:完善的2D绘图API。 +\end_layout + +\begin_layout Itemize +\begin_inset Index idx +status open + +\begin_layout Plain Layout +国际化 +\end_layout + +\end_inset + +国际化支持:秉承Java一贯的国际化支持,能够方便的在GUI中处理各种编码的文字。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +Swing是在早期的Java GUI应用程序设计接口AWT的基础上发展起来的,目前是Java GUI应用程序设计的官方标准。除了Swing之外,Eclipse( +www.eclipse.org)组织也发布了一套Java图形用户界面的设计库SWT(Standard Widget Toolkit),主要配合Eclipse的RCP +(Rich Client Program)应用程序开发,详情可参考:https://www.eclipse.org/swt/ +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +Swing入门 +\begin_inset CommandInset label +LatexCommand label +name "sec:Swing入门" + +\end_inset + + +\end_layout + +\begin_layout Standard +本节以JetBrain Idea为例说明如何创建和运行简单的 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Swing +\end_layout + +\end_inset + +Swing应用程序。 +\end_layout + +\begin_layout Example +使用Idea创建一个简单的Swing应用程序,将人民币转换为美元。 +\end_layout + +\begin_layout Paragraph* +步骤1 +\end_layout + +\begin_layout Standard +创建一个新的Java项目,见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:新建一个Java项目" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/getting-started-1.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +新建一个Java项目 +\begin_inset CommandInset label +LatexCommand label +name "fig:新建一个Java项目" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤2 +\end_layout + +\begin_layout Standard +在接下来的项目配置窗口中,可以不选择从模板创建项目,因为我们要创建一个GUI应用程序,命令行应用的模板没有实质用处,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:跳过从模板创建项目" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/getting-started-2.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +跳过从模板创建项目 +\begin_inset CommandInset label +LatexCommand label +name "fig:跳过从模板创建项目" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤3 +\end_layout + +\begin_layout Standard +给项目起个名字,这里叫做“gui”,并选择项目所在的目录,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:给项目起个名字" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/getting-started-3.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +给项目起个名字 +\begin_inset CommandInset label +LatexCommand label +name "fig:给项目起个名字" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤4 +\end_layout + +\begin_layout Standard +在项目的“project视图”中,右键点击src,在弹出的菜单中选择New->GUI Form,新建一个Form表单 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Form表单 +\end_layout + +\end_inset + +,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:准备新建一个Form表单" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-1.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +准备新建一个Form表单 +\begin_inset CommandInset label +LatexCommand label +name "fig:准备新建一个Form表单" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +如果在菜单中没有出现GUI Form子菜单,系没有安装Form Designer +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Form Designer +\end_layout + +\end_inset + +插件所致,请在系统设置中激活Form Designer即可,方法是在File->Settings...菜单中搜索“UI Designer”插件并安装激活,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:安装并激活UI-Designer插件" + +\end_inset + +所示。 +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/active-ui-designer.png + width 60line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +安装并激活UI Designer插件 +\begin_inset CommandInset label +LatexCommand label +name "fig:安装并激活UI-Designer插件" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +图片和文字可能不在一个页面,应该想办法处理一下 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤5 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:给Form起个名字" + +\end_inset + +所示,给将要创建的Form起个名字,这里叫做“RMB2DollarConverter”,选择布局管理器(此处先认可默认设置,随后可以更改)。注意要勾选(默认已经 +勾选了) +\begin_inset Quotes erd +\end_inset + +create bound class +\begin_inset Quotes erd +\end_inset + +选项,即同时创建和这个Form绑定在一起的Java类。这个Java类我们将来用于显示和操作这个Form。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-2.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +给Form起个名字 +\begin_inset CommandInset label +LatexCommand label +name "fig:给Form起个名字" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤6 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:空白的Form设计窗口" + +\end_inset + +所示,在新建Form后会呈现一个空白的Form设计窗口,其主要组成部分为: +\end_layout + +\begin_layout Itemize +界面组件关系图:在这个窗口中展示了组件的“父子”关系,目前只有一个JPanel组件,随后我们会加入更多组件,可以通过这个窗口直观的查看组件之间的关系。也可以通过 +这个窗口快捷的选择某个组件进行操作。 +\end_layout + +\begin_layout Itemize +组件属性窗:当在主设计界面或者界面组件关系窗口中选择了某个组件时,组件属性窗的内容将随之改变。可以通过这个窗口方便的了解界面组件拥有哪些属性,当然,更重要的是, +可以设置界面组件的属性值。 +\end_layout + +\begin_layout Itemize +主设计界面:可以拖放“组件面板”中的组件导主设计界面,主设计界面会根据使用的布局管理器的不同,自动摆放组件。 +\end_layout + +\begin_layout Itemize +组件面板:列出了各种Swing界面组件,可以方便的拖放到主设计界面。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-3.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +空白的Form设计窗口 +\begin_inset CommandInset label +LatexCommand label +name "fig:空白的Form设计窗口" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤7 +\end_layout + +\begin_layout Standard +首先在“界面组件关系窗口”中选择目前唯一的组件Panel,然后在组件属性窗口中编辑“field name”属性,设置其值为“mainPanel +\begin_inset Quotes erd +\end_inset + +。这里的值是什么并不重要的,重要的是必须给主Panel设置一个名字,否则将来无法显示这个Panel。 +\end_layout + +\begin_layout Standard +在这里,我们也将mainPanel的 +\begin_inset Quotes erd +\end_inset + +Layout Manager +\begin_inset Quotes erd +\end_inset + +(布局管理器)修改为更为简单的 +\begin_inset Quotes erd +\end_inset + +FlowLayout +\begin_inset Quotes erd +\end_inset + +,我们将在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:布局管理器" + +\end_inset + +一节详细的阐述各种布局管理器 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +布局管理器 +\end_layout + +\end_inset + +的用法。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-4.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +给主Panel起个名字 +\begin_inset CommandInset label +LatexCommand label +name "fig:给主Panel起个名字" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤8 +\end_layout + +\begin_layout Standard +在“组件面板”窗口选择JLabel组件拖放到主设计界面,可以看到在“界面组件关系”窗口中,JLabel包含在mainPanel中。这里只是简单的设置这个JLab +el的text属性为“人民币:”即可。JLabel的目的是显示一个标签 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +标签 +\end_layout + +\end_inset + +,我们将在 +\begin_inset CommandInset ref +LatexCommand formatted +reference "subsec:JLabel" + +\end_inset + +一节详细讨论Jlabel的用法。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-5.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +添加一个简单的Label +\begin_inset CommandInset label +LatexCommand label +name "fig:添加一个简单的Label" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤9 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:添加JTextField组件" + +\end_inset + +所示,接着添加一个JTextField +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JTextField +\end_layout + +\end_inset + +组件到主设计界面。这个JTextField我们用来输入人民币数额,因此要设置其 +\begin_inset Quotes erd +\end_inset + +field name +\begin_inset Quotes erd +\end_inset + +属性。为了更好的显示这个输入框,也设置了这个JTextField的默认宽度(preferedSize->width)和默认显示的文字(text属性)。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-6.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +添加JTextField组件 +\begin_inset CommandInset label +LatexCommand label +name "fig:添加JTextField组件" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤10 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:添加转换按钮" + +\end_inset + +所示,再增加一个“转换”按钮 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +按钮 +\end_layout + +\end_inset + +,设置这个按钮的field name和text属性。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-7.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +添加转换按钮 +\begin_inset CommandInset label +LatexCommand label +name "fig:添加转换按钮" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤11 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:添加显示转换结果的JLabel" + +\end_inset + +所示,在界面中再添加一个用于显示转换结果的JLabel。由于我们要通过程序设置这个JLabel的text属性,因此要设置这个JLabel的field + name属性。为了能够更好的显示转换后的结果,也有设置这个JLabel的宽度,这里设置为100(像素值)。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-8.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +添加显示转换结果的JLabel +\begin_inset CommandInset label +LatexCommand label +name "fig:添加显示转换结果的JLabel" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤12 +\begin_inset CommandInset label +LatexCommand label +name "par:步骤12" + +\end_inset + + +\end_layout + +\begin_layout Standard +界面的设计工作基本就绪,下面我们为按钮设计处理代码。如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:准备创建Listener" + +\end_inset + +所示,在主设计界面的“转换”按钮上点击右键,在弹出的菜单中选择“create Listener”,准备创建一段点击此按钮的响应代码。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-9.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +准备创建Listener +\begin_inset CommandInset label +LatexCommand label +name "fig:准备创建Listener" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤13 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:选择Listener的类型" + +\end_inset + +所示,在接下来的窗口中选择Listener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Listener +\end_layout + +\end_inset + +的类型为“ActionListener”。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-10.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +选择Listener的类型 +\begin_inset CommandInset label +LatexCommand label +name "fig:选择Listener的类型" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +步骤14 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:选择需要覆盖的方法" + +\end_inset + +所示,在接下来的窗口中,选择ActionListener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +ActionListener +\end_layout + +\end_inset + +需要覆盖的方法。这里只有一个选项,已经自动选中了。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-11.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +选择需要覆盖的方法 +\begin_inset CommandInset label +LatexCommand label +name "fig:选择需要覆盖的方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +点击 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:选择需要覆盖的方法" + +\end_inset + +中的“OK”按钮后,在所绑定的方法中自动添加了一个构造方法 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +构造方法 +\end_layout + +\end_inset + +,内容如下(行5-7是自己编写的): +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + public RMB2DollarConverter() { +\end_layout + +\begin_layout Plain Layout + + convertButton.addActionListener(new ActionListener() { +\end_layout + +\begin_layout Plain Layout + + @Override +\end_layout + +\begin_layout Plain Layout + + public void actionPerformed(ActionEvent actionEvent) { +\end_layout + +\begin_layout Plain Layout + + // 获取文本输入框的文字内容并转换为double +\end_layout + +\begin_layout Plain Layout + + Double rmb = Double.valueOf(rmbTextField.getText()); +\end_layout + +\begin_layout Plain Layout + + dollarLabel.setText(String.valueOf(rmb / 7.0)); // 假设当前人民币和美元汇率为7.0 +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + }); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +这是GUI应用程序事件处理的基本方法,我们将在 +\begin_inset CommandInset ref +LatexCommand formatted +reference "sec:JAVA图形用户界面的事件机制" + +\end_inset + +一节中具体讨论。 +\end_layout + +\begin_layout Paragraph* +步骤15 +\end_layout + +\begin_layout Standard +最后一步,我们需要在类RMB2DollarConverter中增加一个main方法并初始化和显示应用程序窗口,JetBrain Idea提供了自动化的代码生成工 +具,只需要在代码的合适位置(希望插入main方法的位置)按下Alt+Insert +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Alt+Insert +\end_layout + +\end_inset + +组合键,在如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:准备插入main方法" + +\end_inset + +所示的窗口中选择 +\begin_inset Quotes erd +\end_inset + +Form main() +\begin_inset Quotes erd +\end_inset + +即可自动创建main方法如下: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + public static void main(String[] args) { +\end_layout + +\begin_layout Plain Layout + + JFrame frame = new JFrame("RMB2DollarConverter"); +\end_layout + +\begin_layout Plain Layout + + frame.setContentPane(new RMB2DollarConverter().mainPanel); +\end_layout + +\begin_layout Plain Layout + + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); +\end_layout + +\begin_layout Plain Layout + + frame.pack(); +\end_layout + +\begin_layout Plain Layout + + frame.setVisible(true); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/new-form-12.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +准备插入main方法 +\begin_inset CommandInset label +LatexCommand label +name "fig:准备插入main方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +经过了以上的15个步骤,现在终于可以运行这个应用程序了 +\begin_inset Foot +status open + +\begin_layout Plain Layout +本例的完整代码请参见:https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui +\end_layout + +\end_inset + +。和运行其他Java应用程序的方法一样,运行RMB2DollarConverter类结果如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand formatted +reference "fig:RMB2DollarConverter的运行结果" + +\end_inset + +所示。可以在输入框输入人民币数额,然后点击“转换”按钮获得相应的美元数。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/RMB2DollarConverter-output.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +RMB2DollarConverter的运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:RMB2DollarConverter的运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +虽然在上面我们使用了15个步骤创建了一个简单的GUI应用程序,其实关键的步骤是4个,如下图所示: +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset include +LatexCommand input +filename "../imgs/gui/basic-gui-flow.pgf" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status collapsed + +\begin_layout Plain Layout +你可能会问,在类RMB2DollarConverter中的几个私有属性(对象):mainPanel、rmbTextField等是什么时候初始化的?很好的问题! +\end_layout + +\begin_layout Plain Layout +实际上,Idea通过一个xml文件(RMB2DollarConvert.form)保存了界面中所包含的组件及其属性和相互关系,在编译的时候,Idea会自动读取这个 +界面配置文件并生成创建界面中的组件的构造方法,也就是说,mainPanel等对象其实是Idea帮我们创建了的,我们可以直接拿来就用。 +\end_layout + +\begin_layout Plain Layout +可以通过反编译class文件看到这一点,在构造方法中的setupUI方法创建了各个界面组件对象(部分删减,请自行运行jad RMB2DollarConverte +r获得完整的反编译后的文件): +\end_layout + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class RMB2DollarConverter +\end_layout + +\begin_layout Plain Layout + +{ +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + public static void main(String args[]) +\end_layout + +\begin_layout Plain Layout + + { +\end_layout + +\begin_layout Plain Layout + + JFrame frame = new JFrame("RMB2DollarConverter"); +\end_layout + +\begin_layout Plain Layout + + frame.setContentPane((new RMB2DollarConverter()).mainPanel); +\end_layout + +\begin_layout Plain Layout + + frame.setDefaultCloseOperation(3); +\end_layout + +\begin_layout Plain Layout + + frame.pack(); +\end_layout + +\begin_layout Plain Layout + + frame.setVisible(true); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + public RMB2DollarConverter() +\end_layout + +\begin_layout Plain Layout + + { +\end_layout + +\begin_layout Plain Layout + + setupUI(); +\end_layout + +\begin_layout Plain Layout + + convertButton.addActionListener(new ActionListener() { +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + public void actionPerformed(ActionEvent actionEvent) +\end_layout + +\begin_layout Plain Layout + + { +\end_layout + +\begin_layout Plain Layout + + Double rmb = Double.valueOf(rmbTextField.getText()); +\end_layout + +\begin_layout Plain Layout + + dollarLabel.setText(String.valueOf(rmb.doubleValue() / 7D)); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + }); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + private void setupUI() +\end_layout + +\begin_layout Plain Layout + + { +\end_layout + +\begin_layout Plain Layout + + JPanel jpanel; +\end_layout + +\begin_layout Plain Layout + + JLabel jlabel; +\end_layout + +\begin_layout Plain Layout + + jpanel = new JPanel(); +\end_layout + +\begin_layout Plain Layout + + mainPanel = jpanel; +\end_layout + +\begin_layout Plain Layout + + jpanel.setLayout(new FlowLayout(1, 5, 5)); +\end_layout + +\begin_layout Plain Layout + + jlabel = new JLabel(); +\end_layout + +\begin_layout Plain Layout + + jlabel.setText(" +\backslash +u4EBA +\backslash +u6C11 +\backslash +u5E01 +\backslash +uFF1A"); +\end_layout + +\begin_layout Plain Layout + + jpanel.add(jlabel); +\end_layout + +\begin_layout Plain Layout + + JTextField jtextfield; +\end_layout + +\begin_layout Plain Layout + + jtextfield = new JTextField(); +\end_layout + +\begin_layout Plain Layout + + rmbTextField = jtextfield; +\end_layout + +\begin_layout Plain Layout + + jtextfield.setMinimumSize(new Dimension(14, 29)); +\end_layout + +\begin_layout Plain Layout + + jtextfield.setPreferredSize(new Dimension(60, 29)); +\end_layout + +\begin_layout Plain Layout + + jtextfield.setText("#.##"); +\end_layout + +\begin_layout Plain Layout + + jtextfield.setToolTipText(" +\backslash +u8BF7 +\backslash +u8F93 +\backslash +u5165 +\backslash +u4EBA +\backslash +u6C11 +\backslash +u5E01 +\backslash +u6570 +\backslash +u989D"); +\end_layout + +\begin_layout Plain Layout + + jpanel.add(jtextfield); +\end_layout + +\begin_layout Plain Layout + + JButton jbutton; +\end_layout + +\begin_layout Plain Layout + + jbutton = new JButton(); +\end_layout + +\begin_layout Plain Layout + + convertButton = jbutton; +\end_layout + +\begin_layout Plain Layout + + jbutton.setText(" +\backslash +u8F6C +\backslash +u6362"); +\end_layout + +\begin_layout Plain Layout + + jpanel.add(jbutton); +\end_layout + +\begin_layout Plain Layout + + JLabel jlabel1; +\end_layout + +\begin_layout Plain Layout + + jlabel1 = new JLabel(); +\end_layout + +\begin_layout Plain Layout + + dollarLabel = jlabel1; +\end_layout + +\begin_layout Plain Layout + + jlabel1.setPreferredSize(new Dimension(100, 21)); +\end_layout + +\begin_layout Plain Layout + + jlabel1.setText(" +\backslash +u7F8E +\backslash +u5143 +\backslash +uFF1A"); +\end_layout + +\begin_layout Plain Layout + + jpanel.add(jlabel1); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + private JPanel mainPanel; +\end_layout + +\begin_layout Plain Layout + + private JTextField rmbTextField; +\end_layout + +\begin_layout Plain Layout + + private JButton convertButton; +\end_layout + +\begin_layout Plain Layout + + private JLabel dollarLabel; +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status collapsed + +\begin_layout Plain Layout +在Idea的Form Designer中,我们看到可以直接拖放各种控件到应用程序界面中,并且可以直观的通过“属性查看器”查看和修改控件的属性,其中一个重要的属性 +是field name属性,即属性的名称。什么时候需要给控件的field name属性赋值,什么时候不需要理会field name属性呢?简单的说,如果我们在程 +序中需要获得这个控件的其他属性,比如输入的文字,或者需要在程序运行期间通过程序改变这个控件的状态,则需要给这个控件的field name赋值。比如常见的JLab +el控件一般是不需要field name属性的,而JTextField则需要field name属性。 +\end_layout + +\begin_layout Plain Layout +进一步的观察我们可以发现,只有给控件一个field name属性值,Idea才能在绑定的类中自动创建私有的属性对象(变量)表示这个控件,变量的名字就是field + name属性的值。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +GUI的顶级容器类 +\begin_inset CommandInset label +LatexCommand label +name "sec:GUI的顶级容器类" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java的图形用户界面也是“面向对象”的,比如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java图形用户界面应用程序的大致布局" + +\end_inset + +是常见的一个窗口应用程序,我们从Java的观点来看,可以分为如下的几部分: +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/swing-app-outline.png + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java图形用户界面应用程序的大致布局 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java图形用户界面应用程序的大致布局" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +整个应用程序框架使用JFrame +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JFrame +\end_layout + +\end_inset + +来表示,在JFrame内部布置了菜单栏(JMenuBar)、工具栏(JToolBar)、内容区(ContentPane),我们最经常操作的区域是ContentP +ane,即几乎所有的界面设计工作集中在ContentPane上面。 +\end_layout + +\begin_layout Standard +所以,JFrame是一个顶层的容器 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +容器 +\end_layout + +\end_inset + +,其他所有的界面组件都放置在顶层容器 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +顶层容器 +\end_layout + +\end_inset + +之中,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java-GUI应用程序的基本结构" + +\end_inset + +所示。除了JFrame之外,Java也提供了JDialog、JApplet +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JApplet +\end_layout + +\end_inset + +顶层容器,分别用于对话框的设计和Applet +\begin_inset Foot +status open + +\begin_layout Plain Layout +一种已经没落的技术。 +\end_layout + +\end_inset + +的设计。本章重点介绍基于JFrame的Java图形用户界面设计,JDialog +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JDialog +\end_layout + +\end_inset + +的用法于此类似。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jframe-overview.eps + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java GUI应用程序的基本结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java-GUI应用程序的基本结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +不介绍分层的面板会有影响吗? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +下面的代码展示了 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java-GUI应用程序的基本结构" + +\end_inset + +中的组件间的关系: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +JFrame frame = new JFrame("标题栏内容"); +\end_layout + +\begin_layout Plain Layout + +frame.getContentPane().add(new JLabel("a label", BorderLayout.TOP)); +\end_layout + +\begin_layout Plain Layout + +frame.getContentPane().add(new JTextField("##.##", BorderLayout.BOTTOM)); +\end_layout + +\begin_layout Plain Layout + +JPanel panel = new JPanel(); +\end_layout + +\begin_layout Plain Layout + +panel.add(new JLabel("another label")); +\end_layout + +\begin_layout Plain Layout + +panel.add(new JCheckBox(...)); +\end_layout + +\begin_layout Plain Layout + +frame.add(panel, BorderLayout.CENTER); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +Swing控件 +\begin_inset CommandInset label +LatexCommand label +name "sec:Swing控件" + +\end_inset + + +\end_layout + +\begin_layout Subsection +JLabel +\begin_inset CommandInset label +LatexCommand label +name "subsec:JLabel" + +\end_inset + + +\end_layout + +\begin_layout Standard +Label(文本标签)也许是最简单的Swing控件了,一般用来表示界面上的几个字符或者一段提示性文字、展示输出结果、图标等。 +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JLabel +\end_layout + +\end_inset + +JLabel的主要属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:JLabel的主要属性" + +\end_inset + +所示(每个属性对应一对get/set方法),请参照Form Designer +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Form Designer +\end_layout + +\end_inset + +的属性对话框了解属性值的可能取值范围。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +说明 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +icon +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label所使用的图片 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +text +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label显示的文字 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label的水平对齐方式 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +verticalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label的纵向对齐方式 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalTextPosition +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label文字的水平位置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +verticalTextPosition +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label文字的垂直位置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +textGap +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Label文字和图片之间的间隙(像素值) +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JLabel的主要属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:JLabel的主要属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +JLabel示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整的代码请参见:https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/sr +c/cn/edu/sdut/softlab/,双击JLabelDemo.form即可打开Form Designer查看界面设计效果。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +我们在内容区增加了三个JLabel:最上面的Label同时包含了文字和图片,中间的Label只包含了文字,最下面的Label只包含了图片,其属性对话框的设置分别 +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:顶部Label属性框设置" + +\end_inset + + +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:中间Label属性框设置" + +\end_inset + + +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:下面Label属性框设置" + +\end_inset + +所示,其中修改过的属性已经黑体加重标注了,没有使用黑体标注的属性无需设置。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +当拖放第一个JLabel到内容区的时候,Form Designer自动在这个JLabel的下面增加了一个垂直占位符,以保证这个JLabel能够在希望的顶部展示。 +由于我们还要增加下面的两个Label,因此这里可以删除这个垂直占位符。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/gui/jlabel-demo-1.png + width 30line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +顶部Label属性框设置 +\begin_inset CommandInset label +LatexCommand label +name "fig:顶部Label属性框设置" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/gui/jlabel-demo-2.png + width 30line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +中间Label属性框设置 +\begin_inset CommandInset label +LatexCommand label +name "fig:中间Label属性框设置" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/gui/jlabel-demo-3.png + width 30line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +下面Label属性框设置 +\begin_inset CommandInset label +LatexCommand label +name "fig:下面Label属性框设置" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JLabel的属性对话框 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行此示例,初始状态如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:运行的初始状态" + +\end_inset + +所示,可以尝试缩放窗口,比如水平放大窗口可以更明显的看出效果,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:水平方法后的窗口" + +\end_inset + +所示。请任意缩放窗口请注意观察这三个Label位置的变化,体会水平对齐 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +水平对齐 +\end_layout + +\end_inset + +、垂直对齐 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +垂直对齐 +\end_layout + +\end_inset + +等的效果。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jlabel-demo-4.png + height 30theight% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +运行的初始状态 +\begin_inset CommandInset label +LatexCommand label +name "fig:运行的初始状态" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jlabel-demo-5.png + height 30theight% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +水平放大后的窗口 +\begin_inset CommandInset label +LatexCommand label +name "fig:水平方法后的窗口" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JLabelDemo运行结果 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +注意以下几点: +\end_layout + +\begin_layout Itemize +这三个 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JLabel +\end_layout + +\end_inset + +JLabel都无需设置field name属性值。 +\end_layout + +\begin_layout Itemize +特别注意观察Horizental Align属性的不同效果,可以尝试不同的水平对齐方式观察效果(通过Idea的Form Designer提供的预览工具更方便,在 +Form Designer界面直接右键选择“preview”即可)。 +\end_layout + +\begin_layout Itemize +在组合使用文本和图片时,还要注意horizentalTextPosition +\begin_inset Index idx +status open + +\begin_layout Plain Layout +horizentalTextPosition +\end_layout + +\end_inset + +和verticalTextPosition +\begin_inset Index idx +status open + +\begin_layout Plain Layout +verticalTextPosition +\end_layout + +\end_inset + +这两个属性的效果。 +\end_layout + +\begin_layout Subsection +文本控件 +\begin_inset CommandInset label +LatexCommand label +name "subsec:JTextField" + +\end_inset + + +\end_layout + +\begin_layout Standard +Swing的文本控件是指能够输入文本的控件,比如文本框(JTextField +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JTextField +\end_layout + +\end_inset + +)、文本域(JTextArea +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JTextArea +\end_layout + +\end_inset + +)、富文本编辑器(JEdtiorPane +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JEdtiorPane +\end_layout + +\end_inset + +)等。Swing的文本控件类的关系如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:文本输入控件" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/text-input-controls.eps + lyxscale 40 + scale 40 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +文本输入控件 +\begin_inset CommandInset label +LatexCommand label +name "fig:文本输入控件" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +单行纯文本控件:用于输入一行纯文本字符串。根据场合不同,可以选择使用JTextField,输入简单的单行字符串;或者JFormattedTextField +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JFormattedTextField +\end_layout + +\end_inset + +,输入格式化的单行字符串,比如表示日期的“2017-3-12”等;或者JPasswordField +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JPasswordField +\end_layout + +\end_inset + +,输入密码(默认不显示输入的密码)。 +\end_layout + +\begin_layout Itemize +多行纯文本控件:用于输入多行纯文本字符串。如果需要输入的字符串比较长,可以采用JTextArea +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JTextArea +\end_layout + +\end_inset + +,会显示一个多行的文本编辑区域供输入。 +\end_layout + +\begin_layout Itemize +多行富文本控件:用于输入带格式的文本字符串,通常用于输入HTML等格式的字符串。 +\end_layout + +\begin_layout Standard +文本控件的常见属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:文本控件的常见属性" + +\end_inset + +所示,请参照Form Designer中的属性对话框了解这些属性的取值范围。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +说明 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +text +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +文本框的内容 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +editable +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +是否可编辑 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +columns +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +文本框的长度(多少个字符),仅仅作为计算默认显示宽度的依据 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +字符在文本框内的对齐方式,可以选择:JTextField.LEADING, JTextField.CENTER, JTextField.TRAILING +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +文本控件的常见属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:文本控件的常见属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +文本控件示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +我们设计一个同时展示三种TextField的Panel,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:文本控件示例" + +\end_inset + +所示 +\begin_inset Foot +status open + +\begin_layout Plain Layout +详情请参见:https://github.com/subaochen/java-tutorial-examples/blob/master/gui/src/cn/ +edu/sdut/softlab/TextControlDemo.form +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +.当在文本框中输入一些字符后(失去焦点后),在最下面的 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Label +\end_layout + +\end_inset + +Label中显示输入的内容。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/textfield-demo-1.png + width 95line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +文本控件示例 +\begin_inset CommandInset label +LatexCommand label +name "fig:文本控件示例" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行此应用程序的界面如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:文本控件示例运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/textfield-demo-2.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +文本控件示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:文本控件示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +这个简单的示例我们要注意以下三点: +\begin_inset Note Note +status open + +\begin_layout Plain Layout +示例代码的布局要说明吗? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +可以通过 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Panel +\end_layout + +\end_inset + +Panel进一步组织控件,这是一种常见的手段。在例中,我们把三个 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +TextField +\end_layout + +\end_inset + +TextField控件放到一个Panel中,在把这Panel添加到mainPanel中。并且,放置三个TextField的Panel添加了标题(title):“ +单行纯文本控件”,以更清晰的表达这个Panel的意义,这也是一种常见的手段。 +\end_layout + +\begin_layout Itemize +请参照 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "par:步骤12" + +\end_inset + +为三个TextField添加FocusListener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +FocusListener +\end_layout + +\end_inset + +,这里我们重点监听了失去焦点的事件。 +\end_layout + +\begin_layout Itemize +本例也可以监听ActionListener(当在输入框按下回车键时触发该事件)获得当前输入框的内容,请读者自行完成相关代码并运行测试。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +焦点 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +焦点 +\end_layout + +\end_inset + +(Focus)通常是指文本输入框是否正在接受输入。获得焦点即文本输入框可以输入文字,失去焦点即文本输入框不再能够输入文字,即光标已经离开了此输入框。失去焦点往往 +意味着用户结束了输入,因此,我们可以通过监听失去焦点事件来获得文本输入框中的内容。 +\end_layout + +\begin_layout Plain Layout +如果焦点的概念用于窗口(应用程序),则获得焦点意味着当前窗口是活动窗口,即可操作的窗口;失去焦点意味着其他窗口获得了焦点,当前窗口不可操作。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +JButton +\begin_inset CommandInset label +LatexCommand label +name "subsec:JButton" + +\end_inset + + +\end_layout + +\begin_layout Standard +按钮(Button +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Button +\end_layout + +\end_inset + +)是一种常见的交互控件,在Swing中最常见的按钮通过JButton +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JButton +\end_layout + +\end_inset + +来描述。按钮用法很直接,通常涉及到以下三个方面: +\end_layout + +\begin_layout Itemize +给按钮一个合适的名称,包括显示在按钮上面的文字。 +\end_layout + +\begin_layout Itemize +有的时候希望在按钮上面也显示图标以更明确的表达按钮的意思,可以通过按钮的icon +\begin_inset Index idx +status open + +\begin_layout Plain Layout +icon +\end_layout + +\end_inset + +属性来设置图标。 +\end_layout + +\begin_layout Itemize +给按钮添加鼠标点击的响应代码( +\begin_inset Index idx +status open + +\begin_layout Plain Layout +ActionListener +\end_layout + +\end_inset + +ActionListener或者MouseListener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +MouseListener +\end_layout + +\end_inset + +)。 +\end_layout + +\begin_layout Standard +JButton的常见属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:JButton的常见属性" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +说明 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +enabled +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +是否允许点击 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +icon +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +在按钮上面要显示的图标 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +text +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +在按钮上面要显示的文字 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalTextPosition +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +水平方向的文字位置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +verticalTextPosition +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +垂直方向的文字位置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +水平方向的对齐方式 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +virticalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +垂直方向的对齐方式 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JButton的常见属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:JButton的常见属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +JButton示例 +\begin_inset CommandInset label +LatexCommand label +name "exa:JButton示例" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +我们设计一个包含三个按钮的Panel,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Button示例Panel" + +\end_inset + +所示 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整的代码请参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/button-demo-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Button示例Panel +\begin_inset CommandInset label +LatexCommand label +name "fig:Button示例Panel" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +依然参照 +\begin_inset CommandInset ref +LatexCommand formatted +reference "par:步骤12" + +\end_inset + +为这三个Button 添加三个ActionListener,分别响应鼠标左键单击事件。 +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +在运行时点击各个按钮,观察发生了什么?比如点击“紧急呼叫”按钮,弹出了一个消息框,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Button示例运行结果" + +\end_inset + +所示。点击“被禁止的按钮”,会怎样? +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/button-demo-2.png + width 50line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Button示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:Button示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +请仔细查看三个按钮的属性对话框以了解这三个按钮是如何实现这样的效果的: +\end_layout + +\begin_layout Itemize +第一个按钮演示了按钮上是可以图文并茂的(设置icon +\begin_inset Index idx +status open + +\begin_layout Plain Layout +icon +\end_layout + +\end_inset + +属性即可),并且通过设置horizentalTextPosition +\begin_inset Index idx +status open + +\begin_layout Plain Layout +horizentalTextPosition +\end_layout + +\end_inset + +属性为Leading(在开头),将图片放到了文字的后面。 +\end_layout + +\begin_layout Itemize +第二个按钮演示了如何将按钮上的文字和图片上下布局:首先让按钮上的内容水平居中(horizentalTextPosition +\begin_inset Index idx +status open + +\begin_layout Plain Layout +horizentalTextPosition +\end_layout + +\end_inset + +属性为Center),然后设置verticalTextPosition +\begin_inset Index idx +status open + +\begin_layout Plain Layout +verticalTextPosition +\end_layout + +\end_inset + +属性为Bottom即可。 +\end_layout + +\begin_layout Itemize +第三个按钮设置enabled为false即可,即去掉默认选中的enabled选项。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +默认的,JButton的actionListener是响应鼠标左键单击事件的,比如在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +example +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:JButton示例" + +\end_inset + +中,我们给按钮增加了响应鼠标左键单击的actionListener,那么如何响应鼠标右键、中键的单击事件呢?参见下面的代码: +\end_layout + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +// 响应右键单击事件 +\end_layout + +\begin_layout Plain Layout + +emegencyCallButton.addMouseListener(new MouseAdapter() { +\end_layout + +\begin_layout Plain Layout + + @Override +\end_layout + +\begin_layout Plain Layout + + public void mouseClicked(MouseEvent mouseEvent) { +\end_layout + +\begin_layout Plain Layout + + super.mouseClicked(mouseEvent); +\end_layout + +\begin_layout Plain Layout + + if(SwingUtilities.isRightMouseButton(mouseEvent) && mouseEvent.getClickCou +nt() == 1) { +\end_layout + +\begin_layout Plain Layout + + JOptionPane.showMessageDialog(null,"右键单击急呼叫按钮"); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +}); +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +JCheckBox +\begin_inset CommandInset label +LatexCommand label +name "subsec:JCheckBox" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JCheckBox +\end_layout + +\end_inset + +JCheckBox通常叫做“复选框”,即可以同时打开或关闭多个选项 +\begin_inset Foot +status open + +\begin_layout Plain Layout +对比一下JRadioButton(单选框),JRadionButton只能在一组选项中选中一项。 +\end_layout + +\end_inset + +。当选项被选中时,该复选框的“选择”状态为true,否则为false。 +\end_layout + +\begin_layout Standard +JCheckBox的常见属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:JCheckBox的常见属性" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +说明 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +text +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +CheckBox的提示文字 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +icon +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +CheckBox的提示图片 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +enabled +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +是否启用这个控件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +selected +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +CheckBox默认的选中状态 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +文字的水平对齐方式 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizentalTextPosition +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +文字的水平位置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +verticalAlignment +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +文字的垂直对齐方式 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +virticalTextPosition +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +文字的垂直位置 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JCheckBox的常见属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:JCheckBox的常见属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +JCheckBox示例 +\begin_inset CommandInset label +LatexCommand label +name "exa:JCheckBox示例" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +我们设计一个包含4个CheckBox(业余爱好)的Panel +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +,当鼠标点击某个爱好时显示选中的CheckBox的状态;当鼠标移动到某个爱好上面时,同步显示表示这个业余爱好的图片,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JCheckBox运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/checkbox-demo-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JCheckBox示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:JCheckBox示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +在运行时,注意观察鼠标在各个CheckBox上面和离开CheckBox时界面的不同反应,选中或者反选选项时不同的消息提示,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JCheckBox运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/checkbox-demo-2.png + width 20line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +运行初始状态 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/checkbox-demo-3.png + width 20line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +鼠标移动到“足球”选项 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/checkbox-demo-4.png + width 45line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +选中“足球”选项 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JCheckBox运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:JCheckBox运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +我们为每个JCheckBox添加了两个事件监听器,一个ActionListener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +ActionListener +\end_layout + +\end_inset + +用于监听鼠标左键单击选项选择或者反选时产生的事件,一个MouseListener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +MouseListener +\end_layout + +\end_inset + +用于监听当鼠标进入或者离开选项所在区域时产生的事件。 +\end_layout + +\begin_layout Paragraph +延伸阅读 +\end_layout + +\begin_layout Standard +其实,JButton +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JButton +\end_layout + +\end_inset + +, JCheckBox +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JCheckBox +\end_layout + +\end_inset + +, JRadionButton +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JRadionButton +\end_layout + +\end_inset + +等都从 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +AbstractButton +\end_layout + +\end_inset + +AbstractButton继承下来的,即JButton一族的类层次关系如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Button类层次关系" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/button-overview.eps + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Button类层次关系 +\begin_inset CommandInset label +LatexCommand label +name "fig:Button类层次关系" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +因此,JButtron、JCheckBox、JRadionButton等的共性就不难理解了。 +\end_layout + +\begin_layout Subsection +JRadioButton +\begin_inset CommandInset label +LatexCommand label +name "subsec:JRadioButton" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JRadioButton +\end_layout + +\end_inset + +JRadioButton通常叫做“单选框”,即通过JRadionButton可以展示一组选项,但是只能有一个选项处于“选中”状态。当选择另外一个选项时,原先被选 +中的选项自动失效。 +\end_layout + +\begin_layout Standard +JRadionButton的常见属性和JCheckBox基本相同,只有一点需要注意:JRadioButton的buttonGroup属性是必须设置的,即每个JR +adioButton都需要设置buttonGroup属性,表明这个JRadioButton是属于哪个“组”的,以便Java根据用户的选择情况设置当前组的Radi +oButton哪个有效,哪个失效。 +\end_layout + +\begin_layout Example +JRadionButton示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +类似于 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:JCheckBox示例" + +\end_inset + +,我们设计一个图形用户应用程序 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整的代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +,根据选项决定显示哪种运动的图片,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JRadioButton示例设计" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jradiobutton-demo-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JRadioButton示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:JRadioButton示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +点击不同的选项,将显示不同的运动图片,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JRadionButton示例运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jradiobutton-demo-2.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JRadionButton示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:JRadionButton示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +本例中,我们手工创建了ActionListener +\begin_inset Index idx +status open + +\begin_layout Plain Layout +ActionListener +\end_layout + +\end_inset + +,通常JRadioButton的ActionListener需要手工创建更合适,因为JRadioButton一般需要设置为属于某个ButtonGroup,整个B +uttonGroup设计一个ActionListener就可以了,没有必要每个JRadioButton都独立设计一个ActionListener,如下列代码所示 +: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + public RadioButtonDemo() { +\end_layout + +\begin_layout Plain Layout + + swimming.setActionCommand("swimming"); +\end_layout + +\begin_layout Plain Layout + + swimming.addActionListener(this); +\end_layout + +\begin_layout Plain Layout + + tennis.setActionCommand("tennis"); +\end_layout + +\begin_layout Plain Layout + + tennis.addActionListener(this); +\end_layout + +\begin_layout Plain Layout + + basketball.setActionCommand("basketball"); +\end_layout + +\begin_layout Plain Layout + + basketball.addActionListener(this); +\end_layout + +\begin_layout Plain Layout + + football.setActionCommand("football"); +\end_layout + +\begin_layout Plain Layout + + football.addActionListener(this); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + @Override +\end_layout + +\begin_layout Plain Layout + + public void actionPerformed(ActionEvent actionEvent) { +\end_layout + +\begin_layout Plain Layout + + sportLabel.setIcon(new ImageIcon(RadioButtonDemo.class.getResource("/images +/" +\end_layout + +\begin_layout Plain Layout + + + actionEvent.getActionCommand() + ".png"))); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在以上代码中,我们在构造方法中为每个JRadioButton指定了actionCommand +\begin_inset Index idx +status open + +\begin_layout Plain Layout +actionCommand +\end_layout + +\end_inset + +以便在监听器代码中获取actionCommand拼装图片的路径。 +\end_layout + +\begin_layout Standard +另外需要注意的是,我们需要将这组JRadionButton设置一个共同的ButtonGroup,即在Form Designer中如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:设置ButtonGroup" + +\end_inset + +所示,创建一个新的ButtonGroup +\begin_inset Index idx +status open + +\begin_layout Plain Layout +ButtonGroup +\end_layout + +\end_inset + +,并将所有JRadioButton的ButtonGroup属性都设置为这个新建的ButtonGroup。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jradiobutton-demo-3.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +设置ButtonGroup +\begin_inset CommandInset label +LatexCommand label +name "fig:设置ButtonGroup" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +JComboBox +\begin_inset CommandInset label +LatexCommand label +name "subsec:JComboBox" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +JcomboBox +\end_layout + +\end_inset + +JcomboBox表示“下列选择框”,通常在空间比较紧张或者选项很多时采用下拉选择框比较合适。 +\end_layout + +\begin_layout Example +下拉选择框示例 +\begin_inset CommandInset label +LatexCommand label +name "exa:下拉选择框示例" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:JCheckBox示例" + +\end_inset + +类似,我们设计一个下拉选择框来提供运动项目选项 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +,当选中某个运动项目时则显示相应的图片,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JComboBox示例设计" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jcombobox-demo-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JComboBox示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:JComboBox示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +注意到,下拉选择框sports需要设置在其中要显示的条目,可以通过属性对话框的model属性来设置,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JComboBox的model属性设置" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jcombobox-demo-2.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JComboBox的model属性设置 +\begin_inset CommandInset label +LatexCommand label +name "fig:JComboBox的model属性设置" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +该示例的运行结果如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:JComboBox示例的运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/jcombobox-demo-3.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +JComboBox示例的运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:JComboBox示例的运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +其他常见控件 +\end_layout + +\begin_layout Subsubsection* +Spinner +\begin_inset CommandInset label +LatexCommand label +name "subsec:Spinner" + +\end_inset + + +\end_layout + +\begin_layout Standard +Spinner是一种便捷填写数字的控件,详情请参见示例代码: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + +及其注释。 +\end_layout + +\begin_layout Subsubsection* +Slider +\begin_inset CommandInset label +LatexCommand label +name "subsec:Slider" + +\end_inset + + +\end_layout + +\begin_layout Standard +Slider是一种通过滑动选择数字的控件,详情请参见示例代码: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + +及其注释。 +\end_layout + +\begin_layout Subsubsection* +Tabbed Pane +\begin_inset CommandInset label +LatexCommand label +name "subsec:Tabbed-Pane" + +\end_inset + + +\end_layout + +\begin_layout Standard +Tabbed Pane可以实现“标签页”,详情请参见示例代码: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/cn/edu/ +sdut/softlab +\end_layout + +\end_inset + +及其注释。 +\end_layout + +\begin_layout Section +布局管理器 +\begin_inset CommandInset label +LatexCommand label +name "sec:布局管理器" + +\end_inset + + +\end_layout + +\begin_layout Standard +在图形用户界面应用程序的设计中,界面中的控件如何布局总是一个容易让人困扰的问题,有过WEB界面设计经历的读者可能对此有更深刻的体会。比如当窗口大小或者分辨率发生 +改变的时候,如何保证界面布局符合当初的设计(期望)呢?通常有两种常见的界面布局思路:绝对布局和相对布局。绝对布局是指使用绝对(像素)坐标确定控件在界面的位置,很 +显然,当窗口大小发生改变时,绝对布局的界面不会随窗口发生改变,于是导致了不能充分利用放大了的窗口或者无法适应缩小了的窗口,因此绝对布局在实际的编程中很少用到,也 +不建议使用绝对布局,本节主要阐述各种相对布局的基本思路和方法。 +\end_layout + +\begin_layout Subsection +BorderLayout +\begin_inset CommandInset label +LatexCommand label +name "subsec:BorderLayout" + +\end_inset + + +\end_layout + +\begin_layout Standard +BorderLayout很像“麻将桌”,将界面分为5个部分: +\end_layout + +\begin_layout Itemize +PAGE_START:界面的顶部 +\end_layout + +\begin_layout Itemize +PAGE_END:界面的底部 +\end_layout + +\begin_layout Itemize +LINE_START:界面的左边 +\end_layout + +\begin_layout Itemize +LINE_END:界面的右边 +\end_layout + +\begin_layout Itemize +CENTER:界面的中间 +\end_layout + +\begin_layout Standard +BorderLayout的特点是,当窗口缩放时,四周的控件只占用尽可能小的空间,中间的控件将随窗口占用尽可能多的空间。 +\end_layout + +\begin_layout Example +BorderLayout示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:BorderLayout示例" + +\end_inset + +所示,5个按钮分别位于界面的4边和中间 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见:https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/ +cn/edu/sdut/softlab +\end_layout + +\end_inset + +。注意到我们将主Panel的Layout Manager修改为了BorderLayout,而不是默认的GridBagLayout。 +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/borderlayout-demo-0.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +BorderLayout示例 +\begin_inset CommandInset label +LatexCommand label +name "fig:BorderLayout示例" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:BorderLayout示例运行结果" + +\end_inset + +所示的运行结果是放大窗口后的效果。建议读者在不同的窗口大小情况下观察BorderLayout的布局效果,以加深对BorderLayout的理解。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/borderlayout-demo-1.png + width 50line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +BorderLayout示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:BorderLayout示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +这个示例很简单,我们只是修改了Panel的Layout Manager为BorderLayout,然后将5个按钮依次放到界面的合适位置即可。 +\end_layout + +\begin_layout Exercise +尝试将 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:BorderLayout示例运行结果" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +中“Center”按钮所在的位置替换为另外一个“麻将桌”,即如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:BorderLayout练习1" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +示的效果。 +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/BorderLayout-exe1.1.png + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +BorderLayout练习1 +\begin_inset CommandInset label +LatexCommand label +name "fig:BorderLayout练习1" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +FlowLayout +\begin_inset CommandInset label +LatexCommand label +name "subsec:FlowLayout" + +\end_inset + + +\end_layout + +\begin_layout Standard +流式布局(FlowLayout)是一种很自然的布局方式,即各个控件按照加入的顺序在窗口从左向右依次排开,各自只占用尽量小的空间。 +\end_layout + +\begin_layout Example +FlowLayout示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:FlowLayout示例设计" + +\end_inset + +所示,设计一个包含若干按钮和RadioButton的应用程序 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见:https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/ +cn/edu/sdut/softlab +\end_layout + +\end_inset + +,控件使用FlowLayout布局。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/flowlayout-demo-1.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +FlowLayout示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:FlowLayout示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +默认的运行结果如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:FlowLayout示例运行结果" + +\end_inset + +所示。请尝试改变窗口的大小观察FlowLayout的布局效果。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/flowlayout-demo-2.png + width 50line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +FlowLayout示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:FlowLayout示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +本例重点有两个: +\end_layout + +\begin_layout Itemize +mainPanel采用了FlowLayout布局管理器。 +\end_layout + +\begin_layout Itemize +mainPanel的preferedSize修改为300x200,以便更好的展现FlowLayout的布局效果。 +\end_layout + +\begin_layout Subsection +CardLayout +\begin_inset CommandInset label +LatexCommand label +name "subsec:CardLayout" + +\end_inset + + +\end_layout + +\begin_layout Example +CardLayout示例 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:CardLayout示例设计" + +\end_inset + +所示 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见:https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/ +cn/edu/sdut/softlab +\end_layout + +\end_inset + +,主界面使用默认的GridLayout,界面的上半部分放置了一个下拉选择框,根据不同的选择展示不同的card。下半部分是一个Panel,此Panel(cardP +anel)使用CardLayout,在其中添加了两个card,分别是buttonPanel和textFieldPanel。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/cardlayout-demo-1.png + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +CardLayout示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:CardLayout示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +根据选择的不同,可以看到显示了不同card的内容,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:CardLayout示例运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/gui/cardlayout-demo-2.png + width 45line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +默认运行结果 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/gui/cardlayout-demo-3.png + width 45line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +选择Card with JTextField +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +CardLayout示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:CardLayout示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +增加代码的分析,因为CardLayout的代码不是特别直观 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +CardLayout的show方法可以有选择的显示指定的card,注意到show方法的第二个参数是指定的card的name(字符串),因此在Form + Designer中要设置每个card的name属性。为了和下拉选择框的设置一致,在本例中card的name属性设置为了下拉选择框的相应文字。 +\end_layout + +\begin_layout Standard +注意到mainPanel的布局管理器我们使用了Idea默认的GridBLayout,可以尝试换为BorderLayout或者FlowLayout看看效果如何? +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +在本例中我们使用了一个常见的Java GUI界面设计技巧:通过Panel在局部组织控件,然后对Panel使用合适的布局管理器进行管理。也就是说,通常一个Java + GUI的界面设计是分为两个层面的:第一个层面,对整个界面进行合理的大体的界面划分(使用Panel);第二个层面,在每个Panel内部进行控件的合理布局。我们在 +Java GUI的综合应用举例中还会看到这种布局策略。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +GridLayout +\begin_inset CommandInset label +LatexCommand label +name "subsec:GridLayout" + +\end_inset + + +\end_layout + +\begin_layout Standard +网格布局(GridLayout)是将整个界面划分为表格,表格的每个单元格可以放置一个控件(或者Panel),从而实现了规整的界面布局。影响GridLayout效 +果的除了表格单元格的个数之外,常见的属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:GridLayout的常见属性" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +说明 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +默认值 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizental gap +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +单元格的水平间隔的像素值,-1代表使用父容器的此设置,或者内置的10px +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +virtical gap +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +单元格的垂直间隔的像素值,-1代表使用父容器的此设置,或者内置的5px +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +same size horizentally +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +如果是true的话,所有控件在水平方向大小一致 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +false +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +same size vitically +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +如果是true的话,所有控件在垂直方向大小一致 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +false +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +margin +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +容器和控件之间的四周间隔大小 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0,0,0,0 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridLayout的常见属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:GridLayout的常见属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +GridLayout示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +使用GridLayout设计一个3x2的表格,其中放置5个按钮 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见:https://github.com/subaochen/java-tutorial/tree/master/guide/code/gui/src/ +cn/edu/sdut/softlab +\end_layout + +\end_inset + +,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:GridLayout示例设计" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridlayout-demo-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridLayout示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:GridLayout示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:GridLayout示例运行结果" + +\end_inset + +所示,GridLayout的用法简洁明了,请自行在Form Designer中修改相应的参数,比如virticalGap(水平间隔),horizentalGap +(垂直间隔)等观察这些参数对布局的影响。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridlayout-demo-2.png + width 50line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridLayout示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:GridLayout示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +使用Idea设计GridLayout界面 +\begin_inset Foot +status open + +\begin_layout Plain Layout +我们使用了Idea提供的GridLayoutManager,详情请参考: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://www.formdev.com/jformdesigner/doc/layouts/intellijgridlayout/ +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +的小技巧:Idea的Form Designer通常能够智能的判断应该使用多少格子来放置控件,但是我们也必须给出明确的“指令”。比如我们希望设计如下的界面: +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridlayout-tip-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +第一步,先添加三个JTextField,然后在第一个JTextField上面放置一个JLabel,如下图所示: +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridlayout-tip-2.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +第二步,需要首先将三个JTextField调整到一个水平面上,即如下图所示: +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridlayout-tip-3.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +第三步,添加另外的两个JLabel。 +\end_layout + +\begin_layout Plain Layout +如果没有在第二步首先将三个JTextField调整到一个水平面上,则继续添加JLabel时Form Designer可能会错误的领会我们的意思,从而错误的计算单 +元格的数量,读者可自行尝试和认真体会。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +GridBagLayout +\begin_inset CommandInset label +LatexCommand label +name "subsec:GridBagLayout" + +\end_inset + + +\end_layout + +\begin_layout Standard +网格袋布局(GridBagLayout)显然是GridLayout的扩展:GridLayout只允许控件放置在一个单元格中,而GridBagLayout允许一个 +控件占用多个单元格,因而GridBaglayout更加灵活,控制选项(属性)也比较多,常见的属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:GridBagLayout的常见属性" + +\end_inset + +所示 +\begin_inset Foot +status open + +\begin_layout Plain Layout +本书以JetBrain Idea提供的Form Designer为蓝本说明GridBagLayout的常见属性,和标准的Java Swing的GridBagLa +yout的属性略有出入。 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +说明 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +默认值 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +grid x +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +控件所占单元格的起始x坐标(左上角) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +grid y +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +控件所占单元格中的起始y坐标(左上角) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +grid width +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +控件横向占用的单元格数 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +grid height +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +控件纵向占用的单元格数 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +horizental align +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +横向的对齐方式,Fill意味着充满可能的横向空间(受weight x设置的影响) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Fill +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +virtical align +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +纵向的对齐方式,Fill意味着充满可能的纵向空间(受weight y设置的影响) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Center +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +weight x +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +横向扩展的权重。如果值为0则横向不扩展,即控件只占用可能小的空间;通常此值在0-1之间设置。 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0.0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +weight y +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +纵向扩展的权重。如果值为0则纵向不扩展,即控件只占用可能小的空间;通常此值在0-1之间设置。 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0.0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +insets +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +控件的外边距 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0,0,0,0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ipad x +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +横向的内边距素数,决定了控件距离单元格的边线有多远 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ipad y +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +纵向的内边距素数,决定了控件距离单元格的边线有多远 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridBagLayout的常见属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:GridBagLayout的常见属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +在Idea的Form Designer中,grid x/grid y/grid width/grid height属性是通过拖放控件自动设置的,无需手工设置。实 +际上,Form Designer的属性对话框没有提供编辑这4个属性的功能。 +\end_layout + +\begin_layout Plain Layout +如果熟悉CSS的盒子模型的话,insets相当于CSS盒子模型的margin,ipadx/ipady相当于CSS盒子模型的padding。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +GridBagLayout示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:GridBagLayout示例设计" + +\end_inset + +所示,我们设计一个包含几个按钮的界面,使用GridBagLayout布局管理器。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridbaglayout-demo-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridBagLayout示例设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:GridBagLayout示例设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:GridBagLayout示例运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/gridbaglayout-demo-2.png + scale 70 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridBagLayout示例运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:GridBagLayout示例运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +本例中各控件的属性如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:GridBagLayout示例应用中的控件属性" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +控件 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +属性设置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ButtonA +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 0,grid y = 0 +\end_layout + +\begin_layout Plain Layout +grid width = 1, grid height = 1 +\end_layout + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ButtonB +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 1,grid y = 0 +\end_layout + +\begin_layout Plain Layout +grid width = 1, grid height = 1 +\end_layout + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +Another Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 2,grid y = 0 +\end_layout + +\begin_layout Plain Layout +grid width = 1, grid height = 1 +\end_layout + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +A Long Name Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 0,grid y = 1 +\end_layout + +\begin_layout Plain Layout +grid width = 3, grid height = 1 +\end_layout + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ButtonC +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 0,grid y = 2 +\end_layout + +\begin_layout Plain Layout +grid width = 1, grid height = 1 +\end_layout + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +ButtonD +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 0,grid y = 3 +\end_layout + +\begin_layout Plain Layout +grid width = 1, grid height = 1 +\end_layout + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +Last Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +grid x = 1,grid y = 2 +\end_layout + +\begin_layout Plain Layout +grid width = 2, grid height = 2 +\end_layout + +\begin_layout Plain Layout +h align = Center, v align = Fill +\end_layout + +\begin_layout Plain Layout +weight x = 0, weight y = 0 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +GridBagLayout示例应用中的控件属性 +\begin_inset CommandInset label +LatexCommand label +name "tab:GridBagLayout示例应用中的控件属性" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +请读者尝试 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:控件属性的各种组合方式" + +\end_inset + +的控件属性组合方式,观察GridBagLayout在界面布局中的灵活性。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +测试场景 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +控件 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +属性设置 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +只设置ButtonA的属性,其他控件属性不变 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +ButtonA +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +h align = Center, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 1, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +只设置Last Button的属性,其他控件属性不变 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Last Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +h align = Center, v align = Fill +\end_layout + +\begin_layout Plain Layout +weight x = 1, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +只设置Last Button的属性,其他控件属性不变 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Last Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +h align = Fill, v align = Fill +\end_layout + +\begin_layout Plain Layout +weight x = 1, weight y = 0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +只设置Last Button的属性,其他控件属性不变 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Last Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +h align = Fill, v align = Fill +\end_layout + +\begin_layout Plain Layout +weight x = 1, weight y = 1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +只设置Last Button的属性,其他控件属性不变 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Last Button +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +h align = Fill, v align = Center +\end_layout + +\begin_layout Plain Layout +weight x = 1, weight y = 1 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +控件属性的各种组合方式 +\begin_inset CommandInset label +LatexCommand label +name "tab:控件属性的各种组合方式" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +JAVA图形用户界面的事件机制 +\begin_inset CommandInset label +LatexCommand label +name "sec:JAVA图形用户界面的事件机制" + +\end_inset + + +\end_layout + +\begin_layout Subsection +事件机制的基本原理 +\begin_inset CommandInset label +LatexCommand label +name "subsec:事件机制的基本原理" + +\end_inset + + +\end_layout + +\begin_layout Standard +事件机制是指代码如何对界面的点击、输入等事件做出响应,我们在前面的例子中已经多次使用了Swing的事件机制。Swing事件机制的三个要点是: +\end_layout + +\begin_layout Itemize +事件源(Event Source):即触发事件的控件,比如按钮、文本框等。 +\end_layout + +\begin_layout Itemize +事件对象(Event Object):描述事件的封装对象,其中包括了事件源、事件发生事件、事件相关参数(比如鼠标事件包括鼠标点击的坐标、鼠标点击次数等)等。 +\end_layout + +\begin_layout Itemize +监听器(Listener):当事件发生时Java会自动调用的方法被称为监听器。 +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Swing事件机制" + +\end_inset + +说明了按钮事件的处理过程 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这里对“注册”的原理没有展开说明,需要说明Event Loop的过程吗?需要说明注册和Java虚拟机的关系吗? +\end_layout + +\end_inset + + +\begin_inset Note Note +status open + +\begin_layout Plain Layout +是否可以在这里增加一个设计模式的示例?比如设计一个Container模拟OS,设计一个Listener模拟按钮、checkbox等 +\end_layout + +\end_inset + +,其他类型的事件处理过程与此类似。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/swing-event-model.eps + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Swing事件机制(以按钮为例) +\begin_inset CommandInset label +LatexCommand label +name "fig:Swing事件机制" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +控件的常见监听器 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整的Java GUI控件和事件监听器的对照表参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +http://docs.oracle.com/javase/tutorial/uiswing/events/eventsandcomponents.html +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:控件的常见监听器" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +控件 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +常用监听器 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +JButton +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +ActionListener:响应鼠标左键单击和回车事件 +\end_layout + +\begin_layout Plain Layout +MouseListener:响应除左键单击外的其他的各种鼠标事件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +JTextField +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +ActionListener:响应在输入框回车事件 +\end_layout + +\begin_layout Plain Layout +FocusListener:响应获得和失去焦点事件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +JRadioButton +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +ActionListener:响应选项选择事件 +\end_layout + +\begin_layout Plain Layout +MouseListener:响应各种鼠标事件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +JCheckBox +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +ActionListener:响应选项选择事件 +\end_layout + +\begin_layout Plain Layout +MouseListener:响应各种鼠标事件 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +JComboBox +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +ActionListener:响应选项选择事件 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +控件的常见监听器 +\begin_inset CommandInset label +LatexCommand label +name "tab:控件的常见监听器" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +监听器类的几种情形 +\begin_inset CommandInset label +LatexCommand label +name "subsec:监听器类的几种情形" + +\end_inset + + +\end_layout + +\begin_layout Standard +注意到注册监听器的方法:src.addXxxListener(listenerObject)的参数是一个实现了监听器接口的对象,即通过这个方法告诉Java虚拟机, +当src(事件源)对象产生了一个Xxx类型的事件时,需要调用listenerObject中的相关方法进行事件处理。在实现监听器时,通常有如下的几种策略,以按钮的 +单击事件actionEvent为例: +\end_layout + +\begin_layout Itemize +主类直接实现XxxListener接口或者扩展XxxHandler类,比如: +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class FrameDemo implements ActionListener { +\end_layout + +\begin_layout Plain Layout + + private JButton button; +\end_layout + +\begin_layout Plain Layout + + public FrameDemo() { +\end_layout + +\begin_layout Plain Layout + + button = new JButton("OK"); +\end_layout + +\begin_layout Plain Layout + + button.addActionListener(this); // 注册事件监听器。由于FrameDemo本身实现ActionListener接 +口,因此这里直接使用this作为实现了事件监听器接口的对象。 +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + public void actionPerformed(ActionEvent event) { +\end_layout + +\begin_layout Plain Layout + + // 事件处理代码 +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +使用匿名内部类实现监听器接口,比如: +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class FrameDemo { +\end_layout + +\begin_layout Plain Layout + + private JButton button; +\end_layout + +\begin_layout Plain Layout + + public FrameDemo() { +\end_layout + +\begin_layout Plain Layout + + button = new JButton("OK"); +\end_layout + +\begin_layout Plain Layout + + button.addActionListener(new ActionListener() { // 匿名内部类实现ActionListener接 +口 +\end_layout + +\begin_layout Plain Layout + + @Override +\end_layout + +\begin_layout Plain Layout + + public void actionPerformed(ActionEvent event) { +\end_layout + +\begin_layout Plain Layout + + // 事件处理代码 +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + }); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +使用独立的类实现监听器接口,比如: +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class FrameDemo { +\end_layout + +\begin_layout Plain Layout + + private JButton button; +\end_layout + +\begin_layout Plain Layout + + public FrameDemo() { +\end_layout + +\begin_layout Plain Layout + + button = new JButton("OK"); +\end_layout + +\begin_layout Plain Layout + + button.addActionListener(new ButtonListener()); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +// 独立的事件监听器类,实现了ActionListener接口 +\end_layout + +\begin_layout Plain Layout + +class ButtonListener implements ActionListener { +\end_layout + +\begin_layout Plain Layout + + @Override +\end_layout + +\begin_layout Plain Layout + + public void actionPerformed(ActionEvent event) { +\end_layout + +\begin_layout Plain Layout + + // 事件处理代码 +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在大多数情况下,我们建议使用匿名内部类实现监听器接口,代码更简洁,封装性更好。 +\end_layout + +\begin_layout Section +Java GUI综合应用举例 +\begin_inset CommandInset label +LatexCommand label +name "sec:Java-GUI综合应用举例" + +\end_inset + + +\end_layout + +\begin_layout Example +计算器 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +这是一个典型的可以使用GridBagLayout进行界面设计的应用场合,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:计算器的界面设计" + +\end_inset + +所示。为了更好的适应窗口大小,界面中的所有控件设置了如下属性: +\end_layout + +\begin_layout Itemize +horizental align:Fill +\end_layout + +\begin_layout Itemize +virtical align: Fill +\end_layout + +\begin_layout Itemize +weight x : 1.0 +\end_layout + +\begin_layout Itemize +weight y : 1.0 +\end_layout + +\begin_layout Standard +完整的代码参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "Caculator.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/gui/src/cn/edu/sdut/softlab/Caculator.java" +lstparams "caption={Caculator.java},label={Caculator.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/caculator-1.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +计算器的界面设计 +\begin_inset CommandInset label +LatexCommand label +name "fig:计算器的界面设计" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:计算器的运行结果" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/gui/caculator-2.png + width 60line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +计算器的运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:计算器的运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +本例为了简化起见,表达式的求值借用了JDK内置的JavaScript引擎,有兴趣的读者可以自行实现一个表达式求值的引擎或者方法。 +\end_layout + +\begin_layout Exercise +请尝试使用GridLayout重新设计计算器(提示:首先使用GridLayout将界面分为上下两部分,上部分是一个Panel显示计算结果,使用任意的Layout +即可;下部分是一个显示计算按钮的Panel,使用GridLayout布局)。 +\end_layout + +\end_body +\end_document diff --git a/guide/lecture_guide/lecture15.lyx b/guide/lecture_guide/lecture15.lyx new file mode 100644 index 0000000..1ac14d6 --- /dev/null +++ b/guide/lecture_guide/lecture15.lyx @@ -0,0 +1,2751 @@ +#LyX 2.3 created this file. For more info see http://www.lyx.org/ +\lyxformat 544 +\begin_document +\begin_header +\save_transient_properties true +\origin unavailable +\textclass ctex-book +\begin_preamble +\input{../../../writing-common/book-preamble.tex} +\end_preamble +\use_default_options true +\begin_modules +coderemarks +warning-inset +note-inset +tip-inset +theorems-bytype +theorems-chap-bytype +logicalmkup +\end_modules +\maintain_unincluded_children false +\begin_local_layout +PackageOptions url hyphens +\end_local_layout +\language chinese-simplified +\language_package default +\inputencoding utf8-plain +\fontencoding global +\font_roman "default" "DejaVu Sans" +\font_sans "default" "DejaVu Serif" +\font_typewriter "default" "DejaVu Sans Mono" +\font_math "auto" "auto" +\font_default_family default +\use_non_tex_fonts true +\font_sc false +\font_osf false +\font_sf_scale 100 100 +\font_tt_scale 100 100 +\use_microtype false +\use_dash_ligatures true +\graphics default +\default_output_format pdf4 +\output_sync 0 +\bibtex_command default +\index_command default +\float_placement tbph +\paperfontsize default +\spacing single +\use_hyperref true +\pdf_bookmarks true +\pdf_bookmarksnumbered false +\pdf_bookmarksopen false +\pdf_bookmarksopenlevel 3 +\pdf_breaklinks false +\pdf_pdfborder true +\pdf_colorlinks true +\pdf_backref false +\pdf_pdfusetitle true +\papersize default +\use_geometry false +\use_package amsmath 1 +\use_package amssymb 1 +\use_package cancel 1 +\use_package esint 1 +\use_package mathdots 1 +\use_package mathtools 1 +\use_package mhchem 1 +\use_package stackrel 1 +\use_package stmaryrd 1 +\use_package undertilde 1 +\cite_engine basic +\cite_engine_type default +\biblio_style plain +\use_bibtopic false +\use_indices false +\paperorientation portrait +\suppress_date false +\justification true +\use_refstyle 1 +\use_minted 0 +\boxbgcolor #dad3d7 +\index Index +\shortcut idx +\color #008000 +\end_index +\secnumdepth 3 +\tocdepth 2 +\paragraph_separation indent +\paragraph_indentation default +\is_math_indent 0 +\math_numbering_side default +\quotes_style english +\dynamic_quotes 0 +\papercolumns 1 +\papersides 2 +\paperpagestyle default +\tracking_changes false +\output_changes false +\html_math_output 0 +\html_css_as_file 0 +\html_be_strict false +\end_header + +\begin_body + +\begin_layout Standard +\align center + +\size larger +\bar under +山东理工大学教案 +\end_layout + +\begin_layout Standard +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +第十五次课 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +教学课型:理论课□√ 实验课□√ 习题课□ 实践课□ 技能课□ 其它□ +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +主要教学内容 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:网络通讯基础知识" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:网络通讯基础知识" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:使用URL" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:使用URL" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Socket编程" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:Socket编程" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +重点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +Java网络编程的基本模型; +\end_layout + +\begin_layout Enumerate +使用URL的网络编程; +\end_layout + +\begin_layout Enumerate +Java Socket编程; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +难点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +Java网络编程和Java I/O的关系; +\end_layout + +\begin_layout Enumerate +Java Socket编程; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +课程目标及要求 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +课程目标:课程目标1 +\end_layout + +\begin_layout Plain Layout +要求: +\end_layout + +\begin_layout Enumerate +掌握Java网络编程的基本模型; +\end_layout + +\begin_layout Enumerate +掌握Java Socket编程的基本思路和方法; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +教学方法和手段 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +板书和多媒体相结合,边讲边练,当堂消化。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +讨论、思考题 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +Java Socket编程如何有用,你知道有哪些框架是对Java Socket编程的进一步封装? +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +参考资料 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Chapter +网络编程 +\end_layout + +\begin_layout Standard +\align center +\begin_inset Graphics + filename ../../advance/imgs/network/network-programming.png + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Section +网络通讯基础知识 +\begin_inset CommandInset label +LatexCommand label +name "sec:网络通讯基础知识" + +\end_inset + + +\end_layout + +\begin_layout Standard +在讲述Java的网络编程之前,我们迅速的回顾一下网络通讯的基础知识,读者如果已经熟悉此部分内容可跳过。 +\end_layout + +\begin_layout Standard +现代的互联网是基于TCP/IP的四层通讯模型的,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:TCP/IP通讯模型" + +\end_inset + +所示。 +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../../advance/imgs/network/tcp-ip-model.eps + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +TCP/IP四层通讯模型 +\begin_inset CommandInset label +LatexCommand label +name "fig:TCP/IP通讯模型" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + +虽然我们使用java.net包编写的Java网络应用程序位于应用层,但是了解TCP、IP的基本概念有助于我们选择合适的类包编写应用程序。 +\end_layout + +\begin_layout Subsection +TCP +\end_layout + +\begin_layout Standard +TCP(Transmission Control Protocol)是一种可靠的传输控制协议。TCP协议通过建立可靠的网络链接保证数据在传输过程中不会丢失,顺序 +也不会乱掉,因此当我们需要可靠的网络数据传输时就要选择TCP协议,比如负责网页传输的HTTP协议,负责文件传输的FTP协议,负责邮件传输的Email协议,负责远 +程登录的Telnet/ssh协议等:你一定不希望收到的是破损的文件或者邮件的,对吧? +\end_layout + +\begin_layout Standard +但是,TCP协议建立可靠的网络链接也是要付出代价的,即相对于“不太可靠”的UDP而言,TCP的传输效率要低一些。 +\end_layout + +\begin_layout Subsection +UDP +\end_layout + +\begin_layout Standard +UDP(User Datagram Protocol)是一种“不太可靠”的传输控制协议,即UDP并不保证数据发出后,接收端一定能够收到,也不保证数据传输的顺序。 +这种“不太可靠”的数据传输方式在并不要求百分百数据准确性的场合大有用武之地,比如网络视频,即使数据在传输中丢掉了一点点数据,并不影响视频的流畅和质量。 +\end_layout + +\begin_layout Standard +由于UDP协议不需要维护可靠的传输通道,UDP协议的传输效率要比TCP高一些。 +\end_layout + +\begin_layout Subsection +IP地址 +\end_layout + +\begin_layout Standard +网络上的每一台设备都有一个唯一的地址编号,即IP地址,网络中的路由器就是根据数据包中的目的IP地址和源IP地址构建了数据传输的路由(通道)。常见的IP地址是32 +位的,,每8位使用句点隔开,比如210.44.176.123。 +\end_layout + +\begin_layout Subsection +端口(port) +\begin_inset CommandInset label +LatexCommand label +name "subsec:端口(port)" + +\end_inset + + +\end_layout + +\begin_layout Standard +我们知道,现代操作系统都是多任务操作系统,可以同时运行多个应用程序,每一个应用程序可以看做这台计算机提供的一种服务。如果这些应用程序提供网络服务,比如HTTP, +FTP服务,那么如何区分在一台计算机上面运行着的多个网络应用程序呢?单纯依赖IP地址是不够的,需要借助以端口(Port)的概念,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:端口示意图" + +\end_inset + +所示。 +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../../advance/imgs/network/port.eps + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +端口示意图 +\begin_inset CommandInset label +LatexCommand label +name "fig:端口示意图" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + +当数据到达计算机后,计算机会根据应用程序的不同将数据分发到不同端口,这就要求通信双方事先约定好使用的端口号。端口号是一个16位的数字,其范围为0~55635,但 +是0~1024号端口通常被称作“熟知端口”,即这些端口很多已经用于大家约定俗成的网络通讯服务,比如80端口用于HTTP协议传输,21用于FTP等等,因此我们自己 +编写的Java网络应用程序尽量避免使用1024以下的端口号,以免和熟知端口冲突。 +\end_layout + +\begin_layout Section +使用URL +\begin_inset CommandInset label +LatexCommand label +name "sec:使用URL" + +\end_inset + + +\end_layout + +\begin_layout Subsection +什么是URL? +\end_layout + +\begin_layout Standard +URL(Uniform Resource Locator)是网络资源的唯一地址,即通常所说的“网址”。我们可以根据URL查找网络资源(文字、图片、视频等),ja +va.net.URL类表示了一个URL。一个URL包含包含了如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:URL示意图" + +\end_inset + +所示的几部分: +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../../advance/imgs/network/url.eps + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +URL示意图 +\begin_inset CommandInset label +LatexCommand label +name "fig:URL示意图" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +协议(protocal):使用何种协议请求这个网络资源?http用于请求超文本文件,只是常见的网络协议之一,此外还有ftp、email、telnet等各种网络协 +议。协议和主机部分通过 +\begin_inset Quotes erd +\end_inset + +:// +\begin_inset Quotes erd +\end_inset + +隔开。 +\end_layout + +\begin_layout Itemize +主机(host):网络资源位于哪台网络设备,即主机中?主机往往由主机名和域名联合组成,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:URL示意图" + +\end_inset + +所示,www是一台提供WEB服务的主机的主机名,example.com是这台主机所在的域名,www.example.com是URL的主机部分。 +\end_layout + +\begin_layout Itemize +端口:(port):如 +\begin_inset CommandInset ref +LatexCommand formatted +reference "subsec:端口(port)" + +\end_inset + +所述,端口决定了主机将URL请求转发到哪个应用程序来处理。对于常见的“熟知端口”,比如http协议的80端口,通常在URL中可以略去。 +\end_layout + +\begin_layout Itemize +文件名(file):所请求的具体资源(文件、图片等)在主机的存储路径(含文件名)。这里的文件名是一个广义的概念,其一,文件名包括了路径和文件的具体名称;其二,U +RL中的文件名也可能仅仅是一个目录,但是要知道,WEB服务器会自动根据配置情况附加一个index.html或者类似的具体文件名。 +\end_layout + +\begin_layout Itemize +请求参数(query):在交互式网络应用程序中,往往需要附带额外的参数来进一步确定所请求的网络资源,通过 +\begin_inset Quotes erd +\end_inset + +? +\begin_inset Quotes erd +\end_inset + +隔开文件名和请求参数(Query String)。 +\end_layout + +\begin_layout Standard +此外需要注意到,在Java的URL类中,还给出了authority的概念,即主机和端口合称为authority。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +为什么称作authority呢?其实一个完整的URL是这样子的 +\begin_inset Foot +status open + +\begin_layout Plain Layout +https://en.wikipedia.org/wiki/Uniform_Resource_Identifier +\end_layout + +\end_inset + +: +\end_layout + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +scheme:[//[user:password@]host[:port]][/]path[?query][#fragment] +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +也就是说,在一个URL中还包含user:password部分,因此authority应该包含三部分: +\end_layout + +\begin_layout Enumerate +可选的用户名和密码 +\end_layout + +\begin_layout Enumerate +必须的主机 +\end_layout + +\begin_layout Enumerate +可选的端口号 +\end_layout + +\begin_layout Plain Layout +也就是说,这三个部分决定了用户是否有权限访问所给定的主机(和具体的资源没有关系):使用什么用户名和密码可以访问主机的哪个端口,因此这三个部分联合起来又叫做“au +thority”,即权威认证。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +创建URL +\end_layout + +\begin_layout Standard +java.net.URL类的构造方法提供了常见的创建URL对象的构造方法,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:URL的构造方法" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +说明 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public URL(String spec) throws MalformedURLException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据给定的URL字符串创建URL对象 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public URL(URL context, String spec) throws MalformedURLException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据给定的上下文和字符串创建URL对象 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public URL(String protocol, String host, int port, String file) throws Malformed +URLException +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据跟定的协议、主机、端口号和文件名创建URL对象 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public URL(String protocol, String host, String file) throws MalformedURLExcepti +on +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据跟定的协议、主机和文件名创建URL对象 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +URL的构造方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:URL的构造方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +创建绝对URL +\end_layout + +\begin_layout Standard +创建URL对象的最简单方式,是使用我们常见的URL(网址)的形式作为参数,比如 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整示例参见:https://github.com/subaochen/java-tutorial-examples/tree/master/network/sr +c/cn/edu/sdut/softlab +\end_layout + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +URL url = new URL("http://www.example.com/doc/tutorial/networking.html?id=101"); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +注意到参数:"http://www.example.com/doc/tutorial/networking.html?id=101"是一个完整的URL字符串,叫做“绝 +对URL”,类似于我们描述文件名的时候,称带完整路径信息的文件名为“绝对路径”。 +\end_layout + +\begin_layout Subsubsection +创建相对URL +\end_layout + +\begin_layout Standard +所谓的相对URL,是指在给定的URL的基础上再附加所缺少的URL元素创建一个URL对象,类似于“相对路径”的概念,比如: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +URL url = new URL("http://www.example.com"); // 创建一个绝对URL +\end_layout + +\begin_layout Plain Layout + +URL tutUrl = new URL(url, "doc/tutorial/networking.html?id=101"); // 创建一个相对URL +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +在创建相对URL的时候,如果第一个参数为null,则构造方法会将第二个参数看做“绝对URL”来处理;如果第二个参数为绝对URL,则会忽略第一个参数,比如: +\end_layout + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +URL url = new URL(null, "http://www.example.com/doc"); // 创建一个绝对URL对象 +\end_layout + +\begin_layout Plain Layout + +URL url = new URL(url, "http://www.example.com"); // 创建一个绝对URL对象 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +使用绝对URL和相对URL两种方式,分别创建 https://github.com/subaochen/java-tutorial-examples/tree/m +aster/network/src/cn/edu/sdut/softlab 的URL对象。 +\end_layout + +\begin_layout Subsubsection +使用协议、主机等创建URL +\end_layout + +\begin_layout Standard +有时我们获得的是URL的各个组成部分:协议、主机、文件名等,可以根据这些组成部分方便的创建URL对象,比如: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +URL url = new URL("http","www.example.com","doc/tutorial/networking.html?id=101"); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +解析URL +\end_layout + +\begin_layout Standard +URL类提供了一系列的getXXX方法帮助我们解析给定的URL对象的各个部分,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "ParseURL.java" + +\end_inset + +所示,请读者参照 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:URL示意图" + +\end_inset + +并根据此示例程序的运行结果仔细体会URL的各个组成部分是如何划分的。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../../advance/code/network/src/cn/edu/sdut/softlab/ParseURL.java" +lstparams "caption={ParseURL.java},label={ParseURL.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +运行结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +protocol = http +\end_layout + +\begin_layout Plain Layout +authority = example.com:80 +\end_layout + +\begin_layout Plain Layout +host = example.com +\end_layout + +\begin_layout Plain Layout +port = 80 +\end_layout + +\begin_layout Plain Layout +path = /docs/books/tutorial/index.html +\end_layout + +\begin_layout Plain Layout +query = name=networking +\end_layout + +\begin_layout Plain Layout +filename = /docs/books/tutorial/index.html?name=networking +\end_layout + +\begin_layout Plain Layout +ref = DOWNLOADING +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +读取URL +\end_layout + +\begin_layout Standard +创建URL对象后,我们可以通过URL类的 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +openStream() +\end_layout + +\end_inset + +方法获得一个到指定URL的inputStream流,然后就可以和操作本地文件一样方便的读取URL所指向的内容了,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "URLReader.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../../advance/code/network/src/cn/edu/sdut/softlab/URLReader.java" +lstparams "caption={URLReader.java},label={URLReader.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +运行结果如下 +\begin_inset Foot +status open + +\begin_layout Plain Layout +是的,不要怀疑,获取的内容就这么简单!读者可自行访问 +\begin_inset CommandInset href +LatexCommand href +name "https://raw.githubusercontent.com/subaochen/java-tutorial-examples/master/network/sample/hello.txt" +target "https://raw.githubusercontent.com/subaochen/java-tutorial-examples/master/network/sample/hello.txt" +literal "false" + +\end_inset + +验证一下。 +\end_layout + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status collapsed + +\begin_layout Plain Layout +hello, java! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +读取URL的另外方式是使用URLConnection类提供的方法,同时URLConnection还提供了更丰富的交互功能,详情参见: +\end_layout + +\begin_layout Plain Layout +https://docs.oracle.com/javase/tutorial/networking/urls/connecting.html +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +Socket编程 +\begin_inset CommandInset label +LatexCommand label +name "sec:Socket编程" + +\end_inset + + +\end_layout + +\begin_layout Standard +网络通讯的基本形式是“端对端”通信,即所谓的“客户端-服务器模式”(Client Server:CS),如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:客户-服务器通信模型" + +\end_inset + +所示。 +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../../advance/imgs/network/client-server-model.eps + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +客户-服务器通信模型 +\begin_inset CommandInset label +LatexCommand label +name "fig:客户-服务器通信模型" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + +在端对端通信中,客户端和服务器端首先建立通讯链接,然后客户端发送请求(request)到服务器端,服务器端返回响应(response)到客户端,实现了一次数据交 +换。这很像我们打电话的过程:首先拨号呼叫对方,如果对方摘机应答(或者手机上按下应答键),则双方通话的通道就建立起来了,然后就可以你一言我一语的通过电话交谈了。任 +何一方挂机,则整个通话过程(通信过程)就结束了。 +\end_layout + +\begin_layout Subsection +什么是Socket? +\end_layout + +\begin_layout Standard +在端对端的通信中,通信的双方不仅需要知道对方的主机IP地址,还需要知道对方应用使用的端口号,这是建立端对端通信的必要基础,因此将 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +IP地址和端口号合称为Socket +\end_layout + +\end_inset + +(插口),如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Socket示意图" + +\end_inset + +所示。 +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../../advance/imgs/network/socket.eps + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Socket示意图 +\begin_inset CommandInset label +LatexCommand label +name "fig:Socket示意图" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +基于Socket概念的编程通常被称为“Socket编程”,java.net包中提供了Socket、ServerSocket等类封装了Socket的基本操作,可以方 +便的实现客户端和服务器端的Socket编程。 +\end_layout + +\begin_layout Subsection +使用Socket +\begin_inset CommandInset label +LatexCommand label +name "subsec:使用Socket" + +\end_inset + + +\end_layout + +\begin_layout Standard +下面我们通过一个实现了Echo协议的例子来说明Java Socket编程的基本思路。如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "EchoServer.java" + +\end_inset + +所示的EchoServer.java是服务器端,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "EchoClient.java" + +\end_inset + +所示的EchoClient.java是客户端。客户端每次向服务器端发送字符串时,服务器端仅仅是把收到的字符串原样返回到客户端,即所谓的echo操作。 +\end_layout + +\begin_layout Standard +本示例的运行测试方法:首先启动EchoServer,再启动EchoClient。注意到EchoServer需要一个命令行参数 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +设置命令行参数的方法参见: +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:如何设置命令行参数?" + +\end_inset + + +\end_layout + +\end_inset + +:端口号,这里假设为2000;EchoClient需要两个命令行参数,主机IP地址和服务器端端口号,在这里主机使用localhost,服务器端端口号为2000。 +本示例程序的服务器端EchoServer是静默运行的,即启动后没有给出任何提示。客户端EchoClient运行后可以在终端窗口输入内容,一个可能的测试结果如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:EchoClient的运行结果" + +\end_inset + +所示。 +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../../advance/imgs/network/echoclient-result.png + scale 50 + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +EchoClient的运行结果 +\begin_inset CommandInset label +LatexCommand label +name "fig:EchoClient的运行结果" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Java Socket的基本原理如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java-Socket通讯示意图" + +\end_inset + +所示, +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../../advance/imgs/network/java-socket-programming.eps + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java Socket通讯示意图 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java-Socket通讯示意图" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +服务器端(这里是EchoServer)创建ServerSocket对象后,通过serverSocket对象的accept方法等待客户端发起连接请求。也就是说,S +ocketServer是一个被动的服务器端,当SocketServer启动后会阻塞在accept方法,一直在等待客户端发起连接请求。一旦有客户端连接成功,则创建 +一个描述此端对端通信的Socket对象(这里是clientSocket),通过此socket对象即可获得一个从客户端读取数据的InputStream(这里是in +),以及可以写入客户端的outputStream(这里是out)。注意到serserSocket、clientSocket、in、out都是需要用完即关闭的资源 +,因此在本例中我们使用try-with-resources +\begin_inset Foot +status open + +\begin_layout Plain Layout +如果不熟悉try-with-resources结构,请参照 +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:try-with-resources" + +\end_inset + + +\end_layout + +\end_inset + +结构帮助我们自动关闭打开的资源。 +\end_layout + +\begin_layout Standard +客户端EchoClient的过程类似,首先创建一个Socket对象(这里是echoSocket)。注意到我们使用服务器端的IP地址和端口号创建的echoSock +et,因此echoSocket会试图根据我们提供的参数发起到服务器端的连接请求,连接成功则建立了客户端和服务器端的通信通道,这就是echoSocket。通过ec +hoSocket我们可以获得从服务器端读取数据的InputStream(这里是in),往服务器端写入数据的OutputStream(这里是out),然后不断将从 +键盘输入的字符串送往服务器端即可。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +一般的Linux发布版中都提供了Socket测试工具,包括服务器端和客户端。在ubuntu中可以简单的执行命令: +\end_layout + +\begin_layout Plain Layout +\begin_inset Box Shadowbox +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +$ sudo apt-get install socket +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +安装socket测试工具。安装完成后,启动EchoServer,可以在另外一个终端如下方式测试EchoServer的功能: +\end_layout + +\begin_layout Plain Layout +\begin_inset Box Shadowbox +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status collapsed + +\begin_layout Plain Layout +$ socket -v localhost 2000 +\end_layout + +\begin_layout Plain Layout +inet: connected to localhost port 2000 (cisco-sccp) +\end_layout + +\begin_layout Plain Layout +hello? +\end_layout + +\begin_layout Plain Layout +hello? +\end_layout + +\begin_layout Plain Layout +你是谁? +\end_layout + +\begin_layout Plain Layout +你是谁? +\end_layout + +\begin_layout Plain Layout +我们交个朋友吧! +\end_layout + +\begin_layout Plain Layout +我们交个朋友吧! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +socket工具作为编写服务器端的测试工具很方便,当然,socket也可以作为服务器端运行来测试客户端应用程序,读者可以自行探索。 +\end_layout + +\begin_layout Plain Layout +另外一个简单的客户端工具是telnet,比如: +\end_layout + +\begin_layout Plain Layout +\begin_inset Box Shadowbox +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +$ telnet localhost 2000 +\end_layout + +\begin_layout Plain Layout +Trying 127.0.0.1... +\end_layout + +\begin_layout Plain Layout +Connected to localhost. +\end_layout + +\begin_layout Plain Layout +Escape character is '^]'. +\end_layout + +\begin_layout Plain Layout +hello +\end_layout + +\begin_layout Plain Layout +hello +\end_layout + +\begin_layout Plain Layout +if it is to be, it is up to me +\end_layout + +\begin_layout Plain Layout +if it is to be, it is up to me +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../../advance/code/network/src/cn/edu/sdut/softlab/EchoServer.java" +lstparams "caption={EchoServer.java},label={EchoServer.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../../advance/code/network/src/cn/edu/sdut/softlab/EchoClient.java" +lstparams "caption={EchoClient.java},label={EchoClient.java}" + +\end_inset + + +\end_layout + +\begin_layout Exercise +使用Socket编写一个服务器端和客户端,客户端给出一个算术表达式,服务器端返回计算结果 +\begin_inset Foot +status open + +\begin_layout Plain Layout +算术表达式求值可以参考: +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:Java-GUI综合应用举例" + +\end_inset + + +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Subsection +*编写健壮的服务器端Socket应用 +\end_layout + +\begin_layout Standard +在编写服务器端的Socket应用程序时要考虑以下的问题: +\end_layout + +\begin_layout Itemize +如何响应多个客户端的连接请求?通常的做法是针对每个客户发起一个独立的线程。 +\end_layout + +\begin_layout Itemize +如何灵活的处理不同的业务逻辑,即客户端和服务器端的通讯协议?这是服务器端Socket编程的重要内容,不好的架构往往不恰当的提高了软件的复杂度,降低了软件的可维护 +性。 +\end_layout + +\begin_layout Itemize +网络I/O和消息的编码、解码处理。 +\end_layout + +\begin_layout Itemize +错误处理。网络通讯环境是复杂和易出错的,保证服务器端SocketServer总是能够正确响应不是一件很容易的事情。 +\end_layout + +\begin_layout Standard +有很多第三方组织开发了一些帮助开发者处理以上问题的框架,其中比较著名的是Apache +\begin_inset Foot +status open + +\begin_layout Plain Layout +http://www.apache.org +\end_layout + +\end_inset + +组织的mina +\begin_inset Foot +status open + +\begin_layout Plain Layout +http://mina.apache.org +\end_layout + +\end_inset + +。Apache mina 2 (2指mina的第二个大的版本号,是目前的最新版本)是一个开发高性能和高可伸缩性网络应用程序的网络应用框架。它提供了一个抽象的事件 +驱动的异步 API,可以使用 TCP/IP、UDP/IP、串口和虚拟机内部的管道等传输方式。Apache mina 2 可以作为开发网络应用程序的一个良好基础。 +下面就mina的开发做一简单介绍 +\begin_inset Foot +status open + +\begin_layout Plain Layout +mina的官方文档非常详尽,有需要详细了解mina的读者建议直接阅读mina的官方指南:http://mina.apache.org/mina-project/us +erguide/user-guide-toc.html,中文译本请参考:https://waylau.gitbooks.io/apache-mina-2-user-g +uide/ +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Subsubsection +建立mina开发环境 +\end_layout + +\begin_layout Paragraph* +下载mina +\end_layout + +\begin_layout Standard +首先需要下载mina的合适版本,我们采用最新的版本即可,本书写作时mina的最新版本是2.0.16,可以从这里下载: +\begin_inset CommandInset href +LatexCommand href +name "http://mina.apache.org/mina-project/downloads.html" +target "http://mina.apache.org/mina-project/downloads.html" +literal "false" + +\end_inset + +。下载后(这里是下载到~/downloads目录下)解压缩到合适的目录,作者的习惯是在家目录建立一个devel目录,并将所有开发相关的软件都放到devel目录下 +: +\end_layout + +\begin_layout Standard +\begin_inset Box Shadowbox +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status collapsed + +\begin_layout Plain Layout +cd ~/devel +\end_layout + +\begin_layout Plain Layout +tar xzvf ~/downloads/apache-mina-2.0.16-bin.tar.gz +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +我们看到在apache-mina-2.0.16目录下的文件如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shadowbox +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status collapsed + +\begin_layout Plain Layout +$ tree -L 1 +\end_layout + +\begin_layout Plain Layout +. +\end_layout + +\begin_layout Plain Layout +├── dist +\end_layout + +\begin_layout Plain Layout +├── docs +\end_layout + +\begin_layout Plain Layout +├── lib +\end_layout + +\begin_layout Plain Layout +├── LICENSE.jzlib.txt +\end_layout + +\begin_layout Plain Layout +├── LICENSE.ognl.txt +\end_layout + +\begin_layout Plain Layout +├── LICENSE.slf4j.txt +\end_layout + +\begin_layout Plain Layout +├── LICENSE.springframework.txt +\end_layout + +\begin_layout Plain Layout +├── LICENSE.txt +\end_layout + +\begin_layout Plain Layout +└── NOTICE.txt +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +其中的三个目录分别为: +\end_layout + +\begin_layout Itemize +dist:mina的发布文件,提供了mina的功能实现,我们下一步需要的mina-core就在这个目录下。 +\end_layout + +\begin_layout Itemize +docs:mina的API文档。 +\end_layout + +\begin_layout Itemize +lib:mina运行所需要支撑库。 +\end_layout + +\begin_layout Paragraph* +Idea中建立mina的开发环境 +\end_layout + +\begin_layout Standard +在Idea中开发mina应用,需要将mina的核心库加入到项目的配置中,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Idea项目增加类库的方法" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../../advance/imgs/network/idea-module-setting-add-lib-0.png + width 20line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +右键点击项目打开设置菜单 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../../advance/imgs/network/idea-module-setting-add-lib-1.png + width 34line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +从Libraries添加类库 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../../advance/imgs/network/idea-module-setting-add-lib-2.png + width 42line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +选择mina-core加入到项目中 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Idea项目增加类库的方法 +\begin_inset CommandInset label +LatexCommand label +name "fig:Idea项目增加类库的方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +同样的方法,从apache-mina-2.0.16/lib目录下把slf4j-api-1.7.21.jar也加入到项目的库配置中。 +\end_layout + +\begin_layout Subsubsection +简单mina应用程序示例 +\end_layout + +\begin_layout Standard +我们先从一个简单的“时间服务器”入手,看一下mina socket server是如何构建的。这个事件服务器实现的功能很简单,客户端无论发送什么消息上来,服务器 +只是返回当前时间作为响应。 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "MinaTimeServer.java" + +\end_inset + +所示,时间服务器的主类MinaTimeServer的主要工作是: +\end_layout + +\begin_layout Itemize +创建一个NioSocketAcceptor对象acceptor,这是mina对使用TCP的SocketServer的进一步封装,我们此后可以利用这个accept +or完成mina服务器的配置和启动。 +\end_layout + +\begin_layout Itemize +创建几个过滤器对象并添加到acceptor。这里添加了两个过滤器:一是日志过滤器,实现对操作过程的日志处理;二是文本编码过滤器,使用UTF-8对Socket流中 +的字符进行编码转换。 +\end_layout + +\begin_layout Itemize +设置这个时间服务器的事物逻辑处理器,即TimeServerHandler,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "TimeServerHandler.java" + +\end_inset + +。 +\end_layout + +\begin_layout Itemize +(可选)设置acceptor监听器的配置属性,这里设置了缓冲器大小和idle时间。 +\end_layout + +\begin_layout Itemize +将acceptor监听器绑定到指定的端口。 +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "TimeServerHandler.java" + +\end_inset + +所示,在主类中我们使用TimeServerHandler来进行具体的业务逻辑处理,这里的逻辑很简单:当收到任何消息(即messageReceived方法被调用时 +)时,我们创建新的Date对象并写入到发送队列(session.write()),mina会将发送队列的消息返回到客户端。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../../advance/code/network/src/cn/edu/sdut/softlab/mina/MinaTimeServer.java" +lstparams "caption={MinaTimeServer.java},label={MinaTimeServer.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../../advance/code/network/src/cn/edu/sdut/softlab/mina/TimeServerHandler.java" +lstparams "caption={TimeServerHandler.java},label={TimeServerHandler.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +运行MinaTimeServer后,我们可以通过telnet或者socket工具连接MinaTimeServer,一个可能的运行结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +$ telnet localhost 9123 +\end_layout + +\begin_layout Plain Layout +Trying 127.0.0.1... +\end_layout + +\begin_layout Plain Layout +Connected to localhost. +\end_layout + +\begin_layout Plain Layout +Escape character is '^]'. +\end_layout + +\begin_layout Plain Layout +hello +\end_layout + +\begin_layout Plain Layout +Sun Feb 19 08:49:01 CST 2017 +\end_layout + +\begin_layout Plain Layout +anybody there? +\end_layout + +\begin_layout Plain Layout +Sun Feb 19 08:49:33 CST 2017 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +mina应用程序的基本结构 +\end_layout + +\begin_layout Standard +基于 Apache mina 的网络应用有三个层次,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:mina框架各部分关系" + +\end_inset + + +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +本图借鉴了http://www.cnblogs.com/xuekyo/archive/2013/03/06/2945826.html,感谢作者的精彩阐述。 +\end_layout + +\end_inset + +所示, +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../../advance/imgs/network/mina-overview.eps + width 95line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +mina框架各部分关系 +\begin_inset CommandInset label +LatexCommand label +name "fig:mina框架各部分关系" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +分别是 I/O 服务、I/O 过滤器和 I/O 处理器: +\end_layout + +\begin_layout Standard +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +I/O 服务(I/O Processor) +\end_layout + +\end_inset + +:I/O 服务用来执行实际的 网络I/O 操作,即Socket通信。Apache mina 已经提供了一系列支持不同协议的 I/O 服务,如 TCP/IP、UD +P/IP、串口和虚拟机内部的管道等,我们可以直接拿来使用。开发人员也可以实现IoService接口打造一个适合特定场景的 I/O 服务。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +I/O 过滤器(IOFilter) +\end_layout + +\end_inset + +:I/O 服务能够传输的是字节流(Socket通讯),而上层应用(即IoHandler部分)需要的是特定的对象与数据结构。I/O 过滤器用来完成这两者之间的转换 +。I/O 过滤器的另外一个重要作用是对输入输出的数据进行处理,满足横切的需求。多个 I/O 过滤器串联起来,形成 I/O 过滤器链。 mina已经实现了常见的I +oFilter,我们可以根据需要选择使用,开发人员可以通过实现IoFilter接口或者扩展IoFilterAdaptor类打造特定的I/O过滤器。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +I/O 处理器(Handler) +\end_layout + +\end_inset + +:I/O 处理器用来执行具体的业务逻辑,对接收到的消息执行特定的处理。 通常,开发人员需要实现IoHandler接口或者扩展IoHandlerAdaptor类。 +\end_layout + +\begin_layout Standard +创建一个完整的基于 Apache mina 的网络应用,需要分别构建这三个层次。Apache mina 已经为 I/O 服务和 I/O 过滤器提供了不少的缺省实 +现,因此这两个层次在大多数情况下可以使用已有的实现。I/O 处理器由于是与具体的业务相关的,一般来说都是需要自己来实现的。 +\end_layout + +\begin_layout Subsubsection +事件驱动的异步API +\end_layout + +\begin_layout Standard +Apache mina 提供的是事件驱动的 API,它把与网络相关的各种活动抽象成事件,网络应用只需要对其感兴趣的事件进行处理即可。事件驱动的 + API 使得基于 Apache mina 开发网络应用变得比较简单。应用不需要考虑与底层传输相关的具体细节,而只需要处理抽象的 I/O 事件。比如在实现一个服 +务端应用的时候,如果有新的连接进来,I/O 服务会产生 sessionOpened这样一个事件。如果该应用需要在有连接打开的时候,执行某些特定的操作,只需要在 + I/O 处理器中此事件处理方法 sessionOpened中添加相应的代码即可。 +\end_layout + +\begin_layout Exercise +使用mina编写一个计算算术表达式的服务器。 +\end_layout + +\end_body +\end_document diff --git a/guide/lecture_guide/lecture2.lyx b/guide/lecture_guide/lecture2.lyx new file mode 100644 index 0000000..30aa959 --- /dev/null +++ b/guide/lecture_guide/lecture2.lyx @@ -0,0 +1,3770 @@ +#LyX 2.3 created this file. For more info see http://www.lyx.org/ +\lyxformat 544 +\begin_document +\begin_header +\save_transient_properties true +\origin unavailable +\textclass ctex-book +\begin_preamble +\input{../../../writing-common/book-preamble.tex} +\end_preamble +\use_default_options true +\begin_modules +tip-inset +note-inset +warning-inset +coderemarks +logicalmkup +theorems-bytype +theorems-chap-bytype +\end_modules +\maintain_unincluded_children false +\begin_local_layout +PackageOptions url hyphens +\end_local_layout +\language chinese-simplified +\language_package default +\inputencoding utf8-plain +\fontencoding global +\font_roman "default" "DejaVu Sans" +\font_sans "default" "DejaVu Serif" +\font_typewriter "default" "DejaVu Sans Mono" +\font_math "auto" "auto" +\font_default_family default +\use_non_tex_fonts true +\font_sc false +\font_osf false +\font_sf_scale 100 100 +\font_tt_scale 100 100 +\use_microtype false +\use_dash_ligatures true +\graphics default +\default_output_format pdf4 +\output_sync 0 +\bibtex_command default +\index_command default +\float_placement tbph +\paperfontsize default +\spacing single +\use_hyperref true +\pdf_bookmarks true +\pdf_bookmarksnumbered false +\pdf_bookmarksopen false +\pdf_bookmarksopenlevel 3 +\pdf_breaklinks true +\pdf_pdfborder true +\pdf_colorlinks true +\pdf_backref false +\pdf_pdfusetitle true +\papersize default +\use_geometry false +\use_package amsmath 1 +\use_package amssymb 1 +\use_package cancel 1 +\use_package esint 1 +\use_package mathdots 1 +\use_package mathtools 1 +\use_package mhchem 1 +\use_package stackrel 1 +\use_package stmaryrd 1 +\use_package undertilde 1 +\cite_engine basic +\cite_engine_type default +\biblio_style plain +\use_bibtopic false +\use_indices false +\paperorientation portrait +\suppress_date false +\justification true +\use_refstyle 1 +\use_minted 0 +\boxbgcolor #dad3d7 +\index Index +\shortcut idx +\color #008000 +\end_index +\secnumdepth 3 +\tocdepth 2 +\paragraph_separation indent +\paragraph_indentation default +\is_math_indent 0 +\math_numbering_side default +\quotes_style english +\dynamic_quotes 0 +\papercolumns 1 +\papersides 2 +\paperpagestyle default +\tracking_changes false +\output_changes false +\html_math_output 0 +\html_css_as_file 0 +\html_be_strict false +\end_header + +\begin_body + +\begin_layout Standard +\align center + +\size larger +\bar under +山东理工大学教案 +\end_layout + +\begin_layout Standard +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +第二次课 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +教学课型:理论课□√ 实验课□√ 习题课□ 实践课□ 技能课□ 其它□ +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +主要教学内容 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:变量和变量的命名" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:变量和变量的命名" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:常量和常量的命名" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:常量和常量的命名" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:简单数据类型" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:简单数据类型" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:运算符" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:运算符" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:表达式" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:表达式" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:数组" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:数组" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:条件判断和分支" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:条件判断和分支" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:循环" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:循环" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:方法的不定长参数" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:方法的不定长参数" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Java的注释" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:Java的注释" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:综合应用举例" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:综合应用举例" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +重点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +Java的命名规范; +\end_layout + +\begin_layout Enumerate +加强了Java循环表达式; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +难点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +加强了Java循环表达式; +\end_layout + +\begin_layout Enumerate +Java的不定长参数; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +课程目标及要求 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +课程目标:课程目标1 +\end_layout + +\begin_layout Plain Layout +要求: +\end_layout + +\begin_layout Enumerate +能够和C语言对照,快速掌握Java的基本语法和关键词; +\end_layout + +\begin_layout Enumerate +熟练掌握Java语言的条件判断、循环的用法; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +教学方法和手段 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +板书和多媒体相结合,边讲边练,当堂消化。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +讨论、思考题 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +列出Java和C语言在数据类型、表达式等方面的异同点; +\end_layout + +\begin_layout Enumerate +Java在哪些方面加强了C语言的数据类型、表达式? +\end_layout + +\begin_layout Enumerate +作业: +\begin_inset CommandInset ref +LatexCommand vref +reference "exer:编写一个程序,寻找一组整数中的最大值和最小值。输入格式:首先输入" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +参考资料 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Chapter +Java的基础语法 +\begin_inset CommandInset label +LatexCommand label +name "chap:Java的基础语法" + +\end_inset + + +\begin_inset Note Note +status open + +\begin_layout Plain Layout +附录增加一个quick reference card +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\align center +\begin_inset Graphics + filename ../imgs/verybasic/data-type.png + width 70col% + +\end_inset + + +\end_layout + +\begin_layout Section +变量和变量的命名 +\begin_inset CommandInset label +LatexCommand label +name "sec:变量和变量的命名" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java语言中变量的概念和C语言完全一致,这里不再赘述。所不同的是,C语言中一般使用下划线分隔开多个单词,而在Java中,我们一般使用“驼式命名法 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +驼式命名法 +\end_layout + +\end_inset + +”(Camel Case Name)来给变量起名字,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:驼峰命名法" + +\end_inset + +所示,多个单词构成了一个变量,除第一个单词之外,其他单词的第一个字母大写。大写的字母很像隆起的驼峰,因此此种命名法被形象的称之为“驼式命名法”。 +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/verybasic/camel-naming-style.eps + width 40line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +驼式命名法 +\begin_inset CommandInset label +LatexCommand label +name "fig:驼峰命名法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:C语言的变量和Java语言变量对照表" + +\end_inset + +是常见的C语言变量 +\begin_inset Foot +status open + +\begin_layout Plain Layout +摘自Linux内核源代码 +\end_layout + +\end_inset + +和Java语言变量的对照,也是优秀变量命名的典范: +\end_layout + +\begin_layout Standard +\align center +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +C中的常见变量 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Java中的变量表示方法 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +boot_info +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +bootInfo +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +cmdline_boot_cpuid +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +cmdlineBootCpuid +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +time_attrs +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +timeAttrs +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +lookup_flags +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +lookupFlag +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +C语言的变量和Java语言变量对照表 +\begin_inset CommandInset label +LatexCommand label +name "tab:C语言的变量和Java语言变量对照表" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +合理的变量命名能够加强代码的可读性,减轻团队沟通的压力,软件后期的维护压力也会缓解。从一开始就要 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +有意识的培养合理命名变量的习惯 +\end_layout + +\end_inset + +。善于合理的命名变量也是一种能力,这种能力不会从天上掉下来,只有多阅读优秀的代码,注意学习高手的编程思路和变量命名习惯,在平时的练习中坚持给变量合理的命名,才能 +逐步培养这种能力。本书坚持以合理的变量命名方式给出示例程序,希望通过此种方式让初学者在 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +潜移默化 +\end_layout + +\end_inset + +中获得这种能力。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +关于C中的__file这样的变量命名,有必要在这里说道一下吗? +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +常量和常量的命名 +\begin_inset CommandInset label +LatexCommand label +name "sec:常量和常量的命名" + +\end_inset + + +\end_layout + +\begin_layout Standard +常量是一种特殊的变量:其值不允许改变的变量。在C语言中,我们一般使用全大写字母表示常量,Java也完全遵守这一通用规则。所不同的是,Java语言中的常量通常使用 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +final +\end_layout + +\end_inset + +final static +\begin_inset Index idx +status open + +\begin_layout Plain Layout +static +\end_layout + +\end_inset + +进行联合修饰:final表示不可修改,static表示类变量,即所有对象共享一个此常量的备份。显然,对于常量而言,这样的修饰是十分合理和必要的,举例 +\begin_inset Foot +status open + +\begin_layout Plain Layout +摘自openjdk源代码: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/l +ang/Shutdown.java +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +/* Shutdown state */ +\end_layout + +\begin_layout Plain Layout + +public static final int RUNNING = 0; +\end_layout + +\begin_layout Plain Layout + +public static final int HOOKS = 1; +\end_layout + +\begin_layout Plain Layout + +public static final int FINALIZERS = 2; +\end_layout + +\begin_layout Plain Layout + +public static final int MAX_SYSTEM_HOOKS = 10; +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Itemize +请暂时忽略例子中的public,我们将在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:访问控制" + +\end_inset + +深入学习public的用法。 +\end_layout + +\begin_layout Itemize +我们将在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:static常量" + +\end_inset + +深入学习static的用法,这里可以简单理解为和C语言中的static用法类似:在C语言中,static变量表示变量位于静态存储区,因此可以在函数之间共享此变量 +。在Java中使用static修饰变量其实用意很相似:static变量在多个对象中只保存一份,即static变量的目的是 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +在多个对象中共享变量 +\end_layout + +\end_inset + +。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +简单数据类型 +\begin_inset CommandInset label +LatexCommand label +name "sec:简单数据类型" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java的 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +简单数据类型 +\end_layout + +\end_inset + +简单数据类型(又称为基本数据类型)和C语言几乎完全一致,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Java的数据类型" + +\end_inset + +所示。 +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +类别 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +类型 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +字节数 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +取值范围 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +举例 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +整数类型 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +byte +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-128~127 +\end_layout + +\begin_layout Plain Layout +(-2 +\begin_inset script superscript + +\begin_layout Plain Layout +7 +\end_layout + +\end_inset + +~2 +\begin_inset script superscript + +\begin_layout Plain Layout +7 +\end_layout + +\end_inset + +-1) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\align left +byte minor; +\end_layout + +\begin_layout Plain Layout +\align left +byte[] image; +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +short +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-32768~32767 +\end_layout + +\begin_layout Plain Layout +-2 +\begin_inset script superscript + +\begin_layout Plain Layout +15 +\end_layout + +\end_inset + +~2 +\begin_inset script superscript + +\begin_layout Plain Layout +15 +\end_layout + +\end_inset + +-1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\align left +short state; +\end_layout + +\begin_layout Plain Layout +\align left +short index = indexArray[i]; +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +int +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-2147483648~2147483647 +\end_layout + +\begin_layout Plain Layout +-2 +\begin_inset script superscript + +\begin_layout Plain Layout +31 +\end_layout + +\end_inset + +~2 +\begin_inset script superscript + +\begin_layout Plain Layout +31 +\end_layout + +\end_inset + +-1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\align left +int searchOffset; +\end_layout + +\begin_layout Plain Layout +\align left +int nextComma; +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +long +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +8 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-9223372036854775808~9223372036854775807 +\end_layout + +\begin_layout Plain Layout +-2 +\begin_inset script superscript + +\begin_layout Plain Layout +63 +\end_layout + +\end_inset + +~2 +\begin_inset script superscript + +\begin_layout Plain Layout +63 +\end_layout + +\end_inset + +-1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\align left +long timeout; +\end_layout + +\begin_layout Plain Layout +\align left +long remaining = 100L; +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +浮点类型 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +float +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Formula $\pm1.4E-45f$ +\end_inset + +~ +\begin_inset Formula $\pm3.4028235E+38f$ +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\align left +float loadFactor; +\end_layout + +\begin_layout Plain Layout +\align left +float f = 2.5F; +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +double +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +8 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Formula $\pm4.9E-324$ +\end_inset + +~ +\begin_inset Formula $\pm1.796931348623157E+308$ +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\align left +double scaledFractional; +\end_layout + +\begin_layout Plain Layout +\align left +double approxMax; +\end_layout + +\begin_layout Plain Layout +\align left +double myNumber = -1234.56; +\end_layout + +\begin_layout Plain Layout +\align left +double[] limits = {1,2,3,4,5,6,7}; +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +字符类型 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +char +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\backslash +u0000~ +\backslash +uffff +\end_layout + +\begin_layout Plain Layout +(0~65535) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\align left +char c = 'a'; +\end_layout + +\begin_layout Plain Layout +\align left +char[] text; +\end_layout + +\begin_layout Plain Layout +\align left +char trailChar; +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +布尔类型 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +boolean +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +true,false +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\align left +boolean isDefaultLevel; +\end_layout + +\begin_layout Plain Layout +\align left +boolean isInverse; +\end_layout + +\begin_layout Plain Layout +\align left +boolean mayAllocateText; +\end_layout + +\begin_layout Plain Layout +\align left +boolean first = true; +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java的数据类型 +\begin_inset CommandInset label +LatexCommand label +name "tab:Java的数据类型" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "SimpleDataType.java" + +\end_inset + +演示了Java中的简单数据类型: +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/verybasic/src/SimpleDataType.java" +lstparams "caption={SimpleDataType.java},label={SimpleDataType.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +执行结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +c(char) = a,size of c = 2 +\end_layout + +\begin_layout Plain Layout +b(byte) = 20,size of n = 1 +\end_layout + +\begin_layout Plain Layout +n(int) = 10,size of n = 4 +\end_layout + +\begin_layout Plain Layout +s(short) = 2,size of s = 2 +\end_layout + +\begin_layout Plain Layout +l(long) = 100,size of l = 8 +\end_layout + +\begin_layout Plain Layout +f(float) = 2.5,size of f = 4 +\end_layout + +\begin_layout Plain Layout +d(double) = 2.5,size of d = 8 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +C语言中没有字符串数据类型,Java语言中同样没有字符串这种简单数据类型。不过,Java是面向对象的程序设计语言,允许通过定义类来无限扩展数据类型,我们将在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:字符串处理" + +\end_inset + +讨论使用JDK中提供的 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +String +\end_layout + +\end_inset + +String类来表示字符串以及字符串的相关操作。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这部分内容可以删除?在openjdk中long/double/float没有采用此种方式来表示数字。 +\end_layout + +\end_inset + + +\begin_inset Note Note +status open + +\begin_layout Plain Layout +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +注意到,我们在Java中采用了和C中类似的方法,往往在数字的末尾使用不同的字母表示不同的数据类型: +\end_layout + +\begin_layout Itemize +L表示long; +\end_layout + +\begin_layout Itemize +F表示float; +\end_layout + +\begin_layout Itemize +D表示double; +\end_layout + +\begin_layout Plain Layout +当然,不这样表示在语法上也是正确的。但是,通过这种方式可以明确告诉Java编译器数字的类型,编译器能够帮助检查数字类型是否匹配。 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Warning +status open + +\begin_layout Plain Layout +实际上,Java的数据类型分为基本数据类型和引用数据类型,我们在这里只讨论基本数据类型,引用数据类型延迟到 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:引用类型" + +\end_inset + +讨论。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +运算符 +\begin_inset CommandInset label +LatexCommand label +name "sec:运算符" + +\end_inset + + +\end_layout + +\begin_layout Standard +参见表 +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java中的运算符" + +\end_inset + +,除了 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +instanceof +\end_layout + +\end_inset + +instanceof和 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +new +\end_layout + +\end_inset + +new运算符外,Java的运算符及其优先级规则和C是一样的: +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +类型 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +运算符 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +算术运算符 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout ++,-,*,/,%,++,-- +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +关系运算符 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +<,<=,>,>=,==,!= +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +逻辑运算符 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +&&,||,! +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +位运算符 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +&,|,~,^,<<,>>,>>> +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +赋值运算符 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +=,*=,+=,-=,/=,%=,<<=,>>=,>>>=,&=,^=,|= +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +对象运算符 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +instanceof +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +new +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java中的运算符 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java中的运算符" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这里有一个综合的运算符示例程序 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +表达式 +\begin_inset CommandInset label +LatexCommand label +name "sec:表达式" + +\end_inset + + +\end_layout + +\begin_layout Standard +我们说“C语言是一种表达式语 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +表达式语 +\end_layout + +\end_inset + +言”,可见表达式的概念是多么的重要!实际上,现代的程序设计语言,包括Java都可以称作“表达式语言”,表达式由参与运算的元素(称为运算数 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +运算数 +\end_layout + +\end_inset + +)和运算符 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +运算符 +\end_layout + +\end_inset + +的不同组合而成,即: +\end_layout + +\begin_layout Definition +表达式=运算数 + 运算符 +\end_layout + +\begin_layout Definition +要特别强调的是,每一个表达式都一定有一个确定的值,即“表达式的值 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +表达式的值 +\end_layout + +\end_inset + +”。举例说明: +\end_layout + +\begin_layout Definition +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +表达式类型 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +表达式 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +表达式的值 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +算术表达式 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 + 2 - (3 * 4) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-9 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +关系表达式 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 > 2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +false +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +逻辑表达式 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 && 2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +true +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +赋值表达式 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +a = 3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +true +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +表达式和表达式的值 +\begin_inset CommandInset label +LatexCommand label +name "fig:表达式和表达式的值" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Definition +我们经常在条件判断语句中使用表达式及表达式的值,请参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:条件判断和分支" + +\end_inset + +。 +\end_layout + +\begin_layout Example +输入圆的半径,求圆的面积和周长 +\begin_inset CommandInset label +LatexCommand label +name "exa:输入圆的半径,求圆的面积" + +\end_inset + + +\begin_inset Note Note +status open + +\begin_layout Plain Layout +增加圆的周长计算,说明如何避免魔幻数字 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "CircleArea.java" + +\end_inset + +中,我们将综合运用Java的输入输出和算术表达式。也请注意Java常量的定义和使用方式。 +\end_layout + +\begin_layout Example +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/verybasic/src/CircleArea.java" +lstparams "caption={CircleArea.java},label={CircleArea.java}" + +\end_inset + + +\end_layout + +\begin_layout Example +执行结果如下: +\end_layout + +\begin_layout Example +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +请输入半径:10.3 +\end_layout + +\begin_layout Plain Layout +面积=333.12261233749405 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +请结合 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:输入圆的半径,求圆的面积" + +\end_inset + +,阐述什么是魔幻数字 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这里似乎应该解释什么是魔幻数字? +\end_layout + +\end_inset + +(魔幻字符串)?常量在消除魔幻数字中起到怎样的作用? +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +从键盘输入球体的半径,求球体的体积 +\begin_inset CommandInset label +LatexCommand label +name "exer:从键盘输入球体的半径,求球体的体积。" + +\end_inset + +。 +\end_layout + +\begin_layout Section +数组 +\begin_inset CommandInset label +LatexCommand label +name "sec:数组" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java数组的意义、用法和C语言几乎完全一致,只是定义方式有两点不同: +\end_layout + +\begin_layout Itemize +Java定义数组不需要指定数组大小,Java虚拟机能够自动“推断”数组的大小。 +\end_layout + +\begin_layout Itemize +通常,Java将定义数组时的[]放到数据类型的右边,而不是变量的右边,即如:int[] array,这样能够更明确表示array是数组的名字。 +\end_layout + +\begin_layout Standard +Java的数组示例请参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "exa:遍历数组" + +\end_inset + +。 +\end_layout + +\begin_layout Section +条件判断和分支 +\begin_inset CommandInset label +LatexCommand label +name "sec:条件判断和分支" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java中的条件判断语句用法和C语言完全一致,不再赘述,通过一个例子看一下在Java中条件判断语句的基本用法。 +\end_layout + +\begin_layout Example +输入成绩,输出成绩的等级(优秀、良好、及格、不及格) +\begin_inset CommandInset label +LatexCommand label +name "exa:输入成绩,输出成绩的等级(优秀、良好、及格、不及格)" + +\end_inset + + +\end_layout + +\begin_layout Example +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/verybasic/src/ShowGrade.java" +lstparams "caption={ShowGrade.java},label={ShowGrade.java}" + +\end_inset + + +\end_layout + +\begin_layout Example +执行结果为: +\end_layout + +\begin_layout Example +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +请输入成绩:87 +\end_layout + +\begin_layout Plain Layout +成绩87.0的等级为:优秀 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +Java加强了的switch分支结构 +\begin_inset CommandInset label +LatexCommand label +name "subsec:Java加强了的switch分支结构" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java中的 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +switch +\end_layout + +\end_inset + +switch语句,不仅可以接受一个整数表达式(即表达式的值为整数),也可以接受一个字符串表达式(即表达式的值为字符串)和Enum类 +\begin_inset Foot +status open + +\begin_layout Plain Layout +Enum以及Emum用于Switch请参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:switch中的enum" + +\end_inset + +。 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Example +输入月份的英文缩写,输出月份的天数 +\begin_inset CommandInset label +LatexCommand label +name "exa:输入月份的英文缩写,输出月份的天数" + +\end_inset + + +\end_layout + +\begin_layout Example +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/verybasic/src/Month.java" +lstparams "caption={Month.java},label={Month.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +请使用switch-case结构重新实现 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "exa:输入成绩,输出成绩的等级(优秀、良好、及格、不及格)" + +\end_inset + + +\begin_inset CommandInset label +LatexCommand label +name "exer:请使用switch-case结构重新实现。" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +改进 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "exa:输入成绩,输出成绩的等级(优秀、良好、及格、不及格)" + +\end_inset + +,使得可以录入任意多的成绩并给出相应的等级分。录入-1表示录入结束 +\begin_inset CommandInset label +LatexCommand label +name "exer:改进,使得可以录入任意多的成绩并给出相应的等级分。录入-1表示录" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +尝试使用C语言的思路重新实现 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "exa:输入月份的英文缩写,输出月份的天数" + +\end_inset + +,即switch中的表达式只允许为整数,应该如何改写? +\begin_inset CommandInset label +LatexCommand label +name "exer:尝试使用C语言的思路重新实现,即switch中的表达式只允许为整" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "exa:输入成绩,输出成绩的等级(优秀、良好、及格、不及格)" + +\end_inset + +中并没有考虑闰月问题,请补充完整 +\begin_inset CommandInset label +LatexCommand label +name "exer:在中并没有考虑闰月问题,请补充完整。" + +\end_inset + +。 +\end_layout + +\begin_layout Section +循环 +\begin_inset CommandInset label +LatexCommand label +name "sec:循环" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +三大循环结构 +\end_layout + +\begin_layout Standard +Java中的三大循环结构( +\begin_inset Index idx +status open + +\begin_layout Plain Layout +for +\end_layout + +\end_inset + +for循环、while +\begin_inset Index idx +status open + +\begin_layout Plain Layout +while +\end_layout + +\end_inset + +循环、do-while +\begin_inset Index idx +status open + +\begin_layout Plain Layout +do-while +\end_layout + +\end_inset + +循环)以及break +\begin_inset Index idx +status open + +\begin_layout Plain Layout +break +\end_layout + +\end_inset + +、continue +\begin_inset Index idx +status open + +\begin_layout Plain Layout +continue +\end_layout + +\end_inset + +的用法和C语言完全一致,不再赘述。 +\end_layout + +\begin_layout Paragraph* +Java加强了的循环结构 +\end_layout + +\begin_layout Standard +Java提供了一种加强了的for循环语句,可以很方便的遍历集合(包括数组),其基本结构为: +\end_layout + +\begin_layout Standard +\begin_inset Box Boxed +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +for(元素类型T 循环变量t:集合s) {...} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +此加强了的for循环会自动从集合s中取出每一个元素赋值给“:”前面定义的循环变量t,这样在循环体中就可以使用这个变量t了。 +\end_layout + +\begin_layout Example +遍历数组 +\begin_inset CommandInset label +LatexCommand label +name "exa:遍历数组" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/verybasic/src/EnhancedFor.java" +lstparams "caption={EnhancedFor.java},label={EnhancedFor.java}" + +\end_inset + + +\end_layout + +\begin_layout Section +方法的不定长参数 +\begin_inset CommandInset label +LatexCommand label +name "sec:方法的不定长参数" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java方法的参数可以是不定长的,即任意个数的参数。 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +不定长参数 +\end_layout + +\end_inset + +不定长参数的表示方法是在参数类型和参数名之间使用...隔开,当实参和形参匹配时,实参列表会保存到一个指定的 +\begin_inset Flex Emph +status open + +\begin_layout Plain Layout +数组 +\end_layout + +\end_inset + +中(即不定长参数名),在方法体内可以遍历这个数组访问每一个参数。 +\end_layout + +\begin_layout Standard +比如将任意多个整数相加的方法,可以如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "VarargsTest.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/verybasic/src/VarargsTest.java" +lstparams "float,caption={VarargsTest.java},label={VarargsTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +作为单独的一节介绍main方法及其参数 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +Java的注释 +\begin_inset CommandInset label +LatexCommand label +name "sec:Java的注释" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java支持两种方式的注 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +注 +\end_layout + +\end_inset + +释: +\end_layout + +\begin_layout Enumerate +C语言风格的注释:即/*...*/方式的注释。 +\end_layout + +\begin_layout Enumerate +C++语言风格的注释:即//...方式的注释。 +\end_layout + +\begin_layout Standard +通常,多行的注释采用C语言风格比较方便,单行注释采用C++语言风格比较方便。习惯上,多行的注释使用/**开头,比如: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +/** +\end_layout + +\begin_layout Plain Layout + + * 方法的功能描述. +\end_layout + +\begin_layout Plain Layout + + * @param param1 参数1的描述 +\end_layout + +\begin_layout Plain Layout + + * @param param2 参数2的描述 +\end_layout + +\begin_layout Plain Layout + + * @return 返回值的描述 +\end_layout + +\begin_layout Plain Layout + + */ +\end_layout + +\begin_layout Plain Layout + +public String method(String param1, int param2) {...} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在上面的例子中,@param, @return分别用于描述方法的参数和返回值,javadoc +\begin_inset Foot +status open + +\begin_layout Plain Layout +javadoc是Java提供的API文档生成工具,位于SDK的bin目录下,即和java、java在同一个目录下。Java SDK的API文档就是通过javad +oc工具生成的,简单的用法是运行:javadoc 包名(类名列表),即可在当前目录下生成HTML格式的标准API文档,读者可自行尝试和体会。详细了解javado +c可以参考: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://en.wikipedia.org/wiki/Javadoc +\end_layout + +\end_inset + +和 +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +http://www.oracle.com/technetwork/articles/java/index-137868.html +\end_layout + +\end_inset + +,使用Linux的读者也可以执行man javadoc。 +\end_layout + +\end_inset + +可以根据这些标签自动生成API文档,建议读者在阅读优秀的源代码时注意学习注释的写法,养成写规范注释的习惯。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +大多数IDE都支持自动插入注释框架,比如在Idea中,只要在方法(函数)的上一行输入/**(注意是两个*)再按回车,然后在空白处补充描述即可。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +Java的基本语法结构中,哪些方面和C语言一致?Java增加了哪些新特性? +\end_layout + +\begin_layout Section +综合应用举例 +\begin_inset CommandInset label +LatexCommand label +name "sec:综合应用举例" + +\end_inset + + +\end_layout + +\begin_layout Example +利用下面的公式计算 +\begin_inset Formula $\pi$ +\end_inset + +的近似值,要求精确到 +\begin_inset Formula $10^{-6}$ +\end_inset + +为止。 +\begin_inset CommandInset label +LatexCommand label +name "exa:利用下面的公式计算的近似值,要求精确到为止。" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Formula +\[ +\pi/4\approx1-\frac{1}{3}+\frac{1}{5}-\frac{1}{7}+\cdots +\] + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +问题分析 +\end_layout + +\begin_layout Standard +这是利用级数公式近似计算某个特定值的典型应用,计算结果的精确度取决于累加的项数多少,累加的项数越多,精度越好。 +\end_layout + +\begin_layout Paragraph* +设计说明 +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "CalculatePi.java" + +\end_inset + +中,设计了一个计算 +\begin_inset Formula $\pi$ +\end_inset + +近似值的方法 +\begin_inset Foot +status open + +\begin_layout Plain Layout +本书大多数地方把C语言中的函数(function)称作“方法”(method),这是面向对象程序设计语言中对函数的称呼。其实,这两者没有差别,只是叫法不同而已。 +也就是说,在面向过程的语言中,通常称作函数;在面向对象的语言中,通常称作方法。 +\end_layout + +\end_inset + +,这样在main方法中调用这个方法即可。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/verybasic/src/CalculatePi.java" +lstparams "caption={CalculatePi.java},label={CalculatePi.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +显示结果 +\end_layout + +\begin_layout Standard +运行例 +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:利用下面的公式计算的近似值,要求精确到为止。" + +\end_inset + +后,输出结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +pai = 3.141591 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +程序说明 +\end_layout + +\begin_layout Standard +本例的主要内容是计算 +\begin_inset ERT +status open + +\begin_layout Plain Layout + +$ +\backslash +pi$ +\end_layout + +\end_inset + +近似值的方法pi()。其设计思路很直接,利用变量item保存每个迭代项的数值,然后累加到result中即可。注意到sign的用法很常见,在每次迭代的时候实现了符 +号的变换。 +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +编写一个程序,寻找一组整数中的最大值和最小值。输入格式:首先输入N,表示这组整数的个数,然后依次输入这组整数 +\begin_inset CommandInset label +LatexCommand label +name "exer:编写一个程序,寻找一组整数中的最大值和最小值。输入格式:首先输入" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +编写字符界面版计算器程序,运行时提示输入两个操作数,然后输出加减乘除运行结果。 +\begin_inset CommandInset label +LatexCommand label +name "exer:编写字符界面版计算器程序,运行时提示输入两个操作数,然后输出加减" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +编写一个程序,从键盘输入x,利用下面公式计算的近似值,要求精度到10 +\begin_inset script superscript + +\begin_layout Plain Layout +-6 +\end_layout + +\end_inset + +: +\begin_inset CommandInset label +LatexCommand label +name "exer:编写一个程序,从键盘输入x,利用下面公式计算的近似值,要求精度到" + +\end_inset + + +\end_layout + +\begin_layout Exercise +\begin_inset Formula +\[ +\cos(x)=1-\frac{x^{2}}{2!}+\frac{x^{4}}{4!}-\frac{x^{6}}{6!}+\frac{x^{8}}{8!}-\cdots +\] + +\end_inset + + +\end_layout + +\begin_layout Exercise + +\end_layout + +\end_body +\end_document diff --git a/guide/lecture_guide/lecture3.lyx b/guide/lecture_guide/lecture3.lyx new file mode 100644 index 0000000..cec0e70 --- /dev/null +++ b/guide/lecture_guide/lecture3.lyx @@ -0,0 +1,9340 @@ +#LyX 2.3 created this file. For more info see http://www.lyx.org/ +\lyxformat 544 +\begin_document +\begin_header +\save_transient_properties true +\origin unavailable +\textclass ctex-book +\begin_preamble +\input{../../writing-common/book-preamble.tex} +\end_preamble +\use_default_options true +\begin_modules +theorems-bytype +theorems-chap-bytype +coderemarks +note-inset +tip-inset +warning-inset +logicalmkup +\end_modules +\maintain_unincluded_children false +\begin_local_layout +PackageOptions url hyphens +\end_local_layout +\language chinese-simplified +\language_package default +\inputencoding utf8-plain +\fontencoding global +\font_roman "default" "DejaVu Sans" +\font_sans "default" "DejaVu Serif" +\font_typewriter "default" "DejaVu Sans Mono" +\font_math "auto" "auto" +\font_default_family default +\use_non_tex_fonts true +\font_sc false +\font_osf false +\font_sf_scale 100 100 +\font_tt_scale 100 100 +\use_microtype false +\use_dash_ligatures false +\graphics default +\default_output_format pdf4 +\output_sync 0 +\bibtex_command default +\index_command default +\float_placement tbph +\paperfontsize default +\spacing single +\use_hyperref true +\pdf_bookmarks true +\pdf_bookmarksnumbered false +\pdf_bookmarksopen false +\pdf_bookmarksopenlevel 3 +\pdf_breaklinks true +\pdf_pdfborder true +\pdf_colorlinks true +\pdf_backref false +\pdf_pdfusetitle true +\papersize default +\use_geometry false +\use_package amsmath 1 +\use_package amssymb 1 +\use_package cancel 1 +\use_package esint 1 +\use_package mathdots 1 +\use_package mathtools 1 +\use_package mhchem 1 +\use_package stackrel 1 +\use_package stmaryrd 1 +\use_package undertilde 1 +\cite_engine basic +\cite_engine_type default +\biblio_style plain +\use_bibtopic false +\use_indices false +\paperorientation portrait +\suppress_date false +\justification true +\use_refstyle 1 +\use_minted 0 +\boxbgcolor #d8daeb +\index Index +\shortcut idx +\color #008000 +\end_index +\secnumdepth 3 +\tocdepth 2 +\paragraph_separation indent +\paragraph_indentation default +\is_math_indent 0 +\math_numbering_side default +\quotes_style english +\dynamic_quotes 0 +\papercolumns 1 +\papersides 2 +\paperpagestyle default +\tracking_changes false +\output_changes false +\html_math_output 0 +\html_css_as_file 0 +\html_be_strict false +\end_header + +\begin_body + +\begin_layout Standard +\align center + +\size larger +\bar under +山东理工大学教案 +\end_layout + +\begin_layout Standard +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +第三次课 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +教学课型:理论课□√ 实验课□√ 习题课□ 实践课□ 技能课□ 其它□ +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +主要教学内容 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:再说C语言的struct" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:再说C语言的struct" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:类和对象的初步概念" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:类和对象的初步概念" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:对象的创建过程" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:对象的创建过程" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:类的组织:包" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:类的组织:包" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +重点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +类和对象的概念; +\end_layout + +\begin_layout Enumerate +Java对象的创建过程; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +难点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +类和对象在现实中的类比; +\end_layout + +\begin_layout Enumerate +对象的创建过程; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +课程目标及要求 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +课程目标:课程目标1 +\end_layout + +\begin_layout Plain Layout +要求: +\end_layout + +\begin_layout Enumerate +能把Java的类和对象的概念,在现实世界中找到丰富的案例; +\end_layout + +\begin_layout Enumerate +掌握Java对象的创建过程,熟悉构造方法的各种常见情形; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +教学方法和手段 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +板书和多媒体相结合,边讲边练,当堂消化。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +讨论、思考题 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +通过类和对象的概念的学习,学会用面向对象的角度思考和看待现实世界:比如如何通过面向对象的方法表达学校的组织机构? +\end_layout + +\begin_layout Enumerate +Java为什么要设计“构造方法”这个概念? +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +参考资料 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Chapter +面向对象编程基础 +\begin_inset CommandInset label +LatexCommand label +name "chap:面向对象的基本概念" + +\end_inset + + +\end_layout + +\begin_layout Standard +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/oop.png + width 100col% + +\end_inset + + +\end_layout + +\begin_layout Section +再说C语言的struct +\begin_inset CommandInset label +LatexCommand label +name "sec:再说C语言的struct" + +\end_inset + + +\end_layout + +\begin_layout Standard +C语言以简练、灵活、高效著称,但是C语言本身提供的基本数据类型有限,描述现实世界的能力自然也有限。比如要求输入班级同学的英语和数学成绩并按照平均成绩排序 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这个例子不恰当,排序任务脱离了对象本身,是否换成画图 or animal,涉及到各种图形和图形的操作? +\end_layout + +\end_inset + +,如果我们仅使用C的基本数据类型来设计的话,大概能想到的策略有如下几种: +\end_layout + +\begin_layout Enumerate +每个同学都用三个变量来表示:zhangsan_name, zhangsan_english, zhangsan_math, wangwu_name, + wangwu_english, wangwu_english......。如果班级有40位同学,这需要120个变量来表达,不仅容易写错,还不胜其烦!这个思路显然值得商榷, +为下策。 +\end_layout + +\begin_layout Enumerate +使用数组来分别存储同学的名字、英语成绩和数学成绩,比如下面的代码片段: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +char* name[40]; +\end_layout + +\begin_layout Plain Layout + +float english_score[40]; +\end_layout + +\begin_layout Plain Layout + +float math_score[40]; +\end_layout + +\end_inset + +使用数组极大减少了变量的数量,但是也存在一个问题,我们其实隐含了这样一条规则:name数组的第i个元素(同学)的英语成绩是english_score数组的第i个 +元素,数学成绩是math_score数组的第i个元素。也就是说,这三个数组的对应元素有一一映射的关系。这个一一映射的关系是需要我们程序员自己维护的,也就是说,如 +果我们破坏了这一隐含的规则,无论有意还是无意,编译器并不能帮助我们发现这个“破坏”,因为从语法上,不符合这个隐含规则也是允许的,这即为程序员带来了负担,也为程序 +埋下了隐患。可以看出,带来这些问题的关键原因是三个数组的一一映射关系不是 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +语法级别的映射 +\end_layout + +\end_inset + +,编译器无法 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +从语法上保证和检查 +\end_layout + +\end_inset + +这三个数组是否遵循了一一映射的关系,这就是C语言引入struct概念的原因:将变量之间的映射关系语法化,我们看使用struct如何解决这个问题。 +\end_layout + +\begin_layout Enumerate +使用 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +struct +\end_layout + +\end_inset + +struct描述同学们的英语和数学成绩,代码片段如下: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +struct score{ +\end_layout + +\begin_layout Plain Layout + + char* name; +\end_layout + +\begin_layout Plain Layout + + float english_score; +\end_layout + +\begin_layout Plain Layout + + float math_score; +\end_layout + +\begin_layout Plain Layout + + float avg_score;/*平均成绩*/ +\end_layout + +\begin_layout Plain Layout + +}; +\end_layout + +\begin_layout Plain Layout + +struct score stu_scores[40]; +\end_layout + +\end_inset + +struct在语法上保证了name、english_score、math_score这三个变量是一一映射的,是score结构体的“成员分量 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +成员分量 +\end_layout + +\end_inset + +”,因此struct在语法上保证了名字和成绩不可能张冠李戴,杜绝了可能存在的隐患,也减轻了程序员的思想负担(不需要时刻提醒自己要维护姓名和成绩的映射关系)。所以 +,struct是C语言的重要组成部分,是C语言描述现实世界的重武器,在大型项目中大量使用struct来表达同类事物的共同特征(属性)。比如打开Linux内核源代 +码的头文件目录,我们随处可见大量的struct定义: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +struct font_desc { +\end_layout + +\begin_layout Plain Layout + + int idx; +\end_layout + +\begin_layout Plain Layout + + const char *name; +\end_layout + +\begin_layout Plain Layout + + int width, height; +\end_layout + +\begin_layout Plain Layout + + const void *data; +\end_layout + +\begin_layout Plain Layout + + int pref; +\end_layout + +\begin_layout Plain Layout + +}; +\end_layout + +\end_inset + +因此,我们可以这样定义struct: +\end_layout + +\begin_layout Definition +\begin_inset Index idx +status open + +\begin_layout Plain Layout +struct +\end_layout + +\end_inset + +struct是对一类事物公共属性的描述。 +\end_layout + +\begin_layout Subsection +struct的局限性 +\begin_inset CommandInset label +LatexCommand label +name "subsec:struct的局限性" + +\end_inset + + +\end_layout + +\begin_layout Standard +C语言通过struct大大扩充了C的数据类型,每一个struct都定义了一种新的数据类型来对应客观世界的某种事物,这样C语言不但描述客观世界的能力大大加强了,C +语言程序的可读性、可维护性也大大提高了。 +\end_layout + +\begin_layout Standard +C语言能够更好的描述客观世界,可以给struct记大功一件。但是,我们描述客观世界的目的是认识世界并进而改造世界,struct仅仅是方便了描述世界,对于改造世界 +并没有多大帮助。比如回到我们本章开头的问题:我们不仅仅要输入同学们的成绩,还要按照平均成绩排序。这里至少包含两个方面的“认识世界”和“改造世界”世界的动作: +\end_layout + +\begin_layout Enumerate +计算平均成绩:这是属于进一步认识世界的范畴:根据已有的事物属性,我们可以计算和推断出新的属性。 +\end_layout + +\begin_layout Enumerate +按照平均成绩排序:这是属于改造世界的范畴:对已有事物重新组合排序。 +\end_layout + +\begin_layout Standard +struct帮助我们很好的描述了同学们的名字和成绩的对应关系,但是计算平均成绩和按照成绩排序这两个“动作”,在C语言中是通过独立的函数来实现的,比如下面的代码片 +段: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +void calculate_avg_score(struct score* score) { +\end_layout + +\begin_layout Plain Layout + + /*按照某种权重算法计算平均成绩并保存到score.avg_score中*/ +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +struct score[] sort_score(struct score* scores[]) { +\end_layout + +\begin_layout Plain Layout + + /* 将数组scores排序后返回新的struct score数组*/ +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +可以看出,calculate_avg_score函数和sort_score函数虽然都和struct score有关系(作为参数或者返回值),但是这种关系是“弱关 +系”,因为calcuate_avg_score、sort_score可以没有定义,可以存在于另外的文件中,可以被定义为另外的名称等等。也就是说,在语法上,str +uct score和这两个函数并没有必然的联系,编译器没有办法帮助程序员检查这两个函数和struct score的映射关系,一切还需要程序员人工的 +\begin_inset Quotes erd +\end_inset + +细心 +\begin_inset Quotes erd +\end_inset + +照料。显然,struct一定程度上解决了描述世界的问题,但是没有解决认识世界和改造世界的问题。 +\end_layout + +\begin_layout Section +类和对象的初步概念 +\begin_inset CommandInset label +LatexCommand label +name "sec:类和对象的初步概念" + +\end_inset + + +\end_layout + +\begin_layout Subsection +类是struct概念的自然延伸 +\end_layout + +\begin_layout Standard +C中的struct实现了对客观事物属性的分组描述,即同一类型的客观事物的属性可以用一个struct来表达。正如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:struct的局限性" + +\end_inset + +所述,struct有其局限性,只能描述客观事物的属性,不能表达对客观事物的进一步认知动作和改造利用的动作,于是在面向对象的程序设计语言中引入“ +\begin_inset Index idx +status open + +\begin_layout Plain Layout +类 +\end_layout + +\end_inset + +类”的概念弥补struct的这一缺陷。 +\end_layout + +\begin_layout Definition +类是对一类客观事物公共 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + +和 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +动作 +\end_layout + +\end_inset + +的描述。 +\end_layout + +\begin_layout Standard +对比struct我们可以看出,类比struct多了“动作”的描述,也就是说,类即可以描述事物的属性,也可以描述我们可以对(用)这类事物“做什么”,是对客观世界的 +完整的描述。Java使用 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +class +\end_layout + +\end_inset + +关键字来定义类,一个简单的只包含属性的类和struct非常相似,比如二维坐标中的“点”,一开始可以这样定义(右边作为对照,列出了C中point结构体的定义): +\end_layout + +\begin_layout Standard +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "40line%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java的Point类定义 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +class Point { +\end_layout + +\begin_layout Plain Layout + + int x; // 点的x坐标 +\end_layout + +\begin_layout Plain Layout + + int y; // 点的y坐标 +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "45line%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +\begin_inset Caption Standard + +\begin_layout Plain Layout +C的point结构体定义 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +struct point { +\end_layout + +\begin_layout Plain Layout + + int x; /*点的x坐标*/ +\end_layout + +\begin_layout Plain Layout + + int y; /*点的y坐标*/ +\end_layout + +\begin_layout Plain Layout + +}; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +但是如果只是使用class替换了struct关键字,显然没有发挥类描述客观事物的最大威力,因此一个更合理的Point类如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "Point.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub321/Point.java" +lstparams "caption={Point.java},label={Point.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +可以看出,在这个版本的Point类定义中,“点”的属性(x,y)和对点的操作moveTo封装在一起了。 +\end_layout + +\begin_layout Subsection* +定义Java类 +\begin_inset CommandInset label +LatexCommand label +name "subsec:定义Java类" + +\end_inset + + +\begin_inset Note Note +status open + +\begin_layout Plain Layout +为了满足李震梅老师的审美观,修改为star form section +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +完整的定义Java类的语法是: +\end_layout + +\begin_layout Standard +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +[public] class ClassName { ...} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +这里有几个要点: +\end_layout + +\begin_layout Itemize +大部分情况下需要将类定义为 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +public +\end_layout + +\end_inset + +public的,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:类的访问控制" + +\end_inset + +。 +\end_layout + +\begin_layout Itemize +类名的常规命名遵循驼式命名法 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +驼式命名法 +\end_layout + +\end_inset + +,并且第一个字母是大写的。 +\end_layout + +\begin_layout Itemize +一个Java源代码文件中只能有一个类是public的,且这个public的类名必须和文件名完全一致,包括大小写。 +\end_layout + +\begin_layout Itemize +在Java源代码文件中可以定义多个类,只要保证只有一个public类即可。 +\end_layout + +\begin_layout Subsection +对象的概念 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +画图说明更清晰 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Wrap figure +lines 0 +placement r +overhang 0in +width "30line%" +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/point-monitor.eps + lyxscale 20 + width 100line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +类和实例的关系 +\begin_inset CommandInset label +LatexCommand label +name "fig:类和实例的关系" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +类是对一类事物的抽象描述,比如Point类是对二维坐标“点”的抽象描述,它表达了屏幕上的一个点所具有的公共属性:x坐标和y坐标,以及我们可以对“点”的操作,比如 +moveTo操作。但是,Point类并没有和屏幕上的实体点绑在一起,屏幕上的每一个实体点,可以看作Point类的一个具体 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Index idx +status open + +\begin_layout Plain Layout +实例 +\end_layout + +\end_inset + +实例 +\end_layout + +\end_inset + +,都具有Point类给出的一些属性,在这里就是屏幕上的每一个实体点都有相应的x、y坐标。我们把实体点叫做类Point的 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +实例(instance) +\end_layout + +\end_inset + +,或者叫做类Point的 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Index idx +status open + +\begin_layout Plain Layout +对象 +\end_layout + +\end_inset + +对象 +\end_layout + +\end_inset + +。 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +对象就是实例,实例就是对象 +\end_layout + +\end_inset + +。可以看出,一个类可以创建若干实例,所有实例(对象)都具有类中定义的属性,只是属性的值各不相同而已,一般称作对象的状态不同。比如,点(1,2),(3,5),(1 +0,50)都是Point的实例。 +\end_layout + +\begin_layout Standard +在这里有必要进一步澄清一下常见的几种说法: +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +类(class) +\end_layout + +\end_inset + +就是类型的意思,定义了一个类,就是定义了一个新的数据类型,表达某种事物的公共属性和方法,我们可以根据类创建多个实例(对象)。 +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +对象(object)即类的实例 +\end_layout + +\end_inset + +。如果把类看作数据类型,则对象可以看作变量。 +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +对象的属性 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + +(property)即为类的“成员分量” +\end_layout + +\end_inset + +(借用struct的叫法),即类中定义的变量。 +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +对象的方法 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + +(method)即为类中定义的函数 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +函数 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + 。由于这些函数往往是操作类的属性的某种方法,因此大家习惯上称为对象的方法。 +\end_layout + +\begin_layout Standard +在java中,通过 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +new +\end_layout + +\end_inset + +new操作符创建类的实例(对象),比如new Point()创建了一个“点”的实例(对象)。和C语言中访问struct的成员变量类似,访问Java对象的属性和方 +法是通过 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +. +\end_layout + +\end_inset + +运算符实现的 +\begin_inset Foot +status open + +\begin_layout Plain Layout +和C语言不同的是,由于Java中没有提供指针,在Java中不存在->运算符。 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub321/Draw.java" +lstparams "caption={Draw.java},label={sub311-Draw.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +在程序中,我们通过new操作符创建了2个Point类的对象one和two,并设置了两个对象的状态(即x、y坐标),然后打印出两个对象的状态。 +\end_layout + +\begin_layout Example +根据已有的Point类,编写一个Rectangle和Circle类,并能够计算Rectangle和Circle的面积 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/oopbasic/src/cn +/edu/sdut/softlab/oopbasic/sub322 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +问题分析 +\end_layout + +\begin_layout Standard +矩形(Rectangle)是由一个点和长、宽决定的,圆形(Circle)是由一个点和半径决定的,因此我们可以在Point类的基础上定义Rectangle和Cir +cle类。 +\end_layout + +\begin_layout Paragraph* +设计说明 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub322-Rectangle.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub322-Circle.java" + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub322/Rectangle.java" +lstparams "caption={Rectangle.java},label={sub322-Rectangle.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub322/Circle.java" +lstparams "caption={Circle.java},label={sub322-Circle.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +主类Draw.java的设计参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub322-Draw.java" + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub322/Draw.java" +lstparams "float,caption={Draw.java},label={sub322-Draw.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +显示结果 +\end_layout + +\begin_layout Standard +执行文件Draw.java的结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +rect1's area=100 +\end_layout + +\begin_layout Plain Layout +circle1's area=314.159 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +程序说明 +\end_layout + +\begin_layout Standard +注意到我们在Rectangle中使用Point类定义一个startPoint对象的同时 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +初始化 +\end_layout + +\end_inset + +初始化了这个对象,即通过new Point()创建了一个空的Point对象。这是必要的,因为我们在Draw.java中创建一个Rectangle对象rect1后, +通过rect1.startPoint.x设置startPoint的x坐标。如果不在Rectangle中创建空的Point对象,则rect1.startPoint.x操作 +会报告著名的 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Index idx +status open + +\begin_layout Plain Layout +NPE +\end_layout + +\end_inset + +NPE +\end_layout + +\end_inset + +(NullPointException:空指针)异常: +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Exception in thread "main" java.lang.NullPointerException +\end_layout + +\begin_layout Plain Layout +at cn.edu.sdut.softlab.oopbasic.sub322.Draw.main(Draw.java:7) +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +对象的创建过程 +\begin_inset CommandInset label +LatexCommand label +name "sec:对象的创建过程" + +\end_inset + + +\end_layout + +\begin_layout Standard +当我们使用 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +new +\end_layout + +\end_inset + +new Point()创建一个Point类的对象时,Java是如何创建这个对象的呢? +\begin_inset Note Note +status open + +\begin_layout Plain Layout +画图表示类的创建过程 +\end_layout + +\end_inset + +实际上,Java创建对象的过程如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:对象的构造过程" + +\end_inset + +所示 +\begin_inset Foot +status open + +\begin_layout Plain Layout +实际上,为了理解方便,这是一个简化了的对象创建过程,对象的完整创建过程可参考JVM Specification +\begin_inset CommandInset citation +LatexCommand cite +key "jvm-se8-specification" +literal "true" + +\end_inset + +。 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/object-creation.eps + width 100col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +对象的构造过程 +\begin_inset CommandInset label +LatexCommand label +name "fig:对象的构造过程" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在这里我们暂且不讨论“递归的构造父类对象”这个话题(留待 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:再说构造方法" + +\end_inset + +再讨论),其他的几个步骤是指: +\end_layout + +\begin_layout Itemize +步骤1:分配空间。我们已经看到,相对于简单的数据类型,Java的对象往往是个复杂的数据结构,其中除了一些基本的数据类型的属性之外,还可能包含其他的对象(比如Re +ctangle中包含了Point)以及方法代码,因此创建Java对象的第一步是为这些数据和方法分配内存空间。分配内存空间后,类中的基本数据类型属性会被自动设置为 +默认值:数字类型的属性默认值为0(或者0.0),boolean类型的默认为false,字符类型的默认为''(这里是两个单引号,和C语言中的用法一样,表示空字符) +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这些需要验证或者查证: 如何通过示例验证? +\end_layout + +\end_inset + +。如果使用类作为属性,则默认为null。 +\end_layout + +\begin_layout Itemize +步骤3:初始化本类属性。如果本类的属性在定义时由初始化表达式,则使用该表达式初始化属性。比如 +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +int x = 10; +\end_layout + +\begin_layout Plain Layout + +Point startPoint = new Point(); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +步骤4:调用本类的构造方法,这是本节的重点。 +\end_layout + +\begin_layout Subsubsection* +构造方法 +\begin_inset CommandInset label +LatexCommand label +name "subsec:构造方法" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +构造方法 +\end_layout + +\end_inset + +构造方法的用途,我们在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:对象的构造过程" + +\end_inset + +中已经看到了,那么如何定义构造方法呢?简单的说, +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +构造方法就是和类同名并且没有返回值的方法 +\end_layout + +\end_inset + +。这里有两个关键点:一是构造方法的方法名必须和类名完全相同,包括大小写。二是构造方法不需要返回值,也不允许有返回值。 +\end_layout + +\begin_layout Subsubsection* +默认的构造方法 +\end_layout + +\begin_layout Standard +可是,我们在以前的类中,并没有看到构造方法,是怎么回事呢?原来,如果一个类没有定义任何的构造方法,java编译器会自动增加(插入)一个“默认的构造方法”,即不带 +任何参数的空的构造方法。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +需要验证在类继承环境下,默认构造方法是否自动调用父类的构造方法? +\end_layout + +\end_inset + +也就是说,我们new Point()创建一个对象的时候,最后一步会调用Point类的无参构造方法 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +无参构造方法 +\end_layout + +\end_inset + +。如果Point类没有提供这样的构造方法,则调用Point类的默认构造方法 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +默认构造方法 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +当然,我们也可以“主动”为Point编写一个无参的构造方法,这样new Point()的最后一步就是调用我们自己编写的构造方法而非默认构造方法了。 +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +重新起一个包,实现所有的无参构造方法。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +注意 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +无参构造方法 +\end_layout + +\end_inset + +无参构造方法和 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +默认构造方法 +\end_layout + +\end_inset + +默认构造方法的区别:默认构造方法一定是无参的构造方法,但是无参的构造方法不一定是默认构造方法。当一个类没有显式的定义任何构造方法时,编译器自动添加默认构造方法; +当一个类有任何的构造方法时,编译器都不会自动添加默认构造方法。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +编写程序,覆盖Point类的默认构造方法,为Point对象提供默认的(x,y)坐标为(10,10) +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整代码参见 +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/oopbasic/src/cn +/edu/sdut/softlab/oopbasic/sub332 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +设计说明 +\end_layout + +\begin_layout Standard +这里只列出Point.java和Draw.java两个文件,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub332-Point.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub322-Draw.java" + +\end_inset + +,Circle.java和Rectangle.java没有变化。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub332/Point.java" +lstparams "float,caption={Point.java},label={sub332-Point.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub332/Draw.java" +lstparams "float,caption={Draw.java},label={sub331-Draw.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Draw.java文件结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +rect1的左上角坐标:(10,10),width=10,height=10,面积=100 +\end_layout + +\begin_layout Plain Layout +circle1的原点坐标:(10,10),radius=10.0面积=314.159 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +程序分析 +\end_layout + +\begin_layout Standard +在本例中,Draw.java创建Circle对象circle1的时候,并没有设置原点的坐标,但是从运行结果可以看出,原点坐标的值为(10,10),这就是Point +类的无参构造方法的作用:当我们使用new Point()创建对象时,最后会调用Point的无参构造方法初始化对象的状态。 +\end_layout + +\begin_layout Subsubsection* +带参数的构造方法 +\end_layout + +\begin_layout Standard +很多时候,我们希望在创建对象的时候就设置对象的初始状态,比如是否可以通过new Point(10,20)这样的方式,创建Point对象的同时,设置Point对象 +的x坐标为10,y坐标为20呢?这可以通过带参数的构造方法来实现。也就是说,当我们通过new Point(10,20)这样的形式创建Point对象时,最后会调用 +Point类中带两个参数的构造方法。 +\end_layout + +\begin_layout Example +编写程序,使用带参数的构造方法创建Point对象 +\begin_inset CommandInset label +LatexCommand label +name "exa:编写程序,使用带参数的构造方法创建Point对象" + +\end_inset + + +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见 +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/oopbasic/src/cn +/edu/sdut/softlab/oopbasic/sub333 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +设计说明 +\end_layout + +\begin_layout Standard +主类Draw.java没有变化,这里就不列出了。其他类参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub333-Point.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub333-Circle.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub333-Rectangle.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub333/Point.java" +lstparams "float,caption={Point.java},label={sub333-Point.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub333/Circle.java" +lstparams "float,caption={Circle.java},label={sub333-Circle.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub333/Rectangle.java" +lstparams "float,caption={Rectangle.java},label={sub333-Rectangle.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Draw.java结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +rect1的左上角坐标:(20,20),width=10,height=10,面积=100 +\end_layout + +\begin_layout Plain Layout +circle1的原点坐标:(0,0),radius=10.0面积=314.159 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +当一个类中定义了任何的构造方法后,编译器就不会自动创建默认的构造方法了。比如Point类中,如果定义了Point的有参构造方法而没有定义无参构造方法,此时Poi +nt类没有默认构造方法,自然new Point()方式创建Point对象时会因为找不到无参的构造方法而报错。如何解决这个问题呢?请参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:多个构造方法" + +\end_inset + +。 +\end_layout + +\begin_layout Subsubsection* +多个构造方法 +\begin_inset CommandInset label +LatexCommand label +name "subsec:多个构造方法" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java允许在类中定义多个构造方法,以便根据不同的情况初始化对象为不同状态。 +\end_layout + +\begin_layout Example +编写程序,给Point类定义两个构造方法 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/oopbasic/src/cn +/edu/sdut/softlab/oopbasic/sub334 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +设计说明 +\end_layout + +\begin_layout Standard +主类Draw.java和Rectangle.java和例 +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:编写程序,使用带参数的构造方法创建Point对象" + +\end_inset + +相同,这里仅列出Point.java和Circle.java,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub334-Point.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub334-Circle.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub334/Point.java" +lstparams "float,caption={Point.java},label={sub334-Point.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub334/Circle.java" +lstparams "float,caption={Circle.java},label={sub334-Circle.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Draw.java结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +rect1的左上角坐标:(10,10),width=10,height=10,面积=100 +\end_layout + +\begin_layout Plain Layout +circle1的原点坐标:(0,0),radius=10.0面积=314.159 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +程序说明 +\end_layout + +\begin_layout Standard +Point类现在有两个构造方法,我们在Circle.java调用了Point的有参构造方法,在Rectangle.java中调用了Point的无参构造方法。 +\end_layout + +\begin_layout Subsection +再说对象的初始化 +\end_layout + +\begin_layout Standard +通过以上分析我们可以看出,构造方法的目的是为了 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +创建对象时设置对象的初始状态 +\end_layout + +\end_inset + +,因此一个类需要多少个构造方法并没有一定之规,需要根据实际情况来确定。通常,在一开始设计一个类的时候,建议覆盖默认的构造方法即无参构造方法,提供一个默认的对象状 +态。随着开发的深入,可以根据实际情况添加更多的构造方法。 +\end_layout + +\begin_layout Standard +除了通过构造方法设置对象的初始状态外,也可以通过以下的方式进行对象的初始化操作: +\end_layout + +\begin_layout Itemize +在创建对象后,直接访问对象的属性并设置希望的值。 +\end_layout + +\begin_layout Itemize +在创建对象后通过setter方法设置对象的状态。所谓setter方法,往往是一系列setX,setY方法,其中的X、Y为对象的属性。 +\end_layout + +\begin_layout Itemize +在JavaEE环境下,可以提供一个初始化方法,比如void init(),然后通过注解@PostConstruct的方式实现对象的初始化。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +定义有参构造方法时,要注意参数的个数不要太多,一般不要超过10个。太多的参数往往给使用者带来记忆和匹配的负担。如果需要大量的对象初始化操作,建议编写专门的方法初 +始化对象(比如init()方法就是一个很好的方法名字),然后在创建对象后调用这个init方法即可。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +Java的构造方法有哪些特点? +\begin_inset CommandInset label +LatexCommand label +name "exer:Java的构造方法有哪些特点?" + +\end_inset + + +\end_layout + +\begin_layout Section +类的组织:包 +\begin_inset CommandInset label +LatexCommand label +name "sec:类的组织:包" + +\end_inset + + +\end_layout + +\begin_layout Subsection +包的概念 +\end_layout + +\begin_layout Standard +在进行文件管理时,我们使用文件夹来组织不同类型的文件。在Java中,我们使用“ +\begin_inset Index idx +status open + +\begin_layout Plain Layout +包 +\end_layout + +\end_inset + +包”( +\begin_inset Index idx +status open + +\begin_layout Plain Layout +package +\end_layout + +\end_inset + +package)来管理不同类型的Java源文件,其实“包”就是文件夹,我们说包cn.edu.sdut.softlab.oopbasic.sub332中的Point.java +时,其实是说,位于目录cn/edu/sdut/softlab/oopbasic/sub332目录下的Point.java。也就是说,把目录的分隔符换成“.”,目录名 +就变成了包名。 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:本章示例代码的目录层级结构" + +\end_inset + +是本章的主要示例代码的目录层级结构: +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/package-tree.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +本章示例代码的目录层级结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:本章示例代码的目录层级结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +包的导入和声明 +\end_layout + +\begin_layout Standard +有了包的概念后,我们就可以使用 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +import +\end_layout + +\end_inset + +导入其他包中的Java源代码,这很像C语言中的include关键字的作用。比如下面的代码片段,我们导入了java.util包中的Date类(时间处理类): +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +import java.util.Date; +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +public class DateTest { +\end_layout + +\begin_layout Plain Layout + + public static void main(String[] args) { +\end_layout + +\begin_layout Plain Layout + + Date today = new Date(); +\end_layout + +\begin_layout Plain Layout + + System.out.println("today is " + today); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +关于包的导入(import),需要注意以下几个方面: +\end_layout + +\begin_layout Itemize +如果一个Java源代码在一个包中,则这个Java源代码应该首先使用 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +package +\end_layout + +\end_inset + +声明自己所在的包,正如本章所有的例子一样,在代码的开头几乎都一句package语句声明了包。建议回顾一下本章学过的例子,重点放在包的命名上面,了解如何在Java +源代码文件中声明包。 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +只有声明(package)了包的Java源代码,才能够被导入进来 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Itemize +如果Java源代码中没有package声明语句,则编译器认为Java文件在 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +默认包 +\end_layout + +\end_inset + +中,即src根目录下,这通常不是一个好的习惯。 +\end_layout + +\begin_layout Itemize +显然,import应该放在class的定义前面。 +\end_layout + +\begin_layout Itemize +在同一个包下的Java源代码不需要导入(import)。 +\end_layout + +\begin_layout Itemize +Java的核心API,即java.lang包的类,Java编译器会自动导入,也不需要我们手工导入。 +\end_layout + +\begin_layout Itemize +可以通过*实现批量导入,比如: +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +import com.company.lab.* +\end_layout + +\end_inset + +表示导入 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +com.company.lab +\end_layout + +\end_inset + +包中的所有类。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +在Idea IDE环境下,在使用到一个其他包的Java类时,有两种方式自动导入相应的包: +\end_layout + +\begin_layout Itemize +使用菜单:code->optimize imports,让Idea自动导入需要的包。 +\end_layout + +\begin_layout Itemize +鼠标移动到未识别的类上面,Idea会给出导入的提示,选择合适的包导入即可。注意,如果Idea给出了多个选择(意味着在多个包中都有这个类),此时要认真甄别要导入的 +包。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Warning +status open + +\begin_layout Plain Layout +根据Google编码规范(参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:不使用通配符import" + +\end_inset + +),尽量避免import package.*这样的用法。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +包的命名原则 +\end_layout + +\begin_layout Standard +我们使用包的目的是把Java文件按照逻辑组织起来 +\begin_inset Foot +status open + +\begin_layout Plain Layout +形式上看是这样,但是包的真正意义和Java虚拟机的类加载机制有关,这里不深入探讨,有兴趣的读者可以参考ClassLoader的相关资料。 +\end_layout + +\end_inset + +,同时也起到了“隔离”的作用,即不同包中的类即使名字相同也是可以的。或者说,以后我们提到一个类,应该连同它的包一起来考虑,即某某包的某某类。因此,当我们给包起名 +字的时候就要谨慎考虑,最好能够做到你起的包名是全球唯一的,这样你的包里面的类也就是全球唯一的了。而全球唯一的资源,很容易就想到了“域名”,于是通用的和建议的包命 +名规则 +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见JLS:http://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.1 +\end_layout + +\end_inset + +是按照域名的反向 +\begin_inset Foot +status open + +\begin_layout Plain Layout +为什么要将通常的域名反向排列形成包名呢?我们阅读的顺序是从左向右的,当谈到一个组织结构时,习惯上也是按照从左向右降序排列的,比如山东省淄博市张店区。因此,在命名 +包时把域名的顺序反向过来,更符合人们的阅读和理解习惯。当然,这不是Java的语法规定,只是“约定俗成”,入乡随俗也体现了一个程序员的素质。 +\end_layout + +\end_inset + +来命名,比如你的域名是lab.company.com,则包的命名可以是: +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +com.company.lab +\end_layout + +\end_inset + +。下面是一些典型的包命名示范: +\end_layout + +\begin_layout Standard +\begin_inset Box Boxed +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +com.google.android +\end_layout + +\begin_layout Plain Layout +cn.edu.sdut.java.lesson +\end_layout + +\begin_layout Plain Layout +org.apache.log4j +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +根据Google的编码规范(参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:包名" + +\end_inset + +),包的名字应该都使用小写字母,并避免使用下划线。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +类的继承 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +消除冗余,代码复用 +\end_layout + +\end_inset + + +\begin_inset CommandInset label +LatexCommand label +name "sec:类的继承" + +\end_inset + + +\end_layout + +\begin_layout Standard +在编程实践中,我们应该力求消除冗余,即不存在两片相同的代码。比如下面的代码片段: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +void method1() { +\end_layout + +\begin_layout Plain Layout + + doSomething(); +\end_layout + +\begin_layout Plain Layout + + foo(); +\end_layout + +\begin_layout Plain Layout + + bar(); +\end_layout + +\begin_layout Plain Layout + + foobar(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +void method2() { +\end_layout + +\begin_layout Plain Layout + + doSomeOtherThing(); +\end_layout + +\begin_layout Plain Layout + + foo(); +\end_layout + +\begin_layout Plain Layout + + bar(); +\end_layout + +\begin_layout Plain Layout + + foobar(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +我们应该这样消除冗余: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +void method1() { +\end_layout + +\begin_layout Plain Layout + + doSomething(); +\end_layout + +\begin_layout Plain Layout + + fun(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +void method2() { +\end_layout + +\begin_layout Plain Layout + + doSomeOtherThing(); +\end_layout + +\begin_layout Plain Layout + + fun(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +void fun() { +\end_layout + +\begin_layout Plain Layout + + foo(); +\end_layout + +\begin_layout Plain Layout + + bar(); +\end_layout + +\begin_layout Plain Layout + + foobar(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +虽然后一种方式多定义了一个方法fun(),但是好处显而易见:软件的逻辑性(可读性)和可维护性提高了。如果需要对fun()的流程做任何修改,我们现在只需要在fun +()方法中修改即可。 +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +\begin_inset Flex Tip +status collapsed + +\begin_layout Plain Layout +主流的IDE现在都支持对代码进行类似的“重构”(refactor)。比如在Idea中,可以选择一段“重复”的代码,然后通过菜单Refactor->Introdu +ce->Method...让IDE自动寻找这段重复的代码,一次性抽象出一个方法,这样就消除了代码的冗余。 +\end_layout + +\end_inset + +增加Idea使用refactor的方法 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +上面代码消除冗余是建立在方法层面上的,在类的层面上应该如何消除冗余呢?比如有如下的两个类:BankCard.java和CreditBandCard.java。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/inherit/step1/BankCard.java" +lstparams "float,caption={BankCard.java},label={step1-BankCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/inherit/step1/CreditCard.java" +lstparams "float,caption={未使用继承的CreditCard.java},label={step1-CreditBankCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +很明显,CreditBankCard具有BankCard的大部分属性和方法,从尽力消除冗余的角度看,这样的代码太“丑陋”了!java提供了“继承”机制解决了这个 +问题,先看一下代码的实现:BankCard.java的代码没有变化,这里只列出CreditCard.java的代码,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "step2-CreditBankCard.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/inherit/step2/CreditCard.java" +lstparams "float,caption={使用了继承的CreditCard.java},label={step2-CreditBankCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,CreditBankCard扩展(extends)了BankCard类:CreditCard自动具有BankCard的属性和方法,只需要在Credit +Card中定义专属的属性和方法即可。 +\end_layout + +\begin_layout Standard +这就是Java等面向对象程序设计语言的“ +\begin_inset Index idx +status open + +\begin_layout Plain Layout +继承 +\end_layout + +\end_inset + +继承”机制。简单的说, +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +继承机制消除了代码的冗余,提高了代码的复用水平 +\end_layout + +\end_inset + +。继承是面向对象程序设计的重要手段,我们将在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:单继承" + +\end_inset + +进一步分析继承在编程实践中的应用和注意事项。 +\end_layout + +\begin_layout Subsection +单继承 +\begin_inset CommandInset label +LatexCommand label +name "subsec:单继承" + +\end_inset + + +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:BankCard的类层次结构" + +\end_inset + + +\begin_inset Foot +status open + +\begin_layout Plain Layout +这样表示类层次关系的图叫做 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +UML +\end_layout + +\end_inset + +UML的类图。UML(Universal Model Language,统一建模语言)是IT行业中通用的描述需求和系统设计的建模工具,其中常用的图形有:类图、用 +例图、顺序图、活动图等,本书中只涉及到类图,用来表达类的继承和接口的实现。类图的意义应该是一目了然的,箭头表示类继承的方向,比如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:BankCard的类层次结构" + +\end_inset + +中,CreditCard指向了BankCard即表示CreditCard是从BankCard继承下来的。绘制UML图的工具有很多,本书采用的是umbrello和 +dia,参见本书前言部分的说明。 +\end_layout + +\end_inset + +的继承关系中,我们把BankCard类称作 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Index idx +status open + +\begin_layout Plain Layout +父类 +\end_layout + +\end_inset + +父类 +\end_layout + +\end_inset + +,或者超类,把CreditCard、DebitCard类称作 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Index idx +status open + +\begin_layout Plain Layout +子类 +\end_layout + +\end_inset + +子类 +\end_layout + +\end_inset + +。CreditCard和DebitCard继承了BankCard的属性和方法,并各自扩展了相应的属性和方法(DebitCard只扩展了属性,并没有扩展方法)。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/bankcard-hirarchy.eps + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +BankCard的类层次结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:BankCard的类层次结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +Java只支持单继承,即一个类只允许有一个父类。绕过这个限制的办法是使用接口,请参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:接口" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +下面的用法是正确的: +\end_layout + +\begin_layout LyX-Code +public class CreditCard extends BandCard{...} +\end_layout + +\begin_layout LyX-Code +public class DebitCard extends BandCard{...} +\end_layout + +\begin_layout Standard +下面的用法是错误的: +\end_layout + +\begin_layout LyX-Code +public class CreditCard extend BandCard{...} +\end_layout + +\begin_layout LyX-Code +public class CreditCard extends BandCard, Card{...} +\end_layout + +\begin_layout Standard +在Java中, +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Object +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Object +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +类是所有类的基类(父类),即在Java的类树结构中, +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Object +\end_layout + +\end_inset + +是“根”。因此,Java中的所有类都继承了 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Object +\end_layout + +\end_inset + +类中定义的属性和方法,具体请参见JDK API中关于 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Object +\end_layout + +\end_inset + +类的介绍。特别的, +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Object +\end_layout + +\end_inset + +类的以下方法在(初级)编程实践中经常用到: +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +toString +\end_layout + +\end_inset + +方法 +\end_layout + +\end_inset + + 输出当前对象的字符串表达,一般用于调式输出。实际上,当直接输出一个对象时,即调用了该对象的 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +toString +\end_layout + +\end_inset + +方法,也就是说, +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +System.out.println(aObject +\end_layout + +\end_inset + +)和 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +System.out.println(aObject.toString()) +\end_layout + +\end_inset + +的结果是一样的。通常情况下,子类需要覆盖 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Object +\end_layout + +\end_inset + +类的 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +toString +\end_layout + +\end_inset + +方法,以便更好的描述类的内部结构。 +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +equals +\end_layout + +\end_inset + +方法 +\end_layout + +\end_inset + + 比较两个对象是否相等。不像简单数据类型的比较,对象的比较复杂,这里不展开阐述,详情可参见以下资料:https://dzone.com/articles/obje +ct-identity-and-equality-in-java,或者:https://stackoverflow.com/questions/13387742/ +compare-two-objects-with-equals-and-operator。 +\end_layout + +\begin_layout Subsection +再说构造方法 +\begin_inset CommandInset label +LatexCommand label +name "subsec:再说构造方法" + +\end_inset + + +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:对象的创建过程" + +\end_inset + +中,我们已经看到创建对象的第二步是递归的构造父类对象。我们仍然以银行卡为例来看一下所谓的“递归的构造父类对象”的含义。为了清楚期间,我们增加了一个类的层级结构, +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:银行卡的类层级结构" + +\end_inset + +所示。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +银行卡的程序示例代码较多,作为一个例子处理如何? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/bankcard-full-hirarchy.eps + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +银行卡的类层级结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:银行卡的类层级结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +从 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "step3-Card.java" + +\end_inset + +可以看出,Card类只定义了所有卡都有的基本属性:卡号。另外,显式定义了无参的构造方法,如果被调用的话,只是打印出一条提示信息。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/inherit/step3/Card.java" +lstparams "float,caption={增加无参构造方法的Card.java},label={step3-Card.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +BankCard、CreditCard、DebitCard的设计思路类似,都是增加了一个无参的构造方法,打印出一条提示信息,如果被调用到的话。在Client类中 +,我们分别创建了CreditCard和DebitCard对象,注意观察构造方法的调用顺序。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/inherit/step3/BankCard.java" +lstparams "float,caption={带有无参构造方法的BankCard.java},label={step3-BankCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/inherit/step3/CreditCard.java" +lstparams "float,caption={带有无参构造方法的CreditCard.java},label={step3-CreditCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/inherit/step3/DebitCard.java" +lstparams "float,caption={带有无参构造方法的DebitCard.java},label={step3-DebitCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/inherit/step3/Client.java" +lstparams "float,caption={Client.java},label={step3-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +执行Client.java的结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Card constructor called +\end_layout + +\begin_layout Plain Layout +BankCard constructor called +\end_layout + +\begin_layout Plain Layout +CreditCard constructor called +\end_layout + +\begin_layout Plain Layout +Card constructor called +\end_layout + +\begin_layout Plain Layout +BankCard constructor called +\end_layout + +\begin_layout Plain Layout +DebitCard constuctor called +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,所谓的“递归的构造父类对象”是指: +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +当初始化子类对象时,从上往下依次调用父类的同名构造方法 +\end_layout + +\end_inset + +,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:构造方法的递归调用" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/object/constructor-chain.eps + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +构造方法的递归调用 +\begin_inset CommandInset label +LatexCommand label +name "fig:构造方法的递归调用" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +在递归构造父类对象的“链条”中,如果其中一环缺失会怎样?请读者自行练习找到此问题的答案:将导致语法错误。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这里应该有习题 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +方法的覆盖和重载 +\end_layout + +\begin_layout Standard +方法的覆盖(override)和重载(overload)是面向对象编程中两个重要且容易混淆的概念,因此这里单独拿出来讨论一下。 +\end_layout + +\begin_layout Subsubsection* +方法重载 +\end_layout + +\begin_layout Standard +Java中的方法重载(overload)是指在一个类中允许存在 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +多个名字相同但是参数不同的方法 +\end_layout + +\end_inset + +。这里所谓的“参数不同”有如下的几种情形: +\end_layout + +\begin_layout Itemize +参数个数不同 +\end_layout + +\begin_layout Itemize +参数类型不同 +\end_layout + +\begin_layout Itemize +参数个数和类型都不相同 +\end_layout + +\begin_layout Standard +如果我们把方法的参数看做一个控制系统的“输入条件”,那么方法的重载意味着同一个动作在不同的输入条件下的表现如何? +\end_layout + +\begin_layout Example +使用方法重载设计一个计算器类。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "Caculator.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/Caculator.java" +lstparams "caption={Caculator.java},label={Caculator.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java中典型的方法重载场合: +\end_layout + +\begin_layout Itemize +构造方法的重载:我们在 +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:多个构造方法" + +\end_inset + +中看到,可以编写类的多个构造方法,实际上就是方法的重载的具体体现。构造方法的名字都是相同的(和类名一致),不同的构造方法(参数不同)表示在不同的条件下如何创建对 +象。 +\end_layout + +\begin_layout Itemize +运算符重载:Java的“+”运算符是被重载了的。我们前面已经看到,“+”运算符在不同的表达式中意义不同,用于算数表达式时表示数学运算的加法,用于两个字符串时表示 +首尾相接连接两个字符串。 +\end_layout + +\begin_layout Itemize +String.valueOf方法可以接收的参数有boolean, char, char[], double, float, int, long等 +\begin_inset Foot +status open + +\begin_layout Plain Layout +我们将在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:字符串处理" + +\end_inset + +详细讨论String类的用法,String.value方法的形式可参考JDK API,这里暂不详细讨论。 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +需要注意的是,只是参数的顺序不同以及参数的名字不同不能构成方法的重载,原因很简单,我们调用方法的时候进行形参和实参的匹配,顺序和名字并不能唯一决定形参和实参的组 +合。比如方法method(String a, String b) 和method (String c, String d)不能构成方法的重载,在Java编译器看 +来,这是两个相同的方法,因而会报告编译错误。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +TODO:需要实例验证 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +\begin_inset Wrap figure +lines 0 +placement r +overhang 0in +width "30line%" +status collapsed + +\begin_layout Plain Layout +\noindent +\align center +\begin_inset Graphics + filename ../imgs/object/socket-plug.eps + lyxscale 25 + width 100line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +生活中的各种插座和多用插座示例 +\begin_inset CommandInset label +LatexCommand label +name "fig:生活中的各种插座和多用插座" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +举个生活中的例子可能更容易理解方法重载的概念和用途,比如我们知道插座有各种规格以便适用不同的电器,有的电器使用两孔插头,有的电器使用三孔插头,插头还可能分为圆形 +插头和扁平插头等等。正如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:生活中的各种插座和多用插座" + +\end_inset + +所示,生活中我们经常安装一种所谓的“多用插座”,即一个插座可以使用多种不同的插头,这样就免去安装很多个不同的插座的麻烦,也不需要大家记住插头和插座的对应关系,直 +接拿来用就可以了。这种“多用插座”的设计移植到程序设计上,就叫做“方法重载”(overload),即方法的名字相同(多用插座),但是参数各不相同(适用不同的插头 +),在具体使用时,程序员只需要记住少量的方法的名字,参数类型和个数由IDE自动提示即可。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection* +方法覆盖 +\end_layout + +\begin_layout Standard +方法覆盖(override)是指子类中重新实现了父类中的同名方法,即子类方法覆盖了父类方法。这样,当调用子类对象的这个方法时,就是使用子类重新实现的方法了。否则 +,就会调用父类中的方法。因此,方法覆盖的主要用意是 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +在子类中提供父类方法的加强版,或者使用不同的逻辑重新实现 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Example +方法覆盖示例。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "Dog.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/Dog.java" +lstparams "caption={Dog.java},label={Dog.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +方法覆盖是Java多态的基础,具体请参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:多态" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +注意到从JDK 1.5开始,Java允许子类覆盖父类方法时,返回值可以是父类方法返回值的子类。比如: +\end_layout + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +class A{ +\end_layout + +\begin_layout Plain Layout + + Father get(){ return null;} +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +public class B extends A{ +\end_layout + +\begin_layout Plain Layout + + @Override +\end_layout + +\begin_layout Plain Layout + + Son get(){ return null;} +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +class Father{} +\end_layout + +\begin_layout Plain Layout + +class Son extends Father{} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +在类B中,方法get返回值类型是Son,而其父类A的get方法的返回值类型是Father,由于Son是Father的子类,因此类B的方法get也属于方法的覆盖( +override)。 +\end_layout + +\begin_layout Plain Layout +Java是如何做到这一点的呢?我们反编译B.class会发现: +\end_layout + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +// Decompiled by Jad v1.5.8e. + Copyright 2001 Pavel Kouznetsov. + +\end_layout + +\begin_layout Plain Layout + +// Jad home page: http://www.geocities.com/kpdus/jad.html +\end_layout + +\begin_layout Plain Layout + +// Decompiler options: packimports(3) +\end_layout + +\begin_layout Plain Layout + +// Source File Name: B.java +\end_layout + +\begin_layout Plain Layout + +public class B extends A{ +\end_layout + +\begin_layout Plain Layout + + public B() { +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + Son get(){ +\end_layout + +\begin_layout Plain Layout + + return null; +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + volatile Father get(){ // 桥接方法 +\end_layout + +\begin_layout Plain Layout + + return get(); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +可以看出,编译器自动增加了一个所谓的“桥接方法”实现了标准的方法覆盖。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +在覆盖父类方法时,可以通过super关键字引用父类的同名方法。 +\end_layout + +\begin_layout Plain Layout +构造方法中的覆盖问题 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +访问控制 +\begin_inset CommandInset label +LatexCommand label +name "sec:访问控制" + +\end_inset + + +\end_layout + +\begin_layout Standard +当我们说到面向对象程序设计的封装时,不仅仅是指把对象的属性和方法“捏合”在了一起,也指从使用者的角度看,访问对象是受到限制的,即对象内部的状态和方法并不总是需要 +暴露给使用者的。推而广之,甚至对类的访问也可以加以限制。 +\end_layout + +\begin_layout Subsection +属性和方法的访问控制 +\end_layout + +\begin_layout Standard +为什么需要对属性和方法进行访问控制呢?从面向对象的设计角度看,一个对象完成了特定的功能,对象的使用者其实并不关心这个特定功能是如何实现的,只要这个功能能够正常工 +作就可以了,这就是所谓的“ +\begin_inset Index idx +status open + +\begin_layout Plain Layout +松耦合 +\end_layout + +\end_inset + +松耦合”(loose coupling principle)原则。考虑 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:松耦合原则" + +\end_inset + +所示的情形。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/loose-coupling-model.png + width 60col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +松耦合原则示意图 +\begin_inset CommandInset label +LatexCommand label +name "fig:松耦合原则" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +当Client使用Bean组件(对象)提供的功能时,并不需要知晓Bean组件内部是如何实现的,也就是时说,Bean组件在后续进行算法完善、性能改进或者界面优化...时 +,Client的代码不需要做任何改动。Bean组件只需要对外(Client)暴露必须的调用接口(如何暴露,我们会在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:接口" + +\end_inset + +讨论),其内部实现及只在内部实现中用到的一些对象状态,应该想办法隐藏起来。换句话说,Bean组件如果对外暴露的调用接口越多,则后续改进时要考虑的因素就越多,困难 +也越大。 +\end_layout + +\begin_layout Standard +Java提供了完善的访问控制策略来保护属性和方法,如表所示 +\begin_inset Foot +status open + +\begin_layout Plain Layout +也参见:http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html +\end_layout + +\end_inset + +(形成了一个三角形排列)。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java的访问控制修饰符 +\begin_inset CommandInset label +LatexCommand label +name "tab:Java的访问控制修饰符" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +修饰词 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Class(类) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Package(包) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Subclass(子类) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +World(其他) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +protected +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +X +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +(default) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +X +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +X +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +private +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +X +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +X +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +X +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +default修饰符 +\begin_inset CommandInset label +LatexCommand label +name "subsec:default修饰符" + +\end_inset + + +\end_layout + +\begin_layout Standard +在之前我们的代码中,属性和方法前面没有使用任何修饰符,即默认修饰符 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +默认修饰符 +\end_layout + +\end_inset + +。对照 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Java的访问控制修饰符" + +\end_inset + +可以看出,default修饰的(即不使用任何修饰符)的属性和方法对同一个包内的其他类是可见的:即可以读,也可以修改。因此,default修饰符也被称为“ +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +包范围 +\end_layout + +\end_inset + +”的修饰符,它以包为限界定了访问权限,这是一种很自然的权限划分,因此被Java确定为“default”(默认)情形。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Warning +status open + +\begin_layout Plain Layout +default的意思是默认修饰符,即没有在属性和方法前面指定修饰符的情形,并非要显式的指定一个“default”的修饰符。实际上,java中不存在一个名字叫做“ +default”的修饰符。因此,下文中的default均指: +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +在属性、方法、类前面不使用任何访问控制修饰符 +\end_layout + +\end_inset + +。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "ac-BankCard.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "ac-Client.java" + +\end_inset + +中,BankCard类中的username和password属性以及withdraw方法都是default的,因此同一个包中的Client类可以随意修改密码,随 +意取钱: +\begin_inset Flex Emph +status open + +\begin_layout Plain Layout +这太不安全了! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/ac/BankCard.java" +lstparams "float,caption={演示default修饰符的BankCard.java},label={ac-BankCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/ac/Client.java" +lstparams "float,caption={Client.java},label={ac-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +执行结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +BankCard constructor called +\end_layout + +\begin_layout Plain Layout +钱被取走啦! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Warning +status open + +\begin_layout Plain Layout +default修饰符意味着同一个包内的其他类都可以随意操纵你的属性和方法,这是一个危险的设置!设想一下,黑客把一个自己写的破坏性Java文件放到你的包里面,然后 +修改你的银行卡密码,盗取你的钱财...因此,default修饰符给软件的安全留了一个后门,并不是一个好的“默认值”! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +private修饰符 +\end_layout + +\begin_layout Standard +default给了同一个包下的其他类“篡改”本类的机会, +\begin_inset Index idx +status open + +\begin_layout Plain Layout +private +\end_layout + +\end_inset + +private修饰符则完全杜绝了这个问题:从 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Java的访问控制修饰符" + +\end_inset + +可以看出,private修饰过的属性和方法只有本类可以访问,即只有本类可以读取和修改,对同一个包下的其他类、子类以及所有其他的类都不可见。正如private的名 +字所宣示的, 这是一个完全隐私的保护性设置,特别适合于本节开头所述的“松耦合原则”中组件(对象)内部属性、方法的表达。实际上, +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +在绝大多数情况下,我们应该将类的属性和方法设置为private +\end_layout + +\end_inset + +,然后根据需要或者设计要求逐步放开限制,以达到对组件(对象)最大程度的封装和保护。 +\end_layout + +\begin_layout Standard +有时我们希望对外一定程度上暴露私有的属性,即不直接暴露私有(private)属性,而是通过一个公有(public)的方法间接的访问私有属性。这样如果需要的话,我 +们可以在这个方法中对属性修改做合法性检查,避免任意的篡改私有属性。这些能够读取和设置私有属性的方法往往以get和set开头,一般称作 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +getter/setter方法 +\end_layout + +\end_inset + +,比如下面的代码片段: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class Person { +\end_layout + +\begin_layout Plain Layout + + private String username; +\end_layout + +\begin_layout Plain Layout + + private String password; +\end_layout + +\begin_layout Plain Layout + + private String email; +\end_layout + +\begin_layout Plain Layout + + +\end_layout + +\begin_layout Plain Layout + + public void setUsername(String newUsername) { +\end_layout + +\begin_layout Plain Layout + + username = newUsername; +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + +\end_layout + +\begin_layout Plain Layout + + public String getUsername() { +\end_layout + +\begin_layout Plain Layout + + return username; +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + +\end_layout + +\begin_layout Plain Layout + + // setPassword/getPassword等方法和getUsername/setUsername类似 +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +大多数IDE开发环境可以帮助我们自动生成这些getter/setter方法:在类中右键选择“Insert Code... +\begin_inset Quotes erd +\end_inset + +,然后选择“Getter and Setter...”,选中希望自动生成getter/setter方法的私有属性,可以多选,然后点击“Generate”按钮即可。自动 +产生的getter/setter代码中使用了this关键字,我们将在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:对象的存储模型" + +\end_inset + +讨论它。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +改造 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:default修饰符" + +\end_inset + +中的例子,使得BankCard类中的username和password都是private的。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "acPrivate-BankCard.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "acPrivate-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/acprivate/BankCard.java" +lstparams "float,caption={演示private修饰符的BankCard.java},label={acPrivate-BankCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/acprivate/Client.java" +lstparams "float,caption={Client.java},label={acPrivate-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +可以看出,我们在Client中无法直接修改密码了,否则会报告语法错误。 +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +BankCard类的两个属性使用private修饰符后,Client类无法直接访问这两个属性了。可以通过提供getter/setter方法,方便Client访问 +BankCard的这两个属性。请读者试着在BankCard中加上getter/setter方法,并在Client中调用getter/setter修改用户名和密码 +。 +\end_layout + +\begin_layout Problem +构造方法是私有的会怎样?为什么? +\end_layout + +\begin_layout Problem +我们在Client类中使用new BankCard()创建对象时会试图调用BankCard的构造方法,但是此时BankCard的构造方法是私有的,意味着对同一个 +包下面的Client不可见!因此,如果使用private修饰构造方法,意味着你不希望别人直接通过new操作符创建对象。那么这个类还有啥用处呢?实际上,在这种情况 +下,可以通过提供一个方法来创建对象,比如下面的代码片段: +\end_layout + +\begin_layout Problem +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class BankCard { +\end_layout + +\begin_layout Plain Layout + + .... +\end_layout + +\begin_layout Plain Layout + + private BankCard () {} +\end_layout + +\begin_layout Plain Layout + + +\end_layout + +\begin_layout Plain Layout + + public static BankCard getInstance() { +\end_layout + +\begin_layout Plain Layout + + new BankCard(); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Problem +在本类中new BankCard()当然是没有问题的了,所以通过一个公有的方法getInstance()来创建对象,则Client就可以这样使用: +\end_layout + +\begin_layout Problem +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class Client { +\end_layout + +\begin_layout Plain Layout + + .... +\end_layout + +\begin_layout Plain Layout + + BankCard card = BankCard.getInstance(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Problem +此种用法常见于工厂模式 +\begin_inset CommandInset citation +LatexCommand cite +key "design-pattern-4gangs" +literal "true" + +\end_inset + +、单例模式 +\begin_inset CommandInset citation +LatexCommand cite +key "design-pattern-4gangs" +literal "true" + +\end_inset + +等。 +\end_layout + +\begin_layout Subsubsection +protected修饰符 +\end_layout + +\begin_layout Standard +private修饰过的属性和方法只有本类可以访问,default修饰过的属性和方法本类和本包其他类可以访问, +\begin_inset Index idx +status open + +\begin_layout Plain Layout +protected +\end_layout + +\end_inset + +protected修饰过的属性和方法则进一步放宽了限制:除了本类、本包之外,子类也可以访问。或者说,我们使用protected修饰属性和方法的唯一目的就是: +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +子类可见 +\end_layout + +\end_inset + +,这也是protected这个修饰符的本意:受保护的本意大概就是家族内无本质纷争的意思,所谓“兄弟阋于墙,外御其辱”,可以理解为一家人不见外,不是一家人就对不起 +了,不可见。因此,protected修饰的属性和方法本人可见(这个很自然),同包内的其他类(同胞)可见,子类(对自己的下一代不隐瞒,即使下一代不在同一个包内)可 +见,其他外族(其他包中的类)则不可见。当然, +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:public修饰符" + +\end_inset + +的 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +public +\end_layout + +\end_inset + +public修饰过的属性和方法在子类也是可见的,但是 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +public +\end_layout + +\end_inset + +public往往太宽泛,实际应用的时候应该严格限制。 +\end_layout + +\begin_layout Example +使用protected改造银行卡的例子,观察protected是如何保护属性和方法的 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整代码参见 +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/oopbasic/src/cn +/edu/sdut/softlab/oopbasic/acprotected/other +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "acprotected-BankCard.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "acprotected-CreditCard.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/acprotected/BankCard.java" +lstparams "float,caption={演示protected修饰符的BankCard.java},label={acprotected-BankCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/acprotected/other/CreditCard.java" +lstparams "float,caption={演示protected修饰符的CreditCard.java},label={acprotected-CreditCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/acprotected/other/Test.java" +lstparams "float,caption={Test.java},label={acprotected-Test.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Client.java得到如下结果: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +BankCard constructor called +\end_layout + +\begin_layout Plain Layout +钱被取走啦! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +在BankCard中,我们将两个属性和两个方法均使用protected修饰,因此其子类CreditCard能够直接访问这两个属性和方法。注意到CreditCar +d和BankCard不在一个包内,这并不影响CreditCard访问父类BankCard中protected修饰过的属性和方法,也就是说,Java首先根据“父子 +”关系检查访问权限,然后再根据包内还是包外检查访问权限。 +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "acprotected-Test.java" + +\end_inset + +中创建了一个BankCard对象,但是由于Test类和BankCard不在同一包内,也不是BankCard的子类,因此Test中创建的BankCard对象无法直 +接访问protected修饰过的属性和方法。 +\end_layout + +\begin_layout Subsubsection +public修饰符 +\begin_inset CommandInset label +LatexCommand label +name "subsec:public修饰符" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +public +\end_layout + +\end_inset + +public修饰符当然就是无限制的意思了,在属性和方法的访问控制中,public修饰符应该谨慎使用,只有确定需要公开的情形才使用public修饰属性和方法,否则 +和C语言有啥区别呢?请记住,public意味着公开的承诺,一旦你使用了public修饰属性和方法,就意味着你失去了后续修改这部分代码的机会。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +虽然在属性和方法上要谨慎使用pubic修饰符,但是构造方法往往是public的,这是因为绝大多数情况下,我们编写了一个类是希望任何人都能够创建相应的对象的。试想 +,如果构造方法是protected、default甚至是private的,会怎样?这里列出四种修饰符修饰构造方法的情形: +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +public的构造方法 +\end_layout + +\end_inset + +:任何人都可以通过new创建对象 +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +protected的构造方法 +\end_layout + +\end_inset + +:只有本类、子类和同一个包内的类可以通过new创建对象 +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +default的构造方法 +\end_layout + +\end_inset + +:只有本类、同一个包内的类可以通过new创建对象 +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +private的构造方法 +\end_layout + +\end_inset + +:只有本类可以通过new创建对象 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +属性和方法的访问控制小结 +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:访问控制保护范围示意" + +\end_inset + +可以帮助我们理解public/protected/private修饰符的保护范围。一般的,可以根据 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "tab:Java的访问控制修饰符" + +\end_inset + +按照从左向右的顺序推断修饰符在当前语境中的保护作用。比如,如果父类中的属性是default的,并且子类和父类不在同一个包中,则子类是无法访问父类中该属性的。但是 +如果子类和父类在同一个包中,则子类可以访问父类中这个default修饰的属性—此时default修饰符允许同一包中的类访问这个条件起了作用。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/access-control-overview.eps + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +访问控制保护范围示意 +\begin_inset CommandInset label +LatexCommand label +name "fig:访问控制保护范围示意" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在编程实践中,我们往往根据以下的原则来确定使用什么修饰符控制属性和方法的访问权限: +\end_layout + +\begin_layout Itemize +首先考虑使用最严格的访问控制策略,即优先考虑使用private修饰属性和方法,除非你有足够的理由,比如希望子类可见,则选择使用protected修饰符。 +\end_layout + +\begin_layout Itemize +尽量避免default修饰符,即不使用任何修饰符,这是一个危险和不好的编程习惯。 +\end_layout + +\begin_layout Itemize +尽量避免public修饰符,这比default更危险!有两个例外:一是构造方法一般是public的,理由在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:public修饰符" + +\end_inset + +已经讲过了。二是常量一般也是public的。 +\end_layout + +\begin_layout Subsection +类的访问控制 +\begin_inset CommandInset label +LatexCommand label +name "subsec:类的访问控制" + +\end_inset + + +\end_layout + +\begin_layout Standard +属性和方法的访问控制有4个级别,类的访问控制则简单的多,只有两个级别: +\end_layout + +\begin_layout Enumerate +\begin_inset Index idx +status open + +\begin_layout Plain Layout +public +\end_layout + +\end_inset + +public:public修饰的类,在任何包中都可见。 +\end_layout + +\begin_layout Enumerate +\begin_inset Index idx +status open + +\begin_layout Plain Layout +default +\end_layout + +\end_inset + +default:default修饰(即没有任何修饰符)的类,只在本包中可见。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +在一个Java源文件中,只有一个类可以是public的,而且这个public的类的类名和文件名要严格一致。在这个Java源文件中,除了这个public的类之外, +依然可以定义其他的default修饰(即没有使用任何修饰符)的类。但是一般情况下不建议这样做,应该每个类建立单独的Java源文件。原因是我们一般是通过浏览这个包 +(目录)了解这个包中包含了哪些类,如果在一个源文件中包含了多个类,一方面我们无法从文件的目录了解包的内容,另一方面,这些隐藏在其他类文件中的类就只能限于包内访问 +了。一个例外是内部类,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:内部类" + +\end_inset + +。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +内部类 +\begin_inset CommandInset label +LatexCommand label +name "subsec:内部类" + +\end_inset + + +\end_layout + +\begin_layout Standard +有的时候,我们为了防止命名冲突,或者为了安全起见,定义一个类只希望局限在某个类内使用,这样的类就是 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +内部类 +\end_layout + +\end_inset + +内部类(Inner Class): +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +定义在一个类内部的类 +\end_layout + +\end_inset + +,比如: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +class OuterClass { +\end_layout + +\begin_layout Plain Layout + + ... +\end_layout + +\begin_layout Plain Layout + + class InnerClass() { +\end_layout + +\begin_layout Plain Layout + + ... +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + +可以把内部类理解为在类内部定义的第三种资源,其他两种是属性和方法,因此类比属性和方法的用法,我们可以这样使用内部类: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +OuterClass.InnerClass innerObject = outerObject.new InnerClass(); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:内部类的创建过程" + +\end_inset + +形象的表示了内部类的创建过程。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/new-innerclass.png + width 60col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +内部类的创建过程 +\begin_inset CommandInset label +LatexCommand label +name "fig:内部类的创建过程" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +编写NotePad类,使用内部类Editor实现编辑功能 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/oopbasic/src/cn +/edu/sdut/softlab/oopbasic/ac/innerclass +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "NotePad.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "innerclass-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/ac/innerclass/NotePad.java" +lstparams "float,caption={NotePad.java},label={NotePad.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/ac/innerclass/Client.java" +lstparams "float,caption={Client.java},label={innerclass-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +parsing:test string +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +通过这个例子我们要注意到两点: +\end_layout + +\begin_layout Itemize +如何创建一个内部类对象:首先要创建一个外部类对象,然后才能创建一个内部类对象。 +\end_layout + +\begin_layout Itemize +内部类对象可以访问外部包围类(即内部类是在这个外部包围类中定义的)的属性和方法,即使这个外部类的属性和方法是private的(请读者试着把content属性设置 +为private看看会怎样?试着把parseContent方法设置为private看看会怎样?)。这个很容易理解:内部类和外部类的属性和方法是平等的, +\begin_inset Flex Emph +status open + +\begin_layout Plain Layout +就像是本类的方法可以无限制访问本类的属性一样 +\end_layout + +\end_inset + +,本类的内部类当然可以无限制访问本类的属性和方法。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status collapsed + +\begin_layout Plain Layout +也许你会说,NotePad这个例子中,使用内部类Editor实现parseContent这个功能太矫情,根本没有必要!是的,在这种简单的情况下确实没有必要绕道使 +用内部类。但是设想NotePad不仅仅需要提供文本编辑,还需要文本搜索、格式转换等等其他功能,而且每类功能不止包含一个方法,那么为了逻辑上清晰起见,使用内部类将 +文本编辑相关的方法组织为内部类NotePad.Editor,将文本搜索相关的方法组织为内部类NotePad.Search,将格式转换相关的方法组织为内部类NoteP +ad.Transfer就容易理解了。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +引用类型 +\begin_inset CommandInset label +LatexCommand label +name "sec:引用类型" + +\end_inset + + +\end_layout + +\begin_layout Standard +很多人会说,Java语言比C语言更“进步”或者“安全”的一个原因是Java没有指针数据类型,其实这是不确切的。Java的确没有像C语言那样提供“指针 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +指针 +\end_layout + +\end_inset + +”这种基本数据类型,但是Java确实使用了指针,而且指针的正确使用同样很重要。Java中的指针叫做“ +\begin_inset Index idx +status open + +\begin_layout Plain Layout +引用 +\end_layout + +\end_inset + +引用”。 +\end_layout + +\begin_layout Standard +和C语言一样,我们可以从变量在内存中的存储来理解Java的引用(指针)。Java的基本数据类型所形成的变量不是引用,变量的名字直接代表了变量所在存储单元的内容, +这和C语言中的非指针变量是一样的。除此之外,Java中的数组、对象、Enum等的名字,都是引用(指针),如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java中的引用" + +\end_inset + +所示。 +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/reference-object.png + width 30line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java中的引用 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java中的引用" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +比如下面的代码: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +Person person = new Person(); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +之前我们把person叫做“Person”类型的对象,其实这是不严谨的,应该叫做“Peron”类型对象的名字。也就是说,person仅仅是一个对象的名字,这个名 +字其实是指向person对象的一个引用(指针)。因此下面的代码: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +Person person; +\end_layout + +\begin_layout Plain Layout + +person.goHome(); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +就会报“NullPointException +\begin_inset Quotes erd +\end_inset + +错误,即“空指针异常”。这里只是声明了一个person类型的引用,但是并没有初始化,也就是说,person并没有指向任何实质的Person类型的对象。因此在初始 +化之前,任何对象的引用都是null,这和C语言的指针含义完全一样:在C语言中,任何指针在初始化之前都是null指针,直接使用null指针是有风险的。而在Java +中,Java虚拟机会自动侦测空指针,任何对空指针 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +空指针 +\end_layout + +\end_inset + +(未初始化的对象引用)都会报告NullPointException异常。NullPointException异常如此常见,通常大家都把NullPoinitExc +eption异常简称为“ +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +NPE +\begin_inset Index idx +status open + +\begin_layout Plain Layout +NPE +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +”。 +\end_layout + +\begin_layout Standard +在C语言中,指针作为函数的参数是一个强大的特性,即可以帮助把大量的数据传入函数(输入参数),也可以帮助函数返回大量的数据(输出参数)。在Java中,我们也要区分 +方法的参数为简单数据类型和对象(引用)两种情况。 +\end_layout + +\begin_layout Example +使用对象作为方法的参数 +\begin_inset CommandInset label +LatexCommand label +name "exa:使用对象作为方法的参数。" + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +我们首先定义一个简单的Person类,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "objref-Person.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/objref/Person.java" +lstparams "float,caption={Person.java},label={objref-Person.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +测试类Client.java的代码参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "objref-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/objref/Client.java" +lstparams "float,caption={Client.java},label={objref-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +Client的运行结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\align left +Person[username=zhangsan,password=123456,seniority = 20,salary = 5000.0] +\end_layout + +\begin_layout Plain Layout +\align left +Person[username=zhangsan,password=123456,seniority = 20,salary = 6000.0] +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +可以看出,adjustSalary方法中改变了person对象的属性slary的值, +\begin_inset Flex Emph +status open + +\begin_layout Plain Layout +这和C语言中使用指针作为函数参数的作用如出一辙 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Example +两个引用指向同一个对象 +\begin_inset CommandInset label +LatexCommand label +name "exa:两个引用指向同一个对象。" + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +我们借用 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:使用对象作为方法的参数。" + +\end_inset + +中定义的Person类设计一个测试类,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "Client1.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/objref/Client1.java" +lstparams "caption={Client1.java},label={Client1.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Client1的结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +zhangsan1 == zhangsan2 ? false +\end_layout + +\begin_layout Plain Layout +zhangsan3 == zhangsan1 ? true +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:两个引用指向同一个对象。" + +\end_inset + +中,看起来zhangsan1和zhangsan2两个对象是一样的,有相同的名字和密码设置。但是,这是两个不同的对象,即不同的引用,在内存中有不同的地址。而zha +ngsan3指向了zhangsan1,即zhangsan3和zhangsan1指向了同一个对象,因此zhangsan1和zhangsan3是相等的,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:对象的引用示意图" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/object-ref-model.eps + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +对象的引用示意图 +\begin_inset CommandInset label +LatexCommand label +name "fig:对象的引用示意图" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Subsection* +this +\begin_inset Note Note +status open + +\begin_layout Plain Layout +满足李震梅老师的要求 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Java使用 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +this +\end_layout + +\end_inset + +this关键字表示“对象本身”,即 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +指向当前对象的引用 +\end_layout + +\end_inset + +。比如在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "objref-Person.java" + +\end_inset + +中,构造方法是这样写的: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + public Person(String username, String password) { +\end_layout + +\begin_layout Plain Layout + + this.username = username; +\end_layout + +\begin_layout Plain Layout + + this.password = password; +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +其中,this.username即指当前对象的username属性,这样就把作为参数的username和作为对象属性的username区分开来了。 +\end_layout + +\begin_layout Subsection* +super +\begin_inset Note Note +status open + +\begin_layout Plain Layout +满足李震梅老师的要求 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +我们在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:对象的创建过程" + +\end_inset + +中已经看到,对象在创建时会“递归的构造父类对象”,也就是说,递归的调用父类的构造方法,这并不需要我们在子类的构造方法中做什么。但是,有时候我们希望能够控制对象的 +构造过程,也就是说,打破java默认的对象构造过程,在构造对象的链条中加入自定义的成分,这个时候我们可以使用 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +super +\end_layout + +\end_inset + +super关键字:指向父类对象的引用。我们通过一个例子来说明 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +super +\end_layout + +\end_inset + +super在对象的构造过程中是如何起作用的。 +\end_layout + +\begin_layout Example +使用super自定义对象的构造过程 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/oopbasic/src/cn +/edu/sdut/softlab/oopbasic/inherit/step4 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +限于篇幅,这里只列出了CreditCard.java的完整代码,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "inherit-step4-CreditCard.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/inherit/step4/CreditCard.java" +lstparams "float,caption={CreditCard.java},label={inherit-step4-CreditCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果和分析 +\end_layout + +\begin_layout Standard +我们可以分三种情况运行此例,分别在CreditCard类的构造方法CreditCard(String cardNo)中: +\end_layout + +\begin_layout Enumerate +调用super()时,输出如下: +\begin_inset Newline newline +\end_inset + + +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "90col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Card constructor called +\end_layout + +\begin_layout Plain Layout +BankCard constructor called +\end_layout + +\begin_layout Plain Layout +CreditCard constructor called,cardNo=123 +\end_layout + +\begin_layout Plain Layout +============================== +\end_layout + +\begin_layout Plain Layout +Card constructor called,cardNo=456 +\end_layout + +\begin_layout Plain Layout +BankCard constructor called,cardNo=456 +\end_layout + +\begin_layout Plain Layout +DebitCard constuctor called,cardNo=456 +\end_layout + +\end_inset + + +\begin_inset Newline newline +\end_inset + +可以看出,调用super()会触发“递归的构造父类对象”。 +\end_layout + +\begin_layout Enumerate +调用super(cardNo)时,输出如下: +\begin_inset Newline newline +\end_inset + + +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "90col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Card constructor called,cardNo=123 +\end_layout + +\begin_layout Plain Layout +BankCard constructor called,cardNo=123 +\end_layout + +\begin_layout Plain Layout +CreditCard constructor called,cardNo=123 +\end_layout + +\begin_layout Plain Layout +============================== +\end_layout + +\begin_layout Plain Layout +Card constructor called,cardNo=456 +\end_layout + +\begin_layout Plain Layout +BankCard constructor called,cardNo=456 +\end_layout + +\begin_layout Plain Layout +DebitCard constuctor called,cardNo=456 +\end_layout + +\end_inset + + +\begin_inset Newline newline +\end_inset + +可以看出,调用super(cardNo)后,就不会再调用父类的无参构造方法。 +\end_layout + +\begin_layout Enumerate +不调用父类的构造方法时,输出如下: +\begin_inset Newline newline +\end_inset + + +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "90col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Card constructor called +\end_layout + +\begin_layout Plain Layout +BankCard constructor called +\end_layout + +\begin_layout Plain Layout +CreditCard constructor called,cardNo=123 +\end_layout + +\begin_layout Plain Layout +============================== +\end_layout + +\begin_layout Plain Layout +Card constructor called,cardNo=456 +\end_layout + +\begin_layout Plain Layout +BankCard constructor called,cardNo=456 +\end_layout + +\begin_layout Plain Layout +DebitCard constuctor called,cardNo=456 +\end_layout + +\end_inset + + +\begin_inset Newline newline +\end_inset + +可以看出,不显式调用父类的构造方法,实际上也会默认调用父类的无参构造方法,和显式调用super()效果是一样的。也就是说, +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +我们在创建子类对象时,要么通过明确调用父类的有参构造方法递归的创建父类对象,要么java会递归的调用父类的无参构造方法来初始化各级父类对象 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Section +static +\begin_inset CommandInset label +LatexCommand label +name "sec:static" + +\end_inset + + +\end_layout + +\begin_layout Standard +一个典型的面向对象的设计如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:面向对象编程的基本思路" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/book-nostatic.eps + width 80col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +面向对象编程的基本思路 +\begin_inset CommandInset label +LatexCommand label +name "fig:面向对象编程的基本思路" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,我们在抽象出一类事物的共同特性后,编写相应于这类事物的一个类,在这里是Book;然后根据Book类再创建若干个Book类型的对象,book1、book +2等等。有了book对象后,就可以访问book对象的属性和方法了,比如调用:book.edit()。总之,原则上我们只有 +\begin_inset Flex Emph +status open + +\begin_layout Plain Layout +持有一个对象后(其实是持有一个指向对象的引用),才能操作这个对象 +\end_layout + +\end_inset + +。由 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:面向对象编程的基本思路" + +\end_inset + +可以看出,不同对象的状态(属性值)往往是不同的。 +\end_layout + +\begin_layout Standard +考虑下面的情形: +\end_layout + +\begin_layout Itemize +比如无论书籍的类型、开张等,书籍的“章”一般都定义为“第一章”、“第二章”,因此可以将CHAPTER_ONE定义为常量,而且不随Book对象的变化而变化,即无论 +有多少个Book对象,也无论Book对象的其他属性如何,CHAPTER_ONE,CHAPTER_TWO的值都不会变化。在这种情况下,每个Book对象都保存一份C +HAPTER_ONE,CHAPTER_TWO属性是没有必要的。解决这个问题的方法参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:static常量" + +\end_inset + +。 +\end_layout + +\begin_layout Itemize +比如给每个Book对象一个id,要求这个id能够自动增长,即假设第一个Book对象的id为1,第二个Book对象的id自动设置为2,以此类推。解决这个问题的方法 +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:static属性" + +\end_inset + +。 +\end_layout + +\begin_layout Itemize +比如我们要设计一个方法usage(),当调用这个方法时打印出Book类的用法。可以看出这个方法和对象的状态没有任何关系,也就是说,usage方法没有必要读取对象 +的状态,因此也没有必要每个对象都保存一个usage方法。解决这个问题的方法参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:static方法" + +\end_inset + +。 +\end_layout + +\begin_layout Subsection +static常量 +\begin_inset CommandInset label +LatexCommand label +name "subsec:static常量" + +\end_inset + + +\end_layout + +\begin_layout Standard +显然,常量没有必要在每个对象中都保存一份,只需要在类的定义中保存一份即可。因此,正如我们在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:常量和常量的命名" + +\end_inset + +中提到的,常量一般的命名方式都是public static final的,其中的static表示静态变量,即只在类定义中保存一份的变量,或者说,所有对象共享一份 +的变量。由于是常量,也通常使用final修饰符限定此变量不可修改,即常量(常数变量)。由于静态常量只和类有关而和具体对象无关,因此静态常量 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +静态常量 +\end_layout + +\end_inset + +又称为 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Index idx +status open + +\begin_layout Plain Layout +类常量 +\end_layout + +\end_inset + +类常量 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +在类中定义常量后,我们有两种方式使用(引用)这个常量: +\end_layout + +\begin_layout Enumerate +直接使用类名引用类常量。也就是说,不需要创建一个此类的对象,可以直接通过类名引用类常量。 +\end_layout + +\begin_layout Enumerate +使用对象引用类常量。如果已经创建了对象,通过对象引用类常量也是可以的。 +\end_layout + +\begin_layout Example +在Book中定义常量CHAPTER_ONE,CHAPTER_TWO,并使用两种方法引用此常量。 +\begin_inset CommandInset label +LatexCommand label +name "exa:在Book中定义常量CHAPTER_ONE,CHAPTER_TW" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "staticcontant-Book.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "staticconstant-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/staticconstant/Book.java" +lstparams "float,caption={使用了static常量的Book.java},label={staticcontant-Book.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/staticconstant/Client.java" +lstparams "float,caption={Client.java},label={staticconstant-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果和分析 +\end_layout + +\begin_layout Standard +执行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +第一章 +\end_layout + +\begin_layout Plain Layout +第一章 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +虽然两种方式都打印出了正确的结果,但是第二种引用static常量的方式是不建议的:即不经济,也没必要。 +\end_layout + +\begin_layout Exercise +在JDK源代码中找到一些常量的定义,认真体会: +\end_layout + +\begin_layout Itemize +常量的惯用命名方式,。 +\end_layout + +\begin_layout Itemize +常量的使用(引用)方式。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +JDK源代码可以从 +\begin_inset CommandInset href +LatexCommand href +name "https://github.com/dmlloyd/openjdk" +target "https://github.com/dmlloyd/openjdk" +literal "false" + +\end_inset + +下载。在openjdk的源代码目录下执行如下命令可以找到非常多的常量定义: +\end_layout + +\begin_layout Plain Layout +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status collapsed + +\begin_layout Plain Layout +$ grep -ri +\begin_inset Quotes eld +\end_inset + +public static final +\begin_inset Quotes erd +\end_inset + + * +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +static属性 +\begin_inset CommandInset label +LatexCommand label +name "subsec:static属性" + +\end_inset + + +\end_layout + +\begin_layout Standard +当我们用static修饰类的属性时,这个属性就成为“ +\begin_inset Index idx +status open + +\begin_layout Plain Layout +类属性 +\end_layout + +\end_inset + +类属性”。相对于“ +\begin_inset Index idx +status open + +\begin_layout Plain Layout +实例属性 +\end_layout + +\end_inset + +实例属性”(每个对象都有一份独立的拷贝), +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +类属性在此类的所有对象之间共享一份拷贝 +\end_layout + +\end_inset + +。对于类属性,我们需要注意到三点: +\end_layout + +\begin_layout Itemize +类属性的引用。我们一般采用Book.nextId的方式,即直接使用类来引用类属性,这也是类属性设计的本意。 +\end_layout + +\begin_layout Itemize +类属性相当于在对象之间共享的变量,因此一个对象修改了类属性,会影响另外对象的状态,因此使用类属性实际上导致了对象之间的“紧耦合”,造成了系统模块之间的界面不清晰 +,这是现代软件设计中力图规避的地方。因此,在软件设计实践中要尽量避免使用类属性,除非你有足够的理由。 +\end_layout + +\begin_layout Itemize +类属性的初始化问题。类属性的默认值和普通属性没有任何区别,但是由于类属性和具体对象没有关联,因此无法在对象的构造方法中初始化。Java提供了“ +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +static块 +\end_layout + +\end_inset + +”的方式初始化类属性,比如在Book中这样初始化nextId类属性: +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + // 初始化静态属性,这里设置id的起点值 +\end_layout + +\begin_layout Plain Layout + + static { +\end_layout + +\begin_layout Plain Layout + + nextId = 100; +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + +和对象的构造方法不同的是,static代码块在整个应用程序运行期间只会执行一次,而对象的构造方法在创建对象时都会执行一次。 +\end_layout + +\begin_layout Example +编写一个Book类,book对象使用自动增长的id作为对象的标识。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "staticvariable-Book.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "staticvariable-Client.java" + +\end_inset + + 。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/staticvariable/Book.java" +lstparams "float,caption={Book.java},label={staticvariable-Book.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/staticvariable/Client.java" +lstparams "float,caption={Client.java},label={staticvariable-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Book{id=100, title=Thinking in Java, author=null, price=0.0} +\end_layout + +\begin_layout Plain Layout +Book{id=101, title=Design Patterns, author=null, price=0.0} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +static方法 +\begin_inset CommandInset label +LatexCommand label +name "subsec:static方法" + +\end_inset + + +\end_layout + +\begin_layout Standard +和类属性 +\begin_inset Foot +status open + +\begin_layout Plain Layout +需要澄清的是,下面两种说法是等价的,我们可能在不同的场合交替使用不同的名称: +\end_layout + +\begin_layout Itemize +类属性=静态属性 +\end_layout + +\begin_layout Itemize +类方法=静态方法 +\end_layout + +\begin_layout Itemize +实例属性=实例变量=非静态属性=非静态变量 +\end_layout + +\begin_layout Itemize +实例方法=实例函数=对象方法=对象函数=非静态方法 +\end_layout + +\end_inset + +一样, +\begin_inset Index idx +status open + +\begin_layout Plain Layout +类方法 +\end_layout + +\end_inset + +类方法指使用static修饰的方法,类方法在所有对象之间共享一个拷贝。类方法通常用于一些工具类的定义,比如JDK中的Math类 +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见:http://docs.oracle.com/javase/8/docs/api/java/lang/Math.html +\end_layout + +\end_inset + +里面的方法都是类方法。 +\end_layout + +\begin_layout Standard +类方法是在对象创建之前就存在的,因此在类方法中不能访问实例属性(对象还没有创建,实例属性根本不存在),只能访问类属性(使用static修饰的属性),见下面的代码 +片段: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class Test { +\end_layout + +\begin_layout Plain Layout + + string name; +\end_layout + +\begin_layout Plain Layout + + static int nextId; +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + static void testStaticMethod() { +\end_layout + +\begin_layout Plain Layout + + nextId++; // 这是可以的 +\end_layout + +\begin_layout Plain Layout + + //name = "zhangsan"; // 这是不允许的,语法错误 +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +在Book类中增加一个类方法usage(),调用这个方法显示一段文字,说明这个类的用途。 +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +设计一个字符串处理工具类,给出如下的方法实现: +\end_layout + +\begin_layout Itemize +能够方便的删除字符串的最后一个字母; +\end_layout + +\begin_layout Itemize +能够自动将字符串转化为网址形式,即自动增加 +\begin_inset Quotes erd +\end_inset + +http:// +\begin_inset Quotes erd +\end_inset + +前缀; +\end_layout + +\begin_layout Subsection +*内部类回头看 +\end_layout + +\begin_layout Standard +在 +\begin_inset CommandInset ref +LatexCommand nameref +reference "subsec:内部类" + +\end_inset + +中,我们看到内部类就像是定义在类内部的方法一样。类的方法分为静态方法和非静态方法,静态方法只能访问类的静态属性,那么内部类是不是也可以使用static修饰呢? +\end_layout + +\begin_layout Standard +实际上,java的内部类分为四种类型: +\end_layout + +\begin_layout Enumerate +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +成员内部类(member inner class) +\end_layout + +\end_inset + +,即我们在 +\begin_inset CommandInset ref +LatexCommand nameref +reference "subsec:内部类" + +\end_inset + +中讨论的,和实例方法用法类似的内部类。 +\end_layout + +\begin_layout Enumerate +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +静态内部类(static inner class) +\end_layout + +\end_inset + +,使用static修饰的内部类。 +\end_layout + +\begin_layout Enumerate +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +局部内部类(local inner class) +\end_layout + +\end_inset + +,定义在方法内部的类。 +\end_layout + +\begin_layout Enumerate +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +匿名内部类(anonymous inner class) +\end_layout + +\end_inset + +,只使用一次的内部类。 +\end_layout + +\begin_layout Standard +内部类的第一种形式:成员内部类我们已经讨论过了,这里不再赘述,下面我们分别看一下其他三种内部类: +\end_layout + +\begin_layout Subsubsection +静态内部类 +\end_layout + +\begin_layout Standard +静态内部类即使用static修饰的内部类,也常叫做“嵌套类”(Nested Class)。静态内部类有两个重要的意义: +\end_layout + +\begin_layout Enumerate +正如静态方法一样,使用静态内部类可以限制内部类对外部包围类属性和方法的访问。对比成员内部类, +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +静态内部类只能访问外部包围类的静态属性和静态方法 +\end_layout + +\end_inset + +。使用静态内部类的好处是,如果我们在外部包围类中不定义静态属性和方法,实际上就切断了静态内部类和外部包围类的联系,使得静态内部类成为一个独立的模块,符合“松耦合 +”的现代软件设计理念。因此可以看到在实际的软件开发中,内部类很多都定义为静态内部类,比如Android程序设计中,大量使用到静态内部类。 +\end_layout + +\begin_layout Enumerate +静态内部类对象的创建不需要首先创建外部包围类对象,比如Outer.Inner innerObj = new Outer.Inner();这实际上让静态内部类成为了一 +个受限的顶级类 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +需要展开说明顶级类和受限的含义吗? +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Example +编写一个静态内部类,演示静态内部类访问外部包围类的静态属性和静态方法 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/oopbasic/src/cn +/edu/sdut/softlab/oopbasic/nestedclass +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "nestedclass-Book.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "nestedclass-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/nestedclass/Book.java" +lstparams "caption={Book.java},label={nestedclass-Book.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/nestedclass/Client.java" +lstparams "caption={Client.java},label={nestedclass-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +edit the book[version=1] by someone +\end_layout + +\begin_layout Plain Layout +publish the book[Learning Java based on C] +\end_layout + +\begin_layout Plain Layout +Book.Editor.usage() called +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +局部内部类 +\end_layout + +\begin_layout Standard +局部内部类定义在方法内部,可以认为是方法的局部变量。就像方法的局部变量一样,局部内部类的作用范围仅限于方法内部,即在方法外部是无法创建局部内部类的对象的。局部内 +部类可以使用所在方法中的属性,也可以访问类的实例属性和类属性。 +\end_layout + +\begin_layout Standard +局部内部类的使用场合较少,通常在组织复杂方法代码时使用。但是,由于在方法内部定义类,可能导致方法体臃肿,使得方法的逻辑层次不清晰,在使用局部内部类时要适当取舍。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +举个在openjdk中的例子?或者实际项目中的例子 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +编写一个局部内部类,演示局部内部类对方法属性的访问和局部内部类对象的创建方式 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/oopbasic/src/cn +/edu/sdut/softlab/oopbasic/localinnerclass +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "localninnerclass-Book.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "localninnerclass-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/localinnerclass/Book.java" +lstparams "float,caption={Book.java},label={localninnerclass-Book.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/localinnerclass/Client.java" +lstparams "float,caption={Client.java},label={localninnerclass-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +edit the book before publish +\end_layout + +\begin_layout Plain Layout +publish book[version=1,id=0 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +匿名内部类 +\begin_inset CommandInset label +LatexCommand label +name "subsec:匿名内部类" + +\end_inset + + +\begin_inset Foot +status open + +\begin_layout Plain Layout +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:JAVA图形用户界面的事件机制" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:接口上的匿名内部类" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:使用匿名内部类" + +\end_inset + +中,我们还会看到匿名内部类的使用。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +如果一个内部类只使用一次的话,就没有必要非要给这个内部类起个名字了,这就是匿名内部类的使用场合。匿名内部类由于没有名字,必须从父类继承下来(在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:接口上的匿名内部类" + +\end_inset + +中我们可以看到,也可以实现一个接口)。 +\end_layout + +\begin_layout Example +使用匿名内部类 +\begin_inset CommandInset label +LatexCommand label +name "exa:使用匿名内部类" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "annonymousinnerclass-Book.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "annonymousinnerclass-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/annnoymousinnerclass/Book.java" +lstparams "float,caption={Book.java},label={annonymousinnerclass-Book.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/annnoymousinnerclass/Client.java" +lstparams "float,caption={Client.java},label={annonymousinnerclass-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +edit the book before publishing +\end_layout + +\begin_layout Plain Layout +publish the book[Learning Java Based on C] +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:使用匿名内部类" + +\end_inset + +中,我们组合使用了匿名对象和匿名内部类,这是由于在这种情况下,创建的匿名内部类对象也只使用一次,就没有必要起个名字了。我们给对象一个名字的目的不就是在重复使用这 +个对象的时候方便引用吗? +\end_layout + +\begin_layout Exercise +还原 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:使用匿名内部类" + +\end_inset + +为不使用匿名内部类的情形,对比一下说明匿名内部类的优点和缺点。 +\end_layout + +\begin_layout Subsection +*内部类的进一步讨论 +\begin_inset CommandInset label +LatexCommand label +name "subsec:内部类的进一步讨论" + +\end_inset + + +\end_layout + +\begin_layout Standard +在前面的讨论中,内部类都是没有父类的。但是,内部类其实也可以是一个子类 +\begin_inset Foot +status open + +\begin_layout Plain Layout +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:实现多个接口" + +\end_inset + +中,我们可以看到,内部类也可以实现(多个)接口,从而更好的实现Java的多继承。 +\end_layout + +\end_inset + +,这样我们在外部包围类中定义多个内部类,每个内部类继承自一个父类,就巧妙的绕过了Java没有多继承的限制,曲线的实现了多继承。 +\end_layout + +\begin_layout Example +编写程序,使用内部类达到多继承的目的。 +\begin_inset CommandInset label +LatexCommand label +name "exa:编写程序,使用内部类达到多继承的目的。" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinherit-Printer.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinherit-Copier.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinherit-SmartPrinter.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinherit-SmartPrinterClient.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/multiinherit/Printer.java" +lstparams "float,caption={Printer.java},label={multiinherit-Printer.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/multiinherit/Copier.java" +lstparams "float,caption={Copier.java},label={multiinherit-Copier.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/multiinherit/SmartPrinter.java" +lstparams "float,caption={SmartPrinter.java},label={multiinherit-SmartPrinter.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/multiinherit/SmartPrinterClient.java" +lstparams "float,caption={SmartPrinter.java},label={multiinherit-SmartPrinterClient.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +basic print +\end_layout + +\begin_layout Plain Layout +SmartPrinter print +\end_layout + +\begin_layout Plain Layout +basic copy +\end_layout + +\begin_layout Plain Layout +SmartPrinter copy +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +可以看出,在SmartPrinterTest中,我们只是使用SmartPrinter对象即可同时获得print和copy两个功能,好像同时从Printer和Co +pier继承下来一样。SmartPrinter类其实是一个Facade类 +\begin_inset CommandInset citation +LatexCommand cite +key "design-pattern-4gangs" +literal "true" + +\end_inset + +,当我们希望在一个类中融合多项功能时,为了代码逻辑清晰起见,借用内部类实现多继承是常见的策略。 +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +举一个在switch中使用Enum的例子 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +内部类的作用范围 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section* +思考和练习 +\end_layout + +\begin_layout Exercise +编写一个default修饰的类,尝试在其他包中创建该类的对象,结果会怎样? +\begin_inset CommandInset label +LatexCommand label +name "exer:编写一个default修饰的类,尝试在其他包中创建该类的对象,结" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +考虑下面的代码,指出哪些是类属性,哪些是实例属性? +\begin_inset CommandInset label +LatexCommand label +name "exer:考虑下面的代码,指出哪些是类属性,哪些是实例属性?" + +\end_inset + + +\begin_inset Note Note +status open + +\begin_layout Plain Layout +http://docs.oracle.com/javase/tutorial/java/javaOO/QandE/creating-questions.html +\end_layout + +\end_inset + + +\end_layout + +\end_body +\end_document diff --git a/guide/lecture_guide/lecture4.lyx b/guide/lecture_guide/lecture4.lyx new file mode 100644 index 0000000..21b9703 --- /dev/null +++ b/guide/lecture_guide/lecture4.lyx @@ -0,0 +1,9374 @@ +#LyX 2.3 created this file. For more info see http://www.lyx.org/ +\lyxformat 544 +\begin_document +\begin_header +\save_transient_properties true +\origin unavailable +\textclass ctex-book +\begin_preamble +\input{../../../writing-common/book-preamble.tex} +\end_preamble +\use_default_options true +\begin_modules +theorems-bytype +theorems-chap-bytype +coderemarks +note-inset +tip-inset +warning-inset +logicalmkup +\end_modules +\maintain_unincluded_children false +\begin_local_layout +PackageOptions url hyphens +\end_local_layout +\language chinese-simplified +\language_package default +\inputencoding utf8-plain +\fontencoding global +\font_roman "default" "DejaVu Sans" +\font_sans "default" "DejaVu Serif" +\font_typewriter "default" "DejaVu Sans Mono" +\font_math "auto" "auto" +\font_default_family default +\use_non_tex_fonts true +\font_sc false +\font_osf false +\font_sf_scale 100 100 +\font_tt_scale 100 100 +\use_microtype false +\use_dash_ligatures false +\graphics default +\default_output_format pdf4 +\output_sync 0 +\bibtex_command default +\index_command default +\float_placement tbph +\paperfontsize default +\spacing single +\use_hyperref true +\pdf_bookmarks true +\pdf_bookmarksnumbered false +\pdf_bookmarksopen false +\pdf_bookmarksopenlevel 3 +\pdf_breaklinks true +\pdf_pdfborder true +\pdf_colorlinks true +\pdf_backref false +\pdf_pdfusetitle true +\papersize default +\use_geometry false +\use_package amsmath 1 +\use_package amssymb 1 +\use_package cancel 1 +\use_package esint 1 +\use_package mathdots 1 +\use_package mathtools 1 +\use_package mhchem 1 +\use_package stackrel 1 +\use_package stmaryrd 1 +\use_package undertilde 1 +\cite_engine basic +\cite_engine_type default +\biblio_style plain +\use_bibtopic false +\use_indices false +\paperorientation portrait +\suppress_date false +\justification true +\use_refstyle 1 +\use_minted 0 +\boxbgcolor #d8daeb +\index Index +\shortcut idx +\color #008000 +\end_index +\secnumdepth 3 +\tocdepth 2 +\paragraph_separation indent +\paragraph_indentation default +\is_math_indent 0 +\math_numbering_side default +\quotes_style english +\dynamic_quotes 0 +\papercolumns 1 +\papersides 2 +\paperpagestyle default +\tracking_changes false +\output_changes false +\html_math_output 0 +\html_css_as_file 0 +\html_be_strict false +\end_header + +\begin_body + +\begin_layout Standard +\align center + +\size larger +\bar under +山东理工大学教案 +\end_layout + +\begin_layout Standard +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +第四次课 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +教学课型:理论课□√ 实验课□√ 习题课□ 实践课□ 技能课□ 其它□ +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +主要教学内容 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:类的继承" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:类的继承" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:访问控制" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:访问控制" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:引用类型" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:引用类型" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:static" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:static" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +重点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +继承的概念和使用场合; +\end_layout + +\begin_layout Enumerate +Java访问控制的层次; +\end_layout + +\begin_layout Enumerate +内部类的概念和使用场合; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +难点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +Java的访问控制; +\end_layout + +\begin_layout Enumerate +内部类; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +课程目标及要求 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +课程目标:课程目标1 +\end_layout + +\begin_layout Plain Layout +要求: +\end_layout + +\begin_layout Enumerate +熟练掌握继承的概念和用法,能够在面向对象的设计中熟练使用继承设计合适的类层次结构; +\end_layout + +\begin_layout Enumerate +熟练掌握Java的访问控制机制,知道在什么情况下使用什么样的访问控制手段; +\end_layout + +\begin_layout Enumerate +了解内部类的概念和用法; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +教学方法和手段 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +板书和多媒体相结合,边讲边练,当堂消化。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +讨论、思考题 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +结合访问控制,说一下继承在类的层次设计中如何使用? +\end_layout + +\begin_layout Enumerate +为什么要使用内部类? +\end_layout + +\begin_layout Enumerate +\begin_inset CommandInset ref +LatexCommand vref +reference "exer:编写一个default修饰的类,尝试在其他包中创建该类的对象,结" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Enumerate +\begin_inset CommandInset ref +LatexCommand vref +reference "exer:考虑下面的代码,指出哪些是类属性,哪些是实例属性?" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +参考资料 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Chapter +面向对象编程基础 +\begin_inset CommandInset label +LatexCommand label +name "chap:面向对象的基本概念" + +\end_inset + + +\end_layout + +\begin_layout Standard +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/oop.png + width 100col% + +\end_inset + + +\end_layout + +\begin_layout Section +再说C语言的struct +\begin_inset CommandInset label +LatexCommand label +name "sec:再说C语言的struct" + +\end_inset + + +\end_layout + +\begin_layout Standard +C语言以简练、灵活、高效著称,但是C语言本身提供的基本数据类型有限,描述现实世界的能力自然也有限。比如要求输入班级同学的英语和数学成绩并按照平均成绩排序 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这个例子不恰当,排序任务脱离了对象本身,是否换成画图 or animal,涉及到各种图形和图形的操作? +\end_layout + +\end_inset + +,如果我们仅使用C的基本数据类型来设计的话,大概能想到的策略有如下几种: +\end_layout + +\begin_layout Enumerate +每个同学都用三个变量来表示:zhangsan_name, zhangsan_english, zhangsan_math, wangwu_name, + wangwu_english, wangwu_english......。如果班级有40位同学,这需要120个变量来表达,不仅容易写错,还不胜其烦!这个思路显然值得商榷, +为下策。 +\end_layout + +\begin_layout Enumerate +使用数组来分别存储同学的名字、英语成绩和数学成绩,比如下面的代码片段: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +char* name[40]; +\end_layout + +\begin_layout Plain Layout + +float english_score[40]; +\end_layout + +\begin_layout Plain Layout + +float math_score[40]; +\end_layout + +\end_inset + +使用数组极大减少了变量的数量,但是也存在一个问题,我们其实隐含了这样一条规则:name数组的第i个元素(同学)的英语成绩是english_score数组的第i个 +元素,数学成绩是math_score数组的第i个元素。也就是说,这三个数组的对应元素有一一映射的关系。这个一一映射的关系是需要我们程序员自己维护的,也就是说,如 +果我们破坏了这一隐含的规则,无论有意还是无意,编译器并不能帮助我们发现这个“破坏”,因为从语法上,不符合这个隐含规则也是允许的,这即为程序员带来了负担,也为程序 +埋下了隐患。可以看出,带来这些问题的关键原因是三个数组的一一映射关系不是 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +语法级别的映射 +\end_layout + +\end_inset + +,编译器无法 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +从语法上保证和检查 +\end_layout + +\end_inset + +这三个数组是否遵循了一一映射的关系,这就是C语言引入struct概念的原因:将变量之间的映射关系语法化,我们看使用struct如何解决这个问题。 +\end_layout + +\begin_layout Enumerate +使用 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +struct +\end_layout + +\end_inset + +struct描述同学们的英语和数学成绩,代码片段如下: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +struct score{ +\end_layout + +\begin_layout Plain Layout + + char* name; +\end_layout + +\begin_layout Plain Layout + + float english_score; +\end_layout + +\begin_layout Plain Layout + + float math_score; +\end_layout + +\begin_layout Plain Layout + + float avg_score;/*平均成绩*/ +\end_layout + +\begin_layout Plain Layout + +}; +\end_layout + +\begin_layout Plain Layout + +struct score stu_scores[40]; +\end_layout + +\end_inset + +struct在语法上保证了name、english_score、math_score这三个变量是一一映射的,是score结构体的“成员分量 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +成员分量 +\end_layout + +\end_inset + +”,因此struct在语法上保证了名字和成绩不可能张冠李戴,杜绝了可能存在的隐患,也减轻了程序员的思想负担(不需要时刻提醒自己要维护姓名和成绩的映射关系)。所以 +,struct是C语言的重要组成部分,是C语言描述现实世界的重武器,在大型项目中大量使用struct来表达同类事物的共同特征(属性)。比如打开Linux内核源代 +码的头文件目录,我们随处可见大量的struct定义: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +struct font_desc { +\end_layout + +\begin_layout Plain Layout + + int idx; +\end_layout + +\begin_layout Plain Layout + + const char *name; +\end_layout + +\begin_layout Plain Layout + + int width, height; +\end_layout + +\begin_layout Plain Layout + + const void *data; +\end_layout + +\begin_layout Plain Layout + + int pref; +\end_layout + +\begin_layout Plain Layout + +}; +\end_layout + +\end_inset + +因此,我们可以这样定义struct: +\end_layout + +\begin_layout Definition +\begin_inset Index idx +status open + +\begin_layout Plain Layout +struct +\end_layout + +\end_inset + +struct是对一类事物公共属性的描述。 +\end_layout + +\begin_layout Subsection +struct的局限性 +\begin_inset CommandInset label +LatexCommand label +name "subsec:struct的局限性" + +\end_inset + + +\end_layout + +\begin_layout Standard +C语言通过struct大大扩充了C的数据类型,每一个struct都定义了一种新的数据类型来对应客观世界的某种事物,这样C语言不但描述客观世界的能力大大加强了,C +语言程序的可读性、可维护性也大大提高了。 +\end_layout + +\begin_layout Standard +C语言能够更好的描述客观世界,可以给struct记大功一件。但是,我们描述客观世界的目的是认识世界并进而改造世界,struct仅仅是方便了描述世界,对于改造世界 +并没有多大帮助。比如回到我们本章开头的问题:我们不仅仅要输入同学们的成绩,还要按照平均成绩排序。这里至少包含两个方面的“认识世界”和“改造世界”世界的动作: +\end_layout + +\begin_layout Enumerate +计算平均成绩:这是属于进一步认识世界的范畴:根据已有的事物属性,我们可以计算和推断出新的属性。 +\end_layout + +\begin_layout Enumerate +按照平均成绩排序:这是属于改造世界的范畴:对已有事物重新组合排序。 +\end_layout + +\begin_layout Standard +struct帮助我们很好的描述了同学们的名字和成绩的对应关系,但是计算平均成绩和按照成绩排序这两个“动作”,在C语言中是通过独立的函数来实现的,比如下面的代码片 +段: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +void calculate_avg_score(struct score* score) { +\end_layout + +\begin_layout Plain Layout + + /*按照某种权重算法计算平均成绩并保存到score.avg_score中*/ +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +struct score[] sort_score(struct score* scores[]) { +\end_layout + +\begin_layout Plain Layout + + /* 将数组scores排序后返回新的struct score数组*/ +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +可以看出,calculate_avg_score函数和sort_score函数虽然都和struct score有关系(作为参数或者返回值),但是这种关系是“弱关 +系”,因为calcuate_avg_score、sort_score可以没有定义,可以存在于另外的文件中,可以被定义为另外的名称等等。也就是说,在语法上,str +uct score和这两个函数并没有必然的联系,编译器没有办法帮助程序员检查这两个函数和struct score的映射关系,一切还需要程序员人工的 +\begin_inset Quotes erd +\end_inset + +细心 +\begin_inset Quotes erd +\end_inset + +照料。显然,struct一定程度上解决了描述世界的问题,但是没有解决认识世界和改造世界的问题。 +\end_layout + +\begin_layout Section +类和对象的初步概念 +\begin_inset CommandInset label +LatexCommand label +name "sec:类和对象的初步概念" + +\end_inset + + +\end_layout + +\begin_layout Subsection +类是struct概念的自然延伸 +\end_layout + +\begin_layout Standard +C中的struct实现了对客观事物属性的分组描述,即同一类型的客观事物的属性可以用一个struct来表达。正如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:struct的局限性" + +\end_inset + +所述,struct有其局限性,只能描述客观事物的属性,不能表达对客观事物的进一步认知动作和改造利用的动作,于是在面向对象的程序设计语言中引入“ +\begin_inset Index idx +status open + +\begin_layout Plain Layout +类 +\end_layout + +\end_inset + +类”的概念弥补struct的这一缺陷。 +\end_layout + +\begin_layout Definition +类是对一类客观事物公共 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + +和 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +动作 +\end_layout + +\end_inset + +的描述。 +\end_layout + +\begin_layout Standard +对比struct我们可以看出,类比struct多了“动作”的描述,也就是说,类即可以描述事物的属性,也可以描述我们可以对(用)这类事物“做什么”,是对客观世界的 +完整的描述。Java使用 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +class +\end_layout + +\end_inset + +关键字来定义类,一个简单的只包含属性的类和struct非常相似,比如二维坐标中的“点”,一开始可以这样定义(右边作为对照,列出了C中point结构体的定义): +\end_layout + +\begin_layout Standard +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "40line%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java的Point类定义 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +class Point { +\end_layout + +\begin_layout Plain Layout + + int x; // 点的x坐标 +\end_layout + +\begin_layout Plain Layout + + int y; // 点的y坐标 +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset space \hfill{} +\end_inset + + +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "45line%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +\begin_inset Caption Standard + +\begin_layout Plain Layout +C的point结构体定义 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +struct point { +\end_layout + +\begin_layout Plain Layout + + int x; /*点的x坐标*/ +\end_layout + +\begin_layout Plain Layout + + int y; /*点的y坐标*/ +\end_layout + +\begin_layout Plain Layout + +}; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +但是如果只是使用class替换了struct关键字,显然没有发挥类描述客观事物的最大威力,因此一个更合理的Point类如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "Point.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub321/Point.java" +lstparams "caption={Point.java},label={Point.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +可以看出,在这个版本的Point类定义中,“点”的属性(x,y)和对点的操作moveTo封装在一起了。 +\end_layout + +\begin_layout Subsection* +定义Java类 +\begin_inset CommandInset label +LatexCommand label +name "subsec:定义Java类" + +\end_inset + + +\begin_inset Note Note +status open + +\begin_layout Plain Layout +为了满足李震梅老师的审美观,修改为star form section +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +完整的定义Java类的语法是: +\end_layout + +\begin_layout Standard +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +[public] class ClassName { ...} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +这里有几个要点: +\end_layout + +\begin_layout Itemize +大部分情况下需要将类定义为 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +public +\end_layout + +\end_inset + +public的,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:类的访问控制" + +\end_inset + +。 +\end_layout + +\begin_layout Itemize +类名的常规命名遵循驼式命名法 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +驼式命名法 +\end_layout + +\end_inset + +,并且第一个字母是大写的。 +\end_layout + +\begin_layout Itemize +一个Java源代码文件中只能有一个类是public的,且这个public的类名必须和文件名完全一致,包括大小写。 +\end_layout + +\begin_layout Itemize +在Java源代码文件中可以定义多个类,只要保证只有一个public类即可。 +\end_layout + +\begin_layout Subsection +对象的概念 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +画图说明更清晰 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Wrap figure +lines 0 +placement r +overhang 0in +width "30line%" +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/point-monitor.eps + lyxscale 20 + width 100line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +类和实例的关系 +\begin_inset CommandInset label +LatexCommand label +name "fig:类和实例的关系" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +类是对一类事物的抽象描述,比如Point类是对二维坐标“点”的抽象描述,它表达了屏幕上的一个点所具有的公共属性:x坐标和y坐标,以及我们可以对“点”的操作,比如 +moveTo操作。但是,Point类并没有和屏幕上的实体点绑在一起,屏幕上的每一个实体点,可以看作Point类的一个具体 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Index idx +status open + +\begin_layout Plain Layout +实例 +\end_layout + +\end_inset + +实例 +\end_layout + +\end_inset + +,都具有Point类给出的一些属性,在这里就是屏幕上的每一个实体点都有相应的x、y坐标。我们把实体点叫做类Point的 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +实例(instance) +\end_layout + +\end_inset + +,或者叫做类Point的 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Index idx +status open + +\begin_layout Plain Layout +对象 +\end_layout + +\end_inset + +对象 +\end_layout + +\end_inset + +。 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +对象就是实例,实例就是对象 +\end_layout + +\end_inset + +。可以看出,一个类可以创建若干实例,所有实例(对象)都具有类中定义的属性,只是属性的值各不相同而已,一般称作对象的状态不同。比如,点(1,2),(3,5),(1 +0,50)都是Point的实例。 +\end_layout + +\begin_layout Standard +在这里有必要进一步澄清一下常见的几种说法: +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +类(class) +\end_layout + +\end_inset + +就是类型的意思,定义了一个类,就是定义了一个新的数据类型,表达某种事物的公共属性和方法,我们可以根据类创建多个实例(对象)。 +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +对象(object)即类的实例 +\end_layout + +\end_inset + +。如果把类看作数据类型,则对象可以看作变量。 +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +对象的属性 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +属性 +\end_layout + +\end_inset + +(property)即为类的“成员分量” +\end_layout + +\end_inset + +(借用struct的叫法),即类中定义的变量。 +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +对象的方法 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + +(method)即为类中定义的函数 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +函数 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + 。由于这些函数往往是操作类的属性的某种方法,因此大家习惯上称为对象的方法。 +\end_layout + +\begin_layout Standard +在java中,通过 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +new +\end_layout + +\end_inset + +new操作符创建类的实例(对象),比如new Point()创建了一个“点”的实例(对象)。和C语言中访问struct的成员变量类似,访问Java对象的属性和方 +法是通过 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +. +\end_layout + +\end_inset + +运算符实现的 +\begin_inset Foot +status open + +\begin_layout Plain Layout +和C语言不同的是,由于Java中没有提供指针,在Java中不存在->运算符。 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub321/Draw.java" +lstparams "caption={Draw.java},label={sub311-Draw.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +在程序中,我们通过new操作符创建了2个Point类的对象one和two,并设置了两个对象的状态(即x、y坐标),然后打印出两个对象的状态。 +\end_layout + +\begin_layout Example +根据已有的Point类,编写一个Rectangle和Circle类,并能够计算Rectangle和Circle的面积 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/oopbasic/src/cn +/edu/sdut/softlab/oopbasic/sub322 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +问题分析 +\end_layout + +\begin_layout Standard +矩形(Rectangle)是由一个点和长、宽决定的,圆形(Circle)是由一个点和半径决定的,因此我们可以在Point类的基础上定义Rectangle和Cir +cle类。 +\end_layout + +\begin_layout Paragraph* +设计说明 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub322-Rectangle.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub322-Circle.java" + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub322/Rectangle.java" +lstparams "caption={Rectangle.java},label={sub322-Rectangle.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub322/Circle.java" +lstparams "caption={Circle.java},label={sub322-Circle.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +主类Draw.java的设计参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub322-Draw.java" + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub322/Draw.java" +lstparams "float,caption={Draw.java},label={sub322-Draw.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +显示结果 +\end_layout + +\begin_layout Standard +执行文件Draw.java的结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +rect1's area=100 +\end_layout + +\begin_layout Plain Layout +circle1's area=314.159 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +程序说明 +\end_layout + +\begin_layout Standard +注意到我们在Rectangle中使用Point类定义一个startPoint对象的同时 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +初始化 +\end_layout + +\end_inset + +初始化了这个对象,即通过new Point()创建了一个空的Point对象。这是必要的,因为我们在Draw.java中创建一个Rectangle对象rect1后, +通过rect1.startPoint.x设置startPoint的x坐标。如果不在Rectangle中创建空的Point对象,则rect1.startPoint.x操作 +会报告著名的 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Index idx +status open + +\begin_layout Plain Layout +NPE +\end_layout + +\end_inset + +NPE +\end_layout + +\end_inset + +(NullPointException:空指针)异常: +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Exception in thread "main" java.lang.NullPointerException +\end_layout + +\begin_layout Plain Layout +at cn.edu.sdut.softlab.oopbasic.sub322.Draw.main(Draw.java:7) +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +对象的创建过程 +\begin_inset CommandInset label +LatexCommand label +name "sec:对象的创建过程" + +\end_inset + + +\end_layout + +\begin_layout Standard +当我们使用 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +new +\end_layout + +\end_inset + +new Point()创建一个Point类的对象时,Java是如何创建这个对象的呢? +\begin_inset Note Note +status open + +\begin_layout Plain Layout +画图表示类的创建过程 +\end_layout + +\end_inset + +实际上,Java创建对象的过程如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:对象的构造过程" + +\end_inset + +所示 +\begin_inset Foot +status open + +\begin_layout Plain Layout +实际上,为了理解方便,这是一个简化了的对象创建过程,对象的完整创建过程可参考JVM Specification +\begin_inset CommandInset citation +LatexCommand cite +key "jvm-se8-specification" +literal "true" + +\end_inset + +。 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/object-creation.eps + width 100col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +对象的构造过程 +\begin_inset CommandInset label +LatexCommand label +name "fig:对象的构造过程" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在这里我们暂且不讨论“递归的构造父类对象”这个话题(留待 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:再说构造方法" + +\end_inset + +再讨论),其他的几个步骤是指: +\end_layout + +\begin_layout Itemize +步骤1:分配空间。我们已经看到,相对于简单的数据类型,Java的对象往往是个复杂的数据结构,其中除了一些基本的数据类型的属性之外,还可能包含其他的对象(比如Re +ctangle中包含了Point)以及方法代码,因此创建Java对象的第一步是为这些数据和方法分配内存空间。分配内存空间后,类中的基本数据类型属性会被自动设置为 +默认值:数字类型的属性默认值为0(或者0.0),boolean类型的默认为false,字符类型的默认为''(这里是两个单引号,和C语言中的用法一样,表示空字符) +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这些需要验证或者查证: 如何通过示例验证? +\end_layout + +\end_inset + +。如果使用类作为属性,则默认为null。 +\end_layout + +\begin_layout Itemize +步骤3:初始化本类属性。如果本类的属性在定义时由初始化表达式,则使用该表达式初始化属性。比如 +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +int x = 10; +\end_layout + +\begin_layout Plain Layout + +Point startPoint = new Point(); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +步骤4:调用本类的构造方法,这是本节的重点。 +\end_layout + +\begin_layout Subsubsection* +构造方法 +\begin_inset CommandInset label +LatexCommand label +name "subsec:构造方法" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +构造方法 +\end_layout + +\end_inset + +构造方法的用途,我们在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:对象的构造过程" + +\end_inset + +中已经看到了,那么如何定义构造方法呢?简单的说, +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +构造方法就是和类同名并且没有返回值的方法 +\end_layout + +\end_inset + +。这里有两个关键点:一是构造方法的方法名必须和类名完全相同,包括大小写。二是构造方法不需要返回值,也不允许有返回值。 +\end_layout + +\begin_layout Subsubsection* +默认的构造方法 +\end_layout + +\begin_layout Standard +可是,我们在以前的类中,并没有看到构造方法,是怎么回事呢?原来,如果一个类没有定义任何的构造方法,java编译器会自动增加(插入)一个“默认的构造方法”,即不带 +任何参数的空的构造方法。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +需要验证在类继承环境下,默认构造方法是否自动调用父类的构造方法? +\end_layout + +\end_inset + +也就是说,我们new Point()创建一个对象的时候,最后一步会调用Point类的无参构造方法 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +无参构造方法 +\end_layout + +\end_inset + +。如果Point类没有提供这样的构造方法,则调用Point类的默认构造方法 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +默认构造方法 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +当然,我们也可以“主动”为Point编写一个无参的构造方法,这样new Point()的最后一步就是调用我们自己编写的构造方法而非默认构造方法了。 +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +重新起一个包,实现所有的无参构造方法。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +注意 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +无参构造方法 +\end_layout + +\end_inset + +无参构造方法和 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +默认构造方法 +\end_layout + +\end_inset + +默认构造方法的区别:默认构造方法一定是无参的构造方法,但是无参的构造方法不一定是默认构造方法。当一个类没有显式的定义任何构造方法时,编译器自动添加默认构造方法; +当一个类有任何的构造方法时,编译器都不会自动添加默认构造方法。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +编写程序,覆盖Point类的默认构造方法,为Point对象提供默认的(x,y)坐标为(10,10) +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整代码参见 +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/oopbasic/src/cn +/edu/sdut/softlab/oopbasic/sub332 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +设计说明 +\end_layout + +\begin_layout Standard +这里只列出Point.java和Draw.java两个文件,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub332-Point.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub322-Draw.java" + +\end_inset + +,Circle.java和Rectangle.java没有变化。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub332/Point.java" +lstparams "float,caption={Point.java},label={sub332-Point.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub332/Draw.java" +lstparams "float,caption={Draw.java},label={sub331-Draw.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Draw.java文件结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +rect1的左上角坐标:(10,10),width=10,height=10,面积=100 +\end_layout + +\begin_layout Plain Layout +circle1的原点坐标:(10,10),radius=10.0面积=314.159 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +程序分析 +\end_layout + +\begin_layout Standard +在本例中,Draw.java创建Circle对象circle1的时候,并没有设置原点的坐标,但是从运行结果可以看出,原点坐标的值为(10,10),这就是Point +类的无参构造方法的作用:当我们使用new Point()创建对象时,最后会调用Point的无参构造方法初始化对象的状态。 +\end_layout + +\begin_layout Subsubsection* +带参数的构造方法 +\end_layout + +\begin_layout Standard +很多时候,我们希望在创建对象的时候就设置对象的初始状态,比如是否可以通过new Point(10,20)这样的方式,创建Point对象的同时,设置Point对象 +的x坐标为10,y坐标为20呢?这可以通过带参数的构造方法来实现。也就是说,当我们通过new Point(10,20)这样的形式创建Point对象时,最后会调用 +Point类中带两个参数的构造方法。 +\end_layout + +\begin_layout Example +编写程序,使用带参数的构造方法创建Point对象 +\begin_inset CommandInset label +LatexCommand label +name "exa:编写程序,使用带参数的构造方法创建Point对象" + +\end_inset + + +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见 +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/oopbasic/src/cn +/edu/sdut/softlab/oopbasic/sub333 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +设计说明 +\end_layout + +\begin_layout Standard +主类Draw.java没有变化,这里就不列出了。其他类参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub333-Point.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub333-Circle.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub333-Rectangle.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub333/Point.java" +lstparams "float,caption={Point.java},label={sub333-Point.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub333/Circle.java" +lstparams "float,caption={Circle.java},label={sub333-Circle.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub333/Rectangle.java" +lstparams "float,caption={Rectangle.java},label={sub333-Rectangle.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Draw.java结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +rect1的左上角坐标:(20,20),width=10,height=10,面积=100 +\end_layout + +\begin_layout Plain Layout +circle1的原点坐标:(0,0),radius=10.0面积=314.159 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +当一个类中定义了任何的构造方法后,编译器就不会自动创建默认的构造方法了。比如Point类中,如果定义了Point的有参构造方法而没有定义无参构造方法,此时Poi +nt类没有默认构造方法,自然new Point()方式创建Point对象时会因为找不到无参的构造方法而报错。如何解决这个问题呢?请参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:多个构造方法" + +\end_inset + +。 +\end_layout + +\begin_layout Subsubsection* +多个构造方法 +\begin_inset CommandInset label +LatexCommand label +name "subsec:多个构造方法" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java允许在类中定义多个构造方法,以便根据不同的情况初始化对象为不同状态。 +\end_layout + +\begin_layout Example +编写程序,给Point类定义两个构造方法 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/oopbasic/src/cn +/edu/sdut/softlab/oopbasic/sub334 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +设计说明 +\end_layout + +\begin_layout Standard +主类Draw.java和Rectangle.java和例 +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:编写程序,使用带参数的构造方法创建Point对象" + +\end_inset + +相同,这里仅列出Point.java和Circle.java,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub334-Point.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub334-Circle.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub334/Point.java" +lstparams "float,caption={Point.java},label={sub334-Point.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/sub334/Circle.java" +lstparams "float,caption={Circle.java},label={sub334-Circle.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Draw.java结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +rect1的左上角坐标:(10,10),width=10,height=10,面积=100 +\end_layout + +\begin_layout Plain Layout +circle1的原点坐标:(0,0),radius=10.0面积=314.159 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +程序说明 +\end_layout + +\begin_layout Standard +Point类现在有两个构造方法,我们在Circle.java调用了Point的有参构造方法,在Rectangle.java中调用了Point的无参构造方法。 +\end_layout + +\begin_layout Subsection +再说对象的初始化 +\end_layout + +\begin_layout Standard +通过以上分析我们可以看出,构造方法的目的是为了 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +创建对象时设置对象的初始状态 +\end_layout + +\end_inset + +,因此一个类需要多少个构造方法并没有一定之规,需要根据实际情况来确定。通常,在一开始设计一个类的时候,建议覆盖默认的构造方法即无参构造方法,提供一个默认的对象状 +态。随着开发的深入,可以根据实际情况添加更多的构造方法。 +\end_layout + +\begin_layout Standard +除了通过构造方法设置对象的初始状态外,也可以通过以下的方式进行对象的初始化操作: +\end_layout + +\begin_layout Itemize +在创建对象后,直接访问对象的属性并设置希望的值。 +\end_layout + +\begin_layout Itemize +在创建对象后通过setter方法设置对象的状态。所谓setter方法,往往是一系列setX,setY方法,其中的X、Y为对象的属性。 +\end_layout + +\begin_layout Itemize +在JavaEE环境下,可以提供一个初始化方法,比如void init(),然后通过注解@PostConstruct的方式实现对象的初始化。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +定义有参构造方法时,要注意参数的个数不要太多,一般不要超过10个。太多的参数往往给使用者带来记忆和匹配的负担。如果需要大量的对象初始化操作,建议编写专门的方法初 +始化对象(比如init()方法就是一个很好的方法名字),然后在创建对象后调用这个init方法即可。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +Java的构造方法有哪些特点? +\begin_inset CommandInset label +LatexCommand label +name "exer:Java的构造方法有哪些特点?" + +\end_inset + + +\end_layout + +\begin_layout Section +类的组织:包 +\begin_inset CommandInset label +LatexCommand label +name "sec:类的组织:包" + +\end_inset + + +\end_layout + +\begin_layout Subsection +包的概念 +\end_layout + +\begin_layout Standard +在进行文件管理时,我们使用文件夹来组织不同类型的文件。在Java中,我们使用“ +\begin_inset Index idx +status open + +\begin_layout Plain Layout +包 +\end_layout + +\end_inset + +包”( +\begin_inset Index idx +status open + +\begin_layout Plain Layout +package +\end_layout + +\end_inset + +package)来管理不同类型的Java源文件,其实“包”就是文件夹,我们说包cn.edu.sdut.softlab.oopbasic.sub332中的Point.java +时,其实是说,位于目录cn/edu/sdut/softlab/oopbasic/sub332目录下的Point.java。也就是说,把目录的分隔符换成“.”,目录名 +就变成了包名。 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:本章示例代码的目录层级结构" + +\end_inset + +是本章的主要示例代码的目录层级结构: +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/package-tree.png + width 90line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +本章示例代码的目录层级结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:本章示例代码的目录层级结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +包的导入和声明 +\end_layout + +\begin_layout Standard +有了包的概念后,我们就可以使用 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +import +\end_layout + +\end_inset + +导入其他包中的Java源代码,这很像C语言中的include关键字的作用。比如下面的代码片段,我们导入了java.util包中的Date类(时间处理类): +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +import java.util.Date; +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +public class DateTest { +\end_layout + +\begin_layout Plain Layout + + public static void main(String[] args) { +\end_layout + +\begin_layout Plain Layout + + Date today = new Date(); +\end_layout + +\begin_layout Plain Layout + + System.out.println("today is " + today); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +关于包的导入(import),需要注意以下几个方面: +\end_layout + +\begin_layout Itemize +如果一个Java源代码在一个包中,则这个Java源代码应该首先使用 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +package +\end_layout + +\end_inset + +声明自己所在的包,正如本章所有的例子一样,在代码的开头几乎都一句package语句声明了包。建议回顾一下本章学过的例子,重点放在包的命名上面,了解如何在Java +源代码文件中声明包。 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +只有声明(package)了包的Java源代码,才能够被导入进来 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Itemize +如果Java源代码中没有package声明语句,则编译器认为Java文件在 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +默认包 +\end_layout + +\end_inset + +中,即src根目录下,这通常不是一个好的习惯。 +\end_layout + +\begin_layout Itemize +显然,import应该放在class的定义前面。 +\end_layout + +\begin_layout Itemize +在同一个包下的Java源代码不需要导入(import)。 +\end_layout + +\begin_layout Itemize +Java的核心API,即java.lang包的类,Java编译器会自动导入,也不需要我们手工导入。 +\end_layout + +\begin_layout Itemize +可以通过*实现批量导入,比如: +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +import com.company.lab.* +\end_layout + +\end_inset + +表示导入 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +com.company.lab +\end_layout + +\end_inset + +包中的所有类。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +在Idea IDE环境下,在使用到一个其他包的Java类时,有两种方式自动导入相应的包: +\end_layout + +\begin_layout Itemize +使用菜单:code->optimize imports,让Idea自动导入需要的包。 +\end_layout + +\begin_layout Itemize +鼠标移动到未识别的类上面,Idea会给出导入的提示,选择合适的包导入即可。注意,如果Idea给出了多个选择(意味着在多个包中都有这个类),此时要认真甄别要导入的 +包。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Warning +status open + +\begin_layout Plain Layout +根据Google编码规范(参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:不使用通配符import" + +\end_inset + +),尽量避免import package.*这样的用法。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +包的命名原则 +\end_layout + +\begin_layout Standard +我们使用包的目的是把Java文件按照逻辑组织起来 +\begin_inset Foot +status open + +\begin_layout Plain Layout +形式上看是这样,但是包的真正意义和Java虚拟机的类加载机制有关,这里不深入探讨,有兴趣的读者可以参考ClassLoader的相关资料。 +\end_layout + +\end_inset + +,同时也起到了“隔离”的作用,即不同包中的类即使名字相同也是可以的。或者说,以后我们提到一个类,应该连同它的包一起来考虑,即某某包的某某类。因此,当我们给包起名 +字的时候就要谨慎考虑,最好能够做到你起的包名是全球唯一的,这样你的包里面的类也就是全球唯一的了。而全球唯一的资源,很容易就想到了“域名”,于是通用的和建议的包命 +名规则 +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见JLS:http://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.1 +\end_layout + +\end_inset + +是按照域名的反向 +\begin_inset Foot +status open + +\begin_layout Plain Layout +为什么要将通常的域名反向排列形成包名呢?我们阅读的顺序是从左向右的,当谈到一个组织结构时,习惯上也是按照从左向右降序排列的,比如山东省淄博市张店区。因此,在命名 +包时把域名的顺序反向过来,更符合人们的阅读和理解习惯。当然,这不是Java的语法规定,只是“约定俗成”,入乡随俗也体现了一个程序员的素质。 +\end_layout + +\end_inset + +来命名,比如你的域名是lab.company.com,则包的命名可以是: +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +com.company.lab +\end_layout + +\end_inset + +。下面是一些典型的包命名示范: +\end_layout + +\begin_layout Standard +\begin_inset Box Boxed +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +com.google.android +\end_layout + +\begin_layout Plain Layout +cn.edu.sdut.java.lesson +\end_layout + +\begin_layout Plain Layout +org.apache.log4j +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +根据Google的编码规范(参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:包名" + +\end_inset + +),包的名字应该都使用小写字母,并避免使用下划线。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +类的继承 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +消除冗余,代码复用 +\end_layout + +\end_inset + + +\begin_inset CommandInset label +LatexCommand label +name "sec:类的继承" + +\end_inset + + +\end_layout + +\begin_layout Standard +在编程实践中,我们应该力求消除冗余,即不存在两片相同的代码。比如下面的代码片段: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +void method1() { +\end_layout + +\begin_layout Plain Layout + + doSomething(); +\end_layout + +\begin_layout Plain Layout + + foo(); +\end_layout + +\begin_layout Plain Layout + + bar(); +\end_layout + +\begin_layout Plain Layout + + foobar(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +void method2() { +\end_layout + +\begin_layout Plain Layout + + doSomeOtherThing(); +\end_layout + +\begin_layout Plain Layout + + foo(); +\end_layout + +\begin_layout Plain Layout + + bar(); +\end_layout + +\begin_layout Plain Layout + + foobar(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +我们应该这样消除冗余: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +void method1() { +\end_layout + +\begin_layout Plain Layout + + doSomething(); +\end_layout + +\begin_layout Plain Layout + + fun(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +void method2() { +\end_layout + +\begin_layout Plain Layout + + doSomeOtherThing(); +\end_layout + +\begin_layout Plain Layout + + fun(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +void fun() { +\end_layout + +\begin_layout Plain Layout + + foo(); +\end_layout + +\begin_layout Plain Layout + + bar(); +\end_layout + +\begin_layout Plain Layout + + foobar(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +虽然后一种方式多定义了一个方法fun(),但是好处显而易见:软件的逻辑性(可读性)和可维护性提高了。如果需要对fun()的流程做任何修改,我们现在只需要在fun +()方法中修改即可。 +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +\begin_inset Flex Tip +status collapsed + +\begin_layout Plain Layout +主流的IDE现在都支持对代码进行类似的“重构”(refactor)。比如在Idea中,可以选择一段“重复”的代码,然后通过菜单Refactor->Introdu +ce->Method...让IDE自动寻找这段重复的代码,一次性抽象出一个方法,这样就消除了代码的冗余。 +\end_layout + +\end_inset + +增加Idea使用refactor的方法 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +上面代码消除冗余是建立在方法层面上的,在类的层面上应该如何消除冗余呢?比如有如下的两个类:BankCard.java和CreditBandCard.java。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/inherit/step1/BankCard.java" +lstparams "float,caption={BankCard.java},label={step1-BankCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/inherit/step1/CreditCard.java" +lstparams "float,caption={未使用继承的CreditCard.java},label={step1-CreditBankCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +很明显,CreditBankCard具有BankCard的大部分属性和方法,从尽力消除冗余的角度看,这样的代码太“丑陋”了!java提供了“继承”机制解决了这个 +问题,先看一下代码的实现:BankCard.java的代码没有变化,这里只列出CreditCard.java的代码,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "step2-CreditBankCard.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/inherit/step2/CreditCard.java" +lstparams "float,caption={使用了继承的CreditCard.java},label={step2-CreditBankCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,CreditBankCard扩展(extends)了BankCard类:CreditCard自动具有BankCard的属性和方法,只需要在Credit +Card中定义专属的属性和方法即可。 +\end_layout + +\begin_layout Standard +这就是Java等面向对象程序设计语言的“ +\begin_inset Index idx +status open + +\begin_layout Plain Layout +继承 +\end_layout + +\end_inset + +继承”机制。简单的说, +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +继承机制消除了代码的冗余,提高了代码的复用水平 +\end_layout + +\end_inset + +。继承是面向对象程序设计的重要手段,我们将在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:单继承" + +\end_inset + +进一步分析继承在编程实践中的应用和注意事项。 +\end_layout + +\begin_layout Subsection +单继承 +\begin_inset CommandInset label +LatexCommand label +name "subsec:单继承" + +\end_inset + + +\end_layout + +\begin_layout Standard +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:BankCard的类层次结构" + +\end_inset + + +\begin_inset Foot +status open + +\begin_layout Plain Layout +这样表示类层次关系的图叫做 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +UML +\end_layout + +\end_inset + +UML的类图。UML(Universal Model Language,统一建模语言)是IT行业中通用的描述需求和系统设计的建模工具,其中常用的图形有:类图、用 +例图、顺序图、活动图等,本书中只涉及到类图,用来表达类的继承和接口的实现。类图的意义应该是一目了然的,箭头表示类继承的方向,比如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:BankCard的类层次结构" + +\end_inset + +中,CreditCard指向了BankCard即表示CreditCard是从BankCard继承下来的。绘制UML图的工具有很多,本书采用的是umbrello和 +dia,参见本书前言部分的说明。 +\end_layout + +\end_inset + +的继承关系中,我们把BankCard类称作 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Index idx +status open + +\begin_layout Plain Layout +父类 +\end_layout + +\end_inset + +父类 +\end_layout + +\end_inset + +,或者超类,把CreditCard、DebitCard类称作 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Index idx +status open + +\begin_layout Plain Layout +子类 +\end_layout + +\end_inset + +子类 +\end_layout + +\end_inset + +。CreditCard和DebitCard继承了BankCard的属性和方法,并各自扩展了相应的属性和方法(DebitCard只扩展了属性,并没有扩展方法)。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/bankcard-hirarchy.eps + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +BankCard的类层次结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:BankCard的类层次结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +Java只支持单继承,即一个类只允许有一个父类。绕过这个限制的办法是使用接口,请参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:接口" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +下面的用法是正确的: +\end_layout + +\begin_layout LyX-Code +public class CreditCard extends BandCard{...} +\end_layout + +\begin_layout LyX-Code +public class DebitCard extends BandCard{...} +\end_layout + +\begin_layout Standard +下面的用法是错误的: +\end_layout + +\begin_layout LyX-Code +public class CreditCard extend BandCard{...} +\end_layout + +\begin_layout LyX-Code +public class CreditCard extends BandCard, Card{...} +\end_layout + +\begin_layout Standard +在Java中, +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Object +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Object +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +类是所有类的基类(父类),即在Java的类树结构中, +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Object +\end_layout + +\end_inset + +是“根”。因此,Java中的所有类都继承了 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Object +\end_layout + +\end_inset + +类中定义的属性和方法,具体请参见JDK API中关于 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Object +\end_layout + +\end_inset + +类的介绍。特别的, +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Object +\end_layout + +\end_inset + +类的以下方法在(初级)编程实践中经常用到: +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +toString +\end_layout + +\end_inset + +方法 +\end_layout + +\end_inset + + 输出当前对象的字符串表达,一般用于调式输出。实际上,当直接输出一个对象时,即调用了该对象的 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +toString +\end_layout + +\end_inset + +方法,也就是说, +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +System.out.println(aObject +\end_layout + +\end_inset + +)和 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +System.out.println(aObject.toString()) +\end_layout + +\end_inset + +的结果是一样的。通常情况下,子类需要覆盖 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Object +\end_layout + +\end_inset + +类的 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +toString +\end_layout + +\end_inset + +方法,以便更好的描述类的内部结构。 +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +equals +\end_layout + +\end_inset + +方法 +\end_layout + +\end_inset + + 比较两个对象是否相等。不像简单数据类型的比较,对象的比较复杂,这里不展开阐述,详情可参见以下资料:https://dzone.com/articles/obje +ct-identity-and-equality-in-java,或者:https://stackoverflow.com/questions/13387742/ +compare-two-objects-with-equals-and-operator。 +\end_layout + +\begin_layout Subsection +再说构造方法 +\begin_inset CommandInset label +LatexCommand label +name "subsec:再说构造方法" + +\end_inset + + +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:对象的创建过程" + +\end_inset + +中,我们已经看到创建对象的第二步是递归的构造父类对象。我们仍然以银行卡为例来看一下所谓的“递归的构造父类对象”的含义。为了清楚期间,我们增加了一个类的层级结构, +如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:银行卡的类层级结构" + +\end_inset + +所示。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +银行卡的程序示例代码较多,作为一个例子处理如何? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/bankcard-full-hirarchy.eps + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +银行卡的类层级结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:银行卡的类层级结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +从 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "step3-Card.java" + +\end_inset + +可以看出,Card类只定义了所有卡都有的基本属性:卡号。另外,显式定义了无参的构造方法,如果被调用的话,只是打印出一条提示信息。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/inherit/step3/Card.java" +lstparams "float,caption={增加无参构造方法的Card.java},label={step3-Card.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +BankCard、CreditCard、DebitCard的设计思路类似,都是增加了一个无参的构造方法,打印出一条提示信息,如果被调用到的话。在Client类中 +,我们分别创建了CreditCard和DebitCard对象,注意观察构造方法的调用顺序。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/inherit/step3/BankCard.java" +lstparams "float,caption={带有无参构造方法的BankCard.java},label={step3-BankCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/inherit/step3/CreditCard.java" +lstparams "float,caption={带有无参构造方法的CreditCard.java},label={step3-CreditCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/inherit/step3/DebitCard.java" +lstparams "float,caption={带有无参构造方法的DebitCard.java},label={step3-DebitCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/inherit/step3/Client.java" +lstparams "float,caption={Client.java},label={step3-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +执行Client.java的结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Card constructor called +\end_layout + +\begin_layout Plain Layout +BankCard constructor called +\end_layout + +\begin_layout Plain Layout +CreditCard constructor called +\end_layout + +\begin_layout Plain Layout +Card constructor called +\end_layout + +\begin_layout Plain Layout +BankCard constructor called +\end_layout + +\begin_layout Plain Layout +DebitCard constuctor called +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,所谓的“递归的构造父类对象”是指: +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +当初始化子类对象时,从上往下依次调用父类的同名构造方法 +\end_layout + +\end_inset + +,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:构造方法的递归调用" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/object/constructor-chain.eps + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +构造方法的递归调用 +\begin_inset CommandInset label +LatexCommand label +name "fig:构造方法的递归调用" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +在递归构造父类对象的“链条”中,如果其中一环缺失会怎样?请读者自行练习找到此问题的答案:将导致语法错误。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这里应该有习题 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +方法的覆盖和重载 +\end_layout + +\begin_layout Standard +方法的覆盖(override)和重载(overload)是面向对象编程中两个重要且容易混淆的概念,因此这里单独拿出来讨论一下。 +\end_layout + +\begin_layout Subsubsection* +方法重载 +\end_layout + +\begin_layout Standard +Java中的方法重载(overload)是指在一个类中允许存在 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +多个名字相同但是参数不同的方法 +\end_layout + +\end_inset + +。这里所谓的“参数不同”有如下的几种情形: +\end_layout + +\begin_layout Itemize +参数个数不同 +\end_layout + +\begin_layout Itemize +参数类型不同 +\end_layout + +\begin_layout Itemize +参数个数和类型都不相同 +\end_layout + +\begin_layout Standard +如果我们把方法的参数看做一个控制系统的“输入条件”,那么方法的重载意味着同一个动作在不同的输入条件下的表现如何? +\end_layout + +\begin_layout Example +使用方法重载设计一个计算器类。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "Caculator.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/Caculator.java" +lstparams "caption={Caculator.java},label={Caculator.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java中典型的方法重载场合: +\end_layout + +\begin_layout Itemize +构造方法的重载:我们在 +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:多个构造方法" + +\end_inset + +中看到,可以编写类的多个构造方法,实际上就是方法的重载的具体体现。构造方法的名字都是相同的(和类名一致),不同的构造方法(参数不同)表示在不同的条件下如何创建对 +象。 +\end_layout + +\begin_layout Itemize +运算符重载:Java的“+”运算符是被重载了的。我们前面已经看到,“+”运算符在不同的表达式中意义不同,用于算数表达式时表示数学运算的加法,用于两个字符串时表示 +首尾相接连接两个字符串。 +\end_layout + +\begin_layout Itemize +String.valueOf方法可以接收的参数有boolean, char, char[], double, float, int, long等 +\begin_inset Foot +status open + +\begin_layout Plain Layout +我们将在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:字符串处理" + +\end_inset + +详细讨论String类的用法,String.value方法的形式可参考JDK API,这里暂不详细讨论。 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +需要注意的是,只是参数的顺序不同以及参数的名字不同不能构成方法的重载,原因很简单,我们调用方法的时候进行形参和实参的匹配,顺序和名字并不能唯一决定形参和实参的组 +合。比如方法method(String a, String b) 和method (String c, String d)不能构成方法的重载,在Java编译器看 +来,这是两个相同的方法,因而会报告编译错误。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +TODO:需要实例验证 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +\begin_inset Wrap figure +lines 0 +placement r +overhang 0in +width "30line%" +status collapsed + +\begin_layout Plain Layout +\noindent +\align center +\begin_inset Graphics + filename ../imgs/object/socket-plug.eps + lyxscale 25 + width 100line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +生活中的各种插座和多用插座示例 +\begin_inset CommandInset label +LatexCommand label +name "fig:生活中的各种插座和多用插座" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +举个生活中的例子可能更容易理解方法重载的概念和用途,比如我们知道插座有各种规格以便适用不同的电器,有的电器使用两孔插头,有的电器使用三孔插头,插头还可能分为圆形 +插头和扁平插头等等。正如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:生活中的各种插座和多用插座" + +\end_inset + +所示,生活中我们经常安装一种所谓的“多用插座”,即一个插座可以使用多种不同的插头,这样就免去安装很多个不同的插座的麻烦,也不需要大家记住插头和插座的对应关系,直 +接拿来用就可以了。这种“多用插座”的设计移植到程序设计上,就叫做“方法重载”(overload),即方法的名字相同(多用插座),但是参数各不相同(适用不同的插头 +),在具体使用时,程序员只需要记住少量的方法的名字,参数类型和个数由IDE自动提示即可。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection* +方法覆盖 +\end_layout + +\begin_layout Standard +方法覆盖(override)是指子类中重新实现了父类中的同名方法,即子类方法覆盖了父类方法。这样,当调用子类对象的这个方法时,就是使用子类重新实现的方法了。否则 +,就会调用父类中的方法。因此,方法覆盖的主要用意是 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +在子类中提供父类方法的加强版,或者使用不同的逻辑重新实现 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Example +方法覆盖示例。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "Dog.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/Dog.java" +lstparams "caption={Dog.java},label={Dog.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +方法覆盖是Java多态的基础,具体请参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:多态" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +注意到从JDK 1.5开始,Java允许子类覆盖父类方法时,返回值可以是父类方法返回值的子类。比如: +\end_layout + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +class A{ +\end_layout + +\begin_layout Plain Layout + + Father get(){ return null;} +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +public class B extends A{ +\end_layout + +\begin_layout Plain Layout + + @Override +\end_layout + +\begin_layout Plain Layout + + Son get(){ return null;} +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +class Father{} +\end_layout + +\begin_layout Plain Layout + +class Son extends Father{} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +在类B中,方法get返回值类型是Son,而其父类A的get方法的返回值类型是Father,由于Son是Father的子类,因此类B的方法get也属于方法的覆盖( +override)。 +\end_layout + +\begin_layout Plain Layout +Java是如何做到这一点的呢?我们反编译B.class会发现: +\end_layout + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +// Decompiled by Jad v1.5.8e. + Copyright 2001 Pavel Kouznetsov. + +\end_layout + +\begin_layout Plain Layout + +// Jad home page: http://www.geocities.com/kpdus/jad.html +\end_layout + +\begin_layout Plain Layout + +// Decompiler options: packimports(3) +\end_layout + +\begin_layout Plain Layout + +// Source File Name: B.java +\end_layout + +\begin_layout Plain Layout + +public class B extends A{ +\end_layout + +\begin_layout Plain Layout + + public B() { +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + Son get(){ +\end_layout + +\begin_layout Plain Layout + + return null; +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + volatile Father get(){ // 桥接方法 +\end_layout + +\begin_layout Plain Layout + + return get(); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +可以看出,编译器自动增加了一个所谓的“桥接方法”实现了标准的方法覆盖。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +在覆盖父类方法时,可以通过super关键字引用父类的同名方法。 +\end_layout + +\begin_layout Plain Layout +构造方法中的覆盖问题 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +访问控制 +\begin_inset CommandInset label +LatexCommand label +name "sec:访问控制" + +\end_inset + + +\end_layout + +\begin_layout Standard +当我们说到面向对象程序设计的封装时,不仅仅是指把对象的属性和方法“捏合”在了一起,也指从使用者的角度看,访问对象是受到限制的,即对象内部的状态和方法并不总是需要 +暴露给使用者的。推而广之,甚至对类的访问也可以加以限制。 +\end_layout + +\begin_layout Subsection +属性和方法的访问控制 +\end_layout + +\begin_layout Standard +为什么需要对属性和方法进行访问控制呢?从面向对象的设计角度看,一个对象完成了特定的功能,对象的使用者其实并不关心这个特定功能是如何实现的,只要这个功能能够正常工 +作就可以了,这就是所谓的“ +\begin_inset Index idx +status open + +\begin_layout Plain Layout +松耦合 +\end_layout + +\end_inset + +松耦合”(loose coupling principle)原则。考虑 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:松耦合原则" + +\end_inset + +所示的情形。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/loose-coupling-model.png + width 60col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +松耦合原则示意图 +\begin_inset CommandInset label +LatexCommand label +name "fig:松耦合原则" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +当Client使用Bean组件(对象)提供的功能时,并不需要知晓Bean组件内部是如何实现的,也就是时说,Bean组件在后续进行算法完善、性能改进或者界面优化...时 +,Client的代码不需要做任何改动。Bean组件只需要对外(Client)暴露必须的调用接口(如何暴露,我们会在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:接口" + +\end_inset + +讨论),其内部实现及只在内部实现中用到的一些对象状态,应该想办法隐藏起来。换句话说,Bean组件如果对外暴露的调用接口越多,则后续改进时要考虑的因素就越多,困难 +也越大。 +\end_layout + +\begin_layout Standard +Java提供了完善的访问控制策略来保护属性和方法,如表所示 +\begin_inset Foot +status open + +\begin_layout Plain Layout +也参见:http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html +\end_layout + +\end_inset + +(形成了一个三角形排列)。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java的访问控制修饰符 +\begin_inset CommandInset label +LatexCommand label +name "tab:Java的访问控制修饰符" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +修饰词 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Class(类) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Package(包) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Subclass(子类) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +World(其他) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +protected +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +X +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +(default) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +X +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +X +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +private +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +√ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +X +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +X +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +X +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +default修饰符 +\begin_inset CommandInset label +LatexCommand label +name "subsec:default修饰符" + +\end_inset + + +\end_layout + +\begin_layout Standard +在之前我们的代码中,属性和方法前面没有使用任何修饰符,即默认修饰符 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +默认修饰符 +\end_layout + +\end_inset + +。对照 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Java的访问控制修饰符" + +\end_inset + +可以看出,default修饰的(即不使用任何修饰符)的属性和方法对同一个包内的其他类是可见的:即可以读,也可以修改。因此,default修饰符也被称为“ +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +包范围 +\end_layout + +\end_inset + +”的修饰符,它以包为限界定了访问权限,这是一种很自然的权限划分,因此被Java确定为“default”(默认)情形。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Warning +status open + +\begin_layout Plain Layout +default的意思是默认修饰符,即没有在属性和方法前面指定修饰符的情形,并非要显式的指定一个“default”的修饰符。实际上,java中不存在一个名字叫做“ +default”的修饰符。因此,下文中的default均指: +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +在属性、方法、类前面不使用任何访问控制修饰符 +\end_layout + +\end_inset + +。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "ac-BankCard.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "ac-Client.java" + +\end_inset + +中,BankCard类中的username和password属性以及withdraw方法都是default的,因此同一个包中的Client类可以随意修改密码,随 +意取钱: +\begin_inset Flex Emph +status open + +\begin_layout Plain Layout +这太不安全了! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/ac/BankCard.java" +lstparams "float,caption={演示default修饰符的BankCard.java},label={ac-BankCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/ac/Client.java" +lstparams "float,caption={Client.java},label={ac-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +执行结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +BankCard constructor called +\end_layout + +\begin_layout Plain Layout +钱被取走啦! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Warning +status open + +\begin_layout Plain Layout +default修饰符意味着同一个包内的其他类都可以随意操纵你的属性和方法,这是一个危险的设置!设想一下,黑客把一个自己写的破坏性Java文件放到你的包里面,然后 +修改你的银行卡密码,盗取你的钱财...因此,default修饰符给软件的安全留了一个后门,并不是一个好的“默认值”! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +private修饰符 +\end_layout + +\begin_layout Standard +default给了同一个包下的其他类“篡改”本类的机会, +\begin_inset Index idx +status open + +\begin_layout Plain Layout +private +\end_layout + +\end_inset + +private修饰符则完全杜绝了这个问题:从 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Java的访问控制修饰符" + +\end_inset + +可以看出,private修饰过的属性和方法只有本类可以访问,即只有本类可以读取和修改,对同一个包下的其他类、子类以及所有其他的类都不可见。正如private的名 +字所宣示的, 这是一个完全隐私的保护性设置,特别适合于本节开头所述的“松耦合原则”中组件(对象)内部属性、方法的表达。实际上, +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +在绝大多数情况下,我们应该将类的属性和方法设置为private +\end_layout + +\end_inset + +,然后根据需要或者设计要求逐步放开限制,以达到对组件(对象)最大程度的封装和保护。 +\end_layout + +\begin_layout Standard +有时我们希望对外一定程度上暴露私有的属性,即不直接暴露私有(private)属性,而是通过一个公有(public)的方法间接的访问私有属性。这样如果需要的话,我 +们可以在这个方法中对属性修改做合法性检查,避免任意的篡改私有属性。这些能够读取和设置私有属性的方法往往以get和set开头,一般称作 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +getter/setter方法 +\end_layout + +\end_inset + +,比如下面的代码片段: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class Person { +\end_layout + +\begin_layout Plain Layout + + private String username; +\end_layout + +\begin_layout Plain Layout + + private String password; +\end_layout + +\begin_layout Plain Layout + + private String email; +\end_layout + +\begin_layout Plain Layout + + +\end_layout + +\begin_layout Plain Layout + + public void setUsername(String newUsername) { +\end_layout + +\begin_layout Plain Layout + + username = newUsername; +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + +\end_layout + +\begin_layout Plain Layout + + public String getUsername() { +\end_layout + +\begin_layout Plain Layout + + return username; +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + +\end_layout + +\begin_layout Plain Layout + + // setPassword/getPassword等方法和getUsername/setUsername类似 +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +大多数IDE开发环境可以帮助我们自动生成这些getter/setter方法:在类中右键选择“Insert Code... +\begin_inset Quotes erd +\end_inset + +,然后选择“Getter and Setter...”,选中希望自动生成getter/setter方法的私有属性,可以多选,然后点击“Generate”按钮即可。自动 +产生的getter/setter代码中使用了this关键字,我们将在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:对象的存储模型" + +\end_inset + +讨论它。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +改造 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:default修饰符" + +\end_inset + +中的例子,使得BankCard类中的username和password都是private的。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "acPrivate-BankCard.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "acPrivate-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/acprivate/BankCard.java" +lstparams "float,caption={演示private修饰符的BankCard.java},label={acPrivate-BankCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/acprivate/Client.java" +lstparams "float,caption={Client.java},label={acPrivate-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +可以看出,我们在Client中无法直接修改密码了,否则会报告语法错误。 +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +BankCard类的两个属性使用private修饰符后,Client类无法直接访问这两个属性了。可以通过提供getter/setter方法,方便Client访问 +BankCard的这两个属性。请读者试着在BankCard中加上getter/setter方法,并在Client中调用getter/setter修改用户名和密码 +。 +\end_layout + +\begin_layout Problem +构造方法是私有的会怎样?为什么? +\end_layout + +\begin_layout Problem +我们在Client类中使用new BankCard()创建对象时会试图调用BankCard的构造方法,但是此时BankCard的构造方法是私有的,意味着对同一个 +包下面的Client不可见!因此,如果使用private修饰构造方法,意味着你不希望别人直接通过new操作符创建对象。那么这个类还有啥用处呢?实际上,在这种情况 +下,可以通过提供一个方法来创建对象,比如下面的代码片段: +\end_layout + +\begin_layout Problem +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class BankCard { +\end_layout + +\begin_layout Plain Layout + + .... +\end_layout + +\begin_layout Plain Layout + + private BankCard () {} +\end_layout + +\begin_layout Plain Layout + + +\end_layout + +\begin_layout Plain Layout + + public static BankCard getInstance() { +\end_layout + +\begin_layout Plain Layout + + new BankCard(); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Problem +在本类中new BankCard()当然是没有问题的了,所以通过一个公有的方法getInstance()来创建对象,则Client就可以这样使用: +\end_layout + +\begin_layout Problem +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class Client { +\end_layout + +\begin_layout Plain Layout + + .... +\end_layout + +\begin_layout Plain Layout + + BankCard card = BankCard.getInstance(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Problem +此种用法常见于工厂模式 +\begin_inset CommandInset citation +LatexCommand cite +key "design-pattern-4gangs" +literal "true" + +\end_inset + +、单例模式 +\begin_inset CommandInset citation +LatexCommand cite +key "design-pattern-4gangs" +literal "true" + +\end_inset + +等。 +\end_layout + +\begin_layout Subsubsection +protected修饰符 +\end_layout + +\begin_layout Standard +private修饰过的属性和方法只有本类可以访问,default修饰过的属性和方法本类和本包其他类可以访问, +\begin_inset Index idx +status open + +\begin_layout Plain Layout +protected +\end_layout + +\end_inset + +protected修饰过的属性和方法则进一步放宽了限制:除了本类、本包之外,子类也可以访问。或者说,我们使用protected修饰属性和方法的唯一目的就是: +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +子类可见 +\end_layout + +\end_inset + +,这也是protected这个修饰符的本意:受保护的本意大概就是家族内无本质纷争的意思,所谓“兄弟阋于墙,外御其辱”,可以理解为一家人不见外,不是一家人就对不起 +了,不可见。因此,protected修饰的属性和方法本人可见(这个很自然),同包内的其他类(同胞)可见,子类(对自己的下一代不隐瞒,即使下一代不在同一个包内)可 +见,其他外族(其他包中的类)则不可见。当然, +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:public修饰符" + +\end_inset + +的 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +public +\end_layout + +\end_inset + +public修饰过的属性和方法在子类也是可见的,但是 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +public +\end_layout + +\end_inset + +public往往太宽泛,实际应用的时候应该严格限制。 +\end_layout + +\begin_layout Example +使用protected改造银行卡的例子,观察protected是如何保护属性和方法的 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整代码参见 +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/oopbasic/src/cn +/edu/sdut/softlab/oopbasic/acprotected/other +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "acprotected-BankCard.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "acprotected-CreditCard.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/acprotected/BankCard.java" +lstparams "float,caption={演示protected修饰符的BankCard.java},label={acprotected-BankCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/acprotected/other/CreditCard.java" +lstparams "float,caption={演示protected修饰符的CreditCard.java},label={acprotected-CreditCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/acprotected/other/Test.java" +lstparams "float,caption={Test.java},label={acprotected-Test.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Client.java得到如下结果: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +BankCard constructor called +\end_layout + +\begin_layout Plain Layout +钱被取走啦! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +在BankCard中,我们将两个属性和两个方法均使用protected修饰,因此其子类CreditCard能够直接访问这两个属性和方法。注意到CreditCar +d和BankCard不在一个包内,这并不影响CreditCard访问父类BankCard中protected修饰过的属性和方法,也就是说,Java首先根据“父子 +”关系检查访问权限,然后再根据包内还是包外检查访问权限。 +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "acprotected-Test.java" + +\end_inset + +中创建了一个BankCard对象,但是由于Test类和BankCard不在同一包内,也不是BankCard的子类,因此Test中创建的BankCard对象无法直 +接访问protected修饰过的属性和方法。 +\end_layout + +\begin_layout Subsubsection +public修饰符 +\begin_inset CommandInset label +LatexCommand label +name "subsec:public修饰符" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +public +\end_layout + +\end_inset + +public修饰符当然就是无限制的意思了,在属性和方法的访问控制中,public修饰符应该谨慎使用,只有确定需要公开的情形才使用public修饰属性和方法,否则 +和C语言有啥区别呢?请记住,public意味着公开的承诺,一旦你使用了public修饰属性和方法,就意味着你失去了后续修改这部分代码的机会。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +虽然在属性和方法上要谨慎使用pubic修饰符,但是构造方法往往是public的,这是因为绝大多数情况下,我们编写了一个类是希望任何人都能够创建相应的对象的。试想 +,如果构造方法是protected、default甚至是private的,会怎样?这里列出四种修饰符修饰构造方法的情形: +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +public的构造方法 +\end_layout + +\end_inset + +:任何人都可以通过new创建对象 +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +protected的构造方法 +\end_layout + +\end_inset + +:只有本类、子类和同一个包内的类可以通过new创建对象 +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +default的构造方法 +\end_layout + +\end_inset + +:只有本类、同一个包内的类可以通过new创建对象 +\end_layout + +\begin_layout Itemize +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +private的构造方法 +\end_layout + +\end_inset + +:只有本类可以通过new创建对象 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +属性和方法的访问控制小结 +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:访问控制保护范围示意" + +\end_inset + +可以帮助我们理解public/protected/private修饰符的保护范围。一般的,可以根据 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "tab:Java的访问控制修饰符" + +\end_inset + +按照从左向右的顺序推断修饰符在当前语境中的保护作用。比如,如果父类中的属性是default的,并且子类和父类不在同一个包中,则子类是无法访问父类中该属性的。但是 +如果子类和父类在同一个包中,则子类可以访问父类中这个default修饰的属性—此时default修饰符允许同一包中的类访问这个条件起了作用。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/access-control-overview.eps + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +访问控制保护范围示意 +\begin_inset CommandInset label +LatexCommand label +name "fig:访问控制保护范围示意" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在编程实践中,我们往往根据以下的原则来确定使用什么修饰符控制属性和方法的访问权限: +\end_layout + +\begin_layout Itemize +首先考虑使用最严格的访问控制策略,即优先考虑使用private修饰属性和方法,除非你有足够的理由,比如希望子类可见,则选择使用protected修饰符。 +\end_layout + +\begin_layout Itemize +尽量避免default修饰符,即不使用任何修饰符,这是一个危险和不好的编程习惯。 +\end_layout + +\begin_layout Itemize +尽量避免public修饰符,这比default更危险!有两个例外:一是构造方法一般是public的,理由在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:public修饰符" + +\end_inset + +已经讲过了。二是常量一般也是public的。 +\end_layout + +\begin_layout Subsection +类的访问控制 +\begin_inset CommandInset label +LatexCommand label +name "subsec:类的访问控制" + +\end_inset + + +\end_layout + +\begin_layout Standard +属性和方法的访问控制有4个级别,类的访问控制则简单的多,只有两个级别: +\end_layout + +\begin_layout Enumerate +\begin_inset Index idx +status open + +\begin_layout Plain Layout +public +\end_layout + +\end_inset + +public:public修饰的类,在任何包中都可见。 +\end_layout + +\begin_layout Enumerate +\begin_inset Index idx +status open + +\begin_layout Plain Layout +default +\end_layout + +\end_inset + +default:default修饰(即没有任何修饰符)的类,只在本包中可见。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +在一个Java源文件中,只有一个类可以是public的,而且这个public的类的类名和文件名要严格一致。在这个Java源文件中,除了这个public的类之外, +依然可以定义其他的default修饰(即没有使用任何修饰符)的类。但是一般情况下不建议这样做,应该每个类建立单独的Java源文件。原因是我们一般是通过浏览这个包 +(目录)了解这个包中包含了哪些类,如果在一个源文件中包含了多个类,一方面我们无法从文件的目录了解包的内容,另一方面,这些隐藏在其他类文件中的类就只能限于包内访问 +了。一个例外是内部类,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:内部类" + +\end_inset + +。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +内部类 +\begin_inset CommandInset label +LatexCommand label +name "subsec:内部类" + +\end_inset + + +\end_layout + +\begin_layout Standard +有的时候,我们为了防止命名冲突,或者为了安全起见,定义一个类只希望局限在某个类内使用,这样的类就是 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +内部类 +\end_layout + +\end_inset + +内部类(Inner Class): +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +定义在一个类内部的类 +\end_layout + +\end_inset + +,比如: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +class OuterClass { +\end_layout + +\begin_layout Plain Layout + + ... +\end_layout + +\begin_layout Plain Layout + + class InnerClass() { +\end_layout + +\begin_layout Plain Layout + + ... +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + +可以把内部类理解为在类内部定义的第三种资源,其他两种是属性和方法,因此类比属性和方法的用法,我们可以这样使用内部类: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +OuterClass.InnerClass innerObject = outerObject.new InnerClass(); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:内部类的创建过程" + +\end_inset + +形象的表示了内部类的创建过程。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/new-innerclass.png + width 60col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +内部类的创建过程 +\begin_inset CommandInset label +LatexCommand label +name "fig:内部类的创建过程" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +编写NotePad类,使用内部类Editor实现编辑功能 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/oopbasic/src/cn +/edu/sdut/softlab/oopbasic/ac/innerclass +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "NotePad.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "innerclass-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/ac/innerclass/NotePad.java" +lstparams "float,caption={NotePad.java},label={NotePad.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/ac/innerclass/Client.java" +lstparams "float,caption={Client.java},label={innerclass-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +parsing:test string +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +通过这个例子我们要注意到两点: +\end_layout + +\begin_layout Itemize +如何创建一个内部类对象:首先要创建一个外部类对象,然后才能创建一个内部类对象。 +\end_layout + +\begin_layout Itemize +内部类对象可以访问外部包围类(即内部类是在这个外部包围类中定义的)的属性和方法,即使这个外部类的属性和方法是private的(请读者试着把content属性设置 +为private看看会怎样?试着把parseContent方法设置为private看看会怎样?)。这个很容易理解:内部类和外部类的属性和方法是平等的, +\begin_inset Flex Emph +status open + +\begin_layout Plain Layout +就像是本类的方法可以无限制访问本类的属性一样 +\end_layout + +\end_inset + +,本类的内部类当然可以无限制访问本类的属性和方法。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status collapsed + +\begin_layout Plain Layout +也许你会说,NotePad这个例子中,使用内部类Editor实现parseContent这个功能太矫情,根本没有必要!是的,在这种简单的情况下确实没有必要绕道使 +用内部类。但是设想NotePad不仅仅需要提供文本编辑,还需要文本搜索、格式转换等等其他功能,而且每类功能不止包含一个方法,那么为了逻辑上清晰起见,使用内部类将 +文本编辑相关的方法组织为内部类NotePad.Editor,将文本搜索相关的方法组织为内部类NotePad.Search,将格式转换相关的方法组织为内部类NoteP +ad.Transfer就容易理解了。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +引用类型 +\begin_inset CommandInset label +LatexCommand label +name "sec:引用类型" + +\end_inset + + +\end_layout + +\begin_layout Standard +很多人会说,Java语言比C语言更“进步”或者“安全”的一个原因是Java没有指针数据类型,其实这是不确切的。Java的确没有像C语言那样提供“指针 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +指针 +\end_layout + +\end_inset + +”这种基本数据类型,但是Java确实使用了指针,而且指针的正确使用同样很重要。Java中的指针叫做“ +\begin_inset Index idx +status open + +\begin_layout Plain Layout +引用 +\end_layout + +\end_inset + +引用”。 +\end_layout + +\begin_layout Standard +和C语言一样,我们可以从变量在内存中的存储来理解Java的引用(指针)。Java的基本数据类型所形成的变量不是引用,变量的名字直接代表了变量所在存储单元的内容, +这和C语言中的非指针变量是一样的。除此之外,Java中的数组、对象、Enum等的名字,都是引用(指针),如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java中的引用" + +\end_inset + +所示。 +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/reference-object.png + width 30line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java中的引用 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java中的引用" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +比如下面的代码: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +Person person = new Person(); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +之前我们把person叫做“Person”类型的对象,其实这是不严谨的,应该叫做“Peron”类型对象的名字。也就是说,person仅仅是一个对象的名字,这个名 +字其实是指向person对象的一个引用(指针)。因此下面的代码: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +Person person; +\end_layout + +\begin_layout Plain Layout + +person.goHome(); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +就会报“NullPointException +\begin_inset Quotes erd +\end_inset + +错误,即“空指针异常”。这里只是声明了一个person类型的引用,但是并没有初始化,也就是说,person并没有指向任何实质的Person类型的对象。因此在初始 +化之前,任何对象的引用都是null,这和C语言的指针含义完全一样:在C语言中,任何指针在初始化之前都是null指针,直接使用null指针是有风险的。而在Java +中,Java虚拟机会自动侦测空指针,任何对空指针 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +空指针 +\end_layout + +\end_inset + +(未初始化的对象引用)都会报告NullPointException异常。NullPointException异常如此常见,通常大家都把NullPoinitExc +eption异常简称为“ +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +NPE +\begin_inset Index idx +status open + +\begin_layout Plain Layout +NPE +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +”。 +\end_layout + +\begin_layout Standard +在C语言中,指针作为函数的参数是一个强大的特性,即可以帮助把大量的数据传入函数(输入参数),也可以帮助函数返回大量的数据(输出参数)。在Java中,我们也要区分 +方法的参数为简单数据类型和对象(引用)两种情况。 +\end_layout + +\begin_layout Example +使用对象作为方法的参数 +\begin_inset CommandInset label +LatexCommand label +name "exa:使用对象作为方法的参数。" + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +我们首先定义一个简单的Person类,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "objref-Person.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/objref/Person.java" +lstparams "float,caption={Person.java},label={objref-Person.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +测试类Client.java的代码参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "objref-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/objref/Client.java" +lstparams "float,caption={Client.java},label={objref-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +Client的运行结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\align left +Person[username=zhangsan,password=123456,seniority = 20,salary = 5000.0] +\end_layout + +\begin_layout Plain Layout +\align left +Person[username=zhangsan,password=123456,seniority = 20,salary = 6000.0] +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +可以看出,adjustSalary方法中改变了person对象的属性slary的值, +\begin_inset Flex Emph +status open + +\begin_layout Plain Layout +这和C语言中使用指针作为函数参数的作用如出一辙 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Example +两个引用指向同一个对象 +\begin_inset CommandInset label +LatexCommand label +name "exa:两个引用指向同一个对象。" + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +我们借用 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:使用对象作为方法的参数。" + +\end_inset + +中定义的Person类设计一个测试类,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "Client1.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/objref/Client1.java" +lstparams "caption={Client1.java},label={Client1.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Client1的结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +zhangsan1 == zhangsan2 ? false +\end_layout + +\begin_layout Plain Layout +zhangsan3 == zhangsan1 ? true +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:两个引用指向同一个对象。" + +\end_inset + +中,看起来zhangsan1和zhangsan2两个对象是一样的,有相同的名字和密码设置。但是,这是两个不同的对象,即不同的引用,在内存中有不同的地址。而zha +ngsan3指向了zhangsan1,即zhangsan3和zhangsan1指向了同一个对象,因此zhangsan1和zhangsan3是相等的,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:对象的引用示意图" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/object-ref-model.eps + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +对象的引用示意图 +\begin_inset CommandInset label +LatexCommand label +name "fig:对象的引用示意图" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Subsection* +this +\begin_inset Note Note +status open + +\begin_layout Plain Layout +满足李震梅老师的要求 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Java使用 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +this +\end_layout + +\end_inset + +this关键字表示“对象本身”,即 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +指向当前对象的引用 +\end_layout + +\end_inset + +。比如在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "objref-Person.java" + +\end_inset + +中,构造方法是这样写的: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + public Person(String username, String password) { +\end_layout + +\begin_layout Plain Layout + + this.username = username; +\end_layout + +\begin_layout Plain Layout + + this.password = password; +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +其中,this.username即指当前对象的username属性,这样就把作为参数的username和作为对象属性的username区分开来了。 +\end_layout + +\begin_layout Subsection* +super +\begin_inset Note Note +status open + +\begin_layout Plain Layout +满足李震梅老师的要求 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +我们在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:对象的创建过程" + +\end_inset + +中已经看到,对象在创建时会“递归的构造父类对象”,也就是说,递归的调用父类的构造方法,这并不需要我们在子类的构造方法中做什么。但是,有时候我们希望能够控制对象的 +构造过程,也就是说,打破java默认的对象构造过程,在构造对象的链条中加入自定义的成分,这个时候我们可以使用 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +super +\end_layout + +\end_inset + +super关键字:指向父类对象的引用。我们通过一个例子来说明 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +super +\end_layout + +\end_inset + +super在对象的构造过程中是如何起作用的。 +\end_layout + +\begin_layout Example +使用super自定义对象的构造过程 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/oopbasic/src/cn +/edu/sdut/softlab/oopbasic/inherit/step4 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +限于篇幅,这里只列出了CreditCard.java的完整代码,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "inherit-step4-CreditCard.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/inherit/step4/CreditCard.java" +lstparams "float,caption={CreditCard.java},label={inherit-step4-CreditCard.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果和分析 +\end_layout + +\begin_layout Standard +我们可以分三种情况运行此例,分别在CreditCard类的构造方法CreditCard(String cardNo)中: +\end_layout + +\begin_layout Enumerate +调用super()时,输出如下: +\begin_inset Newline newline +\end_inset + + +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "90col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Card constructor called +\end_layout + +\begin_layout Plain Layout +BankCard constructor called +\end_layout + +\begin_layout Plain Layout +CreditCard constructor called,cardNo=123 +\end_layout + +\begin_layout Plain Layout +============================== +\end_layout + +\begin_layout Plain Layout +Card constructor called,cardNo=456 +\end_layout + +\begin_layout Plain Layout +BankCard constructor called,cardNo=456 +\end_layout + +\begin_layout Plain Layout +DebitCard constuctor called,cardNo=456 +\end_layout + +\end_inset + + +\begin_inset Newline newline +\end_inset + +可以看出,调用super()会触发“递归的构造父类对象”。 +\end_layout + +\begin_layout Enumerate +调用super(cardNo)时,输出如下: +\begin_inset Newline newline +\end_inset + + +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "90col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Card constructor called,cardNo=123 +\end_layout + +\begin_layout Plain Layout +BankCard constructor called,cardNo=123 +\end_layout + +\begin_layout Plain Layout +CreditCard constructor called,cardNo=123 +\end_layout + +\begin_layout Plain Layout +============================== +\end_layout + +\begin_layout Plain Layout +Card constructor called,cardNo=456 +\end_layout + +\begin_layout Plain Layout +BankCard constructor called,cardNo=456 +\end_layout + +\begin_layout Plain Layout +DebitCard constuctor called,cardNo=456 +\end_layout + +\end_inset + + +\begin_inset Newline newline +\end_inset + +可以看出,调用super(cardNo)后,就不会再调用父类的无参构造方法。 +\end_layout + +\begin_layout Enumerate +不调用父类的构造方法时,输出如下: +\begin_inset Newline newline +\end_inset + + +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "90col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Card constructor called +\end_layout + +\begin_layout Plain Layout +BankCard constructor called +\end_layout + +\begin_layout Plain Layout +CreditCard constructor called,cardNo=123 +\end_layout + +\begin_layout Plain Layout +============================== +\end_layout + +\begin_layout Plain Layout +Card constructor called,cardNo=456 +\end_layout + +\begin_layout Plain Layout +BankCard constructor called,cardNo=456 +\end_layout + +\begin_layout Plain Layout +DebitCard constuctor called,cardNo=456 +\end_layout + +\end_inset + + +\begin_inset Newline newline +\end_inset + +可以看出,不显式调用父类的构造方法,实际上也会默认调用父类的无参构造方法,和显式调用super()效果是一样的。也就是说, +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +我们在创建子类对象时,要么通过明确调用父类的有参构造方法递归的创建父类对象,要么java会递归的调用父类的无参构造方法来初始化各级父类对象 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Section +static +\begin_inset CommandInset label +LatexCommand label +name "sec:static" + +\end_inset + + +\end_layout + +\begin_layout Standard +一个典型的面向对象的设计如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:面向对象编程的基本思路" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oopbasic/book-nostatic.eps + width 80col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +面向对象编程的基本思路 +\begin_inset CommandInset label +LatexCommand label +name "fig:面向对象编程的基本思路" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,我们在抽象出一类事物的共同特性后,编写相应于这类事物的一个类,在这里是Book;然后根据Book类再创建若干个Book类型的对象,book1、book +2等等。有了book对象后,就可以访问book对象的属性和方法了,比如调用:book.edit()。总之,原则上我们只有 +\begin_inset Flex Emph +status open + +\begin_layout Plain Layout +持有一个对象后(其实是持有一个指向对象的引用),才能操作这个对象 +\end_layout + +\end_inset + +。由 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:面向对象编程的基本思路" + +\end_inset + +可以看出,不同对象的状态(属性值)往往是不同的。 +\end_layout + +\begin_layout Standard +考虑下面的情形: +\end_layout + +\begin_layout Itemize +比如无论书籍的类型、开张等,书籍的“章”一般都定义为“第一章”、“第二章”,因此可以将CHAPTER_ONE定义为常量,而且不随Book对象的变化而变化,即无论 +有多少个Book对象,也无论Book对象的其他属性如何,CHAPTER_ONE,CHAPTER_TWO的值都不会变化。在这种情况下,每个Book对象都保存一份C +HAPTER_ONE,CHAPTER_TWO属性是没有必要的。解决这个问题的方法参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:static常量" + +\end_inset + +。 +\end_layout + +\begin_layout Itemize +比如给每个Book对象一个id,要求这个id能够自动增长,即假设第一个Book对象的id为1,第二个Book对象的id自动设置为2,以此类推。解决这个问题的方法 +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:static属性" + +\end_inset + +。 +\end_layout + +\begin_layout Itemize +比如我们要设计一个方法usage(),当调用这个方法时打印出Book类的用法。可以看出这个方法和对象的状态没有任何关系,也就是说,usage方法没有必要读取对象 +的状态,因此也没有必要每个对象都保存一个usage方法。解决这个问题的方法参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:static方法" + +\end_inset + +。 +\end_layout + +\begin_layout Subsection +static常量 +\begin_inset CommandInset label +LatexCommand label +name "subsec:static常量" + +\end_inset + + +\end_layout + +\begin_layout Standard +显然,常量没有必要在每个对象中都保存一份,只需要在类的定义中保存一份即可。因此,正如我们在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:常量和常量的命名" + +\end_inset + +中提到的,常量一般的命名方式都是public static final的,其中的static表示静态变量,即只在类定义中保存一份的变量,或者说,所有对象共享一份 +的变量。由于是常量,也通常使用final修饰符限定此变量不可修改,即常量(常数变量)。由于静态常量只和类有关而和具体对象无关,因此静态常量 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +静态常量 +\end_layout + +\end_inset + +又称为 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Index idx +status open + +\begin_layout Plain Layout +类常量 +\end_layout + +\end_inset + +类常量 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +在类中定义常量后,我们有两种方式使用(引用)这个常量: +\end_layout + +\begin_layout Enumerate +直接使用类名引用类常量。也就是说,不需要创建一个此类的对象,可以直接通过类名引用类常量。 +\end_layout + +\begin_layout Enumerate +使用对象引用类常量。如果已经创建了对象,通过对象引用类常量也是可以的。 +\end_layout + +\begin_layout Example +在Book中定义常量CHAPTER_ONE,CHAPTER_TWO,并使用两种方法引用此常量。 +\begin_inset CommandInset label +LatexCommand label +name "exa:在Book中定义常量CHAPTER_ONE,CHAPTER_TW" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "staticcontant-Book.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "staticconstant-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/staticconstant/Book.java" +lstparams "float,caption={使用了static常量的Book.java},label={staticcontant-Book.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/staticconstant/Client.java" +lstparams "float,caption={Client.java},label={staticconstant-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果和分析 +\end_layout + +\begin_layout Standard +执行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +第一章 +\end_layout + +\begin_layout Plain Layout +第一章 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +虽然两种方式都打印出了正确的结果,但是第二种引用static常量的方式是不建议的:即不经济,也没必要。 +\end_layout + +\begin_layout Exercise +在JDK源代码中找到一些常量的定义,认真体会: +\end_layout + +\begin_layout Itemize +常量的惯用命名方式,。 +\end_layout + +\begin_layout Itemize +常量的使用(引用)方式。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +JDK源代码可以从 +\begin_inset CommandInset href +LatexCommand href +name "https://github.com/dmlloyd/openjdk" +target "https://github.com/dmlloyd/openjdk" +literal "false" + +\end_inset + +下载。在openjdk的源代码目录下执行如下命令可以找到非常多的常量定义: +\end_layout + +\begin_layout Plain Layout +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status collapsed + +\begin_layout Plain Layout +$ grep -ri +\begin_inset Quotes eld +\end_inset + +public static final +\begin_inset Quotes erd +\end_inset + + * +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +static属性 +\begin_inset CommandInset label +LatexCommand label +name "subsec:static属性" + +\end_inset + + +\end_layout + +\begin_layout Standard +当我们用static修饰类的属性时,这个属性就成为“ +\begin_inset Index idx +status open + +\begin_layout Plain Layout +类属性 +\end_layout + +\end_inset + +类属性”。相对于“ +\begin_inset Index idx +status open + +\begin_layout Plain Layout +实例属性 +\end_layout + +\end_inset + +实例属性”(每个对象都有一份独立的拷贝), +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +类属性在此类的所有对象之间共享一份拷贝 +\end_layout + +\end_inset + +。对于类属性,我们需要注意到三点: +\end_layout + +\begin_layout Itemize +类属性的引用。我们一般采用Book.nextId的方式,即直接使用类来引用类属性,这也是类属性设计的本意。 +\end_layout + +\begin_layout Itemize +类属性相当于在对象之间共享的变量,因此一个对象修改了类属性,会影响另外对象的状态,因此使用类属性实际上导致了对象之间的“紧耦合”,造成了系统模块之间的界面不清晰 +,这是现代软件设计中力图规避的地方。因此,在软件设计实践中要尽量避免使用类属性,除非你有足够的理由。 +\end_layout + +\begin_layout Itemize +类属性的初始化问题。类属性的默认值和普通属性没有任何区别,但是由于类属性和具体对象没有关联,因此无法在对象的构造方法中初始化。Java提供了“ +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +static块 +\end_layout + +\end_inset + +”的方式初始化类属性,比如在Book中这样初始化nextId类属性: +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + // 初始化静态属性,这里设置id的起点值 +\end_layout + +\begin_layout Plain Layout + + static { +\end_layout + +\begin_layout Plain Layout + + nextId = 100; +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + +和对象的构造方法不同的是,static代码块在整个应用程序运行期间只会执行一次,而对象的构造方法在创建对象时都会执行一次。 +\end_layout + +\begin_layout Example +编写一个Book类,book对象使用自动增长的id作为对象的标识。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "staticvariable-Book.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "staticvariable-Client.java" + +\end_inset + + 。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/staticvariable/Book.java" +lstparams "float,caption={Book.java},label={staticvariable-Book.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/staticvariable/Client.java" +lstparams "float,caption={Client.java},label={staticvariable-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Book{id=100, title=Thinking in Java, author=null, price=0.0} +\end_layout + +\begin_layout Plain Layout +Book{id=101, title=Design Patterns, author=null, price=0.0} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +static方法 +\begin_inset CommandInset label +LatexCommand label +name "subsec:static方法" + +\end_inset + + +\end_layout + +\begin_layout Standard +和类属性 +\begin_inset Foot +status open + +\begin_layout Plain Layout +需要澄清的是,下面两种说法是等价的,我们可能在不同的场合交替使用不同的名称: +\end_layout + +\begin_layout Itemize +类属性=静态属性 +\end_layout + +\begin_layout Itemize +类方法=静态方法 +\end_layout + +\begin_layout Itemize +实例属性=实例变量=非静态属性=非静态变量 +\end_layout + +\begin_layout Itemize +实例方法=实例函数=对象方法=对象函数=非静态方法 +\end_layout + +\end_inset + +一样, +\begin_inset Index idx +status open + +\begin_layout Plain Layout +类方法 +\end_layout + +\end_inset + +类方法指使用static修饰的方法,类方法在所有对象之间共享一个拷贝。类方法通常用于一些工具类的定义,比如JDK中的Math类 +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见:http://docs.oracle.com/javase/8/docs/api/java/lang/Math.html +\end_layout + +\end_inset + +里面的方法都是类方法。 +\end_layout + +\begin_layout Standard +类方法是在对象创建之前就存在的,因此在类方法中不能访问实例属性(对象还没有创建,实例属性根本不存在),只能访问类属性(使用static修饰的属性),见下面的代码 +片段: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class Test { +\end_layout + +\begin_layout Plain Layout + + string name; +\end_layout + +\begin_layout Plain Layout + + static int nextId; +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + static void testStaticMethod() { +\end_layout + +\begin_layout Plain Layout + + nextId++; // 这是可以的 +\end_layout + +\begin_layout Plain Layout + + //name = "zhangsan"; // 这是不允许的,语法错误 +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +在Book类中增加一个类方法usage(),调用这个方法显示一段文字,说明这个类的用途。 +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +设计一个字符串处理工具类,给出如下的方法实现: +\end_layout + +\begin_layout Itemize +能够方便的删除字符串的最后一个字母; +\end_layout + +\begin_layout Itemize +能够自动将字符串转化为网址形式,即自动增加 +\begin_inset Quotes erd +\end_inset + +http:// +\begin_inset Quotes erd +\end_inset + +前缀; +\end_layout + +\begin_layout Subsection +*内部类回头看 +\end_layout + +\begin_layout Standard +在 +\begin_inset CommandInset ref +LatexCommand nameref +reference "subsec:内部类" + +\end_inset + +中,我们看到内部类就像是定义在类内部的方法一样。类的方法分为静态方法和非静态方法,静态方法只能访问类的静态属性,那么内部类是不是也可以使用static修饰呢? +\end_layout + +\begin_layout Standard +实际上,java的内部类分为四种类型: +\end_layout + +\begin_layout Enumerate +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +成员内部类(member inner class) +\end_layout + +\end_inset + +,即我们在 +\begin_inset CommandInset ref +LatexCommand nameref +reference "subsec:内部类" + +\end_inset + +中讨论的,和实例方法用法类似的内部类。 +\end_layout + +\begin_layout Enumerate +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +静态内部类(static inner class) +\end_layout + +\end_inset + +,使用static修饰的内部类。 +\end_layout + +\begin_layout Enumerate +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +局部内部类(local inner class) +\end_layout + +\end_inset + +,定义在方法内部的类。 +\end_layout + +\begin_layout Enumerate +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +匿名内部类(anonymous inner class) +\end_layout + +\end_inset + +,只使用一次的内部类。 +\end_layout + +\begin_layout Standard +内部类的第一种形式:成员内部类我们已经讨论过了,这里不再赘述,下面我们分别看一下其他三种内部类: +\end_layout + +\begin_layout Subsubsection +静态内部类 +\end_layout + +\begin_layout Standard +静态内部类即使用static修饰的内部类,也常叫做“嵌套类”(Nested Class)。静态内部类有两个重要的意义: +\end_layout + +\begin_layout Enumerate +正如静态方法一样,使用静态内部类可以限制内部类对外部包围类属性和方法的访问。对比成员内部类, +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +静态内部类只能访问外部包围类的静态属性和静态方法 +\end_layout + +\end_inset + +。使用静态内部类的好处是,如果我们在外部包围类中不定义静态属性和方法,实际上就切断了静态内部类和外部包围类的联系,使得静态内部类成为一个独立的模块,符合“松耦合 +”的现代软件设计理念。因此可以看到在实际的软件开发中,内部类很多都定义为静态内部类,比如Android程序设计中,大量使用到静态内部类。 +\end_layout + +\begin_layout Enumerate +静态内部类对象的创建不需要首先创建外部包围类对象,比如Outer.Inner innerObj = new Outer.Inner();这实际上让静态内部类成为了一 +个受限的顶级类 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +需要展开说明顶级类和受限的含义吗? +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Example +编写一个静态内部类,演示静态内部类访问外部包围类的静态属性和静态方法 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/oopbasic/src/cn +/edu/sdut/softlab/oopbasic/nestedclass +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "nestedclass-Book.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "nestedclass-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/nestedclass/Book.java" +lstparams "caption={Book.java},label={nestedclass-Book.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/nestedclass/Client.java" +lstparams "caption={Client.java},label={nestedclass-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +edit the book[version=1] by someone +\end_layout + +\begin_layout Plain Layout +publish the book[Learning Java based on C] +\end_layout + +\begin_layout Plain Layout +Book.Editor.usage() called +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +局部内部类 +\end_layout + +\begin_layout Standard +局部内部类定义在方法内部,可以认为是方法的局部变量。就像方法的局部变量一样,局部内部类的作用范围仅限于方法内部,即在方法外部是无法创建局部内部类的对象的。局部内 +部类可以使用所在方法中的属性,也可以访问类的实例属性和类属性。 +\end_layout + +\begin_layout Standard +局部内部类的使用场合较少,通常在组织复杂方法代码时使用。但是,由于在方法内部定义类,可能导致方法体臃肿,使得方法的逻辑层次不清晰,在使用局部内部类时要适当取舍。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +举个在openjdk中的例子?或者实际项目中的例子 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +编写一个局部内部类,演示局部内部类对方法属性的访问和局部内部类对象的创建方式 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +完整代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://github.com/subaochen/java-tutorial/tree/master/guide/code/oopbasic/src/cn +/edu/sdut/softlab/oopbasic/localinnerclass +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "localninnerclass-Book.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "localninnerclass-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/localinnerclass/Book.java" +lstparams "float,caption={Book.java},label={localninnerclass-Book.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/localinnerclass/Client.java" +lstparams "float,caption={Client.java},label={localninnerclass-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +edit the book before publish +\end_layout + +\begin_layout Plain Layout +publish book[version=1,id=0 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +匿名内部类 +\begin_inset CommandInset label +LatexCommand label +name "subsec:匿名内部类" + +\end_inset + + +\begin_inset Foot +status open + +\begin_layout Plain Layout +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:JAVA图形用户界面的事件机制" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:接口上的匿名内部类" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:使用匿名内部类" + +\end_inset + +中,我们还会看到匿名内部类的使用。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +如果一个内部类只使用一次的话,就没有必要非要给这个内部类起个名字了,这就是匿名内部类的使用场合。匿名内部类由于没有名字,必须从父类继承下来(在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:接口上的匿名内部类" + +\end_inset + +中我们可以看到,也可以实现一个接口)。 +\end_layout + +\begin_layout Example +使用匿名内部类 +\begin_inset CommandInset label +LatexCommand label +name "exa:使用匿名内部类" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "annonymousinnerclass-Book.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "annonymousinnerclass-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/annnoymousinnerclass/Book.java" +lstparams "float,caption={Book.java},label={annonymousinnerclass-Book.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/annnoymousinnerclass/Client.java" +lstparams "float,caption={Client.java},label={annonymousinnerclass-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +edit the book before publishing +\end_layout + +\begin_layout Plain Layout +publish the book[Learning Java Based on C] +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:使用匿名内部类" + +\end_inset + +中,我们组合使用了匿名对象和匿名内部类,这是由于在这种情况下,创建的匿名内部类对象也只使用一次,就没有必要起个名字了。我们给对象一个名字的目的不就是在重复使用这 +个对象的时候方便引用吗? +\end_layout + +\begin_layout Exercise +还原 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:使用匿名内部类" + +\end_inset + +为不使用匿名内部类的情形,对比一下说明匿名内部类的优点和缺点。 +\end_layout + +\begin_layout Subsection +*内部类的进一步讨论 +\begin_inset CommandInset label +LatexCommand label +name "subsec:内部类的进一步讨论" + +\end_inset + + +\end_layout + +\begin_layout Standard +在前面的讨论中,内部类都是没有父类的。但是,内部类其实也可以是一个子类 +\begin_inset Foot +status open + +\begin_layout Plain Layout +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:实现多个接口" + +\end_inset + +中,我们可以看到,内部类也可以实现(多个)接口,从而更好的实现Java的多继承。 +\end_layout + +\end_inset + +,这样我们在外部包围类中定义多个内部类,每个内部类继承自一个父类,就巧妙的绕过了Java没有多继承的限制,曲线的实现了多继承。 +\end_layout + +\begin_layout Example +编写程序,使用内部类达到多继承的目的。 +\begin_inset CommandInset label +LatexCommand label +name "exa:编写程序,使用内部类达到多继承的目的。" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinherit-Printer.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinherit-Copier.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinherit-SmartPrinter.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinherit-SmartPrinterClient.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/multiinherit/Printer.java" +lstparams "float,caption={Printer.java},label={multiinherit-Printer.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/multiinherit/Copier.java" +lstparams "float,caption={Copier.java},label={multiinherit-Copier.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/multiinherit/SmartPrinter.java" +lstparams "float,caption={SmartPrinter.java},label={multiinherit-SmartPrinter.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopbasic/src/cn/edu/sdut/softlab/oopbasic/multiinherit/SmartPrinterClient.java" +lstparams "float,caption={SmartPrinter.java},label={multiinherit-SmartPrinterClient.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +basic print +\end_layout + +\begin_layout Plain Layout +SmartPrinter print +\end_layout + +\begin_layout Plain Layout +basic copy +\end_layout + +\begin_layout Plain Layout +SmartPrinter copy +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +可以看出,在SmartPrinterTest中,我们只是使用SmartPrinter对象即可同时获得print和copy两个功能,好像同时从Printer和Co +pier继承下来一样。SmartPrinter类其实是一个Facade类 +\begin_inset CommandInset citation +LatexCommand cite +key "design-pattern-4gangs" +literal "true" + +\end_inset + +,当我们希望在一个类中融合多项功能时,为了代码逻辑清晰起见,借用内部类实现多继承是常见的策略。 +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +举一个在switch中使用Enum的例子 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +内部类的作用范围 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section* +思考和练习 +\end_layout + +\begin_layout Exercise +编写一个default修饰的类,尝试在其他包中创建该类的对象,结果会怎样? +\begin_inset CommandInset label +LatexCommand label +name "exer:编写一个default修饰的类,尝试在其他包中创建该类的对象,结" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +考虑下面的代码,指出哪些是类属性,哪些是实例属性? +\begin_inset CommandInset label +LatexCommand label +name "exer:考虑下面的代码,指出哪些是类属性,哪些是实例属性?" + +\end_inset + + +\begin_inset Note Note +status open + +\begin_layout Plain Layout +http://docs.oracle.com/javase/tutorial/java/javaOO/QandE/creating-questions.html +\end_layout + +\end_inset + + +\end_layout + +\end_body +\end_document diff --git a/guide/lecture_guide/lecture5.lyx b/guide/lecture_guide/lecture5.lyx new file mode 100644 index 0000000..db0b3ca --- /dev/null +++ b/guide/lecture_guide/lecture5.lyx @@ -0,0 +1,3395 @@ +#LyX 2.3 created this file. For more info see http://www.lyx.org/ +\lyxformat 544 +\begin_document +\begin_header +\save_transient_properties true +\origin unavailable +\textclass ctex-book +\begin_preamble +\input{../../../writing-common/book-preamble.tex} +\end_preamble +\use_default_options true +\begin_modules +tip-inset +note-inset +warning-inset +theorems-bytype +theorems-chap-bytype +coderemarks +logicalmkup +\end_modules +\maintain_unincluded_children false +\begin_local_layout +PackageOptions url hyphens +\end_local_layout +\language chinese-simplified +\language_package default +\inputencoding utf8-plain +\fontencoding global +\font_roman "default" "DejaVu Sans" +\font_sans "default" "DejaVu Serif" +\font_typewriter "default" "DejaVu Sans Mono" +\font_math "auto" "auto" +\font_default_family default +\use_non_tex_fonts true +\font_sc false +\font_osf false +\font_sf_scale 100 100 +\font_tt_scale 100 100 +\use_microtype false +\use_dash_ligatures false +\graphics default +\default_output_format pdf4 +\output_sync 0 +\bibtex_command default +\index_command default +\float_placement tbph +\paperfontsize default +\spacing single +\use_hyperref true +\pdf_bookmarks true +\pdf_bookmarksnumbered false +\pdf_bookmarksopen false +\pdf_bookmarksopenlevel 3 +\pdf_breaklinks true +\pdf_pdfborder true +\pdf_colorlinks true +\pdf_backref false +\pdf_pdfusetitle true +\papersize default +\use_geometry false +\use_package amsmath 1 +\use_package amssymb 1 +\use_package cancel 1 +\use_package esint 1 +\use_package mathdots 1 +\use_package mathtools 1 +\use_package mhchem 1 +\use_package stackrel 1 +\use_package stmaryrd 1 +\use_package undertilde 1 +\cite_engine basic +\cite_engine_type default +\biblio_style plain +\use_bibtopic false +\use_indices false +\paperorientation portrait +\suppress_date false +\justification true +\use_refstyle 1 +\use_minted 0 +\boxbgcolor #dad3d7 +\index Index +\shortcut idx +\color #008000 +\end_index +\secnumdepth 3 +\tocdepth 2 +\paragraph_separation indent +\paragraph_indentation default +\is_math_indent 0 +\math_numbering_side default +\quotes_style english +\dynamic_quotes 0 +\papercolumns 1 +\papersides 2 +\paperpagestyle default +\tracking_changes false +\output_changes false +\html_math_output 0 +\html_css_as_file 0 +\html_be_strict false +\end_header + +\begin_body + +\begin_layout Standard +\align center + +\size larger +\bar under +山东理工大学教案 +\end_layout + +\begin_layout Standard +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +第五次课 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +教学课型:理论课□√ 实验课□√ 习题课□ 实践课□ 技能课□ 其它□ +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +主要教学内容 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:抽象类和抽象方法" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:抽象类和抽象方法" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:接口" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:接口" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +重点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +抽象类的基本概念和用法; +\end_layout + +\begin_layout Enumerate +接口的基本概念和用法; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +难点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +抽象类和接口的关系; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +课程目标及要求 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +课程目标:课程目标1 +\end_layout + +\begin_layout Plain Layout +要求: +\end_layout + +\begin_layout Enumerate +熟练掌握抽象类的概念和使用场合,结合类的层级结构和访问控制,能够根据现实问题设计合适的抽象类作为父类; +\end_layout + +\begin_layout Enumerate +熟练掌握接口的概念和使用场合,能够根据现实问题抽象出接口部分,设计合适的模块耦合; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +教学方法和手段 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +板书和多媒体相结合,边讲边练,当堂消化。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +讨论、思考题 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +抽象类和接口的区别和联系? +\end_layout + +\begin_layout Enumerate +从现实世界中找到几个抽象类和接口的对应关系。 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +参考资料 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Chapter +面向对象工程思想 +\end_layout + +\begin_layout Standard +不想当将军的士兵不是好士兵,不想当架构师的程序员不是一个好程序员。本章内容不可能涵盖Java架构师的所有内容,只是一个菜鸟Java程序员进阶的必由之路。 +\end_layout + +\begin_layout Standard +\align center +\begin_inset Graphics + filename ../imgs/oop-project-method/programmer-steps.eps + lyxscale 50 + width 90col% + +\end_inset + + +\end_layout + +\begin_layout Section +抽象类和抽象方法 +\begin_inset CommandInset label +LatexCommand label +name "sec:抽象类和抽象方法" + +\end_inset + + +\end_layout + +\begin_layout Standard +在类的继承关系中,有些情况下我们不希望根据父类创建对象,或者说希望 +\begin_inset Flex Emph +status open + +\begin_layout Plain Layout +禁止创建父类对象 +\end_layout + +\end_inset + +。比如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Animal的类层次关系" + +\end_inset + +所示的情形。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oop-project-method/java-polymorphism.eps + width 70col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Animal的类层次关系 +\begin_inset CommandInset label +LatexCommand label +name "fig:Animal的类层次关系" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +如果我们希望禁止创建Animal对象 +\begin_inset Foot +status open + +\begin_layout Plain Layout +为什么有这种需求呢?主要的出发点是强制使用具体的子类对象,因为子类对象比父类对象提供了更具体的属性和方法。 +\end_layout + +\end_inset + +,即只允许创建Dog、Cat等Animal的子类对象,该怎么做呢?Java提供了两种方式: +\end_layout + +\begin_layout Enumerate +使用抽象类 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +抽象类 +\end_layout + +\end_inset + +:将Animal定义为抽象类,这样使用new创建Animal对象将导致语法错误,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:抽象类" + +\end_inset + +。 +\end_layout + +\begin_layout Enumerate +使用接口 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +接口 +\end_layout + +\end_inset + +:将Animal定义为接口,这样便不能直接创建Animal类型的对象,只能通过实现Animal接口创建具体的对象,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:接口" + +\end_inset + +。 +\end_layout + +\begin_layout Subsection +抽象类 +\begin_inset CommandInset label +LatexCommand label +name "subsec:抽象类" + +\end_inset + + +\end_layout + +\begin_layout Standard +只要一个类使用 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +abstract +\end_layout + +\end_inset + +abstract修饰,这个类就是一个抽象类。抽象类不允许通过new操作符创建对象,抽象类只能作为父类被继承。 +\end_layout + +\begin_layout Example +编写一个抽象的Animal类 +\begin_inset CommandInset label +LatexCommand label +name "exa:编写一个抽象的Animal类。" + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "abstractclass-Animal.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "abstractclass-Dog.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "abstractclass-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/abstractclass/Animal.java" +lstparams "float,caption={Animal.java},label={abstractclass-Animal.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/abstractclass/Dog.java" +lstparams "float,caption={Dog.java},label={abstractclass-Dog.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/abstractclass/Client.java" +lstparams "float,caption={Client.java},label={abstractclass-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +动物在打招呼 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +抽象类是不允许直接实例化 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +实例化 +\end_layout + +\end_inset + +的,因此在Client中直接创建Animal类型的对象会报告语法错误。虽然Dog类看起来是一个空的类,但是Dog继承自Animal,因此也继承了Animal中已 +经实现了的公有的hello方法。 +\end_layout + +\begin_layout Subsection +抽象方法 +\end_layout + +\begin_layout Standard +有的时候,我们希望父类的方法仅仅是个声明,即只是说明了方法的名字、返回值类型、参数的类型和个数及其顺序,方法的具体内容(即方法体)需要父类的子类去实现。也就是说 +,父类的这个方法是“抽象”的,因为缺少了方法体,直接调用这个抽象的方法也没有意义,因此Java规定只要类中有一个抽象方法 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +抽象方法 +\end_layout + +\end_inset + +,这个类就必须定义为抽象类。子类在继承抽象类后,必须实现父类中的所有抽象方法,除非该子类也是抽象类。 +\end_layout + +\begin_layout Example +实现一个包含抽象方法的抽象类。 +\begin_inset CommandInset label +LatexCommand label +name "exa:实现一个包含抽象方法的抽象类。" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "abstractmethod-Animal.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "abstractmethod-Dog.java" + +\end_inset + +,Client的设计和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:编写一个抽象的Animal类。" + +\end_inset + +一样,这里不再列出。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/abstractmethod/Animal.java" +lstparams "float,caption={Animal.java},label={abstractmethod-Animal.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/abstractmethod/Dog.java" +lstparams "float,caption={Dog.java},label={abstractmethod-Dog.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +汪汪 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +可以看出,父类中的抽象方法hello在子类中必须给出具体的实现。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +在Idea中,如果没有实现父类中的抽象方法,在类名上面会给出提示信息,此时只要在类名上面按Alt+Enter键组合即可自动给出默认的方法实现,非常方便: +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oop-project-method/abstract-method-hint.png + width 60col% + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +如果Dog类也是抽象类,一定需要实现父类Animal中的抽象方法吗?试修改 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:实现一个包含抽象方法的抽象类。" + +\end_inset + +的Dog为抽象类,然后增加一个Hunter类作为Dog的子类。 +\end_layout + +\begin_layout Subsection +抽象类小结 +\end_layout + +\begin_layout Standard +抽象类是系统架构的常见手段,有两个重要的作用: +\end_layout + +\begin_layout Itemize +强制继承,不允许实例化父类,即必须提供子类才能使用抽象父类的属性和功能。 +\end_layout + +\begin_layout Itemize +便于合理划分(区分)事物的共性和个性,将个性化的部分设计为抽象方法,强制子类实现父类的抽象方法,同时子类中的这些方法其名称、参数和返回值也会受到抽象父类的约束, +这在系统架构和团队合作中显得尤为重要。 +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +要讨论抽象类和多态吗? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +接口 +\begin_inset CommandInset label +LatexCommand label +name "sec:接口" + +\end_inset + + +\end_layout + +\begin_layout Subsection +定义接口:纯的抽象类 +\end_layout + +\begin_layout Standard +如果抽象类中所有的方法都是抽象方法会怎样?比如下面的代码: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public abstract class Animal { +\end_layout + +\begin_layout Plain Layout + + public abstract void hello(); +\end_layout + +\begin_layout Plain Layout + + public abstract void eat(); +\end_layout + +\begin_layout Plain Layout + + public abstract void sleep(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,此时的Animal是一个纯抽象类 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +纯抽象类 +\end_layout + +\end_inset + +,Java提供了interface( +\begin_inset Index idx +status open + +\begin_layout Plain Layout +接口 +\end_layout + +\end_inset + +接口)来表达纯的抽象类,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "interface-Animal.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/pureabstract/Animal.java" +lstparams "float,caption={Animal.java},label={interface-Animal.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +接口 +\end_layout + +\end_inset + +接口具有如下的特点: +\end_layout + +\begin_layout Itemize +接口一定是抽象的,因此接口类不需要明确声明是抽象的。即,在定义接口时,下面的两种方式都是可以的,一般采用省略abstract的写法。 +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public abstract interface Animal{...} +\end_layout + +\begin_layout Plain Layout + +public interface Animal {} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +接口中的方法一定是public的,所以可以省略接口方法的访问控制属性。实际上,在接口方法上使用private或者protected是语法错误,比如尝试在接口方法 +上增加protected: +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public interface Animal { +\end_layout + +\begin_layout Plain Layout + + // 语法错误! +\end_layout + +\begin_layout Plain Layout + + protected void hello(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +正因为接口的以上两个特点,可以认为 +\begin_inset Flex Emph +status open + +\begin_layout Plain Layout +接口是对“纯的抽象类”的简化写法 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Subsection +实现接口 +\end_layout + +\begin_layout Standard +接口虽然很像“纯的抽象类”,但是其用法和用意和抽象类有很多不同,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:抽象类和接口的关系" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +抽象类 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +接口 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +意义 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +概括了一类事物的共同属性和行为特征 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +概括了一类事物的共同行为特征 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法的实现 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +可以实现部分方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +只能声明方法,不允许实现方法 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +使用场合 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +用于明确类的层次关系 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +用于明确类的能力范围 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +用法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +子类通过extends继承父类 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +通过implements实现指定的接口 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +抽象类和接口的关系 +\begin_inset CommandInset label +LatexCommand label +name "tab:抽象类和接口的关系" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +将Animal定义为接口,Dog类实现Animal接口。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand formatted +reference "interface-Animal.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand formatted +reference "pureabstract-Dog.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand formatted +reference "pureabstract-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/pureabstract/Dog.java" +lstparams "float,caption={Dog.java},label={pureabstract-Dog.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/pureabstract/Client.java" +lstparams "float,caption={Client.java},label={pureabstract-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +汪汪 +\end_layout + +\begin_layout Plain Layout +Dog eat method +\end_layout + +\begin_layout Plain Layout +Dog sleep method +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +Dog类实现了Animal接口即意味着Dog类要给出Animal接口中规定的所有抽象方法的具体实现。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +和实现抽象方法类似,在Idea中,通过快捷键Alt+Enter可自动补全接口的方法,不再赘述。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +实现多个接口 +\begin_inset CommandInset label +LatexCommand label +name "subsec:实现多个接口" + +\end_inset + + +\end_layout + +\begin_layout Standard +对于抽象类,我们知道需要子类继承抽象的父类并实现父类中的所有抽象方法。但是,Java只支持单继承,即一个子类只能继承自一个抽象类。接口则不同, +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +一个类可以“实现”若干个接口 +\end_layout + +\end_inset + +,这也是接口的强大之处。 +\end_layout + +\begin_layout Standard +现实中,事物总是具有多面性的,比如爱因斯坦不仅仅是物理学家,小提琴也拉的很好。比如大家对毛泽东的评价是伟大的思想家、哲学家、军事家、诗人。通常,我们会把一类事物 +的共同行为特征归纳为一个接口,那么具有多面性的事物,应该可以拥有多个接口才对,或者说,具有多面性的事物,应该实现多个接口。 +\end_layout + +\begin_layout Example +实现多个接口的类。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +需要画出类的UML类图 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinterface-Printer.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinterface-Copier.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinterface-SmartPrinter.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinterface-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/multiinterface/Printer.java" +lstparams "float,caption={Printer.java},label={multiinterface-Printer.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/multiinterface/Copier.java" +lstparams "float,caption={Copier.java},label={multiinterface-Copier.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/multiinterface/SmartPrinter.java" +lstparams "float,caption={SmartPrinter.java},label={multiinterface-SmartPrinter.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/multiinterface/Client.java" +lstparams "float,caption={Client.java},label={multiinterface-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +print called +\end_layout + +\begin_layout Plain Layout +copy called +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +SmartPrinter实现了两个接口Printer和Copier,也就意味着SmartPrinter同时具有打印和复印两项功能。有人说,这不是多此一举吗?去掉 +两个接口的定义,在SmartPrinter类中直接实现copy和print方法就可以。从功能上看,的确可以这样处理,但是从逻辑上看,不使用接口会带来两个方面的问 +题: +\end_layout + +\begin_layout Itemize +Print和Copy两个接口定义了功能方法的名称和参数,如果不使用接口,或者不实现规定的接口,那么方法名就失去了参照,很容易造成各自为政的局面,给代码的维护和团 +队的交流带来麻烦。 +\end_layout + +\begin_layout Itemize +使用接口带来的另外一个好处是,我们可以通过“向上塑型 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +向上塑型 +\end_layout + +\end_inset + +”加强软件的健壮性,我们将在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:向上塑型:面向接口的编程" + +\end_inset + +展示这一点。 +\end_layout + +\begin_layout Standard +基于以上的分析,其实SmartPrinter的更合理的实现应该是 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinterface-BetterSmartPrinter.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/multiinterface/BetterSmartPrinter.java" +lstparams "float,caption={BetterSmartPrinter.java},label={multiinterface-BetterSmartPrinter.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +可以看出,通过内部类的封装,BetterSmartPrinter类的内部结构更清晰了。 +\end_layout + +\begin_layout Subsection +抽象类和接口的区别 +\end_layout + +\begin_layout Standard +抽象类和接口是从不同的方向来分析和看待事物—抽象类是纵向分析,接口是横向分析。如 +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:抽象类和接口的区别" + +\end_inset + +所示,纵向来看,Bus类描述了公交车的公共属性和方法,Classroom类描述了教室的公共属性和方法。但是在Bus和Classroom类中,某些方法是公共的,比 +如都提供Wifi接入服务和休息座椅,这些在不同事物中的公共方法,横向(切片)来看就是接口的意义。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/oop-project-method/abstract-class-interface.eps + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +抽象类和接口的区别 +\begin_inset CommandInset label +LatexCommand label +name "fig:抽象类和接口的区别" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +试根据 +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:抽象类和接口的区别" + +\end_inset + +编写相应的Bus、Classroom类和接口Wifi、Seat。 +\begin_inset CommandInset label +LatexCommand label +name "exer:试根据编写相应的Bus、Classroom类和接口Wifi、Se" + +\end_inset + +(参见: +\begin_inset CommandInset ref +LatexCommand vref +reference "solu:abstract class and interface" + +\end_inset + +) +\end_layout + +\begin_layout Subsection +接口中的常量 +\end_layout + +\begin_layout Standard +接口中除了抽象方法外,也可以持有常量,这也是一种常见的情形。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +需要进一步解释为什么常量是常见情形?JDK中的例子找出来 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +但是,接口中不允许持有变量。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +需要进一步解释为什么? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +接口的继承 +\end_layout + +\begin_layout Standard +接口是“纯的抽象类”,因此接口和其他类一样,也可以实现继承关系,即接口的继承和类的继承有相同的语法和限制,不再赘述。 +\end_layout + +\begin_layout Subsection +接口中的默认方法 +\begin_inset Foot +status open + +\begin_layout Plain Layout +自JDK8开始支持此特性。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +TBD +\begin_inset Note Note +status open + +\begin_layout Plain Layout +可以参考:http://www.cnblogs.com/guangshan/p/4889732.html +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +不懂接口的项目经理不是好的项目经理 +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:实现多个接口" + +\end_inset + +中我们已经看到,通过接口可以帮助我们规划模块的调用界面(界限),这在团队协作中非常重要,也就是说,接口为团队协作提供了有力的语法支持,考虑下面的情形: +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oop-project-method/no-interface.eps + width 90col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +不引入接口时的团队协作 +\begin_inset CommandInset label +LatexCommand label +name "fig:不引入接口时的团队协作" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +如果不使用接口,团队成员在功能实现时,在方法命名和方法规划上就失去了约束,这在小型项目中也许还是可以接受的,但是随着项目规模的增大,项目成员的增加和更迭,这种没 +有约束的编码方式很容易把项目带到沟里,最终失去控制,导致项目失败。因此,作为 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +项目经理 +\end_layout + +\end_inset + +项目经理或者项目的架构师 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +架构师 +\end_layout + +\end_inset + +,接口是一个有力的工具,在项目之初可以通过定义一系列接口的方式规定模块功能和模块之间的交互界面,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:引入接口后的团队协作" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oop-project-method/with-interface.eps + width 90col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +引入接口后的团队协作 +\begin_inset CommandInset label +LatexCommand label +name "fig:引入接口后的团队协作" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +分别实现 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:不引入接口时的团队协作" + +\end_inset + +所示的代码和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:引入接口后的团队协作" + +\end_inset + +所示的代码,认真体会接口在团队协作中的作用。 +\end_layout + +\begin_layout Subsection +接口上的匿名内部类 +\begin_inset CommandInset label +LatexCommand label +name "subsec:接口上的匿名内部类" + +\end_inset + + +\end_layout + +\begin_layout Standard +如果我们确定一个对象只临时使用一次,那么这个对象通常可以采用匿名内部类 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +匿名内部类 +\end_layout + +\end_inset + +的方式来实现,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:匿名内部类" + +\end_inset + +。如果这个临时的对象只是实现了某个接口,那么代码还可以进一步简化,直接可以使用“接口上的匿名类”技术来实现,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "annoymousInnerClass-Client.java" + +\end_inset + +所示(Printer接口和Copier接口不变,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinterface-Printer.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinterface-Copier.java" + +\end_inset + +)。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/annoymousinnerclass/Client.java" +lstparams "float,caption={Client.java},label={annoymousInnerClass-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Section +多态 +\begin_inset CommandInset label +LatexCommand label +name "sec:多态" + +\end_inset + + +\end_layout + +\begin_layout Standard +所谓 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +多态 +\end_layout + +\end_inset + +多态,是指对象在不同阶段或者环境下有不同的行为特征,听起来是不是有点“变色龙”的味道? +\end_layout + +\begin_layout Standard +先看一个实例,假设有如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Animal的类层次关系" + +\end_inset + +所示的类层次结构,也就是说,父类Animal有默认的hello()方法,三个子类Dog,Cat,Duke分别重写(overriding)了父类Animal的方法 +hello()。代码实现如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "ploymorphism-Animal.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "ploymorphism-Dog.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "ploymorphism-Cat.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "ploymorphism-Duke.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "ploymorphism-TestAnimal.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/polymorphism/Animal.java" +lstparams "float,caption={Animal.java},label={ploymorphism-Animal.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/polymorphism/Dog.java" +lstparams "float,caption={Dog.java},label={ploymorphism-Dog.java}" + +\end_inset + + +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/polymorphism/Cat.java" +lstparams "float,caption={Cat.java},label={ploymorphism-Cat.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/polymorphism/Duke.java" +lstparams "float,caption={Duke.java},label={ploymorphism-Duke.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/polymorphism/TestAnimal.java" +lstparams "float,caption={TestAnimal.java},label={ploymorphism-TestAnimal.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +在TestAnimal中,animals数组的每个元素是Animal类型的,貌似调用animal数组元素的hello方法应该打印出“动物在打招呼”,但是执行Te +stAnimal会发现输出结果是: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +汪汪 +\end_layout + +\begin_layout Plain Layout +喵喵 +\end_layout + +\begin_layout Plain Layout +嘎嘎 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,虽然我们调用的是父类对象的方法,但是其实真正执行的却是子类中的方法,这就是 +\begin_inset Flex Noun +status open + +\begin_layout Plain Layout +多态 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +多态 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +。简单的说,多态是指:父类对象调用子类方法。 但是,同一个对象,在不同的运行时间,怎么会有不同的行为呢?这一点是如何做到的?先从对象的存储模型说起。 +\end_layout + +\begin_layout Subsection +对象的概念存储模型 +\begin_inset CommandInset label +LatexCommand label +name "subsec:对象的存储模型" + +\end_inset + + +\end_layout + +\begin_layout Standard +在上面的例子中,Dog、Cat、Duke类的对象在内存中是如何存储的呢?比如当Dog dog = new Dog()创建了一个Dog类的实例,则在内存中的存储如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java对象在内存中的存储模型" + +\end_inset + +所示 +\begin_inset Foot +status open + +\begin_layout Plain Layout +提请读者注意的是,为了简化问题的描述和避免过多的底层细节,本节的对象存储模型仅仅为了大家理解方便,并非对象在内存的真实存储情形。更多的细节请读者参考Java虚拟 +机规范 +\begin_inset CommandInset citation +LatexCommand cite +key "jvm-se8-specification" +literal "true" + +\end_inset + +,推荐阅读《深入理解Java虚拟机》 +\begin_inset CommandInset citation +LatexCommand cite +key "jvm-advanced-feature" +literal "true" + +\end_inset + +一书。 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Wrap figure +lines 0 +placement r +overhang 0in +width "50line%" +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oop-project-method/java-instance-storage.eps + width 100line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java对象在内存中的存储模型 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java对象在内存中的存储模型" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +其中,dog是对象的引用,即指针,指向对象在内存的起始地址。对象在内存中的存储分为两个部分:父类的属性和方法存储区域以及子类的属性和方法存储区域,也就是说,子类 +完全包含了父类的所有信息。因此可以看出,我们得到了一个指向子类的引用dog,这个引用dog即可以访问子类的方法和属性,也可以访问父类的方法和属性,无非是通过do +g指针不同的偏移量指向不同的区域而已。 +\end_layout + +\begin_layout Standard +那么Animal dog = new Dog()是什么意思呢?从 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java对象在内存中的存储模型" + +\end_inset + +可以看出,此时的dog指针仍然是指向整个Dog对象的指针,但是指针的范围却局限于父类Animal的区域,也就是说,此时的dog指针只能调用父类Animal中的属 +性和方法,而不能调用Dog子类扩展了的属性和方法。 +\end_layout + +\begin_layout Standard +如果子类没有重写 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +重写 +\end_layout + +\end_inset + +(orverriding)父类的方法,子类和父类的存储是泾渭分明的。如果子类重写(orverriding)了父类中的方法,那么父类中被重写的方法同样会发生变化, +即变的和子类中重写的方法一模一样,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:存在重写情况下的类存储结构" + +\end_inset + +所示。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这样的讲述是有问题的,试想super.hello()方法的调用过程? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oop-project-method/java-instance-storage1.eps + width 60line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +存在重写情况下的类存储结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:存在重写情况下的类存储结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +可以看出,当子类重写了父类中的方法时,父类存储区域中被重写的方法就变得和子类中的方法一模一样了,这样就能够理解本文刚开始的例子了:虽然animals数组的元素都 +是Animal类型的对象,但是由于这三个引用分别指向了Dog、Cat、Duke的对象,而Dog等对象重写了Animal中的hello方法,致使我们虽然调用的是父 +类中的方法,但是由于子类重写了父类中的这个方法,父类中的这个方法变得和子类中的方法一模一样了(即所谓的overriding,重写),最终的效果和直接调用子类中的 +方法一样,这就是Java中的多态,其实也是我们期望发生的事情。 +\end_layout + +\begin_layout Subsection +方法重载时的情形 +\end_layout + +\begin_layout Standard +在上例中,如果子类不是重写(overriding)父类的方法,而是 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +重载 +\end_layout + +\end_inset + +重载(overloading)父类的方法,结果会怎样呢?比如,Cat类的hello方法改为(Dog/Duke以此类推): +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public void hello(String name){ +\end_layout + +\begin_layout Plain Layout + + System.out.println("喵喵" + name); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,Cat类的hello方法重载了父类的hello方法。执行TestAnimal的结果是: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +动物在打招呼 +\end_layout + +\begin_layout Plain Layout +动物在打招呼 +\end_layout + +\begin_layout Plain Layout +动物在打招呼 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +根据 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:存在重载情况的类存储结构" + +\end_inset + +可自行分析执行结果。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oop-project-method/java-instance-storage2.eps + width 60line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +存在重载情况的类存储结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:存在重载情况的类存储结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +多态的小结 +\end_layout + +\begin_layout Standard +可以看出,Java的多态是一种“动态绑定”技术,即在运行时决定调用哪个方法。多态的使用需要满足三个条件: +\end_layout + +\begin_layout Enumerate +继承 +\end_layout + +\begin_layout Enumerate +重写 +\end_layout + +\begin_layout Enumerate +父类引用指向子类对象 +\end_layout + +\begin_layout Subsection +多态的应用场合 +\end_layout + +\begin_layout Standard +从以上的分析可以看出,通常会利用方法的重写来达到简化代码的目的,即充分利用Java的多态特性。也就是说,在多态的帮助下,我们只需要调用父类的方法就可以了,具体执 +行的却是子类的对应方法。当然,这里有一个前提,即必须使用子类创建对象的引用,否则多态也就失效了。 +\end_layout + +\begin_layout Exercise +请说明实现Java多态的关键是什么? +\end_layout + +\begin_layout Section +*向上塑型:面向接口的编程 +\begin_inset CommandInset label +LatexCommand label +name "sec:向上塑型:面向接口的编程" + +\end_inset + + +\end_layout + +\begin_layout Standard +从 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:对象的存储模型" + +\end_inset + +可以看出,子类对象拥有父类对象的所有属性和方法(当然,在访问控制的限制下),反过来说,父类对象的属性和方法是子类对象的一个子集,因此把子类对象转换为一个父类对象 +是安全的,也就是说,如果我们持有一个子类对象的引用,可以安全的把这个引用转换为父类对象的引用,因为通过这个父类对象的引用,我们访问任何属性和方法都是“可达”的, +都不会引起任何错误。 +\end_layout + +\begin_layout Standard +但是反过来是不可行的,即把父类对象转换为子类对象。原因很简单,转换后的子类对象引用仍然指向了父类对象,但是却可能试图访问超出了父类对象范围的属性和方法,显然是不 +允许的。 +\end_layout + +\begin_layout Standard +这就是Java中的“向上塑型 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +向上塑型 +\end_layout + +\end_inset + +”,即对象的引用可以向父类的方向转换,但是不允许向子类的方向转换。在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "ploymorphism-TestAnimal.java" + +\end_inset + +中,我们已经看到了向上塑型的应用,可以说,向上塑型是Java多态的的基本形态。 +\end_layout + +\begin_layout Standard +在编程实践中,我们也经常按照接口向上塑型,即把对象的类型转换为其实现的某个接口,比如我们重写 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinterface-Client.java" + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + public static void main(String[] args) { +\end_layout + +\begin_layout Plain Layout + + Printer sp = new SmartPrinter(); // 向上塑型为接口类型 +\end_layout + +\begin_layout Plain Layout + + sp.print(); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +可以看出,通过向上塑型为父类对象或者接口类型,实际上我们获得了一个“受限”的对象引用,即这个对象引用只能访问原对象的部分属性和方法,一定程度上提高了程序的安全性 +和健壮性:尽量少的对外暴露调用接口。这也符合面向对象编程的封装 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +封装 +\end_layout + +\end_inset + +原则。 +\end_layout + +\begin_layout Subsection +对象的类型 +\end_layout + +\begin_layout Standard +讨论如下的代码片段: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class SmartPrinter extends BasePrinter implements Printer, Copier + { +\end_layout + +\begin_layout Plain Layout + + ... +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +那么以下的用法都是合法的: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +SmartPrinter sp = new SmartPrinter(); +\end_layout + +\begin_layout Plain Layout + +BasePrinter sp = new SmartPrinter(); // 向上塑型为父类对象 +\end_layout + +\begin_layout Plain Layout + +Printer sp = new SmartPrinter(); // 向上塑型为接口类型 +\end_layout + +\begin_layout Plain Layout + +Copier = new SmartPrinter(); // 向上塑型为接口类型 +\end_layout + +\begin_layout Plain Layout + +Object sp = new SmartPrinter(); // Object是所有类的父类 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +一个对象可以有多少种类型?试举例说明。 +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +此话题说清楚有难度,手头资料似乎不够 +\end_layout + +\begin_layout Plain Layout +子类(subtyping)是面向对象编程的重要概念, +\end_layout + +\begin_layout Definition +子类替换原则 +\begin_inset CommandInset citation +LatexCommand cite +after "2.1" +key "java-generics-collections" +literal "true" + +\end_inset + +是指,凡是我们期望一个对象的时候,都可以使用这个对象的子类对象来替代。 +\end_layout + +\begin_layout Definition +子类替换有两种常见情形: +\end_layout + +\begin_layout Enumerate +使用子类赋值 +\end_layout + +\begin_layout Enumerate +使用子类替换参数 +\end_layout + +\end_inset + + +\end_layout + +\end_body +\end_document diff --git a/guide/lecture_guide/lecture6.lyx b/guide/lecture_guide/lecture6.lyx new file mode 100644 index 0000000..071f40a --- /dev/null +++ b/guide/lecture_guide/lecture6.lyx @@ -0,0 +1,3415 @@ +#LyX 2.3 created this file. For more info see http://www.lyx.org/ +\lyxformat 544 +\begin_document +\begin_header +\save_transient_properties true +\origin unavailable +\textclass ctex-book +\begin_preamble +\input{../../../writing-common/book-preamble.tex} +\end_preamble +\use_default_options true +\begin_modules +tip-inset +note-inset +warning-inset +theorems-bytype +theorems-chap-bytype +coderemarks +logicalmkup +\end_modules +\maintain_unincluded_children false +\begin_local_layout +PackageOptions url hyphens +\end_local_layout +\language chinese-simplified +\language_package default +\inputencoding utf8-plain +\fontencoding global +\font_roman "default" "DejaVu Sans" +\font_sans "default" "DejaVu Serif" +\font_typewriter "default" "DejaVu Sans Mono" +\font_math "auto" "auto" +\font_default_family default +\use_non_tex_fonts true +\font_sc false +\font_osf false +\font_sf_scale 100 100 +\font_tt_scale 100 100 +\use_microtype false +\use_dash_ligatures false +\graphics default +\default_output_format pdf4 +\output_sync 0 +\bibtex_command default +\index_command default +\float_placement tbph +\paperfontsize default +\spacing single +\use_hyperref true +\pdf_bookmarks true +\pdf_bookmarksnumbered false +\pdf_bookmarksopen false +\pdf_bookmarksopenlevel 3 +\pdf_breaklinks true +\pdf_pdfborder true +\pdf_colorlinks true +\pdf_backref false +\pdf_pdfusetitle true +\papersize default +\use_geometry false +\use_package amsmath 1 +\use_package amssymb 1 +\use_package cancel 1 +\use_package esint 1 +\use_package mathdots 1 +\use_package mathtools 1 +\use_package mhchem 1 +\use_package stackrel 1 +\use_package stmaryrd 1 +\use_package undertilde 1 +\cite_engine basic +\cite_engine_type default +\biblio_style plain +\use_bibtopic false +\use_indices false +\paperorientation portrait +\suppress_date false +\justification true +\use_refstyle 1 +\use_minted 0 +\boxbgcolor #dad3d7 +\index Index +\shortcut idx +\color #008000 +\end_index +\secnumdepth 3 +\tocdepth 2 +\paragraph_separation indent +\paragraph_indentation default +\is_math_indent 0 +\math_numbering_side default +\quotes_style english +\dynamic_quotes 0 +\papercolumns 1 +\papersides 2 +\paperpagestyle default +\tracking_changes false +\output_changes false +\html_math_output 0 +\html_css_as_file 0 +\html_be_strict false +\end_header + +\begin_body + +\begin_layout Standard +\align center + +\size larger +\bar under +山东理工大学教案 +\end_layout + +\begin_layout Standard +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +第六次课 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +教学课型:理论课□√ 实验课□√ 习题课□ 实践课□ 技能课□ 其它□ +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +主要教学内容 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:多态" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:多态" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:向上塑型:面向接口的编程" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:向上塑型:面向接口的编程" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +重点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +多态的概念和用法; +\end_layout + +\begin_layout Enumerate +面向接口编程的思想; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +难点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +多态的实现方法; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +课程目标及要求 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +课程目标:课程目标1 +\end_layout + +\begin_layout Plain Layout +要求: +\end_layout + +\begin_layout Enumerate +了解多态的概念和用法,知晓将来的复杂工程实现中多态是一种常见的形态; +\end_layout + +\begin_layout Enumerate +建立面向接口编程的基本思想和态度,逐步培养面向接口编程的素质和能力; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +教学方法和手段 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +板书和多媒体相结合,边讲边练,当堂消化。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +讨论、思考题 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +为什么面向接口编程更加安全? +\end_layout + +\begin_layout Enumerate +在工程实践中,使用抽象类属于面向接口编程吗? +\end_layout + +\begin_layout Enumerate +\begin_inset CommandInset ref +LatexCommand vref +reference "exer:一个对象可以有多少种类型?试举例说明。" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +参考资料 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Chapter +面向对象工程思想 +\end_layout + +\begin_layout Standard +不想当将军的士兵不是好士兵,不想当架构师的程序员不是一个好程序员。本章内容不可能涵盖Java架构师的所有内容,只是一个菜鸟Java程序员进阶的必由之路。 +\end_layout + +\begin_layout Standard +\align center +\begin_inset Graphics + filename ../imgs/oop-project-method/programmer-steps.eps + lyxscale 50 + width 90col% + +\end_inset + + +\end_layout + +\begin_layout Section +抽象类和抽象方法 +\begin_inset CommandInset label +LatexCommand label +name "sec:抽象类和抽象方法" + +\end_inset + + +\end_layout + +\begin_layout Standard +在类的继承关系中,有些情况下我们不希望根据父类创建对象,或者说希望 +\begin_inset Flex Emph +status open + +\begin_layout Plain Layout +禁止创建父类对象 +\end_layout + +\end_inset + +。比如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Animal的类层次关系" + +\end_inset + +所示的情形。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oop-project-method/java-polymorphism.eps + width 70col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Animal的类层次关系 +\begin_inset CommandInset label +LatexCommand label +name "fig:Animal的类层次关系" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +如果我们希望禁止创建Animal对象 +\begin_inset Foot +status open + +\begin_layout Plain Layout +为什么有这种需求呢?主要的出发点是强制使用具体的子类对象,因为子类对象比父类对象提供了更具体的属性和方法。 +\end_layout + +\end_inset + +,即只允许创建Dog、Cat等Animal的子类对象,该怎么做呢?Java提供了两种方式: +\end_layout + +\begin_layout Enumerate +使用抽象类 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +抽象类 +\end_layout + +\end_inset + +:将Animal定义为抽象类,这样使用new创建Animal对象将导致语法错误,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:抽象类" + +\end_inset + +。 +\end_layout + +\begin_layout Enumerate +使用接口 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +接口 +\end_layout + +\end_inset + +:将Animal定义为接口,这样便不能直接创建Animal类型的对象,只能通过实现Animal接口创建具体的对象,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:接口" + +\end_inset + +。 +\end_layout + +\begin_layout Subsection +抽象类 +\begin_inset CommandInset label +LatexCommand label +name "subsec:抽象类" + +\end_inset + + +\end_layout + +\begin_layout Standard +只要一个类使用 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +abstract +\end_layout + +\end_inset + +abstract修饰,这个类就是一个抽象类。抽象类不允许通过new操作符创建对象,抽象类只能作为父类被继承。 +\end_layout + +\begin_layout Example +编写一个抽象的Animal类 +\begin_inset CommandInset label +LatexCommand label +name "exa:编写一个抽象的Animal类。" + +\end_inset + +。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "abstractclass-Animal.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "abstractclass-Dog.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "abstractclass-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/abstractclass/Animal.java" +lstparams "float,caption={Animal.java},label={abstractclass-Animal.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/abstractclass/Dog.java" +lstparams "float,caption={Dog.java},label={abstractclass-Dog.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/abstractclass/Client.java" +lstparams "float,caption={Client.java},label={abstractclass-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +动物在打招呼 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +抽象类是不允许直接实例化 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +实例化 +\end_layout + +\end_inset + +的,因此在Client中直接创建Animal类型的对象会报告语法错误。虽然Dog类看起来是一个空的类,但是Dog继承自Animal,因此也继承了Animal中已 +经实现了的公有的hello方法。 +\end_layout + +\begin_layout Subsection +抽象方法 +\end_layout + +\begin_layout Standard +有的时候,我们希望父类的方法仅仅是个声明,即只是说明了方法的名字、返回值类型、参数的类型和个数及其顺序,方法的具体内容(即方法体)需要父类的子类去实现。也就是说 +,父类的这个方法是“抽象”的,因为缺少了方法体,直接调用这个抽象的方法也没有意义,因此Java规定只要类中有一个抽象方法 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +抽象方法 +\end_layout + +\end_inset + +,这个类就必须定义为抽象类。子类在继承抽象类后,必须实现父类中的所有抽象方法,除非该子类也是抽象类。 +\end_layout + +\begin_layout Example +实现一个包含抽象方法的抽象类。 +\begin_inset CommandInset label +LatexCommand label +name "exa:实现一个包含抽象方法的抽象类。" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "abstractmethod-Animal.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "abstractmethod-Dog.java" + +\end_inset + +,Client的设计和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:编写一个抽象的Animal类。" + +\end_inset + +一样,这里不再列出。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/abstractmethod/Animal.java" +lstparams "float,caption={Animal.java},label={abstractmethod-Animal.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/abstractmethod/Dog.java" +lstparams "float,caption={Dog.java},label={abstractmethod-Dog.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +汪汪 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +可以看出,父类中的抽象方法hello在子类中必须给出具体的实现。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +在Idea中,如果没有实现父类中的抽象方法,在类名上面会给出提示信息,此时只要在类名上面按Alt+Enter键组合即可自动给出默认的方法实现,非常方便: +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oop-project-method/abstract-method-hint.png + width 60col% + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +如果Dog类也是抽象类,一定需要实现父类Animal中的抽象方法吗?试修改 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:实现一个包含抽象方法的抽象类。" + +\end_inset + +的Dog为抽象类,然后增加一个Hunter类作为Dog的子类。 +\end_layout + +\begin_layout Subsection +抽象类小结 +\end_layout + +\begin_layout Standard +抽象类是系统架构的常见手段,有两个重要的作用: +\end_layout + +\begin_layout Itemize +强制继承,不允许实例化父类,即必须提供子类才能使用抽象父类的属性和功能。 +\end_layout + +\begin_layout Itemize +便于合理划分(区分)事物的共性和个性,将个性化的部分设计为抽象方法,强制子类实现父类的抽象方法,同时子类中的这些方法其名称、参数和返回值也会受到抽象父类的约束, +这在系统架构和团队合作中显得尤为重要。 +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +要讨论抽象类和多态吗? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +接口 +\begin_inset CommandInset label +LatexCommand label +name "sec:接口" + +\end_inset + + +\end_layout + +\begin_layout Subsection +定义接口:纯的抽象类 +\end_layout + +\begin_layout Standard +如果抽象类中所有的方法都是抽象方法会怎样?比如下面的代码: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public abstract class Animal { +\end_layout + +\begin_layout Plain Layout + + public abstract void hello(); +\end_layout + +\begin_layout Plain Layout + + public abstract void eat(); +\end_layout + +\begin_layout Plain Layout + + public abstract void sleep(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,此时的Animal是一个纯抽象类 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +纯抽象类 +\end_layout + +\end_inset + +,Java提供了interface( +\begin_inset Index idx +status open + +\begin_layout Plain Layout +接口 +\end_layout + +\end_inset + +接口)来表达纯的抽象类,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "interface-Animal.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/pureabstract/Animal.java" +lstparams "float,caption={Animal.java},label={interface-Animal.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Index idx +status open + +\begin_layout Plain Layout +接口 +\end_layout + +\end_inset + +接口具有如下的特点: +\end_layout + +\begin_layout Itemize +接口一定是抽象的,因此接口类不需要明确声明是抽象的。即,在定义接口时,下面的两种方式都是可以的,一般采用省略abstract的写法。 +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public abstract interface Animal{...} +\end_layout + +\begin_layout Plain Layout + +public interface Animal {} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +接口中的方法一定是public的,所以可以省略接口方法的访问控制属性。实际上,在接口方法上使用private或者protected是语法错误,比如尝试在接口方法 +上增加protected: +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public interface Animal { +\end_layout + +\begin_layout Plain Layout + + // 语法错误! +\end_layout + +\begin_layout Plain Layout + + protected void hello(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +正因为接口的以上两个特点,可以认为 +\begin_inset Flex Emph +status open + +\begin_layout Plain Layout +接口是对“纯的抽象类”的简化写法 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Subsection +实现接口 +\end_layout + +\begin_layout Standard +接口虽然很像“纯的抽象类”,但是其用法和用意和抽象类有很多不同,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:抽象类和接口的关系" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +抽象类 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +接口 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +意义 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +概括了一类事物的共同属性和行为特征 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +概括了一类事物的共同行为特征 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法的实现 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +可以实现部分方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +只能声明方法,不允许实现方法 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +使用场合 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +用于明确类的层次关系 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +用于明确类的能力范围 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +用法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +子类通过extends继承父类 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +通过implements实现指定的接口 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +抽象类和接口的关系 +\begin_inset CommandInset label +LatexCommand label +name "tab:抽象类和接口的关系" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +将Animal定义为接口,Dog类实现Animal接口。 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand formatted +reference "interface-Animal.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand formatted +reference "pureabstract-Dog.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand formatted +reference "pureabstract-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/pureabstract/Dog.java" +lstparams "float,caption={Dog.java},label={pureabstract-Dog.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/pureabstract/Client.java" +lstparams "float,caption={Client.java},label={pureabstract-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +汪汪 +\end_layout + +\begin_layout Plain Layout +Dog eat method +\end_layout + +\begin_layout Plain Layout +Dog sleep method +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +Dog类实现了Animal接口即意味着Dog类要给出Animal接口中规定的所有抽象方法的具体实现。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +和实现抽象方法类似,在Idea中,通过快捷键Alt+Enter可自动补全接口的方法,不再赘述。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +实现多个接口 +\begin_inset CommandInset label +LatexCommand label +name "subsec:实现多个接口" + +\end_inset + + +\end_layout + +\begin_layout Standard +对于抽象类,我们知道需要子类继承抽象的父类并实现父类中的所有抽象方法。但是,Java只支持单继承,即一个子类只能继承自一个抽象类。接口则不同, +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +一个类可以“实现”若干个接口 +\end_layout + +\end_inset + +,这也是接口的强大之处。 +\end_layout + +\begin_layout Standard +现实中,事物总是具有多面性的,比如爱因斯坦不仅仅是物理学家,小提琴也拉的很好。比如大家对毛泽东的评价是伟大的思想家、哲学家、军事家、诗人。通常,我们会把一类事物 +的共同行为特征归纳为一个接口,那么具有多面性的事物,应该可以拥有多个接口才对,或者说,具有多面性的事物,应该实现多个接口。 +\end_layout + +\begin_layout Example +实现多个接口的类。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +需要画出类的UML类图 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinterface-Printer.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinterface-Copier.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinterface-SmartPrinter.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinterface-Client.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/multiinterface/Printer.java" +lstparams "float,caption={Printer.java},label={multiinterface-Printer.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/multiinterface/Copier.java" +lstparams "float,caption={Copier.java},label={multiinterface-Copier.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/multiinterface/SmartPrinter.java" +lstparams "float,caption={SmartPrinter.java},label={multiinterface-SmartPrinter.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/multiinterface/Client.java" +lstparams "float,caption={Client.java},label={multiinterface-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行Client结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +print called +\end_layout + +\begin_layout Plain Layout +copy called +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +SmartPrinter实现了两个接口Printer和Copier,也就意味着SmartPrinter同时具有打印和复印两项功能。有人说,这不是多此一举吗?去掉 +两个接口的定义,在SmartPrinter类中直接实现copy和print方法就可以。从功能上看,的确可以这样处理,但是从逻辑上看,不使用接口会带来两个方面的问 +题: +\end_layout + +\begin_layout Itemize +Print和Copy两个接口定义了功能方法的名称和参数,如果不使用接口,或者不实现规定的接口,那么方法名就失去了参照,很容易造成各自为政的局面,给代码的维护和团 +队的交流带来麻烦。 +\end_layout + +\begin_layout Itemize +使用接口带来的另外一个好处是,我们可以通过“向上塑型 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +向上塑型 +\end_layout + +\end_inset + +”加强软件的健壮性,我们将在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:向上塑型:面向接口的编程" + +\end_inset + +展示这一点。 +\end_layout + +\begin_layout Standard +基于以上的分析,其实SmartPrinter的更合理的实现应该是 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinterface-BetterSmartPrinter.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/multiinterface/BetterSmartPrinter.java" +lstparams "float,caption={BetterSmartPrinter.java},label={multiinterface-BetterSmartPrinter.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +可以看出,通过内部类的封装,BetterSmartPrinter类的内部结构更清晰了。 +\end_layout + +\begin_layout Subsection +抽象类和接口的区别 +\end_layout + +\begin_layout Standard +抽象类和接口是从不同的方向来分析和看待事物—抽象类是纵向分析,接口是横向分析。如 +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:抽象类和接口的区别" + +\end_inset + +所示,纵向来看,Bus类描述了公交车的公共属性和方法,Classroom类描述了教室的公共属性和方法。但是在Bus和Classroom类中,某些方法是公共的,比 +如都提供Wifi接入服务和休息座椅,这些在不同事物中的公共方法,横向(切片)来看就是接口的意义。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/oop-project-method/abstract-class-interface.eps + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +抽象类和接口的区别 +\begin_inset CommandInset label +LatexCommand label +name "fig:抽象类和接口的区别" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +试根据 +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:抽象类和接口的区别" + +\end_inset + +编写相应的Bus、Classroom类和接口Wifi、Seat。 +\begin_inset CommandInset label +LatexCommand label +name "exer:试根据编写相应的Bus、Classroom类和接口Wifi、Se" + +\end_inset + +(参见: +\begin_inset CommandInset ref +LatexCommand vref +reference "solu:abstract class and interface" + +\end_inset + +) +\end_layout + +\begin_layout Subsection +接口中的常量 +\end_layout + +\begin_layout Standard +接口中除了抽象方法外,也可以持有常量,这也是一种常见的情形。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +需要进一步解释为什么常量是常见情形?JDK中的例子找出来 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +但是,接口中不允许持有变量。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +需要进一步解释为什么? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +接口的继承 +\end_layout + +\begin_layout Standard +接口是“纯的抽象类”,因此接口和其他类一样,也可以实现继承关系,即接口的继承和类的继承有相同的语法和限制,不再赘述。 +\end_layout + +\begin_layout Subsection +接口中的默认方法 +\begin_inset Foot +status open + +\begin_layout Plain Layout +自JDK8开始支持此特性。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +TBD +\begin_inset Note Note +status open + +\begin_layout Plain Layout +可以参考:http://www.cnblogs.com/guangshan/p/4889732.html +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +不懂接口的项目经理不是好的项目经理 +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:实现多个接口" + +\end_inset + +中我们已经看到,通过接口可以帮助我们规划模块的调用界面(界限),这在团队协作中非常重要,也就是说,接口为团队协作提供了有力的语法支持,考虑下面的情形: +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oop-project-method/no-interface.eps + width 90col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +不引入接口时的团队协作 +\begin_inset CommandInset label +LatexCommand label +name "fig:不引入接口时的团队协作" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +如果不使用接口,团队成员在功能实现时,在方法命名和方法规划上就失去了约束,这在小型项目中也许还是可以接受的,但是随着项目规模的增大,项目成员的增加和更迭,这种没 +有约束的编码方式很容易把项目带到沟里,最终失去控制,导致项目失败。因此,作为 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +项目经理 +\end_layout + +\end_inset + +项目经理或者项目的架构师 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +架构师 +\end_layout + +\end_inset + +,接口是一个有力的工具,在项目之初可以通过定义一系列接口的方式规定模块功能和模块之间的交互界面,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:引入接口后的团队协作" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oop-project-method/with-interface.eps + width 90col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +引入接口后的团队协作 +\begin_inset CommandInset label +LatexCommand label +name "fig:引入接口后的团队协作" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +分别实现 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:不引入接口时的团队协作" + +\end_inset + +所示的代码和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "fig:引入接口后的团队协作" + +\end_inset + +所示的代码,认真体会接口在团队协作中的作用。 +\end_layout + +\begin_layout Subsection +接口上的匿名内部类 +\begin_inset CommandInset label +LatexCommand label +name "subsec:接口上的匿名内部类" + +\end_inset + + +\end_layout + +\begin_layout Standard +如果我们确定一个对象只临时使用一次,那么这个对象通常可以采用匿名内部类 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +匿名内部类 +\end_layout + +\end_inset + +的方式来实现,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:匿名内部类" + +\end_inset + +。如果这个临时的对象只是实现了某个接口,那么代码还可以进一步简化,直接可以使用“接口上的匿名类”技术来实现,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "annoymousInnerClass-Client.java" + +\end_inset + +所示(Printer接口和Copier接口不变,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinterface-Printer.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinterface-Copier.java" + +\end_inset + +)。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/annoymousinnerclass/Client.java" +lstparams "float,caption={Client.java},label={annoymousInnerClass-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Section +多态 +\begin_inset CommandInset label +LatexCommand label +name "sec:多态" + +\end_inset + + +\end_layout + +\begin_layout Standard +所谓 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +多态 +\end_layout + +\end_inset + +多态,是指对象在不同阶段或者环境下有不同的行为特征,听起来是不是有点“变色龙”的味道? +\end_layout + +\begin_layout Standard +先看一个实例,假设有如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Animal的类层次关系" + +\end_inset + +所示的类层次结构,也就是说,父类Animal有默认的hello()方法,三个子类Dog,Cat,Duke分别重写(overriding)了父类Animal的方法 +hello()。代码实现如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "ploymorphism-Animal.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "ploymorphism-Dog.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "ploymorphism-Cat.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "ploymorphism-Duke.java" + +\end_inset + +、 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "ploymorphism-TestAnimal.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/polymorphism/Animal.java" +lstparams "float,caption={Animal.java},label={ploymorphism-Animal.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/polymorphism/Dog.java" +lstparams "float,caption={Dog.java},label={ploymorphism-Dog.java}" + +\end_inset + + +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/polymorphism/Cat.java" +lstparams "float,caption={Cat.java},label={ploymorphism-Cat.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/polymorphism/Duke.java" +lstparams "float,caption={Duke.java},label={ploymorphism-Duke.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/oopm/src/cn/edu/sdut/softlab/oopm/polymorphism/TestAnimal.java" +lstparams "float,caption={TestAnimal.java},label={ploymorphism-TestAnimal.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +在TestAnimal中,animals数组的每个元素是Animal类型的,貌似调用animal数组元素的hello方法应该打印出“动物在打招呼”,但是执行Te +stAnimal会发现输出结果是: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +汪汪 +\end_layout + +\begin_layout Plain Layout +喵喵 +\end_layout + +\begin_layout Plain Layout +嘎嘎 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,虽然我们调用的是父类对象的方法,但是其实真正执行的却是子类中的方法,这就是 +\begin_inset Flex Noun +status open + +\begin_layout Plain Layout +多态 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +多态 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +。简单的说,多态是指:父类对象调用子类方法。 但是,同一个对象,在不同的运行时间,怎么会有不同的行为呢?这一点是如何做到的?先从对象的存储模型说起。 +\end_layout + +\begin_layout Subsection +对象的概念存储模型 +\begin_inset CommandInset label +LatexCommand label +name "subsec:对象的存储模型" + +\end_inset + + +\end_layout + +\begin_layout Standard +在上面的例子中,Dog、Cat、Duke类的对象在内存中是如何存储的呢?比如当Dog dog = new Dog()创建了一个Dog类的实例,则在内存中的存储如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java对象在内存中的存储模型" + +\end_inset + +所示 +\begin_inset Foot +status open + +\begin_layout Plain Layout +提请读者注意的是,为了简化问题的描述和避免过多的底层细节,本节的对象存储模型仅仅为了大家理解方便,并非对象在内存的真实存储情形。更多的细节请读者参考Java虚拟 +机规范 +\begin_inset CommandInset citation +LatexCommand cite +key "jvm-se8-specification" +literal "true" + +\end_inset + +,推荐阅读《深入理解Java虚拟机》 +\begin_inset CommandInset citation +LatexCommand cite +key "jvm-advanced-feature" +literal "true" + +\end_inset + +一书。 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Wrap figure +lines 0 +placement r +overhang 0in +width "50line%" +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oop-project-method/java-instance-storage.eps + width 100line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java对象在内存中的存储模型 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java对象在内存中的存储模型" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +其中,dog是对象的引用,即指针,指向对象在内存的起始地址。对象在内存中的存储分为两个部分:父类的属性和方法存储区域以及子类的属性和方法存储区域,也就是说,子类 +完全包含了父类的所有信息。因此可以看出,我们得到了一个指向子类的引用dog,这个引用dog即可以访问子类的方法和属性,也可以访问父类的方法和属性,无非是通过do +g指针不同的偏移量指向不同的区域而已。 +\end_layout + +\begin_layout Standard +那么Animal dog = new Dog()是什么意思呢?从 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java对象在内存中的存储模型" + +\end_inset + +可以看出,此时的dog指针仍然是指向整个Dog对象的指针,但是指针的范围却局限于父类Animal的区域,也就是说,此时的dog指针只能调用父类Animal中的属 +性和方法,而不能调用Dog子类扩展了的属性和方法。 +\end_layout + +\begin_layout Standard +如果子类没有重写 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +重写 +\end_layout + +\end_inset + +(orverriding)父类的方法,子类和父类的存储是泾渭分明的。如果子类重写(orverriding)了父类中的方法,那么父类中被重写的方法同样会发生变化, +即变的和子类中重写的方法一模一样,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:存在重写情况下的类存储结构" + +\end_inset + +所示。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这样的讲述是有问题的,试想super.hello()方法的调用过程? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oop-project-method/java-instance-storage1.eps + width 60line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +存在重写情况下的类存储结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:存在重写情况下的类存储结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +可以看出,当子类重写了父类中的方法时,父类存储区域中被重写的方法就变得和子类中的方法一模一样了,这样就能够理解本文刚开始的例子了:虽然animals数组的元素都 +是Animal类型的对象,但是由于这三个引用分别指向了Dog、Cat、Duke的对象,而Dog等对象重写了Animal中的hello方法,致使我们虽然调用的是父 +类中的方法,但是由于子类重写了父类中的这个方法,父类中的这个方法变得和子类中的方法一模一样了(即所谓的overriding,重写),最终的效果和直接调用子类中的 +方法一样,这就是Java中的多态,其实也是我们期望发生的事情。 +\end_layout + +\begin_layout Subsection +方法重载时的情形 +\end_layout + +\begin_layout Standard +在上例中,如果子类不是重写(overriding)父类的方法,而是 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +重载 +\end_layout + +\end_inset + +重载(overloading)父类的方法,结果会怎样呢?比如,Cat类的hello方法改为(Dog/Duke以此类推): +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public void hello(String name){ +\end_layout + +\begin_layout Plain Layout + + System.out.println("喵喵" + name); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,Cat类的hello方法重载了父类的hello方法。执行TestAnimal的结果是: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +动物在打招呼 +\end_layout + +\begin_layout Plain Layout +动物在打招呼 +\end_layout + +\begin_layout Plain Layout +动物在打招呼 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +根据 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:存在重载情况的类存储结构" + +\end_inset + +可自行分析执行结果。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/oop-project-method/java-instance-storage2.eps + width 60line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +存在重载情况的类存储结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:存在重载情况的类存储结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +多态的小结 +\end_layout + +\begin_layout Standard +可以看出,Java的多态是一种“动态绑定”技术,即在运行时决定调用哪个方法。多态的使用需要满足三个条件: +\end_layout + +\begin_layout Enumerate +继承 +\end_layout + +\begin_layout Enumerate +重写 +\end_layout + +\begin_layout Enumerate +父类引用指向子类对象 +\end_layout + +\begin_layout Subsection +多态的应用场合 +\end_layout + +\begin_layout Standard +从以上的分析可以看出,通常会利用方法的重写来达到简化代码的目的,即充分利用Java的多态特性。也就是说,在多态的帮助下,我们只需要调用父类的方法就可以了,具体执 +行的却是子类的对应方法。当然,这里有一个前提,即必须使用子类创建对象的引用,否则多态也就失效了。 +\end_layout + +\begin_layout Exercise +请说明实现Java多态的关键是什么? +\end_layout + +\begin_layout Section +*向上塑型:面向接口的编程 +\begin_inset CommandInset label +LatexCommand label +name "sec:向上塑型:面向接口的编程" + +\end_inset + + +\end_layout + +\begin_layout Standard +从 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:对象的存储模型" + +\end_inset + +可以看出,子类对象拥有父类对象的所有属性和方法(当然,在访问控制的限制下),反过来说,父类对象的属性和方法是子类对象的一个子集,因此把子类对象转换为一个父类对象 +是安全的,也就是说,如果我们持有一个子类对象的引用,可以安全的把这个引用转换为父类对象的引用,因为通过这个父类对象的引用,我们访问任何属性和方法都是“可达”的, +都不会引起任何错误。 +\end_layout + +\begin_layout Standard +但是反过来是不可行的,即把父类对象转换为子类对象。原因很简单,转换后的子类对象引用仍然指向了父类对象,但是却可能试图访问超出了父类对象范围的属性和方法,显然是不 +允许的。 +\end_layout + +\begin_layout Standard +这就是Java中的“向上塑型 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +向上塑型 +\end_layout + +\end_inset + +”,即对象的引用可以向父类的方向转换,但是不允许向子类的方向转换。在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "ploymorphism-TestAnimal.java" + +\end_inset + +中,我们已经看到了向上塑型的应用,可以说,向上塑型是Java多态的的基本形态。 +\end_layout + +\begin_layout Standard +在编程实践中,我们也经常按照接口向上塑型,即把对象的类型转换为其实现的某个接口,比如我们重写 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "multiinterface-Client.java" + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + public static void main(String[] args) { +\end_layout + +\begin_layout Plain Layout + + Printer sp = new SmartPrinter(); // 向上塑型为接口类型 +\end_layout + +\begin_layout Plain Layout + + sp.print(); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +可以看出,通过向上塑型为父类对象或者接口类型,实际上我们获得了一个“受限”的对象引用,即这个对象引用只能访问原对象的部分属性和方法,一定程度上提高了程序的安全性 +和健壮性:尽量少的对外暴露调用接口。这也符合面向对象编程的封装 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +封装 +\end_layout + +\end_inset + +原则。 +\end_layout + +\begin_layout Subsection +对象的类型 +\end_layout + +\begin_layout Standard +讨论如下的代码片段: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class SmartPrinter extends BasePrinter implements Printer, Copier + { +\end_layout + +\begin_layout Plain Layout + + ... +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +那么以下的用法都是合法的: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +SmartPrinter sp = new SmartPrinter(); +\end_layout + +\begin_layout Plain Layout + +BasePrinter sp = new SmartPrinter(); // 向上塑型为父类对象 +\end_layout + +\begin_layout Plain Layout + +Printer sp = new SmartPrinter(); // 向上塑型为接口类型 +\end_layout + +\begin_layout Plain Layout + +Copier = new SmartPrinter(); // 向上塑型为接口类型 +\end_layout + +\begin_layout Plain Layout + +Object sp = new SmartPrinter(); // Object是所有类的父类 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +一个对象可以有多少种类型?试举例说明。 +\begin_inset CommandInset label +LatexCommand label +name "exer:一个对象可以有多少种类型?试举例说明。" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +此话题说清楚有难度,手头资料似乎不够 +\end_layout + +\begin_layout Plain Layout +子类(subtyping)是面向对象编程的重要概念, +\end_layout + +\begin_layout Definition +子类替换原则 +\begin_inset CommandInset citation +LatexCommand cite +after "2.1" +key "java-generics-collections" +literal "true" + +\end_inset + +是指,凡是我们期望一个对象的时候,都可以使用这个对象的子类对象来替代。 +\end_layout + +\begin_layout Definition +子类替换有两种常见情形: +\end_layout + +\begin_layout Enumerate +使用子类赋值 +\end_layout + +\begin_layout Enumerate +使用子类替换参数 +\end_layout + +\end_inset + + +\end_layout + +\end_body +\end_document diff --git a/guide/lecture_guide/lecture7.lyx b/guide/lecture_guide/lecture7.lyx new file mode 100644 index 0000000..7e649d8 --- /dev/null +++ b/guide/lecture_guide/lecture7.lyx @@ -0,0 +1,7179 @@ +#LyX 2.3 created this file. For more info see http://www.lyx.org/ +\lyxformat 544 +\begin_document +\begin_header +\save_transient_properties true +\origin unavailable +\textclass ctex-book +\begin_preamble +\input{../../../writing-common/book-preamble.tex} +\end_preamble +\use_default_options true +\begin_modules +note-inset +tip-inset +warning-inset +theorems-bytype +theorems-chap-bytype +coderemarks +logicalmkup +\end_modules +\maintain_unincluded_children false +\begin_local_layout +PackageOptions url hyphens +\end_local_layout +\language chinese-simplified +\language_package default +\inputencoding utf8-plain +\fontencoding global +\font_roman "default" "DejaVu Sans" +\font_sans "default" "DejaVu Serif" +\font_typewriter "default" "DejaVu Sans Mono" +\font_math "auto" "auto" +\font_default_family default +\use_non_tex_fonts true +\font_sc false +\font_osf false +\font_sf_scale 100 100 +\font_tt_scale 100 100 +\use_microtype false +\use_dash_ligatures true +\graphics default +\default_output_format pdf4 +\output_sync 0 +\bibtex_command default +\index_command default +\float_placement tbph +\paperfontsize default +\spacing single +\use_hyperref true +\pdf_bookmarks true +\pdf_bookmarksnumbered false +\pdf_bookmarksopen false +\pdf_bookmarksopenlevel 3 +\pdf_breaklinks true +\pdf_pdfborder true +\pdf_colorlinks true +\pdf_backref false +\pdf_pdfusetitle true +\papersize default +\use_geometry false +\use_package amsmath 1 +\use_package amssymb 1 +\use_package cancel 1 +\use_package esint 1 +\use_package mathdots 1 +\use_package mathtools 1 +\use_package mhchem 1 +\use_package stackrel 1 +\use_package stmaryrd 1 +\use_package undertilde 1 +\cite_engine basic +\cite_engine_type default +\biblio_style plain +\use_bibtopic false +\use_indices false +\paperorientation portrait +\suppress_date false +\justification true +\use_refstyle 1 +\use_minted 0 +\boxbgcolor #dad3d7 +\index Index +\shortcut idx +\color #008000 +\end_index +\secnumdepth 3 +\tocdepth 2 +\paragraph_separation indent +\paragraph_indentation default +\is_math_indent 0 +\math_numbering_side default +\quotes_style english +\dynamic_quotes 0 +\papercolumns 1 +\papersides 2 +\paperpagestyle default +\tracking_changes false +\output_changes false +\html_math_output 0 +\html_css_as_file 0 +\html_be_strict false +\end_header + +\begin_body + +\begin_layout Standard +\align center + +\size larger +\bar under +山东理工大学教案 +\end_layout + +\begin_layout Standard +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +第七次课 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +教学课型:理论课□√ 实验课□√ 习题课□ 实践课□ 技能课□ 其它□ +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +主要教学内容 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:字符串处理" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:字符串处理" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:数字类" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:数字类" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:日期和时间类" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:日期和时间类" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +重点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +字符串类String的构造方法和各种类方法; +\end_layout + +\begin_layout Enumerate +字符串、数字和数字包裹类的转换关系; +\end_layout + +\begin_layout Enumerate +日期、时间的表示方法和处理方法; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +难点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +字符串、数字和数字包裹类的转换关系 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +课程目标及要求 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +课程目标:课程目标1 +\end_layout + +\begin_layout Plain Layout +要求: +\end_layout + +\begin_layout Enumerate +熟练掌握String类的常见构造方法和字符串的处理方法; +\end_layout + +\begin_layout Enumerate +熟练掌握字符串、数字和数字包裹类的相互转换方法; +\end_layout + +\begin_layout Enumerate +了解日期、时间相应的API。 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +教学方法和手段 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +板书和多媒体相结合,边讲边练,当堂消化。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +讨论、思考题 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +String是Java的基本数据类型吗? +\end_layout + +\begin_layout Enumerate +字符串、数字和数字包裹类的相互转换有什么规律可循? +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +参考资料 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Chapter +Java的常用类 +\begin_inset CommandInset label +LatexCommand label +name "chap:Java的常用类" + +\end_inset + + +\end_layout + +\begin_layout Standard +\align center +\begin_inset Graphics + filename ../imgs/essentail-classes/essentail-classes.png + width 70line% + +\end_inset + + +\end_layout + +\begin_layout Section +字符串类 +\begin_inset CommandInset label +LatexCommand label +name "sec:字符串处理" + +\end_inset + + +\end_layout + +\begin_layout Standard +字符和字符串是程序设计中最常见的数据类型了。在C语言中只有字符类型,字符串需要通过字符数组或者指向字符的指针来表达,而Java直接提供了String类 +\begin_inset Foot +status open + +\begin_layout Plain Layout +建议将JDK API的文档常置手边,方便查询。JDK9以后,本教程中涉及到的API转移到了java.base模块中,相应的在线文档为(以Java9为例,更新的版本 +只需要将其中的数字9替换为更新的版本号即可): +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://docs.oracle.com/javase/9/docs/api/java.base-summary.html +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +来表示字符串,对字符串的处理就方便多了。 +\end_layout + +\begin_layout Subsection +字符串对象的定义和初始化 +\end_layout + +\begin_layout Standard +创建字符串对象的最简单方法是直接使用双引号初始化字符串: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +String hello = "Hello, World!"; +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +除此之外,JDK10提供了多达15个构造方法可以用来创建字符串对象 +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见:http://docs.oracle.com/javase/10/docs/api/java/lang/String.html +\end_layout + +\end_inset + +,在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "essentials-Client.java" + +\end_inset + +中演示了创建字符串对象的常见形式。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/essentials/src/cn/edu/sdut/softlab/essentials/string/Client.java" +lstparams "float,caption={创建字符串对象的几种方法},label={essentials-Client.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +请读者思考以下两种方式创建字符串对象的区别: +\end_layout + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +String hello = "hello world!"; +\end_layout + +\begin_layout Plain Layout + +String hello = new String("hello, world!"); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +第一种方式在内存中只创建了一个字符串对象hello,第二种方式则创建了两个字符串对象:hello和字符串内容为“hello world!”的匿名对象。实际上,双 +引号括起来的字符串一般都会在内存中创建一个匿名对象。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Warning +status open + +\begin_layout Plain Layout +注意双引号和单引号的用法区别:双引号用来表示字符串,单引号用来表示字符,比如: +\end_layout + +\begin_layout Plain Layout +String str = +\begin_inset Quotes eld +\end_inset + +a string +\begin_inset Quotes erd +\end_inset + +;// 一个字符串对象 +\end_layout + +\begin_layout Plain Layout +char c = 'A'; // 一个字符变量 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +常见字符串处理方法 +\end_layout + +\begin_layout Subsubsection* +求字符串的长度 +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +字符串结束符?在这里讲解字符串的不变性? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +获取字符串的长度使用String类提供的length()方法: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +String str = "a string"; +\end_layout + +\begin_layout Plain Layout + +System.out.println(str.length()); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +length方法返回的字符串长度不包括“字符串结束符 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +字符串结束符 +\end_layout + +\end_inset + +” +\begin_inset Foot +status open + +\begin_layout Plain Layout +在C语言中,每个字符串都有一个字符串结束符,即' +\backslash +0',在计算字符串的长度时不包括字符串结束符。 +\end_layout + +\end_inset + +,因此上面的代码片段输出结果为8。 +\end_layout + +\begin_layout Subsubsection* +截取字符串 +\end_layout + +\begin_layout Standard +如果把字符串看做字符的有序序列,那么我们可以任意截取这个字符序列的一小段,String类提供了substring方法,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "SubStringTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/essentials/src/cn/edu/sdut/softlab/essentials/string/SubStringTest.java" +lstparams "float,caption={SubStringTest.java},label={SubStringTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +一个常见的任务是去掉字符串开头或者末尾的某个特殊字符,比如字符串 +\begin_inset Quotes eld +\end_inset + +zhangsan,lisi, +\begin_inset Quotes erd +\end_inset + +,我们希望去掉最后的逗号变成 +\begin_inset Quotes erd +\end_inset + +zhagnsan,lisi +\begin_inset Quotes erd +\end_inset + +,可以使用下面的代码: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +String str = "zhangsan,lisi,"; +\end_layout + +\begin_layout Plain Layout + +System.out.println(str.substring(0,str.length() - 1)); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +注意到,substring方法中,开始字符串的索引和结束字符串的索引都是从0开始的。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +如果仅仅是去掉字符串两端的空白字符(包括空格、回车、Tab),则可以使用String提供的trim()方法,这在WEB开发中很常见:用户从浏览器输入的表单中输入 +的字符串一般需要使用trim处理一下,去掉用户无意中输入的空白字符。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection* +分割字符串 +\begin_inset CommandInset label +LatexCommand label +name "subsec:分割字符串" + +\end_inset + + +\end_layout + +\begin_layout Standard +有的字符串存在明显的分隔符,比如linux的passwd文件,使用“:”隔开了各个区域: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +root:x:0:0:root:/root:/bin/bash +\end_layout + +\begin_layout Plain Layout +daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin +\end_layout + +\begin_layout Plain Layout +bin:x:2:2:bin:/bin:/usr/sbin/nologin +\end_layout + +\begin_layout Plain Layout +sys:x:3:3:sys:/dev:/usr/sbin/nologin +\end_layout + +\begin_layout Plain Layout +sync:x:4:65534:sync:/bin:/bin/sync +\end_layout + +\begin_layout Plain Layout +games:x:5:60:games:/usr/games:/usr/sbin/nologin +\end_layout + +\begin_layout Plain Layout +man:x:6:12:man:/var/cache/man:/usr/sbin/nologin +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +如何方便的把这类字符串解析为一个字符串数组呢?String提供了方便的split方法: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + String str = "root:x:0:0:root:/root:/bin/bash"; +\end_layout + +\begin_layout Plain Layout + + String[] result = str.split(":"); +\end_layout + +\begin_layout Plain Layout + + for (String s : result) { +\end_layout + +\begin_layout Plain Layout + + System.out.println(s); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +注意到,split方法的参数不仅仅可以是一个简单的字符串,还可以是一个正则表达式 +\begin_inset Foot +status open + +\begin_layout Plain Layout +详情请参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +https://docs.oracle.com/javase/tutorial/essential/regex/ +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +,能够处理复杂的字符串分割的情形。 +\end_layout + +\begin_layout Exercise +编写一个程序,解析Linux的passwd文件,输出用户名和该用户的登录shell。(关于如何打开文件请参阅 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "chap:Java的IO" + +\end_inset + +)。 +\end_layout + +\begin_layout Subsubsection* +拼接字符串 +\begin_inset CommandInset label +LatexCommand label +name "subsec:拼接字符串" + +\end_inset + + +\end_layout + +\begin_layout Standard +Java中拼接两个字符串的方法有以下几种: +\end_layout + +\begin_layout Itemize +重载 +\begin_inset Quotes erd +\end_inset + ++ +\begin_inset Quotes erd +\end_inset + +运算符:Java重载了 +\begin_inset Quotes erd +\end_inset + ++ +\begin_inset Quotes erd +\end_inset + +运算符,允许直接将两个字符串首尾连接起来。注意到如果“+”的两个操作数只要任一个是字符串,另外一个操作数都会自动转换为字符串形式,比如下面的代码片段: +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +String str = "Java " + "cool!"; +\end_layout + +\begin_layout Plain Layout + +int a = 10; +\end_layout + +\begin_layout Plain Layout + +System.out.println("variable a=" + a); // 打印出:variable a=10 +\end_layout + +\begin_layout Plain Layout + +String str2 = a + ""; // 简单的方法把数字a转化为字符串"10" +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +使用String的concat方法可以达到和使用+同样的效果,比如: +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +"java".concat(" language"); //返回 java language +\end_layout + +\begin_layout Plain Layout + +"java".concat(" programming").concat(" language");// 返回java programming language +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +使用String的join方法 +\begin_inset Foot +status open + +\begin_layout Plain Layout +这是一个类方法(静态方法) +\end_layout + +\end_inset + +,这个方法是split方法的“反方法”,比如: +\begin_inset Newline newline +\end_inset + + +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +String message = String.join("-", "Java", "is", "cool"); +\end_layout + +\begin_layout Plain Layout + +// message returned is: "Java-is-cool" +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +StringBuilder类提供了高效处理字符串的功能,通常涉及到大量字符串拼接时,建议使用StringBuilder来完成 +\begin_inset Foot +status open + +\begin_layout Plain Layout +其实当使用“+”连接多个字符串时,最终经过编译后也是通过StringBuilder来完成的。但是为什么说直接使用“+”连接多个字符串的效率不高呢?这涉及到Jav +a的内存回收机制,这里不展开阐述,详情可参见本系列教程的提高篇:性能调整。 +\end_layout + +\end_inset + +: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +StringBuilder sb = new StringBuilder(); +\end_layout + +\begin_layout Plain Layout + +sb.append("Java"); +\end_layout + +\begin_layout Plain Layout + +sb.append("is cool!"); +\end_layout + +\begin_layout Plain Layout + +String str = sb.toString(); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +另外一个和StringBuilder功能类似的类是StringBuffer。StringBuilder和StringBuffer的最大区别是StringBuff +er是线程 +\begin_inset Foot +status open + +\begin_layout Plain Layout +关于线程的概念和用法,请参见本系列教程的提高篇:多线程Java程序设计。 +\end_layout + +\end_inset + +安全的,即StringBuffer可以安全的用于多线程环境。StringBuilder不是线程安全的,因此只能用于单线程环境。由此也可以知道,StringBui +lder的效率要比StringBuffer高一些。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection* +查找(匹配)字符串 +\begin_inset CommandInset label +LatexCommand label +name "subsec:查找(匹配)字符串" + +\end_inset + + +\end_layout + +\begin_layout Standard +分为以下几种情形: +\end_layout + +\begin_layout Itemize +检查是否以特定字符串开头的startsWith +\end_layout + +\begin_layout Itemize +检查是否以特定字符串结尾的endsWith +\end_layout + +\begin_layout Itemize +检查是否包含特定字符串的contains +\end_layout + +\begin_layout Itemize +检查字符串是否满足正则表达式的matches +\end_layout + +\begin_layout Example +综合示例String的字符串匹配方法 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "StringMatch.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/essentials/src/cn/edu/sdut/softlab/essentials/string/StringMatchTest.java" +lstparams "float,caption={StringMatch.java},label={StringMatch.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +这里尤其要注意matches方法,其参数是一个正则表达式 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +由于本书没有讲述正则表达式,这里仅仅提及,将来可以补充一个交叉链接进来 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Subsubsection* +其他字符串处理方法 +\end_layout + +\begin_layout Standard +JDK的String类提供了丰富的字符串处理功能,除了上面介绍的常见方法外,还有如下的方法也很常用,请大家自行参考 +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +http://docs.oracle.com/javase/8/docs/api/java/lang/String.html +\end_layout + +\end_inset + + 学习: +\end_layout + +\begin_layout Itemize +根据索引提取字符串中的字符:charAt +\end_layout + +\begin_layout Itemize +比较两个字符串:equals +\end_layout + +\begin_layout Itemize +比较两个字符串(忽略大小写)equalsIgnoreCase +\end_layout + +\begin_layout Itemize +判断字符串是否为空:isEmpty +\end_layout + +\begin_layout Itemize +替换字符串:replace +\end_layout + +\begin_layout Itemize +转换大小写:toLowerCase,toUppperCase +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +5.1.3 字符串综合示例 +\end_layout + +\begin_layout Plain Layout +在应用需求中,我们会遇到这样的客户需求,要把账单上的小写数据转换为大写的数据。比如对于 +\begin_inset Quotes erd +\end_inset + +308.7 +\begin_inset Quotes erd +\end_inset + +,我们希望得到的结果是“叁佰零捌元柒角”。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +需要补充代码 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Paragraph* +代码说明 +\end_layout + +\begin_layout Plain Layout +暂时没有准备好示例程序 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +Java面试中经常遇到的问题:String str = new String( +\begin_inset Quotes eld +\end_inset + +a string +\begin_inset Quotes erd +\end_inset + +)创建了几个字符串对象?答案是2个: +\begin_inset Quotes erd +\end_inset + +a string +\begin_inset Quotes erd +\end_inset + +作为string构造方法的参数本身是一个字符串对象,根据 +\begin_inset Quotes erd +\end_inset + +a string +\begin_inset Quotes erd +\end_inset + +这个字符串使用String的构造方法又创建了一个字符串对象str,因此这一句创建了2个字符串对象。那么String str = +\begin_inset Quotes eld +\end_inset + +a string +\begin_inset Quotes erd +\end_inset + +创建了几个字符串对象呢?显然是1个。因此可以看出,使用new操作符创建字符串对象一般是没有必要的,徒增Java的内存占用而已。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +来自面试真题:试说明下列代码的执行结果: +\begin_inset CommandInset label +LatexCommand label +name "exer:来自面试真题about StringBuffer" + +\end_inset + + +\end_layout + +\begin_layout Exercise +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class Lianxi { +\end_layout + +\begin_layout Plain Layout + + public static void main(String[] args) { +\end_layout + +\begin_layout Plain Layout + + StringBuffer a = new StringBuffer("a"); +\end_layout + +\begin_layout Plain Layout + + StringBuffer b = new StringBuffer("b"); +\end_layout + +\begin_layout Plain Layout + + append(a,b); +\end_layout + +\begin_layout Plain Layout + + System.out.println(a); +\end_layout + +\begin_layout Plain Layout + + System.out.println(b); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + +\end_layout + +\begin_layout Plain Layout + + private static void append(StringBuffer a, StringBuffer b) { +\end_layout + +\begin_layout Plain Layout + + a.append(b); +\end_layout + +\begin_layout Plain Layout + + b = a; +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +数字类 +\begin_inset CommandInset label +LatexCommand label +name "sec:数字类" + +\end_inset + + +\end_layout + +\begin_layout Subsection +基本数字类型变量的包裹类 +\end_layout + +\begin_layout Standard +在程序中,当我们用到数字时,一般使用数字的基本数据类型来表达,比如: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +int age = 20; +\end_layout + +\begin_layout Plain Layout + +float money = 23456.5f; +\end_layout + +\begin_layout Plain Layout + +byte mask = 0xff; +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +如果需要对数字做更深入的处理怎么办呢?Java提供了各种基本数字类型的包裹类 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +包裹类 +\end_layout + +\end_inset + +(Wrapper Class),如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:java中的数字类型包裹类" + +\end_inset + +所示。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +BigDecimal的讲解?放到精度控制中? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/essentail-classes/number-classes.eps + lyxscale 60 + width 60col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +java中的数字类型包裹类 +\begin_inset CommandInset label +LatexCommand label +name "fig:java中的数字类型包裹类" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +一般以下情形中,我们需要数字类型的包裹类: +\end_layout + +\begin_layout Itemize +有的方法参数明确声明需要一个数字类型的对象,比如:int toInt(Integer obj) +\begin_inset Note Note +status open + +\begin_layout Plain Layout +从openjdk中找到这样的一个方法 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Itemize +使用包裹类中定义的常量,比如MAX_VALUE,MIN_VALUE,SIZE,TYPE等。 +\end_layout + +\begin_layout Itemize +在数字和字符串之间转换或者不同数制之间转换时。 +\end_layout + +\begin_layout Standard +所有Number的子类都实现了的方法如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Number子类的方法列表" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +byte byteValue() +\end_layout + +\begin_layout Plain Layout +short shortValue() +\end_layout + +\begin_layout Plain Layout +int intValue() +\end_layout + +\begin_layout Plain Layout +long longValue() +\end_layout + +\begin_layout Plain Layout +float floatValue() +\end_layout + +\begin_layout Plain Layout +double doubleValue() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +返回请求的基本数字类型数值,可能存在损失精度情况,比如一个Double类型的对象使用intValue时。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +int compareTo(Byte anotherByte) +\end_layout + +\begin_layout Plain Layout +int compareTo(Double anotherDouble) +\end_layout + +\begin_layout Plain Layout +int compareTo(Float anotherFloat) +\end_layout + +\begin_layout Plain Layout +int compareTo(Integer anotherInteger) +\end_layout + +\begin_layout Plain Layout +int compareTo(Long anotherLong) +\end_layout + +\begin_layout Plain Layout +int compareTo(Short anotherShort) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +数字类型对象的比较,返回值的意义: +\end_layout + +\begin_layout Plain Layout +0:两个数字类型对象代表的数字相等 +\end_layout + +\begin_layout Plain Layout +<0:本数字类型对象小于参数中的数字类型对象 +\end_layout + +\begin_layout Plain Layout +>0:本数字类型对象大于参数中的数字类型对象 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +boolean equals(Object obj) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +覆盖了Object类的equals方法,仅当两个包裹对象不是Null并且代表的数字相等时返回true。不过有两个例外情况,请参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +http://docs.oracle.com/javase/8/docs/api/java/lang/Number.html +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Number子类的方法列表 +\begin_inset CommandInset label +LatexCommand label +name "tab:Number子类的方法列表" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +Number子类的公共方法。 +\begin_inset CommandInset label +LatexCommand label +name "exa:Number子类的公共方法。" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "WrapperNumberTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/essentials/src/cn/edu/sdut/softlab/essentials/number/WrapperNumberTest.java" +lstparams "float,caption={WrapperNumberTest.java},label={WrapperNumberTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行WrapperNumberTest结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Integer max value=2147483647 +\end_layout + +\begin_layout Plain Layout +Short max value=32767 +\end_layout + +\begin_layout Plain Layout +Long max value=9223372036854775807 +\end_layout + +\begin_layout Plain Layout +Float max value=3.4028235E38 +\end_layout + +\begin_layout Plain Layout +Double max value=1.7976931348623157E308 +\end_layout + +\begin_layout Plain Layout +byteValue=123 +\end_layout + +\begin_layout Plain Layout +intValue=123 +\end_layout + +\begin_layout Plain Layout +shortValue=123 +\end_layout + +\begin_layout Plain Layout +longValue=123 +\end_layout + +\begin_layout Plain Layout +floatValue=123.45 +\end_layout + +\begin_layout Plain Layout +doubleValue=123.44999694824219 +\end_layout + +\begin_layout Plain Layout +compareTo 123.45f=0 +\end_layout + +\begin_layout Plain Layout +eqauls 123.45f=true +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +可以看出,从float到byte、int、short、long转换时丢失了精度,在实际编程实践中,要根据具体需求需用合适的xxxValue方法获得相应的基本类型 +数值。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +\begin_inset Index idx +status open + +\begin_layout Plain Layout +自动装箱 +\end_layout + +\end_inset + +自动装箱(autoboxing) +\end_layout + +\end_inset + +和 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +自动拆箱 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +自动拆箱 +\end_layout + +\end_inset + +(unboxing) +\end_layout + +\end_inset + +是指Java编译器自动在基本数据类型和其包裹类之间转换,即在需要一个包裹类的地方,我们只需要给出一个基本类型的数字即可,Java编译器会自动将这个基本类型的数字 +转化为一个相应的包裹类的对象,称为“自动装箱”,相反的过程称为“自动拆箱”。比如在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "WrapperNumberTest.java" + +\end_inset + +中,我们使用自动装箱机制初始化一个Float类型的对象:Float num = 123.45f。 +\end_layout + +\begin_layout Plain Layout +在Java编程实践中建议使用自动装箱和卸箱机制来处理基本数字类型变量和对象之间的转换,简化了代码,也提高了代码的可读性。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +根据 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:Number子类的公共方法。" + +\end_inset + +,请写出其他数字类的公共方法的测试类。 +\end_layout + +\begin_layout Subsection +不同数字类型之间的转换 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Integer、int、字符串之间的相互转换方法" + +\end_inset + +,这里以Integer为例,给出了Integer、int和字符串之间相互转换的方法,其他类型的数值之间的转换类似。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/essentail-classes/integer-string-Integer.eps + width 95line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Integer、int、字符串之间的相互转换方法 +\begin_inset CommandInset label +LatexCommand label +name "fig:Integer、int、字符串之间的相互转换方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Integer的转换方法" + +\end_inset + +列出了Integer支持的转换方法(全部是 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +类方法 +\end_layout + +\end_inset + +)。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +static Integer decode(String s) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +将字符串转换为整数,可以接收十进制、八进制和十六进制的表示方式。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +static int parseInt(String s) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +将字符串转换为整数,最常见的使用方式,只接受十进制表示方式。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +static int parseInt(String s, int radix) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +将字符串转换为整数,radix为进制形式,可以为10,2,8,16。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +String toString() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +将数字转换为字符串。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +static String toString(int i) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +静态方法,将给定的整数转换为字符串。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +static Integer valueOf(int i) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据给定的整数创建一个整数对象。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +static Integer valueOf(String s) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据给定的字符串创建一个整数对象。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +static Integer valueOf(String s, int radix) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据给定的字符串和进制形式创建一个整数对象。 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Integer的转换方法 +\begin_inset CommandInset label +LatexCommand label +name "fig:Integer的转换方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +演示数字之间的转换。 +\begin_inset CommandInset label +LatexCommand label +name "exa:演示数字之间的转换。" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "NumberTest.java" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/essentials/src/cn/edu/sdut/softlab/essentials/number/NumberTest.java" +lstparams "float,caption={NumberTest.java},label={NumberTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行NumberTest结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +10 +\end_layout + +\begin_layout Plain Layout +16 +\end_layout + +\begin_layout Plain Layout +8 +\end_layout + +\begin_layout Plain Layout +123 +\end_layout + +\begin_layout Plain Layout +num=123 +\end_layout + +\begin_layout Plain Layout +num=123 +\end_layout + +\begin_layout Plain Layout +8 +\end_layout + +\begin_layout Plain Layout +123 +\end_layout + +\begin_layout Plain Layout +123 +\end_layout + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +首先要注意到不同进制数字的表示方式,可以看出,decode方法可以自动判别不同进制的数字字符串并转换为一个整数对象。另外,在将字符串转换为整数时,格式不符的字符 +串会导致Java抛出异常。 +\end_layout + +\begin_layout Exercise +仿照 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:演示数字之间的转换。" + +\end_inset + +,写一个Double类型的数字、字符串之间相互转换的测试类DoubleTest.java。 +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +待补充,数字的格式化输出,作为独立的一节 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +*BigDecimal +\end_layout + +\begin_layout Standard +float和double主要是为了科学计算和工程计算而设计的,其数值的表达和计算结果都是一个近似值,比如float和double无法精确的表示0.1(或者10的任 +何负数次方值),因此在需要精确运算的场合不能使用float和double,比如常见的货币计算 +\begin_inset CommandInset citation +LatexCommand cite +after "p190" +key "effective-java" +literal "true" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +例如,假设你现在有¥10.03,花掉了¥4.36,剩下多少钱呢?如果我们用下面的代码片段计算: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +System.out.println(10.03-4.36); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +结果不是你想要的5.67,而是5.669999999999999。 +\end_layout + +\begin_layout Standard +是不是四舍五入就能解决问题呢?我们看下面的问题: +\end_layout + +\begin_layout Standard +假设你有1元,货架上的铅笔标价分别为0.1元、0.2元、0.3元,直到1元。你打算从0.1元/支的开始,每种买一支,直到买不起为止,请问可以买多少支铅笔,找回多少零头? +这个题目似乎可以用下面的简单代码解决: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + public static void main(String[] args) { +\end_layout + +\begin_layout Plain Layout + + double funds = 1.00; +\end_layout + +\begin_layout Plain Layout + + int itemsBought = 0; +\end_layout + +\begin_layout Plain Layout + + for(double price = .10; funds >= price; price += .10) { +\end_layout + +\begin_layout Plain Layout + + funds -= price; +\end_layout + +\begin_layout Plain Layout + + itemsBought++; +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + +\end_layout + +\begin_layout Plain Layout + + System.out.println(itemsBought + " items bought."); +\end_layout + +\begin_layout Plain Layout + + System.out.println("Charge: ¥" + funds); +\end_layout + +\begin_layout Plain Layout + + +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +问题很简单,显然应该可以买4支铅笔,但是当运行这段代码时,其结果为: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +3 items bought. +\end_layout + +\begin_layout Plain Layout +Charge: ¥0.3999999999999999 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +如何正确的解决这个问题呢?或者说,如何精确的表达计算结果呢?答案是使用BigDecimal,或者int、long进行货币运算。使用int、long进行货币运算需 +要我们自己控制金额的放大系数(小数点位置),而BigDecimal则可以帮助我们处理小数点问题,并提供了很多计算功能,比如将上面代码中的double替换为Big +Decimal的后: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + + public static void main(String[] args) { +\end_layout + +\begin_layout Plain Layout + + BigDecimal funds = new BigDecimal("1.00"); +\end_layout + +\begin_layout Plain Layout + + final BigDecimal TEN_CENTS = new BigDecimal(".10"); +\end_layout + +\begin_layout Plain Layout + + int itemsBought = 0; +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + for (BigDecimal price = TEN_CENTS; +\end_layout + +\begin_layout Plain Layout + + funds.compareTo(price) >= 0; +\end_layout + +\begin_layout Plain Layout + + price = price.add(TEN_CENTS)) { +\end_layout + +\begin_layout Plain Layout + + itemsBought++; +\end_layout + +\begin_layout Plain Layout + + funds = funds.subtract(price); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + System.out.println(itemsBought + " items bought."); +\end_layout + +\begin_layout Plain Layout + + System.out.println("Money left over: ¥" + funds); +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +其运行结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +4 items bought. +\end_layout + +\begin_layout Plain Layout +Money left over: ¥0.00 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +编写一个程序,将买铅笔问题使用int或者long处理。提示:找到货币的最小单位,使用最小单位表示单价和金额。 +\end_layout + +\begin_layout Subsubsection +BigDecimal的常见构造方法 +\end_layout + +\begin_layout Standard +见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:BigDecimal的常见构造方法" + +\end_inset + +,按照使用方便性列出了常见的BigDecimal构造方法 +\begin_inset Foot +status open + +\begin_layout Plain Layout +完整的构造方法列表参见:http://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +构造方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +示例 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public BigDecimal(String val) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +使用字符串构造BigDecimal对象 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +new BigDecimal( +\begin_inset Quotes eld +\end_inset + +123.456 +\begin_inset Quotes erd +\end_inset + +); +\end_layout + +\begin_layout Plain Layout +new BigDecimal( +\begin_inset Quotes eld +\end_inset + +-123.456 +\begin_inset Quotes erd +\end_inset + +); +\end_layout + +\begin_layout Plain Layout +new BigDecimal( +\begin_inset Quotes eld +\end_inset + +1.23E3 +\begin_inset Quotes erd +\end_inset + +); +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public BigDecimal(int val) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +使用基本的整数构造BigDecimal对象 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +new BigDecimal(123); +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public BigDecimal(long val) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +使用基本的long构造BigDecimal对象 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +new BigDecimal(123L); +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public BigDecimal(double val) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +使用基本的double构造BigDecimal对象 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +new BigDecimal(123.456D); +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public BigDecimal(char[] in) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +使用字符序列构造BigDecimal对象 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +char in = {'1','2','3'}; +\end_layout + +\begin_layout Plain Layout +new BigDecimal(in); +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +BigDecimal的常见构造方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:BigDecimal的常见构造方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +BigDecimal提供的计算方法 +\end_layout + +\begin_layout Standard +BigDecimal不仅可以任意精度的数字,还提供了如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:BigDecimal的计算方法" + +\end_inset + +所示的计算方法。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法名称 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +示例 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public BigDecimal add(BigDecimal augend) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +当前的BigDecimal对象和augend对象相加 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +new BigDecimal( +\begin_inset Quotes eld +\end_inset + +123.456 +\begin_inset Quotes erd +\end_inset + +).add(new BigDecimal( +\begin_inset Quotes eld +\end_inset + +234.5432 +\begin_inset Quotes erd +\end_inset + +)); +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public BigDecimal subtract(BigDecimal subtrahend) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +当前的BigDecimal对象和subtrahend对象相减 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +new BigDecimal( +\begin_inset Quotes eld +\end_inset + +123.456 +\begin_inset Quotes erd +\end_inset + +).substract(new BigDecimal( +\begin_inset Quotes eld +\end_inset + +234.5432 +\begin_inset Quotes erd +\end_inset + +)); +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public BigDecimal multiply(BigDecimal multiplicand) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +当前的BigDecimal对象和multiplicand对象相乘 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +new BigDecimal( +\begin_inset Quotes eld +\end_inset + +123.456 +\begin_inset Quotes erd +\end_inset + +).multiploy(new BigDecimal( +\begin_inset Quotes eld +\end_inset + +234.5432 +\begin_inset Quotes erd +\end_inset + +)); +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public BigDecimal divide(BigDecimal divisor) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +当前的BigDecimal对象和divisor对象相除 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +new BigDecimal( +\begin_inset Quotes eld +\end_inset + +123.456 +\begin_inset Quotes erd +\end_inset + +).divide(new BigDecimal( +\begin_inset Quotes eld +\end_inset + +234.5432 +\begin_inset Quotes erd +\end_inset + +)); +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public BigDecimal pow(int n) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +当前对象的n次方 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +new BigDecimal( +\begin_inset Quotes eld +\end_inset + +123.456 +\begin_inset Quotes erd +\end_inset + +).pow(3); +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +BigDecimal的计算方法 +\begin_inset CommandInset label +LatexCommand label +name "tab:BigDecimal的计算方法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +BigDecimal的舍入处理策略 +\end_layout + +\begin_layout Standard +由于BigDecimal提供的是精确的数值计算,我们经常需要根据实际情况进行适当的舍入处理,BigDecimal提供了多达8种舍入处理模式,这8种舍入模式在Ro +undingMode中定义,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:RoundingMode中定义的8种舍入模式" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +输入数据 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +UP +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +DOWN +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +CEIL +\end_layout + +\begin_layout Plain Layout +-ING +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +FLOOR +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +HALF +\end_layout + +\begin_layout Plain Layout +_UP +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +HALF +\end_layout + +\begin_layout Plain Layout +_DOWN +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +HALF +\end_layout + +\begin_layout Plain Layout +_EVEN +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +UNNECE +\end_layout + +\begin_layout Plain Layout +-SSARY +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +5.5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +6 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +6 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +6 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +6 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +抛出异常 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +2.5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +抛出异常 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +1.6 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +抛出异常 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +1.1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +抛出异常 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +1.0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +-1.0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +-1.1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +抛出异常 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +-1.6 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +抛出异常 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +-2.5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +抛出异常 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +-5.5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-6 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-6 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-6 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +-6 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +抛出异常 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +RoundingMode中定义的8种舍入模式 +\begin_inset CommandInset label +LatexCommand label +name "tab:RoundingMode中定义的8种舍入模式" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +可以看出,HALF_UP即我们最常用的“四舍五入”模式。 +\end_layout + +\begin_layout Standard +下面的代码片段演示了编程实践中的常见情形: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +// 计算结果四舍五入保留2位小数 +\end_layout + +\begin_layout Plain Layout + +new BigDecimal("123.456").multiply(new BigDecimal("1.23")).setScale(2, RoundingMode.H +ALF_UP); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +对于任何需要精确答案的计算任务,请不要使用float或者double。如果你想让系统来记录十进制小数点,并且不介意因为不使用基本类型而带来的不便,请使用BigD +ecimal。使用BigDecimal还有一些额外的好处,允许你完全控制舍入。每当一个计算涉及到舍入的时候,BigDecimal允许你8种舍入模式中选择其一。但 +是BigDecimal有一定的性能问题,即比使用float和double要慢(大约上百倍的差距)。如果性能非常关键,那么使用int或者long处理精确计算问题。 +要注意的是,int最多只能处理9位十进制数字,long最多只能处理18位十进制数字。如果数值可能超过18位,就必须使用BigDecimal。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +日期和时间类 +\begin_inset CommandInset label +LatexCommand label +name "sec:日期和时间类" + +\end_inset + + +\end_layout + +\begin_layout Standard +在Java语言中,日期和时间曾经是一个复杂和混乱的问题 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +有必要讲述ZoneId,时区的概念和用法吗? +\end_layout + +\end_inset + + +\begin_inset Foot +status open + +\begin_layout Plain Layout +关于Java8之前的日期和时间API,在互联网上有大量的吐槽,比如: +\end_layout + +\begin_layout Itemize +JDK BUG吗? 混乱的日期API: +\begin_inset Flex URL +status collapsed + +\begin_layout Plain Layout + +http://www.importnew.com/20098.html +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +为什么我们需要新的Java日期/时间API: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +http://www.importnew.com/14140.html +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +What's wrong with Java Date & Time API: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +http://stackoverflow.com/questions/1969442/whats-wrong-with-java-date-time-api +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +,Java8终于给Java带来了一致的日期和时间实现!Java8的日期和时间类是JSR310 +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见:https://jcp.org/en/jsr/detail?id=310 +\end_layout + +\end_inset + +的一个具体实现,是Java8的重要新特性。本书只介绍Java8中新的日期和时间类API,不再涉及旧的日期和时间API,也建议读者在编写Java应用程序的时候不要 +再使用旧版本的日期和时间API。 +\end_layout + +\begin_layout Subsection +日期操作类:LocalDate +\begin_inset Foot +status open + +\begin_layout Plain Layout +最新的API文档在:https://docs.oracle.com/javase/10/docs/api/java/time/LocalDate.html +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +顾名思义,LocalDate的“本意”似乎是“本地日期”,但是遗憾的是,LocalDate的本意应该是“日期”。这是因为Java8之前的日期类(旧的日期API) +叫做Date,因此新的日期API只好另起炉灶,就被称作“LocalDate”了。LocalDate的常见用法见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:LocalDate的常见用法" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +方法 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static LocalDate now() +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据默认时区获得当前日期 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static LocalDate of(int year, int month, int dayOfMonth) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据给定的年月日创建LocalDate对象 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static LocalDate ofYearDay(int year, int dayOfYear) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据给定的年份和天数创建LocalDate对象 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static LocalDate parse(CharSequence text) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据给定的字符串创建LocalDate对象 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public static LocalDate parse(CharSequence text, DateTimeFormatter formatter) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +根据给定的字符串及其格式创建LocalDate对象 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public String format(DateTimeFormatter formatter) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +格式化输出日期(参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "subsec:日期和时间的格式化输出类:DateTimeFormatter" + +\end_inset + +) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public boolean isAfter(ChronoLocalDate other) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +判断日期对象是否在other日期对象之后 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +public boolean isBefore(ChronoLocalDate other) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +判断日期对象是否在other日期对象之前 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +LocalDate的常见用法 +\begin_inset CommandInset label +LatexCommand label +name "tab:LocalDate的常见用法" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +LocalDate用法示例 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "LocalDateTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/essentials/src/cn/edu/sdut/softlab/essentials/time/LocalDateTest.java" +lstparams "caption={LocalDateTest.java},label={LocalDateTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行LocalDateTest结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Current Date=2016-11-20 +\end_layout + +\begin_layout Plain Layout +Specific Date=2016-01-01 +\end_layout + +\begin_layout Plain Layout +Current Date in IST=2016-11-20 +\end_layout + +\begin_layout Plain Layout +365th day from base date= 1971-01-01 +\end_layout + +\begin_layout Plain Layout +100th day of 2016=2016-04-09 +\end_layout + +\begin_layout Plain Layout +2016-11-21 parsed to LocalDate = 2016-11-21 +\end_layout + +\begin_layout Plain Layout +2016-11-21 < 2016-11-22 ? true +\end_layout + +\begin_layout Plain Layout +2016-11-21 < 2016-11-21 ? false +\end_layout + +\begin_layout Plain Layout +2016-11-22 > 2016-11-21 ? true +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +时间操作类:LocalTime +\begin_inset Foot +status open + +\begin_layout Plain Layout +最新的API文档在:https://docs.oracle.com/javase/10/docs/api/java/time/LocalTime.html +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +LocalTime是表示时间的操作类,其API设计和LocalDate很相似,这里不再详细列出LocalTime的方法,具体可以参考 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:LocalTime类用法示例" + +\end_inset + +。 +\end_layout + +\begin_layout Example +LocalTime类用法示例 +\begin_inset CommandInset label +LatexCommand label +name "exa:LocalTime类用法示例" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "LocalTimeTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/essentials/src/cn/edu/sdut/softlab/essentials/time/LocalTimeTest.java" +lstparams "caption={LocalTimeTest.java},label={LocalTimeTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行LocalTimeTest结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Current Time=15:07:13.774 +\end_layout + +\begin_layout Plain Layout +Specific Time of Day=12:20:25.000000040 +\end_layout + +\begin_layout Plain Layout +Current Time in IST=12:37:13.775 +\end_layout + +\begin_layout Plain Layout +10000th second time= 02:46:40 +\end_layout + +\begin_layout Plain Layout +12:30:55 parsed to LocalDate = 12:30:55 +\end_layout + +\begin_layout Plain Layout +12:30:55 < 13:02:15 ? true +\end_layout + +\begin_layout Plain Layout +12:30:55 < 12:30:55 ? false +\end_layout + +\begin_layout Plain Layout +13:02:15 > 12:30:55 ? true +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +日期时间类:LocalDateTime +\begin_inset Foot +status open + +\begin_layout Plain Layout +最新的API文档在:https://docs.oracle.com/javase/10/docs/api/java/time/LocalDateTime.html +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +LocalDateTime是表示日期时间的操作类,其API设计和LocalDate很相似,这里不再详细列出LocalDateTime的方法,具体可以参考 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:LocalDateTime类用法示例" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +日期(LocalDate)、时间(LocalTime)、日期时间(LocalTime)、字符串之间的相互转化关系参见下图: +\end_layout + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/essentail-classes/date-time-string.eps + width 90line% + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +LocalDateTime类用法示例 +\begin_inset CommandInset label +LatexCommand label +name "exa:LocalDateTime类用法示例" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "LocalDateTimeTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/essentials/src/cn/edu/sdut/softlab/essentials/time/LocalDateTimeTest.java" +lstparams "caption={LocalDateTimeTest.java},label={LocalDateTimeTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +执行LocalDateTimeTest结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Current DateTime=2016-11-20T15:08:15.970 +\end_layout + +\begin_layout Plain Layout +Current DateTime=2016-11-20T15:08:15.971 +\end_layout + +\begin_layout Plain Layout +Specific Date=2014-01-01T10:10:30 +\end_layout + +\begin_layout Plain Layout +Current Date in IST=2016-11-20T12:38:15.972 +\end_layout + +\begin_layout Plain Layout +10000th second time from 01/01/1970= 1970-01-01T02:46:40 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +日期和时间的格式化输出类:DateTimeFormatter +\begin_inset Foot +status open + +\begin_layout Plain Layout +最新的API文档在:https://docs.oracle.com/javase/10/docs/api/java/time/format/DateTimeForm +atter.html +\end_layout + +\end_inset + + +\begin_inset CommandInset label +LatexCommand label +name "subsec:日期和时间的格式化输出类:DateTimeFormatter" + +\end_inset + + +\end_layout + +\begin_layout Standard +在大部分情况下,LocalDate和LocalTime的默认输出即符合预期,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "LocalDateTest.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "LocalTimeTest.java" + +\end_inset + +中LocalDate和LocalTime对象的输出。如果需要定制日期和时间的输出格式,DateTimeFormatter提供了丰富的内置格式支持和可定制选项。D +ateTimeFormatter内置的输出格式如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:DateTimeFormatter的输出格式控制选项" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +格式控制选项 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +描述 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +示例 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ofLocalizedDate(date +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +hspace{0pt} +\end_layout + +\end_inset + +Style) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +Formatter with date style from the locale +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +'2011-12-03' +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ofLocalizedTime(time +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +hspace{0pt} +\end_layout + +\end_inset + +Style) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +Formatter with time style from the locale +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +'10:15:30' +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ofLocalizedDateTime( +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +hspace{0pt} +\end_layout + +\end_inset + +dateTimeStyle) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +Formatter with a style for date and time from the locale +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +'3 Jun 2008 11:05:30' +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ofLocalizedDateTime( +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +hspace{0pt} +\end_layout + +\end_inset + +dateStyle,timeStyle) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +Formatter with date and time styles from the locale +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +'3 Jun 2008 11:05' +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +BASIC_ISO_DATE +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +基本的 ISO 日期格式 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +'20111203' +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ISO_LOCAL_DATE +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ISO Local Date +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +'2011-12-03' +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ISO_OFFSET_DATE +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +显示时区偏移量的 ISO 日期格式 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +'2011-12-03+01:00' +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ISO_DATE +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ISO 日期格式 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +'2011-12-03+01:00'; '2011-12-03' +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ISO_LOCAL_TIME +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +不带时区偏移量的时间格式 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +'10:15:30' +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ISO_OFFSET_TIME +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +带时区偏移量的时间格式 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +'10:15:30+01:00' +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ISO_TIME +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ISO时间格式 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +'10:15:30+01:00'; '10:15:30' +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ISO_LOCAL_DATE +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +hspace{0pt} +\end_layout + +\end_inset + +_TIME +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ISO日期和时间格式 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +'2011-12-03T10:15:30' +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ISO_OFFSET_DATE +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +hspace{0pt} +\end_layout + +\end_inset + +_TIME +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +带时区偏移量的日期时间格式 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +2011-12-03T10:15:30+01:00' +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ISO_ZONED_DATE +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +hspace{0pt} +\end_layout + +\end_inset + +_TIME +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +带时区显示的日期时间格式 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +'2011-12-03T10:15:30+01:00[ +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +hspace{0pt} +\end_layout + +\end_inset + +Europe/Paris]' +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ISO_DATE_TIME +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +带时区显示的日期时间格式 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +'2011-12-03T10:15:30+01:00[ +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +hspace{0pt} +\end_layout + +\end_inset + +Europe/Paris]' +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ISO_ORDINAL_DATE +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +显示年份以及第几天 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +'2012-337' +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ISO_WEEK_DATE +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +显示年份和周次 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +'2012-W48-6' +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +ISO_INSTANT +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +Date and Time of an Instant +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\family roman +\series medium +\shape up +\size normal +\emph off +\bar no +\strikeout off +\uuline off +\uwave off +\noun off +\color none +RFC_1123_DATE_TIME RFC 1123 / RFC 822 'Tue, 3 Jun 2008 11:05:30 GMT' +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +DateTimeFormatter的输出格式控制选项 +\begin_inset CommandInset label +LatexCommand label +name "tab:DateTimeFormatter的输出格式控制选项" + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Note Note +status open + +\begin_layout Plain Layout +需要翻译 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:DateTimeFormatter的输出格式控制选项" + +\end_inset + +中,我们常用的日期和时间格式为ISO_LOCAL_DATE,ISO_LOCAL_TIME,ISO_LOCAL_DATE_TIME。 +\end_layout + +\begin_layout Standard +除了可使用 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +tablename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:DateTimeFormatter的输出格式控制选项" + +\end_inset + +中预定义的日期和时间格式外,ofPattern()方法支持任意模式的日期和时间格式化输出,具体的格式化字符串可以参照DateTimeFormmater的API文 +档,这里不再一一列出。 +\end_layout + +\begin_layout Example +使用DateTimeFormmater定制日期和时间的输出 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "DateTimeFormatterTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/essentials/src/cn/edu/sdut/softlab/essentials/time/DateTimeFormatterTest.java" +lstparams "caption={DateTimeFormatterTest.java},label={DateTimeFormatterTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行DateTimeFormatterTest结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Default format of LocalDate=2016-11-20 +\end_layout + +\begin_layout Plain Layout +20::十一月::2016 +\end_layout + +\begin_layout Plain Layout +20161120 +\end_layout + +\begin_layout Plain Layout +Default format of LocalDateTime=2016-11-20T15:18:44.241 +\end_layout + +\begin_layout Plain Layout +20::十一月::2016 15::18::44 +\end_layout + +\begin_layout Plain Layout +20161120 +\end_layout + +\begin_layout Plain Layout +Default format after parsing = 2014-04-27T21:39:48 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +*日期和时间的调整 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +作为较高要求,可以不写这部分? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +大多数日期/时间API类都实现了一系列工具方法,如:加/减天数、周数、月份数,等等。还有其他的工具方法能够使用TemporalAdjuster调整日期,并计算两 +个日期间的周期。 +\end_layout + +\begin_layout Example +使用日期和时间类调整日期和时间 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "DateTimeAPITest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/essentials/src/cn/edu/sdut/softlab/essentials/time/DateTimeAPITest.java" +lstparams "caption={DateTimeAPITest.java},label={DateTimeAPITest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行DateTimeAPITest结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Year 2016 is Leap Year? true +\end_layout + +\begin_layout Plain Layout +Today is before 01/01/2015? false +\end_layout + +\begin_layout Plain Layout +Current Time=2016-11-20T15:26:02.947 +\end_layout + +\begin_layout Plain Layout +10 days after today will be 2016-11-30 +\end_layout + +\begin_layout Plain Layout +3 weeks after today will be 2016-12-11 +\end_layout + +\begin_layout Plain Layout +20 months after today will be 2018-07-20 +\end_layout + +\begin_layout Plain Layout +10 days before today will be 2016-11-10 +\end_layout + +\begin_layout Plain Layout +3 weeks before today will be 2016-10-30 +\end_layout + +\begin_layout Plain Layout +20 months before today will be 2015-03-20 +\end_layout + +\begin_layout Plain Layout +First date of this month= 2016-11-01 +\end_layout + +\begin_layout Plain Layout +Last date of this year= 2016-12-31 +\end_layout + +\begin_layout Plain Layout +Period Format= P1M11D +\end_layout + +\begin_layout Plain Layout +Months remaining in the year= 1 +\end_layout + +\end_inset + + +\end_layout + +\end_body +\end_document diff --git a/guide/lecture_guide/lecture8.lyx b/guide/lecture_guide/lecture8.lyx new file mode 100644 index 0000000..a35c3f6 --- /dev/null +++ b/guide/lecture_guide/lecture8.lyx @@ -0,0 +1,3197 @@ +#LyX 2.3 created this file. For more info see http://www.lyx.org/ +\lyxformat 544 +\begin_document +\begin_header +\save_transient_properties true +\origin unavailable +\textclass ctex-book +\begin_preamble +\input{../../../writing-common/book-preamble.tex} +\end_preamble +\use_default_options true +\begin_modules +tip-inset +note-inset +warning-inset +theorems-bytype +theorems-chap-bytype +logicalmkup +coderemarks +\end_modules +\maintain_unincluded_children false +\begin_local_layout +PackageOptions url hyphens +\end_local_layout +\language chinese-simplified +\language_package default +\inputencoding utf8-plain +\fontencoding global +\font_roman "default" "DejaVu Sans" +\font_sans "default" "DejaVu Serif" +\font_typewriter "default" "DejaVu Sans Mono" +\font_math "auto" "auto" +\font_default_family default +\use_non_tex_fonts true +\font_sc false +\font_osf false +\font_sf_scale 100 100 +\font_tt_scale 100 100 +\use_microtype false +\use_dash_ligatures true +\graphics default +\default_output_format pdf4 +\output_sync 0 +\bibtex_command default +\index_command default +\float_placement tbph +\paperfontsize default +\spacing single +\use_hyperref true +\pdf_bookmarks true +\pdf_bookmarksnumbered false +\pdf_bookmarksopen false +\pdf_bookmarksopenlevel 3 +\pdf_breaklinks true +\pdf_pdfborder true +\pdf_colorlinks false +\pdf_backref false +\pdf_pdfusetitle true +\papersize default +\use_geometry false +\use_package amsmath 1 +\use_package amssymb 1 +\use_package cancel 1 +\use_package esint 1 +\use_package mathdots 1 +\use_package mathtools 1 +\use_package mhchem 1 +\use_package stackrel 1 +\use_package stmaryrd 1 +\use_package undertilde 1 +\cite_engine basic +\cite_engine_type default +\biblio_style plain +\use_bibtopic false +\use_indices false +\paperorientation portrait +\suppress_date false +\justification true +\use_refstyle 1 +\use_minted 0 +\boxbgcolor #dad3d7 +\index Index +\shortcut idx +\color #008000 +\end_index +\secnumdepth 3 +\tocdepth 2 +\paragraph_separation indent +\paragraph_indentation default +\is_math_indent 0 +\math_numbering_side default +\quotes_style english +\dynamic_quotes 0 +\papercolumns 1 +\papersides 2 +\paperpagestyle default +\tracking_changes false +\output_changes false +\html_math_output 0 +\html_css_as_file 0 +\html_be_strict false +\end_header + +\begin_body + +\begin_layout Standard +\align center + +\size larger +\bar under +山东理工大学教案 +\end_layout + +\begin_layout Standard +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +第八次课 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +教学课型:理论课□√ 实验课□√ 习题课□ 实践课□ 技能课□ 其它□ +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +主要教学内容 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:异常的概念" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:异常的概念" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:C中的异常处理方式" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:C中的异常处理方式" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Java的异常处理方式" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:Java的异常处理方式" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:捕获异常" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:捕获异常" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:抛出异常" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:抛出异常" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +重点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +C和Java异常处理的思路差异; +\end_layout + +\begin_layout Enumerate +Java的异常类层次; +\end_layout + +\begin_layout Enumerate +Java异常的捕获和抛出方式及其原理; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +难点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +Java异常的捕获和抛出原理; +\end_layout + +\begin_layout Enumerate +Java异常的链式责任传递机制; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +课程目标及要求 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +课程目标:课程目标1 +\end_layout + +\begin_layout Plain Layout +要求: +\end_layout + +\begin_layout Enumerate +熟练掌握Java异常的概念和常见Java异常类; +\end_layout + +\begin_layout Enumerate +深刻理解Java异常抛出和捕获的机制,清楚Java异常处理的责任链机制; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +教学方法和手段 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +板书和多媒体相结合,边讲边练,当堂消化。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +讨论、思考题 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +你认为Java的异常处理方式有什么优缺点? +\end_layout + +\begin_layout Enumerate +举例说明Java的异常处理责任链机制是如何运作的? +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +参考资料 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Chapter +异常处理 +\end_layout + +\begin_layout Standard +\align center +\begin_inset Graphics + filename ../imgs/exception/exception-vym.png + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Section +异常的概念 +\begin_inset CommandInset label +LatexCommand label +name "sec:异常的概念" + +\end_inset + + +\end_layout + +\begin_layout Standard +“人生不如意事十之八九” +\begin_inset Foot +status open + +\begin_layout Plain Layout +南宋词人辛弃疾词《贺新郎·用前韵再赋》:“叹人生、不如意事,十常八九。” +\end_layout + +\end_inset + +,编程同样道理:世事纷繁复杂,情况千变万化,代码要正确运行,不仅要处理正常的流程,更要处理多样化的非正常流程。比如常见的情形: +\begin_inset Note Note +status open + +\begin_layout Plain Layout +举例说明异常流程之多样化 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +街头的投币电话,总有人尝试用游戏币看看能不能蒙混过关; +\end_layout + +\begin_layout Itemize +长城的古砖墙是为御敌而生,却被人刻上“到此一游”; +\end_layout + +\begin_layout Itemize +机动车道上的行人,人行道上的机动车; +\end_layout + +\begin_layout Standard +回到现实的程序中,在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:日期和时间类" + +\end_inset + +中,我们看到日期和时间类都定义了一个parse方法,能够将字符串解析为LocalDate、LocalTime或者LocalDateTime对象,很直观,很方便, +因此在编程实践中很常见。试运行下面的示例: +\end_layout + +\begin_layout Example +从键盘输入字符串创建日期对象 +\begin_inset CommandInset label +LatexCommand label +name "exa:从键盘输入字符串创建日期对象" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "WhatIfNoException.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/exception/src/cn/edu/sdut/softlab/exception/WhatIfNoException.java" +lstparams "caption={WhatIfNoException.java},label={WhatIfNoException.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行WhatIfNoException结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100line%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Please input date:2016-11-22 +\end_layout + +\begin_layout Plain Layout +2016-11-22 +\end_layout + +\begin_layout Plain Layout +Please input date:2016-13-22 +\end_layout + +\begin_layout Plain Layout +Exception in thread "main" java.time.format.DateTimeParseException: +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +Text '2016-13-22' could not be parsed: Invalid value for MonthOfYear (valid + values 1 - 12): 13 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +at java.time.format.DateTimeFormatter.createError( +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +hspace{0pt} +\end_layout + +\end_inset + +DateTimeFormatter.java:1920) +\end_layout + +\begin_layout Plain Layout +...... +\end_layout + +\begin_layout Plain Layout +at cn.edu.sdut.softlab.exception.WhatIfNoException.main( +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +hspace{0pt} +\end_layout + +\end_inset + +WhatIfNoException.java:30) +\end_layout + +\begin_layout Plain Layout +Caused by: java.time.DateTimeException: Invalid value for MonthOfYear (valid + values 1 - 12): 13 +\end_layout + +\begin_layout Plain Layout +at java.time.temporal.ValueRange.checkValidIntValue(ValueRange +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +hspace{0pt} +\end_layout + +\end_inset + +.java:330) +\end_layout + +\begin_layout Plain Layout +...... +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:从键盘输入字符串创建日期对象" + +\end_inset + +中,从键盘输入的字符串如果符合LocalDate的格式要求自然一切正常,但是我们不能总是期望人们每次输入都遵循LocalDate的格式,无论人们是有意还是无意, +总会有破坏规则的时候,比如输入的月份大于12、天数大于31等。显然,错误的输入是无法获得正确的LocalDate对象的,Java编译器也无法自动纠正这种类型的错 +误。对于这种情况,Java友好的给出了错误的原因及其关联的程序代码(stack trace),以帮助程序员快速定位错误代码的位置,更快的修复问题。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +实际上,类似 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:从键盘输入字符串创建日期对象" + +\end_inset + +的错误提示方式,对于程序员而言是友好的,但是对于终端用户而言是不友好的:终端用户并不关心程序哪一行出错了。对于终端用户而言,程序应该给出更人性化的提示,比如提示 +“日期格式有错误,月份应该在1-12之间”等等。我们将在 +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:Java的异常处理方式" + +\end_inset + +中介绍如何更人性化的处理。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +C中的异常处理方式 +\begin_inset CommandInset label +LatexCommand label +name "sec:C中的异常处理方式" + +\end_inset + + +\end_layout + +\begin_layout Standard +我们先回顾一下在C语言中如何判断用户的输入是否合法,大致应该是如下的代码片段: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +if(month < 1 || month > 12) { +\end_layout + +\begin_layout Plain Layout + + printf("wrong month num:%d",month); +\end_layout + +\begin_layout Plain Layout + + return -1; +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +if(day < 1 || day > 31) { /* 没有考虑二月份情况 */ +\end_layout + +\begin_layout Plain Layout + + printf("wrong day num:%d",day); +\end_layout + +\begin_layout Plain Layout + + return -1; +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +... +\end_layout + +\begin_layout Plain Layout + +/* 用户的输入合法,下面继续处理正常流程 */ +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,我们只能通过一系列的if条件判断来分析用户的输入是否合法,如果可能的异常情形比较多,势必会存在更多的if条件判断,造成程序的流程不清晰:哪些是正常流程 +处理代码,哪些是异常流程处理代码,除非通过注释标识出来,否则很难一眼看清楚。 +\end_layout + +\begin_layout Section +Java的异常处理方式 +\begin_inset CommandInset label +LatexCommand label +name "sec:Java的异常处理方式" + +\end_inset + + +\end_layout + +\begin_layout Standard +当然,在Java中我们依然可以像C语言那样去处理异常 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +异常 +\end_layout + +\end_inset + +。不过,Java提供了更棒的异常处理机制:将异常情况抽象为异常对象 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +异常对象 +\end_layout + +\end_inset + +,并采用责任链 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +责任链 +\end_layout + +\end_inset + +处理机制处理异常对象。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这部分讲的不清楚 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Java内置了常见的异常类,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java的异常类层次结构" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/exception/exception-overview.eps + width 100col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java的异常类层次结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java的异常类层次结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +当异常情况出现时,Java虚拟机能够“捕获 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +捕获 +\end_layout + +\end_inset + +” +\begin_inset Note Note +status open + +\begin_layout Plain Layout +如何捕获?如何感知?这里可能是许多初学者迷惑的地方。 +\end_layout + +\end_inset + +(catch) +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java虚拟机和Java应用程序的关系" + +\end_inset + +了解Java应用程序和Java虚拟机之间的关系,感性认识Java虚拟机是如何捕获异常的。 +\end_layout + +\end_inset + +异常对象,并根据异常对象的类型进行相应的处理。Java将异常类分为两大类: +\end_layout + +\begin_layout Itemize +\begin_inset Index idx +status open + +\begin_layout Plain Layout +非检查型异常 +\end_layout + +\end_inset + +非检查型异常:即Java虚拟机能够 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +自动 +\end_layout + +\end_inset + +处理的异常类型。换言之,这种类型的异常不需要在程序中捕获,一旦发生这种类型的异常,Java虚拟机有一套内置的处理方式,比如除数为零、数组越界、非法参数等异常类型 +。对应于 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java的异常类层次结构" + +\end_inset + +,Error和RuntimeException的子类都是非检查型异常。在程序中可以不捕获非检查型异常,也可以捕获非检查型异常。捕获非检查型异常的目的往往是给用户 +提供更友好的出错提示,但这不是强制的。 +\end_layout + +\begin_layout Itemize +\begin_inset Index idx +status open + +\begin_layout Plain Layout +检查型异常 +\end_layout + +\end_inset + +检查型异常:即Java虚拟机无法自动处理的异常类型,需要在程序中捕获(catch)。对应于 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java的异常类层次结构" + +\end_inset + +,ClassNotFoundException和IOException的子类都是检查型异常。要注意的是,检查型异常是必须捕获的,否则会导致语法错误,因此在程序中 +捕获检查型异常是强制的。 +\end_layout + +\begin_layout Section +捕获异常 +\begin_inset CommandInset label +LatexCommand label +name "sec:捕获异常" + +\end_inset + + +\end_layout + +\begin_layout Standard +我们首先简单回顾一下Java虚拟机和Java应用程序的关系,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java虚拟机和Java应用程序的关系" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/exception/jvm-java.eps + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java虚拟机和Java应用程序的关系 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java虚拟机和Java应用程序的关系" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Java应用程序编译为class文件后,经过Java虚拟机的类加载器解析class文件在内存中创建相应的存储模型然后执行该应用程序。也就是说,Java虚拟机完全 +掌控Java应用程序的执行过程,包括应用程序出现异常情况时。Java通过如下的程序结构捕获异常: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +try { +\end_layout + +\begin_layout Plain Layout + + // 一段可能存在SomeException类型异常的代码 +\end_layout + +\begin_layout Plain Layout + +} catch (SomeException e) { +\end_layout + +\begin_layout Plain Layout + + e.printStackTrace(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在try块中的代码就是所谓的“ +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +正常流程 +\end_layout + +\end_inset + +”,在catch块中的代码就是所谓的“ +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +异常流程 +\end_layout + +\end_inset + +”。如果异常流程有多种,就存在多个catch块: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +try { +\end_layout + +\begin_layout Plain Layout + + // 一段可能存在SomeException类型异常的代码 +\end_layout + +\begin_layout Plain Layout + +} catch (SomeException e) { +\end_layout + +\begin_layout Plain Layout + + e.printStackTrace(); +\end_layout + +\begin_layout Plain Layout + +} catch (OtherException e) { +\end_layout + +\begin_layout Plain Layout + + e.printStackTrace(); +\end_layout + +\begin_layout Plain Layout + +} catch (FooException e ) { +\end_layout + +\begin_layout Plain Layout + + e.printStackTrace(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +对比C语言中使用if...else结构的异常处理方式,Java的try...catch更清晰的区分了正常流程和异常流程:通过不同的异常类也清晰的表达了异常的类型,甚至无需借 +助注释,只是根据异常类的名字,我们也很容易判断异常的类型及其大致的处理方式。 +\end_layout + +\begin_layout Example +捕获异常 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "DivTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/exception/src/cn/edu/sdut/softlab/exception/DivTest.java" +lstparams "float,caption={DivTest.java},label={DivTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +此例的运行需要配置命令行参,配置方法参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:如何设置命令行参数?" + +\end_inset + + +\end_layout + +\begin_layout Standard +当命令行参数为“24 3”时的输出结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +您输入的两个数相除的结果是: 8 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +修改命令行参数为“24 3.5”可以看到输出变为: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +数字格式异常,程序只能接受整数形式的参数 +\end_layout + +\begin_layout Plain Layout +java.lang.NumberFormatException: For input string: "3.5" +\end_layout + +\begin_layout Plain Layout +at java.lang.NumberFormatException.forInputString(NumberFormatException +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +hspace{0pt} +\end_layout + +\end_inset + +.java:65) +\end_layout + +\begin_layout Plain Layout +at java.lang.Integer.parseInt(Integer.java:580) +\end_layout + +\begin_layout Plain Layout +at java.lang.Integer.parseInt(Integer.java:615) +\end_layout + +\begin_layout Plain Layout +at cn.edu.sdut.softlab.exception.DivTest.main(DivTest.java:34) +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +修改命令行参数为“24 0”,输出结果为: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +算数异常,除数不能为0 +\end_layout + +\begin_layout Plain Layout +java.lang.ArithmeticException: / by zero +\end_layout + +\begin_layout Plain Layout +at cn.edu.sdut.softlab.exception.DivTest.main(DivTest.java:35) +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +修改命令行参数为“24”,输出结果为: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +数组越界,运行程序时输入的参数个数不对。应该输入2个参数,您输入的参数个数是:1 +\end_layout + +\begin_layout Plain Layout +java.lang.ArrayIndexOutOfBoundsException: 1 +\end_layout + +\begin_layout Plain Layout +at cn.edu.sdut.softlab.exception.DivTest.main(DivTest.java:34) +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +修改命令行参数为“24.5”,输出结果为: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +数字格式异常,程序只能接受整数形式的参数 +\end_layout + +\begin_layout Plain Layout +java.lang.NumberFormatException: For input string: "24.5" +\end_layout + +\begin_layout Plain Layout +at java.lang.NumberFormatException.forInputString(NumberFormatException +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +hspace{0pt} +\end_layout + +\end_inset + +.java:65) +\end_layout + +\begin_layout Plain Layout +at java.lang.Integer.parseInt(Integer.java:580) +\end_layout + +\begin_layout Plain Layout +at java.lang.Integer.parseInt(Integer.java:615) +\end_layout + +\begin_layout Plain Layout +at cn.edu.sdut.softlab.exception.DivTest.main(DivTest.java:33) +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +可以看出,Java遇到异常时即退出整个应用程序。也就是说,尽管我们在代码中可以捕获多个异常,但是当一个异常发生时就会退出整个应用程序。 +\end_layout + +\begin_layout Standard +但是,ArrayIndexOutOfBoundsException、NumberFormatException、ArithmeticException都是运行时 +异常(RuntimeException),即非检查型异常 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +非检查型异常 +\end_layout + +\end_inset + +,我们在代码中其实不需要主动捕获,当异常发生时虚拟机会自动处理。虚拟机的一般处理策略是打印出异常发生时的调用栈,供程序员追查和排错。 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +主动捕获运行时异常的好处是可以给终端用户更友好的错误提示 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +所有的Java异常类都是Throwable的子类,Throwable类的下列方法能够帮助我们更详细的了解异常的情况: +\end_layout + +\begin_layout Itemize +printStackTrace():打印出异常发生时的调用栈(call stack),对于程序员排错特别有用,因此在catch块中经常看到调用printStac +kTrace。 +\end_layout + +\begin_layout Itemize +getMessage():返回描述异常的一个字符串,对于终端用户更友好一些。但是,默认情况下,getMessage返回的就是stackTrace的内容。因此,调 +用此方法显得更友好的前提条件是,在创建异常对象时设置了描述异常的字符串,通常在用户自定义异常中使用,参见: +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:用户自定义异常" + +\end_inset + +。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +现代的IDE,包括Idea、NetBeans、Eclipse都能够自动检测代码是否应该捕获异常,因此无需记忆哪些代码应该使用try...catch结构包围起来,大部分 +情况下遵从IDE的建议即可。但是,有的时候也需要手工组织一下异常处理的代码层次。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +抛出异常 +\begin_inset CommandInset label +LatexCommand label +name "sec:抛出异常" + +\end_inset + + +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:捕获异常" + +\end_inset + +中,我们捕获(catch)的异常是从哪里来的呢?或者说,我们为什么能够捕获到异常 +\begin_inset Foot +status open + +\begin_layout Plain Layout +通常,我们说捕获异常即捕获异常对象的意思,下文不再区分这两者的差异。 +\end_layout + +\end_inset + +?异常对象是谁创建的呢? +\end_layout + +\begin_layout Standard +异常对象当然不是从石头缝里蹦出来的。事实上,我们之所以能够捕获某个异常对象,是因为在try代码块中的某个方法抛出 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +抛出 +\end_layout + +\end_inset + +( +\begin_inset Index idx +status open + +\begin_layout Plain Layout +throw +\end_layout + +\end_inset + +throw)了异常对象,即某个方法在运行中探测到发生了异常状况,因此创建了异常对象并抛出。 +\end_layout + +\begin_layout Example +抛出异常示例 +\begin_inset CommandInset label +LatexCommand label +name "exa:抛出异常示例" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "Example.java" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/exception/src/cn/edu/sdut/softlab/exception/Example.java" +lstparams "float,caption={Example.java},label={Example.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Example结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +就是这么二! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +在add方法中,我们故意制造了一个异常:当给定的参数是2时就抛出异常(throw new Exception())。 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +所谓抛出异常,就是创建异常对象,通过throw关键字抛出即可 +\end_layout + +\end_inset + +,所以抛出异常的的表达方式通常是: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +if(something bad happened) { +\end_layout + +\begin_layout Plain Layout + + throw new SomethingBadException(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +由于在add方法中我们可能抛出异常,因此add方法必须声明抛出了哪些类型的异常,通过throws关键字列出在方法的参数列表后面: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public void add(int val) throws Exception {... +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +add方法在f方法中被调用,但是f方法并没有捕获add方法抛出的异常,因此f方法也必须在方法中声明抛出异常: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public void f() throws Exception {... +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在main方法中我们捕获了f方法中抛出的异常(其实是add方法抛出的异常),因此main方法就不需要抛出异常了。 +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:抛出异常和捕获异常的关系" + +\end_inset + +形象的表达了抛出异常和捕获异常的联系,图中灰色代码由于异常的关系没有执行到。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +placement tbph +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/exception/throw-catch-exmaple.eps + width 90col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +抛出异常和捕获异常的关系 +\begin_inset CommandInset label +LatexCommand label +name "fig:抛出异常和捕获异常的关系" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +翻一下JDK的源代码,也许有助于深刻理解Java的异常处理机制。比如 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这里寻找一个合适易懂的Java源代码,在:http://hg.openjdk.java.net/jdk10/jdk10/jdk/file/777356696811 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:抛出异常示例" + +\end_inset + +中,如果main方法中也不捕获异常,需要做怎样的代码变动? +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:抛出异常示例" + +\end_inset + +中,修改f方法捕获add方法抛出的异常。 +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:抛出异常示例" + +\end_inset + +中,修改add方法,使得抛出异常部分代码为: +\end_layout + +\begin_layout Exercise +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +if( val == 2 ) throw new Exception(); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +则代码的其他部分应该如何修改更合理? +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +可以看出,Java的异常处理其实也离不开if条件判断,比如在add方法中: +\end_layout + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +if (val == 2) +\end_layout + +\begin_layout Plain Layout + + throw new Exception("就是这么二!"); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +只不过,在Java中通过try...catch和throw机制将杂乱无章的if条件判断良好的组织起来,层次更加清晰罢了。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +要注意区分throw和throws的不同用法。throw用于在代码中创建异常对象并抛出异常,throws只是在方法中声明本方法可能抛出哪些异常。在方法中声明抛出 +了某种类型的异常,表明这个方法没有处理异常,将处理异常的责任“抛”给了方法的调用者。如果方法的调用者也不处理这个异常,则调用者同样需要throws这个异常,如此 +形成了一个异常处理的“责任链”,如下图所示。 +\end_layout + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/exception/exception-chain.eps + width 90col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout +可以想见,main方法是我们程序员处理异常的最后“关口”,即如果我们在main方法中也不处理(捕获)异常的话,main方法同样需要声明throws这些异常。ma +in方法抛出的异常就只有java虚拟机可以处理了,这通常不是一个好的习惯,因为Java虚拟机只能按照默认的异常处理方式打印出调用栈,在终端用户看来,调用栈没有任 +何价值,徒增抱怨而已。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +finally +\begin_inset CommandInset label +LatexCommand label +name "sec:finally" + +\end_inset + + +\end_layout + +\begin_layout Standard +try-catch结构完美的诠释了异常处理的一般过程,不过我们考虑一种特殊情况:如果我们希望在执行完try代码块之后总是执行一段代码(不妨称之为“清理代码块”) +,即 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +无论try代码块是否存在异常,清理代码块总是要执行的 +\end_layout + +\end_inset + +。finally即为此而设置,一般结构为: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +try { +\end_layout + +\begin_layout Plain Layout + + // 正常流程 +\end_layout + +\begin_layout Plain Layout + +} catch (...) { +\end_layout + +\begin_layout Plain Layout + + // 异常流程1 +\end_layout + +\begin_layout Plain Layout + +} catch (...) { +\end_layout + +\begin_layout Plain Layout + + // 异常流程2 +\end_layout + +\begin_layout Plain Layout + +} finally { +\end_layout + +\begin_layout Plain Layout + + // 清理代码块 +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在网络通讯和数据库编程中,这种情形很常见:无论是否发生异常,网络链接和数据库链接总是要断开的(close),因此很适合在finally代码块中处理断开网络链接和 +数据库链接。我们在也将在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "chap:Java的IO" + +\end_inset + +看到很多finally使用的实例。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:try-with-resources" + +\end_inset + +我们可以看到,使用try with resources技术可以避免使用finally,这样即简化了代码,也提高了代码的可读性,值得提倡。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +编写一个包含finally的程序,说明即使发生了异常,finally代码块也是会被执行到的。 +\end_layout + +\begin_layout Section +用户自定义异常 +\begin_inset CommandInset label +LatexCommand label +name "sec:用户自定义异常" + +\end_inset + + +\end_layout + +\begin_layout Standard +异常类代表了一种异常的类型,自然我们也可以根据实际的业务逻辑自定义异常类,通常是从Exception类继承下来即可。比如在电子商务的业务流程中,“下订单”的过程 +可能会遇到以下的异常情况 +\begin_inset Foot +status open + +\begin_layout Plain Layout +在真实的电子商务系统中,往往会采取更为灵活的方式处理下订单时的此类异常,这里仅为简化后的情形。 +\end_layout + +\end_inset + +: +\begin_inset Note Note +status open + +\begin_layout Plain Layout +写出完整的例子,演示抛出异常和catch多种异常的情形,也演示getMessage的好处 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +库存不足:所订购的商品没有及时付款,提交订单时库存不足了,导致提交失败。我们定义这种异常为OutOfInventoryException。 +\end_layout + +\begin_layout Itemize +价格变更:提交订单时商品的价格已经改变了,此时应该阻止提交订单。我们定义这种异常为PriceNotAvailableException。 +\end_layout + +\begin_layout Standard +首先我们定义这两个异常类,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "OutOfIventoryException.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "PriceNotAvailableException.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/exception/src/cn/edu/sdut/softlab/exception/eshop/OutOfInventoryException.java" +lstparams "float,caption={OutOfIventoryException.java},label={OutOfIventoryException.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/exception/src/cn/edu/sdut/softlab/exception/eshop/PriceNotAvailableException.java" +lstparams "float,caption={PriceNotAvailableException.java},label={PriceNotAvailableException.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +在主类CustomerOrder.java中,我们设置了两个变量inventoryOK和priceOK分别代表库存和价格的状态,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "CustomerOrder.java" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +。读者可以尝试修改这两个变量的值观察输出有什么变化?当然,在实际情况中,应该是根据业务逻辑给这两个变量赋值的。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/exception/src/cn/edu/sdut/softlab/exception/eshop/CustomerOrder.java" +lstparams "caption={CustomerOrder.java},label={CustomerOrder.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +在Idea IDE中,可以通过快捷键Alt+Insert方便的自动产生OutOfInventoryException的构造方法:选择 +\begin_inset Quotes erd +\end_inset + +override method... +\begin_inset Quotes erd +\end_inset + +,在随后弹出的窗口中选择 +\begin_inset Quotes erd +\end_inset + +Exception(s:String)”即可。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +try with resources +\begin_inset CommandInset label +LatexCommand label +name "sec:try-with-resources" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +比较困难的一个地方是,在这里讲解try-with-resources很难举出一个合适的例子来。是否把这个部分移动到java io一章? +\end_layout + +\end_inset + +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:finally" + +\end_inset + +中我们看到,对于必须执行的“清理代码块”,我们可以使用finally来保证这一点。Java8更进了一步:如果一个对象实现了 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +java.lang.AutoCloseable +\end_layout + +\end_inset + +接口 +\begin_inset Foot +status open + +\begin_layout Plain Layout +由于AutoCloseable接口只有一个抽象方法close,因此AutoCloseable接口是一个函数接口,参见本系列教程的“提高篇”之“lambda表达式 +”。 +\end_layout + +\end_inset + +或者Closeable接口(这样的对象就是try-with-resources中的resource),则可以通过try-with-resources结构来保证代 +码结束时自动关闭这个对象。实现了 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +java.lang.AutoCloseable +\end_layout + +\end_inset + +接口(或者Closeable接口)的对象被称为resource。try-with-resources结构的一般形式如下 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +本部分示例代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html +\end_layout + +\end_inset + +,我们将在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "chap:Java的IO" + +\end_inset + +看到比较多的try-with-resources用法。 +\end_layout + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +try (resourse1; resource2) { +\end_layout + +\begin_layout Plain Layout + + // 正常流程 +\end_layout + +\begin_layout Plain Layout + +} catch (...) { +\end_layout + +\begin_layout Plain Layout + + // 异常流程 +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +比如下面的例子读取文件的第一行: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +static String readFirstLineFromFile(String path) throws IOException { +\end_layout + +\begin_layout Plain Layout + + try (BufferedReader br = new BufferedReader(new FileReader(path))) { +\end_layout + +\begin_layout Plain Layout + + return br.readLine(); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +BufferedReader是一个实现了AutoCloseable接口的resource(资源),因此我们把创建BufferedReader对象的工作放到了tr +y-with-resources结构中,这样无论br.readLine是否正常执行,当try-with-resources代码块执行完毕后,BufferedRea +der对象br都会被自动关闭。如果我们不使用try-with-resources结构的话,则需要这样编写同样功能的代码: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +static String readFirstLineFromFileWithFinallyBlock(String path) throws + IOException { +\end_layout + +\begin_layout Plain Layout + + BufferedReader br = new BufferedReader(new FileReader(path)); +\end_layout + +\begin_layout Plain Layout + + try { +\end_layout + +\begin_layout Plain Layout + + return br.readLine(); +\end_layout + +\begin_layout Plain Layout + + } finally { +\end_layout + +\begin_layout Plain Layout + + if (br != null) br.close(); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +可见,使用try-with-resources结构不仅简化了代码,也提高了代码的可读性。 +\end_layout + +\begin_layout Standard +下面的例子在try-with-resourses中声明了多个resources: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public static void writeToFileZipFileContents(String zipFileName, +\end_layout + +\begin_layout Plain Layout + + String outputFileName) +\end_layout + +\begin_layout Plain Layout + + throws java.io.IOException { +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + java.nio.charset.Charset charset = +\end_layout + +\begin_layout Plain Layout + + java.nio.charset.StandardCharsets.US_ASCII; +\end_layout + +\begin_layout Plain Layout + + java.nio.file.Path outputFilePath = +\end_layout + +\begin_layout Plain Layout + + java.nio.file.Paths.get(outputFileName); +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + // Open zip file and create output file with +\end_layout + +\begin_layout Plain Layout + + // try-with-resources statement +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + try ( +\end_layout + +\begin_layout Plain Layout + + java.util.zip.ZipFile zf = +\end_layout + +\begin_layout Plain Layout + + new java.util.zip.ZipFile(zipFileName); +\end_layout + +\begin_layout Plain Layout + + java.io.BufferedWriter writer = +\end_layout + +\begin_layout Plain Layout + + java.nio.file.Files.newBufferedWriter(outputFilePath, charset) +\end_layout + +\begin_layout Plain Layout + + ) { +\end_layout + +\begin_layout Plain Layout + + // Enumerate each entry +\end_layout + +\begin_layout Plain Layout + + for (java.util.Enumeration entries = +\end_layout + +\begin_layout Plain Layout + + zf.entries(); entries.hasMoreElements();) + { +\end_layout + +\begin_layout Plain Layout + + // Get the entry name and write it to the output file +\end_layout + +\begin_layout Plain Layout + + String newLine = System.getProperty("line.separator"); +\end_layout + +\begin_layout Plain Layout + + String zipEntryName = +\end_layout + +\begin_layout Plain Layout + + ((java.util.zip.ZipEntry)entries.nextElement()).getName() + +\end_layout + +\begin_layout Plain Layout + + newLine; +\end_layout + +\begin_layout Plain Layout + + writer.write(zipEntryName, 0, zipEntryName.length()); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +使用try-with-resources结构编写数据库访问程序: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public static void viewTable(Connection con) throws SQLException { +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES"; +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + try (Statement stmt = con.createStatement()) { +\end_layout + +\begin_layout Plain Layout + + ResultSet rs = stmt.executeQuery(query); +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + while (rs.next()) { +\end_layout + +\begin_layout Plain Layout + + String coffeeName = rs.getString("COF_NAME"); +\end_layout + +\begin_layout Plain Layout + + int supplierID = rs.getInt("SUP_ID"); +\end_layout + +\begin_layout Plain Layout + + float price = rs.getFloat("PRICE"); +\end_layout + +\begin_layout Plain Layout + + int sales = rs.getInt("SALES"); +\end_layout + +\begin_layout Plain Layout + + int total = rs.getInt("TOTAL"); +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + System.out.println(coffeeName + ", " + supplierID + ", " + +\end_layout + +\begin_layout Plain Layout + + price + ", " + sales + ", " + total); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + } catch (SQLException e) { +\end_layout + +\begin_layout Plain Layout + + JDBCTutorialUtilities.printSQLException(e); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +异常处理的一般原则?举例说明,有很多种处理异常的方式,哪种更合理?谁来处理异常?throw or catch? +\end_layout + +\begin_layout Plain Layout +如何知道该捕获哪个异常? +\end_layout + +\begin_layout Plain Layout +图示责任链 +\end_layout + +\end_inset + + +\end_layout + +\end_body +\end_document diff --git a/guide/lecture_guide/lecture9.lyx b/guide/lecture_guide/lecture9.lyx new file mode 100644 index 0000000..0f0c791 --- /dev/null +++ b/guide/lecture_guide/lecture9.lyx @@ -0,0 +1,3143 @@ +#LyX 2.3 created this file. For more info see http://www.lyx.org/ +\lyxformat 544 +\begin_document +\begin_header +\save_transient_properties true +\origin unavailable +\textclass ctex-book +\begin_preamble +\input{../../../writing-common/book-preamble.tex} +\end_preamble +\use_default_options true +\begin_modules +tip-inset +note-inset +warning-inset +theorems-bytype +theorems-chap-bytype +logicalmkup +coderemarks +\end_modules +\maintain_unincluded_children false +\begin_local_layout +PackageOptions url hyphens +\end_local_layout +\language chinese-simplified +\language_package default +\inputencoding utf8-plain +\fontencoding global +\font_roman "default" "DejaVu Sans" +\font_sans "default" "DejaVu Serif" +\font_typewriter "default" "DejaVu Sans Mono" +\font_math "auto" "auto" +\font_default_family default +\use_non_tex_fonts true +\font_sc false +\font_osf false +\font_sf_scale 100 100 +\font_tt_scale 100 100 +\use_microtype false +\use_dash_ligatures true +\graphics default +\default_output_format pdf4 +\output_sync 0 +\bibtex_command default +\index_command default +\float_placement tbph +\paperfontsize default +\spacing single +\use_hyperref true +\pdf_bookmarks true +\pdf_bookmarksnumbered false +\pdf_bookmarksopen false +\pdf_bookmarksopenlevel 3 +\pdf_breaklinks true +\pdf_pdfborder true +\pdf_colorlinks false +\pdf_backref false +\pdf_pdfusetitle true +\papersize default +\use_geometry false +\use_package amsmath 1 +\use_package amssymb 1 +\use_package cancel 1 +\use_package esint 1 +\use_package mathdots 1 +\use_package mathtools 1 +\use_package mhchem 1 +\use_package stackrel 1 +\use_package stmaryrd 1 +\use_package undertilde 1 +\cite_engine basic +\cite_engine_type default +\biblio_style plain +\use_bibtopic false +\use_indices false +\paperorientation portrait +\suppress_date false +\justification true +\use_refstyle 1 +\use_minted 0 +\boxbgcolor #dad3d7 +\index Index +\shortcut idx +\color #008000 +\end_index +\secnumdepth 3 +\tocdepth 2 +\paragraph_separation indent +\paragraph_indentation default +\is_math_indent 0 +\math_numbering_side default +\quotes_style english +\dynamic_quotes 0 +\papercolumns 1 +\papersides 2 +\paperpagestyle default +\tracking_changes false +\output_changes false +\html_math_output 0 +\html_css_as_file 0 +\html_be_strict false +\end_header + +\begin_body + +\begin_layout Standard +\align center + +\size larger +\bar under +山东理工大学教案 +\end_layout + +\begin_layout Standard +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +第九次课 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +教学课型:理论课□√ 实验课□√ 习题课□ 实践课□ 技能课□ 其它□ +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +主要教学内容 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:finally" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:finally" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:用户自定义异常" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:用户自定义异常" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:try-with-resources" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand nameref +reference "sec:try-with-resources" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +重点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +完整的Java异常处理形式; +\end_layout + +\begin_layout Enumerate +用户自定义异常的方法和原则; +\end_layout + +\begin_layout Enumerate +try with resources的应用场合; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +难点 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +用户自定义异常和JDK内置的异常类的关系; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +课程目标及要求 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +课程目标:课程目标1 +\end_layout + +\begin_layout Plain Layout +要求: +\end_layout + +\begin_layout Enumerate +熟练掌握Java异常处理的完整形式; +\end_layout + +\begin_layout Enumerate +深刻理解用户自定义异常的使用场合,注意和JDK内置异常类的对比; +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +教学方法和手段 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +板书和多媒体相结合,边讲边练,当堂消化。 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +讨论、思考题 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Box Frameless +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "60col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Enumerate +什么情况下 使用JDK内置的异常类,什么情况下需要用户自定义异常? +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +参考资料 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Chapter +异常处理 +\end_layout + +\begin_layout Standard +\align center +\begin_inset Graphics + filename ../imgs/exception/exception-vym.png + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Section +异常的概念 +\begin_inset CommandInset label +LatexCommand label +name "sec:异常的概念" + +\end_inset + + +\end_layout + +\begin_layout Standard +“人生不如意事十之八九” +\begin_inset Foot +status open + +\begin_layout Plain Layout +南宋词人辛弃疾词《贺新郎·用前韵再赋》:“叹人生、不如意事,十常八九。” +\end_layout + +\end_inset + +,编程同样道理:世事纷繁复杂,情况千变万化,代码要正确运行,不仅要处理正常的流程,更要处理多样化的非正常流程。比如常见的情形: +\begin_inset Note Note +status open + +\begin_layout Plain Layout +举例说明异常流程之多样化 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +街头的投币电话,总有人尝试用游戏币看看能不能蒙混过关; +\end_layout + +\begin_layout Itemize +长城的古砖墙是为御敌而生,却被人刻上“到此一游”; +\end_layout + +\begin_layout Itemize +机动车道上的行人,人行道上的机动车; +\end_layout + +\begin_layout Standard +回到现实的程序中,在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:日期和时间类" + +\end_inset + +中,我们看到日期和时间类都定义了一个parse方法,能够将字符串解析为LocalDate、LocalTime或者LocalDateTime对象,很直观,很方便, +因此在编程实践中很常见。试运行下面的示例: +\end_layout + +\begin_layout Example +从键盘输入字符串创建日期对象 +\begin_inset CommandInset label +LatexCommand label +name "exa:从键盘输入字符串创建日期对象" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "WhatIfNoException.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/exception/src/cn/edu/sdut/softlab/exception/WhatIfNoException.java" +lstparams "caption={WhatIfNoException.java},label={WhatIfNoException.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行WhatIfNoException结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100line%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +Please input date:2016-11-22 +\end_layout + +\begin_layout Plain Layout +2016-11-22 +\end_layout + +\begin_layout Plain Layout +Please input date:2016-13-22 +\end_layout + +\begin_layout Plain Layout +Exception in thread "main" java.time.format.DateTimeParseException: +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +Text '2016-13-22' could not be parsed: Invalid value for MonthOfYear (valid + values 1 - 12): 13 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +at java.time.format.DateTimeFormatter.createError( +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +hspace{0pt} +\end_layout + +\end_inset + +DateTimeFormatter.java:1920) +\end_layout + +\begin_layout Plain Layout +...... +\end_layout + +\begin_layout Plain Layout +at cn.edu.sdut.softlab.exception.WhatIfNoException.main( +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +hspace{0pt} +\end_layout + +\end_inset + +WhatIfNoException.java:30) +\end_layout + +\begin_layout Plain Layout +Caused by: java.time.DateTimeException: Invalid value for MonthOfYear (valid + values 1 - 12): 13 +\end_layout + +\begin_layout Plain Layout +at java.time.temporal.ValueRange.checkValidIntValue(ValueRange +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +hspace{0pt} +\end_layout + +\end_inset + +.java:330) +\end_layout + +\begin_layout Plain Layout +...... +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:从键盘输入字符串创建日期对象" + +\end_inset + +中,从键盘输入的字符串如果符合LocalDate的格式要求自然一切正常,但是我们不能总是期望人们每次输入都遵循LocalDate的格式,无论人们是有意还是无意, +总会有破坏规则的时候,比如输入的月份大于12、天数大于31等。显然,错误的输入是无法获得正确的LocalDate对象的,Java编译器也无法自动纠正这种类型的错 +误。对于这种情况,Java友好的给出了错误的原因及其关联的程序代码(stack trace),以帮助程序员快速定位错误代码的位置,更快的修复问题。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +实际上,类似 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:从键盘输入字符串创建日期对象" + +\end_inset + +的错误提示方式,对于程序员而言是友好的,但是对于终端用户而言是不友好的:终端用户并不关心程序哪一行出错了。对于终端用户而言,程序应该给出更人性化的提示,比如提示 +“日期格式有错误,月份应该在1-12之间”等等。我们将在 +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:Java的异常处理方式" + +\end_inset + +中介绍如何更人性化的处理。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +C中的异常处理方式 +\begin_inset CommandInset label +LatexCommand label +name "sec:C中的异常处理方式" + +\end_inset + + +\end_layout + +\begin_layout Standard +我们先回顾一下在C语言中如何判断用户的输入是否合法,大致应该是如下的代码片段: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +if(month < 1 || month > 12) { +\end_layout + +\begin_layout Plain Layout + + printf("wrong month num:%d",month); +\end_layout + +\begin_layout Plain Layout + + return -1; +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +if(day < 1 || day > 31) { /* 没有考虑二月份情况 */ +\end_layout + +\begin_layout Plain Layout + + printf("wrong day num:%d",day); +\end_layout + +\begin_layout Plain Layout + + return -1; +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +... +\end_layout + +\begin_layout Plain Layout + +/* 用户的输入合法,下面继续处理正常流程 */ +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +也就是说,我们只能通过一系列的if条件判断来分析用户的输入是否合法,如果可能的异常情形比较多,势必会存在更多的if条件判断,造成程序的流程不清晰:哪些是正常流程 +处理代码,哪些是异常流程处理代码,除非通过注释标识出来,否则很难一眼看清楚。 +\end_layout + +\begin_layout Section +Java的异常处理方式 +\begin_inset CommandInset label +LatexCommand label +name "sec:Java的异常处理方式" + +\end_inset + + +\end_layout + +\begin_layout Standard +当然,在Java中我们依然可以像C语言那样去处理异常 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +异常 +\end_layout + +\end_inset + +。不过,Java提供了更棒的异常处理机制:将异常情况抽象为异常对象 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +异常对象 +\end_layout + +\end_inset + +,并采用责任链 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +责任链 +\end_layout + +\end_inset + +处理机制处理异常对象。 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这部分讲的不清楚 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Java内置了常见的异常类,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java的异常类层次结构" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/exception/exception-overview.eps + width 100col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java的异常类层次结构 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java的异常类层次结构" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +当异常情况出现时,Java虚拟机能够“捕获 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +捕获 +\end_layout + +\end_inset + +” +\begin_inset Note Note +status open + +\begin_layout Plain Layout +如何捕获?如何感知?这里可能是许多初学者迷惑的地方。 +\end_layout + +\end_inset + +(catch) +\begin_inset Foot +status open + +\begin_layout Plain Layout +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java虚拟机和Java应用程序的关系" + +\end_inset + +了解Java应用程序和Java虚拟机之间的关系,感性认识Java虚拟机是如何捕获异常的。 +\end_layout + +\end_inset + +异常对象,并根据异常对象的类型进行相应的处理。Java将异常类分为两大类: +\end_layout + +\begin_layout Itemize +\begin_inset Index idx +status open + +\begin_layout Plain Layout +非检查型异常 +\end_layout + +\end_inset + +非检查型异常:即Java虚拟机能够 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +自动 +\end_layout + +\end_inset + +处理的异常类型。换言之,这种类型的异常不需要在程序中捕获,一旦发生这种类型的异常,Java虚拟机有一套内置的处理方式,比如除数为零、数组越界、非法参数等异常类型 +。对应于 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java的异常类层次结构" + +\end_inset + +,Error和RuntimeException的子类都是非检查型异常。在程序中可以不捕获非检查型异常,也可以捕获非检查型异常。捕获非检查型异常的目的往往是给用户 +提供更友好的出错提示,但这不是强制的。 +\end_layout + +\begin_layout Itemize +\begin_inset Index idx +status open + +\begin_layout Plain Layout +检查型异常 +\end_layout + +\end_inset + +检查型异常:即Java虚拟机无法自动处理的异常类型,需要在程序中捕获(catch)。对应于 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java的异常类层次结构" + +\end_inset + +,ClassNotFoundException和IOException的子类都是检查型异常。要注意的是,检查型异常是必须捕获的,否则会导致语法错误,因此在程序中 +捕获检查型异常是强制的。 +\end_layout + +\begin_layout Section +捕获异常 +\begin_inset CommandInset label +LatexCommand label +name "sec:捕获异常" + +\end_inset + + +\end_layout + +\begin_layout Standard +我们首先简单回顾一下Java虚拟机和Java应用程序的关系,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Java虚拟机和Java应用程序的关系" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +placement tbph +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/exception/jvm-java.eps + width 80line% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Java虚拟机和Java应用程序的关系 +\begin_inset CommandInset label +LatexCommand label +name "fig:Java虚拟机和Java应用程序的关系" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Java应用程序编译为class文件后,经过Java虚拟机的类加载器解析class文件在内存中创建相应的存储模型然后执行该应用程序。也就是说,Java虚拟机完全 +掌控Java应用程序的执行过程,包括应用程序出现异常情况时。Java通过如下的程序结构捕获异常: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +try { +\end_layout + +\begin_layout Plain Layout + + // 一段可能存在SomeException类型异常的代码 +\end_layout + +\begin_layout Plain Layout + +} catch (SomeException e) { +\end_layout + +\begin_layout Plain Layout + + e.printStackTrace(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在try块中的代码就是所谓的“ +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +正常流程 +\end_layout + +\end_inset + +”,在catch块中的代码就是所谓的“ +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +异常流程 +\end_layout + +\end_inset + +”。如果异常流程有多种,就存在多个catch块: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +try { +\end_layout + +\begin_layout Plain Layout + + // 一段可能存在SomeException类型异常的代码 +\end_layout + +\begin_layout Plain Layout + +} catch (SomeException e) { +\end_layout + +\begin_layout Plain Layout + + e.printStackTrace(); +\end_layout + +\begin_layout Plain Layout + +} catch (OtherException e) { +\end_layout + +\begin_layout Plain Layout + + e.printStackTrace(); +\end_layout + +\begin_layout Plain Layout + +} catch (FooException e ) { +\end_layout + +\begin_layout Plain Layout + + e.printStackTrace(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +对比C语言中使用if...else结构的异常处理方式,Java的try...catch更清晰的区分了正常流程和异常流程:通过不同的异常类也清晰的表达了异常的类型,甚至无需借 +助注释,只是根据异常类的名字,我们也很容易判断异常的类型及其大致的处理方式。 +\end_layout + +\begin_layout Example +捕获异常 +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "DivTest.java" + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/exception/src/cn/edu/sdut/softlab/exception/DivTest.java" +lstparams "float,caption={DivTest.java},label={DivTest.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +此例的运行需要配置命令行参,配置方法参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:如何设置命令行参数?" + +\end_inset + + +\end_layout + +\begin_layout Standard +当命令行参数为“24 3”时的输出结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +您输入的两个数相除的结果是: 8 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +修改命令行参数为“24 3.5”可以看到输出变为: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +数字格式异常,程序只能接受整数形式的参数 +\end_layout + +\begin_layout Plain Layout +java.lang.NumberFormatException: For input string: "3.5" +\end_layout + +\begin_layout Plain Layout +at java.lang.NumberFormatException.forInputString(NumberFormatException +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +hspace{0pt} +\end_layout + +\end_inset + +.java:65) +\end_layout + +\begin_layout Plain Layout +at java.lang.Integer.parseInt(Integer.java:580) +\end_layout + +\begin_layout Plain Layout +at java.lang.Integer.parseInt(Integer.java:615) +\end_layout + +\begin_layout Plain Layout +at cn.edu.sdut.softlab.exception.DivTest.main(DivTest.java:34) +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +修改命令行参数为“24 0”,输出结果为: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +算数异常,除数不能为0 +\end_layout + +\begin_layout Plain Layout +java.lang.ArithmeticException: / by zero +\end_layout + +\begin_layout Plain Layout +at cn.edu.sdut.softlab.exception.DivTest.main(DivTest.java:35) +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +修改命令行参数为“24”,输出结果为: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +数组越界,运行程序时输入的参数个数不对。应该输入2个参数,您输入的参数个数是:1 +\end_layout + +\begin_layout Plain Layout +java.lang.ArrayIndexOutOfBoundsException: 1 +\end_layout + +\begin_layout Plain Layout +at cn.edu.sdut.softlab.exception.DivTest.main(DivTest.java:34) +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +修改命令行参数为“24.5”,输出结果为: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +数字格式异常,程序只能接受整数形式的参数 +\end_layout + +\begin_layout Plain Layout +java.lang.NumberFormatException: For input string: "24.5" +\end_layout + +\begin_layout Plain Layout +at java.lang.NumberFormatException.forInputString(NumberFormatException +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +hspace{0pt} +\end_layout + +\end_inset + +.java:65) +\end_layout + +\begin_layout Plain Layout +at java.lang.Integer.parseInt(Integer.java:580) +\end_layout + +\begin_layout Plain Layout +at java.lang.Integer.parseInt(Integer.java:615) +\end_layout + +\begin_layout Plain Layout +at cn.edu.sdut.softlab.exception.DivTest.main(DivTest.java:33) +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +可以看出,Java遇到异常时即退出整个应用程序。也就是说,尽管我们在代码中可以捕获多个异常,但是当一个异常发生时就会退出整个应用程序。 +\end_layout + +\begin_layout Standard +但是,ArrayIndexOutOfBoundsException、NumberFormatException、ArithmeticException都是运行时 +异常(RuntimeException),即非检查型异常 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +非检查型异常 +\end_layout + +\end_inset + +,我们在代码中其实不需要主动捕获,当异常发生时虚拟机会自动处理。虚拟机的一般处理策略是打印出异常发生时的调用栈,供程序员追查和排错。 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +主动捕获运行时异常的好处是可以给终端用户更友好的错误提示 +\end_layout + +\end_inset + +。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +所有的Java异常类都是Throwable的子类,Throwable类的下列方法能够帮助我们更详细的了解异常的情况: +\end_layout + +\begin_layout Itemize +printStackTrace():打印出异常发生时的调用栈(call stack),对于程序员排错特别有用,因此在catch块中经常看到调用printStac +kTrace。 +\end_layout + +\begin_layout Itemize +getMessage():返回描述异常的一个字符串,对于终端用户更友好一些。但是,默认情况下,getMessage返回的就是stackTrace的内容。因此,调 +用此方法显得更友好的前提条件是,在创建异常对象时设置了描述异常的字符串,通常在用户自定义异常中使用,参见: +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:用户自定义异常" + +\end_inset + +。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +现代的IDE,包括Idea、NetBeans、Eclipse都能够自动检测代码是否应该捕获异常,因此无需记忆哪些代码应该使用try...catch结构包围起来,大部分 +情况下遵从IDE的建议即可。但是,有的时候也需要手工组织一下异常处理的代码层次。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +抛出异常 +\begin_inset CommandInset label +LatexCommand label +name "sec:抛出异常" + +\end_inset + + +\end_layout + +\begin_layout Standard +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:捕获异常" + +\end_inset + +中,我们捕获(catch)的异常是从哪里来的呢?或者说,我们为什么能够捕获到异常 +\begin_inset Foot +status open + +\begin_layout Plain Layout +通常,我们说捕获异常即捕获异常对象的意思,下文不再区分这两者的差异。 +\end_layout + +\end_inset + +?异常对象是谁创建的呢? +\end_layout + +\begin_layout Standard +异常对象当然不是从石头缝里蹦出来的。事实上,我们之所以能够捕获某个异常对象,是因为在try代码块中的某个方法抛出 +\begin_inset Index idx +status open + +\begin_layout Plain Layout +抛出 +\end_layout + +\end_inset + +( +\begin_inset Index idx +status open + +\begin_layout Plain Layout +throw +\end_layout + +\end_inset + +throw)了异常对象,即某个方法在运行中探测到发生了异常状况,因此创建了异常对象并抛出。 +\end_layout + +\begin_layout Example +抛出异常示例 +\begin_inset CommandInset label +LatexCommand label +name "exa:抛出异常示例" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码设计 +\end_layout + +\begin_layout Standard +参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "Example.java" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/exception/src/cn/edu/sdut/softlab/exception/Example.java" +lstparams "float,caption={Example.java},label={Example.java}" + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +运行结果 +\end_layout + +\begin_layout Standard +运行Example结果如下: +\end_layout + +\begin_layout Standard +\begin_inset Box Shaded +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "100col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout +就是这么二! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Paragraph* +代码分析 +\end_layout + +\begin_layout Standard +在add方法中,我们故意制造了一个异常:当给定的参数是2时就抛出异常(throw new Exception())。 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +所谓抛出异常,就是创建异常对象,通过throw关键字抛出即可 +\end_layout + +\end_inset + +,所以抛出异常的的表达方式通常是: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +if(something bad happened) { +\end_layout + +\begin_layout Plain Layout + + throw new SomethingBadException(); +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +由于在add方法中我们可能抛出异常,因此add方法必须声明抛出了哪些类型的异常,通过throws关键字列出在方法的参数列表后面: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public void add(int val) throws Exception {... +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +add方法在f方法中被调用,但是f方法并没有捕获add方法抛出的异常,因此f方法也必须在方法中声明抛出异常: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public void f() throws Exception {... +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在main方法中我们捕获了f方法中抛出的异常(其实是add方法抛出的异常),因此main方法就不需要抛出异常了。 +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +figurename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:抛出异常和捕获异常的关系" + +\end_inset + +形象的表达了抛出异常和捕获异常的联系,图中灰色代码由于异常的关系没有执行到。 +\end_layout + +\begin_layout Standard +\begin_inset Float figure +placement tbph +wide false +sideways false +status collapsed + +\begin_layout Plain Layout +\align center +\begin_inset Graphics + filename ../imgs/exception/throw-catch-exmaple.eps + width 90col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +抛出异常和捕获异常的关系 +\begin_inset CommandInset label +LatexCommand label +name "fig:抛出异常和捕获异常的关系" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +翻一下JDK的源代码,也许有助于深刻理解Java的异常处理机制。比如 +\begin_inset Note Note +status open + +\begin_layout Plain Layout +这里寻找一个合适易懂的Java源代码,在:http://hg.openjdk.java.net/jdk10/jdk10/jdk/file/777356696811 +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:抛出异常示例" + +\end_inset + +中,如果main方法中也不捕获异常,需要做怎样的代码变动? +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:抛出异常示例" + +\end_inset + +中,修改f方法捕获add方法抛出的异常。 +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Exercise +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +examplename +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "exa:抛出异常示例" + +\end_inset + +中,修改add方法,使得抛出异常部分代码为: +\end_layout + +\begin_layout Exercise +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +if( val == 2 ) throw new Exception(); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +则代码的其他部分应该如何修改更合理? +\end_layout + +\begin_layout Standard +\begin_inset Separator plain +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +可以看出,Java的异常处理其实也离不开if条件判断,比如在add方法中: +\end_layout + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +if (val == 2) +\end_layout + +\begin_layout Plain Layout + + throw new Exception("就是这么二!"); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +只不过,在Java中通过try...catch和throw机制将杂乱无章的if条件判断良好的组织起来,层次更加清晰罢了。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Notice +status open + +\begin_layout Plain Layout +要注意区分throw和throws的不同用法。throw用于在代码中创建异常对象并抛出异常,throws只是在方法中声明本方法可能抛出哪些异常。在方法中声明抛出 +了某种类型的异常,表明这个方法没有处理异常,将处理异常的责任“抛”给了方法的调用者。如果方法的调用者也不处理这个异常,则调用者同样需要throws这个异常,如此 +形成了一个异常处理的“责任链”,如下图所示。 +\end_layout + +\begin_layout Plain Layout +\begin_inset Graphics + filename ../imgs/exception/exception-chain.eps + width 90col% + +\end_inset + + +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout +可以想见,main方法是我们程序员处理异常的最后“关口”,即如果我们在main方法中也不处理(捕获)异常的话,main方法同样需要声明throws这些异常。ma +in方法抛出的异常就只有java虚拟机可以处理了,这通常不是一个好的习惯,因为Java虚拟机只能按照默认的异常处理方式打印出调用栈,在终端用户看来,调用栈没有任 +何价值,徒增抱怨而已。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +finally +\begin_inset CommandInset label +LatexCommand label +name "sec:finally" + +\end_inset + + +\end_layout + +\begin_layout Standard +try-catch结构完美的诠释了异常处理的一般过程,不过我们考虑一种特殊情况:如果我们希望在执行完try代码块之后总是执行一段代码(不妨称之为“清理代码块”) +,即 +\begin_inset Flex Strong +status open + +\begin_layout Plain Layout +无论try代码块是否存在异常,清理代码块总是要执行的 +\end_layout + +\end_inset + +。finally即为此而设置,一般结构为: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +try { +\end_layout + +\begin_layout Plain Layout + + // 正常流程 +\end_layout + +\begin_layout Plain Layout + +} catch (...) { +\end_layout + +\begin_layout Plain Layout + + // 异常流程1 +\end_layout + +\begin_layout Plain Layout + +} catch (...) { +\end_layout + +\begin_layout Plain Layout + + // 异常流程2 +\end_layout + +\begin_layout Plain Layout + +} finally { +\end_layout + +\begin_layout Plain Layout + + // 清理代码块 +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +在网络通讯和数据库编程中,这种情形很常见:无论是否发生异常,网络链接和数据库链接总是要断开的(close),因此很适合在finally代码块中处理断开网络链接和 +数据库链接。我们在也将在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "chap:Java的IO" + +\end_inset + +看到很多finally使用的实例。 +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:try-with-resources" + +\end_inset + +我们可以看到,使用try with resources技术可以避免使用finally,这样即简化了代码,也提高了代码的可读性,值得提倡。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Exercise +编写一个包含finally的程序,说明即使发生了异常,finally代码块也是会被执行到的。 +\end_layout + +\begin_layout Section +用户自定义异常 +\begin_inset CommandInset label +LatexCommand label +name "sec:用户自定义异常" + +\end_inset + + +\end_layout + +\begin_layout Standard +异常类代表了一种异常的类型,自然我们也可以根据实际的业务逻辑自定义异常类,通常是从Exception类继承下来即可。比如在电子商务的业务流程中,“下订单”的过程 +可能会遇到以下的异常情况 +\begin_inset Foot +status open + +\begin_layout Plain Layout +在真实的电子商务系统中,往往会采取更为灵活的方式处理下订单时的此类异常,这里仅为简化后的情形。 +\end_layout + +\end_inset + +: +\begin_inset Note Note +status open + +\begin_layout Plain Layout +写出完整的例子,演示抛出异常和catch多种异常的情形,也演示getMessage的好处 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +库存不足:所订购的商品没有及时付款,提交订单时库存不足了,导致提交失败。我们定义这种异常为OutOfInventoryException。 +\end_layout + +\begin_layout Itemize +价格变更:提交订单时商品的价格已经改变了,此时应该阻止提交订单。我们定义这种异常为PriceNotAvailableException。 +\end_layout + +\begin_layout Standard +首先我们定义这两个异常类,如 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "OutOfIventoryException.java" + +\end_inset + +和 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "PriceNotAvailableException.java" + +\end_inset + +所示。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/exception/src/cn/edu/sdut/softlab/exception/eshop/OutOfInventoryException.java" +lstparams "float,caption={OutOfIventoryException.java},label={OutOfIventoryException.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/exception/src/cn/edu/sdut/softlab/exception/eshop/PriceNotAvailableException.java" +lstparams "float,caption={PriceNotAvailableException.java},label={PriceNotAvailableException.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +在主类CustomerOrder.java中,我们设置了两个变量inventoryOK和priceOK分别代表库存和价格的状态,参见 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "CustomerOrder.java" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +。读者可以尝试修改这两个变量的值观察输出有什么变化?当然,在实际情况中,应该是根据业务逻辑给这两个变量赋值的。 +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../code/exception/src/cn/edu/sdut/softlab/exception/eshop/CustomerOrder.java" +lstparams "caption={CustomerOrder.java},label={CustomerOrder.java}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +在Idea IDE中,可以通过快捷键Alt+Insert方便的自动产生OutOfInventoryException的构造方法:选择 +\begin_inset Quotes erd +\end_inset + +override method... +\begin_inset Quotes erd +\end_inset + +,在随后弹出的窗口中选择 +\begin_inset Quotes erd +\end_inset + +Exception(s:String)”即可。 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +try with resources +\begin_inset CommandInset label +LatexCommand label +name "sec:try-with-resources" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +比较困难的一个地方是,在这里讲解try-with-resources很难举出一个合适的例子来。是否把这个部分移动到java io一章? +\end_layout + +\end_inset + +在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand vref +reference "sec:finally" + +\end_inset + +中我们看到,对于必须执行的“清理代码块”,我们可以使用finally来保证这一点。Java8更进了一步:如果一个对象实现了 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +java.lang.AutoCloseable +\end_layout + +\end_inset + +接口 +\begin_inset Foot +status open + +\begin_layout Plain Layout +由于AutoCloseable接口只有一个抽象方法close,因此AutoCloseable接口是一个函数接口,参见本系列教程的“提高篇”之“lambda表达式 +”。 +\end_layout + +\end_inset + +或者Closeable接口(这样的对象就是try-with-resources中的resource),则可以通过try-with-resources结构来保证代 +码结束时自动关闭这个对象。实现了 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +java.lang.AutoCloseable +\end_layout + +\end_inset + +接口(或者Closeable接口)的对象被称为resource。try-with-resources结构的一般形式如下 +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +本部分示例代码参见: +\begin_inset Flex URL +status open + +\begin_layout Plain Layout + +http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html +\end_layout + +\end_inset + +,我们将在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +sectionname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "chap:Java的IO" + +\end_inset + +看到比较多的try-with-resources用法。 +\end_layout + +\end_inset + +: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +try (resourse1; resource2) { +\end_layout + +\begin_layout Plain Layout + + // 正常流程 +\end_layout + +\begin_layout Plain Layout + +} catch (...) { +\end_layout + +\begin_layout Plain Layout + + // 异常流程 +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +比如下面的例子读取文件的第一行: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +static String readFirstLineFromFile(String path) throws IOException { +\end_layout + +\begin_layout Plain Layout + + try (BufferedReader br = new BufferedReader(new FileReader(path))) { +\end_layout + +\begin_layout Plain Layout + + return br.readLine(); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +BufferedReader是一个实现了AutoCloseable接口的resource(资源),因此我们把创建BufferedReader对象的工作放到了tr +y-with-resources结构中,这样无论br.readLine是否正常执行,当try-with-resources代码块执行完毕后,BufferedRea +der对象br都会被自动关闭。如果我们不使用try-with-resources结构的话,则需要这样编写同样功能的代码: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +static String readFirstLineFromFileWithFinallyBlock(String path) throws + IOException { +\end_layout + +\begin_layout Plain Layout + + BufferedReader br = new BufferedReader(new FileReader(path)); +\end_layout + +\begin_layout Plain Layout + + try { +\end_layout + +\begin_layout Plain Layout + + return br.readLine(); +\end_layout + +\begin_layout Plain Layout + + } finally { +\end_layout + +\begin_layout Plain Layout + + if (br != null) br.close(); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +可见,使用try-with-resources结构不仅简化了代码,也提高了代码的可读性。 +\end_layout + +\begin_layout Standard +下面的例子在try-with-resourses中声明了多个resources: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public static void writeToFileZipFileContents(String zipFileName, +\end_layout + +\begin_layout Plain Layout + + String outputFileName) +\end_layout + +\begin_layout Plain Layout + + throws java.io.IOException { +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + java.nio.charset.Charset charset = +\end_layout + +\begin_layout Plain Layout + + java.nio.charset.StandardCharsets.US_ASCII; +\end_layout + +\begin_layout Plain Layout + + java.nio.file.Path outputFilePath = +\end_layout + +\begin_layout Plain Layout + + java.nio.file.Paths.get(outputFileName); +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + // Open zip file and create output file with +\end_layout + +\begin_layout Plain Layout + + // try-with-resources statement +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + try ( +\end_layout + +\begin_layout Plain Layout + + java.util.zip.ZipFile zf = +\end_layout + +\begin_layout Plain Layout + + new java.util.zip.ZipFile(zipFileName); +\end_layout + +\begin_layout Plain Layout + + java.io.BufferedWriter writer = +\end_layout + +\begin_layout Plain Layout + + java.nio.file.Files.newBufferedWriter(outputFilePath, charset) +\end_layout + +\begin_layout Plain Layout + + ) { +\end_layout + +\begin_layout Plain Layout + + // Enumerate each entry +\end_layout + +\begin_layout Plain Layout + + for (java.util.Enumeration entries = +\end_layout + +\begin_layout Plain Layout + + zf.entries(); entries.hasMoreElements();) + { +\end_layout + +\begin_layout Plain Layout + + // Get the entry name and write it to the output file +\end_layout + +\begin_layout Plain Layout + + String newLine = System.getProperty("line.separator"); +\end_layout + +\begin_layout Plain Layout + + String zipEntryName = +\end_layout + +\begin_layout Plain Layout + + ((java.util.zip.ZipEntry)entries.nextElement()).getName() + +\end_layout + +\begin_layout Plain Layout + + newLine; +\end_layout + +\begin_layout Plain Layout + + writer.write(zipEntryName, 0, zipEntryName.length()); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +使用try-with-resources结构编写数据库访问程序: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public static void viewTable(Connection con) throws SQLException { +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES"; +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + try (Statement stmt = con.createStatement()) { +\end_layout + +\begin_layout Plain Layout + + ResultSet rs = stmt.executeQuery(query); +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + while (rs.next()) { +\end_layout + +\begin_layout Plain Layout + + String coffeeName = rs.getString("COF_NAME"); +\end_layout + +\begin_layout Plain Layout + + int supplierID = rs.getInt("SUP_ID"); +\end_layout + +\begin_layout Plain Layout + + float price = rs.getFloat("PRICE"); +\end_layout + +\begin_layout Plain Layout + + int sales = rs.getInt("SALES"); +\end_layout + +\begin_layout Plain Layout + + int total = rs.getInt("TOTAL"); +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + + System.out.println(coffeeName + ", " + supplierID + ", " + +\end_layout + +\begin_layout Plain Layout + + price + ", " + sales + ", " + total); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + } catch (SQLException e) { +\end_layout + +\begin_layout Plain Layout + + JDBCTutorialUtilities.printSQLException(e); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +异常处理的一般原则?举例说明,有很多种处理异常的方式,哪种更合理?谁来处理异常?throw or catch? +\end_layout + +\begin_layout Plain Layout +如何知道该捕获哪个异常? +\end_layout + +\begin_layout Plain Layout +图示责任链 +\end_layout + +\end_inset + + +\end_layout + +\end_body +\end_document diff --git a/guide/lecture_guide/lecture_guide.lyx b/guide/lecture_guide/lecture_guide.lyx new file mode 100644 index 0000000..7768fff --- /dev/null +++ b/guide/lecture_guide/lecture_guide.lyx @@ -0,0 +1,362 @@ +#LyX 2.3 created this file. For more info see http://www.lyx.org/ +\lyxformat 544 +\begin_document +\begin_header +\save_transient_properties true +\origin unavailable +\textclass ctex-book +\begin_preamble +\input{book-preamble.tex} +\usepackage[printwatermark]{xwatermark} +\newwatermark[allpages,fontfamily=bch,color=gray!25,angle=45,scale=3, +xpos=0,ypos=0]{DRAFT} +\end_preamble +\options openany,schema=chinese,heading=true +\use_default_options true +\begin_modules +logicalmkup +tip-inset +warning-inset +note-inset +shapepar +theorems-bytype +theorems-chap-bytype +coderemarks +\end_modules +\maintain_unincluded_children false +\begin_local_layout +PackageOptions url hyphens +\end_local_layout +\language chinese-simplified +\language_package default +\inputencoding utf8-plain +\fontencoding global +\font_roman "default" "DejaVu Serif" +\font_sans "default" "DejaVu Sans" +\font_typewriter "default" "DejaVu Sans Mono" +\font_math "auto" "auto" +\font_default_family default +\use_non_tex_fonts true +\font_sc false +\font_osf false +\font_sf_scale 100 100 +\font_tt_scale 100 100 +\use_microtype false +\use_dash_ligatures true +\graphics default +\default_output_format pdf4 +\output_sync 0 +\bibtex_command default +\index_command default +\float_placement tbph +\paperfontsize default +\spacing single +\use_hyperref true +\pdf_bookmarks true +\pdf_bookmarksnumbered true +\pdf_bookmarksopen true +\pdf_bookmarksopenlevel 3 +\pdf_breaklinks false +\pdf_pdfborder true +\pdf_colorlinks false +\pdf_backref false +\pdf_pdfusetitle true +\papersize default +\use_geometry false +\use_package amsmath 1 +\use_package amssymb 1 +\use_package cancel 1 +\use_package esint 1 +\use_package mathdots 1 +\use_package mathtools 1 +\use_package mhchem 1 +\use_package stackrel 1 +\use_package stmaryrd 1 +\use_package undertilde 1 +\cite_engine basic +\cite_engine_type default +\biblio_style plain +\use_bibtopic false +\use_indices false +\paperorientation portrait +\suppress_date false +\justification true +\use_refstyle 1 +\use_minted 0 +\boxbgcolor #dad3d7 +\index Index +\shortcut idx +\color #008000 +\end_index +\paperwidth 185mm +\paperheight 260mm +\secnumdepth 3 +\tocdepth 2 +\paragraph_separation indent +\paragraph_indentation default +\is_math_indent 0 +\math_numbering_side default +\quotes_style english +\dynamic_quotes 0 +\papercolumns 1 +\papersides 2 +\paperpagestyle empty +\tracking_changes false +\output_changes false +\html_math_output 0 +\html_css_as_file 0 +\html_be_strict false +\end_header + +\begin_body + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +前言部分 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +\begin_inset CommandInset toc +LatexCommand tableofcontents + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Newpage cleardoublepage +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +建立一个怎样的教学模型?类似于Mehran Sahami的karel如何?游戏,有趣,富有变化是重点。 +\end_layout + +\begin_layout Plain Layout +坦克大战也是一个很好的场景,对战对学生是很有吸引力的。 +\end_layout + +\begin_layout Plain Layout +CS呢?角色扮演。Mud? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status open + +\begin_layout Plain Layout +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +AddLabels +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Note Comment +status open + +\begin_layout Plain Layout +在页边使用章序号导航 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand include +filename "lecture1.lyx" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand include +filename "lecture2.lyx" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand include +filename "lecture3.lyx" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand include +filename "lecture4.lyx" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand include +filename "lecture5.lyx" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand include +filename "lecture6.lyx" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand include +filename "lecture7.lyx" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand include +filename "lecture8.lyx" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand include +filename "lecture9.lyx" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand include +filename "lecture10.lyx" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand include +filename "lecture11.lyx" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand include +filename "lecture12.lyx" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand include +filename "lecture13.lyx" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand include +filename "lecture14.lyx" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand include +filename "lecture15.lyx" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Newpage cleardoublepage +\end_inset + + +\end_layout + +\end_body +\end_document diff --git a/guide/lecture_guide/make_lecture.sh b/guide/lecture_guide/make_lecture.sh new file mode 100755 index 0000000..e031a3a --- /dev/null +++ b/guide/lecture_guide/make_lecture.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +lyx --export pdf4 lecture_guide.lyx diff --git a/guide/lecture_guide/readme.MD b/guide/lecture_guide/readme.MD new file mode 100644 index 0000000..1c6e89e --- /dev/null +++ b/guide/lecture_guide/readme.MD @@ -0,0 +1 @@ +教案 diff --git a/guide/object.lyx b/guide/object.lyx index 33b1899..efe4c1b 100644 --- a/guide/object.lyx +++ b/guide/object.lyx @@ -1,5 +1,5 @@ -#LyX 2.2 created this file. For more info see http://www.lyx.org/ -\lyxformat 508 +#LyX 2.3 created this file. For more info see http://www.lyx.org/ +\lyxformat 544 \begin_document \begin_header \save_transient_properties true @@ -36,6 +36,8 @@ PackageOptions url hyphens \font_osf false \font_sf_scale 100 100 \font_tt_scale 100 100 +\use_microtype false +\use_dash_ligatures false \graphics default \default_output_format pdf4 \output_sync 0 @@ -75,6 +77,7 @@ PackageOptions url hyphens \suppress_date false \justification true \use_refstyle 1 +\use_minted 0 \boxbgcolor #d8daeb \index Index \shortcut idx @@ -84,7 +87,10 @@ PackageOptions url hyphens \tocdepth 2 \paragraph_separation indent \paragraph_indentation default -\quotes_language english +\is_math_indent 0 +\math_numbering_side default +\quotes_style english +\dynamic_quotes 0 \papercolumns 1 \papersides 2 \paperpagestyle default @@ -1326,6 +1332,7 @@ status open \begin_inset CommandInset citation LatexCommand cite key "jvm-se8-specification" +literal "true" \end_inset @@ -2143,6 +2150,30 @@ status open 除了通过构造方法设置对象的初始状态外,也可以通过以下的方式进行对象的初始化操作: \end_layout +\begin_layout Itemize +定义属性的同时初始化,比如 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Circle +\end_layout + +\end_inset + +类中 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Point +\end_layout + +\end_inset + +对象的处理方式。 +\end_layout + \begin_layout Itemize 在创建对象后,直接访问对象的属性并设置希望的值。 \end_layout @@ -2157,7 +2188,7 @@ status open \begin_layout Standard \begin_inset Flex Tip -status open +status collapsed \begin_layout Plain Layout 定义有参构造方法时,要注意参数的个数不要太多,一般不要超过10个。太多的参数往往给使用者带来记忆和匹配的负担。如果需要大量的对象初始化操作,建议编写专门的方法初 @@ -2167,6 +2198,112 @@ status open \end_inset +\end_layout + +\begin_layout Standard +\begin_inset Flex Tip +status open + +\begin_layout Plain Layout +对象属性的初始化一般有两种方式:定义的时候直接初始化和使用构造方法。在 +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +lstlistingname +\end_layout + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sub322-Circle.java" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +中采用了直接初始化 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +point +\end_layout + +\end_inset + +属性的方式,如果要使用构造方法初始化point属性,则 +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Circle +\end_layout + +\end_inset + +类的定义大致为: +\end_layout + +\begin_layout Plain Layout +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +public class Circle{ +\end_layout + +\begin_layout Plain Layout + + Point origin; +\end_layout + +\begin_layout Plain Layout + + ... +\end_layout + +\begin_layout Plain Layout + + public Circle(){ +\end_layout + +\begin_layout Plain Layout + + origin = new Point(); +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + + ... +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + \end_layout \begin_layout Exercise @@ -5190,6 +5327,7 @@ public class Client { \begin_inset CommandInset citation LatexCommand cite key "design-pattern-4gangs" +literal "true" \end_inset @@ -5197,6 +5335,7 @@ key "design-pattern-4gangs" \begin_inset CommandInset citation LatexCommand cite key "design-pattern-4gangs" +literal "true" \end_inset @@ -7461,6 +7600,7 @@ JDK源代码可以从 LatexCommand href name "https://github.com/dmlloyd/openjdk" target "https://github.com/dmlloyd/openjdk" +literal "false" \end_inset @@ -8816,6 +8956,7 @@ pier继承下来一样。SmartPrinter类其实是一个Facade类 \begin_inset CommandInset citation LatexCommand cite key "design-pattern-4gangs" +literal "true" \end_inset diff --git a/guide/ppt/enum.lyx b/guide/ppt/enum.lyx index f59f522..ccd58d2 100644 --- a/guide/ppt/enum.lyx +++ b/guide/ppt/enum.lyx @@ -4,7 +4,7 @@ \begin_header \save_transient_properties true \origin unavailable -\textclass beamer-chinese +\textclass beamer \begin_preamble % see http://deic.uab.es/~iblanes/beamer_gallery/ for how % to choose theme and color @@ -169,7 +169,6 @@ C的enum回顾 \end_layout -\begin_deeper \begin_layout Itemize 定义方式: \begin_inset Newline newline @@ -203,6 +202,7 @@ enum{SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY}WEEK; \end_layout +\begin_deeper \begin_layout Itemize 使用方法: \begin_inset Newline newline @@ -285,7 +285,6 @@ plain \end_layout -\begin_deeper \begin_layout Itemize WeekDay \begin_inset Newline newline @@ -320,7 +319,6 @@ public enum WeekDay { SUNDAY,MONDAY,TUESDAY,WENDESDAY,THURSDAY,FRIDAY,SATURDAY; \end_layout -\end_deeper \begin_layout Standard \begin_inset Separator plain \end_inset @@ -351,7 +349,6 @@ plain \end_layout -\begin_deeper \begin_layout Itemize \begin_inset Box Frameless position "t" @@ -420,7 +417,6 @@ public class WeekDayTest { \end_layout -\end_deeper \begin_layout Frame \end_layout @@ -449,11 +445,11 @@ Enum的定义要点 \end_layout -\begin_deeper \begin_layout Itemize Enum关键字 \end_layout +\begin_deeper \begin_layout Itemize 最简单的定义方法 \end_layout @@ -487,11 +483,11 @@ status open \end_layout -\begin_deeper \begin_layout Itemize Enum是类 \end_layout +\begin_deeper \begin_layout Itemize 反编译Enum对象看一下 \end_layout @@ -517,11 +513,11 @@ status open \end_layout -\begin_deeper \begin_layout Itemize 定义四季 \end_layout +\begin_deeper \begin_layout Itemize 定义交通信号灯 \end_layout diff --git a/guide/ppt/enum.pdf b/guide/ppt/enum.pdf new file mode 100644 index 0000000..9d998f8 Binary files /dev/null and b/guide/ppt/enum.pdf differ diff --git a/guide/ppt/essentails.pdf b/guide/ppt/essentails.pdf new file mode 100644 index 0000000..7f94162 Binary files /dev/null and b/guide/ppt/essentails.pdf differ diff --git a/guide/ppt/exception.pdf b/guide/ppt/exception.pdf new file mode 100644 index 0000000..a39bad8 Binary files /dev/null and b/guide/ppt/exception.pdf differ diff --git a/guide/ppt/gui.pdf b/guide/ppt/gui.pdf new file mode 100644 index 0000000..4e9a1b2 Binary files /dev/null and b/guide/ppt/gui.pdf differ diff --git a/guide/ppt/io.lyx b/guide/ppt/io.lyx index c8aacc0..259c454 100644 --- a/guide/ppt/io.lyx +++ b/guide/ppt/io.lyx @@ -4,7 +4,7 @@ \begin_header \save_transient_properties true \origin unavailable -\textclass beamer-chinese +\textclass beamer \begin_preamble % see http://deic.uab.es/~iblanes/beamer_gallery/ for how % to choose theme and color @@ -169,11 +169,11 @@ C的I/O回顾 \end_layout -\begin_deeper \begin_layout Itemize 输入流 \end_layout +\begin_deeper \begin_layout Itemize 输出流 \end_layout diff --git a/guide/ppt/io.pdf b/guide/ppt/io.pdf new file mode 100644 index 0000000..8b5a14b Binary files /dev/null and b/guide/ppt/io.pdf differ diff --git a/guide/ppt/oop.pdf b/guide/ppt/oop.pdf new file mode 100644 index 0000000..d0c4303 Binary files /dev/null and b/guide/ppt/oop.pdf differ diff --git a/guide/ppt/oopm.pdf b/guide/ppt/oopm.pdf new file mode 100644 index 0000000..dc61cf7 Binary files /dev/null and b/guide/ppt/oopm.pdf differ diff --git a/guide/ppt/verybasic.pdf b/guide/ppt/verybasic.pdf new file mode 100644 index 0000000..0da001c Binary files /dev/null and b/guide/ppt/verybasic.pdf differ diff --git a/guide/tests-guide.lyx b/guide/tests-guide.lyx index dc417d6..7b56ffe 100644 --- a/guide/tests-guide.lyx +++ b/guide/tests-guide.lyx @@ -1047,8 +1047,8 @@ status open \begin_layout Plain Layout \align center \begin_inset Graphics - filename imgs/tests/oop-model.svg - scale 60 + filename imgs/tests/oop-model.eps + width 80line% \end_inset