Java泛型详解

简介:

一 概念

1.1 为什么需要泛型?

          当我们将一个对象放入集合中,集合不会记住此对象的类型,当再次从集合中取出此对象时,该对象的编译类型变成了Object类型,但其运行时类型任然为其本身类型。因此,取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易出现“Java.lang.ClassCastException”异常。使用泛型就可以解决此类问题。

1.2 什么是泛型?

        泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。         

        可以在集合框架(Collection framework)中看到泛型的动机。例如,Map 类允许您向一个 Map 添加任意类的对象,即使最常见的情况是在给定映射(map)中保存某个特定类型(比如 String)的对象。因为 Map.get() 被定义为返回 Object,所以一般必须将 Map.get() 的结果强制类型转换为期望的类型,如下面的代码所示:

Map m = new HashMap();
m.put("key", "blarg");
String s = (String) m.get("key");

要让程序通过编译,必须将 get() 的结果强制类型转换为 String,并且希望结果真的是一个 String。但是有可能某人已经在该映射中保存了不是 String 的东西,这样的话,上面的代码将会抛出 ClassCastException。

理想情况下,您可能会得出这样一个观点,即 m 是一个 Map,它将 String 键映射到 String 值。这可以让您消除代码中的强制类型转换,同时获得一个附加的类型检查层,该检查层可以防止有人将错误类型的键或值保存在集合中。这就是泛型所做的工作。

二 定义和使用

2.1 定义

        泛型参数的命名风格为:推荐你用简练的名字作为形式类型参数的名字(如果可能,单个字符)。最好避免小写字母,这使它和其他的普通的形式参数很容易被区分开来。使用T代表类型,无论何时都没有比这更具体的类型来区分它。这经常见于泛型方法。如果有多个类型参数,我们可能使用字母表中T的临近的字母,比如S。如果一个泛型函数在一个泛型类里面出现,最好避免在方法的类型参数和类的类型参数中使用同样的名字来避免混淆。对内部类也是同样。

例:

[java]  view plain  copy
 print ?
  1. <span style="font-size:10px;"> <span style="font-size:12px;">class Notepad<K,V>{       // 此处指定了两个泛型类型    
  2.     private K key ;     // 此变量的类型由外部决定    
  3.     private V value ;   // 此变量的类型由外部决定    
  4.     public K getKey(){    
  5.         return this.key ;    
  6.     }    
  7.     public V getValue(){    
  8.         return this.value ;    
  9.     }    
  10.     public void setKey(K key){    
  11.         this.key = key ;    
  12.     }    
  13.     public void setValue(V value){    
  14.         this.value = value ;    
  15.     }    
  16. };  </span></span>  

2.2 使用方法

2.2.1 通配符(?)与上下界(extends ,super )

        在使用泛型类的时候,既可以指定一个具体的类型,如List<String>就声明了具体的类型是String;也可以用通配符?来表示未知类型,如List<?>就声明了List中包含的元素类型是未知的。 通配符所代表的其实是一组类型,但具体的类型是未知的。List<?>所声明的就是所有类型都是可以的。但是List<?>并不等同于List<Object>。List<Object>实际上确定了List中包含的是Object及其子类,在使用的时候都可以通过Object来进行引用。而List<?>则其中所包含的元素类型是不确定。其中可能包含的是String,也可能是 Integer。如果它包含了String的话,往里面添加Integer类型的元素是错误的。正因为类型未知,就不能通过new ArrayList<?>()的方法来创建一个新的ArrayList对象。因为编译器无法知道具体的类型是什么。但是对于List<?>中的元素确总是可以用Object来引用的,因为虽然类型未知,但肯定是Object及其子类。

例:extends通配符,向上造型一个泛型对象的引用

?extends XX,XX 类是用来限定通配符的上界,XX 类是能匹配的最顶层的类,它只能匹配 XX 类以及 XX 类的子类

[java]  view plain  copy
 print ?
  1. //原始版本  
  2. public void drawAll(List<Shape> shapes) {  
  3.      for (Shapes:shapes)   
  4.          {  
  5.            s.draw(this);  
  6.          }  
  7.     }  
  8. //使用边界通配符的版本  
  9. public void drawAll(List<?exends Shape> shapes) {  
  10.      for (Shapes:shapes)  
  11.          {  
  12.          s.draw(this);  
  13.          }  
  14.     }  

例:?super通配符,向下造型一个泛型对象的引用
? super XX,XX 类是用来限定通配符的下界,XX 类是能匹配的最底层的类,它只能匹配 XX 类及子类。

[java]  view plain  copy
 print ?
  1. List<Shape> shapes = new ArrayList<Shape>();  
  2. List<? super Cicle> cicleSupers = shapes;  
  3. cicleSupers.add(new Cicle()); //OK, subclass of Cicle also OK  
  4. cicleSupers.add(new Shape());//Error  


2.2.2 泛型接口

