集合框架 Collection java.util(interface)
集合 只能存储引用类型,存储对象,不存储基本类型,长度可变
数组 存储基本类型,存储对象,长度固定
集合中存储的都是引用类型的元素,那么引用类型变量实际上存储的是对象的“地址”,所以实际上集合只存储了元素对象在堆中的地址,而并不是将对象本身存入了集合中。
Collection接口
是层次结构中的根接口,定义了集合相关的操作方法。
其有两个子接口:List(可重复集)和Set(不可重复集)
元素是否重复,取决于元素的equals() 比较的结果
成员方法:
boolean add(E e)//添加元素
boolean remove(E e) //移除第一次出现的指定元素
void clear() //清空集合
boolean contains(Object o)//判断是否包含指定对象
boolean isEmpty() //判断集合是否为空
int size()//返回集合的大小(容量),即集合中存储元素的个数
boolean addAll(Collection c) //添加指定集合中的所有元素
boolean removeAll(Collection c) //移除指定集合中包含的所有元素
boolean containsAll(Collection c) //判断是否包含指定集合的所有元素
boolean retainAll(Collection c) //保留与指定集合中相同的元素(获取交集)
Object[] toArray()//集合 --> 数组,可以实现集合的遍历
Iterator iterator()//获取迭代器,集合专用的遍历方式
*迭代器迭代结合,泛型跟随集合
Iterator迭代器
集合专用遍历方式,做集合中元素的获取
集合顶层接口Collection中,定义了一个抽象方法Iterator iterator(),返回值是接口类型,返回的是该接口的实现类对象。
迭代器接口的实现类是集合容器的内部类,Collection下面所有的实现类,都会重写该方法。比如 ArrayList 实现 List 接口,而 List 继承自Collection。
迭代器类的成员方法:
boolean hasNext() //判断集合中是否还有下一个元素
next() //获取迭代的下一个元素
void remove() //移除本次迭代后迭代器返回的最后一个元素
迭代器的删除方法是在原集合中删除元素ConcurrentModificationException
在使用迭代器遍历集合时,不能通过集合的remove() 方法删除集合元素,否则会抛出并发更改异常,可以通过迭代器自身提供的remove() 方法删除通过next() 迭代出的元素。
在调用remove() 方法前必须通过迭代器的next() 方法迭代过元素,那么删除的就是这个元素。并且不能再次调用remove() 方法,除非再次调用next() 后方可再次调用。
使用迭代器接口的两种方式,一般使用 while 循环
Iteratoriterator=collection.iterator();
//调用迭代器接口方法判断集合中有没有下一个元素
while(iterator.hasNext()) {
//调用迭代器接口方法获取出集合中的元素
Objectobject=iterator.next();
System.out.println(object);
}
for(Iteratoriterator=collection.iterator();iterator.hasNext();){
Objectobject=iterator.next();
System.out.println(object);
}
增强型for循环
since JDK1.5,只用于遍历集合或数组,也称新循环
格式:
for(元素类型 变量名 : 集合或数组) {
循环体
}
好处:减少代码量,方便做遍历;弊端:不能改动数组或集合中的元素
增强for循环并非新的语法,而是在编译过程中,编译器会将新循环转换为迭代器模式。所以新循环本质上是迭代器。
遍历集合的 3 种方式:迭代器,增强 for 循环,普通for 循环(size() + get())
List接口 继承 Collection 接口
特点:有序集合,存取有序,有索引,允许重复
成员方法
void add(int index, E element) //向指定索引处添加元素
E remove(int index) //移除指定索引处的元素并返回该元素
E get(int index) //获取指定索引上的元素
E set(int index, E element) //替换指定索引上的元素并返回之前的元素
ListIterator listIterator() //获取迭代器
int lastIndexOf(Object o) //返回指定元素出现的最后一个位置的索引
List subList(int fromIndex, inttoIndex) //获取子List
--------------------------------------------------------------------
importjava.util.ArrayList;
importjava.util.List;
/*
*证明subList获取的List与原List占用相同的存储空间,对子List的操作会影响原List
*/
public classSubListDemo {
public static void main(String[] args) {
List list = newArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
System.out.println("list " +list);
// list [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
List subList =list.subList(3, 8);
System.out.println("subList " +subList);
// sublist [3, 4, 5, 6, 7]
// subList获得的List和原List占有相同的数据空间
for (int i = 0; i < subList.size();i++) {
subList.set(i, subList.get(i) * 10);
}
System.out.println("changedsubList" + subList);
// changedsublist [30, 40, 50, 60, 70]
System.out.println("unchangedlist" + list);
// unchangedlist [0, 1, 2, 30, 40, 50,60, 70, 8, 9]
list.subList(3, 8).clear(); //可以用于删除连续元素
System.out.println(list);
// [0, 1, 2, 8, 9]
}
}
ListIterator列表迭代器
允许按任一方向遍历列表,迭代期间可以修改列表
void add(E e)
booleanhasNext() //正向遍历
boolean hasPrevious() //逆向遍历
E next() //返回列表中的下一个元素
int nextIndex() //返回返回下一个索引
E previous() //返回列表中的前一个元素
int previousIndex() //返回前一个索引
void remove() //移除本次迭代后迭代器返回的最后一个元素
void set(E e) //替换此次迭代后迭代器返回的最后一个元素
对 List 集合进行正向遍历和逆向遍历
Listlist=newArrayList<>();
list.add("www");
list.add("itcast.");
list.add("cn");
//调用集合方法,获取ListIterator接口的实现类对象
ListIteratoriterator=list.listIterator();
while(iterator.hasNext()) {
Objectobject= (Object)iterator.next();
if("www".equals(object)) {
//调用迭代器的方法
//添加元素到迭代到元素的下一个位置
// iterator.add("0807Java");//添加和修改不能在同一次迭代中
//修改迭代到的元素
iterator.set("www.");
}
}
//迭代器指针到了最后,不能再次获取,出现没有元素被取出异常
//逆向遍历逆向遍历之前要先做一次正向遍历
while(iterator.hasPrevious()) {
Objectobject= (Object)iterator.previous();
System.out.print(object+" ");// cn itcast. www.
}
泛型机制Generic since JDK5
泛型在集合中的应用
泛型的本质是参数化类型。在类、接口和方法的定义过程中,所操作的数据类型被传入的参数指定,强制集合必须存储指定的数据类型,保证程序的安全性。
Java泛型机制广泛的应用在集合框架中,所有的集合类型都带有泛型参数,这样在创建集合时可以指定放入集合中元素的类型。Java编译器可以据此进行类型检查,这样可以减少代码在运行时出现错误的可能性。
集合类变量名= new集合类();
好处:减少代码量,避免类型强制转换,安全问题由运行时期提前到了编译时期。
Java中的泛型是伪泛型,只在编译时期有效,编译后的class文件中没有泛型,编译手段。
ArrayList类的定义中,中的E为泛型参数(理解为变量名,相当于定义了一个变量,负责接收数据类型),在创建对象时可以将类型作为参数传递,此时,类定义所有的E将被替换成传入的参数。
*注意:集合存储八种基本类型,泛型必须写包装类;迭代器迭代结合,泛型跟随集合
泛型类、泛型方法
packagecn.itcast;
/*
*自定义泛型类
*自己写的类上,加上泛型
*
*定义成员变量,也是泛型
*
* E变量,等待建立此类对象的时候,由调用者指定他的数据类型
*/
classGenericClass {
privateEe;
/*
*泛型方法
*方法参数上,使用了一个和类上一样的泛型
*创建类的对象的时候,直接指定数据类型
*
*方法上泛型需要单独的定义,定义在方法的声明上
*创建类的对象同时,不能指定方法上泛型,调用者调用方法时直接指定
*
*静态方法参数上的泛型,不能和类上的泛型一样
*原因:静态不能直接调用非静态
*/
publicvoidshow(Ee) {
System.out.println(e);
}
publicvoidfunction(Ww){
System.out.println(w);
}
publicstaticvoidmethod(Cc){
System.out.println(c);
}
publicE getE() {
returne;
}
publicvoidsetE(Ee) {
this.e=e;
}
}
publicclassGenericDefine {
publicstaticvoidmain(String[]args) {
GenericClassgenericClass=newGenericClass();
genericClass.setE(123);
Integerinteger=genericClass.getE();
System.out.println(integer);
GenericClassgenericClass2=newGenericClass();
genericClass2.setE("abc");
Stringstring=genericClass2.getE();
System.out.println(string+ 1);
System.out.println("--------------");
genericClass2.show("传智播客");
}
}
泛型接口
packagecn.itcast;
/*
*泛型接口
*接口上定义泛型,接口中方法全抽象,实现类
*在使用上两种使用方式:
*实现类实现接口,不理会泛型
*实现类实现接口,同时也实现接口上的泛型
*/
interfaceInter {
publicabstractvoidshow(Tt);
}
//定义接口的实现类,实现接口,不理会接口上的泛型
//泛型的指定,实现类没有做,让调用者来指定数据类型
classInterImplimplementsInter {
@Override
publicvoidshow(Tt) {
System.out.println(t);
}
}
//定义接口的实现类,实现接口的同时,也实现泛型--不灵活
classInterImpl2implementsInter{
@Override
publicvoidshow(Stringt) {
System.out.println(t);
}
}
publicclassGenericInterfaceDemo {
publicstaticvoidmain(String[]args) {
Interin=newInterImpl();
in.show(123);
Interin2=newInterImpl();
in2.show("itcast");
}
}
泛型的限定:泛型通配符>
? extends E(向下限定,E及其子类)? super E(向上限定,E及其父类)
线性表
List接口是Collection的子接口,用于定义线性表数据结构,可以将List理解为存放对象的数组,只不过其元素个数可以动态的增加或减少。
List接口的两个常用实现类为ArrayList和LinkedList,分别用动态数组和链表的方式实现了List接口。
List三个子类的特点
共同特点:有序,索引,重复。
ArrayList和LinkedList在性能上有一定的差别。
ArrayList更适合于随机访问,而LinkedList更适合于插入和删除。
ArrayList底层数据结构是可变数组,元素查询速度快,增删慢
线程不安全,不同步,运行速度快
默认容量10,增长率50%
LinkedList底层数据结构是双向链表,元素查询速度慢,增删快
线程不安全,不同步,运行速度快
存储和迭代器代码,和ArrayList完全一样
Vector底层数据结构是可变数组,元素查询速度快,增删慢
线程安全,同步,运行速度慢
默认容量10,增长率100%
Vector类特有方法:
void addElement(E obj) //将指定的组件添加到向量的末尾,容量+1
E elementAt(int index) //返回指定索引处的组件
Enumeration elements() //返回此向量的组件的枚举
LinkedList类特有方法:
void addFirst(E e) voidaddLast(E e);
E getFirst() EgetLast()
E removeFirst() EremoveLast()
去除集合中存储的重复元素
package cn.itcast;
importjava.util.ArrayList;
importjava.util.Iterator;
/*
*去除集合中字符串的重复值--去除数组中重复元素
*去除集合中自定义对象的重复值(需要重写自定义对象的equals()方法)
* ArrayList集合实现,List允许重复
*(String类重写了equals()方法,建立了自己的比较方式)
*如果原集合中元素没有出现在新集合中,将该元素存储到新集合中
*遍历完毕,新集合保存的就是去掉重复后的元素
*将原集合的引用指向新集合
*/
public classArrayListTest {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("www");
list.add(".itcast");
list.add(".cn");
list.add("www");
list.add(".itheima");
list.add(".com");
list = removeSame(list);
System.out.println(list); // [www, .itcast, .cn, .itheima,.com]
}
//返回的是去重复之后的新集合
public static ArrayListremoveSame(ArrayList arrayList) {
//创建新集合,保存去重复之后的元素
ArrayList newList = newArrayList();
//迭代原集合
Iterator iterator = arrayList.iterator();
while (iterator.hasNext()) {
//接收迭代元素的结果
String string = iterator.next();
//判断新集合中是否包含该元素,没有则添加进去
if (!newList.contains(string)) {
newList.add(string);
}
}
return newList;
}
}
LinkedList模拟栈数据结构的集合
packagecn.itcast;
importjava.util.LinkedList;
/*
* LinkedList集合,模拟数据结构栈
*
*将LinkedList集合中的功能封装起来,调用者不直接面对集合,只能从外部调用
*表现为先添加的元素后被取出,存储和取出的顺序是相反的
*/
publicclassLinkedListTest {
publicstaticvoidmain(String[]args) {
LinkedListToollist=newLinkedListTool();
list.add(0);
list.add(1);
list.add(2);
list.add(3);
//当列表不为空时,删除元素并返回
while(!list.isEmpty()) {
System.out.println(list.remove());
}
}
}
//自定义功能,封装LinkedList类功能
classLinkedListTool {
//定义成员变量
privateLinkedListlist;
//构造方法用于新建对象
publicLinkedListTool() {
list=newLinkedList();
}
//添加元素到列表结尾
publicvoidadd(Objectobject) {
list.add(object);
}
//判断列表是否为空
publicbooleanisEmpty() {
returnlist.isEmpty();
}
//从列表结尾删除元素并返回
publicObject remove() {
returnlist.removeLast();
}
}
List集合< == >数组
List转换为数组(集合转成数组,带有泛型)
Object[] toArray()
T[] toArray(T[] a)
Liststrings=newArrayList<>();
strings.add("www");
strings.add(".itcast");
strings.add("cn");
String[]str=strings.toArray(newString[strings.size()]);
//传入一个指定类型的数组,该数组的元素类型应与集合的元素类型一致。
//返回值则是转换后的数组,该数组会保存集合中所有的元素
for(inti= 0;i
System.out.print(str[i] +" ");
}
数组转换为List
Arrays类中提供了一个静态方法asList,使用该方法我们可以将一个数组转换为对应的List集合。其方法定义为:static List asList
注意:返回的List的集合元素类型由传入的数组的元素类型决定;返回的集合不能对其增删元素,否则会抛出异常,并且对集合的元素进行修改会影响数组对应的元素。
String[]strArr= {"www",".itcast",".cn"};
Listlist =Arrays.asList(strArr); // fixed-size list
System.out.println(list);// [www, .itcast, .cn]
//当前集合list的实际类型为java.util.Array$ArrayList
//而不是List接口的实现类java.util.ArrayList,所以不支持对其添加或删除元素
// list.add("IT"); //会抛出UnsupportedOperationException
System.out.println(list.getClass().getName());
list.set(0,"3w");//可以修改元素
//对集合元素的修改会影响原数组
System.out.print("String[] ");
for(Stringstring:strArr) {
System.out.print(string+" ");
}
System.out.println();
//如果想要添加元素,可以用如下方式:
Listlist2=newArrayList<>();
list2.addAll(Arrays.asList(strArr));
System.out.println(list2);// [3w, .itcast, .cn]
list2.add("0807JavaSE");
System.out.println(list2);// [3w, .itcast, .cn, 0807JavaSE]
可变参数since JDK5
如果定义方法的时候,参数类型明确但个数不明确,可使用可变参数
格式:修饰符返回值类型方法名(数据类型...变量名) {}
可变参数方法传递,传递实际参数,数量没有限制
注意:一个方法中只能写1个可变参数,如果有多个参数可变参数只能放在最后
packagecn.itcast.arguments;
publicclassVarArgumentsDemo {
publicstaticvoidmain(String[]args) {
intsum= getSum(0, 1,2, 3, 4, 5);
System.out.println(sum);
}
publicstaticintgetSum(int...is){
intsum= 0;
//传递参数的个数,就是数组的长度
//如果不传递任何参数,可变参数的数组的长度就是0
// for(int i = 0; i < is.length; i++) {
// sum+= is[i];
// }
for(inti:is) {
sum+=i;
}
returnsum;
}
}
l获取10个1-20之间的随机数,要求不能重复
package cn.itcast.test;
importjava.util.ArrayList;
import java.util.List;
importjava.util.Random;
/*
*获取10个1-20之间的随机数,要求不能重复
*/
public class ListTest {
public static void main(String[] args) {
Random r = new Random();
List list = new ArrayList();
while (true) {
//获取随机数
int num = r.nextInt(20) + 1;
//判断随机数如果不在集合中,就存储到集合
if (!list.contains(num)) {
list.add(num);
//判断集合容量为10就退出循环
if (list.size() == 10) {
break;
}
}
}
for (Integer integer : list) {
System.out.println(integer);
}
}
}
l键盘录入多个数据,以0结束,要求在控制台输出这多个数据中的最大值
package cn.itcast.test;
importjava.util.ArrayList;
import java.util.List;
importjava.util.Scanner;
/*
*键盘录入多个数据,以0结束
*在控制台输出最大值:
*利用数组,将集合转成数组
* 1.升序排序,获取最后一个元素
* 2.获取数组中的最大值
*
*/
public classListScannerTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
List list = new ArrayList();
while (true) {
int num = sc.nextInt();
if (num == 0) {
break;
}
//数据存储到集合中
list.add(num);
}
sc.close();
// System.out.println(list);
//将集合转成数组
Integer[] integers = list.toArray(new Integer[list.size()]);
//选择排序
for (int i = 0; i < integers.length; i++) {
for (int j = i + 1; j < integers.length; j++) {
if (integers[i] > integers[j]) {
int temp = integers[i];
integers[i] = integers[j];
integers[j] = temp;
}
}
}
//输出数组中的最后一个索引
System.out.println(integers[integers.length - 1]);
//求数组最值思想
// int max = list.get(0);
// for (Integer integer : integers) {
// if (integer > max)
// max = integer;
// }
// System.out.println(max);
}
}
List排序
Collections.sort()方法实现排序
Collections是集合的工具类,提供很多便于操作集合的方法。
void sort(Listlist) //该方法的作用是对给定的集合元素进行自然排序