关于java集合的初步理解
一. 集合初始:
-
为什么要用集合:
面向对象的语言对事物的具体体现都是以事物的形式。
为了方便对多个对象的操作,就要对对象进行存储,另一方面,使用数组存储对象具有一些弊端,而集合就像是一种容器,可以动态的把多个对象的引用放入容器。
说到这里,不得不说一下数组的局限性:
1.数组只能通过下标操作存储的元素
2.数组的内存空间是连续分布的,而集合的内存空间不一定连续分布
3.数组的长度是固定的,长度的改变会产生新的数组,集合的长度是动态可变的,改变长度不会产生新的集合。
4.数组能存储引用数据和基本数据,集合只能存引用数据,集合更适合引用数据的具体操作
5.数组只能存一种类型的数据,而集合可以添加多种类型的数据
2. 集合的用途
用于存储数量不等的多个对象,还可以保存具有映射关系的关联数组
3. 集合的类别:
单列集合Collection接口和双列集合Map接口
1. Collection接口:分为Set接口和List接口
2. Map接口:具有映射关系的 key------value 对的集合
二. Collection接口:
1. Collection接口继承树
2. Collection接口的方法:
1.Collection 接口是List、Set 和Queue 接口的父接口,该接口里定义的方法既可用于操作Set 集合,也可用于操作List 和Queue 集合。
2.JDK不提供此接口的任何直接实现,而是提供更具体的子接口实现。
3. Collection集合的遍历
//遍历Collection集合创建迭代器对象 集合.iterator();
Collectionc2 = newArrayList();
c2.add("1");
c2.add("12");
c2.add("123");
c2.add("1234");
Iteratori = c2.iterator();
//在调用i.next()方法之前必须要调用 i.hasNext()方法进行判断
while(i.hasNext()) {//判断是否还有下一个元素 有向下进行
System.out.print(i.next()+" ");//取出当前的元素 指针下移
}
//迭代的过程不能对集合进行增删操作
System.out.println();
System.out.println(c2);
//遍历 增强for循环 内部 不能对迭代器进行增删操作
for(Object o:c2) {
System.out.print(o+" ");
}
4. Iterator:
1.Iterator对象称为迭代器(设计模式的一种),主要用于遍历Collection 集合中的元素。
2.所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象。
3.Iterator 仅用于遍历集合,Iterator 本身并不提供承装对象的能力。如果需要创建Iterator 对象,则必须有一个被迭代的集合。
注意:迭代器只能用于遍历,不能用于集合元素的增删,否者会发生ConcurrentModificationException异常,在用foreach和Iterator时都有可能发生。
5. Collection接口的子接口
1. List接口:
1. 特点:
有序且可以重复
取代数组存储数据的局限性
可以根据序号索引存取容器的元素
常用类ArrayList LinkedList Vector
2. 方法:
void add(intindex, Object ele)
booleanaddAll(int index, Collection eles)
Objectget(int index)
intindexOf(Object obj)
intlastIndexOf(Object obj)
Objectremove(int index)
Object set(int index, Object ele)
List subList(int fromIndex, int toIndex)
3. 类:
ArrayList:底层是数组结构,本质上是对象引用的一个可变长的数组
LinkedList:底层是链表结构
注意:ArrayList查询快 LinkedList增删快,对于频繁使用增删操作的建议使用LinkedList
4. 代码:
public class TestList {
public static void main(String[] args) {
//< >之间放的是泛型 一般是引用数据类型
ArrayList list =new ArrayList();
//将数组转换为集合
int[] arr = {1,2,3,4};
//数组的工具类Arrays
List<int[]> arrlist = Arrays.asList(arr);
for (inti = 0; i < arrlist.size(); i++) {
for (intj = 0; j < arrlist.get(i).length; j++) {
//数组转化为集合相当于将数组当做一个元素放入集合中
intp = arrlist.get(i)[j];
System.out.println(p);
}
}
LinkedListlinklist =new LinkedList<>();
linklist.add(1);
linklist.add(12);
linklist.add(16);
System.out.println(list);
linklist.addFirst(15);
System.out.println(list);
linklist.addLast(30);
System.out.println(list);
intx = linklist.removeLast();//移出最后一个数据
System.out.println(x);
}
}
2. Set接口:
1. 特点:
没有提供额外的方法
自动去重,元素无序
根据equals()方法判断元素是否相同
2. 类:
HashSet:
HashSet是Set接口的典型实现,大多数的时候使用Set集合时都会使用这个集合
HashSet的底层实现是根据Hashcode来存储集合中的元素的,具有很好的存取和查找功能
特点:无序,不是线程安全的,集合元素可以为null
注意:当向HashSet 集合中存入一个元素时,HashSet 会调用该对象的hashCode() 方法来得到该对象的hashCode 值,然后根据hashCode 值决定该对象在HashSet 中的存储位置。
HashSet 集合判断两个元素相等的标准:两个对象通过hashCode() 方法比较相等,并且两个对象的equals() 方法返回值也相等
如果两个元素的equals() 方法返回true,但它们的hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。
对于存放在Set容器中的对象,对应的类一定要重写equals()和hashCode(Object obj)方法,以实现对象相等规则。
重写hashCode()方法的基本原则:
在程序运行时,同一个对象多次调用hashCode() 方法应该返回相同的值
当两个对象的equals()方法比较返回true 时,这两个对象的hashCode() 方法的返回值也应相等
对象中用作equals()方法比较的Field,都应该用来计算hashCode 值
3. 代码:
public class TestSetColleation {
public static void main(String[] args) {
//HashSet集合的特点 无序且不重复
HashSet<Integer> set = new HashSet<Integer>();
set.add(1);
set.add(2);
//不允许重复
//如果set集合发现重复 就会覆盖重复值
set.add(1);//有重复 覆盖重复值
set.add(3);
System.out.println(set);
//HasdCode Hash值是有一定的范围的
//自动装箱
Integer i = Integer.valueOf(1);
inthash1 = i.hashCode();//算出Hash值
Integer j = Integer.valueOf(101);
inthash2 = j.hashCode();
if(hash1 == hash2) {
//调用 equals()方法 多个对象调用同一个哈希值 比较对象的内容是否一致
System.out.println("jjj");
//如果equals方法返回true则进行覆盖
}else {
System.out.println(1332);
}
//无序的
HashSet<String> set2 = newHashSet<String>();
set2.add("我");
set2.add("是");
set2.add("谁");
System.out.println("我".hashCode());
System.out.println("是".hashCode());
System.out.println("谁".hashCode());
System.out.println(set2);
test();
}
/**
* 从1 23 4 5 6 7 8 9 找出所有符合
*123 + 456 = 789
* 用 set集合
*/
private static void test() {
// TODO自动生成的方法存根
intsum = 0;
intcount = 0;
for (inti = 100; i < 1000; i++) {
for (intj = 999; j >=i; j--) {
int[] arr = newint[9];
HashSet<Integer> set = new HashSet<Integer>();
sum = i + j;
if(sum<1000) {
//找到每个位的数字
arr[0] = i%10;
arr[1] = i/10%10;
arr[2] = i/100;
arr[3] = j%10;
arr[4] = j/10%10;
arr[5] = j/100;
arr[6] = sum%10;
arr[7] = sum/10%10;
arr[8] = sum/100;
//判断0
for (intk = 0; k < arr.length; k++) {
if(arr[k] != 0) {
set.add(arr[k]);
if(set.size()==arr.length) {
count++;
System.out.println(i+"+"+j+"="+sum);
}
}
}
}
}
}
System.out.println(count);
}
}
LinkedHashSet:HashSet的子类,有序不允许重复,底层是链表结构和Set结构
TreeSet:
TreeSet有两种排序方法:
自然排序:(默认)
TreeSet 会调用集合元素的compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序排列
定制排序:
如果试图把一个对象添加到TreeSet时,则该对象的类必须实现Comparable 接口。
实现Comparable的类必须实现compareTo(Object obj) 方法,两个对象即通过compareTo(Object obj) 方法的返回值来比较大小。
注意:
向TreeSet 中添加元素时,只有第一个元素无须比较compareTo()方法,后面添加的所有元素都会调用compareTo()方法进行比较。
因为只有相同类的两个实例才会比较大小,所以向TreeSet 中添加的应该是同一个类的对象
对于TreeSet 集合而言,它判断两个对象是否相等的唯一标准是:两个对象通过compareTo(Object obj) 方法比较返回值
当需要把一个对象放入TreeSet 中,重写该对象对应的equals() 方法时,应保证该方法与compareTo(Object obj) 方法有一致的结果:如果两个对象通过equals() 方法比较返回true,则通过compareTo(Object obj) 方法比较应返回0
代码:
public class TestTreeSet {
public static void main(String[] args) {
TreeSet<TestTreeSet_test> t = new TreeSet<TestTreeSet_test>();
//添加对象
t.add(new TestTreeSet_test(1,2));
t.add(new TestTreeSet_test(0,9));
t.add(new TestTreeSet_test(3,4));
System.out.println(t);
TreeSet<Integer> t2 = new TreeSet<Integer>();
//添加int数据
t2.add(2);
t2.add(5);
t2.add(3);
t2.add(9);
t2.add(6);
System.out.println(t2);
}
}
class TestTreeSet_test implements Comparable<Object>{
intx,y;
public TestTreeSet_test() {}
public TestTreeSet_test(intx,inty) {
this.x = x;
this.y = y;
}
@Override
public int compareTo(Object o) {
if(o instanceof TestTreeSet_test) {
TestTreeSet_test t = (TestTreeSet_test) o;
if(this.x>t.x) {
return 1;
}else {
return -1;
}
}
return 0;
}
@Override
public String toString() {
return"x="+x+" y="+y;
}
}
三. Map接口:请待下回