Java 拾遗(一)

一、Java 字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* Created by simon on 15/11/22.
*/


public class MyText {
public static void main(String[] args){
String str1 = null;
String str2 = "";
String str3 = " ";
String str4 = "abc";
// null字符串并没有为其分配内存空间
// 指向""的字符串为其分配了空间
// " " 是一个空格字符
System.out.println(str1); // 直接输出null字符串会输出 “null” 字符串
System.out.println(str4+str1); //null字符串也可以进行拼接运算 结果为 "abcnull"
System.out.println(str1.length()); //但对null字符串调用取长度方法时 会跑出NullPointerException
}

String stra = new String("abc");
String strb = "abc";
/*stra 和 strb的区别:
以strb的形式建立字符串时,JVM会首先在字符串常量区寻找 ”abc“ 字符串 如果没有则在字符串常量区新建 “abc” 字符串,不会为其在内存空间中开辟区域
以 new 的方式建立字符串时,无关字符串常量区,都会开辟一个段的内存空间
*/

}

二、带label的 break 和 continue 语句

以这两段代码为例考虑 count 的值:(System.out语句为方便理解后加的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class MyText {
public static void main(String[] args) {
int count = 0;
outerLabel:
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
count++;
System.out.println("i: "+i);
System.out.println("j: "+j);
System.out.println("count: "+count);
if (count > 2) {
System.out.println("inner");
continue outerLabel; //直接continue到label处,没有运行后面的代码
}
}
count += 10;
System.out.println("hello" + i);
}
System.out.print(count); //count = 7
}
}
````

````java
public class MyText {
public static void main(String[] args) {
int count = 0;
outerLabel:
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
count++;
System.out.println("i: "+i);
System.out.println("j: "+j);
System.out.println("count: "+count);
if (count > 2) {
System.out.println("inner");
break outerLabel; //break会直接结束label内的循环
}
}
count += 10;
System.out.println("hello" + i);
}
System.out.print(count); //count = 3
}
}

三、多态和instanceof关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class MyText {
public static void main(String[] args) {
Father a = new Son();
Son s = (Son)a;
//Son s = new Father(); Error!!! 无法用子类指向一个父类
//可以想象成 子类的实例需要更多的空间(有更多的方法和变量) new关键字开辟的父类空间不足,所以无法指向。
// 相反,如果使用new 关键字创建的是子类的内存空间,则可以使用父类引用它
System.out.print(a instanceof Son);
System.out.print(a instanceof Father);
System.out.println(s instanceof Son);
System.out.println(s instanceof Father); //所有的的输出均为 true
a.print();
s.print(); //二者输出均为 "Father" (进行了强制类型转换也可以调用父类的方法)
s.print(1); //输出 ”son“ 子类可以重写父类的方法。
//a.print(1); 报错 不强制类型转换无法调用子类重写的方法。
a.print1();
//a.print2(); Error!!!
s.print1();
s.print2(); //不同的方法,a虽然指向了子类空间,但无法调用子类的方法,但可以通过强制类型转换来调用子类的方法,
/*
不同之处在于相同的方法,例如 Son 类的 print方法如果没有参数的话,采用如下的调用方式:

a.print();
s.print();
二者都会调用 Son 的方法
*/

}
}
class Father{
public void print(){

System.out.println("Father");

}
public void print1(){

System.out.println("print1");

}
}
class Son extends Father{

public void print(int i){

System.out.print("Son");

}
public void print2(){

System.out.println("print2");
}
}
}

四、继承和构造函数

构造函数在继承中的几条原则:

  1. 子类必须调用基类的某个构造方法(使用super()调用父类或者this()调用本类的其他构造方法)
  2. 如果子类没有显示调用父类的构造方法,那么会默认调用父类的无参构造方法,先构造父类,再构造子类,如果父类子类存在同名成员,则调用的是子类的成员。
  3. 子类没有显示调用父类的构造方法,父类也没有无参的构造方法,编译出错。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/*
这段代码来自 java-konas 无法正常编译运行
*/


public class AboutConstructors {

class A {
String someString = "a";
public A() { someString += "x"; }

}

class B extends A {
public B() { someString += "g"; };
} //对于无参构造函数/没有显式的调用父类构造方法时,总是递归调用底层基类的构造函数

@Koan
public void simpleConstructorOrder(){
assertEquals(new B().someString, "axg");
}

class Aa {
String someString = "a";
public Aa() { someString += "x"; }
public Aa(String s) {
someString += s;
}
}

class Bb extends Aa {
public Bb() { super("Boo"); someString += "g"; };
}

@Koan
public void complexConstructorOrder(){
assertEquals(new Bb().someString, "aBoog");
}
// 构造函数的第一行显式的调用了父类的构造函数时,不会递归调用其他的构造函数
}