Thinking In Java 第四版读书笔记

【本文对许久前转载的部分过时博文进行了替换,所以发表时间可以不参考】

        先说明一下,本篇笔记是以JAVA编程思想第四版为基础,之前看到网上很多的所谓第四版书籍、笔记、源码,其实看下来基本都是第三版的。JAVA编程思想针对JAVA编程的最基础指导在广度方面有一定的参考意义,但要深度的学习还需移情别恋。因为书籍本身很厚,加上个人对书中的一些知识已早有积累,因此也不会一一笔录,只对一些关键知识点进行记录,以下为主要描述:
NO.1、对象导论
OO中一起都为对象:对象有类型、状态、行为和标识,对象可组合为更高级的对象,所有的对象是唯一的。
每个对象都有接口:对象与对象间是通过接口交互的,因此……
每个对象都提供服务:意思是将对象看做是服务提供者,提高内聚、简化设计
被隐藏的具体实现:如此可访问保护、内部工作不影响外部调用

复用具体实现:
组合:使用现有类组合新类,更灵活,通常视为has-a关系,比如汽车拥有引擎
聚合:动态发生的组合

继承:
Is-a :A就是B
Is-like-a:A像是一个B,有扩展

伴随多态的可互换对象:只可由子类向上安全转型,除非是Object拆箱,否则不安全
单根继承结构:一切类继承Object,具备一些相同方法
容器:就是集合,通过泛型可定制一个记录对象的集合,方便向下转型。
对象的创建和生命期:动态分配内存和自动垃圾回收(无用的对象)
异常处理:处理错误,相对独立,不是OO的特征,很早就出现
并发编程:同步进行、共享资源、释放资源、相互协作
NO.2、一切都是对象
一切都是对象,对象通过引用操作
堆栈存储对象引用
堆存储JAVA对象
基本类型:值类型、引用类型,基本都有包装器
高精度:BigInteger(任意精度的整数)、BigDecimal(任意精度的定点数)

永远不需要销毁对象:
值类型作用域:离开时会自动清理
引用类作用域:离开时,new产生的对象继续占用空间,但会被垃圾回收监视和处理

创建新的数据类型:类
对象用类来表示:字段(值类型、引用类型对象)、方法
诸如:Integer、Boolean等首字母大写的也为包装类。

构建一个JAVA程序:Static关键字分配了单一的共享存储空间,可独立访问
注释和嵌入式文档:通过JAVADOC可方便的导出已注释的HTML API文档,具体关键字和使用方法,可参阅相关资料
编码风格:通常类名首字母大写、其他所有内容首字母小写
NO.3、操作符
JAVA操作符:+、-、*、/、%、=、==、!=、+=、-=、*=、/=、%=、&&、||、!

赋值:值赋值、引用赋值(指向同一个地址的引用对象值会同步变化)

自动递增和递减:

++a、--a、a++、a—个人感觉可读性不好
a++、a—运算符在后,则先生成表达式值后执行计算,++a、--a运算符在前,则先执行运算再生成表达式值

public class AutoInc {
  public static void main(String[] args) {
    int i = 1;
    print("i : " + i);
    print("++i : " + ++i); // Pre-increment
    print("i++ : " + i++); // Post-increment
    print("i : " + i);
    print("--i : " + --i); // Pre-decrement
    print("i-- : " + i--); // Post-decrement
    print("i : " + i);
  }
} /* Output:
i : 1
++i : 2
i++ : 2
i : 3
--i : 2
i-- : 2
i : 1
*///:~


关系运算符:>、<、>=、<=、!=、==
逻辑操作符:&&、||、!
值类型:通过==、!=判断
引用类型:通过equal判断,equal即比较引用地址又比较内容

直接常量:

 

public class Literals {
  public static void main(String[] args) {
    int i1 = 0x2f; // Hexadecimal (lowercase)
    print("i1: " + Integer.toBinaryString(i1));
    int i2 = 0X2F; // Hexadecimal (uppercase)
    print("i2: " + Integer.toBinaryString(i2));
    int i3 = 0177; // Octal (leading zero)
    print("i3: " + Integer.toBinaryString(i3));
    char c = 0xffff; // max char hex value
    print("c: " + Integer.toBinaryString(c));
    byte b = 0x7f; // max byte hex value
    print("b: " + Integer.toBinaryString(b));
    short s = 0x7fff; // max short hex value
    print("s: " + Integer.toBinaryString(s));
    long n1 = 200L; // long suffix
    long n2 = 200l; // long suffix (but can be confusing)
    long n3 = 200;
    float f1 = 1;
    float f2 = 1F; // float suffix
    float f3 = 1f; // float suffix
    double d1 = 1d; // double suffix
    double d2 = 1D; // double suffix
    // (Hex and Octal also work with long)
  }
} /* Output:
i1: 101111
i2: 101111
i3: 1111111
c: 1111111111111111
b: 1111111
s: 111111111111111
*///:~


按位操作符:&、|、^、~、&=、|=、^=
移位操作符:>>、<<、>>>、>>=、<<=、>>>=
三元操作符:return i < 10 ? i * 100 : i * 10;

字符串操作符:+、+=,自动进行字符串转义操作
使用操作符时常犯的错误:注意优先级

类型转换操作符:
值类型、引用类型转换、四舍五入
Char、byte、short不必进行int转换,这些类型都已属于int类型
NO.4、控制执行流程
        ……
NO.5、初始化与清理
初始化:默认构造、有参构造、构造重载
方法重载:参数、类型、顺序、返回值
构造器:构造器中调用构造器,必须将构造器调用放到第一行,构造器中尽量避免调用其他方法,保证安全实例化
初始化时机:定义时、延迟初始化(构造、方法等使用前)
实例化对象并调用方法时初始化顺序:
(1)普通类:静态成员、普通成员、构造器(重载)、方法
      (多次实例时static只执行一次)
(2)继承
        基类静态
       基类普通成员
       基类构造器(重载时按顺序初始化)(编译器自动调用基类构造)
       子类静态
       子类普通成员
       子类构造器(重载)
       子类或基类方法
       继承初始化示例:

 

class Insect {
  private int i = 9;
  protected int j;
  Insect() {
    print("i = " + i + ", j = " + j);
    j = 39;
  }
  private static int x1 =
    printInit("static Insect.x1 initialized");
  static int printInit(String s) {
    print(s);
    return 47;
  }
}

public class Beetle extends Insect {
  private int k = printInit("Beetle.k initialized");
  public Beetle() {
    print("k = " + k);
    print("j = " + j);
  }
  private static int x2 =
    printInit("static Beetle.x2 initialized");
  public static void main(String[] args) {
    print("Beetle constructor");
    Beetle b = new Beetle();
  }
} /* Output:
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
i = 9, j = 0
Beetle.k initialized
k = 47
j = 39
*///:~


清理:垃圾回收器只回收无法到达的无用对象(new分配的内存),但不知道回收非new方式的特殊内存。所以通过调用finalize()手动回收,但finalize不能保证立即回收,需等到下一次垃圾回收动作时才执行回收(finalize的不及时性最好不直接调用,它无法替代析构函数),因此必须手动清理。
显式地清理:

 

CADSystem x = new CADSystem(47);
try {
  // Code and exception handling...
} finally {
  x.dispose(); //通常清理时注意依赖的顺序, 最后进行基类的清理
}


