Know the history and philosophy of Java 了解 Java 的历史和理念
Understand Java’s contribution to the Internet 理解 Java 对互联网的贡献
Understand the importance of bytecode 理解字节码的重要性
Know the Java buzzwords 了解 Java 的流行术语
Understand the foundational principles of object-oriented programming 理解面向对象编程的基本原理
Create, compile, and run a simple Java program 创建、编译并运行一个简单的 Java 程序
Use variables 使用变量
Use the if and for control statements 使用 if 和 for 控制语句
Create blocks of code 创建代码块
Understand how statements are positioned, indented, and terminated 了解语句如何定位、缩进和终止
Know the Java keywords 了解 Java 关键字
Understand the rules for Java identifiers 理解 Java 标识符的规则
n computing, few technologies have had the impact of Java. Its creation in the early days of the Web helped shape the modern form of the Internet, including both the client and server sides. Its innovative features advanced the art and science of programming, setting a new standard in computer language design. The forward-thinking culture that grew up around Java ensured it would remain vibrant and alive, adapting to the often rapid and varied changes in the computing landscape. Simply put: not only is Java one of the world’s most important computer languages, it is a force that revolutionized programming and, in the process, changed the world. 在计算领域,很少有技术能像 Java 那样产生深远影响。它在网络早期的诞生帮助塑造了现代互联网的形式,包括客户端和服务器端。其创新特性推动了编程的艺术与科学,树立了计算机语言设计的新标准。围绕 Java 形成的前瞻性文化确保了它保持活力和生命力,能够适应计算环境中经常快速且多样的变化。简而言之:Java 不仅是世界上最重要的计算机语言之一,更是一股革命性力量,彻底改变了编程,并在此过程中改变了世界。
Although Java is a language often associated with Internet programming, it is by no means limited in that regard. Java is a powerful, full-featured, general-purpose programming language. Thus, if you are new to programming, Java is an excellent language to learn. Moreover, to be a professional programmer today implies the ability to program in Java—it is that important. In the course of this book, you will learn the basic skills that will help you master it. 尽管 Java 常被认为是与互联网编程相关的语言,但它绝不仅限于此。Java 是一种功能强大、全功能的通用编程语言。因此,如果你是编程新手,Java 是一个极佳的学习语言。此外,成为一名专业程序员意味着必须具备 Java 编程能力——它的重要性不言而喻。在本书的学习过程中,你将掌握帮助你精通 Java 的基本技能。
The purpose of this chapter is to introduce you to Java, beginning with its history, its design philosophy, and several of its most important features. By far, the hardest thing about learning a programming language is the fact that no element exists in isolation. Instead, the components of the language work in conjunction with each other. This interrelatedness is especially pronounced in Java. In fact, it is difficult to discuss one aspect of Java without involving others. To help overcome this problem, this chapter provides a brief overview 本章的目的是向你介绍 Java,从它的历史、设计理念以及几个最重要的特性开始。学习一门编程语言最难的地方莫过于没有任何元素是孤立存在的。相反,语言的各个组成部分是相互协作的。这种相互关联在 Java 中尤为明显。事实上,很难单独讨论 Java 的某一方面而不涉及其他方面。为帮助克服这个问题,本章提供了几个 Java 特性的简要概述
of several Java features, including the general form of a Java program, some basic control structures, and simple operators. It does not go into too many details, but, rather, concentrates on general concepts common to any Java program. ,包括 Java 程序的一般形式、一些基本的控制结构和简单的运算符。它不会涉及过多细节,而是集中于任何 Java 程序共有的一般概念。
The History and Philosophy of Java Java 的历史与理念
Before one can fully appreciate the unique aspects of Java, it is necessary to understand the forces that drove its creation, the programming philosophy that it embodies, and key concepts of its design. As you advance through this book, you will see that many aspects of Java are either a direct or indirect result of the historical forces that shaped the language. Thus, it is fitting that we begin our examination of Java by exploring how Java relates to the larger programming universe. 在充分理解 Java 的独特之处之前,有必要了解促使其诞生的动力、它所体现的编程理念以及其设计的关键概念。随着你阅读本书,你会发现 Java 的许多方面都是由塑造该语言的历史力量直接或间接导致的。因此,我们从探讨 Java 与更广泛的编程世界的关系开始,来审视 Java 是恰当的。
The Origins of Java Java 的起源
Java was conceived by James Gosling, Patrick Naughton, Chris Warth, Ed Frank, and Mike Sheridan at Sun Microsystems in 1991. This language was initially called “Oak” but was renamed “Java” in 1995. Somewhat surprisingly, the original impetus for Java was not the Internet! Instead, the primary motivation was the need for a platform-independent language that could be used to create software to be embedded in various consumer electronic devices, such as toasters, microwave ovens, and remote controls. As you can probably guess, many different types of CPUs are used as controllers. The trouble was that (at the time) most computer languages were designed to be compiled into machine code that was targeted for a specific type of CPU. For example, consider the C++ language. Java 由 James Gosling、Patrick Naughton、Chris Warth、Ed Frank 和 Mike Sheridan 于 1991 年在 Sun Microsystems 构思。该语言最初被称为“Oak”,但在 1995 年更名为“Java”。有些令人惊讶的是,Java 的最初动力并非互联网!相反,主要动机是需要一种平台无关的语言,用于创建嵌入各种消费电子设备的软件,比如烤面包机、微波炉和遥控器。正如你可能猜到的,许多不同类型的 CPU 被用作控制器。问题是(当时)大多数计算机语言设计成编译成针对特定类型 CPU 的机器码。例如,考虑 C++语言。
Although it was possible to compile a C++ program for just about any type of CPU, to do so required a full C++ compiler targeted for that CPU. The problem, however, is that compilers are expensive and time consuming to create. In an attempt to find a better solution, Gosling and the others worked on a portable, cross-platform language that could produce code that would run on a variety of CPUs under differing environments. This effort ultimately led to the creation of Java. 虽然几乎可以为任何类型的 CPU 编译 C++程序,但这需要针对该 CPU 的完整 C++编译器。然而,问题在于编译器的开发既昂贵又耗时。为了寻找更好的解决方案,Gosling 和其他人致力于开发一种可移植的跨平台语言,能够生成在不同环境下多种 CPU 上运行的代码。这一努力最终促成了 Java 的诞生。
About the time that the details of Java were being worked out, a second, and ultimately more important, factor emerged that would play a crucial role in the future of Java. This second force was, of course, the World Wide Web. Had the Web not taken shape at about the same time that Java was being implemented, Java might have remained a useful but obscure language for programming consumer electronics. However, with the emergence of the Web, Java was propelled to the forefront of computer language design, because the Web, too, demanded portable programs. 大约在 Java 细节被敲定的同时,出现了第二个且最终更为重要的因素,这个因素在 Java 的未来发展中起到了关键作用。这个第二个力量当然就是万维网。如果万维网没有在 Java 实现的同时形成,Java 可能会一直是一个用于编程消费电子产品的有用但鲜为人知的语言。然而,随着万维网的出现,Java 被推到了计算机语言设计的前沿,因为万维网同样需要可移植的程序。
Most programmers learn early in their careers that portable programs are as elusive as they are desirable. While the quest for a way to create efficient, portable (platform-independent) programs is nearly as old as the discipline of programming itself, it had taken a back seat to other, more pressing problems. However, with the advent of the Internet and the Web, the old problem of portability returned with a vengeance. After all, the Internet consisted of a diverse, distributed universe populated with many types of computers, operating systems, and CPUs. 大多数程序员在职业生涯早期就会意识到,便携式程序既难以实现又极具吸引力。虽然寻找一种创建高效、便携(平台无关)程序的方法几乎和编程这门学科一样古老,但它一直被其他更紧迫的问题所掩盖。然而,随着互联网和万维网的出现,便携性这一老问题卷土重来。毕竟,互联网是一个多样化、分布式的宇宙,里面充斥着各种类型的计算机、操作系统和 CPU。
What was once an irritating but low-priority problem had become a high-profile necessity. By 1993 it became obvious to members of the Java design team that the problems of portability frequently encountered when creating code for embedded controllers are also found when 曾经是一个令人恼火但优先级较低的问题,如今已成为一个备受关注的必要条件。到了 1993 年,Java 设计团队的成员们明显意识到,在为嵌入式控制器编写代码时经常遇到的便携性问题,同样存在于为互联网编写代码的过程中。
attempting to create code for the Internet. This realization caused the focus of Java to switch from consumer electronics to Internet programming. So, although it was the desire for an architecture-neutral programming language that provided the initial spark, it was the Internet that ultimately led to Java’s large-scale success. 这一认识促使 Java 的重点从消费电子转向互联网编程。因此,尽管最初激发 Java 诞生的是对一种架构中立编程语言的渴望,但最终促成 Java 大规模成功的却是互联网。
Java's Lineage: C and C++ Java 的血统:C 和 C++
The history of computer languages is not one of isolated events. Rather, it is a continuum in which each new language is influenced in one way or another by what has come before. In this regard, Java is no exception. Before moving on, it is useful to understand where Java fits into the family tree of computer languages. 计算机语言的历史不是一系列孤立的事件。相反,它是一个连续体,每一种新语言在某种程度上都受到之前语言的影响。在这方面,Java 也不例外。在继续之前,了解 Java 在计算机语言家族树中的位置是很有用的。
The two languages that form Java’s closest ancestors are C and C++\mathrm{C}++. As you may know, C and C++\mathrm{C}++ are among the most important computer languages ever invented and are still in widespread use today. From C, Java inherits its syntax. Java’s object model is adapted from C++. Java’s relationship to C and C++\mathrm{C}++ is important for a number of reasons. First, at the time of Java’s creation, many programmers were familiar with the C/C++ syntax. Because Java uses a similar syntax, it was relatively easy for a C/C++ programmer to learn Java. This made it possible for Java to be readily utilized by the pool of existing programmers, thus facilitating Java’s acceptance by the programming community. 构成 Java 最接近祖先的两种语言是 C 和 C++\mathrm{C}++ 。正如你可能知道的,C 和 C++\mathrm{C}++ 是有史以来最重要的计算机语言之一,至今仍被广泛使用。Java 继承了 C 的语法。Java 的对象模型则是从 C++改编而来。Java 与 C 和 C++\mathrm{C}++ 的关系有多方面的重要意义。首先,在 Java 诞生之时,许多程序员已经熟悉 C/C++的语法。由于 Java 使用了类似的语法,C/C++程序员学习 Java 相对容易。这使得 Java 能够被现有程序员群体迅速采用,从而促进了 Java 在编程社区的接受度。
Second, Java’s designers did not “reinvent the wheel.” Instead, they further refined an already highly successful programming paradigm. The modern age of programming began with C . It moved to C++\mathrm{C}++ and then to Java. By inheriting and building on that rich heritage, Java provides a powerful, logically consistent programming environment that takes the best of the past and adds new features related to the online environment and advances in the art of programming. Perhaps most important, because of their similarities, C, C++, and Java define a common, conceptual framework for the professional programmer. Programmers do not face major rifts when switching from one language to another. 其次,Java 的设计者并没有“重新发明轮子”。相反,他们进一步完善了已经非常成功的编程范式。现代编程时代始于 C 语言,随后发展到 C++\mathrm{C}++ ,再到 Java。通过继承并建立在这一丰富的遗产之上,Java 提供了一个强大且逻辑一致的编程环境,既汲取了过去的精华,又增加了与在线环境和编程艺术进步相关的新特性。也许最重要的是,由于它们的相似性,C、C++和 Java 为专业程序员定义了一个共同的概念框架。程序员在从一种语言切换到另一种语言时不会面临重大分歧。
Java has another attribute in common with C and C++\mathrm{C}++ : it was designed, tested, and refined by real working programmers. It is a language grounded in the needs and experiences of the people who devised it. There is no better way to produce a top-flight professional programming language. Java 还有一个与 C 和 C++\mathrm{C}++ 共同的特点:它是由真正的在职程序员设计、测试和完善的。这是一种基于设计者需求和经验的语言。没有比这更好的方法来打造一门顶级的专业编程语言。
One last point: although C++ and Java are related, especially in their support for objectoriented programming, Java is not simply the “Internet version of C++.” Java has significant practical and philosophical differences from C++. Furthermore, Java is not an enhanced version of C++. For example, it is neither upwardly nor downwardly compatible with C++. Moreover, Java was not designed to replace C++. Java was designed to solve a certain set of problems. C++ was designed to solve a different set of problems. They will coexist for many years to come. 最后一点:虽然 C++和 Java 有联系,特别是在支持面向对象编程方面,但 Java 并不是简单的“C++的互联网版本”。Java 在实际应用和理念上与 C++有显著的不同。此外,Java 也不是 C++的增强版。例如,它既不向上兼容也不向下兼容 C++。更重要的是,Java 并不是为了取代 C++而设计的。Java 是为了解决一组特定的问题而设计的,而 C++是为了解决另一组不同的问题而设计的。它们将在未来许多年里共存。
How Java Impacted the Internet Java 如何影响互联网
The Internet helped catapult Java to the forefront of programming, and Java, in turn, had a profound effect on the Internet. First, the creation of Java simplified Internet programming in general, acting as a catalyst that drew legions of programmers to the Web. Second, Java innovated a new type of networked program called the applet that changed the way the online world thought about content. Finally, and perhaps most importantly, Java addressed some of the thorniest issues associated with the Internet: portability and security. 互联网帮助 Java 迅速成为编程领域的前沿技术,而 Java 反过来也对互联网产生了深远的影响。首先,Java 的诞生简化了互联网编程,成为吸引大量程序员投身网络开发的催化剂。其次,Java 创新性地推出了一种新的网络程序类型——applet(小程序),改变了在线世界对内容的看法。最后,也许最重要的是,Java 解决了互联网中一些最棘手的问题:可移植性和安全性。
From the start, Java simplified web-based programming in a number of ways. Arguably the most important is found in its ability to create portable, cross-platform programs. Of nearly equal importance is Java’s support for networking. Its library of ready-to-use functionality enabled programmers to easily write programs that accessed or made use of the Internet. It also provided mechanisms that enabled programs to be readily delivered over the Internet. Although the details are beyond the scope of this book, it is sufficient to know that Java’s support for networking was a key factor in its rapid rise. 从一开始,Java 就在多方面简化了基于网络的编程。可以说,最重要的一点是它能够创建可移植的跨平台程序。几乎同等重要的是 Java 对网络的支持。它的现成功能库使程序员能够轻松编写访问或利用互联网的程序。它还提供了机制,使程序能够方便地通过互联网传输。虽然具体细节超出本书范围,但足以知道 Java 对网络的支持是其快速崛起的关键因素。
Java Applets Java 小程序
At the time of Java’s creation, one of its most exciting features was the applet. An applet is a special kind of Java program that is designed to be transmitted over the Internet and automatically executed inside a Java-compatible web browser. If the user clicks a link that contains an applet, the applet will download and run in the browser automatically. Applets were intended to be small programs, typically used to display data provided by the server, handle user input, or provide simple functions, such as a loan calculator. The key feature of applets is that they execute locally, rather than on the server. In essence, the applet allowed some functionality to be moved from the server to the client. 在 Java 诞生之时,其最令人兴奋的特性之一是 Applet。Applet 是一种特殊的 Java 程序,设计用于通过互联网传输,并在支持 Java 的网页浏览器中自动执行。如果用户点击包含 Applet 的链接,Applet 将自动下载并在浏览器中运行。Applet 旨在成为小型程序,通常用于显示服务器提供的数据、处理用户输入或提供简单功能,例如贷款计算器。Applet 的关键特性是它们在本地执行,而不是在服务器上。实质上,Applet 使部分功能从服务器转移到了客户端。
The creation of the applet was important because, at the time, it expanded the universe of objects that could move about freely in cyberspace. In general, there are two very broad categories of objects that are transmitted between the server and the client: passive information and dynamic active programs. For example, when you read your e-mail, you are viewing passive data. Even when you download a program, the program’s code is still only passive data until you execute it. By contrast, the applet is a dynamic, self-executing program. Such a program is an active agent on the client computer, yet it is delivered by the server. 小程序的创建非常重要,因为在当时,它扩展了可以在网络空间中自由移动的对象的范围。一般来说,服务器和客户端之间传输的对象大致分为两类:被动信息和动态活动程序。例如,当你查看电子邮件时,你看到的是被动数据。即使你下载了一个程序,该程序的代码在执行之前仍然只是被动数据。相比之下,小程序是一个动态的、自执行的程序。这样的程序是客户端计算机上的一个活动代理,但它是由服务器传送的。
In the early days of Java, applets were a crucial part of Java programming. They illustrated the power and benefits of Java, added an exciting dimension to web pages, and enabled programmers to explore the full extent of what was possible with Java. Although it is likely that there are still applets in use today, over time they became less important, and for reasons that will be explained shortly, JDK 9 began their phase-out process. Finally, applet support was removed by JDK 11. 在 Java 的早期,小程序是 Java 编程的重要组成部分。它们展示了 Java 的强大功能和优势,为网页增添了令人兴奋的维度,并使程序员能够探索 Java 的全部可能性。尽管现在可能仍有小程序在使用,但随着时间推移,它们的重要性逐渐降低,原因将在后文解释,JDK 9 开始逐步淘汰小程序支持。最终,JDK 11 完全移除了对小程序的支持。
Ask the Expert 专家问答
What is C# and how does it relate to Java? 什么是 C#,它与 Java 有什么关系?
A: A few years after the creation of Java, Microsoft developed the C# language. This is important because C# is closely related to Java. In fact, many of C#'s features directly parallel Java. Both Java and C# share the same general C+±style syntax, support distributed programming, and utilize a similar object model. There are, of course, differences between Java and C#, but the overall “look and feel” of these languages is very similar. This means that if you already know C#, then learning Java will be especially easy. Conversely, if C# is in your future, then your knowledge of Java will come in handy. A: 在 Java 诞生几年后,微软开发了 C#语言。这一点很重要,因为 C#与 Java 关系密切。实际上,C#的许多特性都与 Java 直接对应。Java 和 C#都采用类似 C++风格的语法,支持分布式编程,并使用相似的对象模型。当然,Java 和 C#之间存在差异,但这两种语言的整体“外观和感觉”非常相似。这意味着如果你已经掌握了 C#,学习 Java 将特别容易。反之,如果你未来要学习 C#,那么你对 Java 的了解也会派上用场。
Security 安全性
As desirable as dynamic, networked programs are, they also present serious problems in the areas of security and portability. Obviously, a program that downloads and executes on the client computer must be prevented from doing harm. It must also be able to run in a variety of different environments and under different operating systems. As you will see, Java addressed these problems in an effective and elegant way. Let’s look a bit more closely at each, beginning with security. 尽管动态的、网络化的程序非常受欢迎,但它们在安全性和可移植性方面也带来了严重的问题。显然,一个下载并在客户端计算机上执行的程序必须被防止造成伤害。它还必须能够在各种不同的环境和不同的操作系统下运行。正如你将看到的,Java 以一种有效且优雅的方式解决了这些问题。让我们更仔细地看看每个问题,先从安全性开始。
As you are likely aware, every time that you download a program, you are taking a risk because the code you are downloading might contain a virus, Trojan horse, or other harmful code. At the core of the problem is the fact that malicious code can cause damage because it has gained unauthorized access to system resources. For example, a virus program might gather private information, such as credit card numbers, bank account balances, and passwords, by searching the contents of your computer’s local file system. In order for Java to enable programs to be safely downloaded and executed on the client computer, it was necessary to prevent them from launching such an attack. 正如你可能知道的,每次下载程序时,你都在冒风险,因为你下载的代码可能包含病毒、特洛伊木马或其他有害代码。问题的核心在于恶意代码能够造成损害,是因为它获得了对系统资源的未经授权的访问。例如,病毒程序可能通过搜索你计算机本地文件系统的内容,收集私人信息,如信用卡号码、银行账户余额和密码。为了使 Java 能够安全地下载并在客户端计算机上执行程序,有必要防止它们发起此类攻击。
Java achieved this protection by enabling you to confine an application to the Java execution environment and prevent it from accessing other parts of the computer. (You will see how this is accomplished shortly.) The ability to download an application with a high level of confidence that no harm will be done contributed significantly to Java’s early success. Java 通过使你能够将应用程序限制在 Java 执行环境中,并防止其访问计算机的其他部分,从而实现了这种保护。(你很快就会看到这是如何实现的。)能够以高度信心下载应用程序而不造成任何损害,这一点极大地促进了 Java 的早期成功。
Portability 可移植性
Portability is a major aspect of the Internet because there are many different types of computers and operating systems connected to it. If a Java program were to be run on virtually any computer connected to the Internet, there needed to be some way to enable that program to execute on different types of systems. In other words, a mechanism that allows the same application to be downloaded and executed by a wide variety of CPUs, operating systems, and browsers is required. It is not practical to have different versions of the same application for different computers. The same application code must work in all computers. Therefore, some means of generating portable code was needed. As you will soon see, the same mechanism that helps ensure security also helps create portability. 可移植性是互联网的一个重要方面,因为连接到互联网的计算机和操作系统种类繁多。如果要在几乎任何连接到互联网的计算机上运行 Java 程序,就需要有某种方式使该程序能够在不同类型的系统上执行。换句话说,需要一种机制,允许同一个应用程序被各种 CPU、操作系统和浏览器下载并执行。为不同的计算机制作同一应用程序的不同版本是不切实际的。同一应用程序代码必须能在所有计算机上运行。因此,需要某种生成可移植代码的方法。正如你很快会看到的,帮助确保安全性的同一机制也有助于实现可移植性。
Java's Magic: The Bytecode Java 的魔力:字节码
The key that allowed Java to address both the security and the portability problems just described is that the output of a Java compiler is not executable code. Rather, it is bytecode. Bytecode is a highly optimized set of instructions designed to be executed by what is called the Java Virtual Machine (JVM), which is part of the Java Runtime Environment (JRE). In essence, the original JVM was designed as an interpreter for bytecode. This may come as a bit of a surprise because many modern languages are designed to be compiled into CPU-specific, executable code due to performance concerns. However, the fact that a Java program is executed by the JVM helps solve the major problems associated with web-based programs. Here is why. 允许 Java 同时解决上述安全性和可移植性问题的关键在于,Java 编译器的输出不是可执行代码,而是字节码。字节码是一组高度优化的指令,设计用于由称为 Java 虚拟机(JVM)的组件执行,JVM 是 Java 运行时环境(JRE)的一部分。本质上,最初的 JVM 被设计为字节码的解释器。这可能有些令人惊讶,因为许多现代语言出于性能考虑,通常被设计为编译成特定 CPU 的可执行代码。然而,Java 程序由 JVM 执行这一事实,有助于解决与基于网络的程序相关的主要问题。原因如下。
Translating a Java program into bytecode makes it much easier to run a program in a wide variety of environments because only the JRE (which includes the JVM) needs to be implemented for each platform. Once a JRE exists for a given system, any Java program can run on it. Remember, although the details of the JRE will differ from platform to platform, all JREs understand the same Java bytecode. If a Java program were compiled to native code, then 将 Java 程序翻译成字节码,使得在各种环境中运行程序变得更加容易,因为每个平台只需实现 JRE(包括 JVM)即可。一旦某个系统存在 JRE,任何 Java 程序都可以在其上运行。请记住,尽管 JRE 的细节因平台而异,但所有 JRE 都能理解相同的 Java 字节码。如果 Java 程序被编译成本地代码,那么
different versions of the same program would have to exist for each type of CPU connected to the Internet. This is, of course, not a feasible solution. Thus, the execution of bytecode by the JVM is the easiest way to create truly portable programs. 同一程序的不同版本必须针对连接到互联网的每种类型的 CPU 存在。当然,这不是一个可行的解决方案。因此,由 JVM 执行字节码是创建真正可移植程序的最简单方法。
The fact that a Java program is executed by the JVM also helps to make it secure. Because the JVM is in control, it manages program execution. Thus, it was possible for the JVM to create a restricted execution environment, called the sandbox, that contains the program, preventing unrestricted access to the machine. Safety is also enhanced by certain restrictions that exist in the Java language. Java 程序由 JVM 执行这一事实也有助于提高其安全性。因为 JVM 处于控制之中,它管理程序的执行。因此,JVM 能够创建一个受限的执行环境,称为沙箱,来包含程序,防止对机器的无限制访问。Java 语言中存在的某些限制也增强了安全性。
When a program is interpreted, it generally runs slower than the same program would run if compiled to executable code. However, with Java, the differential between the two is not so great. Because bytecode has been highly optimized, the use of bytecode enables the JVM to execute programs much faster than you might expect. 当程序被解释执行时,其运行速度通常比编译成可执行代码的同一程序要慢。然而,对于 Java 来说,两者之间的差异并不大。由于字节码经过高度优化,使用字节码使得 JVM 能够比预期更快地执行程序。
Although Java was designed as an interpreted language, there is nothing about Java that prevents on-the-fly compilation of bytecode into native code in order to boost performance. For this reason, the HotSpot JVM was introduced not long after Java’s initial release. HotSpot includes a just-in-time (JIT) compiler for bytecode. When a JIT compiler is part of the JVM, selected portions of bytecode are compiled into executable code in real time on a piece-bypiece demand basis. That is, a JIT compiler compiles code as it is needed during execution. Furthermore, not all sequences of bytecode are compiled-only those that will benefit from compilation. The remaining code is simply interpreted. However, the just-in-time approach still yields a significant performance boost. Even when dynamic compilation is applied to bytecode, the portability and safety features still apply because the JVM is still in charge of the execution environment. 尽管 Java 被设计为一种解释型语言,但 Java 本身并不妨碍将字节码即时编译成本地代码以提升性能。正因如此,HotSpot JVM 在 Java 最初发布后不久便被引入。HotSpot 包含一个字节码的即时编译器(JIT 编译器)。当 JIT 编译器成为 JVM 的一部分时,字节码的选定部分会根据需求实时逐块编译成可执行代码。也就是说,JIT 编译器会在执行过程中按需编译代码。此外,并非所有字节码序列都会被编译,只有那些编译后能带来性能提升的部分才会被编译,其余代码则继续被解释执行。然而,即时编译方法仍然能显著提升性能。即使对字节码应用动态编译,Java 的可移植性和安全特性依然有效,因为 JVM 仍然负责执行环境的管理。
One other point: There has been experimentation with an ahead-of-time compiler for Java. Such a compiler can be used to compile bytecode into native code prior to execution by the JVM, rather than on-the-fly. Some previous versions of the JDK supplied an experimental ahead-of-time compiler; however, JDK 17 has removed it. Ahead-of-time compilation is a specialized feature and it does not replace Java’s traditional approach just described. Because of the highly sophisticated nature of ahead-of-time compilation, it is not something that you will use when learning Java, and it is not discussed further in this book. 还有一点:曾经有人尝试过为 Java 开发一种提前编译器。这种编译器可以在 JVM 执行之前,将字节码编译成本地代码,而不是在运行时即时编译。JDK 的某些早期版本提供了一个实验性的提前编译器;然而,JDK 17 已经移除了它。提前编译是一项专业功能,并不取代前面介绍的 Java 传统方法。由于提前编译的高度复杂性,在学习 Java 时你不会用到它,本书也不会对此做进一步讨论。
Ask the Expert 请教专家
Q: I have heard about a special type of Java program called a servlet. What is it? 问:我听说过一种特殊的 Java 程序,叫做 servlet。它是什么?
A: A Java servlet is a small program that executes on a server. Servlets dynamically extend the functionality of a web server. It is helpful to understand that as useful as client-side applications can be, they are just one half of the client/server equation. Not long after the initial release of Java, it became obvious that Java would also be useful on the server side. One result was the servlet. Thus, with the advent of the servlet, Java spanned both sides of the client/server connection. Although the topic of servlets, and server-side programming in general, is beyond the scope of this beginner’s guide, they are something that you will likely find of interest as you advance in Java programming. A: Java servlet 是一种在服务器上执行的小程序。Servlet 动态地扩展了 Web 服务器的功能。理解客户端应用程序虽然有用,但它们只是客户端/服务器关系中的一半,这一点很有帮助。在 Java 最初发布后不久,人们就意识到 Java 在服务器端同样有用。其结果之一就是 servlet 的出现。因此,随着 servlet 的出现,Java 跨越了客户端/服务器连接的两端。虽然 servlet 以及服务器端编程的主题超出了本初学者指南的范围,但随着你在 Java 编程中的进步,你很可能会对它们产生兴趣。
Moving Beyond Applets 超越 Applet
At the time of this writing, it has been more than two decades since Java’s original release. Over those years, many changes have taken place. At the time of Java’s creation, the Internet was a new and exciting innovation; web browsers were undergoing rapid development and refinement; the modern form of the smartphone had not yet been invented; and the near ubiquitous use of computers was still a few years off. As you would expect, Java has also changed and so, too, has the way that Java is used. Perhaps nothing illustrates the ongoing evolution of Java better than the applet. 在撰写本文时,距离 Java 最初发布已经过去了二十多年。在这期间,发生了许多变化。Java 诞生之时,互联网还是一项新颖且令人兴奋的创新;网页浏览器正处于快速发展和完善阶段;现代智能手机的形态尚未被发明;计算机的几乎普及还需要几年时间。正如你所料,Java 也发生了变化,Java 的使用方式也随之改变。也许没有什么比 Applet 更能体现 Java 不断演变的过程。
As explained previously, in the early years of Java, applets were a crucial part of Java programming. They not only added excitement to a web page, they were a highly visible part of Java, which added to its charisma. However, applets rely on a Java browser plug-in. Thus, for an applet to work, it must be supported by the browser. Over the past few years support for the Java browser plug-in has been waning. Simply put, without browser support, applets are not viable. Because of this, beginning with JDK 9, the phase-out of applets was begun, with support for applets being deprecated. In the language of Java, deprecated means that a feature is still available but flagged as obsolete. Thus, a deprecated feature should not be used for new code. The phase-out became complete with the release of JDK 11 because run-time support for applets was removed. Beginning with JDK 17, the entire Applet API was deprecated for removal, which means that it will be removed from the JDK at some point in the future. 如前所述,在 Java 的早期,applet 是 Java 编程的重要组成部分。它们不仅为网页增添了趣味性,还作为 Java 的一个高度可见的部分,提升了 Java 的魅力。然而,applet 依赖于 Java 浏览器插件。因此,applet 要正常运行,必须得到浏览器的支持。近年来,浏览器对 Java 插件的支持逐渐减少。简单来说,没有浏览器支持,applet 就无法使用。正因为如此,从 JDK 9 开始,applet 的淘汰工作启动,applet 的支持被标记为不推荐使用。在 Java 语言中,不推荐使用(deprecated)意味着该功能仍可用,但被标记为过时,因此不应在新代码中使用。随着 JDK 11 的发布,applet 的淘汰工作完成,因为运行时对 applet 的支持被移除。从 JDK 17 开始,整个 Applet API 被标记为将被移除,这意味着它将在未来某个时间点从 JDK 中删除。
As a point of interest, a few years after Java’s creation an alternative to applets was added. Called Java Web Start, it enabled an application to be dynamically downloaded from a web page. It was a deployment mechanism that was especially useful for larger Java applications that were not appropriate for applets. The difference between an applet and a Web Start application is that a Web Start application runs on its own, not inside the browser. Thus, it looks much like a “normal” application. It does, however, require that a stand-alone JRE that supports Web Start is available on the host system. Beginning with JDK 11, support for Java Web Start has been removed. 作为一个有趣的点,在 Java 诞生几年后,添加了一种替代 applet 的方式。称为 Java Web Start,它使得应用程序可以从网页动态下载。这是一种部署机制,特别适用于那些不适合 applet 的较大型 Java 应用程序。applet 和 Web Start 应用程序的区别在于,Web Start 应用程序独立运行,而不是在浏览器内运行。因此,它看起来更像一个“普通”的应用程序。不过,它确实要求主机系统上必须有支持 Web Start 的独立 JRE。从 JDK 11 开始,Java Web Start 的支持已被移除。
Given that neither applets nor Java Web Start are viable options for modern versions of Java, you might wonder what mechanism should be used to deploy a Java application. At the time of this writing, one part of the answer is to use the jlink tool added by JDK 9. It can create a complete run-time image that includes all necessary support for your program, including the JRE. Another part of the answer is the jpackage tool. Added by JDK 16, it can be used to create a ready-to-install application. As you might guess, deployment is a rather advanced topic that is outside the scope of this book. Fortunately, you won’t need to worry about deployment to use this book because all of the sample programs run directly on your computer. They are not deployed over the Internet. 鉴于 Applet 和 Java Web Start 都不再是现代 Java 版本的可行选项,你可能会想知道应该使用什么机制来部署 Java 应用程序。在撰写本文时,答案的一部分是使用 JDK 9 新增的 jlink 工具。它可以创建一个完整的运行时映像,其中包含程序所需的所有支持,包括 JRE。答案的另一部分是 jpackage 工具。该工具由 JDK 16 引入,可用于创建一个可直接安装的应用程序。正如你可能猜到的,部署是一个相当高级的话题,超出了本书的范围。幸运的是,为了使用本书,你无需担心部署问题,因为所有示例程序都直接在你的计算机上运行,而不是通过互联网部署。
A Faster Release Schedule 更快的发布周期
Not long ago, another major change occurred in Java, but it does not involve changes to the language or the run-time environment. Rather, it relates to the way that Java releases are scheduled. In the past, major Java releases were typically separated by two or more years. However, subsequent to the release of JDK 9, the time between major Java releases has been decreased. Today, it is anticipated that a major release will occur on a strict time-based schedule, with the expected time between major releases being just six months. 不久前,Java 又发生了一个重大变化,但这次并不涉及语言或运行时环境的改变。而是与 Java 版本发布的时间安排有关。过去,主要的 Java 版本发布通常相隔两年或更长时间。然而,在 JDK 9 发布之后,主要 Java 版本之间的间隔时间缩短了。如今,预计主要版本将按照严格的时间表发布,主要版本之间的预期间隔仅为六个月。
Each major release, now called a feature release, will include those features ready at the time of the release. This increased release cadence enables new features and enhancements to be available to Java programmers in a timely fashion. Furthermore, it allows Java to respond quickly to the demands of an ever-changing programming environment. Simply put, the faster release schedule promises to be a very positive development for Java programmers. 每个主要版本,现在称为功能版本,将包含在发布时已准备好的功能。这种加快的发布节奏使得新功能和改进能够及时提供给 Java 程序员。此外,它还使 Java 能够快速响应不断变化的编程环境的需求。简而言之,更快的发布计划对 Java 程序员来说无疑是一个非常积极的发展。
At three-year intervals it is anticipated that a long-term support (LTS) release will take place. An LTS release will be supported (and thus remain viable) for a period of time longer than six months. The first LTS release was JDK 11. The second LTS release was JDK 17, for which this book has been updated. Because of the stability that an LTS release offers, it is likely that its feature-set will define a baseline of functionality for a number of years. Consult Oracle for the latest information concerning long-term support and the LTS release schedule. 预计每隔三年会发布一次长期支持(LTS)版本。LTS 版本的支持期限(因此也保持其可用性)将超过六个月。第一个 LTS 版本是 JDK 11。第二个 LTS 版本是 JDK 17,本书已针对该版本进行了更新。由于 LTS 版本提供的稳定性,其功能集很可能会在若干年内定义一个功能基线。有关长期支持和 LTS 版本发布计划的最新信息,请咨询 Oracle。
Currently, feature releases are scheduled for March and September of each year. As a result, JDK 10 was released in March 2018, which was six months after the release of JDK 9. The next release (JDK 11) was in September 2018. It was an LTS release. This was followed by JDK 12 In March 2019, JDK 13 in September 2019, and so on. At the time of this writing, the latest release is JDK 17, which is an LTS release. Again, it is anticipated that every six months a new feature release will take place. Of course, you will want to consult the latest release schedule information. 目前,功能版本计划在每年的三月和九月发布。因此,JDK 10 于 2018 年 3 月发布,距离 JDK 9 发布仅六个月。下一版本(JDK 11)于 2018 年 9 月发布,这是一个 LTS 版本。随后是 2019 年 3 月的 JDK 12,2019 年 9 月的 JDK 13,依此类推。撰写本文时,最新版本是 JDK 17,它是一个 LTS 版本。同样,预计每六个月会发布一个新的功能版本。当然,您需要查阅最新的发布计划信息。
At the time of this writing, there are a number of new Java features on the horizon. Because of the faster release schedule, it is very likely that several of them will be added to Java over the next few years. You will want to review the information and release notes provided by each sixmonth release in detail. It is truly an exciting time to be a Java programmer! 在撰写本文时,许多新的 Java 特性正处于即将发布的阶段。由于发布周期加快,未来几年内很可能会有多个新特性被加入到 Java 中。你需要详细查看每个六个月发布版本提供的信息和发布说明。对于 Java 程序员来说,这真是一个令人兴奋的时代!
The Java Buzzwords Java 热词
No history of Java is complete without a look at the Java buzzwords. Although the fundamental forces that necessitated the invention of Java are portability and security, other factors played an important role in molding the final form of the language. The key considerations were summed up by the Java design team in the following list of buzzwords. 没有对 Java 历史的回顾,就无法完整了解 Java 热词。虽然促使 Java 诞生的根本动力是可移植性和安全性,但其他因素也在塑造语言最终形态中发挥了重要作用。Java 设计团队将关键考虑因素总结为以下热词列表。
Simple 简单
Java has a concise, cohesive set of features that makes it easy to learn and use. Java 拥有简洁且内聚的特性,使其易于学习和使用。
Secure 安全
Java provides a secure means of creating Internet applications. Java 提供了一种安全的方式来创建互联网应用程序。
Portable 可移植
Java programs can execute in any environment for which there is a Java runtime system. Java 程序可以在任何拥有 Java 运行时系统的环境中执行。
Object-oriented 面向对象
Java embodies the modern object-oriented programming philosophy. Java 体现了现代面向对象编程的理念。
Robust 健壮性
Java encourages error-free programming by being strictly typed and performing run-time checks. Java 通过严格的类型检查和运行时检查来鼓励无错误编程。
Multithreaded 多线程
Java provides integrated support for multithreaded programming. Java 提供了对多线程编程的集成支持。
Architecture-neutral 架构中立
Java is not tied to a specific machine or operating system architecture. Java 不依赖于特定的机器或操作系统架构。
Interpreted 解释执行
Java supports cross-platform code through the use of Java bytecode. Java 通过使用 Java 字节码支持跨平台代码。
High performance 高性能
The Java bytecode is highly optimized for speed of execution. Java 字节码经过高度优化,以提高执行速度。
Distributed 分布式
Java was designed with the distributed environment of the Internet in mind. Java 的设计考虑到了互联网的分布式环境。
Dynamic 动态的
Java programs carry with them substantial amounts of run-time type information that is used to verify and resolve access to objects at run time. Java 程序携带大量的运行时类型信息,这些信息用于在运行时验证和解析对对象的访问。
Simple Java has a concise, cohesive set of features that makes it easy to learn and use.
Secure Java provides a secure means of creating Internet applications.
Portable Java programs can execute in any environment for which there is a Java runtime system.
Object-oriented Java embodies the modern object-oriented programming philosophy.
Robust Java encourages error-free programming by being strictly typed and performing run-time checks.
Multithreaded Java provides integrated support for multithreaded programming.
Architecture-neutral Java is not tied to a specific machine or operating system architecture.
Interpreted Java supports cross-platform code through the use of Java bytecode.
High performance The Java bytecode is highly optimized for speed of execution.
Distributed Java was designed with the distributed environment of the Internet in mind.
Dynamic Java programs carry with them substantial amounts of run-time type information that is used to verify and resolve access to objects at run time.| Simple | Java has a concise, cohesive set of features that makes it easy to learn and use. |
| :--- | :--- |
| Secure | Java provides a secure means of creating Internet applications. |
| Portable | Java programs can execute in any environment for which there is a Java runtime system. |
| Object-oriented | Java embodies the modern object-oriented programming philosophy. |
| Robust | Java encourages error-free programming by being strictly typed and performing run-time checks. |
| Multithreaded | Java provides integrated support for multithreaded programming. |
| Architecture-neutral | Java is not tied to a specific machine or operating system architecture. |
| Interpreted | Java supports cross-platform code through the use of Java bytecode. |
| High performance | The Java bytecode is highly optimized for speed of execution. |
| Distributed | Java was designed with the distributed environment of the Internet in mind. |
| Dynamic | Java programs carry with them substantial amounts of run-time type information that is used to verify and resolve access to objects at run time. |
Object-Oriented Programming 面向对象编程
At the center of Java is object-oriented programming (OOP). The object-oriented methodology is inseparable from Java, and all Java programs are, to at least some extent, object-oriented. Because of OOP’s importance to Java, it is useful to understand in a general way OOP’s basic principles before you write even a simple Java program. Later in this book, you will see how to put these concepts into practice. Java 的核心是面向对象编程(OOP)。面向对象的方法论与 Java 密不可分,所有 Java 程序在某种程度上都是面向对象的。由于 OOP 对 Java 的重要性,在编写简单的 Java 程序之前,了解 OOP 的基本原理是有益的。在本书后面,你将看到如何将这些概念付诸实践。
OOP is a powerful way to approach the job of programming. Programming methodologies have changed dramatically since the invention of the computer, primarily to accommodate the increasing complexity of programs. For example, when computers were first invented, programming was done by toggling in the binary machine instructions using the computer’s front panel. As long as programs were just a few hundred instructions long, this approach worked. As programs grew, assembly language was invented so that a programmer could deal with larger, increasingly complex programs, using symbolic representations of the machine instructions. As programs continued to grow, high-level languages were introduced that gave the programmer more tools with which to handle complexity. The first widespread language was, of course, FORTRAN. Although FORTRAN was a very impressive first step, it was hardly a language that encouraged clear, easy-to-understand programs. 面向对象编程(OOP)是一种强大的编程方法。自计算机发明以来,编程方法论发生了巨大变化,主要是为了适应程序日益增长的复杂性。例如,在计算机刚发明时,编程是通过切换计算机前面板上的二进制机器指令来完成的。只要程序只有几百条指令,这种方法是可行的。随着程序规模的扩大,汇编语言被发明出来,使程序员能够使用机器指令的符号表示来处理更大、更复杂的程序。随着程序的不断增长,高级语言被引入,为程序员提供了更多工具来应对复杂性。第一个广泛使用的语言当然是 FORTRAN。尽管 FORTRAN 是一个非常令人印象深刻的第一步,但它并不是一种鼓励编写清晰、易懂程序的语言。
The 1960s gave birth to structured programming. This is the method encouraged by languages such as C and Pascal. The use of structured languages made it possible to write moderately complex programs fairly easily. Structured languages are characterized by their support for stand-alone subroutines, local variables, rich control constructs, and their lack of reliance upon the GOTO. Although structured languages are a powerful tool, even they reach their limit when a project becomes too large. 20 世纪 60 年代诞生了结构化编程。这是由 C 语言和 Pascal 等语言所倡导的方法。结构化语言的使用使得编写中等复杂度的程序变得相当容易。结构化语言的特点是支持独立的子程序、本地变量、丰富的控制结构,并且不依赖于 GOTO 语句。尽管结构化语言是一种强大的工具,但当项目变得过于庞大时,它们也会达到极限。
Consider this: At each milestone in the development of programming, techniques and tools were created to allow the programmer to deal with increasingly greater complexity. Each step of the way, the new approach took the best elements of the previous methods and moved forward. Prior to the invention of OOP, many projects were nearing (or exceeding) the point where the structured approach no longer works. Object-oriented methods were created to help programmers break through these barriers. 请考虑这一点:在编程发展的每一个里程碑阶段,都创造了技术和工具,使程序员能够应对日益复杂的问题。每一步新方法都吸取了前一方法的精华并向前推进。在面向对象编程(OOP)发明之前,许多项目已经接近(或超过)结构化方法无法再有效工作的临界点。面向对象的方法被创造出来,帮助程序员突破这些障碍。
Object-oriented programming took the best ideas of structured programming and combined them with several new concepts. The result was a different way of organizing a program. In the most general sense, a program can be organized in one of two ways: around its code (what is happening) or around its data (what is being affected). Using only structured programming techniques, programs are typically organized around code. This approach can be thought of as “code acting on data.” 面向对象编程吸取了结构化编程的最佳思想,并结合了若干新概念。其结果是一种不同的程序组织方式。从最广义上讲,程序可以通过两种方式之一来组织:围绕代码(正在发生的事情)或围绕数据(受到影响的内容)。仅使用结构化编程技术时,程序通常是围绕代码组织的。这种方法可以被看作是“代码作用于数据”。
Object-oriented programs work the other way around. They are organized around data, with the key principle being “data controlling access to code.” In an object-oriented language, you define the data and the routines that are permitted to act on that data. Thus, a data type defines precisely what sort of operations can be applied to that data. 面向对象程序则相反。它们围绕数据组织,关键原则是“数据控制对代码的访问”。在面向对象语言中,你定义数据以及允许作用于该数据的例程。因此,数据类型精确定义了可以对该数据应用的操作种类。
To support the principles of object-oriented programming, all OOP languages, including Java, have three traits in common: encapsulation, polymorphism, and inheritance. Let’s examine each. 为了支持面向对象编程的原则,所有面向对象语言,包括 Java,都具有三个共同特征:封装、多态和继承。让我们逐一探讨。
Encapsulation 封装
Encapsulation is a programming mechanism that binds together code and the data it manipulates, and that keeps both safe from outside interference and misuse. In an objectoriented language, code and data can be bound together in such a way that a self-contained black box is created. Within the box are all necessary data and code. When code and data are linked together in this fashion, an object is created. In other words, an object is the device that supports encapsulation. 封装是一种编程机制,它将代码和所操作的数据绑定在一起,并保护它们免受外部干扰和误用。在面向对象的语言中,代码和数据可以以一种方式绑定在一起,创建一个自包含的黑盒。盒子内包含所有必要的数据和代码。当代码和数据以这种方式链接在一起时,就创建了一个对象。换句话说,对象是支持封装的装置。
Within an object, code, data, or both may be private to that object or public. Private code or data is known to and accessible by only another part of the object. That is, private code or data cannot be accessed by a piece of the program that exists outside the object. When code or data is public, other parts of your program can access it even though it is defined within an object. Typically, the public parts of an object are used to provide a controlled interface to the private elements of the object. 在一个对象内部,代码、数据或两者都可以是该对象的私有,也可以是公共的。私有的代码或数据仅为对象的其他部分所知并可访问。也就是说,私有的代码或数据不能被存在对象外部的程序部分访问。当代码或数据是公共的时,程序的其他部分即使在对象内部定义,也可以访问它。通常,对象的公共部分用于为对象的私有元素提供受控的接口。
Java’s basic unit of encapsulation is the class. Although the class will be examined in great detail later in this book, the following brief discussion will be helpful now. A class defines the form of an object. It specifies both the data and the code that will operate on that data. Java uses a class specification to construct objects. Objects are instances of a class. Thus, a class is essentially a set of plans that specify how to build an object. Java 的基本封装单位是类。虽然本书后面会详细讲解类,但现在进行以下简要讨论会有所帮助。类定义了对象的形式。它既指定了数据,也指定了操作这些数据的代码。Java 使用类规范来构造对象。对象是类的实例。因此,类本质上是一套构建对象的蓝图。
The code and data that constitute a class are called members of the class. Specifically, the data defined by the class are referred to as member variables or instance variables. The code that operates on that data is referred to as member methods or just methods. Method is Java’s term for a subroutine. If you are familiar with C/C++, it may help to know that what a Java programmer calls a method, a C//C++\mathrm{C} / \mathrm{C}++ programmer calls a function. 构成类的代码和数据称为类的成员。具体来说,类定义的数据称为成员变量或实例变量。操作这些数据的代码称为成员方法或简称方法。方法是 Java 中对子程序的称呼。如果你熟悉 C/C++,了解 Java 程序员所称的方法,在 C//C++\mathrm{C} / \mathrm{C}++ 程序员那里称为函数,可能会有所帮助。
Polymorphism 多态性
Polymorphism (from Greek, meaning “many forms”) is the quality that allows one interface to access a general class of actions. The specific action is determined by the exact nature of the situation. A simple example of polymorphism is found in the steering wheel of an automobile. The steering wheel (i.e., the interface) is the same no matter what type of actual steering mechanism is used. That is, the steering wheel works the same whether your car has manual steering, power steering, or rack-and-pinion steering. Therefore, once you know how to operate the steering wheel, you can drive any type of car. 多态(源自希腊语,意为“多种形式”)是一种特性,允许一个接口访问一类通用的操作。具体的操作由具体情况的性质决定。多态的一个简单例子可以在汽车的方向盘中找到。方向盘(即接口)无论使用何种实际的转向机制都是相同的。也就是说,无论你的汽车是手动转向、助力转向还是齿轮齿条转向,方向盘的操作方式都是一样的。因此,一旦你学会了如何操作方向盘,就能驾驶任何类型的汽车。
The same principle can also apply to programming. For example, consider a stack (which is a first-in, last-out list). You might have a program that requires three different types of stacks. One stack is used for integer values, one for floating-point values, and one for characters. In this case, the algorithm that implements each stack is the same, even though the data being stored differs. In a non-object-oriented language, you would be required to create three different sets of stack routines, with each set using different names. However, because of polymorphism, in Java you can create one general set of stack routines that works for all three specific situations. This way, once you know how to use one stack, you can use them all. 同样的原理也适用于编程。例如,考虑一个栈(先进后出列表)。你可能有一个程序需要三种不同类型的栈。一个栈用于整数值,一个用于浮点值,一个用于字符。在这种情况下,实现每个栈的算法是相同的,尽管存储的数据不同。在非面向对象的语言中,你需要创建三套不同的栈例程,每套使用不同的名称。然而,由于多态性,在 Java 中你可以创建一套通用的栈例程,适用于这三种具体情况。这样,一旦你学会了如何使用一个栈,就可以使用所有的栈。
More generally, the concept of polymorphism is often expressed by the phrase “one interface, multiple methods.” This means that it is possible to design a generic interface to a group of related activities. Polymorphism helps reduce complexity by allowing the same interface to 更一般地说,多态性的概念通常用“一个接口,多种方法”这句话来表达。这意味着可以设计一个通用接口来处理一组相关的活动。多态性通过允许相同的接口来帮助减少复杂性,...
be used to specify a general class of action. It is the compiler’s job to select the specific action (i.e., method) as it applies to each situation. You, the programmer, don’t need to do this selection manually. You need only remember and utilize the general interface. 可用于指定一类通用的操作。编译器的任务是根据具体情况选择特定的操作(即方法)。作为程序员,你不需要手动进行这种选择。你只需记住并使用通用接口即可。
Inheritance 继承
Inheritance is the process by which one object can acquire the properties of another object. This is important because it supports the concept of hierarchical classification. If you think about it, most knowledge is made manageable by hierarchical (i.e., top-down) classifications. For example, a Red Delicious apple is part of the classification apple, which in turn is part of the fruit class, which is under the larger class food. That is, the food class possesses certain qualities (edible, nutritious, etc.) which also, logically, apply to its subclass, fruit. In addition to these qualities, the fruit class has specific characteristics (juicy, sweet, etc.) that distinguish it from other food. The apple class defines those qualities specific to an apple (grows on trees, not tropical, etc.). A Red Delicious apple would, in turn, inherit all the qualities of all preceding classes, and would define only those qualities that make it unique. 继承是一个对象获得另一个对象属性的过程。这一点很重要,因为它支持层次分类的概念。如果你仔细想想,大多数知识都是通过层次(即自上而下)分类来管理的。例如,红富士苹果属于苹果分类,苹果又属于水果类,而水果类则属于更大的食物类。也就是说,食物类具有某些特性(可食用、有营养等),这些特性逻辑上也适用于其子类水果。除了这些特性外,水果类还有特定的特征(多汁、甜等),使其区别于其他食物。苹果类定义了苹果特有的特性(生长在树上,不是热带水果等)。红富士苹果则继承了所有前面类别的所有特性,并且只定义使其独特的那些特性。
Without the use of hierarchies, each object would have to explicitly define all of its characteristics. Using inheritance, an object need only define those qualities that make it unique within its class. It can inherit its general attributes from its parent. Thus, it is the inheritance mechanism that makes it possible for one object to be a specific instance of a more general case. 如果不使用层次结构,每个对象都必须明确地定义其所有特征。通过使用继承,对象只需定义使其在类中独特的那些属性。它可以从其父类继承一般属性。因此,正是继承机制使得一个对象能够成为更一般情况的具体实例。
The Java Development Kit Java 开发工具包
Now that the theoretical underpinning of Java has been explained, it is time to start writing Java programs. Before you can compile and run those programs, you must have a Java Development Kit (JDK). At the time of this writing, the current release of the JDK is JDK 17. This is the version for Java SE 17. (SE stands for Standard Edition.) It is also the version described in this book. Because JDK 17 contains features that are not supported by earlier versions of Java, it is recommended that you use JDK 17 (or later) to compile and run the programs in this book. (Remember, because of Java’s faster release schedule, JDK feature releases are expected at six-month intervals. Thus, don’t be surprised by a JDK with a higher release number.) However, depending on the environment in which you are working, an earlier JDK may already be installed. If this is the case, then newer Java features will not be available. 现在理论基础已经讲解完毕,是时候开始编写 Java 程序了。在你能够编译和运行这些程序之前,必须先安装 Java 开发工具包(JDK)。在撰写本文时,JDK 的最新版本是 JDK 17。这是 Java SE 17 的版本。(SE 代表标准版。)这也是本书所描述的版本。由于 JDK 17 包含早期 Java 版本不支持的功能,建议你使用 JDK 17(或更高版本)来编译和运行本书中的程序。(请记住,由于 Java 的发布周期加快,JDK 功能版本预计每六个月发布一次。因此,看到版本号更高的 JDK 时不要感到惊讶。)不过,根据你所使用的环境,可能已经安装了较早版本的 JDK。如果是这样,较新的 Java 功能将无法使用。
If you need to install the JDK on your computer, be aware that for modern versions of Java, both Oracle JDKs and open source OpenJDKs are available for download. In general, you should first find the JDK you want to use. For example, at the time of this writing, the Oracle JDK can be downloaded from www.oracle.com/java/technologies/downloads/. Also at the time of this writing, an open source version is available at jdk.java.net. Next, download the JDK of your choice and follow its instructions to install it on your computer. After you have installed the JDK, you will be able to compile and run programs. 如果你需要在电脑上安装 JDK,请注意,对于现代版本的 Java,既有 Oracle JDK,也有开源的 OpenJDK 可供下载。一般来说,你应该先找到你想使用的 JDK。例如,在撰写本文时,Oracle JDK 可以从 www.oracle.com/java/technologies/downloads/下载。同时,在撰写本文时,开源版本可在 jdk.java.net 获得。接下来,下载你选择的 JDK,并按照其说明在电脑上安装。安装完成后,你就可以编译和运行程序了。
The JDK supplies two primary programs. The first is javac, which is the Java compiler. The second is java, which is the standard Java interpreter and is also referred to as the application launcher. One other point: The JDK runs in the command-prompt environment and uses command-line tools. It is not a windowed application. It is also not an integrated development environment (IDE). JDK 提供两个主要程序。第一个是 javac,即 Java 编译器。第二个是 java,即标准的 Java 解释器,也称为应用程序启动器。还有一点需要说明:JDK 运行在命令提示符环境中,使用命令行工具。它不是窗口化应用程序,也不是集成开发环境(IDE)。
Ask the Expert 专家问答
Q: You state that object-oriented programming is an effective way to manage large programs. However, it seems that it might add substantial overhead to relatively small ones. Since you say that all Java programs are, to some extent, object-oriented, does this impose a penalty for smaller programs? 问:您说面向对象编程是管理大型程序的有效方法。然而,这似乎会给相对较小的程序增加大量开销。既然您说所有 Java 程序在某种程度上都是面向对象的,那么这会对较小的程序造成负担吗?
A: No. As you will see, for small programs, Java’s object-oriented features are nearly transparent. Although it is true that Java follows a strict object model, you have wide latitude as to the degree to which you employ it. For smaller programs, their “object-orientedness” is barely perceptible. As your programs grow, you will integrate more object-oriented features effortlessly. 答:不会。正如您将看到的,对于小程序来说,Java 的面向对象特性几乎是透明的。虽然 Java 确实遵循严格的对象模型,但您可以自由决定使用的程度。对于较小的程序,它们的“面向对象性”几乎难以察觉。随着程序规模的增长,您将轻松地整合更多的面向对象特性。
NOTE 注释
In addition to the basic command-line tools supplied with the JDK, there are several high-quality IDEs available for Java, such as NetBeans and Eclipse. An IDE can be very helpful when developing and deploying commercial applications. As a general rule, you can also use an IDE to compile and run the programs in this book if you so choose. However, the instructions presented in this book for compiling and running a Java program describe only the JDK command-line tools. The reasons for this are easy to understand. First, the JDK is readily available to all readers. Second, the instructions for using the JDK will be the same for all readers. Furthermore, for the simple programs presented in this book, using the JDK command-line tools is usually the easiest approach. If you are using an IDE, you will need to follow its instructions. Because of differences between IDEs, no general set of instructions can be given. 除了 JDK 自带的基本命令行工具外,还有几款高质量的 Java 集成开发环境(IDE),如 NetBeans 和 Eclipse。IDE 在开发和部署商业应用程序时非常有帮助。一般来说,如果你愿意,也可以使用 IDE 来编译和运行本书中的程序。然而,本书中关于编译和运行 Java 程序的说明仅介绍了 JDK 命令行工具。这样做的原因很容易理解。首先,JDK 对所有读者都是随时可用的。其次,使用 JDK 的说明对所有读者都是相同的。此外,对于本书中展示的简单程序,使用 JDK 命令行工具通常是最简单的方法。如果你使用 IDE,则需要遵循其说明。由于各个 IDE 之间存在差异,因此无法给出通用的操作指南。
A First Simple Program 第一个简单程序
Let’s start by compiling and running the short sample program shown here: 让我们从编译和运行下面这个简短的示例程序开始:
/*
This is a simple Java program.
Call this file Example.java.
*/
class Example {
// A Java program begins with a call to main().
public static void main(String[] args) {
System.out.println("Java drives the Web.");
}
}
You will follow these three steps: 你将按照以下三个步骤进行:
Enter the program. 输入程序。
Compile the program. 编译程序。
Run the program. 运行程序。
Entering the Program 输入程序
The programs shown in this book are available from www.mhprofessional.com. However, if you want to enter the programs by hand, you are free to do so. In this case, you must enter the program into your computer using a text editor, not a word processor. Word processors typically store format information along with text. This format information will confuse the Java compiler. If you are using a Windows platform, you can use Notepad or any other programming editor that you like. 本书中展示的程序可从 www.mhprofessional.com 获取。不过,如果你想手动输入程序,也可以自由选择。在这种情况下,你必须使用文本编辑器将程序输入到计算机中,而不是使用文字处理器。文字处理器通常会将格式信息与文本一起存储,这些格式信息会使 Java 编译器产生混淆。如果你使用的是 Windows 平台,可以使用记事本或任何你喜欢的编程编辑器。
For most computer languages, the name of the file that holds the source code to a program is arbitrary. However, this is not the case with Java. The first thing that you must learn about Java is that the name you give to a source file is very important. For this example, the name of the source file should be Example.java. Let’s see why. 对于大多数计算机语言,保存程序源代码的文件名是任意的。但 Java 并非如此。你必须首先了解的是,给源文件命名非常重要。以本例为例,源文件名应为 Example.java。让我们看看原因。
In Java, a source file is officially called a compilation unit. It is a text file that contains (among other things) one or more class definitions. (For now, we will be using source files that contain only one class.) The Java compiler requires that a source file use the .java filename extension. As you can see by looking at the program, the name of the class defined by the program is also Example. This is not a coincidence. In Java, all code must reside inside a class. By convention, the name of the main class should match the name of the file that holds the program. You should also make sure that the capitalization of the filename matches the class name. The reason for this is that Java is case sensitive. At this point, the convention that filenames correspond to class names may seem arbitrary. However, this convention makes it easier to maintain and organize your programs. Furthermore, as you will see later in this book, in some cases, it is required. 在 Java 中,源文件正式称为编译单元。它是一个文本文件,包含(除其他内容外)一个或多个类定义。(目前,我们将使用只包含一个类的源文件。)Java 编译器要求源文件使用.java 文件扩展名。通过查看程序,你可以看到程序定义的类名也是 Example。这并非巧合。在 Java 中,所有代码必须位于类内部。按照惯例,主类的名称应与保存程序的文件名相匹配。你还应确保文件名的大小写与类名一致。原因是 Java 区分大小写。此时,文件名与类名对应的惯例可能看起来很随意。然而,这一惯例使得维护和组织程序更加容易。此外,正如你将在本书后面看到的,在某些情况下,这是必须的。
Compiling the Program 编译程序
To compile the Example program, execute the compiler, javac, specifying the name of the source file on the command line, as shown here: 要编译 Example 程序,执行编译器 javac,在命令行中指定源文件名,如下所示:
javac Example.java
The javac compiler creates a file called Example.class that contains the bytecode version of the program. Remember, bytecode is not executable code. Bytecode must be executed by a Java Virtual Machine. Thus, the output of javac is not code that can be directly executed. javac 编译器会创建一个名为 Example.class 的文件,其中包含程序的字节码版本。请记住,字节码不是可执行代码。字节码必须由 Java 虚拟机执行。因此,javac 的输出不是可以直接执行的代码。
To actually run the program, you must use the Java interpreter, java. To do so, pass the class name Example as a command-line argument, as shown here: 要实际运行程序,必须使用 Java 解释器 java。为此,将类名 Example 作为命令行参数传递,如下所示:
java Example
When the program is run, the following output is displayed: 当程序运行时,将显示以下输出:
Java drives the Web. Java 驱动着网络。
When Java source code is compiled, each individual class is put into its own output file named after the class and using the .class extension. This is why it is a good idea to give your Java source files the same name as the class they contain-the name of the source file will match the name of the .class file. When you execute the Java interpreter as just shown, you are actually specifying the name of the class that you want the interpreter to execute. It will automatically search for a file by that name that has the .class extension. If it finds the file, it will execute the code contained in the specified class. 当 Java 源代码被编译时,每个单独的类都会被放入一个以该类命名并使用 .class 扩展名的输出文件中。这就是为什么给你的 Java 源文件命名为其包含的类名是个好主意——源文件的名称将与 .class 文件的名称相匹配。当你像刚才那样执行 Java 解释器时,实际上是指定了你希望解释器执行的类的名称。它会自动搜索一个以该名称并带有 .class 扩展名的文件。如果找到该文件,它将执行指定类中包含的代码。
Before moving on, it is important to mention that beginning with JDK 11, Java provides a way to run some types of simple programs directly from a source file, without explicitly invoking javac. This technique, which can be useful in some situations, is described in Appendix C. For the purposes of this book, it is assumed that you are using the normal compilation process just described. 在继续之前,重要的是要提到,从 JDK 11 开始,Java 提供了一种方法,可以直接从源文件运行某些类型的简单程序,而无需显式调用 javac。这种技术在某些情况下非常有用,详见附录 C。就本书而言,假设你使用的是刚才描述的正常编译过程。
NOTE 注意
If, when you try to compile the program, the computer cannot find javac (and assuming that you have installed the JDK correctly), you may need to specify the path to the command-line tools. In Windows, for example, this means that you will need to add the path to the command-line tools to the paths defined for the PATH environmental variable. For example, if JDK 17 was installed under the Program Files directory, then the path to the command-line tools will be similar to C:ไProgram Files \Java \jdk-17 bin. (Of course, you will need to find the path to Java on your computer, which may differ from the one just shown. Also the specific version of the JDK may differ.) You will need to consult the documentation for your operating system on how to set the path, because this procedure differs between OSes. 如果在尝试编译程序时,计算机找不到 javac(并且假设你已经正确安装了 JDK),你可能需要指定命令行工具的路径。例如,在 Windows 中,这意味着你需要将命令行工具的路径添加到 PATH 环境变量中定义的路径中。例如,如果 JDK 17 安装在 Program Files 目录下,那么命令行工具的路径将类似于 C:\Program Files\Java\jdk-17\bin。(当然,你需要找到你电脑上 Java 的路径,这可能与上述路径不同。JDK 的具体版本也可能不同。)你需要查阅操作系统的文档,了解如何设置路径,因为不同操作系统的设置方法不同。
The First Sample Program Line by Line 第一个示例程序逐行解析
Although Example.java is quite short, it includes several key features that are common to all Java programs. Let’s closely examine each part of the program. 虽然 Example.java 非常简短,但它包含了所有 Java 程序共有的几个关键特性。让我们仔细检查程序的每个部分。
The program begins with the following lines: 程序以以下几行开始:
/*
This is a simple Java program.
Call this file Example.java.
*/
This is a comment. Like most other programming languages, Java lets you enter a remark into a program’s source file. The contents of a comment are ignored by the compiler. Instead, a comment describes or explains the operation of the program to anyone who is reading its source code. In this case, the comment describes the program and reminds you that the source file should be called Example.java. Of course, in real applications, comments generally explain how some part of the program works or what a specific feature does. 这是一个注释。像大多数其他编程语言一样,Java 允许你在程序的源文件中输入备注。注释的内容会被编译器忽略。注释的作用是向阅读源代码的任何人描述或解释程序的操作。在本例中,注释描述了程序,并提醒你源文件应命名为 Example.java。当然,在实际应用中,注释通常解释程序的某部分如何工作或某个特定功能的作用。
Java supports three styles of comments. The one shown at the top of the program is called a multiline comment. This type of comment must begin with /* and end with */. Anything between these two comment symbols is ignored by the compiler. As the name suggests, a multiline comment may be several lines long. Java 支持三种注释风格。程序开头显示的这种称为多行注释。这种注释必须以/*开始,以*/结束。位于这两个注释符号之间的任何内容都会被编译器忽略。顾名思义,多行注释可以跨越多行。
The next line of code in the program is shown here: 程序中的下一行代码如下所示:
class Example {
This line uses the keyword class to declare that a new class is being defined. As mentioned, the class is Java’s basic unit of encapsulation. Example is the name of the class. The class definition begins with the opening curly brace ( {\{ ) and ends with the closing curly brace ( }\} ). The elements between the two braces are members of the class. For the moment, don’t worry too much about the details of a class except to note that in Java, all program activity occurs within one. This is one reason why all Java programs are (at least a little bit) object-oriented. 这一行使用关键字 class 来声明正在定义一个新类。如前所述,类是 Java 的基本封装单位。Example 是类的名称。类定义以左大括号( {\{ )开始,以右大括号( }\} )结束。两个大括号之间的元素是类的成员。目前,不必过于担心类的细节,只需注意在 Java 中,所有程序活动都发生在类中。这也是所有 Java 程序至少在某种程度上是面向对象的原因之一。
The next line in the program is the single-line comment, shown here: 程序中的下一行是单行注释,如下所示:
// A Java program begins with a call to main().
This is the second type of comment supported by Java. A single-line comment begins with a // and ends at the end of the line. As a general rule, programmers use multiline comments for longer remarks and single-line comments for brief, line-by-line descriptions. 这是 Java 支持的第二种注释类型。单行注释以 // 开头,直到行尾结束。一般来说,程序员使用多行注释来写较长的说明,使用单行注释来写简短的逐行描述。
The next line of code is shown here: 下一行代码如下所示:
public static void main (String[] args) {
This line begins the main() method. As mentioned earlier, in Java, a subroutine is called a method. As the comment preceding it suggests, this is the line at which the program will begin executing. In general, Java applications begin execution by calling main(). The exact meaning of each part of this line cannot be given now, since it involves a detailed understanding of several other of Java’s features. However, since many of the examples in this book will use this line of code, let’s take a brief look at each part now. 这一行开始了 main()方法。如前所述,在 Java 中,子程序被称为方法。正如前面的注释所示,程序将从这一行开始执行。通常,Java 应用程序通过调用 main()开始执行。由于这行代码涉及对 Java 其他多个特性的详细理解,目前无法对其每个部分的确切含义进行说明。不过,由于本书中的许多示例都会使用这行代码,我们现在先简要了解一下它的各个部分。
The public keyword is an access modifier. An access modifier determines how other parts of the program can access the members of the class. When a class member is preceded by public, then that member can be accessed by code outside the class in which it is declared. (The opposite of public is private, which prevents a member from being used by code defined outside of its class.) In this case, main() must be declared as public, since it must be called by code outside of its class when the program is started. The keyword static allows main() to be called before an object of the class has been created. This is necessary because main() is called by the JVM before any objects are made. The keyword void simply tells the compiler that main() does not return a value. As you will see, methods may also return values. If all this seems a bit confusing, don’t worry. All of these concepts will be discussed in detail in subsequent chapters. public 关键字是一个访问修饰符。访问修饰符决定程序的其他部分如何访问类的成员。当类成员前面有 public 时,该成员可以被声明它的类之外的代码访问。(public 的相反是 private,它阻止类外部定义的代码使用该成员。)在这种情况下,main()必须声明为 public,因为程序启动时必须由类外的代码调用它。static 关键字允许在创建类的对象之前调用 main()。这是必要的,因为 JVM 在创建任何对象之前调用 main()。void 关键字只是告诉编译器 main()不返回值。正如你将看到的,方法也可以返回值。如果这些内容有些令人困惑,不用担心,所有这些概念将在后续章节中详细讨论。
As stated, main() is the method called when a Java application begins. Any information that you need to pass to a method is received by variables specified within the set of parentheses that follow the name of the method. These variables are called parameters. If no parameters are required for a given method, you still need to include the empty parentheses. In main( ) there is only one parameter, String[ ] args, which declares a parameter named args. This is an array of objects of type String. (Arrays are collections of similar objects.) Objects of type String store sequences of characters. In this case, args receives any command-line arguments present when the program is executed. This program does not make use of this information, but other programs shown later in this book will. 如前所述,main() 是 Java 应用程序开始时调用的方法。任何需要传递给方法的信息,都通过紧跟在方法名后面的括号内指定的变量接收。这些变量称为参数。如果某个方法不需要参数,仍然需要包含空括号。在 main() 中只有一个参数,String[] args,它声明了一个名为 args 的参数。它是一个 String 类型对象的数组。(数组是相似对象的集合。)String 类型的对象存储字符序列。在这里,args 接收程序执行时存在的任何命令行参数。这个程序没有使用这些信息,但本书后面展示的其他程序会使用。
The last character on the line is the {\{. This signals the start of main()'s body. All of the code included in a method will occur between the method’s opening curly brace and its closing curly brace. 该行的最后一个字符是 {\{ 。它标志着 main() 方法体的开始。方法中包含的所有代码都位于方法的开括号和闭括号之间。
The next line of code is shown here. Notice that it occurs inside main(). 下一行代码如下所示。注意它出现在 main() 方法内部。
System.out.println("Java drives the Web.");
This line outputs the string “Java drives the Web.” followed by a new line on the screen. Output is actually accomplished by the built-in println( ) method. In this case, println( ) displays the string that is passed to it. As you will see, println( ) can be used to display other types of information, too. The line begins with System.out. While too complicated to explain in detail at this time, briefly, System is a predefined class that provides access to the system, and out is the output stream that is connected to the console. Thus, System.out is an object that encapsulates console output. The fact that Java uses an object to define console output is further evidence of its object-oriented nature. 这一行在屏幕上输出字符串“Java drives the Web.”,并换行。输出实际上是由内置的 println()方法完成的。在本例中,println()显示传递给它的字符串。正如你将看到的,println()也可以用来显示其他类型的信息。这一行以 System.out 开头。虽然目前无法详细解释,但简要来说,System 是一个预定义的类,提供对系统的访问,而 out 是连接到控制台的输出流。因此,System.out 是一个封装了控制台输出的对象。Java 使用对象来定义控制台输出,这进一步证明了它的面向对象特性。
As you have probably guessed, console output (and input) is not used frequently in realworld Java applications. Since most modern computing environments are windowed and graphical in nature, console I/O is used mostly for simple utility programs, for demonstration programs, and for server-side code. Later in this book, you will learn other ways to generate output using Java, but for now, we will continue to use the console I/O methods. 正如你可能已经猜到的,控制台输出(和输入)在现实世界的 Java 应用程序中并不常用。由于大多数现代计算环境都是基于窗口和图形的,控制台输入输出主要用于简单的实用程序、演示程序以及服务器端代码。在本书后面,你将学习使用 Java 生成输出的其他方法,但现在,我们将继续使用控制台输入输出方法。
Notice that the println() statement ends with a semicolon. Many statements in Java end with a semicolon. As you will see, the semicolon is an important part of the Java syntax. 注意,println()语句以分号结束。Java 中的许多语句都以分号结束。正如你将看到的,分号是 Java 语法的重要部分。
The first }\} in the program ends main(), and the last }\} ends the Example class definition. 程序中的第一个 }\} 结束了 main()方法,最后一个 }\} 结束了 Example 类的定义。
One last point: Java is case sensitive. Forgetting this can cause you serious problems. For example, if you accidentally type Main instead of main, or PrintLn instead of println, the preceding program will be incorrect. Furthermore, although the Java compiler will compile classes that do not contain a main() method, it has no way to execute them. So, if you had mistyped main, the compiler would still compile your program. However, the Java interpreter would report an error because it would be unable to find the main() method. 最后一点:Java 是区分大小写的。忽视这一点可能会给你带来严重的问题。例如,如果你不小心将 Main 写成 main,或者将 PrintLn 写成 println,前面的程序就会出错。此外,虽然 Java 编译器可以编译不包含 main()方法的类,但它无法执行这些类。因此,如果你拼写错误了 main,编译器仍然会编译你的程序,但 Java 解释器会报错,因为它找不到 main()方法。
Handling Syntax Errors 处理语法错误
If you have not yet done so, enter, compile, and run the preceding program. As you may know from your previous programming experience, it is quite easy to accidentally type something incorrectly when entering code into your computer. Fortunately, if you enter something incorrectly into your program, the compiler will report a syntax error message when it tries to compile it. The Java compiler attempts to make sense out of your source code no matter what you have written. For this reason, the error that is reported may not always reflect the actual cause of the problem. In the preceding program, for example, an accidental omission of the opening curly brace after the main( ) method causes the compiler to report the following two errors: 如果你还没有这样做,请输入、编译并运行前面的程序。正如你以前的编程经验所知,在将代码输入计算机时,很容易不小心输入错误。幸运的是,如果你在程序中输入错误,编译器在尝试编译时会报告语法错误信息。Java 编译器会尽力理解你的源代码,无论你写了什么。因此,报告的错误信息可能并不总是反映问题的实际原因。例如,在前面的程序中,如果不小心遗漏了 main()方法后的左大括号,编译器会报告以下两个错误:
Example.java:8: error: ';' expected
public static void main(String[] args),
Example.java:11: error: class, interface, enum, or record expected
}
Clearly, the first error message is completely wrong because what is missing is not a semicolon, but a curly brace. 显然,第一个错误信息是完全错误的,因为缺少的不是分号,而是大括号。
The point of this discussion is that when your program contains a syntax error, you shouldn’t necessarily take the compiler’s messages at face value. The messages may be misleading. You may need to “second-guess” an error message in order to find the real problem. Also, look at the last few lines of code in your program that precede the line being flagged. Sometimes an error will not be reported until several lines after the point at which the error actually occurred. 这段讨论的重点是,当你的程序包含语法错误时,不应完全相信编译器的提示信息。这些信息可能具有误导性。你可能需要“反向推断”错误信息,才能找到真正的问题所在。此外,还要查看程序中被标记行之前的最后几行代码。有时错误不会在实际发生错误的那一行立即报告,而是在几行之后才被发现。
A Second Simple Program 第二个简单程序
Perhaps no other construct is as important to a programming language as the assignment of a value to a variable. A variable is a named memory location that can be assigned a value. Further, the value of a variable can be changed during the execution of a program. That is, the content of a variable is changeable, not fixed. The following program creates two variables called myVar1 and myVar2: 也许没有哪个结构比将值赋给变量对编程语言更重要。变量是一个有名称的内存位置,可以被赋予一个值。此外,变量的值可以在程序执行过程中被改变。也就是说,变量的内容是可变的,而非固定的。下面的程序创建了两个名为 myVar1 和 myVar2 的变量:
/*
This demonstrates a variable.
Call this file Example2.java.
*/
class Example2 {
public static void main(String[] args) {
int myVar1; // this declares a variable -Declare variables.
int myVar2; // this declares another variable
myVar1 = 1024; // this assigns 1024 to myVar1 - Assign a variable a value.
System.out.println("myVar1 contains " + myVar1);
myVar2 = myVar1 / 2;
System.out.print("myVar2 contains myVar1 / 2: ");
System.out.println(myVar2);
}
}
When you run this program, you will see the following output: 当你运行这个程序时,你将看到以下输出:
This program introduces several new concepts. First, the statement 该程序介绍了几个新概念。首先,语句
int myVar1; // this declares a variable
declares a variable called myVar1 of type integer. In Java, all variables must be declared before they are used. Further, the type of values that the variable can hold must also be specified. This is called the type of the variable. In this case, myVar1 can hold integer values. These are whole number values. In Java, to declare a variable to be of type integer, precede its name with the keyword int. Thus, the preceding statement declares a variable called myVar1 of type int. 声明了一个名为 myVar1 的整型变量。在 Java 中,所有变量在使用前必须先声明。此外,还必须指定变量可以存储的值的类型。这称为变量的类型。在本例中,myVar1 可以存储整数值,即整数。在 Java 中,要声明一个整型变量,需要在变量名之前加上关键字 int。因此,上述语句声明了一个名为 myVar1 的 int 类型变量。
The next line declares a second variable called myVar2: 下一行声明了第二个变量,名为 myVar2:
int myVar2; // this declares another variable
Notice that this line uses the same format as the first line except that the name of the variable is different. 注意,这一行的格式与第一行相同,只是变量名不同。
In general, to declare a variable you will use a statement like this: 通常,声明变量时会使用如下语句:
type var-name;
Here, type specifies the type of variable being declared, and var-name is the name of the variable. In addition to int, Java supports several other data types. 这里,type 指定了被声明变量的类型,var-name 是变量的名称。除了 int,Java 还支持其他几种数据类型。
The following line of code assigns myVar1 the value 1024: 下面这行代码将值 1024 赋给 myVar1:
myVar1 = 1024; // this assigns 1024 to var1
In Java, the assignment operator is the single equal sign. It copies the value on its right side into the variable on its left. 在 Java 中,赋值运算符是单个等号。它将右侧的值复制到左侧的变量中。
The next line of code outputs the value of myVar1 preceded by the string "myVar1 contains ": 下一行代码输出 myVar1 的值,前面带有字符串“myVar1 contains ”:
System.out.println("myVar1 contains " + myVar1);
In this statement, the plus sign causes the value of myVar1 to be displayed after the string that precedes it. This approach can be generalized. Using the + operator, you can chain together as many items as you want within a single println() statement. 在这条语句中,加号使得 myVar1 的值显示在其前面的字符串之后。这种方法可以推广。使用+运算符,你可以在一个 println()语句中串联任意数量的项。
The next line of code assigns myVar2 the value of myVar1 divided by 2 : 下一行代码将 myVar2 赋值为 myVar1 除以 2 的结果:
myVar2 = myVar1 / 2;
This line divides the value in myVar1 by 2 and then stores that result in myVar2. Thus, after the line executes, myVar2 will contain the value 512 . The value of myVar1\mathbf{m y V a r} \mathbf{1} will be unchanged. Like most other computer languages, Java supports a full range of arithmetic operators, including those shown here: 这一行将 myVar1 中的值除以 2,然后将结果存储在 myVar2 中。因此,该行执行后,myVar2 将包含值 512。 myVar1\mathbf{m y V a r} \mathbf{1} 的值将保持不变。像大多数其他计算机语言一样,Java 支持完整的算术运算符,包括这里显示的运算符:
Two new things are occurring here. First, the built-in method print() is used to display the string "myVar2 contains myVar1 / 2: ". This string is not followed by a new line. This means that when the next output is generated, it will start on the same line. The print() method is just like println(), except that it does not output a new line after each call. Second, in the call to println( ), notice that myVar2 is used by itself. Both print() and println() can be used to output values of any of Java’s built-in types. 这里发生了两件新事情。首先,使用了内置方法 print()来显示字符串"myVar2 contains myVar1 / 2: "。这个字符串后面没有换行。这意味着当下一次输出生成时,它将从同一行开始。print()方法和 println()类似,只是它在每次调用后不输出换行符。其次,在调用 println()时,注意 myVar2 是单独使用的。print()和 println()都可以用来输出 Java 内置类型的任何值。
One more point about declaring variables before we move on: It is possible to declare two or more variables using the same declaration statement. Just separate their names by commas. For example, myVar1 and myVar2 could have been declared like this: 在继续之前,再补充一点关于声明变量的内容:可以使用同一个声明语句声明两个或更多变量。只需用逗号分隔它们的名字。例如,myVar1 和 myVar2 可以这样声明:
int myVar1, myVar2; // both declared using one statement
Another Data Type 另一种数据类型
In the preceding program, a variable of type int was used. However, a variable of type int can hold only whole numbers. Thus, it cannot be used when a fractional component is required. For example, an int variable can hold the value 18 , but not the value 18.3 . Fortunately, int is only one of several data types defined by Java. To allow numbers with fractional components, Java defines two floating-point types: float and double, which represent single- and double-precision values, respectively. Of the two, double is the most commonly used. 在前面的程序中,使用了 int 类型的变量。然而,int 类型的变量只能存储整数。因此,当需要小数部分时,int 类型就无法使用。例如,int 变量可以存储值 18,但不能存储值 18.3。幸运的是,int 只是 Java 定义的几种数据类型之一。为了允许带有小数部分的数字,Java 定义了两种浮点类型:float 和 double,分别表示单精度和双精度值。在这两者中,double 是最常用的。
To declare a variable of type double, use a statement similar to that shown here: 要声明一个 double 类型的变量,可以使用类似下面的语句:
double x;
Here, x\mathbf{x} is the name of the variable, which is of type double. Because x\mathbf{x} has a floating-point type, it can hold values such as 122.23, 0.034, or -19.0. 这里, x\mathbf{x} 是变量名,变量类型为 double。因为 x\mathbf{x} 是浮点类型,它可以存储诸如 122.23、0.034 或-19.0 这样的值。
To better understand the difference between int and double, try the following program: 为了更好地理解 int 和 double 之间的区别,请尝试以下程序:
/*
This program illustrates the differences
between int and double.
Call this file Example3.java.
*/
class Example3 {
public static void main(String[] args) {
int v; // this declares an int variable
double x; // this declares a floating-point variable
v = 10; // assign v the value 10
x = 10.0; // assign x the value 10.0
System.out.println("Original value of v: " + v);
System.out.println("Original value of x: " + x);
System.out.println(); // print a blank line }\longleftarrow\mathrm{ Output a blank line.
// now, divide both by 4
v = v / 4;
x = x / 4;
System.out.println("v after division: " + v);
System.out.println("x after division: " + x);
}
}
Ask the Expert 请教专家
Q: Why does Java have different data types for integers and floating-point values? That is, why aren’t all numeric values just the same type? 问:为什么 Java 对整数和浮点数使用不同的数据类型?也就是说,为什么所有的数值类型不都一样?
A: Java supplies different data types so that you can write efficient programs. For example, integer arithmetic is faster than floating-point calculations. Thus, if you don’t need fractional values, then you don’t need to incur the overhead associated with types float or double. Second, the amount of memory required for one type of data might be less than that required for another. By supplying different types, Java enables you to make best use of system resources. Finally, some algorithms require (or at least benefit from) the use of a specific type of data. In general, Java supplies a number of built-in types to give you the greatest flexibility. 答:Java 提供不同的数据类型是为了让你能够编写高效的程序。例如,整数运算比浮点运算更快。因此,如果你不需要小数值,就不必承担使用 float 或 double 类型带来的额外开销。其次,一种数据类型所需的内存可能比另一种少。通过提供不同的类型,Java 使你能够更好地利用系统资源。最后,有些算法需要(或者至少受益于)使用特定类型的数据。总的来说,Java 提供了多种内置类型,以便给你最大的灵活性。
The output from this program is shown here: 该程序的输出如下所示:
Original value of v: 10
Original value of x: 10.0
v after division: 2 Fractional component lost
x after division: 2.5 Fractional component preserved
As you can see, when v\mathbf{v} is divided by 4 , a whole-number division is performed, and the outcome is 2-the fractional component is lost. However, when the double variable x\mathbf{x} is divided by 4 , the fractional component is preserved, and the proper answer is displayed. 如你所见,当 v\mathbf{v} 除以 4 时,执行的是整数除法,结果是 2——小数部分被舍弃了。然而,当 double 类型的变量 x\mathbf{x} 除以 4 时,小数部分被保留,显示了正确的答案。
There is one other new thing to notice in the program. To print a blank line, simply call println() without any arguments. 程序中还有一处新内容需要注意。要打印空行,只需调用不带任何参数的 println() 方法。
Try This 1-1 Converting Gallons to Liters 练习 1-1 将加仑转换为升
Although the preceding sample programs illustrate several important features of the Java language, they are not very useful. Even though you do not know much about Java at this point, you can still put what you have learned to work to create a practical program. In this project, we will create a program that converts gallons to liters. The program will work by declaring two double variables. One will hold the number of the gallons, and the second will hold the number of liters after the conversion. There are 3.7854 虽然前面的示例程序展示了 Java 语言的几个重要特性,但它们并不是很实用。即使你目前对 Java 了解不多,你仍然可以利用所学知识来创建一个实用的程序。在本项目中,我们将创建一个将加仑转换为升的程序。该程序通过声明两个 double 变量来工作。一个变量保存加仑数,另一个变量保存转换后的升数。1 加仑等于 3.7854
liters in a gallon. Thus, to convert gallons to liters, the gallon value is multiplied by 3.7854. The program displays both the number of gallons and the equivalent number of liters. 升。因此,要将加仑转换为升,只需将加仑数乘以 3.7854。程序会显示加仑数及其等效的升数。
Create a new file called GalToLit.java. 创建一个名为 GalToLit.java 的新文件。
Enter the following program into the file: 将以下程序输入到该文件中:
/*
Try This 1-1
This program converts gallons to liters.
Call this program GalToLit.java.
*/
class GalToLit {
public static void main(String[] args) {
double gallons; // holds the number of gallons
double liters; // holds conversion to liters
gallons = 10; // start with 10 gallons
liters = gallons * 3.7854; // convert to liters
System.out.println(gallons + " gallons is " + liters + " liters.");
}
}
Compile the program using the following command line: 使用以下命令行编译程序:
javac GalToLit.java
Run the program using this command: 使用此命令运行程序:
java GalToLit
You will see this output: 你将看到以下输出:
10.0 gallons is 37.854 liters.
As it stands, this program converts 10 gallons to liters. However, by changing the value assigned to gallons, you can have the program convert a different number of gallons into its equivalent number of liters. 目前,该程序将 10 加仑转换为升。然而,通过更改赋给 gallons 的值,你可以让程序将不同数量的加仑转换为相应的升数。
Two Control Statements 两个控制语句
Inside a method, execution proceeds from one statement to the next, top to bottom. However, it is possible to alter this flow through the use of the various program control statements supported by Java. Although we will look closely at control statements later, two are briefly introduced here because we will be using them to write sample programs. 在方法内部,执行从一个语句顺序进行到下一个语句,自上而下。然而,可以通过使用 Java 支持的各种程序控制语句来改变这种流程。虽然我们稍后会详细介绍控制语句,但这里简要介绍两个,因为我们将使用它们来编写示例程序。
The if Statement if 语句
You can selectively execute part of a program through the use of Java’s conditional statement: the if. The Java if statement works much like the IF statement in any other language. It determines the flow of program execution based on whether some condition is true or false. Its simplest form is shown here: 你可以通过使用 Java 的条件语句 if,有选择地执行程序的一部分。Java 的 if 语句的工作方式与其他语言中的 IF 语句非常相似。它根据某个条件是真还是假来决定程序执行的流程。其最简单的形式如下所示:
if(condition) statement; if(condition) 语句;
Here, condition is a Boolean expression. (A Boolean expression is one that evaluates to either true or false.) If condition is true, then the statement is executed. If condition is false, then the statement is bypassed. Here is an example: 这里,condition 是一个布尔表达式。(布尔表达式是指其值为 true 或 false 的表达式。)如果 condition 为 true,则执行该语句。如果 condition 为 false,则跳过该语句。下面是一个例子:
if(10 < 11) System.out.println("10 is less than 11");
In this case, since 10 is less than 11, the conditional expression is true, and println() will execute. However, consider the following: 在这种情况下,由于 10 小于 11,条件表达式为真,println() 将被执行。然而,考虑以下情况:
if(10 < 9) System.out.println("this won't be displayed");
In this case, 10 is not less than 9 . Thus, the call to println() will not take place. 在这种情况下,10 不小于 9。因此,println() 的调用将不会发生。
Java defines a full complement of relational operators that may be used in a conditional expression. They are shown here: Java 定义了一整套关系运算符,可用于条件表达式。它们如下所示:
Operator 运算符
Meaning 含义
<
Less than 小于
<=
Less than or equal 小于或等于
>
Greater than 大于
>=
Greater than or equal 大于或等于
= =
Equal to 等于
!=
Not equal 不等于
Operator Meaning
< Less than
<= Less than or equal
> Greater than
>= Greater than or equal
= = Equal to
!= Not equal| Operator | Meaning |
| :--- | :--- |
| < | Less than |
| <= | Less than or equal |
| > | Greater than |
| >= | Greater than or equal |
| = = | Equal to |
| != | Not equal |
Notice that the test for equality is the double equal sign. 注意,判断相等使用的是双等号。
Here is a program that illustrates the if statement: 这里有一个演示 if 语句的程序:
/*
Demonstrate the if.
Call this file IfDemo.java.
*/
class IfDemo {
public static void main(String[] args) {
int a, b, c;
a = 2;
b = 3;
if(a < b) System.out.println("a is less than b");
// this won't display anything
if(a == b) System.out.println("you won't see this");
System.out.println();
c = a - b; // c contains -1
System.out.println("c contains -1");
if(c >= 0) System.out.println("c is non-negative");
if(c < O) System.out.println("c is negative");
System.out.println();
c = b - a; // c now contains 1
System.out.println("c contains 1");
if(c >= 0) System.out.println("c is non-negative");
if(c < O) System.out.println("c is negative");
}
}
The output generated by this program is shown here: 该程序生成的输出如下所示:
a is less than b
c contains -1
c is negative
c contains 1
c is non-negative
Notice one other thing in this program. The line 请注意程序中的另一点。该行
int a, b, c;
declares three variables, a,b\mathbf{a}, \mathbf{b}, and c\mathbf{c}, by use of a comma-separated list. As mentioned earlier, when you need two or more variables of the same type, they can be declared in one statement. Just separate the variable names by commas. 通过逗号分隔的列表声明了三个变量, a,b\mathbf{a}, \mathbf{b} 和 c\mathbf{c} 。如前所述,当你需要两个或更多相同类型的变量时,可以在一条语句中声明它们。只需用逗号分隔变量名即可。
The for Loop for 循环
You can repeatedly execute a sequence of code by creating a loop. Loops are used whenever you need to perform a repetitive task because they are much simpler and easier than trying to write the same statement sequence over and over again. Java supplies a powerful assortment of loop constructs. The one we will look at here is the for loop. The simplest form of the for loop is shown here: 你可以通过创建循环来重复执行一段代码。每当需要执行重复任务时,循环非常有用,因为它们比反复编写相同的语句序列要简单得多。Java 提供了多种强大的循环结构。这里我们将介绍的是 for 循环。for 循环的最简单形式如下所示:
In its most common form, the initialization portion of the loop sets a loop control variable to an initial value. The condition is a Boolean expression that tests the loop control variable. 在其最常见的形式中,循环的初始化部分将循环控制变量设置为初始值。条件是一个布尔表达式,用于测试循环控制变量。
If the outcome of that test is true, statement executes and the for loop continues to iterate. If it is false, the loop terminates. The iteration expression determines how the loop control variable is changed each time the loop iterates. Here is a short program that illustrates the for loop: 如果测试结果为真,语句将执行,for 循环继续迭代。如果为假,循环终止。迭代表达式决定了每次循环迭代时循环控制变量如何变化。下面是一个演示 for 循环的简短程序:
/*
Demonstrate the for loop.
Call this file ForDemo.java.
*/
class ForDemo {
public static void main(String[] args) {
int count;
for(count = 0; count < 5; count = count +1) This loop iterates five times.
System.out.println("This is count: " + count);
System.out.println("Done!");
}
}
The output generated by the program is shown here: 程序生成的输出如下所示:
This is count: 0
This is count: 1
This is count: 2
This is count: 3
This is count: 4
Done!
In this example, count is the loop control variable. It is set to zero in the initialization portion of the for. At the start of each iteration (including the first one), the conditional test count < 5<5 is performed. If the outcome of this test is true, the println() statement is executed, and then the iteration portion of the loop is executed, which increases count by 1 . This process continues until the conditional test is false, at which point execution picks up at the bottom of the loop. As a point of interest, in professionally written Java programs, you will almost never see the iteration portion of the loop written as shown in the preceding program. That is, you will seldom see statements like this: 在这个例子中,count 是循环控制变量。它在 for 循环的初始化部分被设置为零。在每次迭代开始时(包括第一次),都会执行条件测试 count < 5<5 。如果该测试结果为真,则执行 println() 语句,然后执行循环的迭代部分,将 count 增加 1。这个过程会持续进行,直到条件测试为假,此时执行将跳到循环底部。值得一提的是,在专业编写的 Java 程序中,你几乎不会看到像前面程序中那样写的迭代部分。也就是说,你很少会看到像下面这样的语句:
count = count + 1;
The reason is that Java includes a special increment operator that performs this operation more efficiently. The increment operator is ++ (that is, two plus signs back to back). The increment operator increases its operand by one. By use of the increment operator, the preceding statement can be written like this: 原因是 Java 包含一个特殊的递增运算符,可以更高效地执行此操作。递增运算符是 ++(即两个加号连写)。递增运算符将其操作数增加一。利用递增运算符,上述语句可以写成这样:
count++;
Thus, the for in the preceding program will usually be written like this: 因此,前面程序中的 for 循环通常会写成这样:
for(count = 0; count < 5; count++)
You might want to try this. As you will see, the loop still runs exactly the same as it did before. 你可能想试试这个。正如你将看到的,循环仍然和之前完全一样运行。
导出提示
谨慎下载超过 300 页以上 PDF,容易内存溢出。
PDF Pro 下载需借用浏览器的打印功能,出现打印界面后,在【打印机】处选择【另存为 PDF】,最后点击【保存】即可。