一、泛型
在Java SE1.5中,增加的一个新的特性:泛型。何谓泛型呢?通俗的说,就是泛泛的指定对象所操作的类型,而不像常规方式一样使用某种固定的类型去指定。泛型的本质就是将所操作的数据类型参数化,也就是说,该数据类型被指定为一个参数。这种参数类型可以使用在类、接口以及方法定义中。用于解决安全问题,是一个安全机制。
1、好处:
在以往的J2SE中,没有泛型的情况下,通常是使用Object类型来进行多种类型数据的操作。这个时候操作最多的就是针对该Object进行数据的强制转换,而这种转换是基于开发者对该数据类型明确的情况下进行的(比如将Object型转换为String型)。倘若类型不一致,编译器在编译过程中不会报错,但在运行时会出错。
所以定义泛型的好处:
(1)将运行时期出现的问题ClasscastEception,转移到了编译时期。方便于程序员解决问题,让运行事情问题减少,增强安全性。
(2)在运行时所有的转换都是强制的,隐式的,避免了强制转换。
(3)提高代码的重用率。
2、泛型类
泛型格式:通过<>未定义要操作的引用数据类型。
在使用Java提供的对象时,什么时候使用泛型?
通常在集合框架中很常见。只要见到<>就要定义泛型。
<>里面是用来接收类型的,当使用集合时,将集合要存储的数据类型作为参数传递到<>中即可。
3.泛型方法
泛型类定义的泛型,在整个类中有效,如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定。
为了让不同方法操作不同类型,而且类型还不确定。那么可以将泛型定义在方法上。
注意:静态方法不可以访问类上定义的泛型,如果静态方法操作的应用数据类型不明确,可以将泛型定义在方法上(泛型定义在返回值前修饰符后)
4.泛型规则限定
1、泛型的参数类型只能是引用类型,而不能是简单类型。
2、可以声明多个泛型参数类型,比如<T, P,Q…>,同时还可以嵌套泛型,例如:<List<String>>
3、泛型的参数类型可以使用extends语句,例如<Textends collection>。
4、泛型的参数类型可以使用super语句,例如< T superchildclass>。
5、泛型还可以使用通配符,例如<? extends ArrayList>
5、扩展
(1)extends语句
使用extends语句将限制泛型参数的适用范围。例如:
<T extends collection> ,则表示该泛型参数的使用范围是所有实现了collection接口的calss。如果传入一个<String>则程序编译出错。
(2)super语句
super语句的作用与extends一样,都是限制泛型参数的适用范围。区别在于,super是限制泛型参数只能是指定该class的上层父类。
例如<T super List>,表示该泛型参数只能是List和List的上层父类。
(3)通配符上限
Vector<? extends 类型1> x = new Vector<类型2>();
类型1指定一个数据类型,那么类型2就只能是类型1或者是类型1的子类
Vector<? extends Number> x = new Vector<Integer>();//这是正确的
Vector<? extends Number> x = new Vector<String>();//这是错误的
(4)通配符下限
Vector<? super 类型1>x = new Vector<类型2>();
类型1指定一个数据类型,那么类型2就只能是类型1或者是类型1的父类
Vector<? super Integer> x = new Vector<Number>();//这是正确的
Vector<? super Integer> x = new Vector<Byte>();//这是错误的
注意:限定通配符包括自己
二 、集合框架工具类Collections
1、Collections 和 Collection 的关系?
Collection是集合类的一个顶级接口,其直接继承接口有List与Set,而Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
2、常见操作
(1)排序(Sort)
使用sort方法可以根据元素的自然顺序对指定列表按升序进行排序。列表中的所有元素都必须实现 Comparable 接口。此列表内的所有元素都必须是使用指定比较器可相互比较的。
public static <T extends Comparable<?super T>> void sort(List<T> list)
根据元素的自然顺序 对指定列表按升序进行排序。
public static <T> voidsort(List<T> list, Comparator<? super T> c)
根据指定比较器产生的顺序对指定列表进行排序。
(2)取最大值和最小值操作
public static <T extends Object &Comparable<? super T>> T max(Collection<? extends T> coll)
根据元素的自然顺序,返回给定collection 的最大元素。
public static <T> Tmax(Collection<? extends T> coll, Comparator<? super T> comp)
根据指定比较器产生的顺序,返回给定collection 的最大元素。
public static <T extends Object &Comparable<? super T>> T min(Collection<? extends T> coll)
根据元素的自然顺序 返回给定 collection 的最小元素。
public static <T> Tmin(Collection<? extends T> coll,Comparator<? super T> comp)
根据指定比较器产生的顺序,返回给定collection 的最小元素。
(3)二分查找
public static <T> intbinarySearch(List<? extends Comparable<? super T>> list, T key)
使用二分搜索法搜索指定列表,以获得指定对象。
public static <T> intbinarySearch(List<? extends T> list, T key, Comparator<? super T>c)
使用二分搜索法搜索指定的比较器对列表进行排序的列表,以获得指定对象。
原理:
public static int binarysearch(List<String> list,String key,Comparator<String> com){
int max=list.size()-1;
int min=0;
while (min<=max){
int mid=(min+max)>>1;
String str=list.get(mid);
//int num=str.compareTo(key);
int num=com.compare(str, key);
if (num>0)
max=mid-1;
else if (num<0)
min=mid+1;
else return mid;
}
return -min-1;
}
(4)替换所有的元素(Fill)
使用指定元素替换指定列表中的所有元素。
<pre name="code" class="java">//练习:使用指定元素替换指定列表中的指定元素。
class Test4{
public static void main(String[] args){
List< String> list= new ArrayList< String>();
list.add( "a" );
list.add( "bbb" );
list.add( "www" );
System.out.println(list);
fillDemo(list,"aaa",1,2);
System.out.println(list);
}
public static void fillDemo(List<String > list,String str,int start,int end){
//第一种方式:
List< String> li=list.subList(start, end);
Collections. fill(li,str);
ListIterator< String> ls=list.listIterator();
ListIterator< String> lis=li.listIterator();
while (ls.hasNext()){
String s=ls.next();
while (lis.hasNext()){
String s1=lis.next();
s=s1;;
}
}
}
//第二种方式:
// for( int x=start;x<=end-1;x++){
// list.set(x,str);
// }
}
(5)替换指定元素(replaceAll)
public static <T> booleanreplaceAll(List<T> list,T oldVal, T newVal)
使用另一个值替换列表中出现的所有某一指定值。
(6)反转(Reverse)
public static void reverse(List<?>list)
使用Reverse方法可以根据元素的自然顺序对指定列表按降序进行排序。
public static <T> Comparator<T>reverseOrder()
返回一个比较器,它强行逆转实现了Comparable 接口的对象 collection 的自然顺序。
public static <T> Comparator<T>reverseOrder(Comparator<T> cmp)
返回一个比较器,它强行逆转指定比较器的顺序。
<pre name="code" class="java"><pre name="code" class="java">public Test4(){
public static void main(String[] args)
{
String s="aaaa";
Set<String> al=new TreeSet<String>(new MyCompara());
al.add("bbb");
al.add("aaaa");
al.add("dddaa");
al.add("aabcaa");
System.out.println(al);
//Collections.sort(al);
//Test4.fillDemo(al,"zzz",0,2);
//Collections.replaceAll(al,"aaa","zzz");
System.out.println(al);
//int i=Test4.binarysearch(al,"ddd");
//String s=al.get(i);
//System.out.println(s);
}
}
class MyCompara implements Comparator<String>
{
public int compare(String s1,String s2){
int num=new Integer(s1.length()).compareTo(new Integer(s2.length()));
if(num==0)
return s1.compareTo(s2);
return num;
}
}
(7)拷贝(Copy)
public static <T> void copy(List<?super T> dest, List<? extends T> src)
用两个参数,一个目标 List 和一个源 List, 将源的元素拷贝到目标,并覆盖它的内容。目标 List 至少与源一样长。如果它更长,则在目标 List 中的剩余元素不受影响。
(8)替换位置(swap)
public static void swap(List<?> list,int i, int j)
在指定列表的指定位置处交换元素。(如果指定位置相同,则调用此方法不会更改列表。)
(9)混排(Shuffling)
混排算法所做的正好与 sort 相反: 它打乱在一个 List 中可能有的任何排列的踪迹。也就是说,基于随机源的输入重排该 List, 这样的排列具有相同的可能性(假设随机源是公正的)。这个算法在实现一个碰运气的游戏中是非常有用的。例如,它可被用来混排代表一副牌的 Card 对象的一个 List 。另外,在生成测试案例时,它也是十分有用的。
public static void shuffle(List<?>list)
使用默认随机源对指定列表进行置换。所有置换发生的可能性都是大致相等的。
public static void shuffle(List<?>list, Random rnd)
使用指定的随机源对指定列表进行置换。所有置换发生的可能性都是相等的,假定随机源是公平的。
三、工具类Arrays
java.util.Arrays类能方便地操作数组,它提供的所有方法都是静态的。
基本操作:
(1)数组转换集合(asList)
public static <T> List<T>asList(T... a)
为什么数组转换为集合?
可以使用集合里的特定方法。
注意:将数组变成集合后,不可以使用集合的增删方法,因为数组的长度是固定的,如果增删的话会出现lang.UnsupportedOperationException异常。
asList接受的参数是一个泛型的变长参数,我们知道基本数据类型是无法发型化的,也就是说8个基本类型是无法作为asList的参数的, 要想作为泛型参数就必须使用其所对应的包装类型。
(2)集合转换为数组(toArray())
public Object[] toArray()
public <T> T[] toArray(T[] a)
public static void theard_2(){
List< String> list= new ArrayList< String>();
list.add( "aaa" );
list.add( "bad" );
list.add( "dgfg" );
String[] s= new String [list.size()];
String [] arr=list.toArray(s);
System. err .println(Arrays.toString(arr));
}
注意:当指定类型的数组长度,小于集合的长度时,那么该方法会创建一个新的数组,长度为集合的长度。
当指定类型的数组长度,大于集合的长度时,就不会创建新的数组,而是使用传递进来的数组。
为什么将集合转换为数组?
为了限定对元素的操作。
(3)高级for循环
for(数据类型 变量名:被遍历的集合(Collection)或者数组){ }
for循环和Interator迭代器有什么区别?
对集合进行遍历,只能获取集合的元素,不能对集合进行操作。
迭代器除了遍历,还可以进行remove集合元素的操作。
如果使用ListIterator,还可以在遍历的时候对集合中的元素进行增删改查操作。
传统的for和高级的for有什么区别?
高级的for有一个局限性,必须由遍历的目标。
(4)可变参数
JDK1.5版本出现的新特性。
方法的可变参数,在使用时可变参数一定要放在最后面。
//虽然少定义了多个方法,但是每次都需要new数组进去。
public static void theard_4( int[] i){
System. err .println(Arrays.toString(i));
}
//可变参数,其实就是上一个数组的简化形式。不用每次手动建立数组对象,
//只要将要操作的元素作为参数传递进去即可,隐式的将这些元素封装成数组。
public static void theard_5( int... i){
System. err .println(Arrays.toString(i));
}
public static void main(String[] args) {
int [] i={1,2,3};
int [] i1={1,2,3,4,5};
theard_4(i1);
theard_5(1,5,6);
}
(5)静态导入(import static)
例如:import staticjava.util.Arrays.*;导入的是Arrays这个类中所有的静态成员。
注意:当类的方法重名时,需要指定具体的包名。
当方法重名时,指定所属的对象,或类。