复用
1.里氏替换原则
里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。
类型替换:
①子类型只能增加而不能删除方法
②子类型需要实现抽象类中所有未实现的方法
③子类型中重写的方法,它的返回值必须是相等类型或是协变类型。
④子类型中重写的方法,它的返回值必须是相等类型或是逆变类型(java不支持)。
⑤子类型中重写的方法不能抛出额外的异常(必须是被重写方法抛出的异常及其子类)。
方法重写:
①更强的不变量(规则限制)
②更弱的前置条件
③更强的后置条件
2.协变、逆变
协变:子类型代替父类型出现,更具体
比如数组中相应子类型的数组引用可以传给父类型
比如泛型中的通配符<?> <? extends xxx>
逆变:父类型代替子类型出现,更抽象
3.委托
一个对象请求另一个对象的功能
与继承相比,主要发生在对象层面,可以选择性的使用方法,比继承更自由。
①将其传入一个具体方法的参数,用完就解除关系。
②将其写入构造函数的参数中,并设立一个字段与委托对象建立联系。
③直接将其固定在一个字段中。
④将其写入一个字段中,并可通过set()方法更改。
4.黑盒框架、白盒框架
白盒框架:通过继承框架类,重写框架方法使用框架
- 允许扩展每一个非私有方法
- 需要理解父类的实现
- 一次只进行一次扩展
- 通常被认为是开发者框架
黑盒框架:通过委派、组合、调用方法,使用框架类,内部不可见。
- 允许在接口中对public方法扩展
- 只需要理解接口
- 通常提供更多的模块
- 通常被认为是终端用户框架,平台
5.常用接口、功能类总结
Iterator、Iterable
iterator是一个接口
package java.util; public interface Iterator<AnyType> { boolean hasNext(); AnyType next(); void remove(); //上次next执行结果的元素 }
iterable是一个泛型接口
package java.lang; public interface Iterable<AnyType> { Iterator<AnyType> iterator(); }
删除元素的三种方式
1.普通for循环
2.迭代器删除
Iterator<String> it = list.iterator(); while(it.hasNext()) { if("b".equals(it.next())) { //list.remove("b"); //不能用集合的删除方法,因为迭代过程中如果集合修改会出现并发修改异常 it.remove(); } } for(Iterator<String> it2 = list.iterator(); it2.hasNext();) { if("b".equals(it2.next())) { //list.remove("b"); //不能用集合的删除方法,因为迭代过程中如果集合修改会出现并发修改异常 it2.remove(); } }
3.另一种for循环
for (String string : list) { if("b".equals(string)){ list.remove("b"); } }
Observer、Observable
Observer:接口、观察者
package java.util; public interface Observer { void update(Observable o, Object arg); }
Observable:类、被观察者
package java.util; public class Observable { private boolean changed = false; //是否改变状态 private Vector obs; //Vector利用同步方法来线程安全,线程安全在多线程情况下不会造成数据混乱 public Observable() { obs = new Vector(); } public synchronized void addObserver(Observer o) { if (o == null) throw new NullPointerException(); if (!obs.contains(o)) { obs.addElement(o); } } public synchronized void deleteObserver(Observer o) { obs.removeElement(o); } public void notifyObservers() { notifyObservers(null); } public void notifyObservers(Object arg) { Object[] arrLocal; synchronized (this) { if (!changed) //状态值未改变时返回,不通知 return; arrLocal = obs.toArray(); //将Vector转换成数组 clearChanged(); //重置状态 } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); } public synchronized void deleteObservers() { obs.removeAllElements(); } protected synchronized void setChanged() { changed = true; } protected synchronized void clearChanged() { changed = false; } public synchronized boolean hasChanged() { return changed; } public synchronized int countObservers() { return obs.size(); } }
Comparable、Comparator
Comparable是排序接口。若一个类实现了Comparable接口,就意味着该类支持排序。实现了Comparable接口的类的对象的列表或数组可以通过Collections.sort或Arrays.sort进行自动排序。
此外,实现此接口的对象可以用作有序映射中的键或有序集合中的集合,无需指定比较器。该接口定义如下:
package java.lang; import java.util.*; public interface Comparable<T> { public int compareTo(T o); }
Comparator是比较接口,我们如果需要控制某个类的次序,而该类本身不支持排序(即没有实现Comparable接口),那么我们就可以建立一个“该类的比较器”来进行排序,这个“比较器”只需要实现Comparator接口即可。也就是说,我们可以通过实现Comparator来新建一个比较器,然后通过这个比较器对类进行排序。该接口定义如下:
package java.util; public interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj); }
注意:1、若一个类要实现Comparator接口:它一定要实现compare(T o1, T o2) 函数,但可以不实现 equals(Object obj) 函数。
2、int compare(T o1, T o2) 是“比较o1和o2的大小”。返回“负数”,意味着“o1比o2小”;返回“零”,意味着“o1等于o2”;返回“正数”,意味着“o1大于o2”。
排序
数组排序:Array.sort(int[] a)
集合排序:
- Collections.sort(List list)
- Collections.sort(List list,Comparator c)