我没有系统学过 Java,从一个 C++ 程序员的角度简单梳理下 Java 语言的基本特性,目的是能上手写一些简单程序。
快捷键:
Java 中有两大数据类型:
一个 C++ 和 Java 的小区别,假设 x 是 int 型变量,那么
while (x) { ...... }
在 C++ 中是正确的,但是在 Java 中一定要写成 while (x != 0)
。
对于 Java 的基本数据类型,赋值操作(assignment,即 =
操作)是按值拷贝的。但对于 Java objects,=
这个操作是“浅拷贝”,即相当于引用。(关于浅拷贝和深拷贝,这里只要记住 =
不能完成深拷贝,只相当于传递了对象的引用)。
消息是 OOP 中的核心概念。Java 中的表达形式:
receiver.method-name(parameter list)
或者
receiver.variable-name
这里 receiver
可以是 class 或 object。
例子:
System.out.println(x.getClass().getName());
Java class 的构造函数形式:
public class-name(typed parameter list) { // object initialization code }
函数名是类名,没有返回值
构造函数调用方式(创建新的实例对象):
new class-name(parameter list)
除了创建实例,构造函数还有可能有如下调用方式:
this(parameter list); // 调用该类重载的构造函数 super(parameter list); // 超类的构造函数
例子:
public String() { this(""); }
public class A { object and class member definitions }
和 C++ 类似,Java 中也有 实例成员(instance member) 和 类成员(class member) 的区别。
用 static 关键字声明的成员是类成员。
Java 中用 final 关键字声明 constants:
static final int taxRates;
和 C++ 类似有 public, private 和 protected
有一点要注意,Java 中有 “package scope”,其范围为一个包含 java source code files 的目录,相同的 package scope 的 java 源文件都包含:
package package-name;
null 可以赋值给任何对象,比如赋值给一个 list 对象,表示 list 对象为空。
用 extends 关键字:
public class B extends A { instance and class member definitions }
使用 abstract 关键字:
public abstract class A { member definitions public abstract boolean func(int n); more member definitions } public class B extends A { new member definitions public boolean func(int n) { implementation code } more new member definitions }
interface 和 抽象类类似,但是其中所有方法都必须是空的,而且如果有数据成员,必须用 final 声明。
接口通过 implements 实现。
public interface C { public boolean func(int n); more method declarations } public class E extends A implements C, D { definitions of members declared in A, C, and D new member definitions }
数组:
int [] A = new int[5]; A[2] = 3; System.out.println("The value of A[2] is " + A[2]);
注意这里自动进行了 int 转 String 。
Java 中的字符串不像 C 中那样是 char 类型的数组,一般通过类 String 表示。
Java 中的所有对象都有一个 toString() 方法。
常用数据结构:
接口类型:
强制转换:
(String)(enum.nextElement())
一般情况下,一个 Java 源文件中应该只定义一个 class,文件名就应该是类名,比如 Comparators.java 。
好的编程规范是将一组相关的 java 源文件写到同一个 package 中。每个 package 应该单独占一个文件夹。
注意 package 可以有层级关系,组织文件时按照子文件夹来组织,比如
package ig.util; // ig 包下有一个 util 包
文件夹形式应该为:
/ig/util
import fully-qualified-class-name;
注意 fully-qualified-class-name 的形式应该为:
package-name.class-name
例子:
import ig.util.Comparators; import java.util.*;
一个 .java 文件应该有如下结构:
package statement import statements class definition
javac A.java java A
基本接口:
常用实现:
常用方法:
public boolean isEmpty() public boolean contains(Object obj) public int size() public boolean equals(Object other) public Object[] toArray()
直接看一个例子:
import java.util.ArrayList; public class test { public static void main(String[] args) { // 创建 ArrayList ArrayList<String> stringList = new ArrayList<String>(); // 添加元素,在尾部添加新元素 stringList.add("foo"); stringList.add("bar"); stringList.add("zot"); stringList.add("bah"); // 使用 get() 获取指定下标元素 System.out.println("Size of List: " + stringList.size()); System.out.println("Contents: "); for (int i = 0; i < stringList.size(); ++i) { System.out.println("At index " + i + " value = " + stringList.get(i)); } System.out.println(); // 删除元素,可以按值或按下标 stringList.remove("bar"); System.out.println("Contents after remove \"bar\": "); for (int i = 0; i < stringList.size(); ++i) { System.out.println("At index " + i + " value = " + stringList.get(i)); } System.out.println(); stringList.remove(1); System.out.println("Contents after remove element of index 1: "); for (int i = 0; i < stringList.size(); ++i) { System.out.println("At index " + i + " value = " + stringList.get(i)); } System.out.println(); // 在指定位置添加元素 stringList.add(1, "meh"); System.out.println("Contents after add \"meh\" at index 1: "); for (int i = 0; i < stringList.size(); ++i) { System.out.println("At index " + i + " value = " + stringList.get(i)); } System.out.println(); // 设置指定位置的元素值 stringList.set(1, "bar"); System.out.println("Contents after set \"bar\" at index 1: "); for (int i = 0; i < stringList.size(); ++i) { System.out.println("At index " + i + " value = " + stringList.get(i)); } System.out.println(); // 查询元素下标 System.out.println("Index of \"bar\": "); System.out.println(stringList.indexOf("bar") + "\n"); // 查询失败返回 -1 System.out.println("Index of \"zzz\": "); System.out.println(stringList.indexOf("zzz") + "\n"); } }
注意 indexOf() 方法基于容器内元素类型的 equals() 方法,如果没有定义 equals() 方法,indexOf() 总会返回 -1。
下面是一个自定义元素类型的例子:
// MyIntClass.java // Simple integer class with just two constructors. // A more robust version would make the int m_value private with // accessor methods instead public class MyIntClass { public int value; public MyIntClass() { value = 0; } public MyIntClass(int val) { value = val; } public boolean equals(Object otherIntObject) { MyIntClass otherInt = (MyIntClass) otherIntObject; if (this.value == otherInt.value) return true; return false; } }
import java.util.ArrayList; public class test { public static void main(String[] args) { ArrayList<MyIntClass> arr = new ArrayList<MyIntClass>(); for (int i = 0; i < 4; ++i) { arr.add(new MyIntClass(i)); } System.out.println("Size: " + arr.size() + "\n"); System.out.println("Original ArrayList: "); PrintArrayList(arr); arr.remove(2); System.out.println("After remove: "); PrintArrayList(arr); arr.add(1, new MyIntClass(100)); System.out.println("After insert :"); PrintArrayList(arr); // 如果 MyIntClass 中没有 equals() 方法,会返回 -1 System.out.println("Position of 1"); System.out.println(arr.indexOf(new MyIntClass(1))); } public static void PrintArrayList(ArrayList<MyIntClass> arr) { MyIntClass tmp; for (int i = 0; i < arr.size(); ++i) { tmp = arr.get(i); System.out.println(tmp.value); } System.out.println(); } }
for (BaseType varName : ArrayListVariable) { Statement with varName }
public static void PrintArrayList(ArrayList<MyIntClass> arr) { for (MyIntClass intObj : arr) { System.out.println(intObj.value); } System.out.println(); }
HashSet 是基于 Set 接口的一个集合类实现(底层通过 hash table 实现),其中保证没有重复元素。所以 HashSet 是一个集合类容器,不是哈希表,注意其中的元素是无序的。如果需要有序的集合,要使用 TreeSet。直接看例子代码:
import java.util.HashSet; import java.util.Iterator; public class test { private static void outputSet(HashSet<String> set) { for (String s : set) { System.out.println(s + " "); } System.out.println(); } public static void main(String[] args) { HashSet<String> round = new HashSet<String>(); HashSet<String> green = new HashSet<String>(); round.add("peas"); round.add("ball"); round.add("pie"); round.add("grapes"); green.add("peas"); green.add("grapes"); green.add("garden hose"); green.add("grass"); System.out.println("Contents of set round: "); outputSet(round); System.out.println("\nContents of set green: "); outputSet(green); // contains() 方法检查是否存在某一元素 System.out.println("\nball and peas in same set? " + ((round.contains("ball") && (round.contains("peas"))) || (green.contains("ball") && (green.contains("peas"))))); System.out.println("\npie and grass in same set? " + ((round.contains("pie") && (round.contains("grass"))) || (green.contains("pie") && (green.contains("grass"))))); // 利用 addAll() 方法求两个 HashSet 的并集 HashSet<String> setUnion = new HashSet<String>(round); setUnion.addAll(green); System.out.println("\nUnion of green and round: "); outputSet(setUnion); // 利用 removeAll() 方法求两个 HashSet 的交集 HashSet<String> tmp = new HashSet<String>(round); tmp.removeAll(green); HashSet<String> setInter = new HashSet<String>(round); setInter.removeAll(tmp); System.out.println("\nIntersection of green and round: "); outputSet(setInter); } }
要在 HashSet 中使用自定义类型,需要实现自定义类的 hashCode() 和 equals() 方法。
注意不要被上面 HaseSet 迷惑,Map 才是保存 key-value 对的容器。要保证 key 的类型有 hashCode() 和 equals() 方法。
看例子代码:
import java.util.HashMap; import java.util.Scanner; public class test { public static void main(String[] args) { HashMap<Integer, String> employees = new HashMap<Integer, String>(10); employees.put(10, "Joe"); employees.put(49, "Andy"); employees.put(91, "Greg"); employees.put(70, "Kiki"); employees.put(99, "Antoinette"); System.out.print("Added Joe, Andy, Greg, Kiki, "); System.out.println("and Antoinette to the map."); System.out.println("The map contains: "); for (Integer key : employees.keySet()) { System.out.println(key + " : " + employees.get(key)); } System.out.println(); // 从键盘输入 id Scanner keyboard = new Scanner(System.in); int id; do { System.out.print("\nEnter an id to look up in the map. "); System.out.println("Enter -1 to quit."); id = keyboard.nextInt(); if (employees.containsKey(id)) { String e = employees.get(id); System.out.println("ID found: " + e.toString()); } else if (id != -1) System.out.println("ID not found."); } while (id != -1); } }