X-Spirit的陋室铭

生活有的时候面临许多选择,这些选择让人困惑。 生活有的时候没有任何选择,这个时候让人压抑。 但无论生活有没有给你选择,你只能做一件事情: 排除困难,勇往直前!

2007年9月17日星期一

3.7 Input and Output 输入与输出

Input and Output 输入与输出

To make our example programs more interesting, we want to accept input and properly format the program output. Of course, modern programs use a GUI for collecting user input. However, programming such an interface requires more tools and techniques than we have at our disposal at this time. Because the first order of business is to become more familiar with the Java programming language, we make do with the humble console for input and output for now. GUI programming is covered in Chapters 7 through 9.

要是我们的程序更有意思,我们需要在程序中接收输入,并适当的格式化输出。当然,先进的程序采用GUI(图形用户界面)来收集用户输入。但是编写这样一个界面需要更多的工具和技术,这已经超出了我们现在的目标。因为我们当前的目标是更熟悉Java编程语言,我们还是采用粗陋的控制台作为输入输出。GUI编程将在7~9章介绍。

Reading Input 读取输入

You saw that it is easy to print output to the "standard output stream" (that is, the console window) just by calling System.out.println. Oddly enough, before JDK 5.0, there was no convenient way to read input from the console window. Fortunately, that situation has finally been rectified.

你可以看到,向标准输出流(也就是控制台窗口)输出内容非常简单,只需要调用System.out.println即可。非常奇怪的是,JDK5.0以前,还没有什么便捷的办法可以从控制台窗口读取输入。幸运的是,这种情况最终得以矫正。

To read console input, you first construct a Scanner that is attached to the "standard input stream" System.in.

要读取控制台输入,你首先构造一个附属于标准输入流System.in的Scanner。

Scanner in = new Scanner(System.in);


Now you use the various methods of the Scanner class to read input. For example, the nextLine method reads a line of input.

现在你可以使用Scanner类的各种方法来读取输入。例如,nextLine方法可以读取一行输入。

System.out.print("What is your name? ");

String name = in.nextLine();


Here, we use the nextLine method because the input might contain spaces. To read a single word (delimited by whitespace), call

这里,我们使用nextLine方法因为输入可能包含空格。要读取单个单词(以空格分隔),调用:

String firstName = in.next();


To read an integer, use the nextInt method.

要读取一个整数,使用nextInt方法。

System.out.print("How old are you? ");

int age = in.nextInt();


Similarly, the nextdouble method reads the next floating-point number.

类似的,nextdouble方法读取下一个浮点数字。

The program in Example 3-2 asks for the user's name and age and then prints a message like

Hello, Cay. Next year, you'll be 46


Finally, add the line

import java.util.*;


at the beginning of the program. The Scanner class is defined in the java.util package. Whenever you use a class that is not defined in the basic java.lang package, you need to use an import directive. We look at packages and import directives in more detail in Chapter 4.

例3-2要求用户输入姓名和年龄,并输出消息”Hello, cay. Next year, you’ll be 46”

最后在程序的开头加上import java.util.*;

Scanner类是定义在java.util包里的。只要你使用了一个没有定义在基本的java.lang包中的类,你都需要一个import 命令。我们将在第四章中更详细的讨论包和import。

Example 3-2. InputTest.java

1. import java.util.*;

2.

3. public class InputTest

4. {

5. public static void main(String[] args)

6. {

7. Scanner in = new Scanner(System.in);

8.

9. // get first input

10. System.out.print("What is your name? ");

11. String name = in.nextLine();

12.

13. // get second input

14. System.out.print("How old are you? ");

15. int age = in.nextInt();

16.

17. // display output on console

18. System.out.println("Hello, " + name + ". Next year, you'll be " + (age + 1));

19. }

20. }


NOTE


If you do not have JDK 5.0 or above, you have to work harder to read user input. The simplest method is to use an input dialog (see Figure 3-6).

如果你没有JDK 5.0或以上版本,你必须在读取用户输入上多费些力气。最简单的方法就是使用一个输入框(见图3-6)

String input = JOptionPane.showInputDialog(promptString)


Figure 3-6. An input dialog


The return value is the string that the user typed.

返回值就是用户输入的字符串。

For example, here is how you can query the name of the user of your program:

例如,下面的代码展示了我们如何在程序中要求输入用户的名字。

String name = JOptionPane.showInputDialog("What is your name?");


Reading numbers requires an additional step. The JOptionPane.showInputDialog method returns a string, not a number. You use the Integer.parseInt or Double.parseDouble method to convert the string to its numeric value. For example,

读取数字型输入需要再多一步。JOptionPane.showInputDialog方法返回一个字符串,而不是一个数字。你需要使用Integer.parseInt或者Double.parseDouble方法来将其数字值转换为字符串。例如


String input = JOptionPane.showInputDialog("How old are you?"); int age = Integer.parseInt(input);


If the user types 45, then the string variable input is set to the string "45". The Integer.parseInt method converts the string to its numeric value, the number 45.

如果用户输入45,则字符串变量被赋值为”45”。Integer.parseInt方法将字符串转换为相应的数字值,也就是数字45。

The JOptionPane class is defined in the javax.swing package, so you need to add the statement

JOptionPane类是定义在javax.swing包中,所以你需要添加语句

import javax.swing.*;


Finally, whenever your program calls JOptionPane.showInputDialog, you need to end it with a call to System.exit(0). The reason is a bit technical. Showing a dialog box starts a new thread of control. When the main method exits, the new thread does not automatically terminate. To end all threads, you call the System.exit method. (For more information on threads, see Chapter 1 of Volume 2.) The following program is the equivalent to Example 3-2 prior to JDK 5.0.

最后,无论何时程序调用JOptionPane.showInputDialog,你需要采用System.exit(0)来结束之。这是一个有点技术性的原因。显示一个对话框需要启动一个新的控制线程。当main方法退出时,新启动的线程并没有终结。要结束所有线程,你需要调用System.exit方法(想进一步了解线程,参见卷2第一章)下面的程序等同于JDK5.0以前的例3-2

import javax.swing.*;

public class InputTest

{

public static void main(String[] args)

{

String name = JOptionPane.showInputDialog("What is your name?");

String input = JOptionPane.showInputDialog("How old are you?");

int age = Integer.parseInt(input);

System.out.println("Hello, " + name + ". Next year, you'll be " + (age + 1));

System.exit(0);

}

}




java.util.Scanner 5.0


  • Scanner(InputStream in)

constructs a Scanner object from the given input stream.

  • String nextLine()

reads the next line of input.

  • String next()

reads the next word of input (delimited by whitespace).

  • int nextInt()

  • double nextDouble()

read and convert the next character sequence that represents an integer or floating-point number.

  • boolean hasNext()

tests whether there is another word in the input.检测后面是否还有一个单词

  • boolean hasNextInt()

  • boolean hasNextDouble()

test whether the next character sequence represents an integer or floating-point number.检测下一个字符序列是否代表一个整数或一个浮点数。


javax.swing.JOptionPane 1.2


  • static String showInputDialog(Object message)

displays a dialog box with a message prompt, an input field, and "OK" and "Cancel" buttons. The method returns the string that the user typed.
显示一个带有消息提示的对话框,一个输入框,还有”OK”和”Cancel”按钮。该方法返回用户键入的字符串。


java.lang.System 1.0


  • static void exit(int status)

terminates the virtual machine and passes the status code to the operating system. By convention, a non-zero status code indicates an error.
终止虚拟机并向操作系统传递状态码。约定非零状态码表示一种错误。

Formatting Output 格式化输出

You can print a number x to the console with the statement System.out.print(x). That command will print x with the maximum number of non-zero digits for that type. For example,

你可以用System.out.print(x)语句将一个数字x输出到控制台。这个命令将以该类型最大非零位数打印x。例如:

double x = 10000.0 / 3.0;

System.out.print(x);


prints打印出

3333.3333333333335


That is a problem if you want to display, for example, dollars and cents.但是当你想显示美元和美分的时候这就成了问题。

