您的位置:首页 > 职场人生

黑马程序员——学习日记之泛型和集合框架工具类

2015-08-11 02:50 666 查看
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

第一节:泛型

一、泛型的由来和基本使用

1、因为集合可以存储的对象类型是任意的,在取出进行向下转型时,容易发生ClassCastException。

所以JDK1.5以后就有了解决这个问题的技术:泛型。

2、泛型的原理:其实就是在操作的元素类型不确定时,通过传递参数的形式来明确类型。

3、泛型的体现就是 <参数类型变量>用于接收具体的实际元素类型。

4、泛型技术在集合框架中应用非常广泛,只要记住:在使用类或者接口时,如果接口上有明确<>泛型。

在使用时,就传递所需的数据类型即可。不传递会出现警告类型不安全提示。

5、了解:泛型技术是用在编译器部分的技术,一旦类型检查正确,

生成的class文件中就没有泛型标记了:这是的泛型的擦除。

6、泛型的好处:

6.1 将运行时期的ClassCastException异常转移到编译时期通过编译失败体现。

6.2 避免了强制转换的麻烦。

7、其实泛型的使用就是往定义了泛型的类或者接口的<>中传递类型参数。

8、泛型在集合对象中的使用,要求写集合代码时必须加入泛型

代码体现

[java] view
plaincopy

import java.util.*;

class FanXingDemo

{

public static void main(String[] args)

{

List<String> list = new ArrayList<String>();

//添加元素

list.add("abc");

list.add("zzzz");

// list.add(6);//只要不是指定的类型对象,编译器检查会 报错。这样将运行时的问题转移到编译时期。

//用迭代器进行对元素遍历

for (Iterator<String> it = list.iterator(); it.hasNext();)

{

// Object object = (Object) it.next();

// System.out.println(object.toString());

//想要打印字符串的长度。

String str = it.next();

System.out.println(str.length());

}

}

}

二、自定义泛型

1、没有泛型之前,对于不确定的对象类型,是通过Object类型多态方式解决的。

弊端:当对象提升为Object后,需要向下转型才可以使用对象的内容。

而转型就会有运行发生ClassCastException异常的风险。

2、有了泛型后,将不确定的类型定义成参数,把Object替换成参数类型。

好处是:调用者在使用时必须先明确类型,如果操作的对象类型不符符合,直接编译失败。

类型符合,使用对象特有方法时,不需要进行强制转换。

3、泛型类,泛型方法,泛型接口的体现

(3) 泛型类

(3).1 把泛型定义在类上 格式:public class 类名<泛型类型1,…>

注意:泛型类型必须是引用类型

(3) 泛型方法

把泛型定义在方法上 格式:public <泛型类型> 返回类型 方法名(泛型类型
.)

(3) 泛型接口

把泛型定义在接口上 格式:public interface 接口名<泛型类型1…>

4、注意:

4.1 类上的泛型是在创建该类对象时进行类型明确。

4.2 静态方法无法访问类上定义的泛型,如果需要泛型,只能定义在方法上。

代码体现

[java] view
plaincopy

import java.util.*;

class Queue<E>{

//封装了一个LinkedList类。

private LinkedList<E> link;

//类初始化,LinkedList对象初始化。

Queue(){

link = new LinkedList<E>();

}

public void myAdd(E obj){

//添加元素

link.addFirst(obj);

}

// 队列的获取方法。

public E myGet(){

return link.removeLast();

}

// 判断队列中元素是否空

public boolean isNull(){

return link.isEmpty();

}

}

三、通配符和泛型的限定

1、当使用了带有泛型的类时,需要传递具体类型实参时,无法明确要传递的实参,可以用?通配符表示。

2、如果要操作的对象的类型是在一个范围之内,比如只操作Person或者Person的子类型对象时。

这时可以使用泛型的限定,对要操作的类型进行限制,提高程序类型操作的安全性。

3、泛型限定体现:

? extends E :接受E类型或者E的子类型。上限。

代码体现

[java] view
plaincopy

import java.util.*;

class FanXingDemo5

{

public static void main (String[] args)

{

//创建list对象,并添加元素

List<Student>s =new ArrayList<Student>();

s.add(new Student("张三"));

s.add(new Student("小三"));

s.add(new Student("小五"));

s.add(new Student("小六"));

getStudent(s);

//创建list对象,并添加元素

List<Wroker>s1 =new ArrayList<Wroker>();

s1.add(new Wroker("李四"));

s1.add(new Wroker("小四"));

s1.add(new Wroker("小李"));

getStudent(s1);

}

//对传入的对象进行限定

public static void getStudent(Collection<?extends Person> cl)

{

//进行迭代

for(Iterator<?extends Person> iee = cl.iterator();iee.hasNext();)

{

//打印出集合中的元素

System.out.println(iee.next());

}

}

}

//人类

class Person

{

private String name;

Person(String name)

{

this.name=name;

}

public String getName()

{

return name;

}

public String toString()

{

return name;

}

}

