Java集合和泛型
集合
常用的集合有ArrayList,TreeSet,HashMap,HashSet.
ArrayList
最常用的集合,每次插入都在后面追加元素。
TreeSet
以有序状态保持并可防止重复。当你需要set集合或元素按照一定的顺序排列时,它会很好用。当然,这需要付出一定的成本,每当插入新项目时,它必须要花时间找到适当的位置,而ArrayList只要把项目放在最后就行。
TreeSet的元素必须是Comparable的,你必须指出对象应该如何排序。我们已经在上面讲过,方法有两种,分别是:
实现Comparable类。
使用重载,取用Comparator参数的构造函数来创建TreeSet,就像sort()的使用一样。
class ArtistCompare implements Comparator<Song>{
public int compare(Song one,Song two){
return one.getAtist().compareTo(two.getArtist());
}
}
ArtistCompare artCompare=new ArtistCompare();
TreeSet<Song> tree=new TreeSet<Song>(artCompare);
HashMap
针对经常插入或删除中间元素所设计的高效率集合。
使用方法:
HashMap<String, Integer> scores=new HashMap<String, Integer>();
scores.put("Kathy",20);
scores.put("Jim",22);
System.out.println(scores.get("Jim"));
HashSet的遍历方法:
Iterator iter = scores.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
Object key = entry.getKey();
Object val = entry.getValue();
String relkey=(String)key;
Integer relval=(Integer) val;
doprocessing();
HashSet
防止重复的集合,可快速的寻找相符的元素。
这里有个问题,对象要怎样才算相等?是引用到完全相同的对象,还是可以使不同的对象,但是我们所关心的值相等。于是,引出一个关键问题:引用相等性和对象相等性。
引用相等性 堆上同一对象的不同引用,如果对这两个引用调用hashCode(),结果相同。如果没有被覆盖的话,hashCode()默认的行为会返回每个对象特定的序号,这个序号一般跟对象的内存位置有关,因此是唯一的。
如果想要知道两个引用是否相等,可以使用==来比较变量上的字节组合,如果引用到相同的对象,字节组合也会一样。
对象相等性 堆上的两个不同对象在意义上是相等的,如果你想把两个不同的对象视为相等,就必须override hashCode()和equals()函数。
hashCode()
HashSet使用hashcode来达到存取速度较快的存储方法,如果你尝试用对象来寻找ArrayList中的相同对象,(不用索引来找),ArrayList会从头开始找起,但HashSet不是,它是根据hashcode来找的,不需要从头找起。
重点在于hashcode相同并不一定保证对象时相等的,学过数据结构的同学肯定知道,hashCode()使用的杂凑算法很可能将多个对象传回相同的杂凑值,越糟糕的杂凑算法越容易碰撞,而且也跟数据值域的分布特性有关,因此如果两个对象的hashcode相同,并不能说它俩就相等,此时还需要使用equals()函数来进一步确认是否相等。你可以这样认为,hashcode用来缩小寻找成本,但是最后还需要equals()来确定是否真的找到了相同的对象。
hashCode()的默认行为时对在heap上的对象产生独特的值,如果你没有override过,则该class的两个对象永远不可能被认为是相同的。
class Song implements Comparable<Song>{
String title;
String artist;
public boolean equals(Object aSong ){
Song s = (Song) aSong;
return getTitle.equals(s.getTitle()); //String覆盖过equals(),我们可以调用。
}
public int hashCode(){
return title.hsahCode(); //String覆盖过hashCode(),我们直接调用就可以了。
}
public int compareTo(Song s){
return title.compareTo(s.getTitle());
}
public getTitle(){
return title;
}
public getAtirst(){
return artist;
}
}
euqals()
equals()的默认行为是执行==的比较,也就是说会去测试两个引用是否堆上heap上同一个对象,如果eqauls没有被覆盖过,两个对象永远都不会被视为相同的,因为不同的对象有不同的字节组合。
toString()
toString()是定义在Object类里的,所以每个java类都会继承到,且因为对象被System.out.println(anObject)列出来时会调用toString(),所以当你想用被System.out.println输出你自定义的对象时,你需要重定义toString().
泛型
只要你再java程序或文件中看到<>这一组符号,就代表泛型正在起作用。泛型的主要目的是让你写出有类型安全性的集合,也就是,让编译器能够帮忙防止你把Dog放到一群Cat中。
使用泛型的两种方法:
使用定义在类声明的类型参数:
public class ArrayList<E> extends AbstractList<E>...{
public boolean add (E o)
...
}
使用未定义在类声明的参数 public void takeThing (ArrayList list)
Collections.sort()
Collections.sort()是集合的常用方法,它只接受Comparable对象的list。因此,如果你自定义了一个类,然后生成了很多类对象,并存入集合中,如果你期望用Collections.sort()来对它们进行排序。你需要对你的自定义类做额外的工作。
你有两种方法:
第一种,实现Comparable 类,并覆盖它的int compareTo(T o)方法 java.lang.Comparable接口:
public interface Comparable<T>{
int compareTo(T o);
}
class Song implements Comparable<Song>{
String title;
String artist;
public int compareTo(Song s){
return title.compareTo(s.getTitle());
}
public getTitle(){
return title;
}
public getAtirst(){
return artist;
}
}
第二种,自制Comparator
使用compareTo()方法时,list中的元素只能有一种将自己与同类型的另一元素相比较的方法。但Comparator是独立于所比较元素类型之外的--它是独立的类。因此,你可以有各种不同的比较方法。例如,除了按照title排序,你也可以按照artist排序。
因此,取用Comparator版的sort()方法会用Comparator而不是内置的 compareTo()方法。有如下规则:
调用单一参数的sort(List o)方法代表由list元素上的compareTo()方法来决定顺序。因此元素必须实现Comparable这个接口。 调用sort(List o,Comparator c)方法代表不会调用list元素的compareTo()方法,而会使用Comparator的compare()方法,这也意味着list元素不用实现
Comparable.
class ArtistCompare implements Comparator<Song>{
public int compare(Song one,Song two){
return one.getAtist().compareTo(two.getArtist());
}
}
ArtistCompare artCompare=new ArtistCompare();
Collections.sort(songList,artCompare);
集合的多态
数组的多态
如果方法的参数是Animal的数组,它也能够取用Animal次类型的数组。
Animal [] animals={new Dog(),new Cat(),new Dog()};
Dog [] dogs={new Dog(),new Dog(),new Dog()};
takeAnimals(animals);
//takeAnimals()能够存取Animal[]或Dog[]参数,因为Dog也是一个Animal,多态在此处起作用
takeAnimals(dogs);
public void takeAnimals(Animal [] animals){
for(Animal a : animals){
a.eat();}
}
abstract class Animal{
void eat(){}
}
class Dog extends Animal{
void bark(){}
}
class Cat extends Animal{
void meow(){}
}
ArrayList的多态
ArrayList<Animal> animals= new ArrayList<Animal>();
animals.add(new Dog());
animals.add(new Dog());
animals.add(new Dog());
takeAnimals(animals);
public void takeAnimals(ArrayList<Animal> animals){
for(Animal a : animals){
a.eat();}
}
因为多态的关系,编译器会让Dog数组通过取用Animal数组参数的方法,这没有问题,问题是ArrayList< Animal >参数能接受ArrayList< Dog >吗,回答是,不行。如果我们在上面的程序里加上这一段,将出现编译错误。
ArrayList dogs = new ArrayList();
dogs.add(new Dog());
dogs.add(new Dog());
takeAnimals(dogs);
可能很多同学会疑惑,毕竟多态的意义就在于Animal能做的事情,Dog也能做,但你想过吗,如果我们的takeAnimals()是这样的:
public void takeAnimals(ArrayList<Animal> animals){
animals.add(new Cat());
}
这就会有问题了,理论上把Cat加到ArrayList< Animal >是合法的,这也是使用Animal的本意--让各种Animal都可以加入到此ArrayList中。但是如果你传入的是一个Dog的ArrayList给该方法,那么将会是Cat强行加入了一个Dog ArrayList中,编译器当然不会让这种事情发生。
所以,如果把方法声明成ArrayList< Animal >,它只能接受ArrayList< Animal >的参数,ArrayList< Dog>和ArrayList< Cat>都不行。
很多同学肯定又要问了,那为什么数组可以过关,而ArrayList却不行,毕竟数组也会遇到这样的问题啊。
其实这跟jvm有关,数组类型是在运行期间检查的,但集合的类型检查发生在编译期间。
下面这段程序在编译时不会出错,但运行时出错。
Dog [] dogs={new Dog(),new Dog(),new Dog()};
takeAnimals(dogs);
public void takeAnimals(Animal [] animals){
animals[0]=new Cat();
}
那有没有一种方法,让我们能够使用多态化的集合参数,就像数组那样,这样我们就可以传入Cat,Dog的集合了,只要我们自己保证不会做出格的行为,比如往Cat集合中加入Dog等等。
万能的java当然有办法,使用这种声明方式:
public void takeThing(ArrayList list)
当你这样声明函数时,编译器会阻止任何可能破坏引用参数所指集合的行为。也就是,你可以调用list中任何元素的方法,但是不能加入元素。
也就是说你可以操作集合元素,但是不能增加集合元素。如此才能保障执行期间的安全性。编译器会阻止执行期的恐怖活动。
所以下面的程序是可行的:
for (Animal a :animals){a.eat();}
但这个就过不了编译:
animals.add(new Cat());
Java集合和泛型的更多相关文章
- Java集合之泛型的使用
Java集合之泛型的使用 泛型提供了一种轻便灵活的数据操作,数据的安全性相对提高. 泛型提供了对列表元素的约束条件,比如ArrayList有序链表,可存储任意类型的元素. 此处构建一个ArrayLis ...
- Java集合与泛型中的陷阱
List,List<Object>区别 List<Integer> t1 = new ArrayList<>(); // 编译通过 List t2 = t1; // ...
- Java集合与泛型中的几个陷阱,你掉进了几个?
下面我总结了集合.泛型.数组转集合等一些常见的陷进,认真看完,相信你绝对有所收获. 1.List ,List<?> 与 List<Object> 有区别吗? 说实话,我敢保证很 ...
- Java 集合和泛型
一.集合(Collections) Java使用集合来组织和管理对象. 1.Java的集合类 集合类主要负责保存.盛装和管理对象,因此集合类也被称为容器类. 集合类分为Set.List.Map和Que ...
- 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 ...
随机推荐
- 常见移动设备的 CSS3 Media Query 整理(iPhone/iPad/Galaxy/HTC One etc.)
@charset "utf-8"; /** * iPhone 4/4s landscape & portrait */ @media only screen and (mi ...
- 深入出不来nodejs源码-内置模块引入初探
重新审视了一下上一篇的内容,配合源码发现有些地方说的不太对,或者不太严谨. 主要是关于内置模块引入的问题,当时我是这样描述的: 需要关注的只要那个RegisterBuiltinModules方法,从名 ...
- vue-cli中配置屏幕自适应(px2rem)
在vue-cli中配置屏幕自适应的方法 首先,我们需要安装flexible库. npm i lib-flexible --save 在index.html文件当中配置meta标签, <meta ...
- Js的substring和C#的Substring
Js的substring 语法: 程序代码String.substring(start, end) 说明:返回一个从start开始到end(不包含end)的子字符串. 示例: 程序代码var str= ...
- Median(vector+二分)
Median Time Limit: 5 Seconds Memory Limit: 65536 KB The median of m numbers is after sorting them in ...
- 随手记:tomcat 与JDK 安装与配置
写了3年的JAVA 每次遇到配置JDK 与按照tomcat的时候都要去网上找一下,太丢人了,所以还是记一下比较好,虽然都知道要配置哪些,但每次都还是有些不确定的感觉~ JDK : 1.安装官网 htt ...
- Console控制台的正确打开方式
Console控制台的正确打开方式 console对象提供了访问浏览器调试模式的信息到控制台 -- Console对象 |-- assert() 如果第一个参数断言为false,则在控制台输出错误信息 ...
- AJAX删除事件与加载数据
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Android Studio支持Java1.8的解决方案
Java1.8新添了一些特性,比如对lambda表达式的支持,父类推断等等,这篇文章讲述了1.8的新特性,有兴趣的同学可以点进去看看.但是由于AndroidStudio并不能直接支持Java1.8,我 ...
- C#和C++互相操作 结构体数组的传递
C++中结构体定义: typedef struct // 平面 { double time; float normal[3]; float center[3]; } plane; C++中方法声明 ...