这是一个经过对《Java编程思想》(Think in java)进行阅读同时对java内容查漏补缺的系列。一些基础的知识不会被罗列出来,这里只会列出一些程序员常常会忽略或者混淆的知识点。html
所列知识点所有都是针对本身我的而言,同时也欢迎你们进行补充。
java
任何抽象性都应该是应真正的需求而产生的。程序员
p172
interface若是不加public关键字,则只具备包访问权限。算法
p181
能够经过extends来扩展接口,但在实现多重继承时要注意不能实现签名或返回类型不一样的接口方法,除非其传入参数不同。最好避免使用同一个方法名称。编程
interface M{ void menace(); void kill(); } interface Danger{ void menace(int s); void kill(); } interface Vampire extends Danger,M{ } public class Monster implements Vampire{ public static void main(String[] args) { System.out.println("Hello,every one,I'm cpacm"); } public void menace(int s) { // TODO Auto-generated method stub } public void kill() { // TODO Auto-generated method stub } public void menace() { // TODO Auto-generated method stub } }
tip:切勿过渡设计设计模式
p182
安全
去商店去买东西,能够选择不一样的出行方式但都能达到买东西的目的,这种选择模式就是策略模式。
把出行方式抽象为一个接口,实现公交车,自行车,走路,出租车等实例,最后本身决定使用哪一种方式。框架
策略模式:定义一系列的算法,把每个算法封装起来, 而且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。也称为政策模式(Policy)。策略模式把对象自己和运算规则区分开来,其功能很是强大,由于这个设计模式自己的核心思想就是面向对象编程的多形性的思想。
环境类(Context):用一个ConcreteStrategy对象来配置。维护一个对Strategy对象的引用。可定义一个接口来让Strategy访问它的数据。
抽象策略类(Strategy):定义全部支持的算法的公共接口。 Context使用这个接口来调用某ConcreteStrategy定义的算法。
具体策略类(ConcreteStrategy):以Strategy接口实现某具体算法。
dom
p183
将一个类的接口转换成客户但愿的另一个接口。Adapter模式使得本来因为接口不兼容而不能一块儿工做的那些类能够在一块儿工做。
在Android中经常使用到的各类Adapter就是用的适配器模式思想。
ide
p187
工厂模式主要用如下几种形态:
抽象工厂和工厂能够根据不一样状况下相互转化。
p191
内部类拥有其外围类的全部元素的访问权。
意思是经过内部类可以得到其外部类的内存信息(参数值)。
故不能直接经过建立普通对象的方法建立内部类,必需要经过外部类才能建立。
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 Inner inner() { return new Inner(); } public static void main(String[] args) { DotThis dt = new DotThis(); DotThis.Inner dti = dt.inner(); dti.outer().f(); } }
p193
.new语法,能够直接建立其内部类,但前提也是要提供其外部类的引用。
public class DotNew { public class Inner{}; public static void main(String[] args) { DotNew dn = new DotNew(); DotNew.Inner dti = dn.new Inner(); } }
当内部类向上转型为基类或接口时,每每是为了隐藏实现细节。
p196
内部类能够嵌入在任何堆做用域内,但只在其做用域内可用。称做为局部内部类
public class Parcel6 { private void inTrack(boolean b){ if(b){ class TrackSlip{ private String id; TrackSlip(String s){ id = s; } String getSlip(){return id;} } TrackSlip ts = new TrackSlip("slip"); String s = ts.getSlip(); } } //TrackSlip ts = new TrackSlip("slip"); //run error public void track(){ inTrack(true); } public static void main(String[] args) { // TODO Auto-generated method stub Parcel6 p = new Parcel6(); p.track(); } }
p200
匿名内部类是一个没有名字的内部类,一般使用它来简化代码编写,同时必须继承一个父类或实现一个接口。
public class Parcel7 { public static void main(String[] args) { Thread t = new Thread() { public void run() { for (int i = 1; i <= 5; i++) { System.out.print(i + " "); } } }; t.start(); } } //1 2 3 4 5
tip:经常使用的扩展是将只使用一次的工厂类做为匿名内部类放在生产类上。
p201
将内部类声明为static时,此时就做为嵌套类使用。建立嵌套类的对象并不须要外围对象,同时也不能从嵌套类的对象中访问非静态的外围对象。
p202
在接口中能够放入嵌套类。
public interface ClassInInterface { void howdy(); class Test implements ClassInInterface{ @Override public void howdy() { // TODO Auto-generated method stub System.out.println("Howdy!"); } public static void main(String[] args) { new Test().howdy(); } } }
p205
使用内部类的一些好处
p207
模板方法模式:定义一个操做中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类能够不改变一个算法的结构便可重定义该算法的某些特定步骤。
模板模式须要一个抽象类和继承该抽象类的子类来实现。一样使用出门买东西的情景:出门->买东西->回来。
咱们不关心怎么出去和回来,因此把出门和回来的方法写在抽象类中,而后将买东西这个方法抽象化放在抽象类中以便子类实现。
接着建立子类继承抽象类,买一种东西能够建立一个新类,从而实现抽象方法。
而策略模式是使用委托方法实现的,须要一个用来实现
方法的接口存在。
模板模式和策略模式一般能够互相替换。
p211
命令模式的结构
顾名思义,命令模式就是对命令的封装,首先来看一下命令模式类图中的基本结构:
Command类:是一个抽象类,类中对须要执行的命令进行声明,通常来讲要对外公布一个execute方法用来执行命令。
ConcreteCommand类:Command类的实现类,对抽象类中声明的方法进行实现。
Client类:最终的客户端调用类。
以上三个类的做用应该是比较好理解的,下面咱们重点说一下Invoker类和Recevier类。
Invoker类:调用者,负责调用命令。
Receiver类:接收者,负责接收命令而且执行命令。
命令模式的精髓所在:把命令的调用者与执行者分开,使双方没必要关心对方是如何操做
p212
当继承内部类的时候必须在构造器中传入外围类的引用和外围类的super;
p220
ArrayList LinkedList 都是按插入顺序存放数据
ArrayList在随机访问速度上比较快,而LinkedList在插入和删除数据比较有优点,具备Queue,Stack的特性。
HashSet TreeSet LinkedHashSet
HashMap TreeMap LinkedHashMap
通用点:Hash开头的容器都是经过Hash值来查找数据,因此特色是无序但速度快;
Tree开头的容器都会将存入的数据进行升序排列;
Linked则是按插入的顺序进行排序。
(后面17章会介绍其原理)
p226
迭代器具备如下特性:
1)建立代价小
2)单向移动
3)next()获取下一个对象,hasNext()判断是否具备下一个对象,remove()移除当前对象。
(ListIterator做为List特有的迭代器,具备双向移动功能,其对应方法为hasPrevious(),previous())
````java
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeSet;
public class CrossContainerIteration {
public static void display(Iterator<Pet> it) { while (it.hasNext()) { Pet p = it.next(); System.out.println(p.id() + ":" + p + " "); } System.out.println(); } public static void main(String[] args) { // TODO Auto-generated method stub List<Pet> pets = new ArrayList<>(); pets.add(new Pet("cat")); pets.add(new Pet("dog")); pets.add(new Pet("bird")); pets.add(new Pet("fish")); pets.add(new Pet("pig")); LinkedList<Pet> petsLL = new LinkedList<>(pets); HashSet<Pet> petsHS = new HashSet<>(pets); TreeSet<Pet> petsTS = new TreeSet<>(pets); display(pets.iterator()); display(petsLL.iterator()); display(petsHS.iterator()); display(petsTS.iterator()); }
}
/*0:Pet cat
1:Pet dog
2:Pet bird
3:Pet fish
4:Pet pig
0:Pet cat
1:Pet dog
2:Pet bird
3:Pet fish
4:Pet pig
3:Pet fish
1:Pet dog
4:Pet pig
2:Pet bird
0:Pet cat
2:Pet bird
0:Pet cat
1:Pet dog
3:Pet fish
4:Pet pig */
```
p230
后进先出
一般可使用LinkedList来实现Stack的功能
public class Stack<T> { private LinkedList<T> storge = new LinkedList<>(); public void push(T v){ storge.addFirst(v); } public T peek(){ return storge.getFirst(); } public T pop(){ return storge.removeFirst(); } public boolean empty(){ return storge.isEmpty(); } }
p236
Queue 先进先出
一样可使用LinkedList来实现功能,因为其实现了Queue接口,能够将其向上转型。
public class QueueDemo { public static void printQ(Queue queue) { while (queue.peek() != null) System.out.print(queue.remove() + " "); System.out.println(); } 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); } } /* * Output: 8 1 1 1 5 14 3 1 0 1 B r o n t o s a u r u s */
p237
PriorityQueue
简单来讲就是具备排序功能的队列,下一个弹出的元素是在队列中优先级最高的一个。使用Comparator比较器来进行比较。
public class PriorityQueueDemo { 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); /* * 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 */ 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); /* * 25 23 22 21 20 18 18 14 14 9 9 3 3 2 1 1 */ 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); } /* * 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 */ }
总结:四种容器List Set Queue Map
Java的基本理念是“结构不佳的代码不能运行
p252
咱们能够继承Exception类来自定义异常,在自定义异常类中能够添加一些动做,好比写入日志等等。
class MyException extends Exception { public MyException() {} public MyException(String msg) { super(msg); } } public class FullConstructors { public static void f() throws MyException { System.out.println("Throwing MyException from f()"); throw new MyException(); } public static void g() throws MyException { System.out.println("Throwing MyException from g()"); throw new MyException("Originated in g()"); } public static void main(String[] args) { try { f(); } catch(MyException e) { e.printStackTrace(System.out); } try { g(); } catch(MyException e) { e.printStackTrace(System.out); } } } /* Output: Throwing MyException from f() MyException at FullConstructors.f(FullConstructors.java:11) at FullConstructors.main(FullConstructors.java:19) Throwing MyException from g() MyException: Originated in g() at FullConstructors.g(FullConstructors.java:15) at FullConstructors.main(FullConstructors.java:24) *///:~
异常也是类的一种,因此咱们能够扩展使其得到更强大的功能。
class MyException2 extends Exception { private int x; public MyException2() { } public MyException2(String msg) { super(msg); } public MyException2(String msg, int x) { super(msg); this.x = x; } public int val() { return x; } public String getMessage() { return "Detail Message: " + x + " " + super.getMessage(); } } public class ExtraFeatures { public static void f() throws MyException2 { System.out.println("Throwing MyException2 from f()"); throw new MyException2(); } public static void g() throws MyException2 { System.out.println("Throwing MyException2 from g()"); throw new MyException2("Originated in g()"); } public static void h() throws MyException2 { System.out.println("Throwing MyException2 from h()"); throw new MyException2("Originated in h()", 47); } public static void main(String[] args) { try { f(); } catch (MyException2 e) { e.printStackTrace(System.out); } try { g(); } catch (MyException2 e) { e.printStackTrace(System.out); } try { h(); } catch (MyException2 e) { e.printStackTrace(System.out); System.out.println("e.val() = " + e.val()); } } } /* Throwing MyException2 from f() chapter12.MyException2: Detail Message: 0 null at chapter12.ExtraFeatures.f(ExtraFeatures.java:32) at chapter12.ExtraFeatures.main(ExtraFeatures.java:47) Throwing MyException2 from g() chapter12.MyException2: Detail Message: 0 Originated in g() at chapter12.ExtraFeatures.g(ExtraFeatures.java:37) at chapter12.ExtraFeatures.main(ExtraFeatures.java:52) Throwing MyException2 from h() chapter12.MyException2: Detail Message: 47 Originated in h() at chapter12.ExtraFeatures.h(ExtraFeatures.java:42) at chapter12.ExtraFeatures.main(ExtraFeatures.java:57) e.val() = 47 */// :~
p257
全部的异常均可以由Exception进行捕获,能够经过Exception打印发生错误时所获取的信息。
p258
能够经过throw将catch到的异常从新抛出,不过异常里面是原来异常抛出的调用栈信息。可使用 fillInStackTrace()更新,调用 fillInStackTrace那一行就成了异常的新发生地。
public class Rethrowing { public static void f() throws Exception { System.out.println("originating the exception in f()"); throw new Exception("thrown from f()"); } public static void g() throws Exception { try { f(); } catch(Exception e) { System.out.println("Inside g(),e.printStackTrace()"); e.printStackTrace(System.out); throw e; } } public static void h() throws Exception { try { f(); } catch(Exception e) { System.out.println("Inside h(),e.printStackTrace()"); e.printStackTrace(System.out); throw (Exception)e.fillInStackTrace(); } } public static void main(String[] args) { try { g(); } catch(Exception e) { System.out.println("main: printStackTrace()"); e.printStackTrace(System.out); } try { h(); } catch(Exception e) { System.out.println("main: printStackTrace()"); e.printStackTrace(System.out); } } } /* Output: originating the exception in f() Inside g(),e.printStackTrace() java.lang.Exception: thrown from f() at Rethrowing.f(Rethrowing.java:7) at Rethrowing.g(Rethrowing.java:11) at Rethrowing.main(Rethrowing.java:29) main: printStackTrace() java.lang.Exception: thrown from f() at Rethrowing.f(Rethrowing.java:7) at Rethrowing.g(Rethrowing.java:11) at Rethrowing.main(Rethrowing.java:29) originating the exception in f() Inside h(),e.printStackTrace() java.lang.Exception: thrown from f() at Rethrowing.f(Rethrowing.java:7) at Rethrowing.h(Rethrowing.java:20) at Rethrowing.main(Rethrowing.java:35) main: printStackTrace() java.lang.Exception: thrown from f() at Rethrowing.h(Rethrowing.java:24) at Rethrowing.main(Rethrowing.java:35) *///:~
p260
Throwable的子类能够接受一个cause对象做为参数,cause表示原始异常,这样能够经过把原始异常传递给新的异常使得能够追踪全部链接起来的异常。
在Throwable子类中,只有三种基本的异常类提供了带cause参数的构造器,分别为Error,Exception和RuntimeException。若是要把其余类型的异常连接起来,应该使用initCause()方法。
p268
return 与 fianl共用时,即便在try里面实行return,finally里面的代码仍是会运行,
而在final里面使用热力return 的话,即便抛出了异常也不会产生任何输出。
p281