Android-Java-泛型-官方文档走一走

关于泛型,官方有解释,看起来还好:

先看开头几段:

When you take an element out of a Collection, you must cast it to the type of element that is stored in the collection. Besides being inconvenient, this is unsafe. The compiler does not check that your cast is the same as the collection's type, so the cast can fail at run time.

Generics provides a way for you to communicate the type of a collection to the compiler, so that it can be checked. Once the compiler knows the element type of the collection, the compiler can check that you have used the collection consistently and can insert the correct casts on values being taken out of the collection.

Here is a simple example taken from the existing Collections tutorial:

// Removes 4-letter words from c. Elements must be strings
static void expurgate(Collection c) {
    for (Iterator i = c.iterator(); i.hasNext(); )
      if (((String) i.next()).length() == 4)
        i.remove();
}
Here is the same example modified to use generics:

// Removes the 4-letter words from c
static void expurgate(Collection c) {
    for (Iterator i = c.iterator(); i.hasNext(); )
      if (i.next().length() == 4)
        i.remove();
}
When you see the code , read it as "of Type"; the declaration above reads as "Collection of String c." The code using generics is clearer and safer. We have eliminated an unsafe cast and a number of extra parentheses. More importantly, we have moved part of the specification of the method from a comment to its signature, so the compiler can verify at compile time that the type constraints are not violated at run time. Because the program compiles without warnings, we can state with certainty that it will not throw a ClassCastException at run time. The net effect of using generics, especially in large programs, is improved readability and robustness.

To paraphrase Generics Specification Lead Gilad Bracha, when we declare c to be of type Collection, this tells us something about the variable c that holds true wherever and whenever it is used, and the compiler guarantees it (assuming the program compiles without warnings). A cast, on the other hand, tells us something the programmer thinks is true at a single point in the code, and the VM checks whether the programmer is right only at run time.

解释总结:这里提到一点,就是我们在用Collection的时候,难免需要强转元素的类型

image

不仅不方便,同时也是不安全的。而且这个在编译期间不会进行类型检查,就可导致运行时强转失败。而我们修改为泛型以后就可以这样:

image

这个在编译期间就会进行类型错误检查,既方便又安全...就可以这么先简单知道点好处啥的。

再看后面一些段落:

 While the primary use of generics is collections, there are many other uses. "Holder classes," such as WeakReference and ThreadLocal, have all been generified, that is, they have been retrofitted to make use of generics. More surprisingly, class Class has been generified. Class literals now function as type tokens, providing both run-time and compile-time type information. This enables a style of static factories exemplified by the getAnnotation method in the new AnnotatedElement interface:

     T getAnnotation(Class annotationType); 
This is a generic method. It infers the value of its type parameter T from its argument, and returns an appropriate instance of T, as illustrated by the following snippet:
    Author a = Othello.class.getAnnotation(Author.class);
Prior to generics, you would have had to cast the result to Author. Also you would have had no way to make the compiler check that the actual parameter represented a subclass of Annotation.
Generics are implemented by type erasure: generic type information is present only at compile time, after which it is erased by the compiler. The main advantage of this approach is that it provides total interoperability between generic code and legacy code that uses non-parameterized types (which are technically known as raw types). The main disadvantages are that parameter type information is not available at run time, and that automatically generated casts may fail when interoperating with ill-behaved legacy code. There is, however, a way to achieve guaranteed run-time type safety for generic collections even when interoperating with ill-behaved legacy code.

The java.util.Collections class has been outfitted with wrapper classes that provide guaranteed run-time type safety. They are similar in structure to the synchronized and unmodifiable wrappers. These "checked collection wrappers" are very useful for debugging. Suppose you have a set of strings, s, into which some legacy code is mysteriously inserting an integer. Without the wrapper, you will not find out about the problem until you read the problem element from the set, and an automatically generated cast to String fails. At this point, it is too late to determine the source of the problem. If, however, you replace the declaration:

    Set s = new HashSet();
