IEEE 754标准不仅包含由一个符号位和一个量值构成的正负数字,而且还包含正负0、 正负无穷,以及特殊的“NaN”值(表示非数字Not a Number)。NaN值用来表示某些无效操作的结果,例如0除0。float 和 double 的 NaN常量 被预定义为Float.NaN和Double.NaN。
Java编程语言的每个实现都需要支持浮点值的两个标准集,即单精度浮点值集(float value set)和双精度浮点值集(double value set)。另外,任何Java编程语言的实现可以同时支持两个扩展指数浮点值集,或者只支持其中之一,它们是单精度扩展指数值集(float- extended-exponent value set)和双精度扩展指数值集(double-extended-exponent value set)。这些扩展指数值集可以在某些情况下替代标准值集,用来表示类型为float和double的表达式的值。
任何浮点值集中的有限非0值全部都可以表示成 s . m . 2 e − N + 1 s.m.2^{e - N +1} s.m.2e−N+1 的形式,其中s是 +1 或-1, m是小于 2 N 2^{N} 2N的正整数,e是位于从 E m i n = − ( 2 K − 1 − 1 ) E{_{min}}= -(2^{K-1} - 1) Emin=−(2K−1−1) 到 E m a x = 2 K − 1 − 1 E{_{max}}= 2^{K-1} - 1 Emax=2K−1−1 的闭区间中的整 数,其中N和K是依赖于所用的值集的参数。按照这种形式,某些值可能会有多种表示方式。例如,假设值集中某个值v可以用s、m和e的恰当取值来按照这种形式表示,那么当m是偶数,e小于 2 K − 1 2^{K-1} 2K−1 时会怎样呢?我们可以将m取值减半,然后给e增加1,这样就会产生v的第二种表示。在符合这种形式的表示中,如果m>= 2 K − 1 2^{K-1} 2K−1,那么这种表示就称为规格化的表示,否则,这种表示就称为非规格化的表示。如果值集中的某个值不能按照m>= 2 K − 1 2^{K-1} 2K−1的 方式来表示,那么这个值就称为非规格化值,因为它没有任何规格化的表示。
对于两个必须支持的值集,以及两个扩展的浮点值集来说,在参数N和K上的约束(以及在推导出的参数 E m i n E{_{min}} Emin 到 E m a x E{_{max}} Emax上的约束)如下表所示。
表4-1 浮点值集参数
参数
单精度
单精度扩展指数
双精度
双精度扩展指数
N
24
24
53
53
K
8
>=11
11
>=15
E m i n E{_{min}} Emin
+127
>=+1023
+1023
>=-16383
E m a x E{_{max}} Emax
-126
<=-1022
-1022
<=-16382
如果某个Java实现支持一个或同时支持两个扩展指数值集,那么对于所支持的每一个 扩展指数值集,都有一个依赖于该实现的特定的常数K,它的值由 上表 限定,而这个值也就决定了 E m i n E{_{min}} Emin 和 E m a x E{_{max}} Emax 的值。
classTest{publicstaticvoidmain(String[] args){// An example of overflow:double d =1e308;
System.out.print("overflow produces infinity:");
System.out.printin(d +"*10=="+ d*10);// An example of gradual underflow:
d =1e-305* Math.PI;
System.out.print("gradual underflow: "+ d +"\n ");for(int i =0; i <4; i++)
System.out.print(" "+(d /=100000));
System.out.printin();// An example of NaN:
System.out.print("0.0/0.0 is Not-a-Number:");
d =0.0/0.0;
System.out.printin(d);//An example of inexact results and rounding:
System.out.print("inexact results with float:");for(int i =0; i <100; i++){float z =1.0f/ i;if(z * i !=1.0f)
System.out.print(" "+ i);}
System.out.printin();// Another example of inexact results and rounding:
System.out.print("inexact results with double:");for(int i =0; i <100; i++){double z =1.0/ i;if(z * i !=1.0)
System.out.print(" "+ i);}
System.out.printin();// An example of cast to integer rounding:
System.out.print("cast to int rounds toward 0:");
d =12345.6;
System.out.printin((int)d +" "+(int)(-d));}}
这个程序会产生下面的输出:
overflow produces infinity:1.0e+308*10==Infinity
gradual underflow:3.141592653589793E-3053.1415926535898E-3103.141592653E-3153.142E-3200.00.0/0.0 is Not-a-Number: NaN
inexact results with float:04147556182839497
inexact results with double:04998
cast to int rounds toward 0:12345-12345
classPoint{int x, y;Point(){ System.out.printin("default");}Point(int x,int y){this.x = x;this.y = y;}/* A Point instance is explicitly created at
class initialization time: */static Point origin =newPoint(0,0);/* A String can be implicitly created by a *
operator: */public String toString(){return"("+ x +","+ y +")"}}classTest{publicstaticvoidmain(String[] args){/* A Point is explicitly created
using newlnstance: */
Point p = null;try{
p =(Point)Class.forName("Point").newlnstance();}catch(Exception e){
System.out.printin(e);}/* An array is implicitly created
by an array constructor: */
Point a[]={newPoint(0,0),newPoint(1,1)};/* Strings are implicitly created
by + operators: */
System.out.prihtln("p: "+ p);
System.out.printin("a: { "+ a[0]+", "+ a[l]+" }");/* An array is explicitly created
by an array creation expression: */
String sa[]=newString[2];
sa[0]="he"; sa[l]="llo";
System.out.printIn(sa[0]+ sa [1]);}}
边界为 I 1 α − I 1 n I{_1} α- I{_1}n I1α−I1n 的类型变量X的成员,是由位于类型变量声明处的交集类型 I 1 α − I 1 n I{_1} α- I{_1}n I1α−I1n 的成员构成的。
类型变量的成员
package TypeVarMembers;classC{publicvoidmCPublic(){}protectedvoidmCProtected(){}voidmCPackage(){}privatevoidmCPrivate(){}}interfaceI{voidmI();}classCTextendsCimplementsI{publicvoidmI(){}}classTest{<T extendsC& I>voidtest(T t){
t.mI();// OK
t.mCPublic();// OK
t.mCProtected();// OK
t.mCPackage();// OK
t.mCPrivate();// Compile-time error}}
参数化类型是形式为 C < T 1 , … , T n > CC<T1,…,Tn>的类或接口,其中C是泛型名,而 < T 1 , … , T n > <T1,…,Tn>是表示该泛型的特定参数化形式的类型引元列表。
泛型带有类型参数 F 1 , … , F n F_{1} , … ,F_{n} F1,…,Fn,并且这些类型参数还带有相应的边界 B 1 , … , B n B_{1} , … ,B_{n} B1,…,Bn 。参数化类型的每个类型引元 T 1 T_{1} T1 都限定在相应的边界中列出的所有类型的任意子类型的范围内。也就是说,对于 B i B_{i} Bi中的每一个边界类型S, T 1 T_{1} T1是 S [ F 1 : = T 1 , … , F n : = T n ] S[F_{1}:=T_{1},… ,F_{n}:=T_{n}] S[F1:=T1,…,Fn:=Tn] 的子类型。
如果满足下列条件,那么参数化类型 C < T 1 , … , T n > CC<T1,…,Tn> 就是良构的: 1.C是泛型名。 2.类型引元的数量与在C的泛化声明中的类型参数的数量相同。 3.当经过捕获转换并产生类型 C < X 1 , … , X n > CC<X1,…,Xn> 后,对于每一个在 B i B_{i} Bi中的边界类型S,每一个类型引元 X i X_{i} Xi, 都是 S [ F 1 : = X 1 , … , F n : = X n ] S[F_{1}:=X_{1},… ,F_{n}:=X_{n}] S[F1:=X1,…,Fn:=Xn] 的子类型。
在下列规则(其中 <: 表示子类型)的 自反和传递闭包的范围内,如果 T 2 T_{2} T2所表示的类型集可证是 T 1 T_{1} T1所表示的类型集的子集,那么我们就认为类型引元 T 1 T_{1} T1包含另一个类型引元 T 2 T_{2} T2,记为 T 2 T_{2} T2 <= T 1 T_{1} T1:
?extendsT<=?extendsS 如果 T<: S
?extendsT<=??super T<=?super S 如果 S<:T
?super T<=??super T<=?extendsObject
T<=T
T<=?extendsT
T<=?super T
通配符与现有建立起来的类型理论之间的关系非常有趣,这里简要描述一下:通配符是存在类型(existential type)的严格形式,对于泛型声明G, G>大体上相当于 Some X<:B. G。
假设C是具有类型参数 A 1 , … , A n A_{1} , … ,A_{n} A1,…,An的泛化类或接口声明,而 C < T 1 , … , T n > CC<T1,…,Tn>是对C的参数化版 本,其中1<=i<=n, T 1 T_{1} T1是类型(而不是通配符),那么: 1.如果m是C中的成员或构造器声明,其声明的类型是T, 那么,m在 C < T 1 , … , T n > CC<T1,…,Tn>中的类型就是 T [ A 1 : = T 1 , … , A n : = T n ] T[A_{1}:=T_{1},… ,A_{n}:=T_{n}] T[A1:=T1,…,An:=Tn] 。 2.如果m是D中的成员或构造器声明,其中D是C扩展的类或实现的接口,并且如果 D < U 1 , … , U n > DD<U1,…,Un>是 C < T 1 , … , T n > CC<T1,…,Tn> 对应于D的超类型,那么,m在 C < T 1 , … , T n > CC<T1,…,Tn>中的类型就是 m在 D < U 1 , … , U n > DD<U1,…,Un>中的类型。
如果C的参数化版本中任意一个或多个类型引元是通配符,那么: 1.在 C < T 1 , … , T n > CC<T1,…,Tn>中的域、方法和构造器的类型就是在 C < T 1 , … , T n > CC<T1,…,Tn>的捕获转换中的域、方法和构造器的类型。 2.如果D是C中的类或接口(可能是泛化的)声明,那么D在 C < T 1 , … , T n > CC<T1,…,Tn>中的类型就是 D,其中,如果D是泛化的,那么所有类型引元都是无界通配符。
类型擦除是一种映射,即将类型(可能包含参数化类型和类型变量)映射为(不再是参数化类型或类型变量的)类型。我们用|T|来表示类型T的擦除。擦除映射的定义如下: 1.参数化类型 G < T 1 , … , T n > GG<T1,…,Tn>的擦除是|G| 2.嵌套类型T.C的擦除是|T|.C 3.数组类型T[]的擦除是|T| [] 4.类型变量的擦除是其最左边界的擦除 5.每种其他类型的擦除都是该类型自身
classCell<E>{
E value;Cell(E v){ value = v;}
E get (){return value;}voidset(E v){ value = v;}publicstaticvoidmain(String[] args){
Cell x =newCell<String>("abc");
System.out.println(x.value);// OK,has type Object
System.out.println(x.get());// OK, has type Object
x.set("def");// unchecked warning}}
原生类型和继承
import java.util.*;classNonGeneric{
Collection<Number>myNumbers(){return null;}}abstractclassRawMembers<T>extendsNonGenericimplementsCollection<String>{static Collection<NonGeneric> eng =newArrayList<NonGeneric>();publicstaticvoidmain(String[] args){
RawMembers rw = null;
Collection<Number> cn = rw.myNumbers();// OK
Iterator<String> is = rw.iterator();// Unchecked warning
Collection<NonGeneric> enn = rw.eng;// OK, static member }}
原生类型与通配符紧密相关,两者都是基于既存类型的。原生类型可以被认为是为了能够与遗留代码交互而故意设计出来的类型规则并不完善的通配符。在历史上,原生类型先于通配符而产生,它们首先被引入到了 GJ中,在Gilad Bracha、Martin Odersky、David Stoutamire 和 Philip Wadler 撰写的发表于 Proceedings of the ACM Conference on Object- Oriented Programming, Systems, Languages and Application ( OOPSLA 98 ) , October 1998 上的 论文 Making the future safe fbr the past: Adding Genericity to the Java Programming Language中对它们进行了描述。
交集类型
交集类型的形式为 T 1 T_{1} T1 & …& T n T_{n} Tn(n > 0),其中 T 1 T_{1} T1( 1 ≤ i ≤ n 1\leq i \leq n 1≤i≤n) 是类型表达式。
交集类型可以从类型参数边界和类型转换表达式派生,它们还可以在捕获转换和最低上边界计算的过程中产生。
交集类型的值是这样的对象:对于每一个 T i T_{i} Ti ( 1 ≤ i ≤ n 1\leq i \leq n 1≤i≤n) 类型来说,这些对象都是它的值。
每一个交集类型 T 1 T_{1} T1 & …& T n T_{n} Tn 都可以归纳为一个概念类或接口,用来标识交集类型的成员,就像下面这样: 1.对于每一个类型 T i T_{i} Ti ( 1 ≤ i ≤ n 1\leq i \leq n 1≤i≤n) ,假设 C i C_{i} Ci是最具体的类或数组类型,使得 T i T_{i} Ti <: C i C_{i} Ci, 那么必然有某个 C k C_{k} Ck使得对于任意的 i ( 1 ≤ i ≤ n 1\leq i \leq n 1≤i≤n)都有 C k C_{k} Ck <: C i C_{i} Ci,否则就会产生编译时错误。 2.对于 1 ≤ j ≤ n 1\leq j \leq n 1≤j≤n,如果 T j T_{j} Tj是类型变量,那么就使得 T j ′ T_{j}^{'} Tj′是一个接口,其成员与 T j T_{j} Tj的 public 成员相同;否则,如果 T j T_{j} Tj是接口,那么就使得 T j ′ T_{j}^{'} Tj′为 T j T_{j} Tj。 3.如果 C k C_{k} Ck是Object, 就归纳为概念接口,否则,就用 C k C_{k} Ck的超类归纳出概念类。这个类或接口的直接超接口是 T 1 ′ T_{1}^{'} T1′ , …, T n ′ T_{n}^{'} Tn′,并且是在交集类型出现的包中声明的。
给定泛型声明 C < F 1 , … , F n > CC<F1,…,Fn>(n>0),原生类型C 的直接超类型为如下所有类型: 1.原生类型C的直接超类。 2.原生类型C的直接超接口。 3.Object类型,如果 C < F 1 , … , F n > CC<F1,…,Fn>是没有任何直接超接口的泛化接口类型。
给定泛型声明 C < F 1 , … , F n > CC<F1,…,Fn>(n>0),泛型 C < F 1 , … , F n > CC<F1,…,Fn>的直接超类型为如下所有类型: 1. C < F 1 , … , F n > CC<F1,…,Fn>的直接超类。 2. C < F 1 , … , F n > CC<F1,…,Fn>的直接超接口。 3.Object类型,如果 C < F 1 , … , F n > CC<F1,…,Fn>是没有任何直接超接口的泛化接口类型。 4.原生类型C。
给定泛型声明 C < F 1 , … , F n > CC<F1,…,Fn>(n>0),参数化类型 C < F 1 , … , F n > CC<F1,…,Fn>的直接超类型为如下所有类型,这里每个 T i T_{i} Ti ( 1 ≤ i ≤ n 1\leq i \leq n 1≤i≤n)都是一种类型: 1. D < U 1 0 , … , U k 0 > DD<U10,…,Uk0>,其中 D < U 1 , … , U k > DD<U1,…,Uk>是泛型,并且是泛型 C < T 1 , … , T n > CC<T1,…,Tn> 的直接超类型,而 0是替换 [ F 1 : = T 1 , … , F n : = T n ] [F_{1}:=T_{1},…,F_{n}:=T_{n}] [F1:=T1,…,Fn:=Tn]的。 2. C < S 1 , … , S n > CC<S1,…,Sn> ,其中 S i S_{i} Si包含 T i T_{i} Ti ( 1 ≤ i ≤ n 1\leq i \leq n 1≤i≤n)。 3.Object类型,如果 C < F 1 , … , F n > CC<F1,…,Fn>是没有任何直接超接口的泛化接口类型。 4.原生类型C。
给定泛型声明 C < F 1 , … , F n > CC<F1,…,Fn> ( n>0 ),如果参数化类型 C < R 1 , … , R n > CC<R1,…,Rn>中至少有一个 R i R_{i} Ri ( 1 ≤ i ≤ n 1\leq i \leq n 1≤i≤n)是通配符类型引元,那么其直接超类型就是参数化类型 C < X 1 , … , X n > CC<X1,…,Xn> 的直接超类型,而 C < X 1 , … , X n > CC<X1,…,Xn> 是将捕获转换应用于 C < R 1 , … , R n > CC<R1,…,Rn> 后所产生的结果。
交集类型 T 1 T_{1} T1 & …& T n T_{n} Tn的直接超类型是 T i T_{i} Ti ( 1 ≤ i ≤ n 1\leq i \leq n 1≤i≤n)。
一个引用类型集的最低上边界(缩写lub)就是比其他任何共享超类型更具体的共享超类型(也就是说,没有任何其他共享超类型是最低上边界的子类)。这个类型,lub ( U k , … , U k U_{k},…,U_{k} Uk,…,Uk) 是按如下规则确定的。
如果k=1, 那么lub就是该类型自身:lub (U) =U。 否则:
对每一个 U i U_{i} Ui ( 1 ≤ i ≤ n 1\leq i \leq n 1≤i≤n): 设ST(U)是 U i U_{i} Ui的超类型集 设EST( U i U_{i} Ui)是 U i U_{i} Ui的被擦除的超类型集,即: EST ( U i U_{i} Ui)= { |w| | winST ( U i U_{i} Ui) },其中 |w| 是 w 的擦除。 计算被擦除的超类型集的原因是为了处理这样的情况:类型集中包含了某个泛型的若 干个有区别的参数化版本。 例如,给定 List和 List, 直接求 ST ( List) = { List, Collection, Object }和 ST(List的交集将会产生 { Object },而这将掩盖一个事实,即可以将上边界安全地设定为List。 相反,求 EST(List) = { List, Collection, Object }和 EST(List)=( List, Collection, Object }的交集,将会产生 {List, Collection, Object}, 使得我们最终可以找到List>。
设EC是 U 1 , … , U k U_{1},…,U_{k} U1,…,Uk被擦除的候选集,即所有EST ( U i U_{i} Ui)( 1 ≤ i ≤ n 1\leq i \leq n 1≤i≤n )集的交集。
设MEC是最小的 U 1 , … , U k U_{1},…,U_{k} U1,…,Uk被擦除的候选集,即MEC = {v | v属于EC,对于任意 w ≠ \not= = v,不存在可w <: v } 因为我们在寻求推断出更准确的类型,所以我们希望过滤掉所有是其他候选类型的超类型的候选类型。这正是计算MEC所要完成的任务。在上面的示例中,EC={List, Collection, Object}, 因此MEC={List}。下一步将恢复MEC中被擦除类型的类型引元。
对MEC的任何是泛型的元素G: 设G相关的参数化版本为Relevant (G),即: Relevant (G) = { v | 1 ≤ i ≤ k 1\leq i \leq k 1≤i≤k : v 属于 ST ( U i U_{i} Ui) 且 V=G<…>} 在上面的示例中,MEC中仅有的泛化元素是List, 并且Inv ( List)= { List, List} 。现在我们寻求找到同时包含String 和 Object的 List 类型引元。 这是通过下面定义的“最少包含参数化版本(lep)”操作来实现的。第一行在一个集合上,例如Relevant (List),将lcp()定义为在该集合的元素列表上的操作。下一行将在这种列表上的操作定义为在列表元素上两两消减。第三行是在参数化类型对上的 lcp()的定义,这又依赖于"最小包含类型引元(Icta)"这一概念,其中lcta()为所有可能的情况进行了定义。 设G的候选参数化版本为Candidate (G),即泛型G的最具体参数化版本,它包含G的所有相关参数化版本。 Candidate (G)= lcp (Relevant (G)) 其中lcp(),即最小包含调用,为: (1) lcp (s)=lcp ( e i , … , e n e_{i},…,e_{n} ei,…,en)其中 e i e_{i} ei( 1 ≤ i ≤ k 1\leq i \leq k 1≤i≤k)在 s 中 (2) lcp ( e i , … , e n e_{i},…,e_{n} ei,…,en)= lcp (lcp ( e 1 , e 2 e_{1},e_{2} e1,e2) , e 3 , … , e n e_{3},…,e_{n} e3,…,en) (3) lcp ( G < X 1 , … , X n > GG<X1,…,Xn>, G < Y 1 , … , Y n > GG<Y1,…,Yn>) = G X 1 X_{1} X1, Y 1 Y_{1} Y1),…,Icta ( X n X_{n} Xn, Y n Y_{n} Yn) > (4) lcp( G < X 1 , … , X n > GG<X1,…,Xn>) = G< lcta ( X i X_{i} Xi),…,Icta ( X n X_{n} Xn) > 其中lcta(),即最小包含类型引元,为:(假设U和V是类型) (1) Icta(U, V)= U ,如果 U = V,否则为 ?extends lub(U, V) (2) Icta(U, ? extends V) = ? extends lub (U, V) (3) Icta(U, ? super V) = ? super glb (U, V) (4) Icta (? extends U, ? extends V)= ? extends lub(U, V) (5) Icta (? extends U, ? super V)= U, 如果 U=V,否则为? (6) Icta (? super U, ? super V)= ? super gib (U, V) (7) Icta (u) = ? 如果 u 的上边界是 Object, 否则为? extends lub(U, Object) 其中glb()如在第5.1.10节中的定义。
设 lub( U 1 , … , U k U_{1},…,U_{k} U1,…,Uk)为: Best ( W i W_{i} Wi) &…&Best ( W r W_{r} Wr) 其中 W i W_{i} Wi( 1 ≤ i ≤ r 1\leq i \leq r 1≤i≤r)都是MEC,即 U 1 , … , U k U_{1},…,U_{k} U1,…,Uk最小擦除候选集的元素; 并且,如果这些元素中只要有泛化的,就使用候选参数化版本(以便恢复类型引元) 如果 x 是泛化的,则 Best (x)= Candidate (x);否则 Best (x) = x。
严格地讲,这个Iub()函数只能得到近似的最小上边界。形式化地讲,可能存在某个其他类型T,使得所有 U 1 , … , U k U_{1},…,U_{k} U1,…,Uk都是T的子类型,并且T是lub( U 1 , … , U k U_{1},…,U_{k} U1,…,Uk)的子类型。但是,Java编程语言的编译器必须按照上面指定的方式实现lub()。
Task not serializable是Spark开发过程最令人头疼的问题之一,这里记录下出现这个问题的两个实例,一个是自己遇到的,另一个是stackoverflow上看到。等有时间了再仔细探究出现Task not serialiazable的各种原因以及出现问题后如何快速定位问题的所在,至少目前阶段碰到此类问题,没有什么章法
1.
package spark.exampl
mysql 查看当前正在执行的操作,即正在执行的sql语句的方法为:
show processlist 命令
mysql> show global status;可以列出MySQL服务器运行各种状态值,我个人较喜欢的用法是show status like '查询值%';一、慢查询mysql> show variab
1. 只有Map任务的Map Reduce Job
File System Counters
FILE: Number of bytes read=3629530
FILE: Number of bytes written=98312
FILE: Number of read operations=0
FILE: Number of lar
import java.util.LinkedList;
import java.util.List;
import ljn.help.*;
public class BTreeLowestParentOfTwoNodes {
public static void main(String[] args) {
/*
* node data is stored in
本文介绍Java API 中 Date, Calendar, TimeZone和DateFormat的使用,以及不同时区时间相互转化的方法和原理。
问题描述:
向处于不同时区的服务器发请求时需要考虑时区转换的问题。譬如,服务器位于东八区(北京时间,GMT+8:00),而身处东四区的用户想要查询当天的销售记录。则需把东四区的“今天”这个时间范围转换为服务器所在时区的时间范围。
入口脚本
入口脚本是应用启动流程中的第一环,一个应用(不管是网页应用还是控制台应用)只有一个入口脚本。终端用户的请求通过入口脚本实例化应用并将将请求转发到应用。
Web 应用的入口脚本必须放在终端用户能够访问的目录下,通常命名为 index.php,也可以使用 Web 服务器能定位到的其他名称。
控制台应用的入口脚本一般在应用根目录下命名为 yii(后缀为.php),该文