详细标题:去除ArrayList中重复字符串、自定义对象元素方式 栈和队列 泛型 JDK5新特性(增强for循环 三种迭代(普通for、迭代器、增强for)中的元素能否删除 静态导入 可变参数)Arrays工具类的asList() Collection中toArray(T[] a) 集合嵌套之ArrayList嵌套ArrayList
目录
三种迭代(普通for、迭代器、增强for)中的元素能否删除:
去除ArrayList中重复字符串元素方式:
案例演示:
需求:ArrayList去除集合中字符串的重复值(字符串的内容相同)。
思路:创建新集合方式。
import java.util.ArrayList;
import java.util.Iterator;
@SuppressWarnings({ "rawtypes", "unchecked" })
public class Demo1_ArrayList {
/**
* 案例演示:
* 需求:ArrayList去除集合中字符串的重复值(字符串的内容相同)。
* 思路:创建新集合方式。
*/
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("a");
list.add("a");
list.add("b");
list.add("b");
list.add("b");
list.add("c");
list.add("c");
list.add("c");
list.add("c");
ArrayList newList = getSingle(list);
System.out.println(newList);
}
/*
* 创建新集合将重复元素去掉
* 1.明确返回值类型,返回ArrayList。
* 2.明确参数列表,参数列表ArrayList。
*
* 分析:
* 1.创建新集合。
* 2.根据传入的集合(老集合)获取迭代器。
* 3.遍历老集合。
* 4.通过新集合判断是否包含老集合中的元素,如果包含就不添加,如果不包含就添加。
*/
public static ArrayList getSingle(ArrayList list) {
ArrayList newList = new ArrayList(); //创建一个新集合
Iterator it = list.iterator(); //根据传入的集合(老集合)获取迭代器
while(it.hasNext()) { //遍历老集合
Object obj = it.next(); //将每一个元素临时记录住
if(!newList.contains(obj)) { //如果新集合中不包含老集合中的元素
newList.add(obj); //将该元素添加到新集合中
}
}
return newList; //将新集合返回
}
}
去除ArrayList中重复自定义对象元素:
案例演示:
需求:ArrayList去除集合中自定义对象元素的重复值(对象的成员变量值相同)。
注意事项:contains方法判断是否包含,底层依赖的是equals方法。所以要自定义类中要重写equals()方法。remove()判断是否删除,底层也是依赖equals方法。
import java.util.ArrayList;
import java.util.Iterator;
/**
* 需求:ArrayList去除集合中自定义对象元素的重复值(对象的成员变量值相同)。
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public class Demo2_ArrayList {
public static void main(String[] args) {
ArrayList list = new ArrayList(); //创建几个对象
list.add(new Person("张三", 23));
list.add(new Person("张三", 23));
list.add(new Person("李四", 24));
list.add(new Person("李四", 24));
list.add(new Person("李四", 24));
list.add(new Person("李四", 24));
ArrayList newList = getSingle(list); //调用方法去除重复
System.out.println(newList);
list.remove(new Person("张三", 23));
System.out.println(list);
/*public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) { //remove方法底层依赖的也是equals方法
fastRemove(index);
return true;
}
}
return false;
}*/
}
/*
* 创建新集合将重复元素去掉
* 1.明确返回值类型,返回ArrayList。
* 2.明确参数列表,参数列表ArrayList。
*
* 分析:
* 1.创建新集合。
* 2.根据传入的集合(老集合)获取迭代器。
* 3.遍历老集合。
* 4.通过新集合判断是否包含老集合中的元素,如果包含就不添加,如果不包含就添加。
* 5.在自定义类中Ctrl + Alt + S + V重写equals方法。
* public boolean equals(Object obj) {
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age; //调用字符串里的equals方法
}
*/
public static ArrayList getSingle(ArrayList list) {
ArrayList newList = new ArrayList(); //创建一个新集合
Iterator it = list.iterator(); //根据传入的集合(老集合)获取迭代器
/*public boolean contains(Object o) {
return indexOf(o) >= 0;
}
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i])) //底层用equals()作比较,自定义类中没有重写equals方法,所以使用Object类中的equals方法,判断的是地址值。每个对象地址值是不同的,所以最后打印了所有对象
return i;
}
return -1;
}*/
while(it.hasNext()) { //遍历老集合
Object obj = it.next(); //将每一个元素临时记录住
if(!newList.contains(obj)) { //如果新集合中不包含老集合中的元素
newList.add(obj); //将该元素添加到新集合中
}
}
return newList; //将新集合返回
}
}
LinkedList
1、LinkedList类概述:
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, Serializable,双链表实现了List和Deque接口。
实现所有可选列表操作,并允许所有元素(包括null )。所有的操作都能像双向列表一样预期。 索引到列表中的操作将从开始或结束遍历列表,以更接近指定的索引为准。
java.util包下,使用需要导包。
2、LinkedList类特有功能:
public void addFirst(E e) 在该列表开头插入指定的元素。
public void addLast(E e) 将指定的元素追加到此列表的末尾。
public E getFirst() 返回此列表中的第一个元素。
public E getLast() 返回此列表中的最后一个元素。
public E removeFirst() 从此列表中删除并返回第一个元素。
public E removeLast() 从此列表中删除并返回最后一个元素。
public E get(int index) 返回此列表中指定位置的元素。
get()的源代码:
public E get(int index) { checkElementIndex(index); return node(index).item; } Node<E> node(int index) { // assert isElementIndex(index); if (index < (size >> 1)) { //判断索引是否小于size除以2 Node<E> x = first; //小于就从头向尾找 for (int i = 0; i < index; i++) x = x.next; return x; } else { Node<E> x = last; //不是就从尾向前找 for (int i = size - 1; i > index; i--) x = x.prev; return x; } }
栈和队列数据结构
1、栈和队列数据结构
栈:先进后出。类似于弹夹。
队列:先进先出。类似两边通的管道。
2、用LinkedList模拟栈数据结构的集合并测试
案例演示:
需求:请用LinkedList模拟栈数据结构的集合,并测试。
分析:创建一个类将Linked中的方法封装。
import java.util.LinkedList;
public class Stack { //当你创建Stack对象的时候,其实底层在创建LinkedList对象。
private LinkedList list = new LinkedList();
//模拟进栈方法
public void in(Object obj) {
list.addLast(obj); //封装addLast()方法
}
//模拟出栈方法
public Object out() {
return list.removeLast(); //封装removeLast()方法,改成removeFist就可以模拟队列结构,先进先出
}
//模拟栈结构是否为空
public boolean isEmpty() { //封装isEmpty()方法
return list.isEmpty();
}
}
public static void main(String[] args) {
Stack s = new Stack(); //进栈
s.in("a");
s.in("b");
s.in("c");
s.in("d");
while(!s.isEmpty()) { //判断栈结构是否为空
System.out.println(s.out());//弹栈
}
}
泛型generic
1、泛型概述:
类旁边的<>内添加引用数据类型,用于限定集合存储的数据类型。如果加上引用数据类型,就是告诉你这个集合只能存储该类型对象或者该类型的子类对象,父类引用指向子类对象。
2、泛型好处:
提高安全性(将运行期的错误转换到编译期) 。
省去强转(向下转型)的麻烦。
3、泛型基本使用:
<>中放的必须是引用数据类型 (集合自动装箱,只能存储对象)。
4、泛型使用注意事项:
前后的泛型必须一致,或者后面的泛型可以省略不写(1.7的新特性,叫做菱形泛型) 。数组要保证前后的数据类型一致,集合的泛型也要保证前后的数据类型一致。
菱形泛型举例:ArrayList<Object> list = new ArrayList<>();不加默认Object。加要一致,不加就默认。
泛型最好不要定义成Object,没有意义。
5、案例演示:ArrayList存储字符串并遍历泛型版。
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>(); //创建集合对象
list.add("a");
list.add("b");
list.add("c");
list.add("d");
Iterator<String> it = list.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
ArrayList存储对象并遍历泛型版。
public static void main(String[] args) {
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("张三", 23));
list.add(new Person("李四", 24));
list.add(new Person("王五", 25));
list.add(new Person("赵六", 26));
Iterator<Person> it = list.iterator();
while(it.hasNext()) {
Person p = it.next(); //将集合中的每一个元素用person记录。添加的是person,迭代的是person,元素就是person,不用强转了。
System.out.println(p.getName() + "..." + p.getAge());
}
}
6、泛型的由来
案例演示:安全隐患:种瓜非要收豆。
public static void main(String[] args) {
Tool t = new Tool(); //创建工具类对象
t.setObj(new Student("张三", 23));
Worker w = (Worker) t.getObj(); //向下转型
System.out.println(w);
}
泛型的由来:
通过Object转型问题引入。早期的Object类型可以接收任意的对象类型,但是在实际的使用中,会有类型转换的问题。就是因为存在这个隐患,所以Java提供了泛型来解决这个安全问题。
7、泛型类概述<T>:
把泛型定义在类上。
定义格式:
public class 类名<泛型类型1,…> 一般是一个字母大写,T type,E 元素, 无意义也可以。创建对象时赋什么类型就是什么类型。
注意事项 :
泛型类型必须是引用类型。
8、泛型方法的概述:
方法的泛型最好与类的泛型一致,如果不一致,把泛型定义在方法上。
泛型非静态方法的定义格式:
public <泛型类型> 返回类型 方法名(泛型类型 变量名)。相当于方法拥有了自己的泛型。
泛型静态方法的定义格式:
public static<泛型类型> void 方法名(与泛型类型一致的参数类型 参数名)
静态方法是随着类的加载而加载的,加载的时候很有可能还没有创建对象,对象的泛型类型就没确定。静态方法必须声明自己的泛型。在Static后面加<>,<>中的类型与方法的参数类型一致。这时如果类的泛型和静态方法的泛型都是Q,但实际上是不一样的,相当于两个变量。前者在创建对象时被赋值,后者在调用静态方法的时候被赋值。
9、泛型接口概述:
把泛型定义在接口上。
定义格式:
public interface 接口名<泛型类型>。
案例演示:泛型接口的使用。
interface Inter<T> { //接口泛型
public void show(T t);
}
/*class Demo implements Inter<String> { //实现接口的时候指定泛型,推荐用这种。
public void show(String t) { //重写方法的泛型与指定的泛型一致
System.out.println(t);
}
}*/
class Demo<T> implements Inter<T> { //每次创建对象都要指定泛型,没有必要在实现接口的时候给自己的类加泛型。
public void show(T t) {
System.out.println(t);
}
}
10、泛型高级之通配符:
泛型通配符<?> 任意类型,如果没有明确,那么就是Object以及任意的Java类了。
? extends E ?向下限定,可以是E及其子类。将?类型操作到被调用的集合里面去。E代表被调用集合的泛型类型。
? super E 向上限定,E及其父类。
Jdk1.5新特性
自动装箱
泛型<>中基础数据类型自动装箱成引用数据类型。
增强for循环(foreach)
1、增强for概述:
简化数组和Collection集合的遍历。底层有迭代器实现。
2、格式:
for(元素数据类型 变量 : 数组或者Collection集合) {
对该变量进行操作。(使用变量即可,该变量就是元素。)
}
3、快速生成 fore + Alt+/
4、案例演示:数组,集合存储元素用增强for遍历。
public static void main(String[] args) {
int[] arr = {11,22,33,44,55};
for (int i : arr) {
System.out.println(i);
}
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
for (String string : list) {
System.out.println(string);
}
}
5、好处:
简化遍历。
6、案例演示:ArrayList存储字符串并遍历增强for版。增强for循环底层依赖的是迭代器(Iterator)。
public static void main(String[] args) {
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("张三", 23));
list.add(new Person("李四", 24));
list.add(new Person("王五", 25));
list.add(new Person("赵六", 26));
for (Person person : list) {
System.out.println(person);
}
ArrayList<String> list1 = new ArrayList<>();
list1.add("a");
list1.add("b");
list1.add("c");
list1.add("d");
for(String s : list1) {
System.out.println(s);
}
}
三种迭代(普通for、迭代器、增强for)中的元素能否删除:
普通for循环(借助set()和get()):
可以删除,但是索引要 --。
解释:普通for循环删除元素,每次执行删除操作记得使指针返回一次(即i--)。否则元素删除后,之后的元素会补充该元素所在位置,而for循环的操作表达式会将指针后移(i++),导致跳过后方元素,使删除不彻底。而且减完后立刻增加,所以不会使索引为空。
迭代器(借助hasNext()和next()):
可以删除,但是必须使用迭代器自身的remove方法(举例:it.remove();),否则会出现并发修改异常。
解释:会出现ConcurrentModificationException并发修改异常,是因为在迭代过程中对集合进行修改,所以不能用集合的删除方法。
举例:迭代器遍历另一种写法。while循环变量定义在外,用完可以继续使用,for循环变量用完会释放掉。
for(Iterator<String> it2 = list.iterator(); it2.hasNext();) {
if("b".equals(it2.next())) { //next()每一次会将指针向后移动,所以for循环的操作表达式没写。
it2.remove();
}
}
增强for循环:
不能删除。
解释:增强for循环底层依赖迭代器,如果删除只能用集合的删除方法,所以也会报并发修改异常。因此,增强for循环不能删除,只能遍历。
静态导入(JDK1.5唯一败笔)
静态导入概述:
静态导入是导入类中的静态方法。
格式:
import static 包名….类名.方法名; 举例:import static java.util.Arrays.sort;
可以直接导入到方法的级别。举例:sort(arr); 即不用加前缀Arrays.
注意事项:
方法必须是静态的,如果有多个同名的静态方法,容易不知道使用谁。这个时候要使用,必须加前缀。由此可见,意义不大,所以一般不用,但是要能看懂。
可变参数
可变参数概述:
定义方法的时候不知道该定义多少个参数。
格式:
修饰符 返回值类型 方法名(数据类型… 变量名){}
注意事项:
这里的变量其实是一个数组。
如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个(因为可变参数范围0到无穷,会将传入的所有实参全部拿走。后面的形参就无实参可赋值)。
演示:
public class Demo3_ChangeableArgs {
public static void main(String[] args) {
int[] arr = {11,22,33,44,55};
// print(arr);
print(11,22,33,44,55); //可变参数底层将11,22,33,44,55封装了,再将地址值赋给形参arr。
System.out.println("------------------------");
// print();
}
/* public static void print(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}*/
public static void print(int x, int ... arr) { //可变参数其实就是一个数组
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
Arrays工具类的asList()
1、(该方法用的是可变参数)将数组转集合。
2、asList()概述:
public static <T> List<T> asList(T... a) 返回指定数组支持的固定大小的列表。(将返回的列表更改为“写入数组”。)
参数类型:T - 数组中对象的类。
参数:a - 列表将被支持的数组。
结果:指定数组的列表视图。
翻译:返回值类型 集合,将数组转集合。
3、案例演示:Arrays工具类的asList()方法的使用。数组转集合。
public static void main(String[] args) {
String[] arr = {"a", "b", "c"};
List<String> list = Arrays.asList(arr); //将数组转换成集合,虽然不能增加或减少元素,但意义是可以用集合的思想操作数组。也就是说,可以使用其他集合中的方法。
System.out.println(list);
// list.add("d"); //不能添加 //UnsupportedOperationException不支持操作异常。你这个数组虽然能转集合,但是我不支持你这种操作。
System.out.println(list);
}
4、UnsupportedOperationException概述:
public class UnsupportedOperationException extends RuntimeException,当不支持请求的操作时,抛出该异常。
5、 案例演示:基本数据类型的数组转换成集合。
public static void main(String[] args) {
//基本数据类型的数组转换成集合,会将整个数组当作一个对象转换。
/*int[] arr = {11,22,33,44,55}; //数组元素是基本数据类型,整个数组是一个对象,是引用数据类型。
List<int[]> list = Arrays.asList(arr); //集合中只能存引用数据类型。所以asList()把整个数组当成一个对象存进集合里了。泛型是数组类型的。
System.out.println(list);*/
//如果非要把基本数据类型11,22,33,44,55转换成集合,就将数组定义成对应包装类。所以将数组转换成集合,数组必须是引用数据类型。
Integer[] arr = {11,22,33,44,55}; //数组元素代表每一个Integer对象
List<Integer> list = Arrays.asList(arr);
System.out.println(list);
}
Collection中toArray(T[] a)
1、泛型版的集合转数组。
2、toArray(T[] a)概述:
<T> T[] toArray(T[] a) 返回包含此集合中所有元素的数组; 返回的数组的运行时类型是指定数组的运行时类型。 如果集合适合指定的数组,则返回其中。 否则,将为指定数组的运行时类型和此集合的大小分配一个新数组。
如果此集合适合指定的数组,并具有剩余空间(即,该数组具有比此集合更多的元素),则紧跟在集合结束后的数组中的元素将设置为null 。 ( 仅当调用者知道此集合不包含任何null元素时,这才有助于确定此集合的长度。)
如果此集合对其迭代器返回的元素的顺序做出任何保证,则此方法必须以相同的顺序返回元素。
参数类型: T - 包含集合的数组的运行时类型。
参数:a - 要存储此集合的元素的数组,如果它足够大; 否则,为此目的分配相同运行时类型的新数组。
结果:一个包含此集合中所有元素的数组。
异常:ArrayStoreException - 如果指定数组的运行时类型不是此集合中每个元素的运行时类型的超类型。NullPointerException - 如果指定的数组为空。
集合嵌套之ArrayList嵌套ArrayLis
案例演示:集合嵌套之ArrayList嵌套ArrayList。
import java.util.ArrayList;
import com.bean.Person;
/**
* 案例:若干个学科,再分为若干个班级。
* 若干个学科一个大集合,若干个班级分为每一个小集合。
*/
public class Demo5_ArrayListArrayList {
public static void main(String[] args) {
ArrayList<ArrayList<Person>> list = new ArrayList<>(); //学科里放班级,班级里放人
//创建第一个班级
ArrayList<Person> first = new ArrayList<>();
first.add(new Person("陈乔恩", 23));
first.add(new Person("林志玲", 21));
first.add(new Person("杨玉环", 1023));
//创建第二个班级
ArrayList<Person> second = new ArrayList<>();
second.add(new Person("成龙", 55));
second.add(new Person("王羲之", 1255));
second.add(new Person("唐纳德川普", 80));
//将班级添加到学科集合中
list.add(first);
list.add(second);
//遍历学科集合,嵌套for循环
for (ArrayList<Person> a : list) {
for (Person person : a) {
System.out.println(person);
}
}
}
}