finalize使用范例:

 

class Book {
  boolean checkedOut = false;
  Book(boolean checkOut) {
    checkedOut = checkOut;
  }
  void checkIn() {
    checkedOut = false;
  }
  protected void finalize() {
    if(checkedOut)
      System.out.println("Error: checked out");
    // Normally, you'll also do this:
    // super.finalize(); // Call the base-class version
  }
}

public class TerminationCondition {
  public static void main(String[] args) {
    Book novel = new Book(true);
    // Proper cleanup:
    novel.checkIn();
    // Drop the reference, forget to clean up:
    new Book(true);
    // Force garbage collection & finalization:
    System.gc();
  }
} /* Output:
Error: checked out
*///:~


回收器如何工作:对象存储空间的分配,堆指针移动到未分配区域即可,工作时一面回收空间,一面使堆中的对象紧凑排列,高速、有无限空间可分配。每个对象都有一个引用计数器,有引用时+1,离开引用时-1,垃圾回收器遍历所有对象列表,引用计数为0 时释放空间,循环引用的处理比较麻烦。
    另一种:根据目前的存活对象深度查找关联引用对象,不活动的则会释放。停止—复制方式,先把存活对象从当前堆复制到另一个堆,没有被复制的都是垃圾,复制后的对象也是紧密排列的,比较好。此种模式效率较低。此外,一但程序进入稳定状态后,极少会产生垃圾,此时复制就是浪费。
    一些虚拟机会转换到标记—横扫模式,速度慢,但是当你知道有很少垃圾时,它就很快了。遍历存活对象,给对象标记不会被回收,全部标记完成才会清理。

成员初始化:局部变量需初始化,注意初始化顺序,以下是可以的:

 

public class MethodInit2 {
//! int j = g(i); // Illegal forward reference
  int i = f();
  int j = g(i);
  int f() { return 11; }
  int g(int n) { return n * 10; }
}

(1)普通变量初始化:类内部变量定义的顺序决定了初始化顺序,即使是散列分布,依旧在方法调用前顺序初始化:

 

class Window {
  Window(int marker) { print("Window(" + marker + ")"); }
}

class House {
  Window w1 = new Window(1); // Before constructor
  House() {
    // Show that we're in the constructor:
    print("House()");
    w3 = new Window(33); // Reinitialize w3
  }
  Window w2 = new Window(2); // After constructor
  void f() { print("f()"); }
  Window w3 = new Window(3); // At end
}

public class OrderOfInitialization {
  public static void main(String[] args) {
    House h = new House();
    h.f(); // Shows that construction is done
  }
} /* Output:
Window(1)
Window(2)
Window(3)
House()
Window(33)
f()
*///:~

(2)静态变量初始化:静态优先执行、而后非静态、构造,再次实例化时静态不会再初始化。

 

class Bowl {
  Bowl(int marker) {
    print("Bowl(" + marker + ")");
  }
  void f1(int marker) {
    print("f1(" + marker + ")");
  }
}

class Table {
  static Bowl bowl1 = new Bowl(1);
  Table() {
    print("Table()");
    bowl2.f1(1);
  }
  void f2(int marker) {
    print("f2(" + marker + ")");
  }
  static Bowl bowl2 = new Bowl(2);
}

class Cupboard {
  Bowl bowl3 = new Bowl(3);
  static Bowl bowl4 = new Bowl(4);
  Cupboard() {
    print("Cupboard()");
    bowl4.f1(2);
  }
  void f3(int marker) {
    print("f3(" + marker + ")");
  }
  static Bowl bowl5 = new Bowl(5);
}

public class StaticInitialization {
  public static void main(String[] args) {
    print("Creating new Cupboard() in main");
    new Cupboard();
    print("Creating new Cupboard() in main");
    new Cupboard();
    table.f2(1);
    cupboard.f3(1);
  }
  static Table table = new Table();
  static Cupboard cupboard = new Cupboard();
} /* Output:
Bowl(1)
Bowl(2)
Table()
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
f2(1)
f3(1)
*///:~

(3)静态块初始化:看成是static变量,什么时候初始化执行,按顺序放置的顺序来。
(4)匿名内部类初始化:初始化实际和普通变量一样。

 

public class Mugs {
  Mug mug1;
  {
    mug1 = new Mug(1);
    print("mug1 initialized");
  }
}

数组初始化
int[] a1 = { 1, 2, 3, 4, 5 };
int[] a; a = new int[10]; 需要再次赋值
Integer[] a = {
  new Integer(1),
  new Integer(2),
  3, // Autoboxing
};
new String[]{ "fiddle", "de", "dum" }
数组的复制就是引用的复制
public class ArraysOfPrimitives {
  public static void main(String[] args) {
    int[] a1 = { 1, 2, 3, 4, 5 };
    int[] a2;
    a2 = a1;
    for(int i = 0; i < a2.length; i++)
      a2[i] = a2[i] + 1;
    for(int i = 0; i < a1.length; i++)
      print("a1[" + i + "] = " + a1[i]);
  }
} /* Output:
a1[0] = 2
a1[1] = 3
a1[2] = 4
a1[3] = 5
a1[4] = 6
*///:~


可变参数数组:Object…objs,可传参可不传参数
Arrays.toString() 产生一维数组的打印版本
Arrays.deepToString可将二维、多维基本类型或对象数组转化为多个String输出

枚举类型
本质也是类,尽量不要通过ordinal方法来获取顺序。

 

public enum Spiciness {
  NOT, MILD, MEDIUM, HOT, FLAMING
}
for(Spiciness s : Spiciness.values())

NO.6、访问权限控制
public、protected(继承和包内权限)、默认包权限(无关键词修饰)、private
权限控制:信息隐藏、接口和实现分离
静态import,其实已经不常用了
包内访问:类、方法都没有修饰

 

class Cake {
  public static void main(String[] args) {
    Pie x = new Pie();
    x.f();
  }
}
class Pie {
  void f() { System.out.println("Pie.f()"); }
}

NO.7、复用类
主要为组合对象、继承、代理
组合:在新类中签入(引入)某些对象,实现其特定的功能,从而提供新类的外部接口。

 

//执行顺序:变量初始化、构造、toString
class Soap {
  private String s;
  Soap() {
    print("Soap()");
    s = "Constructed";
  }
  public String toString() { return s; } //system.out.print(soap)时默认调用的toString方法
}    

public class Bath {
  private String // Initializing at point of definition:
    s1 = "Happy",
    s2 = "Happy",
    s3, s4;
  private Soap castille;
  private int i;
  private float toy;
  public Bath() {
    print("Inside Bath()");
    s3 = "Joy";
    toy = 3.14f;
    castille = new Soap();
  }    
  // Instance initialization:
  { i = 47; }
  public String toString() {
    if(s4 == null) // Delayed initialization:
      s4 = "Joy";
    return
      "s1 = " + s1 + "\n" +
      "s2 = " + s2 + "\n" +
      "s3 = " + s3 + "\n" +
      "s4 = " + s4 + "\n" +
      "i = " + i + "\n" +
      "toy = " + toy + "\n" +
      "castille = " + castille;
  }    
  public static void main(String[] args) {
    Bath b = new Bath();
    System.out.println (b); // 由编译器默认调用Bath的toString方法
  }
} /* Output:
Inside Bath()
Soap()
s1 = Happy
s2 = Happy
s3 = Joy
s4 = Joy
i = 47
toy = 3.14
castille = Constructed
*///:~