with this declaration:
    Set s = Collections.checkedSet(new HashSet(), String.class);
the collection will throw a ClassCastException at the point where the legacy code attempts to insert the integer. The resulting stack trace will allow you to diagnose and repair the problem.
You should use generics everywhere you can. The extra effort in generifying code is well worth the gains in clarity and type safety. It is straightforward to use a generic library, but it requires some expertise to write a generic library, or to generify an existing library. There is one caveat: You may not use generics (or any other Tiger features) if you intend to deploy the compiled code on a pre-5.0 virtual machine.

If you are familiar with C++'s template mechanism, you might think that generics are similar, but the similarity is superficial. Generics do not generate a new class for each specialization, nor do they permit "template metaprogramming."

There is much more to learn about generics. See the Generics lesson in the Java Tutorials.

解释总结:除了上面的, 泛型还有很多其他的用途。比如像一些类,WeakReferenceandThreadLocal 这些也都是被泛型化了的。其中提到一个getAnnotation的泛型方法。(小白具体没怎么接触过,我想后面可以看看相关资料).毕竟后面做什么框架学习还会对泛型有所接触。

另外提到就是可能我们一些遗留的代码会在本来是String类型的Colletions中插入整数,这个时候就可能导致运行时类型转换异常。这个时候我们可以将原来HashSet的定义

  Set s = new HashSet();

修改为:

   Set s = Collections.checkedSet(new HashSet(), String.class);

这个时候当你想要插入整型时就会抛出ClassCastException的异常。所以我们要尽量无处不在的去使用泛型。

当然也不是全部(5.0以前的java虚拟机上就不要使用):

   There is one caveat: You may not use generics (or any other Tiger features) if you intend to deploy the compiled code on a pre-5.0 virtual machine. 

泛型看似和C++的模板很像,但仅仅只是表面的。泛型不会生成新的类,也不允许所谓的模板元编程(关于C++模板,很早以前有简单练习过,不过都好几年,忘差不多了 http://blog.chinaunix.net/uid-25799257-id-3286305.html)

最后这里有一个官方的泛型知识相关目录(介绍,简单案例啥的,小白大概过了一遍,基本上就是平时用到的(比如适配器封装部分,还有就是rx封装部分

Android-RecyclerView通用适配器BaseAdapter-多绘制类型-Base相关类

Android-Retrofit2+Rxjava2之网络请求预处理-Func1、Subscriber ))

Lesson: Generics

image

还得提几点,一个是类似这种, ,这种的简单理解。

另外就是关于如何转换历史代码去使用泛型,大概看了下,主要是装饰器进行装饰,增加中间层的调用和处理(不再直接调用某个方法,而是通过中间方法,以便进行泛型类型检查).小白目前大概理解是这样。不对了再说....

然后来看看这个?号这种...有篇介绍,小白觉得还可以,可以借鉴

不行再看一个解释:

image

还记得我们的通用适配器吧,都是extends。通用适配器的数据主要是用于取使用,重点在于取! 也就是我们的PECS原则。 至于super目前还没有具体用到,但是要知道,某些时候就会用到存储的情况!

小白又有疑问呢?怎么同时可以使用两种了? - 不能

我们看看常规:FanFanx.java

   public class FanFanx {
    private T item;
    public FanFanx(T t){item=t;}
    public void set(T t){item=t;}
    public T get(){return item;}
}

分别看看两种情况:

image

哇哦,哇哦,哇哦...

有办法两种同时满足么?不能,不信你看看Java的List实现没?

image

所以到这里小白我先记住,哎,大概就是这个样子。泛型也差不多就是这些个常规操作。至少了解后在你看源码的时候不会觉得好多类型,?号啥的感觉陌生......

就这样,坚持,坚持,开心,开心,快乐,快乐,多喝水,多喝水,坐好,坐好 - 黄磊

你可能感兴趣的:(Android-Java-泛型-官方文档走一走)