//工人继承了人类

class Wroker extends Person

{

Wroker(String name)

{

super(name);

}

}

//学生继承了人类

class Student extends Person

{

Student(String name)

{

super(name);

}

}

? super E :接受E类型或者E的父类型。下限。

[java] view
plaincopy

import java.util.*;

class FanXingDemo5

{

public static void main (String[] args)

{

//创建list对象,并添加元素

Set<Student>s =new TreeSet<Student>(new myComparator());

s.add(new Student("张三",23));

s.add(new Student("小三",32));

s.add(new Student("小五",54));

s.add(new Student("小六",12));

getStudent(s);

//创建list对象,并添加元素

Set<Wroker>s1 =new TreeSet<Wroker>(new myComparator());

s1.add(new Wroker("李四",36));

s1.add(new Wroker("小四",87));

s1.add(new Wroker("小李",43));

getStudent(s1);

}

//对传入的对象进行限定

public static void getStudent(Collection<?extends Person> cl)

{

//进行迭代

for(Iterator<?extends Person> iee = cl.iterator();iee.hasNext();)

{

//打印出集合中的元素

System.out.println(iee.next());

}

}

}

//人类

class Person

{

private String name;

private int age;

Person(String name,int age)

{

this.name=name;

this.age=age;

}

public String getName()

{

return name;

}

public int getAge()

{

return age;

}

public String toString()

{

return name;

}

}

//工人继承了人类

class Wroker extends Person

{

Wroker(String name,int age)

{

super(name,age);

}

}

//学生继承了人类

class Student extends Person

{

Student(String name,int age)

{

super(name,age);

}

}

//定义一个比较器

class myComparator implements Comparator<Person>//泛型内的元素定义成Person类,所以wroker类和Student都可以用

{

public int compare(Person s1,Person s2)

{

int temp =s1.getName().compareTo(s2.getName());

return temp==0?s1.getAge()-s2.getAge():temp;

}

}

4、在api中的体现

(1) 通配符的api体现:

Collection中的containsAll(Collection<?>
c):因为该方法内部使用的是equals方法,

而equals(Object)方法是可以和任意对象进行比较,所以传递进来的集合元素是什么类型都可以,

无法确定具体的类型参数用?表示。

(2) 上下限api的体现。TreeSet集合的构造函数。

TreeSet(Collection<? extends E> c)
:在给TreeSet集合初始化元素时,

传递进来的容器中的元素类型只要时TreeSet集合明确的类型或者子类型都可以。

TreeSet(Comparator<? super E> comparator)
:在明确TreeSet比较器时,

只要是TreeSet集合元素类型的比较器,或者该元素类型的父类型都接收元素对象进行比较。

5、泛型限定的练习。

代码体现

[java] view
plaincopy

//泛型的练习

/*

* 案例:获取集合中元素的最大值。

*

* 思路: 1,定义变量记录每次比较后较大的值,初始化元素中任意一个。 2,遍历容器

* 3,在遍历中和变量中记录的元素进行比较。并将较大的值记录到变量中。 4,遍历结束,变量中记录的就是最大值。

*/

import java.util.*;

class FanXingDemo4

{

public static void main (String[] args)

{

//不加泛型进行获取

Set<Student> s1 =new TreeSet<Student>();

s1.add(new Student("王五",39));

s1.add(new Student("小五",19));

s1.add(new Student("大五",99));

Student max=getValue(s1);

System.out.println(max);

}

// 升级版。要操作的元素的类型确定不?不确定。使用泛型限定。getMax方法接收的集合中的元素无论时什么类型,必须具备自然排序,必须是Comparable的子类。

public static <T extends Comparable<?super T>> T getValue(Set<?extends T> cle)

{

Iterator<?extends T> ies = cle.iterator();

T max =ies.next();

while (ies.hasNext())

{

T temp=ies.next();

if (temp.compareTo(max)>0)

{

max=temp;

}

}

return max;

}

}

//自定义一个学生类并实现了Comparable接口

class Student implements Comparable<Student>

{

//私有学生类的属性

private String name;

private int age;

Student(String name,int age)

{

this.name=name;

this.age=age;

}

//并提供对外访问方式

public String getName()

{

return name;

}

public int getAge()

{

return age;

}

//覆盖接口中的CompareTo方法

public int compareTo(Student stu)

{

//看看name是否相同

int temp=this.name.compareTo(stu.name);

//当name和age相同时为同一个人

return temp==0?this.age-stu.age:temp;

}

//覆盖Object中的toString方法

public String toString()

{

return "name="+name+".....age="+age;

}

}

第二节: 集合框架的工具类

一、简述:

1、Collections和Arrays :是集合框架的工具类。里面定义的都是静态方法。

2、Collections工具类中基本上的方法都是对于对List集合进行操作的,例如查找、排序、获取最大值
最小值等方法。

