点击跳转到指定介绍
list & Set
list下面是他们的关系表
–Collection–(单列集合) –|----> List–(有序、可重复数据) —||----> ArrayLis–(主要实现类) —||----> LinkedList (看情况) —||----> Vector–(古老实现类)Collection接口–>常用方法应用:
import com.sun.org.apache.xpath.internal.operations.String;
import org.junit.Assert;
import org.junit.Test;
import java.util.*;
/***
* Collection接口的应用测试类
* 建议导入org.junit.Test,采用@test
* 这里讲 Collection 接口的常用方法!
*
* @author: G_night
* 转载请声明作者
* Reprint please state the author
***/
public class MyCollection {
/**
* add() \ contains() \ remove()
* 添加 || 查询是否包含 || 移除
**/
@Test
public void test_1(){
Collection coll = new ArrayList();
//add添加元素
coll.add(123);
coll.add("Wang");
coll.add(new Person("Liu",11));
//contains(Object obj)判断是否包含
boolean bool_123=coll.contains(123);
System.out.println(bool_123);
System.out.println(coll.contains("Wang"));
System.out.println(coll.contains(new Person("Liu",11)));
/*
其实contains比较调用的是equals
因为String的重写了String所以是比较内容,故返回true
而Perosn还没有重写,所以返回false
如果要返回true,那就重写equals吧(示例的person已经重写了equals)
*/
//containsAll(Collection new_coll);
//判断new_coll的元素是否都存在coll中
Collection new_coll = Arrays.asList(123,new Person("Liu",11));
System.out.println("是否都包含:"+coll.containsAll(new_coll));
//remove(element) 移除元素,会先使用equals去找有没有一样的,再移除,
//所以也要重写equals
//该remove只能移除第一个,所以还是显示true
coll.add(new Person("Liu",11));
coll.remove(new Person("Liu",11));
System.out.println("第一次移除:"+coll.contains(new Person("Liu",11)));
//removeAll会移除coll中re_coll的元素,并且不是只移除一个而是后面多个都一起移除
Collection re_coll=Arrays.asList(new Person("Liu",11));
coll.removeAll(new_coll);
System.out.println("第二次移除:"+coll.contains(new Person("Liu",11)));
}
/**
* retainAll() 求交集
* toArray() 集合变数组 -> 便于Collection遍历查看
* hashcode() 求hashcode
**/
@Test
public void test_2(){
Collection coll=new ArrayList();
coll.add(123);
coll.add(new Person("Liu",12));
Collection t_coll=Arrays.asList(123);
//求coll和t_coll的交集,并赋值给coll
//求交集前
System.out.println("求交集前:");
Object[] arr=coll.toArray();//toArray是为了方便遍历
for(int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
//求交集后
System.out.println("\n求交集后:");
coll.retainAll(t_coll);
arr=coll.toArray();//toArray是为了方便遍历
for(int i=0;i 为容器而生
* 如果是List 可以使用iterator.hasNext()遍历 ArrayList
* 还有一些列迭代器的应用案例
* 注:ArrayList 还可以使用 list.get(i) 遍历
**/
@Test
public void test_3(){
Collection coll=new ArrayList();
coll.add(123);
coll.add("Wang");
coll.add(new Person("Liu",12));
coll.add(false);
System.out.println("iterator遍历方式:");
Iterator iterator=coll.iterator();
while(iterator.hasNext()){
// 案例一、移除Wang
Object obj=iterator.next();//先放到obj做判断操作
System.out.println(obj);
if("Wang".equals(obj)){
iterator.remove();
}
}
// 案例二、再次刷新迭代器的指针,回到头部
// 发现上一次的“Wang”成功删除
System.out.println("\n第二次遍历:");
iterator=coll.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
使用到的Person类:
import java.util.Objects;
/***
* 测试采用的Person类
*
* @author: G_night
* 转载请声明作者
* Reprint please state the author
***/
public class Person {
private String name;
private int age;
Person(String name,int age){
setName(name);
setAge(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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
/*
重写equals,最好配上hashcode
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
List接口及其实现类 – 详解
ArrayList是使用object[] element
存储、线程不安全、效率高;
Vector是使用object[] element
存储、线程安全、效率低;
LinkedList是使用双向链表
存储、插入和删除效率比ArrayList更高,不过不支持随机访问,访问效率不如ArrayList
相同点:都实现了List接口,存储数据的特点相同,都是有序的,课程夫的数据
不同点:线程安全和效率不同,底层实现也有所不同,看上面~
package com.zzt.MyLIst;/*
* @author: G_night
* 转载请申明作者
* Reprint please state the author
*/
import org.junit.Test;
import java.util.ArrayList;
import java.util.Iterator;
public class MyListTemplate {
@Test
public void test1(){
//初始化
ArrayList list=new ArrayList();
list.add(123);
list.add("Wang");
list.add(false);
list.add(123);
//indexof()返回第一次出现的位置,从0开始,未找到就返回-1
int index=list.indexOf(123);
System.out.println("123第一次出现的位置:"+index);
//lastindexof()返回最后一次出现的位置
int lastindex=list.lastIndexOf(123);
System.out.println("123最后一次出现的位置:"+lastindex);
//remove有两种,一个是移除对象,一个是按照index移除
// (移除对象,没有的话不会跑出错误)(按照index移除,越界会抛出错误)
list.remove(0);
list.remove(new Integer(1234));
//set(index,element),在指定index修改元素
//最后输出的时候,会发现“Wang”也不见了
//这是因为移除了第一个后,后面的元素往前移动了,
// 然后又使用了set覆盖了第0个的元素,故“Wang”消失了
list.set(0,123);
Iterator it=list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
System.out.println("\n获取index=1元素:"+list.get(1));
}
}
底层实现情况 – 简述
ArrayList:
package diceng;/*
* @author: G_night
* 转载请申明作者
* Reprint please state the author
*/
import java.util.ArrayList;
public class MyArrayList {
public static void main(String[] args) {
//JDK1.7
ArrayList arrayList=new ArrayList();//底层创建了,长度为10的数组 Object[]
// 每次添加数组,都会判断是否会溢出,溢出的话就扩容为原来的1.5倍(默认)
//JDk1.8
ArrayList arrayList_1_8=new ArrayList();//此时还没有创建长度为10的数组
arrayList_1_8.add(123);//此时才创建了长度为10的数组
// 所以jdk8更加节省内存,延迟了创建
}
}
LinkedList:
package diceng;/*
* @author: G_night
* 转载请申明作者
* Reprint please state the author
*/
import java.util.LinkedList;
public class MyLinkedList {
public static void main(String[] args) {
LinkedList linkedList=new LinkedList();
//声明了Node类型的first和last属性,默认值为null
//相对于ArrayList,LinkedList更适合频繁插入删除,
//因为采用的是双向链表
}
}
//Node(原生的是private static)的定义方式:
class Node{
E item;
Node next;
Node prev;
Node(Node prev,E element,Node next){
this.item=element;
this.next=next;
this.prev=prev;
}
}
总结
List方法的增、删、查、改,插入、遍历、求交集:
增:add(element) 删:remove(obj) 查:indexof(obj) 改:set(inedx,element) 插入:add(index,element) 这个是在index前一位加入哦 遍历:使用iterator等等 求交集:retains(element) or retainsAll(obj) Set下面是他们的关系表
–Collection–(单列集合) –|----> Set–(无序、不可重复数据) —||----> HashSet–(主要实现类) ------|||----> LinkedHashSet (HashSet的子类,可按插入顺序遍历数据) —||----> TreeSet–(底层红黑树,按照指定属性进行排序)无序性 != 随机性
无序性是指存储的按照哈希值排序,而不是按照插入顺序排序
要明白一点:哈希值一样不代表该元素完全相同
HashSet底层是一个数组 Object[]
通过hashCode()
和equals()
判断是否为相同的元素
所以往HashSet添加元素前,一定要重写hashCode()
和equals()
具体判断过程为:
计算出哈希值,看索引位置是否有元素了,没有的话添加成功 如果有该哈希值,那么调用equals()
判断是否相同,如果相同添加失败,不相同就添加成功
示例:
package com.zzt.MySet;/*
* @author: G_night
* 转载请申明作者
* Reprint please state the author
*/
import org.junit.Test;
import com.zzt.MySet.Person;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class MySetTemplate {
/**
* Set没有新的方法,都是Collection接口的方法实现
**/
@Test
public void test1(){
Set set=new HashSet();
set.add(456);
set.add("AA");
set.add(new Person("Liu",12));//Person类见上面Collection的示例
Iterator it=set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
拓展:
为什么重写HashCode方法,采用了31这个数字?
原因:
31只占5bits,乘法造成数据溢出的概率小 i*31 == (i< 结果只能被素数本身还有1来整除 LinkedHashSetLinkedHashSet
和HashSet
其实存储方式是一样的,都是放在数组中,但是他们多了一个前置和后置的索引,故使用iterator索引的时候,会按照插入顺序显示出来!
LinkedHashSet
对于频繁的遍历操作比HashSet
更好
优势:规定顺序排序,查询速度比List快
注意事项:
TreeSet不能再一个Set对象中添加不同类的对象 分自然排序
& 规定排序
-> 需要重写compareTo
重写步骤:
类添加 implements Comparable
;
重写compareTo
package com.zzt.MySet;
import java.util.Objects;
/***
* 测试采用的Person类
* 这里添加了compareTo用于TreeSet
* @author: G_night
* 转载请声明作者
* Reprint please state the author
***/
public class Person implements Comparable{
private String name;
private int age;
Person(String name, int age){
setName(name);
setAge(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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
/*
重写equals,最好配上hashcode
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public int compareTo(Object obj){
if(obj instanceof Person){
Person person=(Person) obj;
//用name&age是否相同作为判断,并按照姓名顺序来比较
if(this.age==person.age&&this.name.equals(person.name)){
return 0;
}
return this.name.compareTo(person.name);
}else{
throw new RuntimeException("类型不匹配");
}
}
}
我们还可以自己在test程序中写方法定义排序(见test2):
package com.zzt.MySet;/*
* @author: G_night
* 转载请申明作者
* Reprint please state the author
*/
import org.junit.Test;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class MyTreeSet {
@Test
public void test1(){
TreeSet set=new TreeSet();
set.add(new Person("Liu",12));
set.add(new Person("Liu",12));
set.add(new Person("Aang",12));
Iterator it=set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
@Test
public void test2(){
Comparator com=new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof Person && o2 instanceof Person){
Person p1=(Person) o1;
Person p2=(Person) o2;
return Integer.compare(p1.getAge(),p2.getAge());
}else{
throw new RuntimeException("类型不匹配");
}
}
};
TreeSet set=new TreeSet(com);
set.add(new Person("Liu",12));
set.add(new Person("Liu",12));
set.add(new Person("Aang",18));
Iterator it=set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}