黑马程序员——java基础-泛型和集合框架工具类

------- android培训、java培训、期待与您交流! ----------

第一节:泛型
一、泛型的由来和基本使用
1、因为集合可以存储的对象类型是任意的,在取出进行向下转型时,容易发生ClassCastException。
所以JDK1.5以后就有了解决这个问题的技术:泛型。
2、泛型的原理:其实就是在操作的元素类型不确定时,通过传递参数的形式来明确类型。
3、泛型的体现就是 <参数类型变量>用于接收具体的实际元素类型。
4、泛型技术在集合框架中应用非常广泛,只要记住:在使用类或者接口时,如果接口上有明确<>泛型。
在使用时,就传递所需的数据类型即可。不传递会出现警告类型不安全提示。
5、了解:泛型技术是用在编译器部分的技术,一旦类型检查正确,
生成的class文件中就没有泛型标记了:这是的泛型的擦除。
6、泛型的好处:
6.1 将运行时期的ClassCastException异常转移到编译时期通过编译失败体现。
6.2 避免了强制转换的麻烦。
7、其实泛型的使用就是往定义了泛型的类或者接口的<>中传递类型参数。
8、泛型在集合对象中的使用,要求写集合代码时必须加入泛型 
代码体现

import java.util.*;
class FanXingDemo
{
	public static void main(String[] args)
	{	
		List list = new ArrayList();
		//添加元素
		list.add("abc");
		list.add("zzzz");
//		list.add(6);//只要不是指定的类型对象,编译器检查会 报错。这样将运行时的问题转移到编译时期。
		//用迭代器进行对元素遍历
		for (Iterator 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 静态方法无法访问类上定义的泛型,如果需要泛型,只能定义在方法上。

       代码体现

import java.util.*;
class Queue{
	//封装了一个LinkedList类。
	private LinkedList link;
	//类初始化,LinkedList对象初始化。
	Queue(){
		link = new LinkedList();
	}
	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的子类型。上限。

          代码体现

import java.util.*;
class FanXingDemo5
{
	public static void main (String[] args)
	{
		//创建list对象,并添加元素
		Lists =new ArrayList();
		s.add(new Student("张三"));
		s.add(new Student("小三"));
		s.add(new Student("小五"));
		s.add(new Student("小六"));
		getStudent(s);
		//创建list对象,并添加元素
		Lists1 =new ArrayList();
		s1.add(new Wroker("李四"));
		s1.add(new Wroker("小四"));
		s1.add(new Wroker("小李"));
		getStudent(s1);
	}
	//对传入的对象进行限定
	public static void getStudent(Collection cl)
	{
		//进行迭代
		for(Iterator 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的父类型。下限。

import java.util.*;
class FanXingDemo5
{
	public static void main (String[] args)
	{
		//创建list对象,并添加元素
		Sets =new TreeSet(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对象,并添加元素
		Sets1 =new TreeSet(new myComparator());
		s1.add(new Wroker("李四",36));
		s1.add(new Wroker("小四",87));
		s1.add(new Wroker("小李",43));
		getStudent(s1);
	}
	//对传入的对象进行限定
	public static void getStudent(Collection cl)
	{
		//进行迭代
		for(Iterator 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类,所以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 c) :在给TreeSet集合初始化元素时,
传递进来的容器中的元素类型只要时TreeSet集合明确的类型或者子类型都可以。
TreeSet(Comparator comparator) :在明确TreeSet比较器时,
只要是TreeSet集合元素类型的比较器,或者该元素类型的父类型都接收元素对象进行比较。

5、泛型限定的练习。

代码体现

//泛型的练习
/*
		 * 案例:获取集合中元素的最大值。
		 * 
		 * 思路: 1,定义变量记录每次比较后较大的值,初始化元素中任意一个。 2,遍历容器
		 * 3,在遍历中和变量中记录的元素进行比较。并将较大的值记录到变量中。 4,遍历结束,变量中记录的就是最大值。
		 */
import java.util.*;
class FanXingDemo4
{
	public static void main (String[] args)
	{
	//不加泛型进行获取
	Set s1 =new TreeSet();
	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 getValue(Set cle)
	{
		Iterator 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
{
	//私有学生类的属性
	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 void sort(List list)根据自然顺序对list集合中的元素进行排序
public static void shuffle(List list)使用默认随机源对list集合中的元素进行随机排序
2、查找
public static int binarySearch(List list,T key)二分法搜索list集合中的指定对象
public static 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 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、代码体现

class Demo16
{
	public static void main(String[] args)
	{
	//传统for遍历数组
		int[] array= {1,2,3};

		for(int x=0; x
二、函数的可变参数
1、如果我们在写方法的时候,参数个数不明确,就应该定义可变参数,其实就是一个数组,但是接收的是数组的元素,自动将这些元素封装成数组。简化了调用者的书写。
2、格式:
修饰符 返回值类型 方法名(数据类型... 变量) {}
注意:
(1)、该变量其实是一个数组名。
(2)、如果一个方法有多个参数,并且有可变参数,可变参数必须在最后。
3、Arrays工具类的一个方法
asList()把数组转成集合。
4、代码体现

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、代码体现
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

------- android培训、java培训、期待与您交流! ----------

你可能感兴趣的:(java,学习日记)