Java 集合和泛型
一、集合(Collections)
Java使用集合来组织和管理对象。
1、Java的集合类
集合类主要负责保存、盛装和管理对象,因此集合类也被称为容器类。
集合类分为Set、List、Map和Queue四大体系。
- Set 代表无序、不可重复集合;
- List 代表有序、可重复集合;
- Map 代表具有映射关系元素的集合;
- Queue 代表队列,实现元素的先进先出管理。
数组也是一种集合类,它是能随机存储和访问引用序列的诸多方法中最高效的一种,当追求高效的数据访问时,数组是很不错的选择。
2、集合与泛型
所有集合类都位于java.util包中,集合中只能保存对象的引用。集合类把它所含有的元素看成是Object的实例,这样方便但是也有隐患,即多个类型不同的元素被放入一个集合中,会增加集合访问时类型转换的困难,甚至会产生错误。
泛型的引入改善了这种情况,使用泛型来限制集合里元素的类型,并让集合记住元素的类型。这样可以允许编译器检查加入集合的元素类型,避免值类型不一致的错误。
3、Java集合框架介绍
集合框架是一个用来表示和操作集合的统一架构,包含实现集合的接口和类。
Java的整个集合框架围绕一组标准接口设计,开发者可以直接使用这些接口的标准实现,也可以使用集合框架接口实现自定义的集合实现类。
集合框架的设计应满足一下三个目标:
- 高性能。保证算法的实现效率。
- 互操作性。
- 高扩展性。对集合进行扩展是简单的,只需要实现特定接口即可。
4、Java集合框架基于统一的方式组织和管理对象,包含3个方面:
- 接口。接口定义了集合操作的行为规约,它形成集合的高层视图。
- 实现类。是集合接口的具体表现。本质上说,是可重复使用的数据结构。
- 算法。实现集合操作中常用的算法,比如搜索和排序。这些算法通过多态实现,即相同的方法在相似的接口上有着不同的实现
5、集合接口
集合框架定义了一组接口,接口申明了对特定类型的集合可以执行的操作。
Java的集合类主要由两个接口派生而出——Collection和Map,它们是Java集合框架的根接口。
Collection接口的子接口:
- java.util.List
- java.util.Set
- java.util.SortedSet
- java.util.NavigableSet
- java.util.Queue
- java.util.concurrent.BlockingQueue
- java.util.concurrent.TransferQueue
- java.util.Deque
- java.util.concurrent.BlockingDeque
Map接口的子接口:
- java.util.SortedMap
- java.util.NavigableMap
- java.util.concurrent.ConcurrentMap
- java.util.concurrent.ConcurrentNavigableMap
6、集合类
标准集合类实现了Collection接口,其中一些是抽象类,实现部分接口,其它是具体类,可以直接在代码中使用。
Interface | Hash Table | Resizable Array | Balanced Tree | Linked List |
Hash Table+ Linked List |
Set | HashSet | TreeSet | LinkedHashSet | ||
List | ArrayList | LinkedList | |||
Deque | ArrayDeque | LinkedList | |||
Map | HashMap | TreeMap | LinkedHashMap |
所有实现Collection接口的类都必须提供两个标准的构造函数:
- 无参构造函数——用于创建一个空的Collection;
- 使用Collection类型作为参数的构造函数——用于创建一个新的Collection,目的是复制。
二、泛型(Generics)
泛型允许在定义类、接口和方法时使类型(类、接口)成为参数,声明的类型参数在使用时用具体的类型替换。
泛型主要应用在集合框架中。
1、为什么使用泛型
- 提高程序的类型安全;泛型的使用让编译器可以验证类型假设。
- 有助于避免(强制)转型,使得编译器能够在编译时发现转型错误而不用等到运行时
- 可以实现通用算法
2、泛型类
泛型类的定义和声明:
类名之后通过<>指定一个或者多个类型参数的名字,同时还可以对类型参数的取值范围进行限定,多个类型参数之间使用逗号分隔。
public class Matrix<T>{
….
}
泛型的使用:
定义完类型参数后,可以在该类几乎任意地方(静态块、静态属性、静态方法除外)使用类型参数。注意,父类定义的类型参数不能被子类继承。
/*实例化泛型类*/
Matrix<Float> ft=new Matrix<Float>();
3、泛型方法
方法也可以泛型化,不管定义他们的类是不是泛型化。
为什么要使用泛型方法而不是将类型T添加到类定义中呢?
- 当泛型方法是静态时,不能使用类的类型参数。
- 当T上的类型约束对于方法是局部时,这意味着没有在类的另一个方法签名中使用相同类型的T的约束。泛型方法的类型参数是局部的,可以简化封闭类型的签名。
声明泛型方法:
public <T> T ifThenElse(boolean b, T first, T second) {
return b? first : second;
}
泛型类是在实例化类时指明泛型的具体类型,泛型方法是在调用方法时指明泛型的具体类型。
编译器会允许调用下面的代码时使用类型推理来推断出T的类型,并用实际参数替代T:
String s=ifThenElse(b, ”a”, ”b”); Integer i=ifThenElse(b, new Integer(1), new Integer(2));
4、类型限制
有时我们需要限制类型参数的范围。
类型通配符(?),Matrix<?>表示任意的泛型类型。
/*表示add()可以接受任意泛型类型的参数。*/
public void add(Matrix<?> m);
这种情况下,add()可以接受的参数类型太宽泛了。开发人员可能希望限制参数的具体类型,例如只希望接受Number及其子类的类型的变量,而不接受Random、Locale等类型的变量。这样就要对通配符有所限制。
如Matrix类,使用了类型参数T,我们让Number类作为类型上界来限制这个类型参数:
/*表示Matrix中包含的参数类型是Number及其子类*/
public class Matrix<T extends Numbers>{…}
当引入了类型上界后,在使用类型时就可以使用类型上界类(Number)中定义的方法。
同理我们可以使用Number类作为类型下界:
/*表示Matrix中包含的参数类型是Number及其父类*/
public class Matrix<? super Number>{…}
5、类型擦除(Type Erasure)
泛型是在编译器这个层次实现的,在生成的字节代码中是不包含泛型的类型信息的。
使用泛型时加上的类型参数,会被编译器在编译时去掉,这个过程称为类型擦除。也就是说,由泛型附加的类型信息对JVM来说都是不可见的。
编译器在编译时尽可能地发现可能出错的地方,但是仍然无法避免在运行时刻出现类型转换异常的情况。
类型擦除的过程:
首先,找到用来替换类型参数的具体类。如果指定了类型参数的上界的话,则使用上界。
然后,把代码中的类型参数都替换成具体类型,同时去掉出现的类型声明,即<>的内容;
理解了类型擦除,就会明白编译器承担了全部的类型检查工作。编译器禁止某些泛型的使用方式,是为了确保类型的安全性。
很多泛型的特性都与类型擦除有关,如
- 静态变量是被泛型类的所有实例共享的,即泛型不能用于静态变量
- 泛型的类型参数不能用在异常处理的catch语句中,因为异常处理是由JVM在运行时刻进行的。由于类型擦除,JVM已经无法区分源于同一泛型类型的两个不同类型的异常。
6、开发泛型类
因为类型擦除机制,类型参数并不能用来(在类中)创建对象(比如T t=new T();)或是静态变量的类型。
/*泛型类*/
public class Lhist<V>{}
/*创建泛型类实例*/
Lhist<Integer>li=new Lhist<Integer>(30);
7、泛型的最佳实践
使用泛型常见的实践原则:
- 在代码中避免泛型类和原始类型混用,如List<String>和List不应共同使用。
- 使用带通配符(?)的泛型类时,需要明确通配符所代表的一组类型的概念。
- 不能实例化泛型类型变量,然后利用反射的newInstance来创建实例;同样,不能创建一个泛型的数组。
- 尽量不要忽视编译器给出的警告。
Java 集合和泛型的更多相关文章
- Java集合之泛型的使用
Java集合之泛型的使用 泛型提供了一种轻便灵活的数据操作,数据的安全性相对提高. 泛型提供了对列表元素的约束条件,比如ArrayList有序链表,可存储任意类型的元素. 此处构建一个ArrayLis ...
- Java集合与泛型中的陷阱
List,List<Object>区别 List<Integer> t1 = new ArrayList<>(); // 编译通过 List t2 = t1; // ...
- Java集合与泛型中的几个陷阱,你掉进了几个?
下面我总结了集合.泛型.数组转集合等一些常见的陷进,认真看完,相信你绝对有所收获. 1.List ,List<?> 与 List<Object> 有区别吗? 说实话,我敢保证很 ...
- Java集合和泛型
集合 常用的集合有ArrayList,TreeSet,HashMap,HashSet. ArrayList 最常用的集合,每次插入都在后面追加元素. TreeSet 以有序状态保持并可防止重复.当你需 ...
- java——集合、泛型、ArrayList、LinkedList、foreach循环、模拟ktv点歌系统
集合:一系列特殊的类,这些类可以存储任意类型的对象,长度可变,集合类都在java.util包中. 但是集合记不住对象的类型,当把对象从集合中取出时这个对象的编译类型就变成了Object类型.这样在取元 ...
- Java泛型和集合之泛型介绍
在声明一个接口和类的时候可以使用尖括号带有一个或者多个参数但是当你在声明属于一个接口或者类的变量的时候或者你在创建一个类实例的时候需要提供他们的具体类型.我们来看下下面这个例子 List<Str ...
- java数组、泛型、集合在多态中的使用及对比
我们在使用数组,泛型集合的过程中不可避免的会碰到多态,或者说什么情况下能如何使用父数组引用子数组(集合.泛型)呢? 数组在多态中的使用 元素为父类型的数组引用可指向元素为子类型的数组对象 当数组被调用 ...
- -1-3 java集合框架基础 java集合体系结构 Collection 常用java集合框架 如何选择集合 迭代器 泛型 通配符概念 Properties 集合 迭代器
集合又称之为容器存储对象的一种方式 •数组虽然也可以存储对象,但长度是固定的:显然需要可变长度的容器 集合和数组的区别? A:长度区别 ...
- Java 集合、Iterator迭代器、泛型等
01集合使用的回顾 A:集合使用的回顾 a.ArrayList集合存储5个int类型元素 public static void main(String[] args) { ArrayList<I ...
随机推荐
- JavaScript设计模式—代理模式
代理模式介绍 使用者无权访问目标对象,中间加代理,通过代理做授权和控制 代理(proxy)是一个对象,它可以用来控制对另外一个对象的访问: 代理对象和本体对象实现了同样的接口,并且会把任何方法调用传递 ...
- SRS之SrsHlsCache::reap_segment详解
1. 是否可切片的检测 首先在调用 SrsHlsCache::reap_segment 函数进行切片时,针对音频或视频,都会有一个函数来进行检测当前片的时长是否符合所要求的时长. 对于音频,会调用 S ...
- RDP连接失败的解决方法
当RDP某一桌面时,远程桌面连接提示:发生身份验证错误,要求的函数不受支持. 解决方法: 打开Run, 输入gpedit.msc,打开组策略编辑器. 如上如所示,修改配置加密Oracle修正策略. E ...
- 检查并解决CentOS 7 安装Tomcat是否成功
参考网址 https://blog.csdn.net/Blue_Sky_rain/article/details/91348791
- [log4j]Error:The method getLogger(String) in the type Logger is not applicable for the arguments
原因:本该导入import org.apache.log4j.Logger; 结果成了import java.util.logging.Logger; 如果硬把private static Logge ...
- Android中图片优化
1.对图片进行压缩:建议使用TinyPNG工具压缩 2.WebP格式(支持4.0以上)可减少文件大小 3.尽量使用NinePatch的PNG 4.图片缓存
- RecoderUtils录音工具类
import android.media.MediaRecorder; import android.os.Environment; import java.io.File; import java. ...
- Hander创建消息
每一个消息都需要被指定的Handler处理,通过Handler创建消息便可以完成此功能.Android消息机制中引入了消息池.Handler创建消息时首先查询消息池中是否有消息存在,如果有直接从消息池 ...
- RabbitMQ学习之:(三)第一个RMQ的程序 (转贴+我的评论)
RabbitMQ for Windows: Building Your First Application Posted by Derek Greer on March 7, 2012 This is ...
- Linux高级命令 ==> find、grep、sed、awk
一.find find命令用来在指定目录下查找文件.如果使用该命令时,不设置任何参数,则find命令将在当前目录下查找子目录与文件.并且将查找到的子目录和文件全部进行显示. 语法 find path ...