Before JDK 5.0, formatting numbers was a bit of a hassle. Fortunately, JDK 5.0 brought back the venerable printf method from the C library. For example, the call

JDK5.0前,对数字的格式化产生了争论。幸运的是,JDK5.0将古老的printf方法从C库中带回来了。例如:

System.out.printf("%8.2f", x);


prints x with a field width of 8 characters and a precision of 2 characters. That is, the printout contains a leading space and the seven characters

以8个字符的字段宽度和2个字符的精度打印出x。也就是说,输出包含前导空白和七个字符

3333.33


You can supply multiple parameters to printf, for example:你可以在printf中使用多个参数。

System.out.printf("Hello, %s. Next year, you'll be %d", name, age);


Each of the format specifiers that start with a % character is replaced with the corresponding argument. The conversion character that ends a format specifier indicates the type of the value to be formatted: f is a floating-point number, s a string, and d a decimal integer. Table 3-5 shows all conversion characters.

每个格式区分符以%开始,并被相应的变量取代。结束格式区分符的转换字符指明了要格式化的值的类型:f是指一个浮点数字,s是指一个字符串,d是指一个十进制整数。表3-5列出了所有的转换字符。

Table 3-5. Conversions for printf

Conversion Character

Type

Example

d

Decimal integer十进制整数

159

x

Hexadecimal integer十六进制整数

9f

o

Octal integer八进制整数

237

f

Fixed-point floating-point定点浮点数

15.9

e

Exponential floating-point指数型浮点数

1.59e+01

g

General floating-point (the shorter of e and f)

a

Hexadecimal floating point十六进制浮点

0x1.fccdp3

s

String

Hello

c

Character

H

b

Boolean

TRue

h

Hash code哈希码

42628b2

tx

Date and time

See Table 3-7

%

The percent symbol百分号

%

n

The platform-dependent line separator换行符


Table 3-7. Date and Time Conversion Characters

Conversion Character

Type

Example

C

Complete date and time

Mon Feb 09 18:05:19 PST 2004

F

ISO 8601 date

2004-02-09

D

U.S. formatted date (month/day/year)

02/09/2004

T

24-hour time

18:05:19

r

12-hour time

06:05:19 pm

R

24-hour time, no seconds

18:05

Y

Four-digit year (with leading zeroes)

2004

y

Last two digits of the year (with leading zeroes)

04

C

First two digits of the year (with leading zeroes)

20

B

Full month name

February

b or h

Abbreviated month name月份名称缩写

Feb

m

Two-digit month (with leading zeroes)

02

d

Two-digit day (with leading zeroes)

09

e

Two-digit day (without leading zeroes)

9

A

Full weekday name

Monday

a

Abbreviated weekday name

Mon

j

Three-digit day of year (with leading zeroes), between 001 and 366

069

H

Two-digit hour (with leading zeroes), between 00 and 23

18

k

Two-digit hour (without leading zeroes), between 0 and 23

18

I

Two-digit hour (with leading zeroes), between 01 and 12

06

l

Two-digit hour (without leading zeroes), between 1 and 12

6

M

Two-digit minutes (with leading zeroes)

05

S

Two-digit seconds (with leading zeroes)

19

L

Three-digit milliseconds (with leading zeroes)三位毫秒数

047

N

Nine-digit nanoseconds (with leading zeroes)九位纳秒数

047000000

P

Uppercase morning or afternoon marker大写上下午标记

PM

p

Lowercase morning or afternoon marker小写上下午标记

pm

z

RFC 822 numeric offset from GMT格林尼治时间偏移量

-0800

Z

Time zone时区

PST

s

Seconds since 1970-01-01 00:00:00 GMT

1078884319

E

Milliseconds since 1970-01-01 00:00:00 GMT

1078884319047


In addition, you can specify flags that control the appearance of the formatted output. Table 3-6 shows all flags. For example, the comma flag adds group separators. That is,

另外,你可以指定标记来控制格式化输出的行为。例如逗号标记可以添加组分隔符。也就是

System.out.printf("%,.2f", 10000.0 / 3.0);


Table 3-6. Flags for printf

Flag

Purpose

Example

+

Prints sign for positive and negative numbers输出数字的正负号

+3333.33

space

Adds a space before positive numbers在整数前加一个空格

3333.33

0

Adds leading zeroes加入前导的0

003333.33

-

Left-justifies field左对齐字段

3333.33

