目录
集合产生的原因:
数组可以保存多个对象,但在无法确定需要保存多少个对象时,数组将不再适用,因为数组的长度不可变。
例如,要保存一个学校的学生信息,由于不停有新生来报道,同时也有学员毕业离开学校,这时学生的数目无法固定,并且随时可能变动。
为了保存这些数目不确定的对象,Java中提供了集合,集合可以存储任意类型的对象,并且长度可变。
定义:Java中的集合就像一个容器,专门用来存储Java对象。
说明:集合对象可以是任意的数据类型,并且长度可变。
注意:这些集合类都位于java.util包中,在使用时一定要注意导包的问题。
集合分为两大类:
单列集合(Collection):
1.单列集合用于存储一系列符合某种规则的元素。
2.Collection集合有两个重要的子接口,分别是List和Set。
3.List集合的特点是元素有序、可重复。该接口的主要实现类有ArrayList和LinkedList。
4.Set集合的特点是元素无序丶不可重复。该接口的主要实现类有HashSet和TreeSet。
Collection:
Collection 是接口 不能new
和Map接口区分,添加元素是add方法.
Collection col1=new ArrayList();
col1.add("a");
col1.add("b");
col1.add("c");
Collection col2=new ArrayList();
col2.add(1);//为什么可以添加基本数据类型?:自动包装
col1.addAll(col2);
List:
定义: List接口继承自Collection 接口 ,是单列集合的一个重要分支,习惯性的会将实现了List接口的对象称为List集合
特点: List集合中有序 且允许出现重复元素,所有的元素是以一种线性方式进行存储的,在程序中可以通过索引(类似于数组中的元素角标)来访问集合中的元素。
List集合还有一个特点就是元素有序,即元素的存入顺序和取出顺序一致
ArrayList
说明:
ArrayList是List接口的一个 实现类,它是程序中最常见的一种集合。
ArrayList内部的数据存储结构是数组形式。
特点:
由于ArrayList的存储结构,在增加或删除指定位置的元素时,会创建新的数组,效率比较低,因此不适合做大量的增删操作。
这种数组结构允许程序通过索引的方式来访问元素,使用ArrayList集合在遍历和查找元素时显得非常高效。
实例:
import java.util.ArrayList;
import java.util.List;
public class ArrayLisrDemo1
{
public static void main(String[] args)
{
List list=new ArrayList();
list.add("java");
list.add("hello");
list.add("world");
list.add("good");
System.out.println(list);
System.out.println(list.get(3));
list.set(1, "nimei");
System.out.println(list);
System.out.println("集合的长度:" + list.size());
System.out.println("第2个元素是:" + list.get(1));
System.out.println(list.remove(2));
System.out.println(list.indexOf("nimei"));
}
}
/*
输出结果:
[java, hello, world, good]
good
[java, nimei, world, good]
集合的长度:4
第2个元素是:nimei
world
1
*/
LinkedList集合(不做重点,掌握特点):
说明:
LinkedList是List接口的 另一个实现类 。
LinkedList内部包含有两个Node类型的first和last属性的双向循环链表结构。
特点:
由于LinkedList的存储结构, LinkedList集合对于元素的遍历和查找效率较低。
LinkedList集合对于元素的增删操作表现出很高的效率
LinkedList特有的方法:
实例:
LinkedList link = new LinkedList();
link.add("stu1");
link.add("stu2");
link.offer("offer"); // 向集合尾部追加元素
link.push("push"); // 向集合头部添加元素
Object object = link.peek(); //获取集合第一个元素
link.removeFirst(); // 删除集合第一个元素
link.pollLast(); // 删除集合最后一个元素
Collection集合遍历:
Iterator遍历集合:
定义: Iterator接口是Java集合框架中的一员,主要用于迭代访问(即遍历)Collection中的元素,因此Iterator对象也被称为迭代器。
import java.util.List;
public static void main(String []args)
{
List l=new ArrayList();
l.add("java");
l.add("hello");
l.add("world");
l.add("good");
Iterator it=l.iterator();//返回类型就是一个Iterator的对象
System.out.println(it.next()+" n");
while(it.hasNext())//hasNext判断是否还有元素.
{
String s=(String) it.next();//Object对象转换为String类型
System.out.println(s);
}
}
/*
输出结果为:
java n
hello
world
good
*/
List迭代器ListIterator
Iterator有一个子类,不仅可以对集合进行从前向后遍历,还可以从后面向前遍
//List迭代器,可以从前向后遍历
ListIterator lit=list.listIterator();
while(lit.hasNext()) {//向后遍历
String str=(String)lit.next();//next返回的Object对象
System.out.print(str+" ");
}
System.out.println();
while(lit.hasPrevious()) {//向前遍历
String str=(String)lit.previous();
System.out.print(str+" ");
}
foreach遍历集合:
定义: foreach循环是一种更加简洁的for循环,也称 增强for循环,用于遍历数组或集合中的元素。
import java.util.*;
public class JavaArrayListDemo
{
public static void main(String[]args)
{
ArrayList<String> list=new ArrayList<String>();
Collections.addAll(list, "a","t","at");
Collections.reverse(list);
printarray(list);
System.out.println(Collections.max(list));
Collections.sort(list);
printarray(list);//这里的printarray方法是自定义的一个方法,不是java的
Collections.shuffle(list);
printarray(list);
}
public static void printarray(ArrayList<String> list)
{
for(String s:list)
System.out.print(s+" ");
System.out.println(" ");
}
}
shuffle方(仅做了解) static void shuffle(List<?> list)
使用默认随机源对列表进行置换,所有置换发生的可能性都是大致相等的。 static void shuffle(List<?> list,
Random rand) 使用指定的随机源对指定列表进行置换,所有置换发生的可能性都是大致相等的,假定随机源是公平的
通俗一点的说,就像洗牌一样,随机打乱原来的顺序。
在这里,集合加了泛型:
泛型,即“参数化类型”。就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
- 一些常用的泛型类型变量:
E:元素(Element),多用于java集合框架
K:关键字(Key)
N:数字(Number)
T:类型(Type)
V:值(Value)
实例:
假定我们有这样一个需求:写一个排序方法,能够对整型数组、字符串数组甚至其他任何类型的数组进行排序,该如何实现?
答案是可以使用 Java 泛型
使用 Java 泛型的概念,我们可以写一个泛型方法来对一个对象数组排序。然后,调用该泛型方法来对整型数组、浮点数数组、字符串数组等进行排序。
public class MethodTest
{
// 泛型方法 printArray
public static < E > void printArray( E[] inputArray )
{
// 输出数组元素
for ( E element : inputArray ){
System.out.printf( "%s ", element );
}
System.out.println();
}
public static void main( String args[] )
{
// 创建不同类型数组: Integer, Double 和 Character
Integer[] intArray = { 1, 2, 3, 4, 5 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
System.out.println( "整型数组元素为:" );
printArray( intArray ); // 传递一个整型数组
System.out.println( "\n双精度型数组元素为:" );
printArray( doubleArray ); // 传递一个双精度型数组
System.out.println( "\n字符型数组元素为:" );
printArray( charArray ); // 传递一个字符型数组
}
}
JDK 8——forEach遍历集合
定义: forEach(Consumer action)方法是JDK 8中新增的遍历集合元素的方法,根据Lambda表达式特性,该方法所需要的参数是一个函数式接口。
list.forEach(obj -> System.out.println("迭代集合元素:"+obj));
说明: JDK 8中还针对Iterator迭代器对象提供了一个forEachRemaining(Consumer action)方法来进行遍历,该方法同样需要一个函数式接口。
Iterator it = list.iterator();
it.forEachRemaining(obj -> System.out.println("迭代集合元素:"+obj));
遍历所需注意的问题:
- 1.foreach循环遍历集合和数组时,只能访问集合中的元素,不能对其中的元素进行修改。
- 2.Iterator迭代器对集合中的元素进行迭代时,如果调用了集合对象的remove()方法删除元素,会出现ConcurrentModificationException异常。
Set
说明: Set接口和List接口一样,同样继承自Collection接口。
特点: Set接口中的元素无序,并且都会以某种规则保证存入的元素不出现重复。
HashSet: 根据对象的哈希值来确定元素在集合中的存储的位置,因此具有良好的存取和查找性能.
TreeSet: 以二叉树的方式来存储元素,它可以实现对集合中的元素进行排序.
HashSet:
说明: HashSet是Set接口的一个实现类,它所存储的元素不可重复,并且无序。
特点: 当向HashSet集合中添加一个元素时,首先会调用该元素的hashCode()方法来确定元素的存储位置,然后再调用元素对象的equals()方法来确保该位置没有重复元素。
注意: 在Java中,一些基本数据包装类、String类等都已经 默认重写了hashCode()和equals()方法。
开发者向HashSet集合中添加自定义的数据类型,如Student类时,必须增加重写的hashCode()和equals()方法,才能保证数据的唯一性。
HashSet set = new HashSet();
set.add("Jack");
set.add("Eve");
...
set.forEach(o -> System.out.println(o));//o为参数
TreeSet集合:
说明: TreeSet是Set接口的另一个实现类,它内部采用平衡二叉树来存储元素,来保证TreeSet集合中没有重复的元素,并且可以对元素进行排序。
TreeSet集合还有一些特有的方法。(有兴趣了解)
重点:自然排序和定制排序。
1.自然排序
说明: 要求存储的元素类必须实现Comparable接口,并重写compareTo()方法。
- 元素类本身实现Comparable接口。
- 依赖compareTo()方法的实现
- 实现Comparable接口排序规则比较单一,不利于后续改进。
步骤: - 1.让元素自身具备比较性
- 2.实现Compareable接口,覆盖其CompareTo方法
import java.util.Set;
import java.util.TreeSet;
//自然排序,有序按照大小
public class TreeSetDemo1 {
public static void main (String args[])
{
TreeSet<Teacher> s=new TreeSet<Teacher>();
Teacher t1=new Teacher("zhangsan",20,"aa");
Teacher t2=new Teacher("lisi",30,"bb");
Teacher t3=new Teacher("wangwu",40,"cc");
Teacher t4=new Teacher("luqi",50,"dd");
s.add(t1);
s.add(t2);
s.add(t3);
s.add(t4);
System.out.println(s);
}
}
class Teacher implements Comparable
{
private String name;
private int age;
private String id;
Teacher(String name,int age,String id)
{
super();
this.name=name;
this.age=age;
this.id=id;
}
public int compareTo(Object obj)//重写compareTo方法
{
if(!(obj instanceof Teacher))
{throw new RuntimeException("不是老师对象");}//抛出错误
Teacher t=(Teacher)obj;//将obj强制转换成Teacher类对象
if(this.age>t.age)
return 1;
if(this.age==t.age)
return 0;
return -1;
}
public String toString()
{
return name+" "+age+" "+id;
}
/*
输出结果:
[zhangsan 20 aa, lisi 30 bb, wangwu 40 cc, luqi 50 dd]
*/
}
2.定制排序
说明 : 要求自定义一个比较器,该比较器必须实现Comparator接口,并重写compare()方法,然后将该比较器作为参数传入集合的有参构造。
- 适合元素类本身未实现Comparable接口,无法进行比较。
- 适合元素类实现的Comparable接口排序规则无法满足用户需求。
- 会额外定义一个实现Comparator接口的比较器。
步骤: - 实现comparator接口
- 复写compare方法
- 在创建TreeSet集合对象时,提供一个一个Comparator对象,
import java.util.Comparator;
import java.util.TreeSet;
//TreeSet的自定义比较器
public class TreeSetDemo2
{
public static void main(String[] args)
{
TreeSet ts=new TreeSet(new Comparator()
{
public int compare(Object o1,Object o2)
{
String s1=(String)o1;
String s2=(String)o2;
return s1.length()-s2.length();//上面自然排序中的简单写法
}
});//匿名内部类的方式
ts.add("aa");
ts.add("456");
ts.add("ccdr");
ts.add("dfggg");
System.out.println(ts);
}
}
/*public class TreeSetDemo2
{
public static void main(String[] args)
{//兰姆达表达式
TreeSet ts=new TreeSet((Object o1,Object o2)->
{
String s1=(String)o1;
String s2=(String)o2;
return s1.length()-s2.length();
});
ts.add("aa");
ts.add("456");
ts.add("ccdr");
ts.add("dfggg");
System.out.println(ts);
}
}*/
/*class Mycompare implements Comparator
{//单独定义一个类,重写compare方法以长度来比较
public int compare(Object o1,Object o2)
{
String s1=(String)o1;
String s2=(String)o2;
return s1.length()-s2.length();
}
}*/
/*
输出结果:
[aa, 456, ccdr, dfggg]
*/