OCA/OCP Java Note (1): Java Building Blocks (1)
Contents
1. Understanding the Java Class Structure
1.1. Comments
注释有以下三种形式,其中最后一种用于Javadoc:
// comment until end of line /* Multiple * line comment */ /** * Javadoc multiple-line comment * @author Jeanne and Scott */
对于多行注释,在一组 /*
和 */
之间的多行内容都会被作为注释,要小心 /*
和 */
不匹配的情况,如下面的代码无法编译:
/* * /* ferret */ */
第一行的 /*
和第二行末尾的 */
配对,之间的 * /* ferret 成为注释(注意这里第一个*和/之间有一个空格),而第三行的 */
没有与之相对的 /*
,导致编译错误。
1.2. Classes vs. Files
多数情况下,Java类都被定义在自己的同名*.java文件中,且通常都是public的,表明任何代码都可以调用它。但Java并不强制要求每一个类都是public,如:
class Animal { String name; }
也可以在同一个文件中定义多个类,但其中最多只能有一个类是public的:
public class Animal { private String name; } class Animal2 { }
对于public的类,它的类名必须与文件名匹配,上面的例子在一个文件中定义了两个类,其中Animal为public,则这个文件的文件名必须为Animal.java。
2. Writing a main() Method
一个典型的main()函数如下:
public class Main { public static void main(String[] args) { } }
其参数列表为一个java.lang.String对象的列表,可以写成数组String[] args 、String args[] 或可变参数String… args 的形式。
下面的mian()函数会将其前两个参数打印出来:
public class Main { public static void main(String[] args) { System.out.println(args[0]); System.out.println(args[1]); } }
编译并使用如下参数运行:
$ javac Zoo.java $ java Zoo A1 A2
得到的打印为:
A1 A2
两个参数用空格区分,如果想在一个参数中使用空格,需要将参数用双引号“” 括起来:
$ java Zoo "A1 A2" A3
得到的打印为:
A1 A2 A3
通过命令行传入的参数都被作为String对象:
$ java Zoo A1 2
得到的打印为:
A1 2
这里的2 为String而不是int。
如果通过命令行给出的参数数量少于main()函数访问的参数,则在main()函数访问到命令行未给出的参数时,会发生java.lang.ArrayIndexOutOfBoundsException。
3. Understanding Package Declarations and Imports
3.1. Wildcards
通配符(wildcard)用于一次性导入一个包中的所有类,如:
import java.util.*;
这里的* 作为通配符,将导入java.util包中的所有类,包括java.util.Random等等,但不会导入子包(child packages)、字段(fields)或是方法(methods)。之后会涉及到静态导入(static import),允许导入其他类型。
3.2. Redundant Imports
之前的例子在使用String时,并没有导入String所在的包java.lang,这是因为java.lang包会被自动导入,其余的包都需要手动导入。
下面的例子使用了Files和Paths两个类:
public class InputImports { public void read(Files files) { Paths.get("name"); } }
Files和Path都位于java.nio.file包中,可以使用通配符导入:
import java.nio.file.*;
也可以使用类名导入:
import java.nio.file.Files; import java.nio.file.Paths;
但是,下面的导入方法都是不正确的:
import java.nio.*; // NO GOOD – 通配符只能匹配类名,导入当前包下的所有类, // 不会包括java.nio下的file包,不会导入Files和Paths两个类 import java.nio.*.*; // NO GOOD – 最多只能使用一个通配符,且通配符必须在末尾 import java.nio.files.Paths.*; // NO GOOD – 不能导入方法
3.3. Naming Conflicts
不同的包下面可以存在具有相同名称的类,导入时需要注意避免命名冲突。下面的例子希望使用 java.util.Date:
public class Conflicts { Date date; // some more code }
与之前类似,导入java.util.Date可以使用如下两种方式:
import java.util.*;
或:
import java.util.Date;
有很多包中都有名叫Date的类,当这个类同时存在于多个被导入的包中时,会导致编译错误:
import java.util.*; import java.sql.*; // DOES NOT COMPILE
java.util和java.sql包中都有一个名叫Date的类,上面第二行在导入java.sql时会发生编译错误:The type Date is ambiguous。如果想同时使用java.util.Date和java.sql中的其他类,可以使用如下的方式:
import java.util.Date; import java.sql.*;
第一行显式地指明了要导入java.util.Date,这种方式的优先级高于通配符。如果以相同的优先级导入两个命名冲突的类,同样会导致编译错误:
import java.util.Date; import java.sql.Date; // DOES NOT COMPILE
如果一定要同时使用java.util.Date和java.sql.Date,解决办法是只导入其中之一,另一个使用完整名称(包名.类名):
import java.util.Date; public class Conflicts { Date date; java.sql.Date sqlDate; }
或者二者都不导入,只使用完整名称:
public class Conflicts { java.util.Date date; java.sql.Date sqlDate; }
3.4. Creating a New Package
包名和路径相关联,如有位于packagea的ClassA在C:\temp\packagea\ClassA.java,有packageb的ClassB在C:\temp\packageb\ClassB.java:
package packagea; public class ClassA { }
package packageb; import packagea.ClassA; public class ClassB { public static void main(String[] args) { ClassA a; System.out.println("Got it"); } }
在Windows下进行编译和运行的方法如下:
cd C:\temp javac packagea/ClassA.java packageb/ClassB.java java packageb.ClassB
packagea和packageb都位于temp文件夹下,进入temp文件夹后,可以直接使用javac进行编译。此外,还可以通过class path来指定其他路径下的文件:
java -cp ".;C:\temp\someOtherLocation;c:\temp\myJar.jar" myPackage.MyClass
也可以使用通配符来包含class path下的所有jar:
java -cp "C:\temp\directoryWithJars\*" myPackage.MyClass
3.5. Code Formatting on the Exam
如果考试中的问题不涉及import,则题目的代码中会省略import的部分,此时代码段的行号不会从1开始,下面的代码段从第6行开始,说明省略了import的部分:
6: public void method(ArrayList list) { 7: if (list.isEmpty()) { System.out.println("e"); 8: } else { System.out.println("n"); 9: } }
而对于下面的代码段,行号从1开始,而又没有import ArrayList,则认为该段代码无法编译:
1: public class LineNumbers { 2: public void method(ArrayList list) { 3: if (list.isEmpty()) { System.out.println("e"); 4: } else { System.out.println("n"); 5: } } }