objList.add(new Object()); // runtime could not throw exception
其次,考虑下面的例子, B extends A ,有 B extends A ,如果使用 covariant subtyping ,又有 B extends B ,这意味着存在多重继承,而多重继承在 java 里面是不被允许的。值得注意的是,尽管数组使用 covariant subtyping ,但却不会导致多重继承,因为数组属于系统类型, java 并不允许数组被继承。
采用了 invariant subtyping 之后,假如有 A ,由于 A 不再是其他类型 A 、 A 等类型的父类, 则无法声明可以指向所有 A 类型对象的变量。为了解决这一问题, java 1.5 引入了 wildcard ,声明为 A> 类型的变量可以指向所有 A 类型的对象。需要注意的是, wildcard 跟继承是两种不同的关系,继承使类型间呈现树状的关系,类型为 B 的变量可以指向的对象类型必须在以 B 为根节点的子树中,而类型为 A> 的变量可以指向的对象类型必须为类型树中 A 或与 A 平行的节点。最后, wildcard 跟继承结合使得 A> 类型变量能够指向的对象类型必须在以 A 及 A 平行的节点为根的所有子树中。
// A extends Object, B extends Object, C extends B, D extends B
A> a; // instances of A, A, A can be assigned to this variable
B b; // instance of B, C, D can be assigned to this variable
Generic 的实现
加入了 generic 后 java 的 type safe
保证 type safe ,其实就关键在于确保所有变量所指向的对象的类型必须是正确的。我认为在理想状态下,应该实现以下几点:首先,类型为 A 的变量所能指向的对象类型必须在以 A 为根节点的子树中;其次,类型为 wildcard 的变量,如 A> ,所能指向的对象类型必须在以 A 及 A 平行的节点为根的所有子树中;最后,所有的显式转换在 runtime 必须做类型判定。其中,前两点由 compiler 实现,最后一点由 jvm 实现,然而事实上, java 5 仅实现了前两点,而决定不在 runtime 做检测。
Compile time 下 generic 的 type safe 主要包括 generic class 跟 generic method 的 type safe ,以下分开讨论。
Generic class 的 type safe
假设有以下的类:
public class A {};
public class B extends A {
public T obj;
}
public class C extends B {
public void set(T obj) { this. obj = obj; }
public T get() { return obj; }
}
对于类型为 C 的对象,能够指向它的变量的类型有: A 、 B 、 C 、 B> 、 C> 。对于类型为 A 的变量,通过该变量无法访问到任何与 T 相关的方法或对象变量,很显然在原有 java 的 type safe 机制仍然有效;对于类型为 B 、 C 的变量, compiler 对所有通过该变量所访问的方法( set 、 get )或对象变量 (obj) 进行检测,所有涉及到 T 的赋值都必须满足 T=String ,则 type safe 得以保证。对于类型为 B> 、 C> 的变量,通过该变量所访问的方法或对象变量,所有的输出值中 T 类型被替换成 T 的 bound (见下文中“ type parameter 的限制”),所有输入值中由于 T 类型未知,所以不能接受任何变量赋值( null 除外)。在理想状态下,输入值中 T 类型应该也被替换成 T 的 bound ,然后由 runtime 去做类型判定,但是由于 runtime 没有 generic 相关的任何信息
C strC = new C();
C> c = strC;
// even if the following code pass compile time check, runtime could not throw exception
c.obj = new Object();
c.set(new Object());
// here’s a unexpected exception
String str = strC.obj;
str = strC.get();
在 generic class 的所有方法中, T 的类型被认为是其 bound 或者 bound 的某个子类。也就是说,首先, T 的变量只能指向类型为 T 或 T 的子类的对象;其次,通过 T 的变量只能访问到其 bound 的方法和对象变量。假设以下代码存在于 C 的 set 方法中:
public void set(T obj;) {
Object temp;
temp = obj; // ok
obj = temp; // ompile error
obj.toString(); // can access Object’s methods
}
Generic method 的 type safe
与 Generic class 不同的是,在 generic method 中, actual type argument 并非指定的,而是由 compiler 推断出的( Inference )。 Compiler 通过对 generic method 中的输入变量的类型推断 type parameter 的类型,如果不能够得到一个 unique smallest type ,则被视为 compile error ,参考以下代码:
通过 Class 能够创建 T 的对象, Class 的奥妙在于,一方面它能够通过 compiler 的检测,另一方面,它本身携带的信息也足以让 runtime 得以创建 T 的对象。
public T create(Class c) { return c.newInstance(); };
…
String temp = create(String.class);
4.不得不插入 bridge method (如上文所述)。
5.使用 instanceof 时受到限制。
List list = new ArrayList();
boolean temp;
temp = list instanceof List; // compile error
temp = list instanceof List>; // ok
6.使用 reflection 时存在安全隐患。
public class A {
public T obj;
}
public class B {
public A a;
}
…
A a = new A();
B b = new B();
B.class.getField(“a”).set(a); // everything ok
String temp = b.a.obj; // unexpected error
7.Generic class 中的 type parameter 在其静态方法及静态变量中无法使用。
在 generic 中对 type parameter 的限制
使用 extends 关键字
对于如 A 的 generic class ,可以使用 extends 来进一步限制 T 所能代表的类型。如:
public class A { … }
…
A objA; // compile error
A strA; // compile error
A numA; // ok
A intA; // ok
这里, extends 意味着 T 必须是 Number 或者 Number 的子类,以下是对于 extends 更为复杂的使用。
public class B> {…}
public class C extends B { … }
public class D extends C { … }
…
C c = new C();
D d = new D();
B bc; // ok
bc = c;
bc = d;
B bd; // compile error
B b; // compile error
这里,显然 B 是非法的,对于 B ,虽然 D 继承了 C ,但是把 D 替换到“ T extends B ”中,显然“ D extends B ”不成立,所以 B 也是非法的,与此类似的是 java.lang 里面的“ Enum> ”,这一声明保证了,假设有类 Test ,它不是 Enum 类型(编译器保证只有使用 enum 关键字创建时才能满足 Enum 类中对 T 的限制),那么无法声明 Enum 类型的变量。
public class E { … }
…
E e1; // ok
E e2; // ok
E e3; // compile error
这里, extends 用来限制不同的 type parameter(T 、 S) 之间的关系。
最后,需要注意的是,在 generic class 里面通过使用 extends 对 type parameter 进行限制所导致的结果是删除了一部分类型(如上述的 E ),而并非阻止这一类型的对象的创建,而在 generic method 里面使用 extends 则在于阻止某些类型的对象作为输入参数,如:
public void test(List list) {}
…
test(new ArrayList()); // ok
test(new ArrayList()); // compile error
关于 wildcard – “?”
在不使用 super 关键字的时候, ”?” 可以理解成 parameter type 的匿名形式,事实上,这些 ”?” 都可以转变成用 parameter type 表示。
public void test(List extends String> list) {}
public void test(List list) {}
“?” 只能作为 parameterized type 的 actual type argument 使用,同时由于 ”?” 是匿名的形式,编译器并不会认为出现两次的 A> 要求相同的 type parameter 。
public void test(? obj) {} // compile error
public void test1(List list1, List list2) {}
public void test2(List> list1, List> list2) {}
…
test1(new ArrayList(), new ArrayList()); // compile error
test2(new ArrayList(), new ArrayList()); // ok
使用 super 关键字
对于 T super A , super 表示 T 必须是 A 或者 A 的父类,相比起 extends ,对 super 的使用有更多的限制。考虑以下代码:
public void test(T obj) {} // assumes that there’s no compile error
…
test(new Object()); // this looks reasonable
test(1); // Integer is not super class of Number, so compiler should reject this, but Integer is also an object, why would a method accept object as valid argument but not integer?
可以看到, super 限制对象类型必须是某个类或其父类,而继承则允许父类的变量接受子类的对象,这两者是互相抵触的,所以对 super 的时候有以下的限制:
首先, super 只能在 parameterized type 的 actual type argument 中作为限制条件使用,在这个时候,它并不和继承相抵触。如:
public void test(List super Number> list) {}
其次, super 不能用于限制非匿名的 parameter type ,显然如果可以这样的话,就会出现上述代码中的错误。这就决定了 super 只能与 ”?” 连用。
Generic 的向前兼容
下面以 List 为例,为了向前兼容原先的代码,允许使用 List 这样的 raw type 。在语义上, List 跟 List 是一致的,然而在语法上 List 跟 List> 更为类似,并且编译器允许原先在 List 使用原先在 List> 上禁止的某些操作(对于 List> 为 compile error 的操作在 List 上仅仅是 warning )。
首先,在类型转换上, List 跟 List> 是等价的, List 类型可以赋给任何指定了 actual type argument 的 parameterized type (如 List ),而 List> 则不行(除非使用显式转换)。
List list;
List> wildcardList;
List strList;
list = wildcardList;
list = strList;
wildcardList = list;
wildcardList = strList;
strList = list; // warning
strList = wildcardList; // compile error
其次, compiler 不允许通过 List> 访问任何输入参数与 E 相关的方法,而 List 则仅给出 wanring 。
对于 test 方法,如果方法内仅需要调用 A 的 set 方法(即仅需要用到输入值为 T 类型的方法,注意,这不包括如 List 这种类新),使用 A super T> 代替 A 可能会更为合适,这使得 (1) 得以编译通过,由于仅需要调用 A 的 set 方法, A.set(Object) 显然比 A.set(Number) 允许更多的类型,从而使 A 可以替换 A 。相似的,如果 test 方法内仅需要调用 A 个 get 方法,则使用 A extends T> 代替 A 可能会更合适,这使得 (2) 得以编译通过。
关于 type parameter 的命名规范
推荐使用精简同时有意义的名称,如 E for element 、 T for type (最好是单个字母),同时避免使用任何小写字母以使得 type parameter 能够从一般的类还有接口名称中被区分出来。如果需要同时使用多个 type parameter ,则考虑使用邻近的几个不同字母,如 T 、 S 。如果在某个类中已经使用了某个字母作为 type parameter ,则在其 generic method 以及 nested class 中避免使用同样的字母。
Generic method 采用 inference 所产生的问题
public interface I {}
public class A implements I {}
public class B{}
public void test(T a, T b);
…
test(new A(), new B()); // ok
当代码改动 B 也需要实现接口 I 的时候:
public class B implements I {}
…
test(new A(), new B()); // compile error
仍然搞不懂的地方
对于类似 java.util.Collections 的 max 方法,经过我的试验以下两种声明方式所能接受的类型是一样的,不明白它为什么要用前者。
public static > T max1(Collection extends T> coll)
public static > T max2(Collection coll)
参考资料
GJ- Making the future safe for the past: Adding Genericity to the JavaTM Programming Language
用简单的话来定义tcpdump,就是:dump the traffic on a network,根据使用者的定义对网络上的数据包进行截获的包分析工具。 tcpdump可以将网络中传送的数据包的“头”完全截获下来提供分析。它支 持针对网络层、协议、主机、网络或端口的过滤,并提供and、or、not等逻辑语句来帮助你去掉无用的信息。
实用命令实例
默认启动
tcpdump
普通情况下,直
MO= Mobile originate,上行,即用户上发给SP的信息。MT= Mobile Terminate,下行,即SP端下发给用户的信息;
上行:mo提交短信到短信中心下行:mt短信中心向特定的用户转发短信,你的短信是这样的,你所提交的短信,投递的地址是短信中心。短信中心收到你的短信后,存储转发,转发的时候就会根据你填写的接收方号码寻找路由,下发。在彩信领域是一样的道理。下行业务:由SP
import java.util.Arrays;
import java.util.Random;
public class MinKElement {
/**
* 5.最小的K个元素
* I would like to use MaxHeap.
* using QuickSort is also OK
*/
public static void
添加没有默认值:alter table Test add BazaarType char(1)
有默认值的添加列:alter table Test add BazaarType char(1) default(0)
删除没有默认值的列:alter table Test drop COLUMN BazaarType
删除有默认值的列:先删除约束(默认值)alter table Test DRO
Spring Boot 1.2.4已于6.4日发布,repo.spring.io and Maven Central可以下载(推荐使用maven或者gradle构建下载)。
这是一个维护版本,包含了一些修复small number of fixes,建议所有的用户升级。
Spring Boot 1.3的第一个里程碑版本将在几天后发布,包含许多