(

Encloses negative number in parentheses用圆括号括起负数

(3333.33)

,

Adds group separators添加组分隔符

3,333.33

# (for f format)

Always includes a decimal point总是包含小数点

3,333.

# (for x or o format)

Adds 0x or 0 prefix添加0x或者0前缀

0xcafe

^

Converts to upper case转换为大写

0XCAFE

$

Specifies the index of the argument to be formatted; for example, %1$d %1$x prints the first argument in decimal and hexadecimal指定要格式化的参数的索引,例如%1$d %1$x以十进制和十六进制形式输出第一个参数

159 9F

<

Formats the same value as the previous specification; for example, %d %<x prints the same number in decimal and hexadecimal格式化前面指定的相同的值,例如%d %<x 以十进制和十六进制的形式输出同一个数字。

159 9F


prints打印出

3,333.33


You can use multiple flags, for example, "%,(.2f", to use group separators and enclose negative numbers in parentheses.

你可以使用多个标记,例如"%,(.2f",使用组分隔符并用圆括号括住负数。

NOTE


You can use the s conversion to format arbitrary objects. If an arbitrary object implements the Formattable interface, the object's formatTo method is invoked. Otherwise, the toString method is invoked to turn the object into a string. We discuss the toString method in Chapter 5 and interfaces in Chapter 6.

你可以使用s转换来格式化任意对象。如果任意对象实现了Formattable接口,则对象的formatTo方法被调用。否则调用toString方法来将一个对象转变为一个字符串。我们将在第五章和第六章中分别讨论toString方法和接口


You can use the static String.format method to create a formatted string without printing it:

你可使用静态方法String.format来创建格式化的字符串,而并不将其输出。

String message = String.format("Hello, %s. Next year, you'll be %d", name, age);


Although we do not describe the Date type in detail until Chapter 4, we do, in the interest of completeness, briefly discuss the date and time formatting options of the printf method. You use two a two-letter format, starting with t and ending in one of the letters of Table 3-7. For example,

尽管我们到第4章才讲述Date类型,但是完全是出于兴趣,简要介绍一下printf方法的时间和日期格式选项。你可以使用一个两字母的格式,以t开始,以表3-7中的字母结束。例如

System.out.printf("%tc", new Date());


prints the current date and time in the format

以如下格式输出日期和时间。

Mon Feb 09 18:05:19 PST 2004


As you can see in Table 3-7, some of the formats yield only a part of a given date, for example, just the day or just the month. It would be a bit silly if you had to supply the date multiple times to format each part. For that reason, a format string can indicate the index of the argument to be formatted. The index must immediately follow the %, and it must be terminated by a $. For example,

如你在表3-7中所见,一些格式仅输出指定时间的一部分,例如,仅仅是日或者月。如果你要多次提供时间,并要格式化每个部分,这看起来很傻。一个格式化字串可以指定要格式化的参数的索引。索引值紧跟百分号%,并以$结束。例如

System.out.printf("%1$s %2$tB %2$te, %2$tY", "Due date:", new Date());


prints输出

Due date: February 9, 2004


Alternatively, you can use the < flag. It indicates that the same argument as in the preceding format specification should be used again. That is, the statement

或者你可以选择使用<标记。它表明将再次使用前一个格式所规范的参数。也就是如下语句

System.out.printf("%s %tB %<te, %<tY", "Due date:", new Date());


yields the same output as the preceding statement.

将和上一条语句产生相同的输出。

CAUTION


Argument index values start with 1, not with 0: %1$... formats the first argument. This avoids confusion with the 0 flag.

参数索引值以1开始,而不是0.


You have now seen all features of the printf method. Figure 3-7 shows a syntax diagram for format specifiers.

下图是格式化说明符的语法:

Figure 3-7. Format specifier syntax

[View full size image]


NOTE


A number of the formatting rules are locale specific. For example, in Germany, the decimal separator is a period, not a comma, and Monday is formatted as Montag. You will see in Volume 2 how to control the international behavior of your applications.

一些格式化规范是地区性的。例如,在德国,十进制分隔符是一个句点,而不是一个逗号,而Monday被格式化为Montag。你将在卷2中看到如何在你的程序中处理国际化问题。


TIP


If you use a version of Java prior to JDK 5.0, use the NumberFormat and DateFormat classes instead of printf.

如果你使用的是JDK5.0以前版本,请使用NumberFormat和DateFormat来代替printf


2007年9月12日星期三

3.6 Strings字符串

 

Conceptually, Java strings are sequences of Unicode characters. For example, the string "Java\u2122" consists of the five Unicode characters J, a, v, a, and ™. Java does not have a built-in string type. Instead, the standard Java library contains a predefined class called, naturally enough, String. Each quoted string is an instance of the String class:

概念上讲,Java字符串就是Unicode字符序列。例如,字符串"Java\u2122"由5个Unicode字符J,a,v,a和™组成。Java没有内建的string类型。但是,标准Java库提供了一个类,很自然的,叫做String。每个被引起来的字符串就是一个String实例:

String e = ""; // an empty string

String greeting = "Hello";

Code Points and Code Units 代码点和代码单元

Java strings are implemented as sequences of char values. As we discussed on page 41, the char data type is a code unit for representing Unicode code points in the UTF-16 encoding. The most commonly used Unicode characters can be represented with a single code unit. The supplementary characters require a pair of code units.

Java字符串是以char值序列的方式实现的。如我们在41页中提到的,char数据类型是一个表示UTF-16编码中各个Unicode代码点的代码单元。最常用的Unicode字符可以用一个单独的代码单元表示。增补字符需要一对代码单元。

The length method yields the number of code units required for a given string in the UTF-16 encoding. For example:

length方法返回指定的UTF-16编码字符串所需代码单元的数量,例如:

String greeting = "Hello";

int n = greeting.length(); // is 5.

To get the true length, that is, the number of code points, call

要得到真实的长度,即代码点的数量,调用:

int cpCount = greeting.codePointCount(0, greeting.length());

The call s.charAt(n) returns the code unit at position n, where n is between 0 and s.length() – 1. For example,

s.charAt(n) 返回位置n对应的代码单元,这里n介于0和s.length()-1之间。例如:

char first = greeting.charAt(0); // first is 'H'

char last = greeting.charAt(4); // last is 'o'

To get at the ith code point, use the statements

要获得第i个代码点,使用语句:

int index = greeting.offsetByCodePoints(0, i);

int cp = greeting.codePointAt(index);

NOTE

 

Java counts the code units in strings in a peculiar fashion: the first code unit in a string has position 0. This convention originated in C, where there was a technical reason for counting positions starting at 0. That reason has long gone away and only the nuisance remains. However, so many programmers are used to this convention that the Java designers decided to keep it.

Java以一种特殊的方式计算字符串中的代码单元:字符串中的第一个代码单元的位置是0。这个约定源于C,在C中位置从0开始计数是有技术原因的。这个技术原因现在早已不存在了,但是却留下了这个令人讨厌的方式。但是由于很多程序员习惯了这个约定,所以Java的设计者们决定保留它。

Why are we making a fuss about code units? Consider the sentence

我们为什么要在代码单元上小题大做?看一下这个句子

is the set of integers

The character requires two code units in the UTF-16 encoding. Calling

在UTF-16编码中,字符需要两个代码单元,调用

char ch = sentence.charAt(1)

doesn't return a space but the second code unit of . To avoid this problem, you should not use the char type. It is too low-level.

并不返回一个空格,而是其第二个代码单元。要避免这个问题,你不应当使用char类型。这个类型太低级。

If your code traverses a string, and you want to look at each code point in turn, use these statements:

如果你的代码遍历一个字符串,并且你想逐个查看每个代码单元,请使用下面的语句:

int cp = sentence.codePointAt(i);

if (Character.isSupplementaryCodePoint(cp)) i += 2;

else i++;

Fortunately, the codePointAt method can tell whether a code unit is the first or second half of a supplementary character, and it returns the right result either way. That is, you can move backwards with the following statements:

幸运的是,codePointAt方法可以告诉我们何处是一个辅助字符的前一半或者后一半,并且对于任一一种都可以返回正确的结果。也就是说,你也可以用下面的语句进行逆向遍历

i--;

int cp = sentence.codePointAt(i);

if (Character.isSupplementaryCodePoint(cp)) i--;

Substrings 子串

You extract a substring from a larger string with the substring method of the String class. For example,

用substring方法可以从一个大的字符串中提取字串。例如

String greeting = "Hello";

String s = greeting.substring(0, 3);

creates a string consisting of the characters "Hel".

得到一个由字符”Hel”组成的字串。

The second parameter of substring is the first code unit that you do not want to copy. In our case, we want to copy the code units in positions 0, 1, and 2 (from position 0 to position 2 inclusive). As substring counts it, this means from position 0 inclusive to position 3 exclusive.

substring的第二个参数是你第一个不想复制的代码单元。在我们的例子中,我们想复制的是位置0、1、2(从位置0到位置2,包含端点)。也就是从位置0(包含)到位置3(不包含)。

There is one advantage to the way substring works: Computing the number of code units in the substring is easy. The string s.substring(a, b) always has b - a code units. For example, the substring "Hel" has 3 – 0 = 3 code units.

substring的这种工作方式有一个优点:计算字串中的代码单元数量是简单的。字符串s.substring(a,b)的代码单元数总是等于b-a。从例子即可看出。

String Editing 字符串编辑

The String class gives no methods that let you change a character in an existing string. If you want to turn greeting into "Help!", you cannot directly change the last positions of greeting into 'p' and '!'. If you are a C programmer, this will make you feel pretty helpless. How are you going to modify the string? In Java, it is quite easy: concatenate the substring that you want to keep with the characters that you want to replace.

Java中的String类型虽然不提供字符串编辑的方法,但是,你可以采用将某个字符串的字串和其他字串相连接的方式。例如你希望将”Hello”修改为”Help!”,你可以这样做

greeting = greeting.substring(0, 3) + "p!";

This declaration changes the current value of the greeting variable to "Help!".

Because you cannot change the individual characters in a Java string, the documentation refers to the objects of the String class as being immutable. Just as the number 3 is always 3, the string "Hello" will always contain the code unit sequence describing the characters H, e, l, l, o. You cannot change these values. You can, as you just saw however, change the contents of the string variable greeting and make it refer to a different string, just as you can make a numeric variable currently holding the value 3 hold the value 4.

在Java中,你不能改变Java字串中的某个值,但是,你可以改变变量的内容,即使得字符串变量指向其他字符串。

Isn't that a lot less efficient? It would seem simpler to change the code units than to build up a whole new string from scratch. Well, yes and no. Indeed, it isn't efficient to generate a new string that holds the concatenation of "Hel" and "p!". But immutable strings have one great advantage: the compiler can arrange that strings are shared.

虽然生成新的字符组合效率会降低,但是不可变的字符串有一大优点:编译器可以将字符串共享。

To understand how this works, think of the various strings as sitting in a common pool. String variables then point to locations in the pool. If you copy a string variable, both the original and the copy share the same characters. Overall, the designers of Java decided that the efficiency of sharing outweighs the inefficiency of string editing by extracting substrings and concatenating.

要理解这个工作过程,假设各种字符串处在一个共享池中。字符串变量指向池中的某一个位置。如果你复制一个字符串,原字串和拷贝共享同一个字符序列。总之,Java设计者认为共享的有效性远大于提取字串在连接的字符串编辑的有效性。

Look at your own programs; we suspect that most of the time, you don't change strings—you just compare them. Of course, in some cases, direct manipulation of strings is more efficient. (One example is assembling strings from individual characters that come from a file or the keyboard.) For these situations, Java provides a separate StringBuilder class that we describe in Chapter 12. If you are not concerned with the efficiency of string handling, you can ignore StringBuilder and just use String.

看看我们的程序,大多数时候,我们并不改变字串,而是进行比较。当然,有时候直接对字符串进行操作更为有效。(一个例子就是编译来自于一个文件或者键盘的独立字符序列。)对此种情况而言,Java提供独立的StringBuilder类。我们在12章中讨论。如果你对字符串处理的效率不感兴趣,你可以跳过StringBuilder,仅仅使用String就可以了。

C++ NOTE

 

C programmers generally are bewildered when they see Java strings for the first time because they think of strings as arrays of characters:

C程序员第一次看到Java字符串的时候会感到疑惑,因为他们会认为字符串其实就是字符数组:

char greeting[] = "Hello";

That is the wrong analogy: a Java string is roughly analogous to a char* pointer,

这是一个错误的类比:Java字符串组略的类同于一个char*指针。

char* greeting = "Hello";

When you replace greeting with another string, the Java code does roughly the following:

当你用另一个字符串代替greeting的时候,Java代码粗略的进行如下工作:

char* temp = malloc(6);

strncpy(temp, greeting, 3);

strncpy(temp + 3, "p!", 3);

greeting = temp;

Sure, now greeting points to the string "Help!". And even the most hardened C programmer must admit that the Java syntax is more pleasant than a sequence of strncpy calls. But what if we make another assignment to greeting?

当然,现在greeting指向字符串”Help!”。即使是最铁杆的C程序员也必须承认Java语句比使用一组strncpy函数要令人愉快。但如果我们要给greeting另作指派又会如何呢?

greeting = "Howdy";

Don't we have a memory leak? After all, the original string was allocated on the heap. Fortunately, Java does automatic garbage collection. If a block of memory is no longer needed, it will eventually be recycled.

这难道不会产生内存泄漏?毕竟,原字串是分配在堆上的。幸运的是,Java具有垃圾自动回收机制。如果某部分内存不再需要,它将最终被回收。

If you are a C++ programmer and use the string class defined by ANSI C++, you will be much more comfortable with the Java String type. C++ string objects also perform automatic allocation and deallocation of memory. The memory management is performed explicitly by constructors, assignment operators, and destructors. However, C++ strings are mutable—you can modify individual characters in a string.

如果你是C++程序员,并且使用由ANSI C++定义的string类,你将感到和Java中的String类型一样的舒服。C++中的string对象也能自动分配和释放内存。内存管理由构造函数、赋值运算符和析构函数清晰的执行。但是C++字符串是可变的,你可以修改字串中的独立字符。

Concatenation 连接

Java, like most programming languages, allows you to use the + sign to join (concatenate) two strings.

和大多数编程语言一样,Java也可以使用+号将两个字符串相连接。

String expletive = "Expletive";

String PG13 = "deleted";

String message = expletive + PG13;

The above code sets the variable message to the string "Expletivedeleted". (Note the lack of a space between the words: the + sign joins two strings in the order received, exactly as they are given.)

以上的代码将变量message设置为字符串”Expletivedeleted”。(之所以两个单词之间会缺少空格,是因为+号精确的按照两个单词给出的顺序将其连接起来)

When you concatenate a string with a value that is not a string, the latter is converted to a string. (As you see in Chapter 5, every Java object can be converted to a string.) For example:

当你将一个字符串和一个非字符串连接时,后者将转换为字符串(第五章中,你将看到,Java对象都可以转换成字符串),例如:

int age = 13;

String rating = "PG" + age;

sets rating to the string "PG13".

将rating设置为”PG13”。

This feature is commonly used in output statements. For example,

这一功能通常用于输出语句,例如

System.out.println("The answer is " + answer);

is perfectly acceptable and will print what one would want (and with the correct spacing because of the space after the word is).

可以很好的接受,并打印出你想要的(由于is 后面有空格,所以也能正确的打印出空格)

Testing Strings for Equality 测试字符串相等

To test whether two strings are equal, use the equals method. The expression

要测试两个字符串是否相等,使用equals方法。表达式

s.equals(t)

returns TRue if the strings s and t are equal, false otherwise. Note that s and t can be string variables or string constants. For example, the expression

返回true当字符串t和s相等时,否则,返回false。注意,s和t可以是字符串变量,也可以是字符串常量。例如,表达式

"Hello".equals(greeting)

is perfectly legal. To test whether two strings are identical except for the upper/lowercase letter distinction, use the equalsIgnoreCase method.

也是很合法的。要测试两个字符串除了大小写的差别是否相同,使用equalsIgnoreCase方法。

"Hello".equalsIgnoreCase("hello")

Do not use the == operator to test whether two strings are equal! It only determines whether or not the strings are stored in the same location. Sure, if strings are in the same location, they must be equal. But it is entirely possible to store multiple copies of identical strings in different places.

不要使用==运算符来测试两个字符串是否相等!这种方法仅能判断两个字符串是否存储在同一个位置上。当然,如果字符串存储在同一个位置上,他们肯定相等。但是在不同的位置存储相同的字符串的多个拷贝也是完全有可能的。

String greeting = "Hello"; //initialize greeting to a string

if (greeting == "Hello") . . .

// probably true

if (greeting.substring(0, 3) == "Hel") . . .

// probably false

If the virtual machine would always arrange for equal strings to be shared, then you could use the == operator for testing equality. But only string constants are shared, not strings that are the result of operations like + or substring. Therefore, never use == to compare strings lest you end up with a program with the worst kind of bug—an intermittent one that seems to occur randomly.

如果虚拟机总是将字符串分配为共享的,那么,你可以使用==运算符来测试相等。但是只有字符串常量是共享的,而那些+或者substring运算产生的字符串则不是共享的。所以,千万不可以使用==来比较字符串,以免你编写出的程序存在最糟糕的一种bug——一种不连续发生的貌似随机的Bug。

C++ NOTE

 

If you are used to the C++ string class, you have to be particularly careful about equality testing. The C++ string class does overload the == operator to test for equality of the string contents. It is perhaps unfortunate that Java goes out of its way to give strings the same "look and feel" as numeric values but then makes strings behave like pointers for equality testing. The language designers could have redefined == for strings, just as they made a special arrangement for +. Oh well, every language has its share of inconsistencies.

如果你习惯了C++的string类,那么你需要特别注意相等性测试。C++中的string类在进行字符串内容的相等比较的时候,运算符==进行了重载。Java打破自己的形式,给字符串赋予数字值一般的外表,而实际上又让这些字符串在比较的时候像指针一样,这也许是个不幸的事情。这门语言的设计者可以重新定义string中的==符号,就像他们特别分配了+号一样。嗯,好吧,每个语言都有其矛盾的一面。

C programmers never use == to compare strings but use strcmp instead. The Java method compareTo is the exact analog to strcmp. You can use

C程序员从不使用==来比较字符串,而是使用strcmp。Java中的compareTo方法精确的类似于strcmp,你可以使用

if (greeting.compareTo("Hello") == 0) . . .

but it seems clearer to use equals instead.

但是使用equals似乎更清晰明了。

The String class in Java contains more than 50 methods. A surprisingly large number of them are sufficiently useful so that we can imagine using them frequently. The following API note summarizes the ones we found most useful.

Java中的String类有多达50个方法。这么多的方法都十分的有用,所以我们可以经常使用它们。下面的API注释中,我们总结了最有用的一些方法

(译者:以下内容不再翻译,仅供参考。)

NOTE

 

You will find these API notes throughout the book to help you understand the Java Application Programming Interface (API). Each API note starts with the name of a class such as java.lang.String—the significance of the so-called package name java.lang is explained in Chapter 4. The class name is followed by the names, explanations, and parameter descriptions of one or more methods.

We typically do not list all methods of a particular class but instead select those that are most commonly used, and describe them in a concise form. For a full listing, consult the on-line documentation.

We also list the version number in which a particular class was introduced. If a method has been added later, it has a separate version number.

 

java.lang.String 1.0

  • char charAt(int index)

returns the code unit at the specified location. You probably don't want to call this method unless you are interested in low-level code units.

  • int codePointAt(int index) 5.0

returns the code point that starts or ends at the specified location.

  • int offsetByCodePoints(int startIndex, int cpCount) 5.0

returns the index of the code point that is cpCount code points away from the code point at startIndex.

  • int compareTo(String other)

returns a negative value if the string comes before other in dictionary order, a positive value if the string comes after other in dictionary order, or 0 if the strings are equal.

  • boolean endsWith(String suffix)

returns TRue if the string ends with suffix.

  • boolean equals(Object other)

returns true if the string equals other.

  • boolean equalsIgnoreCase(String other)

returns true if the string equals other, except for upper/lowercase distinction.

  • int indexOf(String str)
  • int indexOf(String str, int fromIndex)
  • int indexOf(int cp)
  • int indexOf(int cp, int fromIndex)

return the start of the first substring equal to the string str or the code point cp, starting at index 0 or at fromIndex, or -1 if str does not occur in this string.

  • int lastIndexOf(String str)
  • int lastIndexOf(String str, int fromIndex)
  • int lastindexOf(int cp)
  • int lastindexOf(int cp, int fromIndex)

return the start of the last substring equal to the string str or the code point cp, starting at the end of the string or at fromIndex.

  • int length()

returns the length of the string.

  • int codePointCount(int startIndex, int endIndex) 5.0

returns the number of code points between startIndex and endIndex - 1. Unpaired surrogates are counted as code points.

  • String replace(CharSequence oldString, CharSequence newString)

returns a new string that is obtained by replacing all substrings matching oldString in the string with the string newString. You can supply String or StringBuilder objects for the CharSequence parameters.

  • boolean startsWith(String prefix)

returns true if the string begins with prefix.

  • String substring(int beginIndex)
  • String substring(int beginIndex, int endIndex)

return a new string consisting of all code units from beginIndex until the end of the string or until endIndex - 1.

  • String toLowerCase()

returns a new string containing all characters in the original string, with uppercase characters converted to lower case.

  • String toUpperCase()

returns a new string containing all characters in the original string, with lowercase characters converted to upper case.

  • String trim()

returns a new string by eliminating all leading and trailing spaces in the original string.

Reading the On-Line API Documentation

As you just saw, the String class has lots of methods. Furthermore, there are thousands of classes in the standard libraries, with many more methods. It is plainly impossible to remember all useful classes and methods. Therefore, it is essential that you become familiar with the on-line API documentation that lets you look up all classes and methods in the standard library. The API documentation is part of the JDK. It is in HTML format. Point your web browser to the docs/api/index.html subdirectory of your JDK installation. You will see a screen like that in Figure 3-2.

Figure 3-2. The three panes of the API documentation

[View full size image]

The screen is organized into three frames. A small frame on the top left shows all available packages. Below it, a larger frame lists all classes. Click on any class name, and the API documentation for the class is displayed in the large frame to the right (see Figure 3-3). For example, to get more information on the methods of the String class, scroll the second frame until you see the String link, then click on it.

Figure 3-3. Class description for the String class

[View full size image]

Then scroll the frame on the right until you reach a summary of all methods, sorted in alphabetical order (see Figure 3-4). Click on any method name for a detailed description of that method (see Figure 3-5). For example, if you click on the compareToIgnoreCase link, you get the description of the compareToIgnoreCase method.

Figure 3-4. Method summary of the String class

[View full size image]

Figure 3-5. Detailed description of a String method

[View full size image]

TIP

 

Bookmark the docs/api/index.html page in your browser right now.

2007年9月10日星期一

3.5.4 其他运算符

Bitwise Operators 位运算符

When working with any of the integer types, you have operators that can work directly with the bits that make up the integers. This means that you can use masking techniques to get at individual bits in a number. The bitwise operators are

& ("and") | ("or") ^ ("xor") ~ ("not")

These operators work on bit patterns. For example, if n is an integer variable, then

int fourthBitFromRight = (n & 8) / 8;

gives you a 1 if the fourth bit from the right in the binary representation of n is 1, and 0 if not. Using & with the appropriate power of 2 lets you mask out all but a single bit.

在对整数类型进行处理的时,还有能够直接处理构成整数的各个位的运算符。这意味着你可以使用掩码技术来处理一个数字中的各个独立位。这些位运算符是:

& ("与") | ("或") ^ ("异或") ~ ("非")

这些运算符工作在比特形式下。例如,如果n是一个整型变量,那么

int fourthBitFromRight = (n & 8) / 8;

这条语句将在n的二进制表示从右起第四位是1时得出结果1,否则为0。使用&符号搭配适当的2的指数幂可以使你屏蔽某一个位以外的所有位。

NOTE 注释

 

When applied to boolean values, the & and | operators yield a boolean value. These operators are similar to the && and || operators, except that the & and | operators are not evaluated in "short circuit" fashion. That is, both arguments are first evaluated before the result is computed.

当应用于布尔值时,&和|运算将产生一个布尔值。这些运算符和&&以及||运算符是类似的,但是&和|并不以短路形式运算。也就是说,两个参数在结果算出之前就参与运算。(译者注,参见http://www.itsway.net/java/java020505.aspx)

There are also >> and << operators, which shift a bit pattern to the right or left. These operators are often convenient when you need to build up bit patterns to do bit masking:

int fourthBitFromRight = (n & (1 << 3)) >> 3;

Finally, a >>> operator fills the top bits with zero, whereas >> extends the sign bit into the top bits. There is no <<< operator.

还有>>和<<运算符,可以向左或者向右移动一位。这些运算符在你需要通过位模式来执行按位掩码时是非常方便的,例如:

int fourthBitFromRight = (n & (1 << 3)) >> 3;

最后,>>>运算符用0填写头两位,而>>把符号为增加到头一位。没有<<<运算符。

CAUTION 注意

 

The right-hand side argument of the shift operators is reduced modulo 32 (unless the left-hand side is a long, in which case the right-hand side is reduced modulo 64). For example, the value of 1 << 35 is the same as 1 << 3 or 8.

移位运算符右边的参数被减少到32(除非左边的参数较长,这种情况下,右边的较少到64)。例如,1<<35的值和1<<3或者1<<8是一样的。

C++ NOTE C++注释

 

In C/C++, there is no guarantee as to whether >> performs an arithmetic shift (extending the sign bit) or a logical shift (filling in with zeroes). Implementors are free to choose whatever is more efficient. That means the C/C++ >> operator is really only defined for non-negative numbers. Java removes that ambiguity.

在C/C++中,并不保证>>进行的是算术移位(扩展符号位)还是逻辑移位(以0填充)。设备可以在二者中选择更有效的操作。这就意味着C/C++中的>>运算符的确仅仅是为非负数定义的。Java去除了这种歧义性。

Mathematical Functions and Constants 数学函数与常量

The Math class contains an assortment of mathematical functions that you may occasionally need, depending on the kind of programming that you do.

To take the square root of a number, you use the sqrt method:

Math类包含一组你有时会用到的数学函数,这取决于你所编程序的类型。要计算一个数字的平方根,需要使用sqrt方法:

double x = 4;

double y = Math.sqrt(x);

System.out.println(y); // 打印 2.0

NOTE 注释

 

There is a subtle difference between the println method and the sqrt method. The println method operates on an object, System.out, defined in the System class. But the sqrt method in the Math class does not operate on any object. Such a method is called a static method. You can learn more about static methods in Chapter 4.

println方法和sqrt方法有一个微妙的差别。println方法对一个对象进行操作,即System类中定义的System.out。但是Math类中的sqrt方法并不对任何对象进行操作。这样的方法称作静态方法。你可在第四章中学习更多有关静态方法的知识。

The Java programming language has no operator for raising a quantity to a power: you must use the pow method in the Math class. The statement

double y = Math.pow(x, a);

sets y to be x raised to the power a (xa). The pow method has parameters that are both of type double, and it returns a double as well.

Java语言没有指数幂运算符,你需要使用Math类中的pow方法。语句

double y = Math.pow(x, a);

将y的值设置为x的a次幂。pow方法的两个参数都应该是double类型,且返回值也是double类型。

The Math class supplies the usual trigonometric functions

Math类提供了常用的三角函数:

Math.sin

Math.cos

Math.tan

Math.atan

Math.atan2

and the exponential function and its inverse, the natural log:

以及指数函数及其逆运算——自然对数:

Math.exp

Math.log

Finally, two constants denote the closest possible approximations to the mathematical constants p and e:

最后,介绍两个与数学常量p 和 e的值非常近似的常量:

Math.PI

Math.E

TIP提示

 

Starting with JDK 5.0, you can avoid the Math prefix for the mathematical methods and constants by adding the following line to the top of your source file:

从JDK5.0开始,你可以在源文件起始处使用如下代码来避免每次使用数学方法和常量的Math前缀。

import static java.lang.Math.*;

For example,

例如:

System.out.println("The square root of \u03C0 is " + sqrt(PI));

We discuss static imports in Chapter 4.

我们将在第四章讨论静态导入。

NOTE注意

 

The functions in the Math class use the routines in the computer's floating-point unit for fastest performance. If completely predictable results are more important than fast performance, use the StrictMath class instead. It implements the algorithms from the "Freely Distributable Math Library" fdlibm, guaranteeing identical results on all platforms. See http://www.netlib.org/fdlibm/index.html for the source of these algorithms. (Whenever fdlibm provides more than one definition for a function, the StrictMath class follows the IEEE 754 version whose name starts with an "e".)

为了获得最快的性能,Math类中的函数使用计算机浮点运算单元中的例程。如果可预测的结果完全重于快速表现,则使用StrictMath类。这个类从“自由分布数学库”中实现运算,保证各个平台上的统一的结果。算法源码参见http://www.netlib.org/fdlibm/index.html。不论何时fdlibm提供对一个函数的多种定义,StrictMath类始终遵循以“e”开始命名的IEEE 754版本。

Conversions Between Numeric Types 数字类型之间的转换

It is often necessary to convert from one numeric type to another. Figure 3-1 shows the legal conversions.

在多种数字类型之间进行转换是常有的事,图3-1说明了合法的转换:

图3-1 数字类型之间的合法转换

The six solid arrows in Figure 3-1 denote conversions without information loss. The three dotted arrows denote conversions that may lose precision. For example, a large integer such as 123456789 has more digits than the float type can represent. When the integer is converted to a float, the resulting value has the correct magnitude but it loses some precision.

图3-1中的六个实箭头表示无信息丢失的转换。三个虚箭头表示可能丢失精度的转换。例如,一个大的整型数字,如123456789,其位数多于浮点型能够表示的位数。当这个整型数转换成浮点型时,结果值仍然很大,但是丢失了精度。

int n = 123456789;

float f = n; // f is 1.23456792E8

When two values with a binary operator (such as n + f where n is an integer and f is a floating-point value) are combined, both operands are converted to a common type before the operation is carried out.

当两个数字和一个二进制运算符结合在一起(例如n+f中,n是一个整数,而f是一个浮点数),两个操作数都会在运算之前被转换为通用类型。

  • If either of the operands is of type double, the other one will be converted to a double.
  • Otherwise, if either of the operands is of type float, the other one will be converted to a float.
  • Otherwise, if either of the operands is of type long, the other one will be converted to a long.
  • Otherwise, both operands will be converted to an int.
  • 如果两个操作数有一个是double型,另一个转换为double型。
  • 否则,如果两个操作数有一个为float型,则另一个转换为float型。
  • 否则,如果两个操作数有一个为long型,则另一个转换为long型。
  • 否则,两个操作数都被转换为整型。

Casts

In the preceding section, you saw that int values are automatically converted to double values when necessary. On the other hand, there are obviously times when you want to consider a double as an integer. Numeric conversions are possible in Java, but of course information may be lost. Conversions in which loss of information is possible are done by means of casts. The syntax for casting is to give the target type in parentheses, followed by the variable name. For example:

在前面的章节中,你可以看到整型值在需要的时候可以自动转换为double型,另一方面,有时你也希望把double型转换为整型。在Java中,数字类型的转换是允许的,但是丢失信息也是自然的。丢失信息的转换是依靠强制转换来完成的。强制转换的语句是在变量名前加上由圆括号括起来的目标类型,例如:

double x = 9.997;

int nx = (int) x;

Then, the variable nx has the value 9 because casting a floating-point value to an integer discards the fractional part.

这样,变量nx的值就是0,因为浮点型向整型的强制转换舍弃了小数部分。

If you want to round a floating-point number to the nearest integer (which is the more useful operation in most cases), use the Math.round method:

如果你想把一个浮点数四舍五入成最接近的整数(在大多数情况下,这是更有用的操作),使用Math.round方法:

double x = 9.997;

int nx = (int) Math.round(x);

Now the variable nx has the value 10. You still need to use the cast (int) when you call round. The reason is that the return value of the round method is a long, and a long can only be assigned to an int with an explicit cast because there is the possibility of information loss.

现在,变量nx的值就是10了。在你调用round方法时,你还是需要进行强制转换(int)。原因是round方法的返回值类型是long,而long类型在给int变量赋值时,由于可能产生信息丢失,所以必须采用显式转换。

CAUTION注意

If you try to cast a number of one type to another that is out of the range for the target type, the result will be a truncated number that has a different value. For example, (byte) 300 is actually 44.

如果你试图将某种类型的数字转换为比原类型范围小的目标类型,结果将被截断,产生一个不同的值,例如(byte) 300 的结果实际上是44。

C++ NOTE C++注释

You cannot cast between boolean values and any numeric type. This convention prevents common errors. In the rare case that you want to convert a boolean value to a number, you can use a conditional expression such as b ? 1 : 0.

你不能在布尔型和数字类型之间进行转换。这种转换将产生常见错误。极少数情况下,你希望将布尔值转换为一个数字,此时你可以使用条件表达式,例如b?1:0

Parentheses and Operator Hierarchy 圆括号和运算优先级

Table 3-4 shows the precedence of operators. If no parentheses are used, operations are performed in the hierarchical order indicated. Operators on the same level are processed from left to right, except for those that are right associative, as indicated in the table. For example, because && has a higher precedence than ||, the expression

Table 3-4. Operator Precedence

Operators

Associativity

[] . () (method call)

Left to right

! ~ ++ -- + (unary) – (unary) () (cast) new

Right to left

* / %

Left to right

+ -

Left to right

<< >> >>>

Left to right

< <= > >= instanceof

Left to right

== !=

Left to right

&

Left to right

^

Left to right

|

Left to right

&&

Left to right

||

Left to right

?:

Right to left

= += -= *= /= %= &= |= ^= <<= >>= >>>=

Right to left

表3-4展示了运算符的优先级。如果没有使用括号,运算符将按照表中显示的优先级进行运算。除了表中指明的右结合的运算符,同一级别的运算符自左向右运算。例如,&&和优先级高于||,表达式

a && b || c

means等于

(a && b) || c

Because += associates right to left, the expression

由于+=自右向左结合,表达式

a += b += c

means等于

a += (b += c)

That is, the value of b += c (which is the value of b after the addition) is added to a.

也就是b+=c的值(即第一次加法后b的值)再加到a上。

C++ NOTE C++注释

Unlike C or C++, Java does not have a comma operator. However, you can use a comma-separated list of expressions in the first and third slot of a for statement.

与C或C++不同,Java没有逗号运算符,但是你可以在一个for语句中的第一个和第三个位置使用一个逗号分隔的表达式。

C语言中的逗号运算符:

C语言中逗号“,”也是一种运算符,称为逗号运算符。 其功能是把两个表达式连接起来组成一个表达式, 称为逗号表达式。
其一般形式为: 表达式1,表达式2 其求值过程是分别求两个表达式的值,并以表达式2的值作为整个逗号表达式的值。
void main(){
int a=2,b=4,c=6,x,y;
y=(x=a+b),(b+c);
printf("y=%d,x=%d",y,x);
}
a<--2,b<--4,c<--6,x<--0,y<--0
x<--a+b,y<---b+c
本例中,y等于整个逗号表达式的值,也就是表达式2的值,x是第一个表达式的值。对于逗号表达式还要说明几点:
1.逗号表达式一般形式中的表达式1和表达式2 也可以又是逗号表达式。例如: 表达式1,(表达式2,表达式3) 形成了嵌套情形。因此可以把逗号表达式扩展为以下形式: 表达式1,表达式2,…表达式n 整个逗号表达式的值等于表达式n的值。
2.程序中使用逗号表达式,通常是要分别求逗号表达式内各表达式的值,并不一定要求整个逗号表达式的值。
3.并不是在所有出现逗号的地方都组成逗号表达式,如在变量说明中,函数参数表中逗号只是用作各变量之间的间隔符。
以上是摘抄来的 我本人觉得自己最常使用逗号运算符是在
for循环里
for (i = 0, j = 0; i < 3 && j < 3; i++, j+=2) {
printf("i = %d, j = %d",i,j);
}

Enumerated Types 枚举类型

Sometimes, a variable should only hold a restricted set of values. For example, you may sell clothes or pizza in four sizes: small, medium, large, and extra large. Of course, you could encode these sizes as integers 1, 2, 3, 4, or characters S, M, L, and X. But that is an error-prone setup. It is too easy for a variable to hold a wrong value (such as 0 or m).

有时候,一个变量需要仅保存一组有限值的集合。例如,你可能出售四种尺寸的衣服或者匹萨:小号、中号、大号和特大号。当然,你可以给这四种型号编号为1,2,3,4或者S,M,L,X。但这是一个具有错误倾向的设置。变量很可能会承载一个错误的值(比如0或者m)。

Starting with JDK 5.0, you can define your own enumerated type whenever such a situation arises. An enumerated type has a finite number of named values. For example,

从JDK5.0开始,你可以在遇到这种情况时定义自己的枚举类型。一个枚举类型具有有限个数的命名变量。例如:

enum Size { SMALL, MEDIUM, LARGE, EXTRA_LARGE };

Now you can declare variables of this type:

现在,你可以定义这种类型的变量:

Size s = Size.MEDIUM;

A variable of type Size can hold only one of the values listed in the type declaration or the special value null that indicates that the variable is not set to any value at all.

一个Size类型的变量只能承载Size类型中声明的一个值,或者承载一个特殊值null来表示这个变量没有被设置任何值。

We discuss enumerated types in greater detail in Chapter 5.

我们将在第五章更详细的讨论枚举类型。

3.5.3 Relational and boolean Operators关系和逻辑运算符

 

Java has the full complement of relational operators. To test for equality you use a double equal sign, ==. For example, the value of

Java有完全的关系运算符补充。要测试相等,你可以使用一个双等号,==。比如,

3 == 7

is false.

3==7的值是false。

Use a != for inequality. For example, the value of

使用!=来测试不等。比如:

3 != 7

is true.

3 != 7的值是true。

Finally, you have the usual < (less than), > (greater than), <= (less than or equal), and >= (greater than or equal) operators.

最后,还有普通的< (小于),> (大于),<= (小于等于),和 >= (大于等于) 运算符。

Java, following C++, uses && for the logical "and" operator and || for the logical "or" operator. As you can easily remember from the != operator, the exclamation point ! is the logical negation operator. The && and || operators are evaluated in "short circuit" fashion. The second argument is not evaluated if the first argument already determines the value. If you combine two expressions with the && operator,

Java,和C++一样,使用&&表示逻辑与,使用||表示逻辑或。由于你能轻易记得!=运算符,所以感叹号!就表示逻辑非。 && 和 || 运算符采用“短路”方式求值。如果第一个参数的值已经确定,则不需要考虑第二个参数的值。如果你将两个表达式用&&连接,

expression1 && expression2

and the truth value of the first expression has been determined to be false, then it is impossible for the result to be TRue. Thus, the value for the second expression is not calculated. This behavior can be exploited to avoid errors. For example, in the expression

并且第一个表达式的真值是false,那么运算结果不可能为true。因此第二个表达式的值不参与运算。该特性可以用来避免错误。例如,在表达式

x != 0 && 1 / x > x + y // no division by 0

the second part is never evaluated if x equals zero. Thus, 1 / x is not computed if x is zero, and no divide-by-zero error can occur.

当中,第二部分如果x等于0的话就不被计算。

Similarly, the value of expression1 || expression2 is automatically true if the first expression is true, without evaluation of the second expression.

类似的,表达式expression1 || expression2 中,如果第一表达式为true,那么整个表达式的值就为true,而不计算第二个表达式的值。

Finally, Java supports the ternary ?: operator that is occasionally useful. The expression

最后,Java支持偶尔很有用的三目运算符?:。表达式

condition ? expression1 : expression2

evaluates to the first expression if the condition is TRue, to the second expression otherwise. For example,

如果condition为ture则计算expression1的值,否则计算expression2的值。例如:

x < y ? x : y

gives the smaller of x and y.

求得x和y当中较小的一个。

2007年9月7日星期五

我对Java Serializable(序列化)的理解和总结[转]

1、序列化是干什么的?
       简单说就是为了保存在内存中的各种对象的状态,并且可以把保存的对象状态再读出来。虽然你可以用你自己的各种各样的方法来保存Object States,但是Java给你提供一种应该比你自己好的保存对象状态的机制,那就是序列化。
2、什么情况下需要序列化  
    a)当你想把的内存中的对象保存到一个文件中或者数据库中时候;
    b)当你想用套接字在网络上传送对象的时候;
    c)当你想通过RMI传输对象的时候;