[java]  view plain  copy
 print ?
  1. <span style="font-size:12px;">   interface Info<T>{        // 在接口上定义泛型    
  2.        public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型    
  3.    }    
  4.    class InfoImpl<T> implements Info<T>{   // 定义泛型接口的子类    
  5.        private T var ;             // 定义属性    
  6.        public InfoImpl(T var){     // 通过构造方法设置属性内容    
  7.            this.setVar(var) ;      
  8.        }    
  9.        public void setVar(T var){    
  10.            this.var = var ;    
  11.        }    
  12.        public T getVar(){    
  13.            return this.var ;    
  14.        }    
  15.    };    
  16.    public class GenericsDemo24{    
  17.        public static void main(String arsg[]){    
  18.            Info<String> i = null;        // 声明接口对象    
  19.            i = new InfoImpl<String>("汤姆") ;  // 通过子类实例化对象    
  20.            System.out.println("内容:" + i.getVar()) ;    
  21.        }    
  22.    };    
  23.    ----------------------------------------------------------    
  24.    interface Info<T>{        // 在接口上定义泛型    
  25.        public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型    
  26.    }    
  27.    class InfoImpl implements Info<String>{   // 定义泛型接口的子类    
  28.        private String var ;                // 定义属性    
  29.        public InfoImpl(String var){        // 通过构造方法设置属性内容    
  30.            this.setVar(var) ;      
  31.        }    
  32.        public void setVar(String var){    
  33.            this.var = var ;    
  34.        }    
  35.        public String getVar(){    
  36.            return this.var ;    
  37.        }    
  38.    };    
  39.    public class GenericsDemo25{    
  40.        public static void main(String arsg[]){    
  41.            Info i = null;      // 声明接口对象    
  42.            i = new InfoImpl("汤姆") ;    // 通过子类实例化对象    
  43.            System.out.println("内容:" + i.getVar()) ;    
  44.        }    
  45.    };  </span>  

2.2.3 泛型数组

[java]  view plain  copy
 print ?
  1. public class GenericsDemo30{    
  2.     public static void main(String args[]){    
  3.         Integer i[] = fun1(1,2,3,4,5,6) ;   // 返回泛型数组    
  4.         fun2(i) ;    
  5.     }    
  6.     public static <T> T[] fun1(T...arg){  // 接收可变参数    
  7.         return arg ;            // 返回泛型数组    
  8.     }    
  9.     public static <T> void fun2(T param[]){   // 输出    
  10.         System.out.print("接收泛型数组:") ;    
  11.         for(T t:param){    
  12.             System.out.print(t + "、") ;    
  13.         }    
  14.     }    
  15. };    


转载:http://blog.csdn.net/chaoyu168/article/details/49360529

目录
相关文章
|
4月前
|
Java API
[Java]泛型
本文详细介绍了Java泛型的相关概念和使用方法,包括类型判断、继承泛型类或实现泛型接口、泛型通配符、泛型方法、泛型上下边界、静态方法中使用泛型等内容。作者通过多个示例和测试代码,深入浅出地解释了泛型的原理和应用场景,帮助读者更好地理解和掌握Java泛型的使用技巧。文章还探讨了一些常见的疑惑和误区,如泛型擦除和基本数据类型数组的使用限制。最后,作者强调了泛型在实际开发中的重要性和应用价值。
106 0
[Java]泛型
|
4月前
|
存储 安全 Java
🌱Java零基础 - 泛型详解
【10月更文挑战第7天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
37 1
|
4月前
|
安全 Java 编译器
Java基础-泛型机制
Java基础-泛型机制
44 0
|
4月前
|
存储 Java 编译器
Java集合定义其泛型
Java集合定义其泛型
33 1
|
4月前
|
Java 语音技术 容器
java数据结构泛型
java数据结构泛型
45 5
|
4月前
|
存储 Java 编译器
【用Java学习数据结构系列】初识泛型
【用Java学习数据结构系列】初识泛型
33 2
|
4月前
|
Java
【Java】什么是泛型?什么是包装类
【Java】什么是泛型?什么是包装类
45 0
|
5月前
|
存储 安全 搜索推荐
Java中的泛型
【9月更文挑战第15天】在 Java 中,泛型是一种编译时类型检查机制,通过使用类型参数提升代码的安全性和重用性。其主要作用包括类型安全,避免运行时类型转换错误,以及代码重用,允许编写通用逻辑。泛型通过尖括号 `&lt;&gt;` 定义类型参数,并支持上界和下界限定,以及无界和有界通配符。使用泛型需注意类型擦除、无法创建泛型数组及基本数据类型的限制。泛型显著提高了代码的安全性和灵活性。
|
5月前
|
Java 编译器 容器
Java——包装类和泛型
包装类是Java中一种特殊类,用于将基本数据类型(如 `int`、`double`、`char` 等)封装成对象。这样做可以利用对象的特性和方法。Java 提供了八种基本数据类型的包装类:`Integer` (`int`)、`Double` (`double`)、`Byte` (`byte`)、`Short` (`short`)、`Long` (`long`)、`Float` (`float`)、`Character` (`char`) 和 `Boolean` (`boolean`)。包装类可以通过 `valueOf()` 方法或自动装箱/拆箱机制创建。
64 9
Java——包装类和泛型
|
5月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射

热门文章

最新文章