java从0的二倍速学习系列——泛型,Collections工具类,Arrays工具类
1. 一个集合的问题
同时存在
list.add("str1")
list.add(123)
的情况下,无法很好的分辨存储的数据类型,导致后序List调用出错。
因为collection默认存储Object类型数据,所以编译过程中不会报错。
所以我们希望在创建集合时,就明确类型。
List<String> li = new ArratyList<String>()
- 保证安全
- 将运行时ClassCastException转移到了编译时期检查
2. 集合泛型的使用
略
注意
Iterator<String> it = XXX.iterator();
Comparator<String>
3. 泛型的擦除
在编译后,会进行泛型的擦除,在生成.class文件后,泛型消失
泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛形的java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。
3. 泛型类的使用
和模板类一样
class Example<E,Q,W>{ //设置泛型
private E para1;
private Q para2;
private W para3;
public Example(E para1, Q para2, W para3) {
this.para1 = para1;
this.para2 = para2;
this.para3 = para3;
}
public void show(){
System.out.println("para1 = "+para1);
System.out.println("para2 = "+para2);
System.out.println("para3 = "+para3);
}
}
public class demo {
public static void main(String[] args) {
Example<String,Integer,Float> ex = new Example<String, Integer, Float>("str",12,78F);//根据泛型进行初始化
ex.show();
}
结果
para1 = str
para2 = 12
para3 = 78.0
3.1 泛型类的泛型方法
类内的方法,也可以使用泛型
public <G> void show2(G g){
System.out.println("G= "+g);
}
------------------------------
ex.show2("string");
ex.show2(1234f);
ex.show2(new Exception("213"));
结果
G= string
G= 1234.0
G= java.lang.Exception: 213
3.2 泛型中的静态方法
- 静态方法,无法使用类的泛型,但是可以定义为泛型方法。
- 如果方法是静态的,还需要使用泛型,那么泛型必须定义在方法上
3.3 泛型的接口
如果子类能明确类型,接口可以直接定义类型
如果不明确,可以类对象初始化时明确类型。
interface Inter<E>{
void show(E e);
}
class InterImpl implements Inter<String>{
void show(String e){.....}
}
class InterImpl2<T> implements Inter<T>{
public void show(T e){....}
}
3.4 泛型通配符
当传入的泛型类型不明时,可以采用通配符进行控制。
如下代码:分别由String的HashSet与Integer的ArrayList组成,通过将打印函数的参数设置为其父类,并且使用通配符,能够完成参数的传入Collection<?> colle
public class demo {
public static void printCollection(Collection<?> colle){
//使用父类与类型通配符进行传参
for (Iterator it = colle.iterator();it.hasNext();){
//因为类型不明,可能为Integer或者String,所以直接打印toString
System.out.println(it.next().toString());
}
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(135);
list.add(246);
list.add(680);
printCollection(list);
Set<String> se = new HashSet<String>();
se.add("123");
se.add("456");
se.add("789");
printCollection(se);
}
运行结果
135
246
680
123
456
789
通配符也可以用来代替泛型方法
//使用通配符
public static void test(List<?> list) { }
//使用泛型方法
public <T> void test2(List<T> t) { }
3.5 泛型限定:相比通配符的全部类型加了些限制类型,上限与下限
如果想要限制一些类型,不是通配符的全部类型,需要使用泛型的限定。
? extends E //E类的子类对象或E类对象,上限
? super E //接受E的父类对象或E类对象,下限
public static void printCollection(Collection<? extends Object>
colle)
//此处限定的意思是,Object的子类,所有对象,此处只做例子。
{
for (Iterator<? extends Object> it = colle.iterator();it.hasNext();){
Object obj = it.next();
System.out.println(obj);
}
}
3.6 泛型的一个例子,使用泛型强化泛用性
如下图可见,该方法具有局限性,只能完成对于student对象的集合的最大值的获取。
但是也无法定义为默认的Object,因为Object没有compareTo,无法比较大小
public static student getMax(Collection<student> co){
// xxxxx code xxxxx
return null;
}
public static void main(String[] args) {
List<student> list = new ArrayList<student>();
list.add(new student(11,"zhang1"));
list.add(new student(13,"zhang2"));
list.add(new student(19,"zhang3"));
student maxStu = getMax(list);
}
如果使用Object,没有限定存入内容,鲁棒性不强。
public static Object getMax(Collection co){
Iterator it = co.iterator();
Object max =it.next();
while (it.hasNext()){
Object o = it.next();
Comparable tmp = (Comparable)o;
//接口的多态,实现接口的类也是子类
//Object类没有CompareTo方法,需要强转
if(tmp.compareTo(max)>0){max = tmp;}
}
return max;
public static void main(String[] args) {
Collection<student> list = new ArrayList<student>();
list.add(new student(11,"zhang1"));
list.add(new student(13,"zhang2"));
list.add(new student(19,"zhang3"));
student maxStu = (student) getMax(list);
}
通过泛型方法限定,增强鲁棒性。
如下方法中:
- 传入为T或T的子类构成的集合
Collection<? extends T>
- 同时,限定T必须为Comparable的子类
T extends Comparable
- 同时,限定Comparable中的compareTo方法,必须被T或T的父类实现
Comparable<? super T>
public static <T extends Comparable<? super T>> T getMax(Collection<? extends T> co){
Iterator<? extends T> it = co.iterator();
T max =it.next();
while (it.hasNext()){
T tmp = it.next();
if(tmp.compareTo(max)>0){max = tmp;}
//此处存在限定,T必须为Comparable的子类,
// 同时,Comparable必须在T或T的父类,实现comparaTo方法
}
return max;
}
4. Collections工具类
如上面3.6小节所述:可以定义Collection工具类来集成一些集合共有的方法。
4.1 排序相关操作
Collections提供以下方法对List进行排序操作
-
void reverse(List list):反转
-
void shuffle(List list),随机排序
-
void sort(List list),按自然排序的升序排序
-
void sort(List list, Comparator c);定制排序,由Comparator控制排序逻辑
-
void swap(List list, int i , int j),交换两个索引位置的元素
-
void rotate(List list, int distance),旋转。
当distance为正数时,将list后distance个元素整体移到前面。当distance为负数时,将 list的前distance个元素整体移到后面。
package collection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class CollectionsTest {
public static void main(String[] args) {
ArrayList nums = new ArrayList();
nums.add(8);
nums.add(-3);
nums.add(2);
nums.add(9);
nums.add(-2);
System.out.println(nums);
Collections.reverse(nums);
System.out.println(nums);
Collections.sort(nums);
System.out.println(nums);
Collections.shuffle(nums);
System.out.println(nums);
//下面只是为了演示定制排序的用法,将int类型转成string进行比较
Collections.sort(nums, new Comparator() {
//临时创建Comparator内部类对象
@Override
public int compare(Object o1, Object o2) {
// TODO Auto-generated method stub
String s1 = String.valueOf(o1);
String s2 = String.valueOf(o2);
return s1.compareTo(s2);
}
});
System.out.println(nums);
}
}
运行结果
[8, -3, 2, 9, -2]
[-2, 9, 2, -3, 8]
[-3, -2, 2, 8, 9]
[9, -2, 8, 2, -3]
[-2, -3, 2, 8, 9]
4.2 查找替换相关操作
-
int binarySearch(List list, Object key), 对List进行二分查找,返回索引,注意List必须是有序的
-
int max(Collection coll),根据元素的自然顺序,返回最大的元素。 类比int min(Collection coll)
-
int max(Collection coll, Comparator c),根据定制排序,返回最大元素,排序规则由Comparatator类控制。类比int min(Collection coll, Comparator c)
-
void fill(List list, Object obj),用元素obj填充list中所有元素
-
int frequency(Collection c, Object o),统计元素出现次数
-
int indexOfSubList(List list, List target), 统计targe在list中第一次出现的索引,找不到则返回-1,类比int lastIndexOfSubList(List source, list target).
-
boolean replaceAll(List list, Object oldVal, Object newVal), 用新元素替换旧元素。
package collection.collections;
import java.util.ArrayList;
import java.util.Collections;
public class CollectionsTest {
public static void main(String[] args) {
ArrayList num = new ArrayList();
num.add(3);
num.add(-1);
num.add(-5);
num.add(10);
System.out.println(num);
System.out.println(Collections.max(num));
System.out.println(Collections.min(num));
Collections.replaceAll(num, -1, -7);
System.out.println(Collections.frequency(num, 3));
Collections.sort(num);
System.out.println(Collections.binarySearch(num, -5));
}
}
运行结果
[3, -1, -5, 10]
10
-5
1
1
4.3 同步控制相关(待补)
5. Arrays工具类
用于操作数组的工具类,不是collection集合
类中定义静态工作方法
- 排序
- 二分查找
- 数组复制
- 判断两个数的内部元素,判断是否相同
- 将数组转化为字符串
- 将数组转为列表
详见文档,略
5.1 Arrays的特点
-
Arrays操作的数组,Collections操作的是List.
-
在sort()和binarySearch()中Collections要求加一个Comparator对象;
-
Collections可以用shuffle()对List对象进行乱序;
-
Arrays有 asList() 可以将数组或可变参数转换为List对象,Collection对象则可以直接用 ToArray(T[] a) 集合转化为数组
String[] str = {"13","213","31"}; List<String> list = Arrays.asList(str); //通过转为集合,能够便于操作集合中的元素 下面错误行为 list.add("new"); //UnsupportedOperationException
重点:转换为list后,列表长度固定,不可CURD(增删改查)
List<String> list = new ArrayList<String>(); list.add("123"); list.add("333"); list.add("544"); String[] str_arr = c.ToArray(new String[c.size()]);
-
如果数组存储基本数据类型(Integer),转成集合,数组对象存入集合(集合里面为数组胡地址)
-
如果数组存储引用数据类型(String),转成集合,数组元素存入集合。
int[] arr = {123,412,14};
List list = Arrays.asList(arr); //此时存入的是数组对象的地址(@XXXX)
List<int[]> list = Arrays.asList(arr);//正确操作,三个数组元素存入列表。