3、当对一个对象实现序列化时,究竟发生了什么?
    在没有序列化前,每个保存在堆(Heap)中的对象都有相应的状态(state),即实例变量(instance ariable)比如:

java 代码

  1. Foo  myFoo = new Foo();  
  2. myFoo .setWidth(37);  
  3. myFoo.setHeight(70);  

当 通过下面的代码序列化之后,MyFoo对象中的width和Height实例变量的值(37,70)都被保存到foo.ser文件中,这样以后又可以把它 从文件中读出来,重新在堆中创建原来的对象。当然保存时候不仅仅是保存对象的实例变量的值,JVM还要保存一些小量信息,比如类的类型等以便恢复原来的对 象。

java 代码

  1. FileOutputStream fs = new FileOutputStream("foo.ser");  
  2. ObjectOutputStream os = new ObjectOutputStream(fs);  
  3. os.writeObject(myFoo);  

4、实现序列化(保存到一个文件)的步骤
a)Make a FileOutputStream            

java 代码

  1. FileOutputStream fs = new FileOutputStream("foo.ser");    

       b)Make a ObjectOutputStream           

java 代码

  1. ObjectOutputStream os =  new ObjectOutputStream(fs);   

       c)write the object

java 代码

  1. os.writeObject(myObject1);  
  2. os.writeObject(myObject2);  
  3. os.writeObject(myObject3);  

    d) close the ObjectOutputStream