3、Arrays:针对数组进行操作的工具类。提供了排序,查找等功能。

二、Collections 的常见方法

1、排序

public static <T> void sort(List<T>
list)根据自然顺序对list集合中的元素进行排序

public static void shuffle(List<?>
list)使用默认随机源对list集合中的元素进行随机排序

2、查找

public static <T> int binarySearch(List<?>
list,T key)二分法搜索list集合中的指定对象

public static <T> T max(Collection<?>
coll)根据集合的自然顺序,获取coll集合中的最大元素。

3、反转

public static void reverse(List<?>
list)把list集合中元素的顺序进行反转。

三、Collections和Collection的区别

1、Collection是集合框架中的一个顶层接口,它里面定义了单列集合的共性方法,它有两个常用的子接口:List
Set。

2、Collections:集合框架的工具类,里面定义的都是静态方法。基本上都是对于对List集合进行操作的,例如查找、排序、获取最大值
最小值等方法,

也可以通过该工具类中的同步方法,将线程不安全的集合,转换成安全的。

四、Arrays 的常见方法

1、public static String toString(int[]
a)把一个数组转变成字符串。

2、public static void sort(int[] a)把数组里面的元素进行排序。

3、public static int binarySearch(int[] a,int key)二分查找。

五、集合与数组之间相互转换

1、public static Lsit<T> asList(T...
a)将数组转换为集合

(1)、当把一个数组转变成一个集合时,不能使用集合中的增删方法,那是由于数组的长度是固定不变的,要是用的法,在编译时期报出UnsupportedOperationException异常。

(2)、当数组转变成集合的时候,假如数组元素是对象的话,数组中的元素就成了集合中的元素了,要是基本数据类型,这个数组就成了集合中的元素了。

2、Collection接口中的toArray方法 集合转变成数组

(1)、好处:可以对集合中的元素操作的方法进行限定,但不允许对其进行增删。

(2)、在toArray方法中需要传入一个指定类型的数组,既然是数组那么它的长度该如何定义呢?

(2).1 如果长度小于集合的size,那么该方法会创建一个同类型并和集合相同size的数组。

(2).2 如果长度大于集合的size,那么该方法就会使用指定的数组,存储集合中的元素,其他位置默认为null。

(2).3 如果长度等于集合的size, 在最好不过了。

第三节:1.5版本的新特性

一、高级for循环

1、是for循环的一种

2、格式:

for(元素的数据类型 变量名 : 数组或者Collection集合的对象)
{

使用该变量即可,该变量其实就是数组或者集合中的元素。

}

3、好处:

简化了数组和集合的遍历

4、弊端:

高级for循环的目标不能为null。建议在使用前,先判断是否为null。

5、传统for和高级for的区别?

(1)、传统for可以完成对语句执行很多次,因为可以定义控制循环的增量和条件。

(2)高级for是一种简化形式。

(2).1 它必须有被遍历的目标。该目标要是数组,要么是Collection单列集合。

(2).2 对数数组的遍历如果仅仅是获取数组中的元素,可以使用高级for。

(2).3 如果要对数组的角标进行操作建议使用传统for。

6、代码体现

[java] view
plaincopy

class Demo16

{

public static void main(String[] args)

{

//传统for遍历数组

int[] array= {1,2,3};

for(int x=0; x<array.length; x++)

{

System.out.println(array[x]);

}

//高级for遍历数组

for(int in : array)

{

System.out.println("in:"+in);

}

}

}

二、函数的可变参数

1、如果我们在写方法的时候,参数个数不明确,就应该定义可变参数,其实就是一个数组,但是接收的是数组的元素,自动将这些元素封装成数组。简化了调用者的书写。

2、格式:

修饰符 返回值类型 方法名(数据类型... 变量) {}

注意:

(1)、该变量其实是一个数组名。

(2)、如果一个方法有多个参数,并且有可变参数,可变参数必须在最后。

3、Arrays工具类的一个方法

asList()把数组转成集合。

4、代码体现

[java] view
plaincopy

class Demo17

{

public static void main(String[] args)

{

//传入一定量的数

show(1,2,3,4,5,6);

}

public static void show(int... array)//...就表示可变参数

{

//打印array的长度

System.out.println(array.length);

}

}

三、静态导入

1、可以导入到方法级别的导入

2、格式:

import static 包名....类名.方法名。

3、注意事项:

(1)、方法必须是静态的。

(2)、如果多个类下有同名的方法,就不好区分了,还得加上前缀。

所以一般我们并不使用静态导入,但是一定要能够知道看懂。

4、代码体现

[java] view
plaincopy

import static java.util.Arrays.*;

import static java.lang.System.*;

class Demo18

{

public static void main(String[] args)

{

int[] arr = {2,1,9,8};

sort(arr);//方法sort时就可以省略书写Array.

for (int x=0;x<arr.length ;x++ )

{

out.println(arr[x]);//打印可以省略System

}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: