480 likes | 624 Views
主题:集合框架与泛型. - Java 核心技术 -. 本讲主要内容. 掌握Java集合框架 理解什么是泛型 掌握泛型的简单用法. Java集合框架. 什么是JCF Java集合框架(Java Collection Framaework)是一组采用了动态存储对象的数据结构与操作算法的框架 JCF的优点 在编码时不需要采用手动的方式对些 “ 数据引擎 ” 进行编码; 框架允许不同类型的集合以相似的方式进行操作,并且有高度的互用性; 通过设计一系列标准的接口,使得框架易于扩展; 具有将标准数组集成到集合框架中的机制;
E N D
主题:集合框架与泛型 - Java核心技术 -
本讲主要内容 • 掌握Java集合框架 • 理解什么是泛型 • 掌握泛型的简单用法
Java集合框架 • 什么是JCF • Java集合框架(Java Collection Framaework)是一组采用了动态存储对象的数据结构与操作算法的框架 • JCF的优点 • 在编码时不需要采用手动的方式对些“数据引擎”进行编码; • 框架允许不同类型的集合以相似的方式进行操作,并且有高度的互用性; • 通过设计一系列标准的接口,使得框架易于扩展; • 具有将标准数组集成到集合框架中的机制; • 通过引入Iterator(迭代器)接口实现对集合元素遍历
Java集合框架 • JCF的构成 • 由接口(如:Collection、List、Set和Map等接口)和其所对应的实现类组成,都位于JDK中的java.util包中
Collection接口 • Collection是最基本的集合接口,用来说明作为一个集合类应有的结构特征属性和共性的操作方法,是所有集合类的基类。 • 其遍历的典型代码 • 用增强for循环实现
List接口 • List接口扩展了Collection,该集合是一种允许有重复元素的有序列表。 • 它引入位置下标的概念(这一点和数组类似),下标从0开始计数,列表中元素的顺序与插入列表的顺序保持一致。 • List列表可以通过指定下标的方式将集合元素插入到对应的位置,或者使用下标访问集合中的元素。 • 在JDK中为List接口提供了2个主要的实现类:ArrayList类和LinkedList类。
List接口 • ArrayList类 • ArrayList是一个对象引用的变长数组,也就是说它能根据需求动态改变存储容量,而且它能接收包括 null 在内的所有类型数据作为其元素。 • 其具有索引数据快而插入数据慢的特点 • 使用get方法从列表中取指元素时,需要对取到的元素进行手动类型转换,特别是将Java语言的基本数据类型作为集合元素时,需要进行“装/拆箱”处理
List接口 • ArrayList类示例 1.创建学生类,有姓名、班级2个属性。 2.创建6个学生对象,存储在ArrayList中。 3.显示ArrayList中第3个元素的值。 4.删除ArrayList中第2个元素。 5.用3种方式,显示ArrayList中的所有元素。 6.在ArrayList中查找是否有名为“张三”的学生,如果有将他的班级改为“三班”。 7.在ArrayList中查找是否有名为“王五”的学生,如果有将他从ArrayList中删除。
List接口 练习1.2.1 指出下述程序中存在的错误。
没有使用泛型的示例 在JSE5之前,没有引入泛型的情况下从List中读取对象,都需要进行类型的强制转换。如下: List list = new ArrayList(); Student stu = new Student(”张三”,”一班”); list.add(stu); … Student stu = (Student)list.get(0); System.out.println(stu.MingZi); 在使用get方法来取集合中的元素时,需要进行类型强制转换。如果代码改成如下形式,编译也不会出错,只会在运行时出错。 String stu = (String)list.get(0);
没有使用泛型的示例 而泛型的引入弥补了这个问题,下面是使用泛型来改进程序: List <Student> list = new ArrayList<Student>(); Student stu = list.get(0);
课堂练习 1.定义一个“书籍”类,它有三个属性:书名、作者、价格。 2.创建6书籍对象,存储在ArrayList中。 3.显示ArrayList中第3个元素的值。 4.删除ArrayList中第2个元素。 5.用3种方式,显示ArrayList中的所有元素。 6.在ArrayList中查找价格最贵的书籍的书名。 7.在ArrayList中,输出作者为“张明”的所有书籍名。
Set接口 • Set接口是一种不允许有重复元素的无序集合列表,Set接口包含Collection接口中所有的方法,没有新增任何新方法。 • Set接口在每个对象上使用equals方法来检查add和addAll方法是否添加了重复的对象。 • 在Java API中SortedSet接口扩展了Set接口,是一种按照数字排序的集合,默认按升序排列。 • 主要的实现类有HashSet和TreeSet两个类。
Set接口 • HashSet实现了Set接口,它创建一个使用哈希表来存储集合元素。 • 哈希表是采用散列法的机制来存储信息的。 • 在散列法中,键的信息内容用于确定一个唯一值,这种键称为哈希码(散列码)。通过这个键值就能取到与键对应的元素。 • 哈希表在存储元素时并不会保存元素的顺序,也就是说存入元素的顺序,不一定与其在哈希表中的位置相同。
Set接口 注意:HashSet集合插入顺序与存储顺序是不一致的,而且这类集合不允许有重复元素。
Set接口 • 练习1.2.2 请选择程序运行后输出的正确结果。 (A)abcdefabcdef (B)defabcdefabc (C) fedcbafedcba (D) defabc
Map接口 • Map(映射)是一种与Collection集合无任何关系的集合,它是存储键/值对的对象。 • 给定一个键,就可以以找到它对应的值。 • 键和值都必须是对象,键在映射对象中要求是惟一的,但值却可以重复。 • Map主要通过get和put方法来完成对映射集合进行存、取操作的,使用remove方法来实现删除操作。 • 在JDK中主要提供了Map的子接口SortedMap和HashMap实现类。
Map接口 • SortedMap接口 • StoredMap接口扩展了Map,它确保了以键的升序方式存储键值对。 • 实现SortedMap接口的是java.util.TreeMap
Map接口 • 练习1.2.3 A.程序编译时会出错,因为Integer型数据不能做为Map的键值; B.程序编译时会出错,因为Map对象不能将null做为值; C.程序编译时会出错,因为SortedMap对象不能用null做为值; D.程序能正确编译和运行。
Map接口 • HashMap • HashMap是使用哈希表实现Map接口 • 它将键值对之间的相对顺序按照插入Map的先后顺序存储在集合中。 • 注意:HashMap只是提供快速的查找功能,并不能保证元素的存储顺序,因此元素添加到哈希映射中的顺序并不一定是它们被迭代器读出的顺序
Map接口 • 示例1.2.6 注意:HashMap集合是一种无序的集合,且要求关键字是惟一,值可是重复的
没有使用泛型的示例 • Gen类功能:能对任意一个类的对象进行赋值、取值等操作。 public class Gen { private Object ob; //定义一个通用类型成员 public Gen(Objectob) {this.ob = ob; } public Object getOb() {return ob;} public void setOb(Object ob) {this.ob = ob;} public void showType () { System.out.println(“ob的实际类型是: " + ob.getClass().getName()); } }
没有使用泛型的示例 public class GenDemo { public static void main(String[] args) { //定义类Gen的一个Integer版本 Gen intOb = new Gen(newInteger(88)); intOb.showType (); int i = (Integer) intOb.getOb(); System.out.println("value= " + i); System.out.println("----------------------------------"); //定义类Gen的一个String版本 Gen strOb = new Gen("Hello Gen!"); strOb.showType (); String s = (String) strOb.getOb(); System.out.println("value= " + s); } }
泛型的起因 • JDK1.4以前类型不明确: • 在不能确定数据类型的情况下,必须将具体使用的数据类型转化为object类型,从而失去自己的实际类型的特性。 • 再使用已被转化为object类型的数据时,常常又需要转化为原始类型,造成效率低,容易出错的不足。 • 使用泛型来解决此问题。
什么是泛型 • 泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。 • 这种参数类型可以用在 • 类——泛型类:public class ArrayList<E> • 接口——泛型接口:public interface Map<K,V> • 方法——泛型方法:public boolean add(E o) • 泛型是Java SE 1.5的新特性
如何理解泛型 • 其实Java的泛型类就是创建一个用类型作为参数的类。 • class Java_Generics<K,V>。 这个类就使用了泛型,包含K,V两个参数类型。
使用泛型的示例 public class Gen<T> { private T ob; //定义泛型成员变量 public Gen(T ob) {this.ob = ob;} public T getOb() {return ob;} public void setOb(T ob) {this.ob = ob;} public void showType () { System.out.println("T的实际类型是: " + ob.getClass().getName()); } }
使用泛型的示例 public class GenDemo { public static void main(String[] args){ //定义泛型类Gen的一个Integer版本 Gen<Integer> intOb=new Gen<Integer>(88); intOb.showType (); int i= intOb.getOb(); System.out.println("value= " + i); System.out.println("----------------------------------"); //定义泛型类Gen的一个String版本 Gen<String> strOb=newGen<String>("Hello Gen!"); strOb.showType (); String s=strOb.getOb(); System.out.println("value= " + s); } }
使用泛型后的优点 • Java语言引入泛型的好处是安全简单。 • 在Java SE 1.5之前,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。 • 泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率,也增强的程序可阅读性与稳定性。
泛型类的定义与使用 • 在定义一个泛型类时,在类名后用“<>”来声明是泛型类,“<>”之间定义形式类型参数,例如泛型类 HashMap< Key, Value>,其中 Key 和 Value 是类型参数。
泛型类的定义与使用 • 示例1.2.7
泛型类的定义与使用 • 定义泛型类时需要注意如下几个方面: • 在定义一个泛型类的时候,在 “<>”之间定义形式类型参数,例如:“class GenExample3<T>”,其中“T”不代表值,而是表示类型。 • 实例化泛型对象的时候,一定要在类名后面指定类型参数的值(类型),一共要有两次书写。例如:GenExample3<String> gen=new GenExample3<String>(); • 泛型中<T extends String>,extends并不代表继承,它是类型范围限制,说明T的类型只能属于String类型或者是String的子类。 • 在泛型中,可以支持一个以上的类型参数。如果指定两个或更多的类型参数,只需在参数行用逗号将其隔开即可,例如: public class ArrayList<K,V>{….}。
泛型接口的定义 • 泛型接口的指定方法与泛型类相类似。其定义的语法格式如下所示: • interface interface-name<type-param-list>{…} • 实现所定义的泛型接口的语法如下所示: • class class-name<type-param-list> implements interface-name<type-param-list>{…}
泛型接口的定义 • 示例1.2.8 试定义一个取集合中值最大和最小元素的泛型接口
泛型接口的定义 • 示例1.2.8 试定义一个取集合中值最大和最小元素的泛型接口 • 泛型接口实现类
泛型接口的定义 • 示例1.2.8 试定义一个取集合中值最大和最小元素的泛型接口
学会使用JDK中的泛型 • JDK中有大量使用到泛型的实例。 • 如:集合型数据类型 ArrayList、List、Map等。
学会使用JDK中的泛型 • 示例1.2.9 试运行下述程序 import java.util.*; /** * 用户信息Bean * @author */ class User { private String name;//用户名 private String psw;//用户口令 public User(String name, String psw) { this.name = name; this.psw = psw; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPsw() { return psw; } public void setPsw(String psw) { this.psw = psw; } } /** * 泛型集合类的使用 * @author */ public class GenExample4 { public static void main(String[] args) { //创建泛型Map集合 Map<String, User> users = new HashMap<String, User>(); users.put("John", new User("John", "123456")); users.put("Tom", new User("Tom", "564534")); users.put("Jacke",new User("Jacke","4567890")); //根据关键字取用户信息 User user = users.get("Tom"); System.out.println("Tom的口令是:" + user.getPsw()); } }
泛型规则和限制-1 1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。 2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。 3、泛型的类型参数可以有多个。
泛型规则和限制-2 4、泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上成为“有界类型”。 public class ListGenericFoo<T extends Exception>{} 5、泛型的参数类型还可以是通配符类型。例如BGeneric<? extends B>,表示任何泛型BGeneric类型,它的类型参数是B的子类,如BGeneric<BSub>,但不是BGeneric<String>
总结 • 泛型(Generic)的概念 • 泛型的使用