继承:private类型无法被覆盖重写
代理:在两个类之间增加对象或行为适配,由适配器来完成,就不需要继承了
同时组合和继承:
(1)简单应用
(2)应用中对象的正确清理:try-catch-finally,注意清理顺序
(3)名称屏蔽:继承时基类的方法不会被屏蔽,除非被覆盖override,当然子类也可有同名的重载方法。
向上转型:是安全的,向下转型需要强制转型,所以不一定安全
final:
(1)数据
        值类型:编译时常量,初始化时已赋值
       引用类型:引用恒定不变,一旦引用初始化指向某个对象就无法指向另一个对象,但是对象自身是可以修改的。
       Static final:占据一段不能改变的存储空间,值不可变、对象引用地址不可变(两次创建相同类的实例也不会改变)。
       效率:带来的效率意义不大
(2)方法:主要是锁定方法,不被重写(private类的方法除外)。
(3)类:使类无法被继承,无法做任何的变动。同时类中的方法都被隐士的指定为final,因此也无法覆盖。
NO.8、多态
除static、final外,其他的方法都是后期编译器自动绑定的。
1、只有普通的方法调用可以是多态的

 

class Super {
  public int field = 0;
  public int getField() { return field; }
}

class Sub extends Super {
//与基类不同的存储空间,如果重名使用时必须显式的调用this.field、super.field
  public int field = 1;
  public int getField() { return field; }
  public int getSuperField() { return super.field; }
}

public class FieldAccess {
  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());
  }
} /* Output:
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()
*///:~

NO.9、接口
接口中的方法、域、内嵌接口等默认都是public的
放入接口中的域都会自动变成static、final的
可向上转型为多个接口类型
NO.10、内部类
可独立完成一些事务,有利于模块化组织对象,更灵活多态的编程。
事件驱动类、应用框架程序经常用内部类来进行事务控制,如不同的action(当然我们可以都做成外部类,但是那样会造成类爆炸,也不好集中管理,更重要的是对外部信息隐蔽,是外部不必关系实现细节。)。
内部类也有利于事务处理的细粒度化(小单元做不同的事情)。
1、生成外围类、成员对象的引用:外围类.成员、外围类.this

 

public class DotThis {
  void f() { System.out.println("DotThis.f()"); }
  public class Inner {
    public DotThis outer() {
      return DotThis.this;
      // A plain "this" would be Inner's "this"
    }
  }
}
public class DotNew {
  public class Inner {}
  public static void main(String[] args) {
    DotNew dn = new DotNew();
    DotNew.Inner dni = dn.new Inner();
  }
}

2、如果是静态内部类(称为嵌套类),就不需要内部类与外围类之间有关系
静态类可直接应用,无法new也不需要new
静态类无法访问非静态的外围类对象
普通内部类的字段与方法只能放在类的外部层次上,不能有static类字段和数据,但嵌套类可以
3、接口内部类
Static final的,同样可继承其他接口
4、匿名类

 

Contents content = new Contents() {……};
return new Contents() { // Insert a class definition
  private int i = 11;
  public int value() { return i; }
};
return new Contents(x) { // Insert a class definition
  private int i = 11;
  public int value() { return i; }
};
//同时初始化
  public Destination destination(final String dest) {
    return new Destination() {
      private String label = dest;
      public String readLabel() { return label; }
    };
  }
//匿名构造器
  public static Base getBase(int i) {
    return new Base(i) {
      { print("Inside instance initializer"); } //实例初始化
      public void f() {
        print("In anonymous f()");
      }
    };
  }

5、闭包、回调
闭包:可调用的对象,记录了一些信息,这些信息来自于创建它的作用域,内部类就是面向对象的闭包,因为它包含外围类对象及引用,此作用域内有权操作所有成员,包括private。
6、内部类继承
不常用,使用场景不多

 

class WithInner {
  class Inner {}
}

public class InheritInner extends WithInner.Inner {
  //! InheritInner() {} // Won't compile
  InheritInner(WithInner wi) {
    wi.super();
  }
  public static void main(String[] args) {
    WithInner wi = new WithInner();
    InheritInner ii = new InheritInner(wi);
  }
}

7、内部类覆盖
当继承了某个外围类时,这两个内部类时完全独立的两个实体。这时采用基类来实例化,然后调用内部类的方法,还会是基类的方法。
8、局部内部类
不能有访问修饰符,因为不是外围类的一部分,可以访问当前代码块的常量及外围类的所有成员。
和匿名内部类的区别:局部有已命名的构造器可重载,而匿名只能用于实例初始化。
NO.11、持有对象(容器、集合)
1、集合基本操作

 

public class AddingGroups {
  public static void main(String[] args) {
    Collection<Integer> collection =
      new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4, 5));
    Integer[] moreInts = { 6, 7, 8, 9, 10 };
    collection.addAll(Arrays.asList(moreInts));
    // Runs significantly faster, but you can't
    // construct a Collection this way:
    Collections.addAll(collection, 11, 12, 13, 14, 15);
    Collections.addAll(collection, moreInts);
    // Produces a list "backed by" an array:
    List<Integer> list = Arrays.asList(16, 17, 18, 19, 20);
    list.set(1, 99); // OK -- modify an element
    // list.add(21); // Runtime error because the
                     // underlying array cannot be resized.
  }
} ///:~

class Snow {}
class Powder extends Snow {}
class Light extends Powder {}
class Heavy extends Powder {}
class Crusty extends Snow {}
class Slush extends Snow {}

    // Won't compile:
    // List<Snow> snow2 = Arrays.asList(new Light(), new Heavy());
    // Collections.addAll() doesn't get confused:
    List<Snow> snow3 = new ArrayList<Snow>();
    Collections.addAll(snow3, new Light(), new Heavy());
    // Give a hint using an explicit type argument specification:
    List<Snow> snow4 = Arrays.<Snow>asList(new Light(), new Heavy());
  }
} ///:~

2、容器打印

 

public class PrintingContainers {
  static Collection fill(Collection<String> collection) {
    collection.add("rat");
    collection.add("cat");
    collection.add("dog");
    collection.add("dog");
    return collection;
  }
  static Map fill(Map<String,String> map) {
    map.put("rat", "Fuzzy");
    map.put("cat", "Rags");
    map.put("dog", "Bosco");
    map.put("dog", "Spot");
    return map;
  }    
  public static void main(String[] args) {
    print(fill(new ArrayList<String>()));//按插入顺序
    print(fill(new LinkedList<String>()));
    print(fill(new HashSet<String>()));//set不重复
    print(fill(new TreeSet<String>()));//升序集合
    print(fill(new LinkedHashSet<String>()));
    print(fill(new HashMap<String,String>()));
    print(fill(new TreeMap<String,String>()));
    print(fill(new LinkedHashMap<String,String>()));
  }
} /* Output:
[rat, cat, dog, dog]
[rat, cat, dog, dog]
[dog, cat, rat]
[cat, dog, rat]
[rat, cat, dog]
{dog=Spot, cat=Rags, rat=Fuzzy}
{cat=Rags, dog=Spot, rat=Fuzzy}
{rat=Fuzzy, cat=Rags, dog=Spot}
*///:~