java 代码

  1. os.close();  


5、举例说明

java 代码

  1. import java.io.*;
  2. public class  Box implements Serializable  
  3. {  
  4. private int width;  
  5. private int height;  
  6. public void setWidth(int width){  
  7. this.width  = width;  
  8.     }  
  9. public void setHeight(int height){  
  10. this.height = height;  
  11.     }  
  12. public static void main(String[] args){  
  13.         Box myBox = new Box();  
  14.         myBox.setWidth(50);  
  15.         myBox.setHeight(30);  
  16. try{  
  17.             FileOutputStream fs = new FileOutputStream("foo.ser");  
  18.             ObjectOutputStream os =  new ObjectOutputStream(fs);  
  19.             os.writeObject(myBox);  
  20.             os.close();  
  21.         }catch(Exception ex){  
  22.             ex.printStackTrace();  
  23.         }  
  24.     }  
  25. } 


6、相关注意事项
    a)当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
    b)当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;
    c)并非所有的对象都可以序列化,,至于为什么不可以,有很多原因了,比如:
        1.安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行rmi传输  等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的。
       2. 资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分  配,而且,也是没有必要这样实现。

2007年9月6日星期四

3.5.2 Operators运算符之增量运算符和减量运算符

Increment and Decrement Operators增量和减量运算符

