1. Java Basic Structure
public class Hello {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
java 程序由定义组成。在这个程序中,定义了Hello class, main 函数. 且定义(定义函数、变量)都包裹在class中
执行程序时会调用main方法(不一定所有程序都有main,比如该程序只是另一程序的组件时就没有main; 但是对大多数程序来说,main是程序的起点)
main 中的参数为 String[] args , 是为了在命令行中执行java程序时可以传入参数.
2. Java Simple Values and Expressions
2.1 Base types
byte, short, int, long, float, double, boolean, char
int类型可以赋值给long类型(float类型可以赋值给double类型) , 但反过来就要用cast nt i = (int) l
int i, j = 100;
double e = 2.71828;
boolean first, second;
int,long等的default为0, boolea的default为false
这些base type 有相应的wrapper type
Byte, Short, Integer, Long, Float, Double, Boolean, Character
这些wrapper type支持automatic boxing and unboxing(base type 和 wrapper type 之间隐性转化)
int j = 8; Integer a = new Interger (12); int k = a; // unboxing, implicit call to a.intValue() int m = j + a; // a is automatically unboxed before the addition a = 3 * m; // result is automaticially boxed before assignment Integer b = new Integer("100"); // constructor accepts a string int n = Integer.parselnt("100"); // using static method of Integer class
2.2 Operators
java 支持算术操作符 (+ - * /), 比较操作符(> < >= <= == != && || !)
2.3 String
Java中字符串 immutable, 只能修改变量的指向, 而不能真正的修改string
三种创建字符串的方法:
String s1 = new String();
String s2 = new String(); s = "Hello";
String s3 = "Hello";
String s4 = s3;
字符串用双引号, 字符用单引号, + 操作符支持字符串操作
常用内建操作方法:
s1.length();
s1.charAt(index);
s1.indexOf();
s1.equals(s2); // == 操作符不好比较两个字符串
s1.substring(index1, [index2]);
s1.concat(s2); //相当于 s1 = s1 + s2
toString method
toString method 相当于 Python 中的 __str__, 会自动把object转换成字符串
2.4 Variables and Assignment
int x ,y; int a = 1, b = 2, c;
constants
final 用来定义一个不能被改变的常量(e.g 数组的length就是一个final定义的常量)
另外一种使用情景: 如果你发现你在重复使用一个含有确切含义的数字, 你最好把它转换成 final 常量.
if (month == 2) {}; // Bad public final static int FEBRUARY = 2; // 通常放在类定义的最前面 if (month == FEBRUARY) {}; // Good
3. Control Flow
3.1 Conditional Execution
If
If:
if (condition) {
something;
} else if (condition) {
something;
} else {
otherthing;
}
Switch
switch (month) {
case 2:
days = 28;
break;
case 4:
case 6:
case 9:
case 11:
days = 30;
break;
default:
days = 31;
}
3.2 Loop
while
while (condition) {
statement;
}
do-while
do {
statement;
} while();
for
for (initial, condition, counter) {
statement
} // 注意for括号中内容可为空
int[] a = {1, 2, 4, 5}; for (int data : a) { System.out.println(data); }
break continue
continue在while和for中的区别
4. Array
数组是reference type
一个数组中的内容必须是相同的类型(定义数组时的类型) (如果定义时用object, 就可以储存所有类型的对象)
int[] A = {3, 2, 1}; // 定义一个已知内容的数组
A.length 可以获得数组的长度
e.g. 定义一个固定长度空数组, element为相应类型的default值
int[] B = new int[100]
多维数组:
int[][] A;
A = new int[][] {
new int[] {1, 2},
new int[] {3, 4, 5}
};
int [][] A = { {1, 2}, {3, 5, 6} };
也可以定义一个固定长度的空二维数组
int[][] A = new int [10][10];
int a[], b, c[][]; // a是一维数组, b不是数组, c是二维数组
int[] a, b[]; // a是一维数组, c是二维数组
5. Class and Object
5.1 Basic Structure
reference types : types in which are pointers to things (objects) that themselves can contain variables
不指向任何对象的变量指向null (如果调用为初始化的变量(即指向null的变量)的方法, 会抛出NullPointerException)
class Point {
double x, y;
something;
}
Point A ;// 定义变量A可以包含指向Point对象的指针, 但此时A并没有创建Point对象(包含null指针)
A = new Point (); // A, B 包含指向Point对象的指针, new Point() 为 constructor
A.x = 16.0; A.y = 12.0 //定义实例变量
5.2 Fields, Methods
带static的为类属性, 类方法
non-static field 也称作instance variables(fields的内容可以在方法中用this.fieldname 调用 , 有时候会省略this)
static field 也称作class variables, 在当前类的对象中可以直接用, 在其他类中用classname.fieldname 调用(不用新建一个instance)
Method 和 Static Method
class Point {
double x, y;
static double dist (Point p) {
return Math.sqrt (p.x * p.x + p.y + p.y);
}
}
此时为 static method (class method), 通过Point.dist(A) 调用
如果没有static 即
double dist () {
return Math.sqrt (this.x * this.x + this.y + this.y);
}
此时为instance method , 用A.dist() 调用.
此时函数有一个隐含的参数 this(this只存在于non-static method中), this的内容为A这个Point实例(Python中的self), 而且在这个函数中, 所有变量隐含一个前缀this(这点同Python不同, Python必须显性指明self)
double dist() {
return Math.sqrt (x*x + y*y);
}
注意method的参数传递的是value, 也就是说如果传递的是base type, 就会copy一份传入, 如果是object, 就会copy一份reference
5.3 constructor
默认的 constructor do nothing, 可以自定义constructor(会覆盖默认的constructor)
public Point (double x, double, y) {
this.x = x; this.y = y;
}
这样一来我们就不能直接写 new Point() 了, 但我们可以写多个constructor
public Point (double x, double y) {
this. x = x; this.y = y;
}
public Point () {}
这样就构造了多个constructor. 这种方法叫 overloading (多个相同名称但内容不同的函数)(但返回类型不属于method的signature, 因此Java不允许出现名称参数相同但返回类型不同的多个方法)
this在多个constructor中的用途非常大
p.s public private protected, default 区别
- private,表示成员是私有的,只有自身可以访问(子类也不行);
- protected,表示受保护权限,体现在继承,即子类可以访问父类受保护成员(包内其他成员也可以访问该类).(在设计类时, 如果觉得以后可能需要继承这个类, 就可以将相应的field, method设为protected)
- 无修饰词(default),表示包访问权限(friendly, java语言中是没有friendly这个修饰符的,这样称呼应该是来源于c++ ),同一个包内可以访问,访问权限是包级访问权限;
- public,表示成员是公开的,所有其他类都可以访问;
5.4 local variable, instance varibale, class variable
local variable(定义在函数中的): 当函数执行完即消失, 只有在定义的函数中调用
instance variable : 对象消失时消失(对象何时消失? 当没有变量指向它时), 存在于non-static method中(除非名称被local varibale覆盖)
class variable : 存在于整个程序运行中, 在这个类的各处都可以调用(除非名称被local variable覆盖)
P.S. Difference between Object types and Primitive types
6. OOP in Java
6.1 constructor
构造器不会继承, 但会在你定义的子类构造器内被调用
在Java中, 你没有办法让子类不去调用父类的构造器(同Python不同, Python可以覆盖掉父类的构造器), 你只有选择调用父类那个构造器的权利. 默认是没有参数的构造器, 但可以用super(x) 显性指出调用哪个构造器. (如果没有super, 且最近的父类没有没有参数的构造器, 就会出现 compile-time error)
调用父类方法: super.supermethodname.
6.2 继承
An object of class TailList can be assigned to a variable of type SList, but the reverse is not true.
SList s = new TailList(); // Ok
TailList t = new SList(); // Compile-time error
Static type: The type of a variable
Dynamic type: The class of the object the variable references.
so, say "type" for static type and "class" for dynamic type.
Dynamic Method Lookup: Java calls the method for the object's dynamic type
SList s = new TailList();
s.insertEnd(obj); // Calls TailList.insertEnd()
s = new SList();
s.insertEnd(obj); // Calls SList.insertEnd()
Field shadowing: method的选择看dynamic type, field的选择看static type
class Super {
int x = 2;
int f() {
return 2;
}
}
class Sub extends Super {
int x = 4; // shadows Super.x
int f() { // overrides Super.f()
return 4;
}
}
---------------------------
Sub sub = new Sub();
Super supe = sub; // supe and sub reference the same object.
int i;
i = supe.x; // 2
i = sub.x; // 4
i = ((Super) sub).x; // 2
i = ((Sub) supe).x; // 4
i = supe.f(); // 4
i = sub.f(); // 4
i = ((Super) sub).f(); // 4
i = ((Sub) supe).f(); // 4
尽量避免子类和父类的名称相同, 避免 Field shadowing.
static method 也是采用 shadow
final: 定义为final的method不能被override, 定义为final的class不能被继承(final用来提高程序的速度)
继承的重要注意事项:
假设 TailList class 添加了一个 eatTail() 方法, SList 不能调用eatTail(), 即使一个变量指向一个TailList对象, 但type是SList也不能.
TailList t = new TailList();
t.eatTail(); // Ok
SList s = new TailList();
s.eatTail(); // Compile-time error
可以这么理解, s的type是SList, 而且s之后可能指向其他对象(类为SList或父类为SList的对象), 可能出现找不到eatTail方法的情况, 所以为了保险起见, 编译器不会给你通过.
但可以通过一个cast让编译器通过(运行时通不通过就看你写的对不对了)
SList s;
TailList t = new TailList();
s = t; // OK
t = s; // Compiler-time error
t = (TailList) s; // OK, 通过一个cast, 让编译通过, s的static type并不变, 但(TailList) s的static type为TailList
s = new Slist();
t = (TailList) s; //Run-time error: ClassCastException
Why does the compiler reject "t = s", but accept "t = (TailList) s"? It refuses "t = s" because not every SList is a TailList, and it wants you toconfirm that you’re not making a thoughtless mistake. The cast in the latter statement is your way of reassuring the compiler that you’ve designed theprogram to make sure that the SList s will always be a TailList.
If you’re wrong, Java will find out when you run the program, and will crash with a "ClassCastException" error message. The error occurs only at run-time because Java cannot tell in advance what class of object s will reference.
Recall that SLists store items of type Object. When they’re recovered, they usually have to be cast back to a more specific type before they can be used.
Suppose we have a list of Integers. Recall that nth() returns type Object.
int x = t.nth(1).intValue(); // Compiler-time error
int y = ( (Integer) t.nth(1) ).intValue(); // OK
ps: Java中有instanceof(对应Python中的isinstance), 查看的是变量的class
if (s instanceof TailList) {
t = TailList(s) s;
}
6.3 Abstract class and Interface
Abstract class
抽象类是一个不能被初始化的类, 它的功能仅仅是被继承, 定义抽象类的目的是定义一些interface, 让子类都共有, 即使现在还没有定义子类. 抽象类中可以定义具体实现的方法, 也可以定义抽象方法, 这点与interface不同.
public abstract class List{ protected int size; public int length(){ return size; } public abstract void insertFront(Object item); }
抽象类就跟普通类一样能被继承, 而且它的子类往往不是抽象的(如果子类不是抽象类, 则必须实现父类的那些抽象方法)
public class SList extends List{ // inherits the size field protected SListNode head; // inherits the length method public void insertFront(Object item) { head = new SListNode(item, head); size++; } }
Java Interface
Java中, 不能多重继承, 但可以implements 多个Java interface (Java interface中不能实现任何method和field, 除了final field)
public interface Nukeable { public void nuke(); } public interface Comparable { public int compareTo(Object o); } public class SList extends List implements Nukeable, Comparable { // 其他内容同上 public void nuke() { head = null; size = 0 } public int compareTo(Object o){ [Return a number < 0 if this < o, 0 if this.equals(o), > 0 if this > o] } } Nukeable n = new SList(l); Comparable c = (Comparable) n; // 注意这里的cast
interface间支撑多重继承
public interface NukeAndCompare extends Nukeable, Comparable { // other method }
6.4 Generics:
declare general classes that prodece specialized objects. e.g creat an SList for Strings only and another SList for Integers only, even though you only wrote one SList class.
class SListNode<T> { // T is the formal parameter. T item; SListNode<T> next; SListNode(T i, SListNode<T> n) { item = i; next = n; } } public class SList<T> { SListNode<T> head; public void insertFront(T item) { head = new SListNode<T>(item, head); } } SList<String> l = new SList<String>(); // 注意这句话的语法 l.insertFront("Hello"); String s = l.front().item() // 通过generics, 这步就不需要cast了
ps: 在java中不支持泛型的数组
a = new T[N]; // 会出错 a = (T[]) new Object[N]; // 这种形式才正确
6.5 Nested Class
类的定义可以嵌套
public class SinglyLinkedList<E> { //---- nested Node class ----- private static class Node<E> { } }
nested class中的public, private 决定了nested class 能不能被outer class以外的class访问
A nested class can also be designated as either static or (by default) nonstatic,with significant consequences.
A static nested class is most like a traditional class; its instances have no association with any specific instance of the outer class.
A nonstatic nested class is more commonly known as an inner class in Java. An instance of an inner class can only be created from within a nonstatic method of the outer class, and that inner instance becomes associated with the outer instance that creates it. Each instance of an inner class implicitly stores a reference to its associated outer instance, accessible from within the inner class methods using the syntax OuterName.this (as opposed to this, which refers to the inner instance). The inner instance also has private access to all members of its associated outer instance, and can rely on the formal type parameters of the outer class, if generic.
7. 常用 interface
7.1 Iterators
以 stack 为例
import java.util.Iterator; public class Stack<Item> implements Iterable<Item> { ... public Iterator<Item> iterator() { return new ListIterator(); } private class ListIterator implements Iterator<Item> { private Node current = first; public boolean hasNext() { return current != null; } public void remove() { /* not supported */ } public Item next() { Item item = current.item; current = current.next; return item; } } }
7.2 compareTo
public interface Comparable<Item> { public int compareTo(Item that); }
public class Date implements Comparable<Date> { private final int month, day, year; public Date(int m, int d, int y) { month = m; day = d; year = y; } public int compareTo(Date that) { if (this.year < that.year ) return -1; if (this.year > that.year ) return +1; if (this.month < that.month) return -1; if (this.month > that.month) return +1; if (this.day < that.day ) return -1; if (this.day > that.day ) return +1; return 0; } }
8. Exception
8.1 catch Exception
try{
statementX;
return 1;
} catch (IOException e) {
e.printStackTrace();
return 2;
} finally {
f.close();
}
finally 中的内容在 return 或将 Exception 抛上去之前执行
如果 finally 中有 return 3, 则 return 3的内容将会覆盖 return 2 和 return 1 (这样也就没有写 return 1 和 return 2 的必要了)
如果 finally 中出现 Exception, 会替换掉之前的 Exception 或 return.
8.2 throw Exception
public ParseTree parse() throws ParserException, DumbCodeException {
[loops and code]
p = parseExpression();
[more code]
}
public void compile() {
ParseTree p;
try {
p = parse();
p.toByteCode();
}
catch (ParserException e1) { }
catch (DumbCodeException e2) { }
}
checked Throwables 都需要写明会 throws 哪些 Exception (Unchecked Throwables 只有Error及其子类和RunTimeException及其子类, 其余都是checked Throwables)
注意 compile() 中, 如果去掉 catch (DumbCodeException e2) { }, 则必须在前面加上 throws DumbCodeException.(即要对可能出现的checked Throwables进行throw或catch操作)
8.3 Exception constructors
class MyException extends Exception {} // 这样只有没有参数的构造器
class MyException extends Exception { // 这样就有没有参数的构造器和一个接受错误信息的构造器
public MyException() {super(); }
public MyException(String s) { super(s); }
}
9. Java内部机制
9.1 stack and heap
The heap stores all objects(e.g arrays) and all class variables
The stack stores all local variables, including all parameters.
When a method is called, the JVM creates a stack frame(alse known as an activation record) that stores the parameters and local variables for that method.