------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
集合框架 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<E> iterator() // 获取迭代器,集合专用的遍历方式
* 迭代器迭代结合,泛型跟随集合
Iterator 迭代器
集合专用遍历方式,做集合中元素的获取
集合顶层接口Collection中,定义了一个抽象方法Iterator<E> iterator(),返回值是接口类型,返回的是该接口的实现类对象。
迭代器接口的实现类是集合容器的内部类,Collection下面所有的实现类,都会重写该方法。比如 ArrayList 实现 List 接口,而 List 继承自Collection。
迭代器类的成员方法:
boolean hasNext() // 判断集合中是否还有下一个元素
<E> next() // 获取迭代的下一个元素
void remove() // 移除本次迭代后迭代器返回的最后一个元素
迭代器的删除方法是在原集合中删除元素
ConcurrentModificationException
在使用迭代器遍历集合时,不能通过集合的remove() 方法删除集合元素,否则会抛出并发更改异常,可以通过迭代器自身提供的remove() 方法删除通过next() 迭代出的元素。
在调用remove() 方法前必须通过迭代器的next() 方法迭代过元素,那么删除的就是这个元素。并且不能再次调用remove() 方法,除非再次调用next() 后方可再次调用。
使用迭代器接口的两种方式,一般使用 while 循环
Iterator iterator = collection.iterator();
// 调用迭代器接口方法判断集合中有没有下一个元素
while (iterator.hasNext()) {
// 调用迭代器接口方法获取出集合中的元素
Object object = iterator.next();
System.out.println(object);
}
for (Iteratoriterator = collection.iterator(); iterator.hasNext();){
Object object = 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<E> listIterator() // 获取迭代器
int lastIndexOf(Object o) // 返回指定元素出现的最后一个位置的索引
List<E> 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<Integer> 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<Integer> 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 集合进行正向遍历和逆向遍历
List list= 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 为泛型参数(理解为变量名,相当于定义了一个变量,负责接收数据类型),在创建对象时可以将类型作为参数传递,此时,类定义所有的 E 将被替换成传入的参数。
*注意:集合存储八种基本类型,泛型必须写包装类;迭代器迭代结合,泛型跟随集合
泛型类、泛型方法
package cn.itcast;
/*
* 自定义泛型类
* 自己写的类上,加上泛型<变量>
*
* 定义成员变量,也是泛型
*
* E 变量,等待建立此类对象的时候,由调用者指定他的数据类型
*/
class GenericClass<E> {
private E e;
/*
* 泛型方法
* 方法参数上,使用了一个和类上一样的泛型
* 创建类的对象的时候,直接指定数据类型
*
* 方法上泛型需要单独的定义,定义在方法的声明上
* 创建类的对象同时,不能指定方法上泛型,调用者调用方法时直接指定
*
* 静态方法参数上的泛型,不能和类上的泛型一样
* 原因:静态不能直接调用非静态
*/
publicvoid show(E e) {
System.out.println(e);
}
public <W> void function(W w){
System.out.println(w);
}
publicstatic <C> void method(C c){
System.out.println(c);
}
public E getE() {
returne;
}
publicvoid setE(E e) {
this.e = e;
}
}
publicclassGenericDefine {
publicstaticvoid main(String[] args) {
GenericClass<Integer>genericClass= newGenericClass<Integer>();
genericClass.setE(123);
Integerinteger= genericClass.getE();
System.out.println(integer);
GenericClass<String>genericClass2= newGenericClass<String>();
genericClass2.setE("abc");
Stringstring= genericClass2.getE();
System.out.println(string + 1);
System.out.println("--------------");
genericClass2.show("传智播客");
}
}
泛型接口
package cn.itcast;
/*
* 泛型接口
* 接口上定义泛型,接口中方法全抽象,实现类
* 在使用上两种使用方式:
* 实现类实现接口,不理会泛型
* 实现类实现接口,同时也实现接口上的泛型
*/
interface Inter<T> {
publicabstractvoid show(T t);
}
// 定义接口的实现类,实现接口,不理会接口上的泛型
// 泛型的指定,实现类没有做,让调用者来指定数据类型
class InterImpl<T> implements Inter<T> {
@Override
publicvoid show(T t) {
System.out.println(t);
}
}
// 定义接口的实现类,实现接口的同时,也实现泛型 -- 不灵活
class InterImpl2 implements Inter<String>{
@Override
publicvoid show(String t) {
System.out.println(t);
}
}
publicclassGenericInterfaceDemo {
publicstaticvoid main(String[] args) {
Inter<Integer>in = newInterImpl<Integer>();
in.show(123);
Inter<String>in2= newInterImpl<String>();
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<String> list = new ArrayList<String>();
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 ArrayList<String>removeSame(ArrayList<String> arrayList) {
// 创建新集合,保存去重复之后的元素
ArrayList<String> newList = newArrayList<String>();
// 迭代原集合
Iterator<String> iterator = arrayList.iterator();
while (iterator.hasNext()) {
// 接收迭代元素的结果
String string = iterator.next();
// 判断新集合中是否包含该元素,没有则添加进去
if (!newList.contains(string)) {
newList.add(string);
}
}
return newList;
}
}
LinkedList 模拟栈数据结构的集合
package cn.itcast;
import java.util.LinkedList;
/*
* LinkedList集合,模拟数据结构栈
*
* 将LinkedList集合中的功能封装起来,调用者不直接面对集合,只能从外部调用
* 表现为先添加的元素后被取出,存储和取出的顺序是相反的
*/
publicclassLinkedListTest {
publicstaticvoid main(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类功能
class LinkedListTool {
// 定义成员变量
privateLinkedList<Object> list;
// 构造方法用于新建对象
public LinkedListTool() {
list = newLinkedList<Object>();
}
// 添加元素到列表结尾
publicvoid add(Object object) {
list.add(object);
}
// 判断列表是否为空
publicboolean isEmpty() {
returnlist.isEmpty();
}
// 从列表结尾删除元素并返回
public Object remove() {
returnlist.removeLast();
}
}
List 集合 < == > 数组
List 转换为数组(集合转成数组,带有泛型)
Object[] toArray()
<T>T[] toArray(T[] a)
List<String>strings = new ArrayList<>();
strings.add("www");
strings.add(".itcast");
strings.add("cn");
String[] str = strings.toArray(newString[strings.size()]);
// 传入一个指定类型的数组,该数组的元素类型应与集合的元素类型一致。
// 返回值则是转换后的数组,该数组会保存集合中所有的元素
for (inti = 0; i< str.length; i++){
System.out.print(str[i] + " ");
}
数组转换为 List
Arrays 类中提供了一个静态方法 asList,使用该方法我们可以将一个数组转换为对应的 List 集合。其方法定义为: static <T> List<T> asList<T… a>
注意:返回的 List的集合元素类型由传入的数组的元素类型决定;返回的集合不能对其增删元素,否则会抛出异常,并且对集合的元素进行修改会影响数组对应的元素。
String[] strArr = { "www", ".itcast", ".cn" };
List<String>list =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 (String string : strArr) {
System.out.print(string + " ");
}
System.out.println();
// 如果想要添加元素,可以用如下方式:
List<String>list2= 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 个可变参数,如果有多个参数可变参数只能放在最后
package cn.itcast.arguments;
publicclassVarArgumentsDemo {
publicstaticvoid main(String[] args) {
intsum = getSum(0, 1,2, 3, 4, 5);
System.out.println(sum);
}
publicstaticint getSum(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<Integer> list = new ArrayList<Integer>();
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<Integer> list = new ArrayList<Integer>();
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(List<T>list) // 该方法的作用是对给定的集合元素进行自然排序