这是一个经过对《Java编程思想》(Think in java)第四版进行阅读同时对java内容查漏补缺的系列。一些基础的知识不会被罗列出来,这里只会列出一些程序员常常会忽略或者混淆的知识点。java
所列知识点所有都是针对本身我的而言,同时也欢迎你们进行补充。
程序员
public class HelloWorld { public static void main(String[] args) { System.out.println("Hello every one,I'm cpacm"); } }
这一章是java的总体介绍,让咱们先熟悉了java是什么。其具体的内容都会在后面介绍。编程
p22
栈(堆栈):存放基本类型变量和对象引用变量。位于RAM区
堆:存放new获得的对象和数组。也位于RAM区
常量存储:存放常量,包括静态变量。数组
p26
基本数据类型在没有初始化的时候会得到一个默认值。ide
基本数据类型 | 默认值 | 大小 |
---|---|---|
boolean | false | 未肯定 |
char | null | 16bits |
byte | 0 | 8bits |
short | 0 | 16bits |
int | 0 | 32bits |
float | 0f | 32bits |
long | 0L | 64bits |
double | 0d | 64bits |
tip1:String不是基本数据类型
tip2:上面的初始默认值并不适用于方法内部变量。其默认初始化值未知。当使用未初始化的变量编译器会返回错误函数
public class BaseType { static boolean b; static char c; static byte bt; static short s; static int i; static float f; static long l; static double d; public static void main(String[] args) { System.out.println("类变量——"+"boolean:"+b+" char:"+c+" byte:"+bt+" short:"+s+" int:"+i+" float:"+f+" long:"+l+" double:"+d); } } //类变量——boolean:false char: byte:0 short:0 int:0 float:0.0 long:0 double:0.0
p40
当两个变量包含的是同一个引用时,修改其中一个变量的值另外一个变量的值也同时改变。记住new出来的对象的=赋值都是只传递引用。
Tip:减小为对象赋值。测试
class T{ int i; } public class Assigment { public static void main(String[] args) { T t1 = new T(); T t2 = new T(); t1.i = 5; t2.i = 8; t1 = t2; t1.i = 10000; System.out.println(t2.i); } } //10000
p45
在自定义的对象中使用equals方法时须要覆盖此方法,不然默认是比较引用。ui
p47
其现象本质为:当已经肯定一个逻辑表达式的结果时不会再计算剩余的部分。this
public class ShortCircuit { public static void main(String[] args) { // TODO Auto-generated method stub boolean flag1 = test1()&&test2()||test3()&&test4(); System.out.println("\n"); boolean flag2 = test1()&&test3()||test2()&&test4(); } static boolean test1(){ System.out.println("test1"); return true; } static boolean test2(){ System.out.println("test2"); return false; } static boolean test3(){ System.out.println("test3"); return true; } static boolean test4(){ System.out.println("test4"); return false; } } /* test1 test2 test3 test4 test1 test3 */
boolean flag2 = test1()&&test3()||test2()&&test4();
若test1为true,test3为true时,由于前面这部分已经肯定为true,因此后面部分不会被调用。code
p49
科学与工程领域中,"e"表明天然对数的基数,为2.718。
而在C,C++和java(或者更多的语言)中,"e"表明“10的幂次”
$1.39e-43f = 1.39*10^{-43}$
p49
与,或,异或,非 &,|,^,~
与:全部的位都为1则输出1,不然输出0;
或:只要有一个位是1就输出1;
异或:两个位值相等时输出1;
非:1输出0,0输出1.
位运算不会出现短路现象。
p50
移位操做符:
$<<$:操做数向左移动,低位补0;
$>>$:操做数向右移动,(1)符号为正时,高位补0,(2)符号为负时,高位补1;
$>>>$:java独有操做符,操做数向右移动,高位统一补0。
char,byte,short进行移位操做时先会转成int类型,即32位
public class URShift { public static void main(String[] args) { int i = 1024; System.out.println(Integer.toBinaryString(i)); i >>= 10; System.out.println(Integer.toBinaryString(i)); i = -1; System.out.println(Integer.toBinaryString(i)); i >>>= 10; System.out.println(Integer.toBinaryString(i)); i <<= 1; System.out.println(Integer.toBinaryString(i)); short s = -1; s >>>= 10;//s移位后获得的结果在赋值时会强行转为int,因此移位后的s已是int型 System.out.println(Integer.toBinaryString(s)); s = -1; System.out.println(Integer.toBinaryString(s>>>10)); } } /* 10000000000 1 11111111111111111111111111111111 1111111111111111111111 11111111111111111111110 11111111111111111111111111111111 1111111111111111111111 */
p55
将float或double转型为整数值时,老是对数字进行截尾,不会进行四舍五入。若是想要获得舍入的结果可使用Math.round()
public class CastingNumbers { public static void main(String[] args) { double d = 1.7d; int i = (int)d; System.out.println(i); i = (int) Math.round(d); System.out.println(i); } } //1 //2
goto关键词,在java中则是使用标签代替臭名昭著的goto。其实在java中也是最好不要用标签来跳转语句,太伤智商。。
写法
outer:
并放在迭代语句前。
(1)continue 标签
跳出全部循环,并到标签位置的语句,但会从新进入紧接后面的循环里。
(2)break 标签
跳出全部循环,且再也不进入紧接后面的循环里。
public class LabeledFor { public static void main(String[] args) { System.out.println("测试continue————————————"); label: for(int i=0;i<3;i++){ System.out.println("外部for循环"+i); for(int j=0;j<3;j++){ if(j==1){ continue label; } System.out.println("内部循环"+j); } } System.out.println("测试break————————————————"); label2: for(int m=0;m<3;m++){ System.out.println("外部for循环"+m); for(int n=0;n<3;n++){ if(n==1){ break label2; } System.out.println("内部循环"+n); } } } } /* 测试continue———————————— 外部for循环0 内部循环0 外部for循环1 内部循环0 外部for循环2 内部循环0 测试break———————————————— 外部for循环0 内部循环0*/
p81
重载主要以传入参数及顺序来区别。不能经过返回值来区别
以基本数据类型传入时:自动包装机制
(1)若传入的数据类型小于方法中声明的形式参数类型,实际数据类型就会提高。
byte->short->int->long->float->double
(2)若是传入的实际参数较大,就得经过类型转换执行窄化转换。
p91
标记-清扫(Android中使用这个技术)
从堆栈和存储区出发,遍历全部的引用,进而找出全部存活的对象,并给与标记。遍历完成后,清理全部未被标记的对象。
中止-复制
先暂停程序的运行,而后将全部存活的对象复制到另外一个堆,而没有复制的是可回收的内存。
p94
全部的变量都会在任何方法(包括构造器)被调用以前获得初始化。
p95
不管建立多少对象,静态数据都只占用一份存储区域,static不能做用于局部变量。且静态初始化动做只执行一次。
p102
void method(Object... args){}
调用 method();或method(new Object[]{1,2,3,4});
p126
有时候编译器会自动帮你调用toString()方法。
"source"+ source;这时候会自动调用source对象的toString方法。
p130
构造函数老是从基类开始。
class Insert{ Insert(){ System.out.println("Insert"); } } public class Beetle extends Insert{ Beetle(){ System.out.println("Beetle"); } public static void main(String[] args) { // TODO Auto-generated method stub Beetle b = new Beetle(); } } //Insert //Beetle
p140
对于基本类型,final使数值恒定不变;而用于对象引用,final使引用恒定不变,但对象自己是能够改变的。
private 属于 final 方法
static final是属于类属性,即能被类调用,不用实例化
final则须要实例化。
组合模式能够看作是一颗树,每一个枝干均可以长出新的枝干,它们的结构都是相同的。
将枝干抽象为一个类,里面包含连接下一个节点的方法,若须要不断的连接下一个节点只须要继承这个方法并实现。
示例:导航菜单
组合模式,将对象组合成树形结构以表示“部分-总体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具备一致性。
public abstract class Tab { private String title; public Tab(String title) { this.title = title; } protected abstract void add(Tab tab); protected abstract void romove(Tab tab); } public class CardTab extends Tab{ public CardTab(String title) { super(title); // TODO Auto-generated constructor stub } private List<Tab> tabs; @Override protected void add(Tab tab) { // TODO Auto-generated method stub tabs.add(tab); } @Override protected void romove(Tab tab) { // TODO Auto-generated method stub tabs.remove(tab); } } public class TabView { public static void main(String[] args) { // TODO Auto-generated method stub CardTab rootTab = new CardTab("roottab"); CardTab tab1 = new CardTab("tab1"); CardTab tab2 = new CardTab("tab2"); CardTab tab3 = new CardTab("tab3"); rootTab.add(tab1); rootTab.add(tab2); rootTab.add(tab3); CardTab tab4 = new CardTab("tab1-1"); CardTab tab5 = new CardTab("tab1-2"); tab1.add(tab4); tab1.add(tab5); } } /** * 这样子Tab组成了一个导航列表,这就是一个简单的组合模式. */
多态是一项让程序员“将改变的事物与未变的事物分离开来”的重要技术。
p156
缺陷1:只有非private方法才能够被覆盖
class Super{ public int field = 0; public int getField(){return field;}; } class Sub extends Super { public int field = 1; public int getField() { return field; } public int getSuperField() { return super.field; } } public class FiledAccess { public static void main(String[] args) { Super sup = new Sub(); // Upcast System.out.println("sup.field = " + sup.field + ", sup.getField() = " + sup.getField()); Sub sub = new Sub(); System.out.println("sub.field = " + sub.field + ", sub.getField() = " + sub.getField() + ", sub.getSuperField() = " + sub.getSuperField()); } } 输出: sup.field = 0, sup.getField() = 1 sub.field = 1, sub.getField() = 1, sub.getSuperField() = 0
缺陷2:域和静态方法直接在编译时候进行解析,因此多态不会对其产生做用。
class StaticSuper { public static String staticGet() { return "Base staticGet()"; } public String dynamicGet() { return "Base dynamicGet()"; } } class StaticSub extends StaticSuper { public static String staticGet() { return "Derived staticGet()"; } public String dynamicGet() { return "Derived dynamicGet()"; } } public class StaticPolymorphism { public static void main(String[] args) { StaticSuper sup = new StaticSub(); // Upcast System.out.println(sup.staticGet()); System.out.println(sup.dynamicGet()); } } /* Output: Base staticGet() Derived dynamicGet() */
p153
@Override做用:
断言,若是咱们使用了这种annotation在一个没有覆盖父类方法的方法时,java编译器将以一个编译错误来警示
p158
构造器在多态时的构造顺序:
class Meal { Meal() { P.print("Meal()"); } } class Bread { Bread() { P.print("Bread()"); } } class Cheese { Cheese() { P.print("Cheese()"); } } class Lettuce { Lettuce() { P.print("Lettuce()"); } } class Lunch extends Meal { Lunch() { P.print("Lunch()"); } } class PortableLunch extends Lunch { PortableLunch() { P.print("PortableLunch()"); } } public class Sandwich extends PortableLunch { private Bread b = new Bread(); private Cheese c = new Cheese(); private Lettuce l = new Lettuce(); public Sandwich() { P.print("Sandwich()"); } public static void main(String[] args) { new Sandwich(); } } class P { public static void print(String s){ System.out.println(s); } } 输出: Meal() Lunch() PortableLunch() Bread() Cheese() Lettuce() Sandwich()
解释说明:
一个继承类实例化的时候必需要确保所使用的成员已经构建完毕,因此必须先调用基类的构造器,因此当实例化Sandwich对象时先调用其基类的构造方法:
Meal()
Lunch()
PortableLunch()
其次对成员变量进行初始化
Bread()
Cheese()
Lettuce()
最后调用构造器
Sandwich()
p163
初始化的过程: (1)在全部事物发生以前,将分配给对象的存储空间初始化为二进制的零。 (2)调用基类构造器。 (3)按照声明顺序调用成员的初始化方法。 (4)调用导出类(本体)的构造器主体。