文章目录
集合概念:对象的容器,实现了对对象常用的操作,类似于数组功能
数组和集合的区别
- 数组长度固定,集合长度不固定。
- 数组可以存储基本类型和引用类型,集合只能存储引用类型(或者基本类型的装箱操作)
Collection父接口
特点:代表一组任意类型的对象,无序、无下标、不能重复
方法
boolean add(Object obj)
//添加一个对象。
boolean addAll(Collection c)
//将一个集合中的所有对象添加到此集合中
void clear()
//清空此集合中的所有对象。
boolean contains(Object o)
//检查此集合中是否包含o对象
boolean equals(Object o)
//比较此集合是否与指定对象相等
boolean isEmpty()
//判断此集合是否为空
boolean remove(Object o)
//在此集合中移除o对象
int size()
//返回此集合中的元素个数
Object[] toArray()
//将此集合转换成数组。
类型 | 存储结构 | 是否有序 |
---|---|---|
ArrayList | 数组结构 | 是 |
LinkedList | 链表结构 | 是 |
Vector | 数组结构 | 是 |
HashSet | 哈希表(数组+链表+红黑树) | 否 |
TreeSet | 排序二叉树 | 是(要实现compare接口) |
HashMap | 哈希表(数组+链表+红黑树) | 否 |
TreeMap | 近似平衡的二叉树 | 是(要实现compare接口) |
List子接口
方法
void add(int index, Object o)
//在index位置插入对象o
boolean addAll(int index, Collection c)
//将一个集合中的元素添加到此集合中的index位置
Object get(int index)
//返回集合中指定位置的元素
List subList(int fromIndex, int toIndex)
//返回fromIndex和toIndex之间的元素(含头不含尾)
ListIterator要比Iterator好用,它可以向前或向后遍历,添加删除修改元素
//list的遍历
//3.1使用for遍历
System.out.println("----------------使用for遍历------------");
for(int i = 0; i < list.size(); i++) System.out.println(list.get(i));
//3.2使用增强for
System.out.println("-----------使用增强for--------------------");
for (Object object : list) System.out.println(object);
//3.3使用迭代器
System.out.println("-----------使用迭代器---------------------");
Iterator it = list.iterator();
while(it.hasNext()) System.out.println(it.next());
//3.4使用列表迭代器
ListIterator lit = list.listIterator();
System.out.println("-----------使用列表迭代器从前往后-----------------");
while(lit.hasNext()) System.out.println(lit.nextIndex() + ":" + lit.next());
System.out.println("-----------使用列表迭代器从后往前-----------------");
while(lit.hasPrevious()) System.out.println(lit.previousIndex() + ":" + lit.previous());
在list中存储的都是封装类,所以删除的时候要用list.remove(new Integer(10));
ArrayList[重点]
- 数组结构实现,查询遍历快,增删慢
- JDK1.2版本,运行效率快,线程不安全
源码分析
DEFAULT_CAPACITY = 10 默认容量大小
注意:如果没用向集合中添加任何元素,容量是0;添加一个元素后,容量是10
每次扩容原来的1.5倍
elementData 存放元素的数组
size 实际元素个数
add添加元素
Vector
- 数组结构实现,查询快,增删慢
- JDK1.0版本,运行效率慢,线程安全
//使用枚举器循环
Enumeration en = v1.elements();
while(en.hasMoreElements()) {
String o = (String)en.nextElement();
System.out.println(o);
}
//其他方法:v1.firstElement();v1.lastElement();v1.elementAt(0);
LinkedList
- 链表结构实现,查询慢,增删快
泛型集合
概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致
特点:
- 编译时即可检查,而非运行时抛出异常
- 访问时,不必类型转换(拆箱)
- 不同泛型之间引用不能相互赋值,泛型不存在多态
Set子接口
Set中不能用普通for循环因为里面没有根据下标取某个元素的方法
有一个LinkedHashSet,有序
HashSet/Treeset
HashSet存储过程:
- 根据hashcode计算保存的位置,如果位置为空,直接保存,否则执行第二步
- 再执行equals方法,如果equals方法为true,则认为是重复,否则形成链表
getClass()
public final Class<?> getClass()
- 返回引用存储的实际对象类型
- 判断两个引用中实际存储对象类型是否一致
hashCode()
- 返回该对象的哈希码值
- 哈希值根据对象的地址或字符串或数字使用hash算法计算出来的int类型的数值
- 相同对象返回相同哈希码
toString()
- 返回该对象的字符串表示(表现形式)
- 可以根据程序需求覆盖该方法
@override
equals()
public boolean equals(Object obj)
- 默认实现为(this == obj),比较两个对象地址是否相同
- 可进行覆盖,比较两个对象的内容是否相同
finalize()
- 当对象被判定为垃圾对象时,由JVM自动调用此方法,用以标记垃圾对象,进入回收队列
- 垃圾对象:没有有效引用指向此对象时,为垃圾对象
- 垃圾回收:由GC销毁垃圾对象,释放数据存储空间
- 自动回收机制:JVM的内存耗尽,一次性回收所有垃圾对象
- 手动回收机制:使用
System.gc()
;通知JVM执行垃圾回收
例子
package cn.edu.tyut.demo.map;
public class Person implements Comparable<Person> {
//继承了Comparable接口,可以用来比较
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;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Person o) {
return this.age - o.age;
}
//重写compareTo函数,让comparable比较是根据age来进行的
@Override
public boolean equals(Object obj) {
//1判断两个对象是否是同一个引用
if(this == obj)
return true;
//2判断obj是否为null
if(obj == null)
return false;
//3判断是否为同一个类型
if(obj instanceof Person) {
//4强制类型转换
Person p = (Person)obj;
//5比较属性
if(this.getName() == p.getName() && this.age == p.age)
return true;
}
return false;
}
@Override
public int hashCode() {
return (name + age).hashCode();
}
//让equals和hashCode判等是根据name和age来判断的
@Override
protected void finalize() throws Throwable {
System.out.println(this.name + "对象被回收了");
}
}
package cn.edu.tyut.demo.map;
import java.util.HashSet;
import java.util.Iterator;
import java.util.TreeSet;
import org.junit.Test;
public class SetTest {
@Test
public void fun1() {
HashSet<Person> set = new HashSet<Person>();
Person p1 = new Person("zhangsan", 16);
Person p2 = new Person("zhangsan", 16);
Person p3 = new Person("zhangsan", 16);
set.add(p1);
set.add(p2);
set.add(p3);
set.add(p3);//这个元素和前面以及放进去的元素重复了
//遍历方法
//1、普通的for循环不能用了
//2、增强
for (Person person : set) System.out.println(person);
//3、迭代器
//hasNext();有下一个元素
//next();获取下一个元素
//remove();删除当前元素
Iterator it = set.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
//Person [name=zhangsan, age=16]
//Person [name=zhangsan, age=16]
@Test
//TreeSet
public void fun2() {
TreeSet<Person> set = new TreeSet<Person>();
Person p1 = new Person("zhangsan",25);
Person p2 = new Person("wangwu",16);
Person p3 = new Person("lisi",17);
set.add(p1);
set.add(p2);
set.add(p3);
for (Person person : set) {
System.out.println(person);
}
Iterator<Person> it = set.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
//Person [name=wangwu, age=16]
//Person [name=lisi, age=17]
//Person [name=zhangsan, age=25]
@Test
public void fun3() {
//Comparator:实现定制比较(比较器)
//Comparable:可比较的
//创建集合,用匿名内部类表示比较规则
TreeSet<Person> set = new TreeSet<Person>(new Comparator<Person>() {
//先比较年龄,在比较名字
//使用匿名内部类就不用在Person中实现comparable接口了
@Override
public int compare(Person o1, Person o2) {
int n1 = o1.getAge() - o2.getAge();
int n2 = o1.getName().compareTo(o2.getName());//字符串中已经实现了compareTo
return n1 == 0 ? n2 : n1;
}
});
Person p1 = new Person("zhangsan",25);
Person p2 = new Person("wangwu",16);
Person p3 = new Person("lisi",17);
set.add(p1);
set.add(p2);
set.add(p3);
System.out.println(set.toString());
//[Person [name=wangwu, age=16], Person [name=lisi, age=17], Person [name=zhangsan, age=25]]
}
@Test
public void fun4() {
Person p1 = new Person("aaa", 34);
new Person("laji", 4);
p1 = new Person("bbb", 45);
System.gc();
System.out.println("回收垃圾");
}
//回收垃圾
//aaa对象被回收了
//laji对象被回收了
}
Map接口
Map接口的特点
- 用于存储任意键值对(Key-Value)
- 键:无序、无下标、不允许重复(唯一)
- 值:无序、无下标、允许重复
用remove删除的时候只需要写键的名称
录入键相同的元素,后录入的值会把前一个值代替
HashMap/TreeMap
JDK1.2版本,线程不安全,运行效率快,允许用null作为key或是value
默认容量是16,使用key的equals和hashcode作为重复依据
package cn.edu.tyut.demo.map;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import org.junit.Test;
public class MapTest {
@Test
public void fun() {
HashMap<String, Person> map = new HashMap<String, Person>();
map.put("1", new Person("zhangsan", 25));
map.put("2", new Person("Lisi", 25));
//map.put("3", new Person("8D", 80));
map.put(null, null);
//遍历map
//1、得到key的集合(使用keySet)
System.out.println("---------keySet----------");
//Set<String> keyset = map.keySet();
for (String string : map.keySet()) {
System.out.println(string);
}
//2、使用entrySet()方法(效率高)
System.out.println("---------entrySet--------");
//Set<Entry<String, Person>> entries = map.entrySet();
for (Entry<String, Person> entry : map.entrySet()) {
System.out.println(entry);
System.out.println(entry.getKey() + "-------" + entry.getValue());
}
}
// ---------keySet----------
// null
// 1
// 2
// ---------entrySet--------
// null=null
// null-------null
// 1=Person [name=zhangsan, age=25]
// 1-------Person [name=zhangsan, age=25]
// 2=Person [name=Lisi, age=25]
// 2-------Person [name=Lisi, age=25]
@Test
public void fun2() {
TreeMap<Person, String> map = new TreeMap<Person, String>();
map.put(new Person("fff", 25), "2");
map.put(new Person("tttt", 45), "5");
map.put(new Person("zhangsa", 12), "3");
System.out.println(map);
System.out.println("-------keySet()--------");
for(Person key : map.keySet()) {
System.out.println(key);
}
System.out.println("------entrySet()-------");
for(Entry<Person, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + "--------" + entry.getValue());
}
}
// {Person [name=zhangsa, age=12]=3, Person [name=fff, age=25]=2, Person [name=tttt, age=45]=5}
// -------keySet()--------
// Person [name=zhangsa, age=12]
// Person [name=fff, age=25]
// Person [name=tttt, age=45]
// ------entrySet()-------
// Person [name=zhangsa, age=12]--------3
// Person [name=fff, age=25]--------2
// Person [name=tttt, age=45]--------5
@Test
public void fun3() throws IOException {
Properties prop = new Properties();
prop.load(this.getClass().getClassLoader().getResourceAsStream("config.properties"));
String value = (String)prop.get("password");
System.out.println(value);
}
//12345
}
//config.properties
username=zhangsan
password=12345
Properties
Hashtable : JDK1.0版本,线程安全,运行效率慢,不允许null作为key或是value
Hashtable的子类Properties,要求key和value都是String。通常用于配置文件的读取
Collections方法
@Test
public void fun7() {
//Collections工具类
List<Integer> list = new ArrayList<Integer>();
list.add(4);
list.add(-1);
list.add(89);
list.add(12);
System.out.println("排序前" + list);
//sort排序
Collections.sort(list);
System.out.println("排序后" + list);
//binarySearch二分查找
int a = Collections.binarySearch(list, -1);
System.out.println("所查找的元素位置是:" + a);
//copy复制,必须保证目标数组比原始数组长
List<Integer> dest = new ArrayList<Integer>();
for(int i = 0; i < list.size(); i++) {
dest.add(0);
}
dest.add(0);
Collections.copy(dest, list);
System.out.println("被复制的目标数组是" + dest);
//reverse反转
Collections.reverse(list);
System.out.println("反转后" + list);
//shuffle打乱
Collections.shuffle(list);
System.out.println("打乱后" + list);//每次打乱后list都可能不一样
//list转成数组
Integer[] arr = list.toArray(new Integer[0]);//arr的长度肯定比后面的0大,就是list的长度
System.out.println(Arrays.toString(arr));
//把基本类型转为数组时最好用包装类,不然要用到List<int[]>
//数组转成集合
String[] names = {"张三", "李四", "王五"};
//集合是一个受限集合,不能添加和删除
List<String> list2 = Arrays.asList(names);
System.out.println("数组转成的集合是" + list2);
}
//排序前[4, -1, 89, 12]
//排序后[-1, 4, 12, 89]
//所查找的元素位置是:0
//被复制的目标数组是[-1, 4, 12, 89, 0]
//反转后[89, 12, 4, -1]
//打乱后[4, 12, -1, 89]
//[4, 12, -1, 89]
//数组转成的集合是[张三, 李四, 王五]