JavaSE-泛型机制
2016-02-04 15:12
155 查看
泛型是java编程中经常使用,且很有用的一个特性,经常在集合与DAO(数据库访问对象)编程中使用。
1.存储数据时,不能保证数据的类型安全,也就是说,同一集合中可以存储多种类型的数据
2.在集合中获取数据时,必须经过强制转换,才能转换为自己需要类型的数据,而且由于第一条的不足,导致会出现类型转换异常
这就相当于绕了一个弯,把原本的数据类型--->转换为Object类型存储--->转换为原本的数据类型以便使用。
代码:
java 的泛型机制就是解决这么样的问题,通过使用泛型:
1.保证数据存储类型的安全,就是通过指定泛型的类型,使得在存储数据时,只能存储先前指定类型
2.避免了数据类型的转换,也就避免了异常
代码:
集合List:见“为什么使用泛型”一节
集合Map:
自定义泛型类Order,
代码:
Order的使用,
代码:
1.在实例化泛型类对象时,指定泛型的类型,对应的类中所有使用泛型的位置,都变为实例化中指定的泛型的类型
2.如果我们定义了泛型类,但在实例化中未指定泛型类型,那么默认是Object类型
子类继承泛型类,可以指定泛型类型,也可以保持子类继续是泛型类:
代码:
泛型方法通过权限修饰符后添加泛型<E>,使函数方法成为泛型方法,参看Order类中两个泛型方法getE()和fromArrayToList()
泛型方法的使用:(其实通过参数,便指定类泛型方法的泛型类型)
代码:
List<String>与List<Object>是并列关系,不存在继承关系:
List<?> 是所有List<ClassName>的父类
代码:
List<? extends A>是List<A类及其子类> 的父类
List<? super B> 是List<B类及其父类> 的父类
对于通配符的泛型集合List<?> ,是可以进行遍历查看操作的,但是不允许进行写入,只可以写入null
但是在静态方法中可以使用泛型方法,即结合静态方法与泛型方法:
不能在catch语句中使用,是指catch(T t)是编译不通过的:
1、为什么要使用泛型:
在没有使用泛型时,集合存储和提取数据经常出现两个不足:1.存储数据时,不能保证数据的类型安全,也就是说,同一集合中可以存储多种类型的数据
2.在集合中获取数据时,必须经过强制转换,才能转换为自己需要类型的数据,而且由于第一条的不足,导致会出现类型转换异常
这就相当于绕了一个弯,把原本的数据类型--->转换为Object类型存储--->转换为原本的数据类型以便使用。
代码:
//在没有使用泛型时: //1、不能保证存储数据类型的安全 //2、数据需要强转,可能出现ClassCastExcepetion异常 @Test public void testNoGeneric(){ List list = new ArrayList(); list.add(88); list.add(90); list.add(99); list.add("AA");//不能保证存储数据类型安全 for(int i=0;i<list.size();i++){ int score = (int) list.get(i);//抛出ClassCastException异常 System.out.println(score); } }
java 的泛型机制就是解决这么样的问题,通过使用泛型:
1.保证数据存储类型的安全,就是通过指定泛型的类型,使得在存储数据时,只能存储先前指定类型
2.避免了数据类型的转换,也就避免了异常
代码:
//使用泛型,保证数据存储的类型安全 //同时,避免了强制类型转换 @Test public void testGeneric1(){ //在指定泛型之后,该泛型类的所有有关泛型的方法或返回类型,都变成了指定的泛型类型 List<Integer> list = new ArrayList<Integer>();//实现类的泛型可以不再指定,只需一个<>即可 list.add(88); list.add(90); list.add(99); //list.add("AA");//编译时就会报错,保证数据存储类型的安全 //List容器的遍历方法 Iterator<Integer> it = list.iterator(); while(it.hasNext()){ Integer score = it.next(); System.out.println(score); } //或者 // for(Integer i:list){ // System.out.println(i); // } }
2、在集合中使用泛型:
其实通过指定泛型,泛型类的所有与泛型相关的方法都自动变成了指定的类型集合List:见“为什么使用泛型”一节
集合Map:
@Test public void test3(){ Map<String, Integer> map = new HashMap<String,Integer>();//OR new HashMap<>()即可 map.put("AA", 78); map.put("BB", 88); map.put("CC", 99); Set<Entry<String, Integer>> set = map.entrySet(); for(Entry<String, Integer> o:set){ System.out.println(o); } }
3、自定义泛型类、泛型接口和泛型方法
自定义泛型类
通过添加<T>在类型名后边:class ClassName<T>自定义泛型类Order,
代码:
public class Order<T> { private String orderName; private int orderId; private T t; public List<T> list = new ArrayList<>(); public void add(){ list.add(t); } public String getOrderName() { return orderName; } public void setOrderName(String orderName) { this.orderName = orderName; } public int getOrderId() { return orderId; } public void setOrderId(int orderId) { this.orderId = orderId; } public T getT() { return t; } public void setT(T t) { this.t = t; } @Override public String toString() { return "Order [orderName=" + orderName + ", orderId=" + orderId + ", t=" + t + "]"; } //泛型方法,泛型方法的类型与泛型类无关 public <E> E getE(E e){ return e; } //泛型方法,实现数组到集合的复制 public <E> List<E> fromArrayToList(E[] arr, List<E> list){ for(E e:arr){//数组也可以这样遍历 list.add(e); } return list; } }
Order的使用,
代码:
//自定义泛型类的使用 @Test public void test4(){ Order<Boolean> order = new Order<Boolean>(); order.setT(true); Boolean b = order.getT(); System.out.println(b); order.add(); List<Boolean> list = order.list; System.out.println(list); }
1.在实例化泛型类对象时,指定泛型的类型,对应的类中所有使用泛型的位置,都变为实例化中指定的泛型的类型
2.如果我们定义了泛型类,但在实例化中未指定泛型类型,那么默认是Object类型
子类继承泛型类,可以指定泛型类型,也可以保持子类继续是泛型类:
代码:
//定义泛型类的子类时,可以指明泛型类型,通过在父类后指定类型 class subOrder extends Order<Boolean>{ } //也可以不指定,子类也还是泛型,子类父类都需指定泛型<T> class subOrder2<T> extends Order<T>{ }
泛型接口同泛型类;
泛型方法
泛型方法其实与泛型类无关,泛型方法可以在泛型类中,也可以在非泛型类中。泛型方法通过权限修饰符后添加泛型<E>,使函数方法成为泛型方法,参看Order类中两个泛型方法getE()和fromArrayToList()
//泛型方法,泛型方法的类型与泛型类无关 public <E> E getE(E e){ return e; } //泛型方法,实现数组到集合的复制 public <E> List<E> fromArrayToList(E[] arr, List<E> list){ for(E e:arr){//数组也可以这样遍历 list.add(e); } return list; }
泛型方法的使用:(其实通过参数,便指定类泛型方法的泛型类型)
代码:
//泛型方法的使用 @Test public void test5(){ Order<Boolean> order = new Order<Boolean>(); //调用泛型方法 Integer i = order.getE(50);//指定参数,返回类型确定为Integer Double d = order.getE(4.3);//返回类型为Double Integer[] ints = new Integer[]{1,2,3}; List<Integer> list = new ArrayList<>(); List<Integer> list3 = order.fromArrayToList(ints, list); System.out.println(list3); }
4、泛型与继承的关系
类之间存在继承关系,String类是Object类的子类,那么泛型中List<String>与List<Object>存在怎么样的关系呢?List<String>与List<Object>是并列关系,不存在继承关系:
/* * List<Object>与List<String>不存在子父类关系,属于并列关系 * 他们有共同的父类:List<?> */ @Test public void test6(){ Object obj = null; String str = "AA"; obj = str;//没问题,子类赋给父类 Object[] objs = null; String[] strs = new String[]{"AA","BB","CC"}; objs = strs;//没问题,子类数组赋给父类数组 List<Object> listObject=null; List<String> listString = new ArrayList<String>(); listObject = listString;//编译不通过,说明List<Object>与List<String>不存在子父类关系 }其实,List<String>与List<Object> 有共同的父类:List<?> ,这就是通配符?的作用,看下节。
5、通配符
通配符,就是应对泛型类之间的继承关系的,分三种:List<?> 是所有List<ClassName>的父类
代码:
/** * 通配符? * List<?> 是所有List<Object>、List<String> ... 的父类 */ public void test7(){ List<?> list=null;//共同的父类,通配符? List<Object> listObject = new ArrayList<Object>(); List<String> listString = new ArrayList<String>(); list = listObject; list = listString; show(listObject); show(listString); }
List<? extends A>是List<A类及其子类> 的父类
List<? super B> 是List<B类及其父类> 的父类
/* * List<? extends A>是所有A类及其子类的父类,即: * 可以存放A的所有子类及其本身ClassName类; * List<? super B> 是所有B类及其父类的父类,即: * 可以存放所有B的父类及B类; */ public void test8(){ List<? extends Number> list1 = null; List<Integer> list2= null; list1 = list2;//可以,因为Integer是Number的子类 List<Object> list3 = null; // list1 = list3;//编译不通过,因为Object 是Number的父类 List<? super Number> list4 = null; list4 = list3;//可以 }
对于通配符的泛型集合List<?> ,是可以进行遍历查看操作的,但是不允许进行写入,只可以写入null
@Test public void test9(){ List<String> list = new ArrayList<>(); list.add("AA"); list.add("BB"); list.add("CC"); List<?> list1= list; //可以查看遍历声明通配符List<?>中的元素 Iterator<?> it = list1.iterator(); while(it.hasNext()){ System.out.println(it.next()); } //不可以向声明为通配符的泛型List<?>中添加元素,唯一例外的是null // list1.add("AA");//编译不通过 list1.add(null); }
6、其他注意点
1.静态方法中不能使用类的泛型
在泛型类中,静态方法中不能使用泛型,因为静态方法在类加载时就加载了,此时还未指定泛型类的类型,不能使用。但是在静态方法中可以使用泛型方法,即结合静态方法与泛型方法:
public static <E> E test(E e){ return e; }
2.如果泛型类是一个接口或者抽象类,则不可创建泛型类的对象
接口和抽象类本身就不可以创建类对象,跟泛型无多大关系3.不能在catch语句中使用泛型
在泛型类中,可能会写到try-catch语句,进行异常的处理,但是泛型T是不可以在catch语句中使用的。不能在catch语句中使用,是指catch(T t)是编译不通过的:
public void test(){ try{ }catch(T e){//编译错误 } }但是这样使用是可以的:
public void test(){ try{ T t; }catch(Exception e){ T t; } }
相关文章推荐
- JDK、J2EE、J2SE、J2ME的区别
- JAVA简单的爬虫代码
- Eclipse集成反编译插件jd-Eclipse
- JAVA反序列化漏洞
- Java并发之(3):锁
- Java Criteria表关联查询(两个表未定义关联关系)
- Java实现UDP之Echo客户端和服务端
- 举例说明Java多线程编程中读写锁的使用
- Java基础:修饰符
- Java经典用法总结(二)
- Java实现Socket之WhoisClient
- java注解处理器
- Struts2架构解析
- selenium java 程序 无法打开火狐及相关问题
- JDK里的设计模式
- Java学习笔记--split篇
- Java实现Socket之TimeClient
- Java基础:JDK安装及Java环境变量配置
- java国际化——日期和时间+排序
- Java 数组