Think in Java 笔记【5章】

第五章 初始化与清理

  • 方法重载:相同方法名称 + 不同参数列表

  • 构造器重载 成员函数重载

  • 为什么方法签名不包含 方法返回值?

    • void f() {} 与 int f(){ return 1; } 编译器很容易区分。

    • 但是在调用 有返回值的f()方法时,如下都行。 第二行的调用编译器就无法确分这两个方法了

       int aInt = f();
       f();
      
  • 涉及基本类型的重载

    • 代码

       // boolean can't be automatically converted
          static void prt(String s) {
              System.out.println(s);
          }
          void f1(char x) { prt("f1(char)"); }
          void f1(byte x) { prt("f1(byte)"); }
          void f1(short x) { prt("f1(short)"); }
          void f1(int x) { prt("f1(int)"); }
          void f1(long x) { prt("f1(long)"); }
          void f1(float x) { prt("f1(float)"); }
          void f1(double x) { prt("f1(double)"); }
      
          void f2(byte x) { prt("f2(byte)"); }
          void f2(short x) { prt("f2(short)"); }
          void f2(int x) { prt("f2(int)"); }
          void f2(long x) { prt("f2(long)"); }
          void f2(float x) { prt("f2(float)"); }
          void f2(double x) { prt("f2(double)"); }
      
          void f3(short x) { prt("f3(short)"); }
          void f3(int x) { prt("f3(int)"); }
          void f3(long x) { prt("f3(long)"); }
          void f3(float x) { prt("f3(float)"); }
          void f3(double x) { prt("f3(double)"); }
      
          void f4(int x) { prt("f4(int)"); }
          void f4(long x) { prt("f4(long)"); }
          void f4(float x) { prt("f4(float)"); }
          void f4(double x) { prt("f4(double)"); }
      
          void f5(long x) { prt("f5(long)"); }
          void f5(float x) { prt("f5(float)"); }
          void f5(double x) { prt("f5(double)"); }
      
          void f6(float x) { prt("f6(float)"); }
          void f6(double x) { prt("f6(double)"); }
      
          void f7(double x) { prt("f7(double)"); }
      
      
    • 入参 - 整型常量时,如f5,f6,f7 int型会自动向上转型(没有精度丢失)

       	void testConstVal() {
              prt("Testing with 5");
              f1(5);f2(5);f3(5);f4(5);f5(5);f6(5);f7(5);
          }
      
          //Output
          f1(int)
          f2(int)
          f3(int)
          f4(int)
          f5(long)
          f6(float)
          f7(double)
      
    • 入参 - char型时,先被转换成int 然后同int型入参结果

      	void testChar() {
              char x = 'x';
              prt("char argument:");
              f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
          }
      
          //Output
          f1(char)
          f2(int)
          f3(int)
          f4(int)
          f5(long)
          f6(float)
          f7(double)
      
    • 入参 - byte型时,自动向上转型

      	void testByte() {
              byte x = 0;
              prt("byte argument:");
              f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
          }
          
          //Output
          f1(byte)
          f2(byte)
          f3(short)
          f4(int)
          f5(long)
          f6(float)
          f7(double)
      
    • 入参 - short型时,自动向上转型

      	void testShort() {
              short x = 0;
              prt("short argument:");
              f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
          }
          
          //Output
          f1(short)
          f2(short)
          f3(short)
          f4(int)
          f5(long)
          f6(float)
          f7(double)
      
    • 如果入参类型表数范围 > 方法入参类型 编译报错

  • 默认构造器 = 空参构造器

    • 当class中构造器为0个时,系统默认提供空参构造
    • 当class中构造器 != 0个时,系统不提供空参构造
  • this关键字 = 调用方法的那个对象(一个对象的引用)

    • 在方法内部调用同一个class的other 方法不必用this(不要滥用this)

    • 用途1 ex:

      class Person {
          public void eat() {
              Apple peeled = apple.getPeeled();
              System.out.println("Yummy);
          }
      }
      
      class Peeler {
          Static Apple peel(Apple apple) {
              // 剥皮...
              retrun apple; //削好皮的苹果
          }
      }
      
      class Apple {
          Apple getPeeled() { retrun Peeler.peel(this); }
      }
      
      public class PassingThis {
          public static void main(String[] args) {
              new Person().eat(new Apple());
          }
      }
      
    • 用途2 this() 指代 构造器

      public class Flower {
          private int petalCount = 0;
          private String s = new String("null");
          
          Flower(int petals) {
              petalCount = petals;
              System.out.println("Constructor w/ int arg only, petalCount= " 
                                 + petalCount);
          }
          
          Flower(String ss) {
              System.out.println(
              "Constructor w/ String arg only, s=" + ss);
              s = ss;
          }
          
          Flower(String s, int petals) {
              this(petals);
              //! this(s); // Can't call two!
              this.s = s; // Another use of "this"
              System.out.println("String & int args");
          }
          
          Flower() {
              this("hi", 47);
              System.out.println(
              "default constructor (no args)");
          }
          
          void print() {
              //! this(11); // Not inside non-constructor!
              System.out.println(
              "petalCount = " + petalCount + " s = "+ s);
          }
          
          public static void main(String[] args) {
              Flower x = new Flower();
              x.print();
          }
      }
      
  • static

    • static 方法内部没this关键字
    • 不创建任何class的实例,能够用 className调用static的filed 和 method
  • java中的finalize()方法 与 C++中的析构函数不同

    • 对象可能不被垃圾回收
    • 垃圾回收 != 析构
    • 垃圾回收只与内存有关
    • 本地方法 支持C和C++ 在内存中可能会存下 与java创建对象方式不同的内存区域
    • 肤浅的认为,垃圾回收机制存在 导致 java 没有析构函数
    • 垃圾回收 和 finalize() 都不保证一定发生,JVM没有面临内存耗尽的情形,不一定会浪费时间和资源去执行垃圾回收
    • 暂时不看
  • 感受垃圾回收器如何工作

    • 引用计数 - 为每个对象统计被引用的次数,次数为0 置为null, 不停遍历所有对象,删除。(弊端:两个对象相互引用,数量都=1 但是都需要被删除)
    • 另一种思路,对于任何“活”对象,一定能最终追溯到其存活在heap 或者 静态存储区之中的引用。从 heap 和 静态存储区开始,遍历所有引用,找到“活”的对象。
  • 成员初始化

    Data type Inital value
    boolean false
    char  '' (value = 0)
    byte 0
    short 0
    int 0
    long 0
    float 0.0
    double 0.0
    引用类型 初始值 为 null
    
  • 构造器初始化

    • 无法阻止自动初始化的进行,它将在构造器被调用之前发生

      class Flower {
          int i;
      
          Flower() {
              System.out.println(i);
              i = 7;
          }
      
          public static void main(String[] args) {
              Flower flower = new Flower();
              System.out.println(flower.i);
          }
      }
      
      //Output
      0
      7
      
    • 类内部 变量定义的先后顺序决定了 初始化的顺续

      • 先初始化成员变量 然后执行构造器
    • static不能作用于局部变量

    • static域是基本类型 有默认标准初值 如果是 引用类型 则 null

    • 静态资源只有class的第一个对象被创建or这个静态域第一次被引用时才会被创建

      • 其实在类加载器加载这个类时就初始化了静态对象
  • 类初始化顺序

      1. 初始化静态对象(若其从未被创建)
      2. 执行static 代码块
      3. 然后非静态 - 开辟空间给所有成员赋默认值,然后赋值类定义时的给值
      4. 执行构造代码块
      5. 执行构造器
    
    • 数组初始化 类型相同,统一标识访问,序列

      • 定义

        int [] arr;
        int arr[];
        
      • 初始化

        int[] arr = {1,2,3,4};
        
      • 标识符拿到的是数组的引用,每次访问数组,java都要做边界检查

      • 数组初始化时,会给变量 赋予。对于数值,空值就是零;对于 char,它是null;而对于boolean,它却是 false

      • 利用数组 - 不定参数列表

        public class VarArgs {
            static void f(Object[] x) {
                for (int i = 0; i < x.length; i++)
                    System.out.println(x[i]);
            }
            
            //JDK5 加入可变参数列表
             static void ff(int count, Object... args) {
                for (Object arg : args) {
                    System.out.println(arg);
                }
            }
            
            static void ff(int abc, Object... args) {
                for (Object arg : args) {
                    System.out.println(arg);
                }
            }
        
            public static void main(String[] args) {
                f(new Object[]{
                        new Integer(47), new VarArgs(),
                        new Float(3.14), new Double(11.11)});
                f(new Object[]{"one", "two", "three"});
                f(new Object[]{new AA(), new AA(), new AA()});
                
                //调用方式
                ff(new Object[]{new AA(), new AA(), new AA()});
                ff(new AA(), new AA(), new AA());
                ff();
                ff(10);
            }
        }
        
        class AA {
            int i;
        }
        
      • 数组的getClass() 可以看出 可变参数列表实际使用的是基本类型 不是包装类

             	
             	int[] arr = new int[10];
                char[] arr1 = new char[10];
                byte[] arr2 = new byte[10];
                boolean[] arr3 = new boolean[10];
                String[] arr4 = new String[10];
                short[] arr5 = new short[10];
                Short[] arr6 = new Short[10];
                Boolean[] arr7 = new Boolean[10];
        
                System.out.println(arr.getClass());
                System.out.println(arr1.getClass());
                System.out.println(arr2.getClass());
                System.out.println(arr3.getClass());
                System.out.println(arr4.getClass());
                System.out.println(arr5.getClass());
                System.out.println(arr6.getClass());
                System.out.println(arr7.getClass());
        		Integer[] arr8 = {new Integer(10), 10};
                
                //Output
                class [I
                class [C
                class [B
                class [Z
                class [Ljava.lang.String;
                class [S
                class [Ljava.lang.Short;
                class [Ljava.lang.Boolean;
                class java.lang.Integer
        		class java.lang.Integer
        
  • Enum关键字 Java1.5 可以在switch语句中使用

    • 语法

      enum Spiciness {
          NOT, MILD, MEDIUM, HOT, FLAMING;
      
          public static void main(String[] args) {
              System.out.println(Spiciness.FLAMING);
              System.out.println(Spiciness.FLAMING.getClass());
              System.out.println(Spiciness.valueOf("MEDIUM"));
              System.out.println(Spiciness.FLAMING.ordinal());
          }
      }
      
          //Output
          FLAMING
          class Spiciness
          MEDIUM
      	4
      
    • 由上可以看出,创建类时,编译器提供了toString()方法。还有ordinal()方法,static values()方法

    • 看似新数据类型,生产这个类时,会发生一些编译器的行为。事实上,enum确实是类

posted @ 2018-10-10 18:08  拷贝程序员_厚厚北  阅读(126)  评论(0编辑  收藏  举报