泛型(Generics)小结

泛型的由来

泛型并不是一开始就直接在Java中的,而是在JDK 1.5中才加入的。那么为什么要加入它呢?
不管是什么,只要是新入的东西,基本都有三个目的:

1.使得开发更便捷,减少程序员的开发工作量
2.提高程序运行效率
3.更加安全

所以很多人抱怨软件行业技术迭代快速,自己跟不上等等都是不对的。所有的技术迭代都只是减少我们的工作量,让我们的工作更加简单快捷。但是这种简单快捷是建立在我们的基础牢固,一步一个脚印的情况下。如果囫囵吞枣的学习,对于所有的知识都是一知半解,那么新东西的出现对于我们而言,只是增加了学习量,而不是减少了工作量。
所以,学习知识,还是慢慢来,比较快

让我们继续回到泛型的讲解上,那么对于泛型,我们的目的是什么呢?
要回答这个问题,那么我们就要先看看,没有泛型会发生什么?
1)集合中的类型不安全,可以向集合中放入任何引用类型的对象
2)从集合中取出的对象都是Object类型,在具体操作时可能需要进行类型的强制转换(运行期)。那么,在强制类型转换时也容易发生ClassCastException

类型擦除

意思就是JVM本来没有泛型这一说,所以要把泛型参数擦除(以前和现在的我都一直觉得不如叫做类型翻译比较好,好理解,一下子就知道是虚拟机把泛型参数翻译成具体类型

使用泛型

1.使用泛型方法,泛型类。
2.定义泛型:
1)定义泛型:依照API定义——声明类(接口)时,在类名的后面,大括号的前面利用<>来声明泛型。在类中凡是可以使用类型的地方都可以使用类中声明的泛型。

public class Dao

2)定义泛型方法:
a、在类(不一定是泛型类)中使用泛型方法
b、在方法的返回值前面使用<>声明泛型类型,则在方法的返回值,参数,方法体中都可以使用该类型

public static  T getMiddle(T[] b) {  
       return b[b.length/2];  
}  
String[] names = { "John", "Q.", "public" };  
String middle = ArrayAlg.getMiddle(names);  

3.一个命名的习惯:推荐用简练的名字作为形式类型参数的名字(如果可能,单个字符)。最好避免小写字母。

4.如果Foo 是Bar 的一个子类型(子类或者子接口),而G 是某种泛型声明,那么G是G的子类型并不成立!!

5.Collection ,?被称为通配符。我们可以写:

void printCollection(Collection c) {
for (Object e : c) {
System.out.println(e);
}
}

现在,我们可以使用任何类型的collection 来调用它。注意,我们仍然可以读取c 中的元素,其类型是Object。这永远是安全的,因为不管collection 的真实类型是什么,它包含的都是Object。但是将任意元素加入到其中不是类型安全的:

Collection c = new ArrayList();
c.add(new Object()); // 编译时错误

因为我们不知道c 的元素类型,我们不能向其中添加对象。add 方法有类型参数E 作为集合的元素类型。我们传给add 的任何参数都必须是一个未知类型的子类。因为我们不知道那是什么类型,所以我们无法传任何东西进去。唯一的例外是null,它是所有类型的成员。另一方面,我们可以调用get()方法并使用其返回值。返回值是一个未知的类型,但是我们知道,它总是一个Object。
总结:
?是通配符,它指可以接收接收任何类型的泛型。所以用它声明的方法内并不知道具体的泛型是什么,所以不能往其中加入任何元素除了null。(编译器不允许)但是方法内可以get元素,因为get到的元素永远是object.只要有通配符存在,永远都不能add元素,只能get。

6.Collection为带上限的通配符:该类型可以指向Person类型及Person子类类型的集合,但,也不能向其中放入null以外的任何元素。逻辑和上面一样,因为你不知道Collection具体是哪个子类的泛型。
7.Collection为带下限的通配符,只能add() People类和其子类的对象。

总结:
只要有上限,就不能add和set(其实这里我还是觉得有一点奇怪的,因为尽管有上限,Object类的对象按理来说应该都是可以add和set,但是竟然也不能,大概是大师们为了方便敲代码吧,或者就是我太笨了,有个地方的逻辑没有想通),只要下限就可以add和set那个下限。

参考:
深入泛型

你可能感兴趣的:(JAVA其他)