3、Collection

 

    int size();
    boolean isEmpty();
    boolean contains(Object o);
    Object[] toArray();
    <T> T[] toArray(T[] a);
    boolean add(E e);
    boolean remove(Object o);
    boolean containsAll(Collection<?> c);
    boolean addAll(Collection<? extends E> c);
    boolean removeAll(Collection<?> c);
    default boolean removeIf(Predicate<? super E> filter)
        boolean removed = false;
    boolean retainAll(Collection<?> c); //取得两个List的交集
    void clear();
    boolean equals(Object o);
    int hashCode();
    void forEach(Consumer<? super T> action)

4、List
List可在二次包装为其他各类集合,被包装后拥有其他集合的特性和顺序:

 

 ArrayList<Pet> pets = Pets.arrayList(8);
    LinkedList<Pet> petsLL = new LinkedList<Pet>(pets);
    HashSet<Pet> petsHS = new HashSet<Pet>(pets);
    TreeSet<Pet> petsTS = new TreeSet<Pet>(pets);

除拥有上述方法外,派送了:

 

 

 

boolean addAll(int index, Collection<? extends E> c);
    default void replaceAll(UnaryOperator<E> operator)
default void sort(Comparator<? super E> c)
E get(int index);
    E set(int index, E element);
    void add(int index, E element);
    E remove(int index);
    int indexOf(Object o);
    int lastIndexOf(Object o);
    List<E> subList(int fromIndex, int toIndex);

5、Collections

 

针对集合子类的一些列操作,常用的有:
add、addAll、clear、contains、containsAll、isEmpty、remove、replaceAll、toArray
max、min、reverseOrder
fill、sort、swap、copy、rotate、indexOf、、SingletonList、、
retainAll获取交集
shuffle 打乱顺序,重新随机排序

syncchronized:
syncchronizedCollection
synchronizedList
synchronizedMap
synchronizedSet
synchronizedSortedMap
synchronizedSortedSet

checked:
checkedCollection
checkedList
checkedSet
checkedMap
checkedSortedMap
checkedSortedSet

6、迭代器
(1)针对Collection、Map类元素进行通用遍历处理:next、hasNext、remove。

 

   //应用示例
    List<Pet> pets = Pets.arrayList(12);
    Iterator<Pet> it = pets.iterator(); //所有容器子类都有该方法
    while(it.hasNext()) {
      Pet p = it.next();
    }
    it = pets.iterator();
    for(int i = 0; i < 6; i++) {
      it.next();
      it.remove();
    }

(2)ListIterator是更强大的Iterator的子类型,可双向移动。

 

public class ListIteration {
  public static void main(String[] args) {
    List<Pet> pets = Pets.arrayList(8);
    ListIterator<Pet> it = pets.listIterator();
    while(it.hasNext())
      System.out.print(it.next() + ", " + it.nextIndex() +
        ", " + it.previousIndex() + "; ");
    System.out.println();
    // Backwards:
    while(it.hasPrevious())
      System.out.print(it.previous().id() + " ");
    System.out.println();
    System.out.println(pets);    
    it = pets.listIterator(3);
    while(it.hasNext()) {
      it.next();
      it.set(Pets.randomPet());
    }
    System.out.println(pets);
  }
} /* Output:
Rat, 1, 0; Manx, 2, 1; Cymric, 3, 2; Mutt, 4, 3; ……
7 6 5 4 3 2 1 0
[Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug, Manx]
[Rat, Manx, Cymric, Cymric, Rat, EgyptianMau, Hamster, EgyptianMau]
*///:~

7、LinkedList
CRUD较快,随机访问交慢,常用于栈、队列或双向队列(包含数据和前后的引用)。
具有实现栈的所有功能方法。

