• 《Java编程思想》阅读笔记一


    Java编程思想

    这是一个通过对《Java编程思想》(Think in 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
    基本数据类型在没有初始化的时候会获得一个默认值。

    基本数据类型 默认值 大小
    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
    

    二、equals方法

    p45
    在自定义的对象中使用equals方法时需要覆盖此方法,否则默认是比较引用

    三、短路

    p47
    其现象本质为:当已经确定一个逻辑表达式的结果时不会再计算剩余的部分。

    public class ShortCircuit {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		boolean flag1 = test1()&&test2()||test3()&&test4();
    		System.out.println("
    ");
    		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,所以后面部分不会被调用。

    四、e

    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 标签

    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});

    第七章(复用类)

    一、toString()的自动调用

    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
    

    三、final

    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)调用导出类(本体)的构造器主体。

  • 相关阅读:
    java.lang.NoSuchMethodError: org.springframework.beans.factory.annotation.InjectionMetadata.<init>(Ljava/lang/Class;)V
    tomcat下jndi的三种配置方式
    使用@RequestParam绑定请求参数到方法参数
    IE下easyui 缓存问题
    many to one could not resolve property
    aop郁闷错误
    Spring 运用 pointcut 和 advisor 对特定的方法进行切面编程
    放大改进版~
    cocos2d-x嵌入移动MM短代支付IAP2.4的SDK,点击支付崩溃的解决的方法
    在 Android* 商务应用中实施地图和地理围栏特性
  • 原文地址:https://www.cnblogs.com/cpacm/p/5568405.html
Copyright © 2020-2023  润新知