在java中,普通的类和方法只能用具体的类型,这对代码的限制很大,代码的可重用性大大降低。

那么如何才能让同一个类和方法使用不同类型的对象呢?在接触泛型之前我们可能会想到通过类型转换的方法来实现。

public class Test {
Object o; public Test(Object o) {
this.o = o;
} public void set(Object o){
this.o=o;
} public Object get(){
return o;
} public static void main(String[] args) {
String str="hello world";
Test test=new Test(str);
String str2=(String) test.get();
} }

但是这种方法有很大的缺陷,容易在类型转换过程中出现错误,而使用泛型能很好地避免这个错误的出现。


泛型能够能够指定容器容器要装什么类型的对象,无须类型转换。

泛型类:

public class Test<T> {
private T a; public Test(T a) {
this.a = a;
} public T getA() {
return a;
} public void setA(T a) {
this.a = a;
} public static void main(String[] args) {
Test<String> test = new Test<>("test");
System.out.println(test.getA());
}
}

泛型方法:

    public <T> String getClassName(T t) {
return t.getClass().getSimpleName();
}

对于泛型方法和泛型类,我们通常首先选择泛型方法,毕竟,泛型类的束缚更大,它表示我们在整个类中都要使用着这类型;相对而言泛型方法就灵活许多,我们可以在不同的方法中使用不同的类型。


泛型擦除:

public static void main(String[] args) {
List<Integer> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
System.out.println(list1.getClass()==list2.getClass());
/*
output:
true
*/
}

list1和list2的泛型参数类型不相同,但从上面的结果中不难看出,系统认为它们是相同的类型,因为泛型只在编译过程起作用,当程序运行时泛型参数的具体信息都被擦除。


边界:

class Animal{
void eat(){}
} class Bird extends Animal {
}

当我们已经确认此泛型参数为一固定类型Animal或Animal的子类时,我们希望能够调用Animal对象中的eat方法, 那我们又该如何实现呢?

这里我们需要用到泛型边界,它通过extends关键字来实现:

public class Test<T extends Animal> {
public void test(T t) {
t.eat();
}
}

这里声明了边界Animal,它可以调用Animal中的成员。如果没有声明边界,则默认边界为Object。

当然如果只是实现这个目的,我们无需使用泛型:

public class Test{
public void test(Animal a){
a.eat();
}
}

好像这里使用泛型没什么用处,其实并非如此。当泛型方法有泛型类型的返回值时,它能返回确切的类型:

public class Test<T extends Animal> {
public T get(T t) {
t.eat();
return t;
} public static void main(String[] args) {
Animal a = new Test<>().get(new Animal());
Bird b = new Test<Bird>().get(new Bird());
}
}

这比不使用泛型灵活许多,所以,我们在考虑是否使用泛型时要根据具体情况而定,看看结构是否足够复杂,使用泛型是否会给我们带来方便。


通配符:

我们再来看一个错误例子:

List<Animal> list=new ArrayList<Bird>(); //error:Type mismatch: cannot convert from ArrayList<Bird> to List<Animal>

想当初第一次运行类似的代码时,我有些无法理解,Bird是Animal的子类,为何就不能向上转型呢呢,这泛型也太呆板了。仔细一想才发现,这根本就不是向上转型,List<Animal>代表Animal类型的列表,而ArrayList<Bird>代表Bird类型的列表。

可是我们就是想要实现这样的功能,那该怎么做?这里就需要用到通配符:

List<? extends Animal> list=new ArrayList<Bird>();

泛型与数组:

我们无法直接创建泛型数组实例,因为你数组类型必须是确定的,以此确保类型安全,但是擦除却使类型参数信息消失。

List<String>[] lists=new ArrayList<String>[12]; //error

但是们可以声明一个泛型数组:

List<String>[] lists;

根据以上两个特性,我们可以创建一个非泛型数组,再进行转型,从而获得泛型数组:

List<String>[] lists=(List<String>[])new ArrayList[12];
//或简化为:List<String>[] lists=new ArrayList[12];

最新文章

  1. MySQL数据库
  2. 【2016-10-16】【坚持学习】【Day7】【建造者模式】
  3. springMVC学习笔记(五)
  4. Github 新的项目管理模式——Projects
  5. swiper初步探索
  6. codeforces 487C C. Prefix Product Sequence(构造+数论)
  7. 在Linux上部署和操作Couchbase
  8. Unity 音乐播放全局类
  9. HDU 5019 Revenge of GCD
  10. SQL数据库面试题
  11. android下拉刷新控件 android-pulltorefresh
  12. unity 单指双指事件(单指点击移动,双指滑动拖放)
  13. Ocelot API网关的实现剖析
  14. awk命令练习
  15. hibernate框架学习笔记2:配置文件详解
  16. 【原创】XAF ITreeNode+NonPersistent 使用方式
  17. SUSE12SP3-Mysql5.7安装
  18. easyui 信息提示
  19. 理解ThreadPoolExecutor线程池的corePoolSize、maximumPoolSize和poolSize
  20. php 中self,this的区别和实地操作

热门文章

  1. 强化学习导论 课后习题参考 - Chapter 1,2
  2. C# 基础 - 日志捕获一使用 StreamWriter
  3. 绿色物流-智慧仓储监控管理 3D 可视化系统
  4. IntelliJ IDEA热部署配置总结
  5. Git本地操作2
  6. 8、MyBatis之使用注解开发
  7. OOP第一次博客作业
  8. WebGPU[4] 纹理三角形
  9. CQGUI框架之样式管理
  10. java面试-集合类不安全问题及解决方案