一.集合
a) 集合是一种长度可变的容器,可以存储任意类型的对象
b) 为什么出现集合?
面向对象语言对事物的体现都是通过对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式;
集合和数组的都是容器,有何不同?
数组容器长度固定,一个数组存储一种数据类型;
集合长度是可变的,能存储不同类型的对象;
c) 集合的分类:
i. Collection接口下常用类型分为两种:List,Set
List: 有存储顺序的,可以存储重复的对象;
Set: 没有存储顺序的,不可重复的
3. List集合
i. ArrayList:数组结构,查找快,增删慢;
查找的时候直接获取数组中的元素,直接操作内存地址,速度较快
增删的时候,由于创建数组或者拷贝数组,所以速度较慢
ii. LinkedList: 链表结构,增删快,查找慢
LinkedList:特有方法: jdk1.6出现的替代方法:
添加到集合的首位置:addFirst(); -----> offerFirst();
添加到集合的首位置:addLast(); -----> offerLast();
获取集合中0号索引的对象:getFirst();-----> peekFirst();
获取集合中最后一个对象:getLast(); -----> peekLast();
获取元素,但不删除元素。如果集合中没有元素,会出现NoSuchElementException
removeFirst(); -----> pollFirst();
removeLast();
获取元素,但是元素被删除。如果集合中没有元素,会出现NoSuchElementException
在JDK1.6出现了替代方法。
offerFirst();
offerLast();
peekFirst();
peekLast();
获取元素,但不删除元素。如果集合中没有元素,会返回null。
pollFirst();
pollLast();
获取元素,但是元素被删除。如果集合中没有元素,会返回null。
***4.List类常用方法: (增,删, 改 ,查)
特有方法:凡是可以操作角标的方法都是该体系特有的方法;
boolean add(Objectobj)-----增
向集合中添加一个对象,如果改变了集合的结构,返回true,集合可以添加任意类型的对象
Object remove(intindex)----删
删除指定索引上的元素,并且返回这个元素
Object set(intindex,Object object)---改
将集合中指定位置的元素替换为指定对象;
Object get(int index)----查
从集合中获取指定索引上的对象;
练习:
package cn.itcast;
import java.util.LinkedList;
publicclass ListMethodDemo {
publicstaticvoid main(String[] args) {
// TODO Auto-generated method stub
//add();
//addAll();
//clear();
//contains();
//containsAll();
//equals();
//indexOf();
//remove();
//removeAll();
//set();
//subList();
//print1();
print2();
}
publicstaticvoid print2() {
Listlist1 = newLinkedList();
list1.add("aaa");
list1.add("bb");
list1.add("cc");
list1.add("dd");
String[]str = (String[]) list1.toArray(new String[list1.size()]);
for(int x =0;x<str.length; x++)
System.out.println(str[x]);
}
publicstaticvoid print1() {
Listlist1 = newLinkedList();
list1.add("aaa");
list1.add("bb");
list1.add("cc");
list1.add("dd");
Object[]arr = list1.toArray();
for(int x =0; x<arr.length; x++)
System.out.println(arr[x]);
}
publicstaticvoid subList() {
Listlist1 = newLinkedList();
list1.add("aaa");
list1.add("bb");
list1.add("cc");
list1.add("dd");
//从1号索引截取到3号索引之间的元素,生成新的数组
Listlist2 = list1.subList(1,3);
System.out.println(list2);
}
publicstaticvoid set() {
Listlist1 = newLinkedList();
list1.add("aaa");
list1.add("bb");
list1.add("cc");
list1.add("dd");
//将list1中1号索引的元素改成xx
System.out.println(list1.set(1,"xx"));
System.out.println(list1);
}
publicstaticvoid removeAll() {
Listlist1 = newLinkedList();
list1.add("aaa");
list1.add("bb");
list1.add("cc");
list1.add("dd");
Listlist2= newLinkedList();
list2.add("aaa");
list2.add("bb");
list2.add("xx");
//从list1中删除和list2重复的元素,只要删了,就返回true
System.out.println(list1.removeAll(list2));
System.out.println(list1);
// 在list1中保留和list2重复的元素, list1中没有的全部删除
list1.retainAll(list2);
System.out.println(list1);
}
publicstaticvoid remove() {
Listlist = newLinkedList();
list.add("aa");
list.add("bb");
list.add("cc");
list.add("dd");
list.add("aa");
list.add("aa");
//删除1号索引上的元素,并将元素返回;删除的是bb
System.out.println(list.remove(1));
System.out.println(list.remove(1));
//删除list中的aa,如果删掉了就返回true,如果存在多个,只删除第一次出现的
System.out.println(list.remove("aa"));
System.out.println(list);
}
publicstaticvoid indexOf() {
Listlist1 = newLinkedList();
list1.add("aa");
list1.add("bb");
list1.add("cc");
list1.add("aa");
list1.add("aa");
//查找aa在数组中第一次出现的位置
System.out.println(list1.indexOf("aa"));
//最后一次出现的位置
System.out.println(list1.lastIndexOf("aa"));
}
publicstaticvoid equals() {
Listlist1 = newLinkedList();
list1.add("aaa");
list1.add("bb");
Listlist2= newLinkedList();
list2.add("aaa");
list2.add("bb");
//判断list1和list2中的元素是否都相同,
System.out.println(list1.equals(list2));
}
publicstaticvoid containsAll() {
Listlist1 = newLinkedList();
list1.add("aaa");
list1.add("bb");
list1.add("cc");
Listlist2= newLinkedList();
list2.add("aaa");
list2.add("bb");
list2.add("xx");
//判断list2中的元素是否在list1中全部存在,用equals判断;
System.out.println(list1.containsAll(list2));
}
publicstaticvoid contains() {
Listlist = newLinkedList();
list.add(new String("aaa"));
list.add("bbb");
//判断list数组中是否包含"aaa" ,使用equals方法判断
System.out.println(list.contains("aaa"));
System.out.println(list.contains("bb"));
}
publicstaticvoid clear() {
Listlist = newLinkedList();
list.add("aaa");
list.add("bbb");
list.add("ccc");
//清空集合,删除数组中所有元素
list.clear();
System.out.println(list);
//打印数组长度
System.out.println(list.size());
//判断集合是否为空,如果是结果为true
System.out.println(list.isEmpty());
}
publicstaticvoid addAll() {
Listlist1 = newLinkedList();
list1.add("aaa");
list1.add("bbb");
list1.add("vvv");
Listlist2 = newLinkedList();
list2.add("ccc");
list2.add("ddd");
//和下面有个区别,打印结果把中括号也插入到了list1中
list1.add(1,list2);
//将list2数组所有元素插入到list1数组中的1号索引处,list1中的原有元素向后顺延;
list1.addAll(1,list2);
System.out.println(list1);
}
publicstaticvoid add() {
Listlist = newLinkedList();
list.add("aaa");
list.add("bbb");
//将"vvv"添加到数组中1号索引
list.add(1,"vvv");
System.out.println(list);
//结果为boolean型返回true;添加成功,
System.out.println(list.add(123));
System.out.println(list);
}
}
5.集合的遍历:
For循环:循环size()次,每次调用get(int)方法获取一个元素
迭代器:使用iterator方法获取一个iterator对象,调用hasNext()方法判断是否包含下一个元素,调用next()获取下一个元素;
迭代器就是集合取出元素的方式;迭代器是取出方式,会直接访问集合中的元素。所以将迭代器通过内部类的形式来进行描述。
通过容器的iterator()方法获取该内部类的对象。
增强for循环:for(类型变量名 :容器){循环体}容器长度是多少就执行多少次循环体,变量每次饮用容器中的一个元素;
package cn.itcast;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
publicclass ListIteratorDemo {
/**
* @param args
*/
publicstaticvoid main(String[] args) {
// TODO Auto-generated method stub
Listlist = newLinkedList();
list.add("aa");
list.add("bb");
list.add("ccc");
//itertator1(list);
//itertator2(list);
//iterator3(list);
forIterator(list);
}
privatestaticvoid forIterator(List list) {
//iterator3的改写;
for(Iterator iter = list.iterator();iter.hasNext();)
System.out.println(iter.next());
}
//
privatestaticvoiditerator3(List list) {
// 获取list对象的迭代器(iterator接口的子类)内部有一个指针,默认指向第一个元素之前的位置
Iteratoriter = list.iterator();
// 判断是否包含下一个元素,返回boolean类型
while (iter.hasNext())
// 如果有,就打印下一个元素;
System.out.println(iter.next());
}
privatestaticvoiditertator2(List list) {
// 普通for循环,只能List用,Set不能用
for (int i = 0; i < list.size(); i++)
System.out.println(list.get(i));
}
privatestaticvoiditertator1(List list) {
// 遍历集合,List和Set通用;
// 增强for循环格式;for(类型 变量名: 容器) {循环体}
for (Object obj : list)
System.out.println(obj);
}
}
List集合特有的迭代器:ListInterator是Iterator的子接口;
在迭代时,不可以通过集合对象的方法操作集合中的元素;因为会发生ConcurrentModificationException异常(事件并发异常);所以,在迭代器时,只能用迭代器的方法操作元素,可是iterator方法时有限的,如果想要其他的操作如添加,修改等,就需要使用其子接口ListIterator;
该接口只能通过List集合的listIterator方法获取;
例:
import java.util.List;
import java.util.ListIterator;
publicclass ListDemo {
publicstaticvoid main(String[] args) {
// TODO Auto-generated method stub
ArrayListal = newArrayList();
al.add("java");
al.add("javase");
al.add("javaee");
al.add("javaweb");
//创建列表迭代器;
ListIteratorit = al.listIterator();
//判断是否有下一个元素;
while(it.hasNext())
//如果有,就打印出来
System.out.println(it.next());
//判断是否有上一个元素;
while(it.hasPrevious())
//如果有则打印;
System.out.println("previous>>"+it.previous());
}
} 输出结果是: java
javase
javaee
javaweb
previous>>javaweb
previous>>javaee
previous>>javase
previous>>java
6.遍历时删除元素:
for循环: 由于在list集合中删除元素之后,后面的元素会向前移动,所以每次删除之后将遍历循环-1;
迭代器: 迭代器在使用过程中不允许修改集合,如果要修改,必须使用迭代器中的remove方法;
增起for循环:无法在循环过程中修改集合;
7.泛型:用于解决安全问题,是一个类型安全机制;
JDK1.5之后支持带有泛型的类, 集合上如果加了泛型, 只能存储同一类型的数据, 获取数据时的类型也被指定了
*泛型的优点:
1,将运行时期出现问题ClassCastException,转移到了编译时期;方便于程序员解决问题,让运行时期问题减少,更安全
2,避免了强制转换麻烦
格式:通过<>来定义要操作的引用数据类型
在使用java提供的对象时,什么时候写泛型?
通常在集合框架中常见,只要见到<>就要定义泛型,其实<>就是要接受类型的,当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可;
//练习:删除年龄为19的对象;
packagecn.itcast.day16.list;
import java.util.ArrayList;
publicclass GenericDemo {
publicstaticvoid main(String[] args) {
List<Person>list = new ArrayList<Person>(); // 集合一旦指定泛型,只能存储同一类型数据, 获取时的类型也不再是Object了
list.add(new Person("张三", 19));
list.add(new Person("李四", 20));
list.add(new Person("王五", 19));
list.add(new Person("赵六", 19));
// demo1(list);
// demo2(list);
// demo3(list);
}
privatestaticvoiddemo3(List<Person>list) {
for (Person p : list)
if (p.getAge() == 19)
System.out.println(p.getName());
}
privatestaticvoiddemo2(List<Person>list) {
for (Iterator<Person> iter = list.iterator(); iter.hasNext();){
Personp = iter.next();
if (p.getAge() == 19)
System.out.println(p.getName());
}
}
privatestaticvoiddemo1(List<Person>list) {
for (int i = 0; i < list.size(); i++)
if (list.get(i).getAge() == 19)
System.out.println(list.get(i).getName());
}
}
泛型类和泛型方法:
泛型类:
什么时候定义泛型类?
当类中要操作的引用数据类型不确定的时候,早期定义Object来完成扩展。
现在定义泛型来完成扩展。
?: 通配符。也可以理解为占位符。
泛型的限定;用来支持泛型的扩展;
? extends E: 可以接收E类型或者E的子类型。上限。
? super E: 可以接收E类型或者E的父类型。下限
例:
packageGeneriDemo;
publicclass GeneriDemo {
publicstaticvoid main(String[] args) {
/*泛型前的作法;
Tool t = new Tool();
t.setObject(new Worker());
Worker w = (Worker)t.getObject();
*/
Util<Worker> u = new Util<Worker>();
u.setObject(new Worker());
Worker w = u.getObject();
}
}
class Util<T>{ //将泛型定义在类上;
private Tt;
publicvoid setObject(T t) {
this.t = t;
}
public T getObject() {
returnt;
}
}
/*//泛型前的作法;
classTool {
private Object obj;
public void setObject(Objectobj) {
this.obj = obj;
}
public Object getObject() {
return obj;
}
}
*/
泛型方法:为了让不同方法可以操作不同类型,而且类型还不确定;那么可以讲泛型定义在方法上;
注意:泛型定义在方法上的位置,一定是在返回值类型前,方法修饰符后;其他位置报错;
publicclass GenericDemo {
publicstaticvoid main(String[] args) {
Demo d = newDemo();
d.show(new Integer(3));//调用方法打印不同数据类型的对象;
d.show("abc");
d.print('a');
d.fun("good good study");
}
}
/*
* 静态方法不可以访问类上定义的泛型,如果静态方法操作的应用数据类型不确定,可以将泛型定义在静态方法上;
*/
class Demo<T>{
//静态方法上定义泛型;
publicstatic <Q>void fun(Q q) {
System.out.println("fun="+q);
}
public void show(T t) {
System.out.println("show="+t);
}
public <T>void print(T t) { //将泛型定义在方法上;
System.out.println("print="+t);
}
}
练习:模拟Java提供的ArrayList结构;
package List;
publicclass MyArrayList {
private Object[]arr = new Object[10]; //用来装载元素的数组;
privateintsize; //集合的大小;
/**自定义ArrayList,内部就是将元素添加到数组中
* @param obj 要添加的对象;
* @param return 添加成功
*/
publicboolean add(Object obj) {
if(size ==arr.length) { //如果数组满了
Object[] newArr = new Object[arr.length * 3/2 +1];//创建一个新数组,重新定义数组长度
System.arraycopy(arr,0,newArr,0,size); //将原数组中的元素拷贝到新数组中
arr = newArr; //原数组记住新数组;
}
arr[size++] = obj;
returntrue;
}
/**
* 删除指定索引上的元素
* @param index要删除的索引
* @return 被删除的元素
*/
public Object remove(int index) {
checkRange(index);
Object oldobj = arr[index]; //定义变量,记住原对象;
System.arraycopy(arr,index+1,arr,index,size-index-1);//将要删除位置的后面元素向前移动一位;覆盖要删除的元素;
arr[--size] =null; //将最后一个元素删除(将要删除的元素指定为null,并将size--.)
return oldobj; //将删除的元素返回;
}
/**
* 将集合中指定位置上的元素替换为指定元素
* @param index要替换的位置
* @param obj 要替换成哪个对象
* @return 被替换掉的对象
*/
public Object set(int index ,Object obj) {
checkRange(index);
Object oldobj = arr[index]; //记住原对象;
arr[index] = obj; //将原对象替换为新对象;
return oldobj; //将原对象返回;
}
/**
* 检查索引是否越界
* @param index要检查的索引
*/
privatevoid checkRange(int index) {
if(index >=size) //如果索引越界,抛出异常;
thrownew IndexOutOfBoundsException("index="+index+",size="+size);
}
/**
* 获取集合中指定索引上的元素
* @param index指定索引
* @return 索引上的元素
*/
public Object get(int index) {
checkRange(index);
returnarr[index];
}
/**
* 获取集合的大小
* @return 集合的大小
*/
publicint size() {
returnsize;
}
/**
* 重写Object类的toString,返回集合中每个元素的toString
* @return 每个元素的toString
*/
public String toString() {
//将集合中每个元素添加到StringBuilder中
StringBuilder sb = new StringBuilder();
sb.append("[");
for(int i = 0; i <size; i++)
sb.append(arr[i]+(i <size -1 ? ", " :""));// 如果不是最后一个,加上逗号和空格
sb.append("]");
return sb.toString();
}
}