SINCE Java 5, generics have been a part of the language. Before generics, you had to cast every object you read from a collection. If someone accidentally inserted an object of the wrong type, casts could fail at runtime. With generics, you tell the compiler what types of objects are permitted in each collection. The compiler inserts casts for you automatically and tells you at compile time if you try to insert an object of the wrong type. This results in programs that are both safer and clearer, but these benefits, which are not limited to collections, come at a price. This chapter tells you how to maximize the benefits and minimize the complications.
A class or interface whose declaration has one or more type parameters is a generic class or interface 声明一个或多个类型参数(type parameters)的来或者接口成为范型类或范型接口
Generic classes and interfaces are collectively known as generic types. 范型类和接口统称为范型(generic types)
Each generic type defines a set of parameterized types, which consist of the class or interface name followed by an angle-bracketed list of actual type parameters corresponding to the generic type’s formal type parameters [JLS, 4.4, 4.5]. 每一个范型定义一系列参数化类型(parameterized types),构成格式为:类或接口名称,然后是一个在尖括号内的范型形式参数的实际类型参数列表
Finally, each generic type defines a raw type, which is the name of the generic type used without any accompanying type parameters [JLS, 4.8]. 最后,每个范型对应定义一个原生态类型,一个与去掉类型参数的范型。List对应List
As mentioned throughout this book, it pays to discover errors as soon as possible after they are made, ideally at compile time. 作为本书的典型思考方式,错误应该在发生之后尽快被发现,理想的是在编译的时候。(禁止使用原生态类型的理论依据)
While the prospect of accidentally inserting a coin into a stamp collection may appear far-fetched, the problem is real. For example, it is easy to imagine putting a BigInteger into a collection that is supposed to contain only BigDecimal instances. 虽然,将一个coin类插入到一个stamp的集合的意外有点扯,但是这类问题是存在的。比如,很容易将一个BigInteger插入到BigDecimal集合中。
As noted earlier, it is legal to use raw types (generic types without their type parameters), but you should never do it. If you use raw types, you lose all the safety and expressiveness benefits of generics.Given that you shouldn’t use them, why did the language designers permit raw types in the first place? For compatibility. 如上所述,使用原生态类型是合法的,但是永远不要使用。一旦你使用原生态类型,就失去了范型的安全性和可读性的收益。既然不应该使用原生态类型,为什么语言设计层面允许使用,是为了兼容性。
s a consequence, you lose type safety if you use a raw type such as List, but not if you use a parameterized type such as List
If you want to use a generic type but you don’t know or care what the actual type parameter is, you can use a question mark instead. For example, the unbounded wildcard type for the generic type Set is Set> (read “set of some type”). It is the most general parameterized Set type, capable of holding any set. 如果你想使用范型,但是你不知道或者不关心实际的类型参数是什么,你可以无限制的通配符类型。(unbounded wildcard types)这是最普通的参数化类型,可以持有任何集合。
What is the difference between the unbounded wildcard type Set> and the raw type Set? Does the question mark really buy you anything? Not to belabor the point, but the wildcard type is safe and the raw type isn’t. You can put any element into a collection with a raw type, easily corrupting the collection’s type invariant (as demonstrated by the unsafeAdd method on page 119); you can’t put any element (other than null) into a Collection>.
There are a few minor exceptions to the rule that you should not use raw types. You must use raw types in class literals. The specification does not permit the use of parameterized types (though it does permit array types and primitive types) [JLS, 15.8.2]. In other words, List.class, String[].class, and int.class are all legal, but List.class and List>.class are not. 对于不要使用原生态类型的规则有两个例外。你必须使用原生态类型在类的字面值。这些例外情况不允许使用参数化类型(虽然允许数组和原始类型),换句话说 List.class, String[].class, and int.class 都是合法的,但是List.class and List>.class 是不合法的。
A second exception to the rule concerns the instanceof operator. Because generic type information is erased at runtime, it is illegal to use the instanceof operator on parameterized types other than unbounded wildcard types. The use of unbounded wildcard types in place of raw types does not affect the behavior of the instanceof operator in any way. In this case, the angle brackets and question marks are just noise. This is the preferred way to use the instanceof operator with generic types:
Eliminate every unchecked warning that you can. 解决每一个非检查警告。
If you can’t eliminate a warning, but you can prove that the code that provoked the warning is typesafe, then (and only then) suppress the warning with an @SuppressWarnings("unchecked") annotation. 如果你不能限制一个警告,但是你能确定引起这个警告的代码是类型安全的。在只有在这种情况下,使用@SuppressWarnings("unchecked") 注解
Always use the SuppressWarnings annotation on the smallest scope possible. 应该在尽量小的范围使用@SuppressWarnings("unchecked")注解
Every time you use a @SuppressWarnings("unchecked") annotation, add a comment saying why it is safe to do so. 每次使用@SuppressWarnings("unchecked")注解,添加一段注释说明为什么这么做是安全的。
Summary
In summary, unchecked warnings are important. Don’t ignore them. Every unchecked warning represents the potential for a ClassCastException at runtime. Do your best to eliminate these warnings. If you can’t eliminate an unchecked warning and you can prove that the code that provoked it is typesafe, suppress the warning with a @SuppressWarnings("unchecked") annotation in the narrowest possible scope. Record the rationale for your decision to suppress the warning in a comment. 总的来说,非检查警告非常重要。不要忽视它们。每个非检查警告都代表着一个运行时类型转化类长的可能性。尽你最大的可能去限制这些警告。如果不能消除警告,同时可以证明引起警告的代码是类型安全的就可以在尽可能小的范围加上@SuppressWarnings("unchecked")注解。要用注释把禁止警告的原因记录下来。
Item 28: Prefer lists to arrays
列表优先于数组
Arrays differ from generic types in two important ways. First, arrays are covariant. This scary-sounding word means simply that if Sub is a subtype of Super, then the array type Sub[] is a subtype of the array type Super[]. Generics, by contrast, are invariant: for any two distinct types Type1 and Type2, List is neither a subtype nor a supertype of List You might think this means that generics are deficient, but arguably it is arrays that are deficient. 数组和范型有两个重要的不同点。首先,数组是协变的,这听起来很可怕,但是很简单它表示,如果Sub是Super的子类,则Sub[]是Supper[]的子类。相反范型是不变的。对于任意两种不同的类型Type1和Type2,List即不是List的子类也不是他的父类。你可能会想范型是有缺陷的,但是也可以说明数组才是有缺陷的。
// Fails at runtime!
Object[] objectArray = new Long[1];
objectArray[0] = "I don't fit in"; // Throws ArrayStoreException
but this one is not:
// Won't compile!
List ol = new ArrayList(); // Incompatible types
ol.add("I don't fit in");
以上代码说明应该在尽可能早点的时候发现,并抛出异常。
The second major difference between arrays and generics is that arrays are reified [JLS, 4.7]. This means that arrays know and enforce their element type at runtime. As noted earlier, if you try to put a String into an array of Long, you’ll get an ArrayStoreException. Generics, by contrast, are implemented by erasure [JLS, 4.6]. This means that they enforce their type constraints only at compile time and discard (or erase) their element type information at runtime. Erasure is what allowed generic types to interoperate freely with legacy code that didn’t use generics (Item 26), ensuring a smooth transition to generics in Java 5. 第二个主要的区别是数组是具体话的。这表示数组在运行时才知道,并检查它们的元素类型约束。如上所述,如果你想Long数组中put一个String,你会得到一个ArrayStoreException异常。相比之下范型是通过类型擦除实现的。这表示范型强制要求它们的类型限制仅在编译期,并且在运行时擦除它们的元素类型信息。擦除就是范型可以与没有使用范型的代码相互作用。保证到Java5是一个平滑的过度。
Because of these fundamental differences, arrays and generics do not mix well. For example, it is illegal to create an array of a generic type, a parameterized type, or a type parameter. new List[], new List[], new E[]. All will result in generic array creation errors at compile time. 由于以上不同,数组和范型不能很好的结合使用。创建一个范型数组,参数化类型数组,或者一个类型参数数组都是非法的。new List[], new List[], new E[].都会在编译期产生一个范型数组创建错误。
Why is it illegal to create a generic array? Because it isn’t typesafe. 为什么创建创建范型数组是非法的,因为那不是类型安全的。(List[]如果合法,范型是通过类型擦除实现的,所以在编译期,会变成List[],这个时候赋值给List[]一个List元素是合法的,但是范型在取值时候会做强制类型转换,会抛出异常)
Types such as E, List, and List are technically known as < types [JLS, 4.7]. Intuitively speaking, a non-reifiable type is one whose runtime representation contains less information than its compile-time representation. Because of erasure, the only parameterized types that are reifiable are unbounded wildcard types such as List> and Map,?> (Item 26). It is legal, though rarely useful, to create arrays of unbounded wildcard types. E, List, and List这些类型在技术上统称为不可具体化类型。通俗的说,不可具体化类型是一种在运行时包含的信息比编译期少的信息的类型。由于类型擦除,唯一具体话的参数化类型是无界通配符,例如List> and Map,?>。创建一个无界通配符的数组是合法的,但是不常见
It also means that you get confusing warnings when using varargs methods (Item 53) in combination with generic types. This is because every time you invoke a varargs method, an array is created to hold the varargs parameters.
In summary, arrays and generics have very different type rules. Arrays are covariant and reified; generics are invariant and erased. As a consequence, arrays provide runtime type safety but not compile-time type safety, and vice versa for generics. As a rule, arrays and generics don’t mix well. If you find yourself mixing them and getting compile-time errors or warnings, your first impulse should be to replace the arrays with lists. 总的来说,数组和范型有不同的类型规则。数组是协变的具体话的,范型是不可变的和擦除的。因此数组提供了运行时的类型安全,但没有编译时的类型安全。范型则正好相反。作为一个规则,数组和范型不能很好的混合工作。如果混合使用它们,会得到编译期错误或者警告,最应该先想到的解决办法是用列表替换数组。
Item 29: Favor generic types
优先考虑范型
There are two reasonable ways to solve it. 有两个可以绕过范型数组非法的方法。
elements = new E[DEFAULT_INITIAL_CAPACITY]; // error: generic array creation
The first solution directly circumvents the prohibition on generic array creation: create an array of Object and cast it to the generic array type.
第一个解决方法,声明Object数组之后强转。但是不是类型安全的。
elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY]; // warning: [unchecked] unchecked cast
The compiler may not be able to prove that your program is typesafe, but you can. You must convince yourself that the unchecked cast will not compromise the type safety of the program. The array in question (elements) is stored in a private field and never returned to the client or passed to any other method. The only elements stored in the array are those passed to the push method, which are of type E, so the unchecked cast can do no harm. 编译器不能保证你的程序是类型安全的,但是你可以。你必须说服自己,没检查的转换不会引起类型安全问题。以上问题中的数组是作为私有字段存储的,并且不会被return,或者被传递到其他任何方法中。这个数组中存储的唯一类型是通过push方法传进来的元素,而这个方法限制了参数类型是E,所以这个强制类型转换是不会造成伤害的。(整体上为了确认会不会加进来其他类型元素,通过跟踪变量的程序引用确认,可以通过@SuppressWarnings("unchecked"))
The second way to eliminate the generic array creation error in Stack is to change the type of the field elements from E[] to Object[].
第二种方法是将elements的声明从E[]变为Object[]
Both techniques for eliminating the generic array creation have their adherents. The first is more readable: the array is declared to be of type E[], clearly indicating that it contains only E instances. It is also more concise: in a typical generic class, you read from the array at many points in the code; the first technique requires only a single cast (where the array is created), while the second requires a separate cast each time an array element is read. Thus, the first technique is preferable and more commonly used in practice. It does, however, cause heap pollution (Item 32): the runtime type of the array does not match its compile-time type (unless E happens to be Object). This makes some programmers sufficiently queasy that they opt for the second technique, though the heap pollution is harmless in this situation. 这两种方法有他们各自的拥护者。第一种更加易读,数组声明为E[],清晰,他们只包含E类型的实例。简洁,在一个典型的范型类,你可能会从多个地方读取数组的值,第一种技术只需要一个转换(数组创建的时候),然而第二种需要很多分开的类型转换在读取数组元素的时候。因此第一种方法更加受欢迎,在实践中使用的更加广泛。然而第一种方法会造成堆污染:数组的运行时类型和编译时类型不同。这使得很多开发者觉得不适应,所以他们选择第二种方式,虽然堆污染在这种情况下基本没有实质性的伤害。
Summary
In summary, generic types are safer and easier to use than types that require casts in client code. When you design new types, make sure that they can be used without such casts. This will often mean making the types generic. If you have any existing types that should be generic but aren’t, generify them. This will make life easier for new users of these types without breaking existing clients (Item 26). 总的来说,范型更加安全也更加易于使用相比于需要在客户端进行类型转换的。设计新的类型时,确保他们在使用时不需要类型转换。这通常代表着使类型变成范型。只要有时间,就把需要范型化的类型范型化。这将使生命周期更加清晰,对于新的使用者,并且不会坡缓现有客户端。
Favor generic methods
优先考虑范型方法
static Set merge(Set set1, Set set2) {
Set set = new HashSet();
set.addAll(set1);
set.addAll(set2);
return set;
}
In summary, generic methods, like generic types, are safer and easier to use than methods requiring their clients to put explicit casts on input parameters and return values. Like types, you should make sure that your methods can be used without casts, which often means making them generic. And like types, you should generify existing methods whose use requires casts. This makes life easier for new users without breaking existing clients (Item 26). 总的来说,范型方法,像范型类型一样,相比于需要客户端自己进行入参或者返回值的强制类型转换,都是更安全,更容易使用的。就像类型一样,你需要确保你的方法可以不需要转型直接使用,这一般意义上代表着使用范型。并且像类型一样,还应该将现有方法范型化,使新的用户使用起来更佳容易,并且不会破坏现有客户端。
Item 31: Use bounded wildcards to increase API flexibility
使用有界通配符提高接口的灵活性
List 和 List extend Number>区别是第一个可以多个元素不同,即多个元素是Number的不同子类。第二个是Number的相同子类,在编译期限制了元素必须相同。
public class Stack {
public Stack();
public void push(E e);
public E pop();
public boolean isEmpty();
}
// pushAll method without wildcard type - deficient!
public void pushAll(Iterable) {
for (E e : src)
push(e);
}
Stack numberStack = new Stack<>();
Iterable integers = ... ;
numberStack.pushAll(integers);
StackTest.java:7: error: incompatible types: Iterable
cannot be converted to Iterable
numberStack.pushAll(integers);
由于范型的不可变性,即Integer is subclass of Number, but Iterable not subclass Iterable. 将上述代码中Iterable修改为Iterable extends E>就可以了
For maximum flexibility, use wildcard types on input parameters that represent producers or consumers. 为了最大的灵活性,要在表示生产者或者消费者的输入参数上使用通配符类型。
PECS stands for producer-extends, consumer-super, known as Get and Put Principle Do not use bounded wildcard types as return types. 不要使用有界通配符作为返回值类型
If the user of a class has to think about wildcard types, there is probably something wrong with its API. 如果一个类的用户必须思考通配符类型的内容,表示API可能有些问题。
public static Set union(Set extends E> s1, Set extends E> s2)
Set integers = Set.of(1, 3, 5);
Set doubles = Set.of(2.0, 4.0, 6.0);
Set numbers = union(integers, doubles);
Set numbers = union(integers, doubles);
Prior to Java 8
there will be a long error message like this
Union.java:14: error: incompatible types
Set numbers = union(integers, doubles);
^
required: Set
found: Set
where INT#1,INT#2 are intersection types:
INT#1 extends Number,Comparable extends INT#2>
INT#2 extends Number,Comparable>
If the compiler doesn’t infer the correct type, you can always tell it what type to use with an explicit type argument.
// Explicit type parameter - required prior to Java 8
Set numbers = Union.union(integers, doubles);
after Java 8
the type inference rules are more clever, but Integer And Double is implements Comparable. So must do like [Prior to Java 8]
if a type parameter appears only once in a method declaration, replace it with a wildcard.
public static void swap(List> list, int i, int j) {
swapHelper(list, i, j);
}
// Private helper method for wildcard capture
private static void swapHelper(List list, int i, int j) {
list.set(i, list.set(j, list.get(i)));
}
you can use like above code to avoid the rule, which List> can add null only.
summary
In summary, using wildcard types in your APIs, while tricky, makes the APIs far more flexible. If you write a library that will be widely used, the proper use of wildcard types should be considered mandatory. Remember the basic rule: producer-extends, consumer-super (PECS). Also remember that all comparables and comparators are consumers. 总的来说,使用通配符类型在API比较复杂,但是可以API更加灵活。如果你编写一个即将被广泛应用的类库,一定要考虑广泛的使用通配符。记住一个基本原则:PECS。同时记住所有comparables and comparators都是消费者。
Item 32: Combine generics and varargs judiciously
谨慎将范型和可变参数一起使用
Varargs methods (Item 53) and generics were both added to the platform in Java 5. 可变参数方法和范型都是在java 5的时候添加的。
the SafeVarargs annotation constitutes a promise by the author of a method that it is typesafe. java 7 之后出现了SafeVarargs注解,这个注解由方法的作者保证类型安全。
It is critical that you do not annotate a method with @SafeVarargs unless it actually is safe. So what does it take to ensure this? Recall that a generic array is created when the method is invoked, to hold the varargs parameters. If the method doesn’t store anything into the array (which would overwrite the parameters) and doesn’t allow a reference to the array to escape (which would enable untrusted code to access the array), then it’s safe. In other words, if the varargs parameter array is used only to transmit a variable number of arguments from the caller to the method, which is, after all, the purpose of varargs, then the method is safe.
In Java 8, the annotation was legal only on static methods and final instance methods; in Java 9, it became legal on private instance methods as well. 在java 8中,@SafeVarargs注释只可以在静态方法,final实例方法中使用,在java 9中,也可以使用在私有的实例方法中。(以上修改,总体上为了限制使用在可重写方法上)
In summary, varargs and generics do not interact well because the varargs facility is a leaky abstraction built atop arrays, and arrays have different type rules from generics. Though generic varargs parameters are not typesafe, they are legal. If you choose to write a method with a generic (or parameterized) varargs parameter, first ensure that the method is typesafe, and then annotate it with @SafeVarargs so it is not unpleasant to use.
// Typesafe heterogeneous container pattern - implementation
public class Favorites {
private Map, Object> favorites = new HashMap<>();
public void putFavorite(Class type, T instance) {
favorites.put(Objects.requireNonNull(type), instance);
}
public T getFavorite(Class type) {
return type.cast(favorites.get(type));
}
}
异构容器通过Class>实现
Note, incidentally, that Java’s printf method differs from C’s in that you should use %n where you’d use \n in C. The %n generates the applicable platform-specific line separator, which is \n on many but not all platforms.
java的printf方法和C的不同,应该用%n代替\n,\n在大部分平台好用,但不是所有平台。
The thing to notice is that the wildcard type is nested: it’s not the type of the map that’s a wildcard type but the type of its key. This means that every key can have a different parameterized type: one can be Class, the next Class, and so on. That’s where the heterogeneity comes from. 需要注意的是无界通配符是嵌套的:无界通配符不是map的key的类型。无界通配符表示,每个key可以是不同的参数化类型,一个可能是Class,下一个可能是Class,依此类推。这就是异构名称的由来。
There are two limitations to the Favorites class that are worth noting. First, a malicious client could easily corrupt the type safety of a Favorites instance, by using a Class object in its raw form. The way to ensure that Favorites never violates its type invariant is to have the putFavorite method check that instance is actually an instance of the type represented by type, and we already know how to do this. Just use a dynamic cast: 有两个点需要注意。
public void putFavorite(Class type, T instance) {
favorites.put(Objects.requireNonNull(type), type.cast(instance));
}
There are collection wrappers in java.util.Collections that play the same trick. They are called checkedSet, checkedList, checkedMap, and so forth. 这有一些集合的包装器在java.util.Collections中扮演着参数类型校验的角色。他们是 checkedSet, checkedList, checkedMap等。
The second limitation of the Favorites class is that it cannot be used on a non-reifiable type (Item 28). In other words, you can store your favorite String or String[], but not your favorite List.
In summary, the normal use of generics, exemplified by the collections APIs, restricts you to a fixed number of type parameters per container. You can get around this restriction by placing the type parameter on the key rather than the container. You can use Class objects as keys for such typesafe heterogeneous containers. A Class object used in this fashion is called a type token. You can also use a custom key type. For example, you could have a DatabaseRow type representing a database row (the container), and a generic type Column as its key. 总而言之,集合API说明了范型的一般用法,限制你每个容器只能有固定数目的类型参数。你可以通过将类型参数放在key上而不是容器上来避开这一限制,对于这种类型安全的异构容器,可以用Class对象作为键值。以这种方式使用class对象作为键的方式叫做类型令牌。也可以使用定制的键类型。例如DatabaseRow type 可以使用类型Column作为key
1、网络上现成的资料
格式: sed -i "s/查找字段/替换字段/g" `grep 查找字段 -rl 路径`
linux sed 批量替换多个文件中的字符串
sed -i "s/oldstring/newstring/g" `grep oldstring -rl yourdir`
例如:替换/home下所有文件中的www.admi
对于AJAX应用(使用XMLHttpRequests)来说,向服务器发起请求的传统方式是:获取一个XMLHttpRequest对象的引用、发起请求、读取响应、检查状态码,最后处理服务端的响应。整个过程示例如下:
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange
Hive中的排序语法 2014.06.22 ORDER BY
hive中的ORDER BY语句和关系数据库中的sql语法相似。他会对查询结果做全局排序,这意味着所有的数据会传送到一个Reduce任务上,这样会导致在大数量的情况下,花费大量时间。
与数据库中 ORDER BY 的区别在于在hive.mapred.mode = strict模式下,必须指定 limit 否则执行会报错。
post-commit hook failed (exit code 1) with output:
svn: E155004: Working copy 'D:\xx\xxx' locked
svn: E200031: sqlite: attempt to write a readonly database
svn: E200031: sqlite: attempt to write a