Programmers, of course, know that one of the most common operations with a numeric variable is to add or subtract 1. Java, following in the footsteps of C and C++, has both increment and decrement operators: n++ adds 1 to the current value of the variable n, and n-- subtracts 1 from it. For example, the code

程序员,自然地,知道一种最普通的带有数字变量的运算符,用来实现加1或者减1。Java步C和C++的后尘,也有增量和减量运算符:n++ 给当前变量的值加1,而n-- 从n中减去1。例如,代码:

int n = 12;

n++;

changes n to 13. Because these operators change the value of a variable, they cannot be applied to numbers themselves. For example, 4++ is not a legal statement.

将n改变为13。由于这些运算符用来改变变量的值,所以他们不能被用来改变数字本身。例如4++就不是一个合法的语句。

There are actually two forms of these operators; you have seen the "postfix" form of the operator that is placed after the operand. There is also a prefix form, ++n. Both change the value of the variable by 1. The difference between the two only appears when they are used inside expressions. The prefix form does the addition first; the postfix form evaluates to the old value of the variable.

这些运算符实际上有两种形式;你见过运算符被置于操作数后面的“后缀”形式。还有一个前缀形式,++n。都是改变变量的值多一或少一。二者的不同仅体现在他们用于表达式的时候。前缀形式先做加法运算;后缀形式求得变量的原值。

