可以做推广的门户网站,房地产公司如何网站建设,seo搜索排名优化,建筑工程教育网官方网站目录
动态类型安全
异常
混型
C中的混型
替代方案
与接口混合
使用装饰器模式
与动态代理混合 本笔记参考自#xff1a; 《On Java 中文版》 动态类型安全 在Java 5引入泛型前#xff0c;老版本的Java程序中就已经存在了List等原生集合类型。这意味着#xff0c;我们…目录
动态类型安全
异常
混型
C中的混型
替代方案
与接口混合
使用装饰器模式
与动态代理混合 本笔记参考自 《On Java 中文版》 动态类型安全 在Java 5引入泛型前老版本的Java程序中就已经存在了List等原生集合类型。这意味着我们可以向这些老版本的代码中传递泛型集合这无疑是存在风险的。为此Java 5在java.util.Collections中添加了一组实用工具checked*()
checkedCollection()checkList()checkedMap()checkedSet()checkedSortedMap()checkedSortSet() 这些方法的第一个参数都是被检查的集合之后的参数会传入需要强制确保的类型。若这些方法检测到插入了不匹配的类型就会发出异常。 这一点和Java 5之前的原生集合不同它们只会在我们从中取出对象时报告问题。此时我们难以找出发生问题的代码。 下面的例子展示了check*()的用法
【例子check*()的使用】 假设我们有一个Pet类它有两个子类Cat和Dog。 则代码如下所示
import reflection.pets.Cat;
import reflection.pets.Dog;
import reflection.pets.Pet;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;public class CheckedList {// 一个Java 5之前遗留的方法SuppressWarnings(unchecked)static void oldStyleMethod(List probablyDogs) {// 向probablyDogs集合中传入错误的Cat类型probablyDogs.add(new Cat());}public static void main(String[] args) {ListDog dogs1 new ArrayList();// 安静地放入了Cat类型oldStyleMethod(dogs1);ListDog dogs2 Collections.checkedList(new ArrayList(), Dog.class);try {oldStyleMethod(dogs2);} catch (Exception e) {System.out.println(发生异常 e);}// 使用基类集合不会存在问题ListPet pets Collections.checkedList(new ArrayList(), Pet.class);pets.add(new Dog());pets.add(new Cat());}
} 程序执行的结果是 可以发现oldStyleMethod(dogs1)并没有受到编译器的质疑尽管方法内部会往dogs1集合中插入一个不匹配的Cat对象。而dogs2立刻抛出异常。 异常 因为类型擦除catch子句无法捕获泛型类型的异常因为无法获知异常的确切类型。也因此泛型类无法直接或间接地继承Throwable。 但类型参数可以用于方法声明中的throws子句。根据这个特点我们可以编写随受检查的异常类型变化而变化的泛型代码
【例子可变化的异常】
import java.util.ArrayList;
import java.util.List;interface ProcessorT, E extends Exception {void process(ListT resultCollector) throws E;
}class ProcessRunnerT, E extends Exceptionextends ArrayListProcessorT, E {ListT processAll() throws E {ListT resultCollector new ArrayList();for (ProcessorT, E processor : this)processor.process(resultCollector);return resultCollector;}
}class Failure1 extends Exception {
}class Processor1implements ProcessorString, Failure1 {static int count 3;Overridepublic void process(ListString resultCollector)throws Failure1 {if (count-- 1)resultCollector.add(哼);elseresultCollector.add(哈);if (count 0)throw new Failure1();}
}class Failure2 extends Exception {
}class Processor2implements ProcessorInteger, Failure2 {static int count 2;Overridepublic void process(ListInteger resultCollector)throws Failure2 {if (count-- 0)resultCollector.add(47);else {resultCollector.add(11);}if (count 0)throw new Failure2();}
}public class ThrowGenericException {public static void main(String[] args) {ProcessRunnerString, Failure1 runner1 new ProcessRunner();for (int i 0; i 3; i)runner1.add(new Processor1());try {System.out.println(runner1.processAll());} catch (Failure1 e) {System.out.println(e);}ProcessRunnerInteger, Failure2 runner2 new ProcessRunner();for (int i 0; i 3; i)runner2.add(new Processor2());try {System.out.println(runner2.processAll());} catch (Failure2 e) {System.out.println(e);}}
} 程序执行的结果是 Processor规定了会抛出异常E的方法process()。process()的结果被保存在了ListT resultCollector中这个参数也被称为采集参数。 因为检查型异常的缘故如果不使用参数化的异常我们就无法泛化地进行如上的代码编写。 混型 混型最基本的概念是混合多个类的能力生成一个可以代表混型中所有类型的类不过这通常是我们最后做的一件事。 对混型的更改会应用于所有使用了该混型的类中。可以说混型更加接近面向切面编程。
C中的混型 依旧是先看看混型在C中的表现。C会通过多重继承实现混型除此之外参数化类型也是一个不错的实现手段。
【例子在C中使用混型】
#includestring
#includectime
#includeiostreamusing namespace std;templateclass T class TimeStamped : public T {long timeStamp;
public:TimeStamped() {timeStamp time(0);}long getStamp() {return timeStamp;}
};templateclass T class SerialNumbered : public T {long serialNumber;static long counter;
public:SerialNumbered() {serialNumber counter;}long getSerialNumber() {return serialNumber;}
};// 定义静态存储并进行初始化
templateclass T long SerialNumberedT::counter 1;class Basic {string value;
public:void set(string val) {value val;}string get() {return value;}
};int main() {// 使用混型TimeStampedSerialNumberedBasic mixin1, mixin2;mixin1.set(test 1);mixin2.set(test 2);cout mixin1.get() : mixin1.getStamp() mixin1.getSerialNumber() endl;cout mixin2.get() : mixin2.getStamp() mixin2.getSerialNumber() endl;
} 程序执行的结果是 mixin1和mixin2具有所有混入类型的方法这就相当于将已有的类映射到新的子类上一样。 不幸的是由于类型擦除会丢弃基类的类型因此在Java中泛型类无法直接继承自泛型参数。 替代方案 为了在Java中使用混型下面将会给出一些替代的方案。
与接口混合 一种常见的方式是通过接口来实现泛型的效果
【例子使用接口实现混型的效果】
import java.util.Date;interface TimeStamped {long getStamp();
}class TimeStampedImp implements TimeStamped {private final long timeStamp;TimeStampedImp() {timeStamp new Date().getTime();}Overridepublic long getStamp() {return timeStamp;}
}interface SerialNumbered {long getSerialNumber();
}class SerialNumberedImp implements SerialNumbered {private static long counter 1;private final long serialNumber counter;Overridepublic long getSerialNumber() {return serialNumber;}
}interface Basic {void set(String val);String get();
}class BasicImp implements Basic {private String value;Overridepublic void set(String val) {value val;}Overridepublic String get() {return value;}
}// 混合多个类的能力
class Mixin extends BasicImpimplements TimeStamped, SerialNumbered {private TimeStamped timeStamp new TimeStampedImp();private SerialNumbered serialNumber new SerialNumberedImp();Overridepublic long getStamp() {return timeStamp.getStamp();}Overridepublic long getSerialNumber() {return serialNumber.getSerialNumber();}
}public class Mixins {public static void main(String[] args) {Mixin mixin1 new Mixin(),mixin2 new Mixin();mixin1.set(Test 1);mixin2.set(Test 2);System.out.println(mixin1.get() : mixin1.getStamp() mixin1.getSerialNumber());System.out.println(mixin2.get() : mixin2.getStamp() mixin2.getSerialNumber());}
} 程序执行的结果是 在这里Mixin类使用的是委托模式这种模式要求每个被混入其中的类在Mixin中都有一个字段Mixin负责把对应的任务委托给字段所代表的类。 然而这种做法在面对复杂的混型时会导致代码量的急剧增加。
----------
使用装饰器模式
||| 装饰器模式用其他的类装饰一个可包装的类分层叠加功能。 可以发现装饰器模式和混型的概念有相似之处。装饰器通过组合和规范的结构这个结构就是可装饰物和装饰器的层次结构进行实现而混型的实现基于继承。 装饰器是透明的可以通过一个公共的信息集向其传递信息。 可以将混型看做一种不要求装饰器继承结构的泛型装饰器机制
【例子使用装饰器重写上一个例子】
import java.util.Date;class Basic {private String value;public void set(String val) {val value;}public String get() {return value;}
}class Decorator extends Basic {protected Basic basic;Decorator(Basic basic) {this.basic basic;}Overridepublic void set(String val) {basic.set(val);}Overridepublic String get() {return basic.get();}
}class TimeStamped extends Decorator {private final long timeStamp;TimeStamped(Basic basic) {super(basic);timeStamp new Date().getTime();}public long getStamp() {return timeStamp;}
}class SerialNumbered extends Decorator {private static long counter 1;private final long serialNumber counter;SerialNumbered(Basic basic) {super(basic);}public long getSerialNumber() {return serialNumber;}
}public class Decoration {public static void main(String[] args) {TimeStamped t1 new TimeStamped(new Basic());TimeStamped t2 new TimeStamped(new SerialNumbered(new Basic()));// 该方法不可用// t2.getSerialNumber();t2.getStamp();SerialNumbered s1 new SerialNumbered(new Basic());SerialNumbered s2 new SerialNumbered(new TimeStamped(new Basic()));// 同样不可用// s2.getStamp();s2.getSerialNumber();}
} 通过这种方式创建的类也会包含所有所需的方法但是使用装饰器产生的对象类型是其层次结构上的最后一层包装。换言之因为只有最后一层是实际的类型因此只有最后一层的方法是可见的。
----------
与动态代理混合 通过动态代理可见笔记17-3可以创建一种更捷径混型的机制。使用了动态代理获得的结果类的动态类型将会是混合后的合并类型。 需要注意的是在动态代理中每个被混入的类都必须是某个接口的实现。
【例子使用混合代理实现混型】
import onjava.Tuple2;import static onjava.Tuple.*;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;class MixinProxy implements InvocationHandler {MapString, Object delegateByMethod;SuppressWarnings(unchecked)MixinProxy(Tuple2Object, Class?... pairs) {delegateByMethod new HashMap();for (Tuple2Object, Class? pair : pairs) {for (Method method : pair.b2.getMethods()) {String methodName method.getName();// containKey()来自Map类如果包含key值则返回trueif (!delegateByMethod.containsKey(methodName))delegateByMethod.put(methodName, pair.a2);}}}Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {String methodName method.getName();Object delegate delegateByMethod.get(methodName);return method.invoke(delegate, args);}SuppressWarnings(unchecked)public static Object newInstance(Tuple2... pairs) {Class[] interfaces new Class[pairs.length];for (int i 0; i pairs.length; i) {interfaces[i] (Class) pairs[i].b2;}ClassLoader cl pairs[0].a2.getClass().getClassLoader();return Proxy.newProxyInstance(cl, interfaces, new MixinProxy(pairs));}
}public class DynamicProxyMixin {public static void main(String[] args) {// BasicImp来自于Mixins.java的那个例子SuppressWarnings(unchecked)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());}
} 程序执行的结果是 然而这种实现只对动态类型有效而不会包括静态类型。除此之外如main()中所展示的 在使用方法之前我们还需要强制向下转型这也会带来多余的麻烦。 为了支持Java的混型业界开发了不止一个用于支持泛型的附加语言。