关于JDK中的集合总结(二)
1.2版本的JDK才出现的java集合框架。
下面介绍说一下Vector的一些特点。
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;
public class VectorDemo {
public static void main(String[] args) { Vector v = new Vector();
v.addElement("abc1");
v.addElement("abc2");
v.addElement("abc3");
v.addElement("abc4"); Enumeration en = v.elements();
while(en.hasMoreElements()){
System.out.println("nextelment:"+en.nextElement());
}
Iterator it = v.iterator();
while(it.hasNext()){
System.out.println("next:"+it.next());
}
}
}
方法名上只要有Elements的都是Vector特有 的方法。
Vector中有一个elements()方法。
elements() |
接口 Enumeration<E>
注:此接口的功能与 Iterator 接口的功能是重复的。此外,Iterator 接口添加了一个可选的移除操作,并使用较短的方法名。新的实现应该优先考虑使用 Iterator 接口而不是 Enumeration 接口。
从以下版本开始:
JDK1.0
Enumeration接口也是很早就出现的,但是现在基本上不用了,在jdk2.0之前都是使用该方法进行遍历的,那时候还没有Iterator接口。但是由于其名字比较长,而郁郁而终。
例如,要输出 Vector<E> v 的所有元素,可使用以下方法:
for (Enumeration<E> e = v.elements(); e.hasMoreElements();)
System.out.println(e.nextElement());
上面是java API中的描述,重点是使用了for循环。
LinkedList
void |
|
void |
|
getFirst() |
|
getLast() |
remove() |
|
remove(int index) |
LinkedList:
addFirst();
addLast():
jdk1.6
offerFirst();在此列表的开头插入指定的元素
offerLast();在此列表末尾插入指定的元素。
getFirst();.//获取但不移除,如果链表为空,抛出NoSuchElementException.
getLast();
jdk1.6
peekFirst();//获取但不移除,如果链表为空,返回null.
peekLast():
removeFirst();//获取并移除,如果链表为空,抛出NoSuchElementException.
removeLast();
jdk1.6
pollFirst();//获取并移除,如果链表为空,返回null.
pollLast();
自动装箱:基本数据类型转换成引用数据类型。
自动拆箱:引用数据类型和基本数据类型做运算的时候。
ArrayList集合存储自定对象:
Person.java
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
ArrayListTest.java
import java.util.ArrayList;
import java.util.Iterator;
public class ArrayListTest {
public static void main(String[] args) {
ArrayList list = new ArrayList(); list.add(new Person("lisi1",11));
list.add(new Person("lisi2",12));
list.add(new Person("lisi3",13));
list.add(new Person("lisi4",14)); Iterator it =list.iterator();
while(it.hasNext()){
//System.out.println(((Person) it.next()).getName()+"--"+((Person) it.next()).getAge());
//输出:
//lisi1--12
//lisi3—-14 出现名字和姓名交错的现象原因就是next()访问完一个对象之后接着去访问下一个对象。
Person p = (Person) it.next();
System.out.println(p.getName()+"----"+p.getAge());
}
}
}
输出结果:
lisi1----11
lisi2----12
lisi3----13
lisi4----14
Set:元素不可以重复,是无序的。
Set接口中的方法和Collection一致。
|--HashSet: 内部数据结构是哈希表 ,是不同步的。
如何保证该集合的元素唯一性呢?
是通过对象的hashCode和equals方法来完成对象唯一性的。
如果对象的hashCode值不同,那么不用判断equals方法,就直接存储到哈希表中。
如果对象的hashCode值相同,那么要再次判断对象的equals方法是否为true。
如果为true,视为相同元素,不存储。如果为false,那么视为不同元素,就进行存储。
记住:如果元素要存储到HashSet集合中,必须覆盖hashCode方法和equals方法。
一般情况下,如果定义的类会产生很多对象,比如人,学生,书,通常都需要覆盖equals,hashCode方法。
建立对象判断是否相同的依据。
哈希算法是底层windows做的,而且针对不同的对象有不同的哈希算法运算。
java类中有的哈希算法是native用的windows底层 的,有的根据对象的不同进行了重写。
哈希表:哈希这种算法会算出很多的值,把这些值存储起来形成一个表。表中有对应关系。
哈希表中还是数组。只是哈希这种算法对数组进行了优化。
哈希算法有一种最常见的算法就是取余。
哈希表中不能有重复的元素。
哈希表是如何判断元素是否是重复的?
“ab”和”ba”产生的哈希值是一样的,取余之后都是5,但是内容不一样,哈希值对这样的情况也有对应的方法,在5角标出“挂”一个”ba”。
在list集合remove和contains都要判断相不相同,都是用的equals、
如果到了set集合,要删除一个元素,要依据该元素是否和该容器中的元素是否相同。
hashset依据hashcode和equals。
用HashSet存储自定义对象
Person.java
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
HashSetTest.java
import java.util.HashSet;
import java.util.Iterator;
public class HashSetTest {
public static void main(String[] args) {
HashSet set = new HashSet();
set.add(new Person("lisi1",11));
set.add(new Person("lisi2",12));
set.add(new Person("lisi3",13));
set.add(new Person("lisi4",14));
set.add(new Person("lisi4",14));
Iterator it = set.iterator();
while(it.hasNext()){
Person p = (Person) it.next();
System.out.println(p.getName()+"---"+p.getAge());
}
}
}
打印的结果是:
lisi3---13
lisi4---14
lisi1---11
lisi2---12
lisi4---14
集合中存储进去了两个“lisi4 14”又是集合Set ,Set集合中不会再存储相同的元素。为什么出现这种情况。
首先这是Set存储用户自定义对象。
其次Person类继承的是Object,每new一个Person都有不同的地址值,hashcode不同,对于Set集合来说是不同的元素。
第三你自己定义的只要名字和年龄一样就是不同的对象这个规则程序现在是不知道的。需要你自己去定义,完善。
修改之后的代码:
Person.java
public class Person extends Object {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
//hashCode()方法返回的是一个int类型的值,这里根据Person类对象的特点,返回一个由name和age属性决定的值最合适。age之后乘以的数字只要不是1,都可以。
@Override
public int hashCode() {
System.out.println(this+".......hashCode");
return name.hashCode()+age*27;
}
@Override
public boolean equals(Object obj) {
if(this == obj)
return true;
if(!(obj instanceof Person))
throw new ClassCastException("类型错误");
System.out.println(this+"....equals....."+obj);
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age;
}
public String toString(){
return name +":"+ age;
}
}
从输出的结果可以看出来,这两句if语句并没有执行,因为如果执行了就不会再执行下面的语句了,if中的语句是return结束语句。我在debug模式下inspect监察if中的语句也都是false。
第二if语句感觉到确实是有用,第一句有什么用处呢?
第一if语句的用处就在于,当判断完hashCode()方法之后hash值相同,如果内容也相同,就用if(this ==obj),这样结束equals语句中的判断。
在写上面这段代码时候,我没有重写toString方法,程序就会报错。
Exception in thread "main" java.lang.StackOverflowError
at java.lang.Object.toString(Unknown Source)
at java.lang.String.valueOf(Unknown Source)
at java.lang.StringBuilder.append(Unknown Source)
at Mypack.Person.hashCode(Person.java:26)
如果不重写此方法打印的就是对象,如果不重写toString就是打印的hashcode值,但是这里重写了hashCode方法。
HashSetTest.java
import java.util.HashSet;
import java.util.Iterator;
public class HashSetTest {
public static void main(String[] args) {
HashSet set = new HashSet();
set.add(new Person("lisi1",11));
set.add(new Person("lisi2",12));
set.add(new Person("lisi3",13));
set.add(new Person("lisi4",14));
set.add(new Person("lisi4",14));
Iterator it = set.iterator();
while(it.hasNext()){
Person p = (Person) it.next();
//System.out.println(p);
System.out.println(p.getName()+"---"+p.getAge());
}
}
}
输出:
lisi1:11.......hashCode
lisi2:12.......hashCode
lisi3:13.......hashCode
lisi4:14.......hashCode
lisi4:14.......hashCode
lisi4:14....equals.....lisi4:14
lisi2---12
lisi1---11
lisi4---14
lisi3---13
从上面的输出可以看出在初始化Set集合的时候调用了hashCode()方法,在初始化第二个lishi4的时候set就对其中的元素进行了check,用到了equals方法。
System.out.println(age.hashCode());
System.out.println(name.hashCode());
当时很纳闷name作为一个类中的属性,怎么能有hashCode()方法呢?hashCode()方法不是对象才所具有的吗?于是我就尝试打印age的哈希值,报这个错误:Cannot invoke hashCode() on the primitive type int。
hashCode()确实只有对象才有,但是age是个int类型的,name是String类型的,String类型是对象类型。所以name属性有hashCode()方法。
/*
* 定义功能去除ArrayList中的重复元素。
*/
Person.java
public class Person extends Object {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String toString(){
return name +":"+ age;
} @Override
public boolean equals(Object obj) { if(this == obj)
return true;
if(!(obj instanceof Person))
throw new ClassCastException("类型错误");
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age;
}
}
ArrayList中判断元素是否存在就只重写了一个equals()方法。
用equals()方法来判断对象的属性值是否都相同。
ArrayListTest2 .java
public class ArrayListTest2 {
public static void main(String[] args) {
ArrayList al = new ArrayList();
al.add(new Person("lisi1",21));
al.add(new Person("lisi2",22));
al.add(new Person("lisi3",23));
al.add(new Person("lisi4",24));
al.add(new Person("lisi2",22));
al.add(new Person("lisi3",23)); System.out.println(al);
al = getSingleElement(al); System.out.println(al.remove(new Person("lisi2",22))); //返回值是true
//虽然这个地方new的是一个新对象,但是remove还是把arraylist中的以有该数据删除,因为关键的地方是contains中判断的就是equals,
//equals两个数据内容相同则视为同一个元素,remove返回的是boolean。
System.out.println(al);
}
public static ArrayList getSingleElement(ArrayList list) {
ArrayList temp = new ArrayList();
Iterator it = list.iterator();
while(it.hasNext()){
Object obj = it.next();
//判断被迭代到的元素是否在临时容器中存在
if(!temp.contains(obj)){
temp.add(obj);
}
}
return temp;
}
}
输出:
[lisi1:21, lisi2:22, lisi3:23, lisi4:24, lisi2:22, lisi3:23]
true
[lisi1:21, lisi3:23, lisi4:24]
LinkedHashSet
HashSet是无序的,但是其下的小弟是有有序功能的,就是LinkedHashSet。
具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。
保证唯一还要有序就直接用LinkedHashSet.就可以实现。
HashSet hs = new LinkedHashSet();
|--TreeSet:可以对Set集合中的元素进行排序。是不同步的,即是线程不安全的。
判断元素唯一性的方式:就是根据比较方法compareTo()的返回结果是否是0,是0,就是相同元素,不存。
集合中判断元素不同的方式???
Set中其他的都根据hashcode和equals方法。
TreeSet对元素进行排序的方式一:
让元素自身具备比较功能,就需要实现Comparable接口。覆盖compareTo方法。
如果不要按照对象中具备的自然顺序进行排序。如果对象中不具备自然顺序。怎么办?
可以使用TreeSet集合第二种排序方式二:
让集合自身具备比较功能,定义一个类实现Comparator接口,覆盖compare方法。
将该类对象作为参数传递给TreeSet集合的构造函数。
TreeSet是排序用的,有排序就需要比较。
public interface Comparable<T>
此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。
compareTo
int compareTo(T o)
比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
只要对象需要比较就要实现这个接口。
字符串String 本身就实现了Comparable接口,可以直接进行排序。
public int compareTo(Object o) { Person p = (Person)o; int temp = this.age-p.age;
return temp==0?this.name.compareTo(p.name):temp; int temp = this.name.compareTo(p.name);
return temp==0?this.age-p.age:temp;
}
集合自身具有比较性,具有两个才能比。而元素自身具有比较性传一个就能比,元素自身是一个对象。
TreeSet(
Comparator<? super
E> comparator)
构造一个新的空 TreeSet,它根据指定比较器进行排序。
接口 Comparator<T>
|
compare
int compare(T o1,T o2)
比较用来排序的两个参数。根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。
TreeSet具备比较器,Person具备自然排序,进行元素比较时以TreeSet为主。开发中也是。
java中的很多类都实现了Comparable接口。String,Integer。
凡是一个类具备n多对象的,基本上都实现了这个接口,让其具备比较性。
这个是类的默认比较方式。如果想指定的话最好使用比较器进行。
TreeSetDemo.java
TreeSet ts = new TreeSet(new ComparatorByName());
让TreeSet集合对象在一开始初始化的时候就具备一个比较器。
ComparatorByName.java
姓名比较器的具体实现:
import java.util.Comparator;
/**
* 创建了一个根据Person类的name进行排序的比较器。
*/
public class ComparatorByName implements Comparator { @Override
public int compare(Object o1, Object o2) {
Person p1 = (Person)o1;
Person p2 = (Person)o2; int temp = p1.getName().compareTo(p2.getName()); return temp==0?p1.getAge()-p2.getAge(): temp;
}
}
根据字符串的长度设置比较器。
ComparatorByLength.java
public class ComparatorByLength implements Comparator {
@Override
public int compare(Object o1, Object o2) {
String s1 = (String)o1;
String s2 = (String)o2; int temp = s1.length()-s2.length(); return temp==0? s1.compareTo(s2): temp;
}
}
if(this.hashCode()== obj.hashCode() && this.equals(obj))
哈希表确定元素是否相同
1,判断的是两个元素的哈希值是否相同。
如果相同,在判断两个对象的内容是否相同。
2,判断哈希值相同,其实判断的是对象的hashCode的方法。判断内容相同,用的是equals方法。
注意:如果哈希值不同,是不需要判断equals。
关于JDK中的集合总结(二)的更多相关文章
- Java中的集合(十二) 实现Map接口的WeakHashMap
Java中的集合(十二) 实现Map接口的WeakHashMap 一.WeakHashMap简介 WeakHashMap和HashMap一样,WeakHashMap也是一个哈希表,存储的也是键值对(k ...
- Java中的集合(二)单列集合顶层接口------Collection接口
Java中的集合(二)单列集合顶层接口------Collection接口 Collection是一个高度封装的集合接口,继承自Iterable接口,它提供了所有集合要实现的默认方法.由于Iterab ...
- 关于JDK中的集合总结(一)
静态方法只能继承,不能重写(Override). StringBufffer,数组,对象 都是容器. 加入数据,“zhangsan” true ,67, 三个数据数据类型不同,不能用数组作为集合,只能 ...
- 关于JDK中的集合总结(三)
泛型: jdk1.5出现的安全机制. 好处: 1,将运行时期的问题ClassCastException转到了编译时期. 2,避免了强制转换的麻烦. <>:什么时候用?当操作的引用数据类型不 ...
- 集合篇 —— Collection(1):JDK 中的重复实现问题
1. 问题的提出 在 Java 的集合体系当中,无论是 List(列表)还是 Set(集),在设计的时候都存在一个很奇怪的现象:这两种集合的接口,Java 都为其设计了抽象类 Abstrac ...
- Java中的集合框架-Collection(二)
上一篇<Java中的集合框架-Collection(一)>把Java集合框架中的Collection与List及其常用实现类的功能大致记录了一下,本篇接着记录Collection的另一个子 ...
- JDK中日期和时间的几个常用类浅析(二)
java.util.Calendar JDK中的java.util.Calendar类主要是用来处理日期和时间相关的算法运算.当你需要做一些关于日期和时间的高级算数操作时,此类可能就是你的最好选择 ...
- JDK中String类的源码分析(二)
1.startsWith(String prefix, int toffset)方法 包括startsWith(*),endsWith(*)方法,都是调用上述一个方法 public boolean s ...
- 观察者模式--java jdk中提供的支持
一.简介 观察者设计模式有如下四个角色 抽象主题角色:把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者.抽象主题提供一个接口,可以增加和删除观察者角色.一般用一个抽象 ...
随机推荐
- homework-1
看到这个题目开始我只能想到动态规划四个字,但具体采用什么方法,如何写成代码却还未成型.动态规划的典型特点就是利用之前的结果.于是我很快想到了之前一个比较典型的小程序,即求最长的连续字符串.这两个题目有 ...
- homework-06&homework-09
homework-06 1) 把程序编译通过, 跑起来 , 把正确的 playPrev(GoMove) 的方法给实现了. public void playPrev(GoMove gm) { // ne ...
- POJ 3026 Borg Maze(bfs+最小生成树)
Borg Maze Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 6634 Accepted: 2240 Descrip ...
- 关于EL表达式的大小写问题。谁来帮我解答?
最近在学习ssh框架,今天遇到了一个非常奇怪的问题.我想在jsp页面中的到session中的数据.<%=s.getUserYes() %>这样写能得到数据, ${sessionScope. ...
- php 基本符号
用这么久了,竟然PHP的基本符号都没有认全,看到@号还查了半天才知道什么意思.把基本符号列表帖一下吧,需要的朋友可以参考~ 注解符号: // 单行注解 /* ...
- Bump mapping的GLSL实现 [转]
原文 http://www.cnblogs.com/CGDeveloper/archive/2008/07/03/1234206.html 如果物体表面细节很多,我们可以不断的精细化物体的几何数据,但 ...
- 图形化OpenGL调试器 BuGLe [转]
BuGLe 结合图形化的OpenGL调试与选择的过滤器上的OpenGL命令流.调试器可以查看状态.纹理.framebuffers ,着色器,而过滤器允许日志,错误检查,自由相机控制,视频捕捉等. 主页 ...
- thrift学习笔记
Thrift学习笔记 一:thrift介绍 Thrift是facebook开发的用来处理各不同系统之间数据通讯的rpc服务框架,后来成为apche的开源项目.thrift支持多种程序语言,包括Java ...
- iOS 2D绘图详解(Quartz 2D)之路径(stroke,fill,clip,subpath,blend)
Stroke-描边 影响描边的因素 线的宽度-CGContextSetLineWidth 交叉线的处理方式-CGContextSetLineJoin 线顶端的处理方式-CGContextSetLine ...
- mydumper原理4
Mydumper是一个针对mysql和Drizzle的高性能多线程备份和恢复工具.开发人员分别来自MySQL,Facebook,SkySQL公司.目前已经在有一些大型产品业务上测试并使用了Mydump ...