int m = 7;

int n = 7;

int a = 2 * ++m; // now a is 16, m is 8

int b = 2 * n++; // now b is 14, n is 8

We recommend against using ++ inside other expressions because this often leads to confusing code and annoying bugs.

我们不推荐在其他表达式中使用++,因为这经常导致混乱的代码以及恼人的bug。

(Of course, while it is true that the ++ operator gives the C++ language its name, it also led to the first joke about the language. C++ haters point out that even the name of the language contains a bug: "After all, it should really be called ++C, because we only want to use a language after it has been improved.")

(当然,当++运算符赋予C++语言这个名字的时候,它也引发了这个语言的第一个笑话。C++的反对者指出就连这个程序语言的名字都存在bug:“毕竟,她真的该叫做C++,因为我们只想在语言被改进以后使用它。”)

2007年9月4日星期二

Minute to Midnight Special Edition

eMule资源

下面是用户共享的文件列表,安装eMule后,您可以点击这些文件名进行下载

Linkin.Park.-.[Minutes.To.Midnight.Special.Edition].演唱会.(ISO).iso 详情
4.7GB

eMule主页 下载eMule 使用指南 如何发布

中文名称:Minutes To Midnight
版本:特别豪华版本[Special Edition]
发行时间:2007年05月15日
专辑歌手:Linkin Park
地区:美国
语言:英语
简介:
41UUMbE6gWL__SS500_.jpg
专辑类型: Rock
唱片公司: Warner Bros
级别: Explicit Lyrics
版本:DVD镜像
专辑介绍
<末日警钟 毁灭.新生 Minutes to Midnight>专辑主题跟以往联合公园所触及的创作主题比起来显得特别深沉、格外引人省思,但却也自我唤醒我们每一个人的危机意识。专辑标题<Minutes to Midnight>想要表达出的其实就是『世界末日钟(Doomsday Clock)』的概念!『世界末日钟(Doomsday Clock)』是源自于美国二次世界大战时期,当美国在日本长崎及广岛投下两颗原子弹之后,在1974年由一群芝加哥大学研究原子科学的科学家们(Board of Directors of the Bulletin of the Atomic Scientists at the University of Chicago)所一起创立的概念。科学家们以『世界末日钟(Doomsday Clock)』这个虚拟的定时器,来警惕人类将因过度使用核武,而导致自我灭亡。而「Midnight」午夜所代表的就是灭亡时刻。在二次世界大战之后,由于核武疯狂急速地发展,世界末日钟的时针一度被推进到距离代表世界末日的午夜不到15分钟的时间,甚至在1960年代美苏冷战、核武竞争时期,时针还曾被推进到只剩3分钟(11点57分)。目前在经过前前后后18次调整之后,在核武、天气异常、及环境污染的影响之下,世界距离毁灭的午夜时分也只剩五分钟的时间。主唱查斯特(Chester Bennington)表示:「创立这个末日钟的目的就是要提醒世人,虽然人类拥有巨大力量,但当这股毁灭性力量反扑之时,我们都该仔细思考这股威力带来的严重影响,转眼之间世界末日已进入倒数计时。这个极具争议性的主题,在几年前我们是完全不会触及的,当年我们在制作『混合理论(Hybrid Theory)』专辑时,我是团里最年长的,但年纪也只有23岁,当时的我们不觉得这个议题十分重要,但现在的我们却认为它跟我们息息相关。这张专辑所比喻的「午夜」的概念,不单单只有指涉地球遭到人类破坏的这种巨观层面,同时也映像出联合公园自我的微观层面。「午夜」所代表的『终结』同样也呼应联合公园在音乐上面的改变,因为所有和联合公园一同成长的信徒们,将在这张最新专辑里发现联合公园的全新面貌,过去大家所熟悉的联合公园将毁灭消失,联合公园将以崭新姿态解构重生。"Minutes to Midnight"是美国说唱金属乐团Linkin Park(林肯公园)的第三张录音室专辑。
该特别豪华版本里收藏有CD与DVD各一枚,内容以下:(CD部分因已有人分布,故不再重复)
5.1 versions of all 12 tracks(5.1版的所有歌曲)[CD部分]
MP3 versions of all 12 tracks(歌曲的MP3版)
The Making of Minutes To Midnight(关于MTM的记录片)
The "What I've Done" music video (MTM的MV)
The Making of "What I've Done"(关于MTM的制作)
Wallpapers(墙纸)
Screensavers(屏幕保护)
"Buddy" icons(BUDDY的标识)
A PDF booklet with Lyrics(PDF格式的歌词书册)
使用该DVD自带的播放器时(无法自动播放时,右击浏览DVD,点击DVD内的Minutes to Midnight.exe,记住!完全打开需花上10-15秒左右),将出现以下的画面,使用其他的播放器时,将不会。
在Amazon提前预定后,还以为很快就会到手,没想到17号还不到,还想因缺货订单会被取消,没想今天来了。高兴!!马上分享。
菜单截图:
1.jpg
2.jpg
3.jpg
4.jpg
版权的解释权始终属于发行公司
专辑曲目:
(CD)
1. Wake
2. Given Up
3. Leave Out All The Rest
4. Bleed It Out
5. Shadow Of The Day
6. What I've Done
7. Hands Held High
8. No More Sorrow
9. Valentine's Day
10. In Between
11. In Pieces
12. The Little Things Give You Away
(DVD)
The Making of Minutes To Midnight
The "What I've Done" music video
The Making of "What I've Done"

2007年9月3日星期一

幻觉

时常幻想自己仍然身处大学校园,过着无忧无虑的生活。

但是现实却无情的在耳边尖叫——

我一无所有

但我不是一无是处。

回忆和幻想时常让我放松,

而现实又把我拉回喧嚣的世界。

太想成长,但是又偏偏斩不断那根多愁善感的神经。

 

我不能再这样下去

振作起来,

面对现实;

因为不是一无是处,

所以才要更有信心,

把自己塑造的更加完美!

 

向“孩子”这个称呼告别吧!!!