1.ArrayList
ArrayList集合是程序中最常见的一种集合,它属于引用数据类型(类)。在ArrayList内部封装了一个长度可变的数组,当存入的元素超过数组长度时,ArrayList会在内存中分配一个更大的数组来存储这些元素,因此可以将ArrayList集合看作一个长度可变的数组。
1.1ArrayList的创建
导包:import java.util.ArrayList;
创建对象:与其他普通的引用数据类型创建方式完全相同,但是要指定容器中存储的数据类型:
ArrayList<要存储元素的数据类型> 变量名 = new ArrayList<要存储元素的数据类型>();
- 集合中存储的元素,只能为<>括号中指定的数据类型元素;
- “<要存储元素的数据类型>”中的数据类型必须是引用数据类型,不能是基本数据类型;
下面给出8种基本数据类型所对应的引用数据类型表示形式:
我们通过举几个例子,来明确集合的创建方式:
- 存储String类型的元素
ArrayList<String> list = new ArrayList<String>();
- 存储int类型的数据
ArrayList<Integer> list = new ArrayList<Integer>();
- 存储Phone类型的数据
ArrayList<Phone> list = new ArrayList<Phone>();
1.2常用的方法
package cn.jxufe.java.chapter6; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class TestArrayList01 { public static void main(String[] args) { // TODO Auto-generated method stub // 创建ArrayList集合 ArrayList<String> list1 = new ArrayList<String>();// 第二个可以省略 // 向集合中添加元素 list1.add("stu1"); list1.add("stu2"); list1.add("stu3"); list1.add("stu4"); // 获取集合中元素的个数 // 取出并打印指定位置的元素 System.out.println("第2个元素是:" + list1.get(1)); System.out.println("list1中的元素为:"); System.out.println(list1); System.out.println("去除索引值为2的元素后,list中的元素为"); list1.remove(2); System.out.println(list1); System.out.println("在索引值为1的元素处添加一个student元素:"); list1.add(1, "student"); System.out.println(list1); System.out.println("把索引位置为3的元素置为good:"); list1.set(3, "good"); System.out.println(list1); // 集合的遍历 System.out.println("集合的遍历方法1:"); for (String e : list1) { System.out.print(e + " "); } System.out.println("\n集合的遍历方法2: "); for (int i = 0; i < list1.size(); i++) { System.out.print(list1.get(i) + " "); } System.out.println("\nlist1是否为空:"); System.out.println(list1.isEmpty()); System.out.println("list1是否包涵good:"); System.out.println(list1.contains("good")); ArrayList<String> list2 = new ArrayList<>(); list2.add("stu1"); list2.add("stu2"); System.out.println("list2中的元素为:"); System.out.println(list2); System.out.println("从list1中移除list2中的全部元素"); list1.removeAll(list2);// 获得两个集合元素的差集 System.out.println(list1); System.out.println("list1添加list2中的全部元素"); list1.addAll(list2);// 获得两个集合元素的并集 System.out.println(list1); List<String> list3 = new ArrayList<String>(); list3.add("第一个元素"); // 向列表中添加数据 list3.add("第二个元素"); // 向列表中添加数据 list3.add("第三个元素"); // 向列表中添加数据 List<String> list4 = new ArrayList<String>(); list4.add("第一个元素"); // 向列表中添加数据 list4.add("第三个元素"); // 向列表中添加数据 System.out.println("--------测试retainAll的使用------------:"); boolean ret = list3.retainAll(list4); // 获得两集合相交的元素 System.out.println(ret); System.out.println(list3); // 创建迭代器 Iterator<String> it = list3.iterator(); // 循环遍历迭代器 System.out.println("循环遍历迭代器:"); while (it.hasNext()) { System.out.println(it.next()); // 输出集合中元素 } ArrayList<String> list5 = new ArrayList<>(); ArrayList<String> list6 = new ArrayList<>(); list5.add("a"); list5.add("b"); list5.add("c"); list6.add("b"); list6.add("c"); list6.add("d"); list5.retainAll(list6);// 获得两集合相交的元素 System.out.println(list5); } }
查看ArrayList类发现它继承了抽象类AbstractList同时实现接口List,而List接口又继承了Collection接口。Collection接口为最顶层集合接口了。
源代码: interface List extends Collection { } public class ArrayList extends AbstractList implements List{ }
集合继承体系
这说明我们在使用ArrayList类时,该类已经把所有抽象方法进行了重写。那么,实现Collection接口的所有子类都会进行方法重写。
- Collecton接口常用的子接口有:List接口、Set接口
- List接口常用的子类有:ArrayList类、LinkedList类
- Set接口常用的子类有:HashSet类、LinkedHashSet类
2.迭代器
java中提供了很多个集合,它们在存储元素时,采用的存储方式不同。我们要取出这些集合中的元素,可通过一种通用的获取方式来完成。
Collection集合元素的通用获取方式:在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。
package cn.jxufe.java.chapter6; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class TestIterator03 { /* * 集合中的迭代器: 获取集合中元素方式 接口 Iterator : 两个抽象方法 boolean hasNext() * 判断集合中还有没有可以被取出的元素,如果有返回true next() 取出集合中的下一个元素 * * Iterator接口,找实现类. Collection接口定义方法 Iterator iterator() ArrayList * 重写方法iterator(),返回了Iterator接口的实现类的对象 使用ArrayList集合的对象 Iterator * it=array.iterator(),运行结果就是Iterator接口的实现类的对象 it是接口的实现类对象,调用方法 hasNext 和 next * 集合元素迭代 */ public static void main(String[] args) { // TODO Auto-generated method stub Collection<String> coll = new ArrayList<String>(); coll.add("abc1"); coll.add("abc2"); coll.add("abc3"); coll.add("abc4"); // 迭代器,对集合ArrayList中的元素进行取出 // 调用集合的方法iterator()获取出,Iterator接口的实现类的对象 Iterator<String> it = coll.iterator(); // 接口实现类对象,调用方法hasNext()判断集合中是否有元素 // boolean b = it.hasNext(); // System.out.println(b); // 接口的实现类对象,调用方法next()取出集合中的元素 // String s = it.next(); // System.out.println(s); // 迭代是反复内容,使用循环实现,循环的条件,集合中没元素, hasNext()返回了false while (it.hasNext()) { String s = it.next(); System.out.println(s); } System.out.println(); // for循环的方式进行遍历,for没有while好理解,但是节约点内存,因为while的it是在main函数中建立的,for的it是在for中建立的 for (Iterator<String> it2 = coll.iterator(); it2.hasNext();) { System.out.println(it2.next()); } } }
3.集合迭代中的转型
存储时提升了Object。取出时要使用元素的特有内容,必须向下转型。
package cn.jxufe.java.chapter6; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class TestCollection04 { public static void main(String[] args) { // TODO Auto-generated method stub Collection coll = new ArrayList(); coll.add("abc"); coll.add("aabbcc"); coll.add("shitcast"); Iterator it = coll.iterator(); while (it.hasNext()) { // 由于元素被存放进集合后全部被提升为Object类型 // 当需要使用子类对象特有方法时,需要向下转型 String str = (String) it.next(); System.out.println(str.length()); } // 注意:如果集合中存放的是多个对象,这时进行向下转型会发生类型转换异常。 } }
4.泛型
4.1泛型的引入
在前面学习集合时,我们都知道集合中是可以存放任意对象的,只要把对象存储集合后,那么这时他们都会被提升成Object类型。当我们在取出每一个对象,并且进行相应的操作,这时必须采用类型转换。比如下面程序:
package cn.jxufe.java.chapter6; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class TestGeneric05 { public static void main(String[] args) { // TODO Auto-generated method stub List list = new ArrayList(); list.add("abc"); list.add("itcast"); list.add(5);// 由于集合没有做任何限定,任何类型都可以给其中存放 // 相当于:Object obj=new Integer(5); Iterator it = list.iterator(); while (it.hasNext()) { // 需要打印每个字符串的长度,就要把迭代出来的对象转成String类型 String str = (String) it.next();// String str=(String)obj; // 编译时期仅检查语法错误,String是Object的儿子可以向下转型 // 运行时期String str=(String)(new Integer(5)) // String与Integer没有父子关系所以转换失败 // 程序在运行时发生了问题java.lang.ClassCastException System.out.println(str.length()); } } }
4.2泛型的定义和使用
泛型: 指明了集合中存储数据的类型 <数据类型>
上面已经使用了
4.3Java中的伪泛型
泛型只在编译时存在,编译后就被擦除,在编译之前我们就可以限制集合的类型,起到作用
例如:ArrayList<String> al=new ArrayList<String>();
编译后:ArrayList al=new ArrayList();
4.4泛型类
a:定义格式:
修饰符 class 类名<代表泛型的变量> { } 例如,API中的ArrayList集合: class ArrayList<E>{ public boolean add(E e){ } public E get(int index){ } }
b:使用格式:
创建对象时,确定泛型的类型 例如,ArrayList<String> list = new ArrayList<String>(); 此时,变量E的值就是String类型 class ArrayList<String>{ public boolean add(String e){ } public String get(int index){ } } 例如,ArrayList<Integer> list = new ArrayList<Integer>(); 此时,变量E的值就是Integer类型 class ArrayList<Integer>{ public boolean add(Integer e){ } public Integer get(int index){ } }
package cn.jxufe.java.chapter6; import java.util.ArrayList; public class GenericStack07<E> { ArrayList<E> list = new ArrayList<>(); public int getSize() { return list.size(); } public E peek() { return list.get(getSize() - 1); } public E pop() { E o = list.get(getSize() - 1); list.remove(getSize() - 1); return o; } public boolean isEmpty() { return list.isEmpty(); } public void push(E e) { list.add(e); } @Override public String toString() { // TODO Auto-generated method stub return "stack: " + list.toString(); } public static void main(String[] args) { GenericStack07<String> stack1 = new GenericStack07<>(); stack1.push("good"); stack1.push("good"); stack1.push("study"); System.out.println(stack1); GenericStack07<Integer> stack2 = new GenericStack07<>(); stack2.push(123); stack2.push(456); stack2.push(789); System.out.println(stack2); } }
4.5泛型的方法
- a:定义格式:修饰符 <代表泛型的变量> 返回值类型 方法名(参数){ }
- b:泛型方法的使用:
例如,API中的ArrayList集合中的方法: public <T> T[] toArray(T[] a){ } //该方法,用来把集合元素存储到指定数据类型的数组中,返回已存储集合元素的数组 使用格式:调用方法时,确定泛型的类型 例如: ArrayList<String> list = new ArrayList<String>(); String[] arr = new String[100]; String[] result = list.toArray(arr); 此时,变量T的值就是String类型。变量T,可以与定义集合的泛型不同 public <String> String[] toArray(String[] a){ } 例如: ArrayList<String> list = new ArrayList<String>(); Integer[] arr = new Integer[100]; Integer [] result = list.toArray(arr); 此时,变量T的值就是Integer类型。变量T,可以与定义集合的泛型不同 public <Integer> Integer[] toArray(Integer[] a){ }
使用泛型类型来定义泛型方法
package cn.jxufe.java.chapter6; public class TestGenericMethod { public static void main(String[] args) { // TODO Auto-generated method stub Integer[] integers = { 1, 2, 3, 4, 5 }; String[] strings = { "london", "xuzhou", "nanchang" }; print(integers); print(strings); } public static <E> void print(E[] list) { for (E e : list) { System.out.print(e + " "); } System.out.println(); } }
4.6泛型的接口
/* * 带有泛型的接口 * * public interface List <E>{ * abstract boolean add(E e); * } * * 实现类,先实现接口,不理会泛型 * public class ArrayList<E> implements List<E>{ * } * 调用者 : new ArrayList<String>() 后期创建集合对象的时候,指定数据类型 * * * 实现类,实现接口的同时,也指定了数据类型 * public class XXX implements List<String>{ * } * new XXX() */
4.7受限的泛型类型
可以将泛型指定为另一种类型的子类型,这样的泛型类型称为受限的。
package cn.jxufe.java.chapter6; abstract class GeometricObject { public abstract double getArea(); } class Rectangle extends GeometricObject { double length; double hight; public Rectangle(double length, double hight) { // TODO Auto-generated constructor stub this.length = length; this.hight = hight; } public double getArea() { return length * hight; } } class Circle extends GeometricObject { double radius; public Circle(double radius) { // TODO Auto-generated constructor stub this.radius = radius; } public double getArea() { return 3.14 * radius * radius; } } public class TestBoundedType { public static void main(String[] args) { // TODO Auto-generated method stub Rectangle rectangle = new Rectangle(2, 2); Rectangle rectangle2 = new Rectangle(2, 2); Circle circle = new Circle(2); System.out.println(equalArea(rectangle, circle)); System.out.println(equalArea(rectangle, rectangle2)); } public static <E extends GeometricObject> boolean equalArea(E object1, E object2) { return object1.getArea() == object2.getArea(); } }
4.8示例学习:对一个对象数组进行排序
package cn.jxufe.java.chapter6; public class TestGenericSort { public static void main(String[] args) { // TODO Auto-generated method stub Integer[] intArray = { new Integer(2), new Integer(4), new Integer(3) }; Double[] doubleArray = { new Double(3.4), new Double(1.3), new Double(-22.1) }; Character[] charArray = { new Character('a'), new Character('c'), new Character('b') }; String[] stringArray = { "tom", "jack", "blue" }; sort(intArray); sort(doubleArray); sort(charArray); sort(stringArray); System.out.println("sorted integer objects:"); printList(intArray); System.out.println("sorted double objects:"); printList(doubleArray); System.out.println("sorted charArray objects:"); printList(charArray); System.out.println("sorted stringArray objects:"); printList(stringArray); } public static <E extends Comparable<E>> void sort(E[] list) { E currentMin; int currentMinIndex; for (int i = 0; i < list.length - 1; i++) { currentMin = list[i]; currentMinIndex = i; for (int j = i + 1; j < list.length; j++) { if (currentMin.compareTo(list[j]) > 0) { currentMin = list[j]; currentMinIndex = j; } } if (currentMinIndex != i) { list[currentMinIndex] = list[i]; list[i] = currentMin; } } } public static void printList(Object[] list) { for (int i = 0; i < list.length; i++) { System.out.print(list[i] + " "); } System.out.println(); } }
4.9泛型的好处
- 将运行时期的ClassCastException,转移到了编译时期变成了编译失败。
- 避免了类型强转的麻烦。
4.10泛型的通配符
package cn.jxufe.java.chapter6; public class TestWildCard { public static void main(String[] args) { // TODO Auto-generated method stub GenericStack07<Integer> intStack = new GenericStack07<>(); intStack.push(1); intStack.push(2); intStack.push(-1); System.out.println("the max number is " + max(intStack));//编译会报错,因为intStack不是GenericStack<Number>的实例 } public static double max(GenericStack07<Number> stack) { double max = stack.pop().doubleValue(); while (!stack.isEmpty()) { double value = stack.pop().doubleValue(); if (value > max) max = value; } return max; } }
package cn.jxufe.java.chapter6; public class TestWildCard { public static void main(String[] args) { // TODO Auto-generated method stub GenericStack07<Integer> intStack = new GenericStack07<>(); intStack.push(1); intStack.push(2); intStack.push(-1); System.out.println("the max number is " + max(intStack));//编译会报错,因为intStack不是GenericStack<Number>的实例 } public static double max(GenericStack07<? extends Number> stack) { double max = stack.pop().doubleValue(); while (!stack.isEmpty()) { double value = stack.pop().doubleValue(); if (value > max) max = value; } return max; } }
package cn.jxufe.java.chapter6; public class TestAnyWild { public static void main(String[] args) { // TODO Auto-generated method stub GenericStack07<Integer> intStack = new GenericStack07<>(); intStack.push(1); intStack.push(2); intStack.push(-2); print(intStack); GenericStack07<String> stringStack = new GenericStack07<>(); stringStack.push("zhangSan"); stringStack.push("zhaoSi"); stringStack.push("wangWu"); print(stringStack); } public static void print(GenericStack07<?> stack) { while (!stack.isEmpty()) { System.out.print(stack.pop() + " "); } System.out.println(); } }
package cn.jxufe.java.chapter6; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; public class TestWildcard06 { public static void main(String[] args) { // TODO Auto-generated method stub ArrayList<String> array = new ArrayList<String>(); HashSet<Integer> set = new HashSet<Integer>(); array.add("123"); array.add("456"); set.add(789); set.add(890); iterator(array); iterator(set); } /* * 定义方法,可以同时迭代2个集合 参数: 怎么实现 , 不能写ArrayList,也不能写HashSet 参数: 或者共同实现的接口 * 泛型的通配,匹配所有的数据类型 ? */ public static void iterator(Collection<?> coll) { Iterator<?> it = coll.iterator(); while (it.hasNext()) { // it.next()获取的对象,什么类型 System.out.println(it.next()); } }
}
package cn.jxufe.java.chapter6; public class TestSuperWildChard { public static void main(String[] args) { // TODO Auto-generated method stub GenericStack07<String> stack1 = new GenericStack07<>(); GenericStack07<Object> stack2 = new GenericStack07<>(); stack2.push("java"); stack2.push(2); stack1.push("sun"); add(stack1, stack2); TestAnyWild12.print(stack2); } public static <T> void add(GenericStack07<T> stack1, GenericStack07<? super T> stack2) { while (!stack1.isEmpty()) { stack2.push(stack1.pop()); } } }