E getFirst() {
 E getLast() {
 E removeFirst() {
 E removeLast() {
 void addFirst(E e) {
 void addLast(E e) {
 boolean contains(Object o) {
 int size() {
 boolean add(E e) {
 boolean remove(Object o) {
 boolean addAll(Collection<? extends E> c) {
 boolean addAll(int index, Collection<? extends E> c) {
 void clear() {
 E get(int index) {
 E set(int index, E element) {
 void add(int index, E element) {
 E remove(int index) {
 int indexOf(Object o) {
 int lastIndexOf(Object o) {
 E peek() {
 E element() {
 E poll() {
 E remove() {
 boolean offer(E e) {
 boolean offerFirst(E e) {
 boolean offerLast(E e) {
 E peekFirst() {
 E peekLast() {
 E pollFirst() {
 E pollLast() {
 void push(E e) {
 E pop() {
 boolean hasNext() {
 E next() {
 boolean hasPrevious() {
 E previous() {
 int nextIndex() {
 int previousIndex() {
 void remove() {
 void set(E e) {
 void add(E e) {
 boolean hasNext() {
 E next() {
 void remove() {
 Object clone() {
 Object[] toArray() {
 <T> T[] toArray(T[] a)

8、Stack
和队列相反,出栈顺序是:先进后出LIFO
Push、Pop、……、Peek(返回栈顶对象,并不将其从栈顶移除)

public class StackTest {
  public static void main(String[] args) {
    Stack<String> stack = new Stack<String>();
    for(String s : "My dog has fleas".split(" "))
      stack.push(s);
    while(!stack.empty())
      System.out.print(stack.pop() + " ");
  }
} /* Output:
fleas has dog My
*///:~

9、Set
无序不重复,如果想对结果排序,可用TreeSet代替HashSet(采用散列排序,比较复杂)。
通常需要为Set的key对象覆盖equals、hashCode散列,通过散列码方便查找和排序,散列的价值在于速度。同一个对象的hashCode是相同值。散列码不必是独一无二的,但结合equals则是唯一的。

Random rand = new Random(47);
SortedSet<Integer> intset = new TreeSet<Integer>();
// SortedSet<Integer> intset = new
// TreeSet<Integer>(String.CASE_INSENSITIVE_ORDER); 忽略大小写
// Set<String> set1 = new HashSet<String>();
    for(int i = 0; i < 10000; i++)
      intset.add(rand.nextInt(30));
System.out.println(intset); //升序输出

SortedSet:First、last、subSet、headSet、tailSet
10、Map
映射,善于检查Random的随机性:keySet(一系列key)、values

Map<String,Pet> petMap = new HashMap<String,Pet>();
Map<Person, List<? extends Pet>> petPeople = new HashMap<Person, List<? extends Pet>>();

SortedMap:    subMap、headMap、tailMap
new LinkedHashMap<Integer, String>(16, 0.75f, true); //采用LRU算法,没有访问的元素出现在队列前面
11、Queue
(1)基础概念
       两个实现:LinkedList、PriorityQueue,差异在于排序而不是性能,其他的子类型不常用。
       先进先出,与栈相反。同样的,LinkedList也提供了队列的功能支持。避免使用add、remove,这两者失败时会抛出异常,而要采用offer、poll等队列特性方法。
       add:加入
       remove、poll:移除并返回队头
       peek、element:不移除并返回队头
       offer:插入队尾

  //范例
  public static void main(String[] args) {
    Queue<Integer> queue = new LinkedList<Integer>();
    Random rand = new Random(47);
    for(int i = 0; i < 10; i++)
      queue.offer(rand.nextInt(i + 10));
    printQ(queue);
    Queue<Character> qc = new LinkedList<Character>();
    for(char c : "Brontosaurus".toCharArray())
      qc.offer(c);
    printQ(qc);
  }
  public static void printQ(Queue queue) {
    while(queue.peek() != null)
      System.out.print(queue.remove() + " ");
    System.out.println();
  }
/* Output:
8 1 1 1 5 14 3 1 0 1
B r o n t o s a u r u s
*///:~

(2)优先级队列PriorityQueue
       声明下一个弹出元素是最需要的元素,对象入队、出队删除时都将是优先级最高的元素,offer插入一个对象时默认按自然顺序来排序(如int、string等按升序排列)。
       如果要对自己的对象进行优先级队列管理,必须包括产生自然排序功能或提供自己的Comparator,compareTo处理优先级并返回int值。

public static void main(String[] args) {
    PriorityQueue<Integer> priorityQueue =
      new PriorityQueue<Integer>();
    Random rand = new Random(47);
    for(int i = 0; i < 10; i++)
      priorityQueue.offer(rand.nextInt(i + 10));
    QueueDemo.printQ(priorityQueue);

    List<Integer> ints = Arrays.asList(25, 22, 20,
      18, 14, 9, 3, 1, 1, 2, 3, 9, 14, 18, 21, 23, 25);
    priorityQueue = new PriorityQueue<Integer>(ints);
    QueueDemo.printQ(priorityQueue);
    priorityQueue = new PriorityQueue<Integer>(
        ints.size(), Collections.reverseOrder());
    priorityQueue.addAll(ints);
    QueueDemo.printQ(priorityQueue);

    String fact = "EDUCATION SHOULD ESCHEW OBFUSCATION";
    List<String> strings = Arrays.asList(fact.split(""));
    PriorityQueue<String> stringPQ =
      new PriorityQueue<String>(strings);
    QueueDemo.printQ(stringPQ);
    stringPQ = new PriorityQueue<String>(
      strings.size(), Collections.reverseOrder());
    stringPQ.addAll(strings);
    QueueDemo.printQ(stringPQ);

    Set<Character> charSet = new HashSet<Character>();
    for(char c : fact.toCharArray())
      charSet.add(c); // Autoboxing
    PriorityQueue<Character> characterPQ =
      new PriorityQueue<Character>(charSet);
    QueueDemo.printQ(characterPQ);
  }
/* Output:
0 1 1 1 1 1 3 5 8 14
1 1 2 3 3 9 9 14 14 18 18 20 21 22 23 25 25
25 25 23 22 21 20 18 18 14 14 9 9 3 3 2 1 1
       A A B C C C D D E E E F H H I I L N N O O O O S S S T T U U U W
W U U U T T S S S O O O O N N L I I H H F E E E D D C C C B A A
  A B C D E F H I L N O S T U W
*///:~

(3)双向队列(自定义实现)不常用

 

public class Deque<T> {
  private LinkedList<T> deque = new LinkedList<T>();
  public void addFirst(T e) { deque.addFirst(e); }
  public void addLast(T e) { deque.addLast(e); }
  public T getFirst() { return deque.getFirst(); }
  public T getLast() { return deque.getLast(); }
  public T removeFirst() { return deque.removeFirst(); }
  public T removeLast() { return deque.removeLast(); }
  public int size() { return deque.size(); }
  public String toString() { return deque.toString(); }
  // And other methods as necessary...
}

12、Collection与迭代器

 

       Collection子类默认都有forEach、迭代器支持。List.iterator()、map.values.iterator()
       自定义集合类,往往比较麻烦,需要重写iterator(),如:
       class CollectionSequence extends AbstractCollection<Pet>
13、Foreach与迭代器
       对于List、ArrayList的操作,适当时候可以继承并扩展以适配特定的实现需求,也可进行适配包装。
14、其他
(1)Arrays
        针对数组的一系列操作封装,如:初始化、搜索。
       Arrays.asList();
(2)尽量避免使用过时的Vector、Hashtable、Stack
15、打印Collection、Map差异

public class ContainerMethodDifferences {
  static Set<String> methodSet(Class<?> type) {
    Set<String> result = new TreeSet<String>();
    for(Method m : type.getMethods())
      result.add(m.getName());
    return result;
  }
  static void interfaces(Class<?> type) {
    System.out.print("Interfaces in " +
      type.getSimpleName() + ": ");
    List<String> result = new ArrayList<String>();
    for(Class<?> c : type.getInterfaces())
      result.add(c.getSimpleName());
    System.out.println(result);
  }
  static Set<String> object = methodSet(Object.class);
  static { object.add("clone"); }
  static void
  difference(Class<?> superset, Class<?> subset) {
    System.out.print(superset.getSimpleName() +
      " extends " + subset.getSimpleName() + ", adds: ");
    Set<String> comp = Sets.difference(
      methodSet(superset), methodSet(subset));
    comp.removeAll(object); // Don't show 'Object' methods
    System.out.println(comp);
    interfaces(superset);
  }
  public static void main(String[] args) {
    System.out.println("Collection: " +
      methodSet(Collection.class));
    interfaces(Collection.class);
    difference(Set.class, Collection.class);
    difference(HashSet.class, Set.class);
    difference(LinkedHashSet.class, HashSet.class);
    difference(TreeSet.class, Set.class);
    difference(List.class, Collection.class);
    difference(ArrayList.class, List.class);
    difference(LinkedList.class, List.class);
    difference(Queue.class, Collection.class);
    difference(PriorityQueue.class, Queue.class);
    System.out.println("Map: " + methodSet(Map.class));
    difference(HashMap.class, Map.class);
    difference(LinkedHashMap.class, HashMap.class);
    difference(SortedMap.class, Map.class);
    difference(TreeMap.class, Map.class);
  }
}

NO.12、通过异常处理错误
你懂的,不用多说。
异常捕获、参数、说明。
栈轨迹:先入栈的为就近发生的异常信息
异常的转换,如将受检异常转换为运行时异常。
方法throws的使用形式。
NO.13、字符串
String为不可变引用对象,对String的修改都是在新对象中进行(如return new String(data, true)、Long.toString(l)),最初的String对象不会变化。
当String作为参数时,都会复制一份引用(局部引用),该引用所指的对象一直都在一个物理位置上为变动,一旦方法运行结束,拷贝引用部分就消失了,而返回的对象则是另一个新的引用。
(1)格式化:

 

new Formatter(System.out).format("%s The Turtle is at (%d,%d)\n", name, x, y);
MessageFormat……
String.format

(2)支持正则表达式
matches、split、replace都支持正则,也可以自定义Pattern来匹配、查找、替换。
(3)扫描输入,简化控制台获取

 

Scanner stdin = new Scanner(SimpleRead.input);
System.out.println("What is your name?");
String name = stdin.nextLine();
System.out.println(name);
System.out.println("(input: <age> <double>)");
int age = stdin.nextInt();

// Scanner定界符
public class ScannerDelimiter {
  public static void main(String[] args) {
    Scanner scanner = new Scanner("12, 42, 78, 99, 42");
    scanner.useDelimiter("\\s*,\\s*");
    while(scanner.hasNextInt())
      System.out.println(scanner.nextInt());
  }
} /* Output:
12
42
78
99
42
*///:~

 

 

 

// StringTokenizer的使用
String input = "But I'm not dead yet! I feel happy!";
  StringTokenizer stoke = new StringTokenizer(input);
  while(stoke.hasMoreElements())
    System.out.print(stoke.nextToken() + " ");

(5)常用方法

 

boolean isEmpty()
 char charAt(int index)
 boolean equals(Object anObject)
 boolean contentEquals(StringBuffer sb)
 boolean equalsIgnoreCase(String anotherString)
 int compareTo(String anotherString)
 int compare(String s1, String s2)
 boolean startsWith(String prefix)
 boolean endsWith(String suffix)
 int indexOf(String str)
 int lastIndexOf(String str)
 String substring(int beginIndex)
 CharSequence subSequence(int beginIndex, int endIndex)
 String concat(String str)
 String replace(char oldChar, char newChar)
 boolean matches(String regex)
 boolean contains(CharSequence s)
 String replaceFirst(String regex, String replacement)
 String replaceAll(String regex, String replacement)
 String[] split(String regex)
 static String join
 String toLowerCase
 String toUpperCase
 String trim()
 String toString()
 char[] toCharArray()
 static String format(String format, Object... args) 

NO.14、类型信息
运行时识别对象的类型信息:RTTI、反射
RTTI:可查询某个shape引用所指向的对象的确切类型
1、Class对象
Class是所有定义为class类型的类对象共同的父属性

 

PatternTest.class.getClassLoader
Class c1 = PatternTest.class
c1.getClass
Class<?> c1; Class<T> c1 = T.class;
Class c;
c.getName
c.isInstance()
c.getSimpleName
c.getCanonicalName
c.getInterfaces
c.getDeclaringClass 获得其所属类
c.getGenericInterfaces 获得继承接口
c.getSuperClass
c.getClass().getEnumConstants 获得枚举常量
…
Class.forName(“”)返回某个类的引用
Class.newIntance:
Class[] types = { Latte.class, Mocha.class,  Cappuccino.class, Americano.class, Breve.class, };
types[1].newInstance();

2、类型转换
自动向上转型
(A)B 强制转型
A instanceof B
a.isInstance()
instanceof、isInstance比较的是类的类型,是这个类或是这个类的派生类吗。
a.getClass == 或a.getClass.equal比较的是类对象,也没有考虑继承(只比较了是不是这个确切的对象)。

3、反射
java.lang.reflect 处理运行时的类信息:Field、Method、Constructor
    invoke、getFields、getMethods、getConstructors、get、set,示例:

 

Class<?> c = Class.forName(args[0]);
    Method[] methods = c.getMethods();
Constructor[] ctors = c.getConstructors();
c.newInstance();//实例化

Object speaker = …;
Class<?> spkr = speaker.getClass();
try {
  Method speak = spkr.getMethod("speak");
  speak.invoke(speaker);
} catch(NoSuchMethodException e) {
  print(speaker + " cannot speak");
}

4、动态代理
引用原始对象,在此基础上提供额外的或不同的操作。和适配器主要的差别在于后者侧重于双方行为和结构的匹配。实际项目中用到的并不多,两则示例如下:

 

//简单动态代理
class DynamicProxyHandler implements InvocationHandler {
  private Object proxied;
  public DynamicProxyHandler(Object proxied) {
    this.proxied = proxied;
  }
  public Object
  invoke(Object proxy, Method method, Object[] args)  throws Throwable {
    System.out.println("**** proxy: " + proxy.getClass() +
      ", method: " + method + ", args: " + args);
    if(args != null)
      for(Object arg : args)
        System.out.println("  " + arg);
    return method.invoke(proxied, args);
  }
}    

class SimpleDynamicProxy {
  public static void consumer(Interface iface) {
    iface.doSomething();
    iface.somethingElse("bonobo");
  }
  public static void main(String[] args) {
    RealObject real = new RealObject();
    consumer(real);
    // Insert a proxy and call again:
    Interface proxy = (Interface)Proxy.newProxyInstance(
      Interface.class.getClassLoader(),
      new Class[]{ Interface.class },
      new DynamicProxyHandler(real));
    consumer(proxy);
  }
} /* Output: (95% match)    
doSomething
somethingElse bonobo
**** proxy: class $Proxy0, method: public abstract void Interface.doSomething(), args: null
doSomething
**** proxy: class $Proxy0, method: public abstract void Interface.somethingElse(java.lang.String), args: [Ljava.lang.Object;@42e816
  bonobo
somethingElse bonobo
*///:~

//泛型动态代理
class MixinProxy implements InvocationHandler {
  Map<String,Object> delegatesByMethod;
  public MixinProxy(TwoTuple<Object,Class<?>>... pairs) {
    delegatesByMethod = new HashMap<String,Object>();
    for(TwoTuple<Object,Class<?>> pair : pairs) {
      for(Method method : pair.second.getMethods()) {
        String methodName = method.getName();
        if (!delegatesByMethod.containsKey(methodName))
          delegatesByMethod.put(methodName, pair.first);
      }
    }
  }    
  public Object invoke(Object proxy, Method method,
    Object[] args) throws Throwable {
    String methodName = method.getName();
    Object delegate = delegatesByMethod.get(methodName);
    return method.invoke(delegate, args);
  }
  public static Object newInstance(TwoTuple... pairs) {
    Class[] interfaces = new Class[pairs.length];
    for(int i = 0; i < pairs.length; i++) {
      interfaces[i] = (Class)pairs[i].second;
    }
    ClassLoader cl =
      pairs[0].first.getClass().getClassLoader();
    return Proxy.newProxyInstance(
      cl, interfaces, new MixinProxy(pairs));
  }
}
public class DynamicProxyMixin {
  public static void main(String[] args) {
    Object mixin = MixinProxy.newInstance(
      tuple(new BasicImp(), Basic.class),
      tuple(new TimeStampedImp(), TimeStamped.class),
      tuple(new SerialNumberedImp(),SerialNumbered.class));
    Basic b = (Basic)mixin;
    TimeStamped t = (TimeStamped)mixin;
    SerialNumbered s = (SerialNumbered)mixin;
    b.set("Hello");
    System.out.println(b.get());
    System.out.println(t.getStamp());
    System.out.println(s.getSerialNumber());
  }
}
public class TwoTuple<A,B> {
  public final A first;
  public final B second;
  public TwoTuple(A a, B b) { first = a; second = b; }
}

//自定义接口类动态代理
class MethodSelector implements InvocationHandler {
  private Object proxied;
  public MethodSelector(Object proxied) {
    this.proxied = proxied;
  }
  public Object
  invoke(Object proxy, Method method, Object[] args)
  throws Throwable {
    if(method.getName().equals("interesting"))
      print("Proxy detected the interesting method");
    return method.invoke(proxied, args);
  }
}    

interface SomeMethods {
  void boring1();
  void boring2();
  void interesting(String arg);
  void boring3();
}

class Implementation implements SomeMethods {
  public void boring1() { print("boring1"); }
  public void boring2() { print("boring2"); }
  public void interesting(String arg) {
    print("interesting " + arg);
  }
  public void boring3() { print("boring3"); }
}    

class SelectingMethods {
  public static void main(String[] args) {
    SomeMethods proxy= (SomeMethods)Proxy.newProxyInstance(
      SomeMethods.class.getClassLoader(),
      new Class[]{ SomeMethods.class },
      new MethodSelector(new Implementation()));
    proxy.boring1();
    proxy.boring2();
    proxy.interesting("bonobo");
    proxy.boring3();
  }
} /* Output:
boring1
boring2
Proxy detected the interesting method
interesting bonobo
boring3
*///:~

5、空对象
Null可通过instanceof来判断,通常设计时也考虑自定义空对象来作为一种正常的类型。

 

 

 

  public static class NullPerson
  extends Person implements Null {
    private NullPerson() { super("None", "None", "None"); }
    public String toString() { return "NullPerson"; }
  }
  public static final Person NULL = new NullPerson();

NO.15、泛型(参数化类型)

 

泛型类、泛型接口、泛型方法、泛型变量、…
泛型方法:可独立于类而存在,如果可以尽可能使用泛型方法(如static类的方法)。

public <T> void f(T x) {
    System.out.println(x.getClass().getName());
}
public static <A,B> TwoTuple<A,B> tuple(A a, B b)

局限:类型参数T只可以采用类对象,如Integer可以,int则不可以。
边界:限制条件extends,多继承时,类在前接口在后:<T extends A & B>

 

public class HasF { public void f(){} }
class Manipulator2<T extends HasF> {
  private T obj;
  public Manipulator2(T x) { obj = x; }
  public void manipulate() { obj.f(); } //ok
}

通配符:常利用通配符向上转型,extends、super

 

         无界通配符<?>
         有界通配符<? Extends…>
         List等价与List<Object>
         Map<?,?> map; 此时编译器无法与原生Map分开
         Map<String,?> map;
    
Super下界都是安全的,如:

public class GenericWriting {
  static <T> void writeExact(List<T> list, T item) {
    list.add(item);
  }
  static <T> void writeWithWildcard(List<? super T> list, T item) {
    list.add(item);
  }
  static List<Apple> apples = new ArrayList<Apple>();
  static List<Fruit> fruit = new ArrayList<Fruit>();
  static void f1() {
    writeExact(apples, new Apple());
    writeExact(fruit, new Apple());// Error
  }    
  static void f2() {
    writeWithWildcard(apples, new Apple());
    writeWithWildcard(fruit, new Apple());//OK
  }
}


自限定类型:class A    extends SelfBounded<A>
受检安全:checkedList、checkedMap、checkedSet……等。

 

    List<Dog> dogs1 = new ArrayList<Dog>();
    dogs1.add(new Cat());
    List<Dog> dogs2 = Collections.checkedList(new ArrayList<Dog>(), Dog.class);
    dogs2.add(new Cat()); //异常
    List<Pet> pets = Collections.checkedList(new ArrayList<Pet>(), Pet.class);
    pets.add(new Dog()); //ok
    pets.add(new Cat()); //ok


注意:
尽可能不使用Object进行装箱拆箱,根据需要型参可以有很多。
泛型数组运行时类型为Object[],泛型中基本类型会被自动包装为相应的类对象。
如Integer、Boolean、Double等。
泛型不能显示的引用操作,如:转型、instanceof、new实例化等。
T代表的只是一个Object对象,不是拥有有关参数的类型信息。
如果泛型方法返回的结果传入另一方法,这时返回值被赋给一个Object类型的变量。
JAVA泛型使用擦除来实现,因此任何具体的类型信息都被擦除了,只能知道使用了一个对象,因此List<String>、List<Integer>运行时是“相同”的List类型或Object。

 

Class c1 = new ArrayList<String>().getClass();
    Class c2 = new ArrayList<Integer>().getClass();
    System.out.println(c1 == c2); //true

toString泛型集合时只能打印:[E]类似的信息。

一些应用示例:
1、静态工厂方法可避免过多的泛型参数

 

Map<Person, List<? extends Pet>> petPeople = new HashMap< Person, List<? extends Pet>>();
public static <A,B> Map<A,B> map() {
  return new HashMap<A,B>();
}
Map<Person, List<? extends Pet>> petPeople = New.map();

2、泛型继承

 

ThreeTuple<A,B,C> extends TwoTuple<A,B>
static ThreeTuple<Amphibian,String,Integer> g() {
        return new ThreeTuple<Amphibian, String, Integer>(
          new Amphibian(), "hi", 47);
}
class TupleList<A,B,C,D> extends ArrayList<FourTuple<A,B,C,D>>

3、动态参数
      static <T> List<T> makeList(T... args)
4、泛型数组

 

class Generic<T> {}
Generic<Integer>[] gia = (Generic<Integer>[])new Generic[SIZE];
T[] array = (T[])new Object[SIZE];

自定义数组:T[]
5、非法应用
       如果List为自定义类型数组,则另当别论。

 

class Fruit {}
class Apple extends Fruit {}
class Jonathan extends Apple {}
class Orange extends Fruit {}
Fruit[] fruit = new Apple[10];
fruit[0] = new Apple(); //只可存放apple及子类型
List<Fruit> flist = new ArrayList<Apple>(); //error,必须精确为Fruit类型
List<? extends Fruit> flist = new ArrayList<Apple>();
flist.add(new Apple()); //error,向上转型后不能添加任何类型的对象,包括Object
List<? extends Fruit> flist = Arrays.asList(new Apple());
Apple a = (Apple)flist.get(0); //OK

6、通用生成器

 

public class BasicGenerator<T> implements Generator<T> {
  private Class<T> type;
  public BasicGenerator(Class<T> type){ this.type = type; }
  public T next() {
    try {
      return type.newInstance();
    } catch(Exception e) {
      throw new RuntimeException(e);
    }
  }
  // Produce a Default generator given a type token:
  public static <T> Generator<T> create(Class<T> type) {
    return new BasicGenerator<T>(type);
  }
}

NO.16、数组
多维数组:{},{}分割,如Integer[][] a = {{},{}};
Arrays应用:
转化:asList
填充:fill(,)可填充数组为同一值
复制:System.arraycopy(i, 0, j, 0, i.length);
比较:equals,基于内容的,个数和值都相等时true
      继承Comparable<>后,重写相关方法
排序:sort(a)、sort(a, compare),默认为自然排序
查找:binarySearch(a, element),需要对已排序的结果进行查找

示例:

 

Integer[][] a = { //几行几列为动态的,项长度不一致时,默认以最大的值为维度
      { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
      { 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 },
      { 51, 52, 53, 54, 55, 56, 57, 58, 59, 60 },
      { 71, 72, 73, 74, 75, 76, 77, 78, 79, 80 },
    };
    System.out.println(Arrays.deepToString(a));
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [21, 22, 23, 24, 25, 26, 27, 28, 29, 30], [51, 52, 53, 54, 55, 56, 57, 58, 59, 60], [71, 72, 73, 74, 75, 76, 77, 78, 79, 80]]

NO.17、容器深入研究
1、主要容器

 

ConcurrentMap、ConcurrentHashMap
CopyOnWriteArrayList
CopyOnWriteArraySet
EnumMap
EnumSet

2、填充
(1)Collections.nCopies返回一个不可变列表组成的n个拷贝的指定对象
         new ArrayList<StringAddress>(Collections.nCopies(4, new StringAddress("Hello")));
(2)Collections.fill替换所有指定的列表中具有指定元素的元素
         Collections.fill(list, new StringAddress("World!"));
3、不支持操作
       通过Arrays.asList操作获得的List是一个固定大小的数组,仅支持那些不会改变数组大小的操作,对于removeAll、clear等类的操作是不支持的。经过new ArrayList<String>()包装后产生可调整尺寸的结构就可以了。
4、其他
        尽量不用Vector,通常看成是Collection、List,缺点很多。
       Stack继承自Vector。
       Enumeration接口比Iterator小。
       尽量使用HashMap而不是Hashtable
       BitSet:高效率的存储大量开关信息,空间利用率高,访问时间相对本地数组较慢。
NO.18、IO
1、基础概念
       File:代表文件、文件集合和目录集合
       常用:renameTo、…
2、Stream

 

ByteArrayInputStream/ ByteArrayOutStream
StringBufferInputStream 将String转换成InputStream
FileInputStream/ FileOutputStream

FilterInputStream / FilterOutputStream //输入输出装饰,主要修饰如下:
DataInputStream / DataOutputStream
BufferInputStream / BufferOutputStream
LineNumberInputStream
SequenceInputStream
PrintStream

3、Reader
        并不是Stream的替代,意思是主要为了国际化(16位Unicode字符),可适当的结合Stream来使用。

 

    InputStreamReader、OutputStreamReader
    FileReader、FileWriter
    BufferReader、BufferWriter
    StringReader、StringWriter
    CharArrayReader、CharArrayWriter
    PrintReader、PrintWriter

    常用:readLine()、read()
4、压缩

 

CheckedInputStream/out
ZipInputStream/out
GZIPInputStream/out
BufferedOutputStream out = new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream("test.gz")));

5、其他
       RandomAccessFile:适用于由大小已知的记录组成的文件,主要用来访问保存数据记录的文件的。通常采用seek定位指针位置,然后读取和修改。
       FileChannel:通道和缓冲器,stream.getChannel()
6、示例
(1)基本用法

 

File path = new File(".");
list = path.list();
list = path.list(FilenameFilter);
File[] files = path.listFiles(FilenameFilter);
Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);

(2)读取

 

//Buffer缓冲速度快,in.readLine()
BufferedReader in = new BufferedReader(new FileReader(filename));
BufferedReader in = new BufferedReader(new StringReader(BufferedInputFile.read("BasicFileOutput.java")));
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
//读取内存中的String,in.read()
StringReader in = new StringReader(BufferedInputFile.read("MemoryInput.java"));
//内存格式化,in.readByte()
DataInputStream in = new DataInputStream(new ByteArrayInputStream(
BufferedInputFile.read("FormattedMemoryInput.java").getBytes()));
// 格式化
DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream("TestEOF.java")));
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("Data.txt")));

(3)写入

 

 

 

PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(file)));
PrintWriter out = new PrintWriter(new File(fileName).getAbsoluteFile());
PrintWriter out = new PrintWriter(System.out, true);

NO.19、枚举类型

 

1、基础
       .values返回枚举的实例数组,是编译器动态添加的static方法
       valueOf解析枚举
       Enums.random(this.values)
       Enums.random(Test.class) 获得枚举类的随机枚举值
2、EnumSet
       基础是Long型的,非常快速高效,替代传统的基于int的位标志,说明一个二进制位是否存在时,有更好的表达能力,最终操作的是bit。

    EnumSet<AlarmPoints> points = EnumSet.noneOf(AlarmPoints.class); // Empty set
    points.add(BATHROOM);
    points.addAll(EnumSet.of(STAIR1, STAIR2, KITCHEN));
    points = EnumSet.allOf(AlarmPoints.class);
    points.removeAll(EnumSet.of(STAIR1, STAIR2, KITCHEN));
    points.removeAll(EnumSet.range(OFFICE1, OFFICE4));
    points = EnumSet.complementOf(points);

3、EnumMap
       键需为enum类型,速度很快,enum定义时顺序决定了在EnumMap中的顺序。

EnumMap<AlarmPoints,Command> em = new EnumMap<AlarmPoints,Command>(AlarmPoints.class);
    em.put(KITCHEN, new Command() { public void action() { print("Kitchen fire!"); } });

4、实例方法

public enum ConstantSpecificMethod {
  DATE_TIME {
    String getInfo() {
      return
        DateFormat.getDateInstance().format(new Date());
    }
  },
  VERSION {
    String getInfo() {
      return System.getProperty("java.version");
    }
  };
  abstract String getInfo();
  public static void main(String[] args) {
    for(ConstantSpecificMethod csm : values())
      System.out.println(csm.getInfo());
  }
}

5、应用
       枚举链:遍历枚举节点,调用处理器集合,适合处理条件的则处理
       状态机:枚举示例

public enum Input {
  NICKEL(5), DIME(10), QUARTER(25), DOLLAR(100),
  TOOTHPASTE(200), CHIPS(75), SODA(100), SOAP(50),
  ABORT_TRANSACTION {
    public int amount() { // Disallow
      throw new RuntimeException("ABORT.amount()");
    }
  },
  STOP { // This must be the last instance.
    public int amount() { // Disallow
      throw new RuntimeException("SHUT_DOWN.amount()");
    }
  };    
  int value; // In cents
  Input(int value) { this.value = value; }
  Input() {}
  int amount() { return value; }; // In cents
  static Random rand = new Random(47);
  public static Input randomSelection() {
    // Don't include STOP:
    return values()[rand.nextInt(values().length - 1)];
  }

NO.20、注解
1、基础
(1)描述
       @Target:构造器、域、局部变量、方法、包、参数、类、接口、枚举
       @Retention:…
       @Inherited:允许子类继承父类中的注解
       注解元素:基本类型、类、枚举、Annotation
       默认值:只能为确定的值,不可为NULL,通常为-1、””
(2)示例

 

@Target(ElementType.METHOD) //定义作用于方法、域、属性等
@Retention(RetentionPolicy.RUNTIME) //定义哪一级别可用:源代码、类、运行时
public @interface Test { //定义注解标记
  public int id(); //注解元素
  public String description() default "no description"; //默认值
}
@UseCase(id = 47, description ="test")
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints {
  boolean primaryKey() default false;
  boolean allowNull() default true;
  boolean unique() default false;
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLInteger {
Constraints constraints() default @Constraints(unique=true);
}

2、注解处理

 

List<Integer> useCases = new ArrayList<Integer>();
trackUseCases(useCases, PasswordUtils.class);
trackUseCases(List<Integer> useCases, Class<?> cl) {
for(Method m : cl.getDeclaredMethods()) {
  //Annotation[] ann = getDeclaredAnnotations()
      UseCase uc = m.getAnnotation(UseCase.class); //返回注解对象
      if(uc != null) {
          //uc.id
      }
    }
}

3、Apt处理器
       操作JAVA源文件,而不是CLASS文件,所以采用APT时无法使用JAVA反射,APT通常会处理完源文件后编译它们。
       使用mirror API能够解决这个问题,可在未编译的源码中查看方法、域及类型。
       可将观察者模式用于apt,虽然看上去复杂些,但是具有很好的扩展能力。
4、注解的单元测试
       最便捷的方式:继承要测试的类,然后注解特定的方法,调用父类的方法来测试。
NO.21、并发
       因为结合其他的多线程部分笔记,所以涉及到的内容比较多,暂且不提供。
NO.22、图形化用户界面
        ……

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值