黑马程序员———集合


------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

Collection

为什么会出现集合类?

面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对

象最常用的一种方式。

数组和集合类同是容器,有何不同?

数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象。

集合类的特点

集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。

数组存储对象的话,只能存储同一种类型的对象

集合框架图

为什么会出现这么多的容器?

因为每一个容器对数据的存储方式都有不同。也就是数据结构不同。。

List:元素是有序的,元素可以重复。因为该集合体系有索引。

ArrayList:底层的数据结构式数组结构。特点:查询速度快,但是增删稍慢,线程不同步(一般情况下选ArrayList,

因为实际开发中设计增删的一般远远少于查询)

LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询稍慢

Vector:底层是数组结构,线程同步,被ArrayList替代了(Vector支持枚举)

Set:元素是无序的,元素不可以重复。

List有其特有的迭代器:ListIterator。ListIterator是Iterator的子接口。

在迭代时,不可以通过集合对象的方法操作集合中的元素,因为会发生ConcurrentModificationException异常,以,

在迭代器时,只能用迭代器的方法操作原始,可是Iterator方法是有限的,只能对元素进行判读,取出,删除的操作

,如果想要其他的操作,如添加,修改等,就需要使用其子接口,ListIterator。

该接口只能通过List集合的listIterator方法获取。


Vector枚举就是Vector特有的取出方式,发现枚举和迭代器很像,其实枚举和迭代器是一样的。因为枚举的名称以及

方法的名称都过长。所以被迭代器取代了。

Vector 代码:

//创建Vector容器	
	Vector vt = new Vector();
	//添加元素
	vt.add("00");
	vt.add("01");
	vt.add("03");
	vt.add("04");
	//枚举迭代
	Enumeration en = vt.elements();
	while(en.hasMoreElements()){
		sop(en.nextElement());
	}

List练习代码:

import java.util.*;
public class ListDemo {
	public static void main(String args[]){
		//创建List集合
		List list = new ArrayList();
		//添加元素
		list.add("aaa");
		list.add("bbb");
		list.add("ccc");
		list.add("ddd");
		//取出元素第一种方式 for循环
		for(int i = 0 ; i < list.size(); i++){
			System.out.println(list.get(i));
		}
		//取出元素第二种方式,迭代器
		Iterator it = list.iterator();
		while(it.hasNext()){
			System.out.println(it.next());
		}
		//list特有的迭代方式ListIterator
		ListIterator lit = list.listIterator();
		while(it.hasNext()){
			System.out.println(lit.next());
		}
		//Vector特有的取出方式:枚举
	    Vector ve = new Vector();
	    ve.addAll(list);
	    //枚举
	    Enumeration enu = ve.elements();
	    while(enu.hasMoreElements()){
	    	System.out.println(enu.nextElement());
	    }
	}

}

Linkedlist

Linkedlist特有方法:

1、增

        addFirst();

        addLast();

2、获取

        //获取元素,但不删除元素。如果集合中没有元素,会出现NoSuchElementException

        getFirst();

        getLast();

3、删

        //获取元素,并删除元素。如果集合中没有元素,会出现NoSuchElementException

        removeFirst();

        removeLast();

JDK1.6以后,出现了替代方法。

1、增

        offFirst();

        offLast();

2、获取

        //获取元素,但是不删除。如果集合中没有元素,会返回null

        peekFirst();

        peekLast();

3、删

        //获取元素,并删除元素。如果集合中没有元素,会返回null

        pollFirst();

        pollLast();

用LinkedList模仿一个堆栈

import java.util.*;
//测试类
public class StackDemo {

	public static void main(String[] args) {
		Stack st = new Stack();
		st.myAdd("s1");
		st.myAdd("s2");
		st.myAdd("s3");
		st.myAdd("s4");
		st.myAdd("s5");
		while(!st.isEmpty()){
			System.out.println(st.myGet());
		}
		

	}

}
//堆栈类
class Stack{
	//定义一个私有的LinkedList
	private LinkedList ll;
	//一创建对象,对象就包含一个Linkedlist对象
	 Stack(){
		ll = new LinkedList();
	}
	 //将元素插入到列表的开头
	 public void myAdd(Object obj){
		 ll.addFirst(obj);
	 }
	 //移除并返回列表的第一个元素
	 public Object myGet(){
		return ll.removeFirst();
	 }
	 //判断集合是否为空
	 public boolean isEmpty(){
		 return ll.isEmpty();
	 }
}

用LinkedList模仿一个队列

代码:

 

import java.util.*;
//测试类
public class StackDemo {

	public static void main(String[] args) {
		Stack st = new Stack();
		st.myAdd("s1");
		st.myAdd("s2");
		st.myAdd("s3");
		st.myAdd("s4");
		st.myAdd("s5");
		while(!st.isEmpty()){
			System.out.println(st.myGet());
		}
		

	}

}
//堆栈类
class Stack{
	//定义一个私有的LinkedList
	private LinkedList ll;
	//一创建对象,对象就包含一个Linkedlist对象
	 Stack(){
		ll = new LinkedList();
	}
	 //将元素插入到列表的开头
	 public void myAdd(Object obj){
		 ll.addFirst(obj);
	 }
	 //移除并返回列表的第一个元素
	 public Object myGet(){
		return ll.removeFirst();
	 }
	 //判断集合是否为空
	 public boolean isEmpty(){
		 return ll.isEmpty();
	 }
}

队列:先进先出,如同一个水管
package com.itheima;
import java.util.*;
//测试类
public class QueDemo {
	public static void main(String args[]){
		Que q = new Que();
		q.myAdd("j1");
		q.myAdd("j2");
		q.myAdd("j3");
		q.myAdd("j4");
		while(!q.isEmpty()){
			System.out.println(q.myGet());
		}
		
	}
}
//队列类
class Que{
	//定义一个私有的LinkedList
	private LinkedList ll;
	//一初始化对象就有一个LinkedList
	Que(){
		ll = new LinkedList();
	}
	//每次将元素添加到列表的开头
	public void myAdd(Object obj){
		ll.addFirst(obj);
	}
	//移除并返回列表的最后一个元素
	public Object myGet(){
		return ll.removeLast();
	}
	//判断列表是否为空
	public Boolean isEmpty(){
		return ll.isEmpty();
	}

}

ArrayList集合去重

代码:

import java.util.*;
//测试类
public class ArrayListDemo {

	public static void main(String[] args) {
		ArrayList ar = new ArrayList();
		ar.add(new Person1("lisi 01",23));
		ar.add(new Person1("lisi 01",23));
		ar.add(new Person1("lisi 02",26));
		ar.add(new Person1("lisi 03",21));
		ar.add(new Person1("lisi 04",22));
		ar = Singe.sinElemnt(ar);
		Iterator it =ar.iterator();
		while(it.hasNext()){
			Person1 p = (Person1)it.next();
			System.out.println(p.name);
		 
		}
		
	}

}
class Singe{
	//去重的方法
	public static ArrayList sinElemnt(ArrayList ar){//传入一个要去重的集合
		//定义一个新集合
		ArrayList myArray = new ArrayList();
		Iterator it = ar.iterator();
		//遍历传入的集合,并判断新集合中是否包含传入集合的每个元素,如果不包含,就把此元素添加到新集合中
		while(it.hasNext()){
			Object obj = it.next();
			if(!myArray.contains(obj)){
				myArray.add(obj);
			}
		}
		//返回去重后的新集合
		return myArray;
	}
}

class Person1{
	String name;
	int age;
	public Person1(String name, int age){
		this.name = name;
		this.age = age;
	}
	public String getName(){
		return name;
	}
	public int getAge(){
		return age;
	}
	//重写equals方法
	public boolean equals(Object obj){
		
		if(!(obj instanceof Person1))
			return false;
		Person1 p = (Person1)obj;
		return this.name.equals(p.name) && this.age == p.age;
	}
}

set

Set:元素是无序的(存入和取出的顺序不一定一致),元素不可以重复

HashSet:底层数据结构是哈希表

HashSet是如何保证元素的唯一性的?

是通过元素的两个方法,hashCode和equals来完成的

如果元素的hashCode值相同,才会判断equals是否为true

如果元素的hashCode值不同,不会调用equals方法

HashSet判断元素是否存在,以及删除等操作,依赖的方法是元素的hashCode和equals方法

但ArrayList删除和判断元素是否存在,依赖equals方法

TreeSet可以对Set集合中的元素进行排序,底层数据结构式二叉树,保证元素的唯一性依据的是compareTo方法。

TreeSet排序的第一种方式:让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo方法。这种方

式也称为元素的自然顺序,或者叫做默认排序。

排序时,当主要条件相同时,一定要判断一下次要条件

代码:

import java.util.*;
//测试类
public class TreeSetDemo {
	public static void main(String[] args) {
		TreeSet ts = new TreeSet();
		ts.add(new Student("lisi01",22));
		ts.add(new Student("lisi02",22));
		ts.add(new Student("lisi03",24));
		ts.add(new Student("lisi05",20));
		ts.add(new Student("lisi05",19));
		//迭代取出元素
		for(Iterator it = ts.iterator();it.hasNext();){
			Student st = (Student)it.next();
			System.out.println(st.getName()+"...."+st.getAge());
		}

	}

}
//Student实现了Comparable接口
class Student implements Comparable{
	private String name;
	private int age;
	//构造函数
	public Student(String name, int age){
		this.name = name;
		this.age = age;
	}
	//get方法
	public String getName() {
		return name;
	}

	public int getAge() {
		return age;
	}
    //复写compareTo方法
	@Override
	public int compareTo(Object obj) {
		//类型强转
		Student st = (Student)obj;
		//比较年龄 主要条件
		int num = new Integer(this.getAge()).compareTo(new Integer(st.getAge()));
		//如果年龄相等比较姓名 次要条件
		if(num == 0){
			return this.getName().compareTo(st.getName());
		}
		//如果年龄不相等 返回年龄的比较值
		return num;
		
	}
	
}

TreeSet排序的第二种实现方式:当元素自身不具备比较性,或者具备的比较性不是所需要的,这时需要让容器自身

具备比较性。定义一个比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。

当两种排序都存在时,以比较器为主。

定义一个类,实现Comparator接口,覆盖compare方法。

代码:

import java.util.*;
//测试类
public class TreeSetDemo {
	public static void main(String[] args) {
		TreeSet ts = new TreeSet(new MyCompare());
		ts.add(new Student("lisi01",22));
		ts.add(new Student("lisi02",22));
		ts.add(new Student("lisi03",24));
		ts.add(new Student("lisi05",20));
		ts.add(new Student("lisi05",19));
		//迭代取出元素
		for(Iterator it = ts.iterator();it.hasNext();){
			Student st = (Student)it.next();
			System.out.println(st.getName()+"...."+st.getAge());
		}

	}

}
//Student实现了Comparable接口
class Student implements Comparable{
	private String name;
	private int age;
	//构造函数
	public Student(String name, int age){
		this.name = name;
		this.age = age;
	}
	//get方法
	public String getName() {
		return name;
	}

	public int getAge() {
		return age;
	}
    //复写compareTo方法
	@Override
	public int compareTo(Object obj) {
		//类型强转
		Student st = (Student)obj;
		//比较年龄 主要条件
		int num = new Integer(this.getAge()).compareTo(new Integer(st.getAge()));
		//如果年龄相等比较姓名 次要条件
		if(num == 0){
			return this.getName().compareTo(st.getName());
		}
		//如果年龄不相等 返回年龄的比较值
		return num;
		
	}
	
}
//比较器 实现Comparator接口
class MyCompare implements Comparator{
    //重写compare方法
	@Override
	public int compare(Object o1, Object o2) {
		Student s1 = (Student)o1;
		Student s2 = (Student)o2;
		//比较名字 
		int num = s1.getName().compareTo(s2.getName());
		//如果名字相同返回年龄的比较值
		if(num==0){
			return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
		}
		//如果名字不同返回名字的比较值
		return num;
	}
	
}

泛型

泛型:JDK1,5版本以后出现的新特性。用于解决安全问题,是一个类型安全机制。

好处:1,将运行时期出现问题ClassCastException,转移到了编译时期,方便于程序员解决问题,让运行时问题减少,安全。

2,避免了强制转换的麻烦。

泛型格式:通过<>来定义要操作的引用数据类型。

在使用java提供的对象时,什么时候写泛型呢?

通常在集合框架中很常见,只要见到<>就要定义泛型。其实<>就是用来接收类型的,当使用集合时,将集合中要存

储的数据类型作为参数传递到<>中即可。

泛型在集合中的应用代码:

import java.util.*;
public class GenericDemo {

	public static void main(String[] args) {
		//定义带泛型的集合
		ArrayList<String> al = new ArrayList<String>();
		//添加元素
		al.add("java01");
		al.add("java02");
		al.add("java03");
		al.add("java04");
		//迭代输出
		Iterator<String> it = al.iterator();
		while(it.hasNext()){
			System.out.println(it.next());
		}

	}

}

泛型在比较器中的应用代码:

import java.util.*;
public class GenericDemo2 {
	public static void main(String[] args) {
		//定义带泛型的集合
		TreeSet<Student1> ts = new TreeSet<Student1>(new Comp());
		ts.add(new Student1("xiaox1",21));
		ts.add(new Student1("xiaox2",22));
		ts.add(new Student1("xiaox3",24));
		ts.add(new Student1("xiaox4",28));
		ts.add(new Student1("xiaox5",13));
		ts.add(new Student1("xiaox6",17));
		//迭代输出
		Iterator<Student1> it = ts.iterator();
		while(it.hasNext()){
			Student1 t1 = it.next();
			System.out.println(t1.getName()+"..."+t1.getAge());
		}	
	}
}
//在Comprable接口中定义泛型
class Student1 implements Comparable<Student1>{
	private String name;
	private int age;
	public Student1(String name, int age){
		this.name = name;
		this.age = age;
	}
	public String getName(){
		return name;
	}
	public int getAge(){
		return age;
	}
	@Override
	public int compareTo(Student1 t1) {
		int num = new Integer(this.getAge()).compareTo(new Integer(t1.getAge()));
		if(num == 0){
			return this.getName().compareTo(t1.getName());
		}
		return num;
	}
	
	
}
//在Comprator接口中定义泛型
class Comp implements Comparator<Student1>{

	@Override
	public int compare(Student1 t1, Student1 t2) {
		int num = new Integer(t1.getAge()).compareTo(t2.getAge());
		if(num == 0){
			return t1.getName().compareTo(t2.getName());
		}
		return num;
	}
	
}


 

什么时候定义泛型类?

当类中要操作的引用数据类型不确定的时候。早期定义Object来完成扩展,现在定义泛型来完成扩展。

泛型类定义的泛型,在整个类中都有效。如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经

固定了。

同时,为了让不同方法可以操作不同类型,而且类型还不确定,可以将泛型定义在方法上。

特殊之处:静态方法不可以访问类上定义的泛型。如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。

//测试类
public class GenericClassDemo {

	public static void main(String[] args) {
		//测试泛型类
		Demo<String> d = new Demo<String>();
		d.show("哈哈");
		d.print("heihei");
		//测试泛型方法
		Demo1 d1 = new Demo1();
		d1.show("haha");
		d1.print(2);
		//测试泛型类和泛型方法的混合
		Demo2<String> d2 = new Demo2<String>();
		d2.show("你好啊");
		d2.print(3);

	}

}
//泛型类
class Demo<T>{
	public void show(T t){
		System.out.println(t);
	}
	public void print(T t){
		System.out.println(t);
	}
}
//泛型方法
class Demo1{
	public<T> void show(T t){
		System.out.println(t);
	}
	public <Q> void print(Q q){
		System.out.println(q);
	}
}
//泛型类和泛型方法的混合
class Demo2<T>{
	public void show(T t){
		System.out.println(t);
	}
	public<Q> void print(Q q){
		System.out.println(q);
	}
}

泛型定义在接口上

//泛型接口
interface Test<T>{
	void show(T t);
}
//实现泛型接口的类
class Test1 <T> implements Test<String>{//第一个T代表类的泛型 第二个T代表接口的泛型

	@Override
	public void show(String t) {
		System.out.println(t);
		
	}
	public void print(T t){
		System.out.println(t);
	}
	
}
//实现泛型接口的类继续使用泛型
class Test2 <T> implements Test<T>{//类和接口都使用泛型是要一致 不然会报错

	@Override
	public void show(T t) {
		System.out.println(t);
		
	}
	public void print(T t){
		System.out.println(t);
	}
}

?通配符(或者说占位符)可以代表任意类型

泛型限定:

? extends E : 可以接受E类型或者E的子类类型,限定上限。

? super E 可以接受E类型或者E的父类型,限定下限。

?的示例代码:

import java.util.*;
public class GenericDemo3 {

	public static void main(String[] args) {
		ArrayList<String> al = new ArrayList<String>();
		al.add("li1");
		al.add("li2");
		al.add("li3");
		al.add("li4");
		al.add("li5");
		ArrayList<Integer> al2 = new ArrayList<Integer>();
		al2.add(1);
		al2.add(2);
		al2.add(3);
		al2.add(4);
		al2.add(5);
		//传入al 泛型
		print(al);
		//传入 al2 泛型
		print(al2);

	}
	
    public static void print(ArrayList<?> al){//使用通配符
    	Iterator<?> it = al.iterator();
    	while(it.hasNext()){
    		System.out.println(it.next());
    	}
		
	}
}
	

? extends E示例代码:

import java.util.*;
//测试类
public class GenericDemo4 {

	public static void main(String[] args) {
		//泛型为父类Person的ArrayList
		ArrayList <Person> al = new ArrayList<Person>();
		//泛型为子类Student2 的ArrayList
		ArrayList<Student2> al2 = new ArrayList<Student2>();
		//泛型为子类Worker的ArrayList
		ArrayList<Worker> al3 = new ArrayList<Worker>();
		al.add(new Person("Person1"));
		al.add(new Person("Person2"));
		al.add(new Person("Person3"));
	    al2.add(new Student2("Student1"));
	    al2.add(new Student2("Student2"));
	    al2.add(new Student2("Student3"));
	    al3.add(new Worker("Worker1"));
	    al3.add(new Worker("Worker2"));
	    al3.add(new Worker("Worker3"));
	    //打印al
	    print(al);
	    //打印al2
	    print(al2);
	    //打印al3
	    print(al3);
	}
	public static void print(ArrayList<? extends Person> al){//使用上限为Peroson的通配符
		//迭代 取出 打印
		Iterator<? extends Person> it = al.iterator();
		while(it.hasNext()){
			System.out.println(it.next().getName());
		}
		
	}

}
//父类
class Person{
	private String name;
	public Person(String name){
		this.name  = name;
	}
	public String getName(){
		return name;
	}
	private void show(){
		
	}
}
//子类 Student2
class Student2 extends Person{
	
	public Student2(String name){
		super(name);
	}
}
//子类 Worker
class Worker extends Person{
    String name;
	public Worker(String name) {
		super(name);
	}
	
}

? super E代码:

TreeSet<E> 有一个构造函数TreeSet(Comparator<? super E comparator>

示例代码:

import java.util.*;
public class GenaricDemo5 {

	public static void main(String[] args) {
		TreeSet<Student3> al = new TreeSet<Student3>(new Comp3());//Student3 TreeSet 传入Person3 比较器
		TreeSet<Worker3> al2 = new TreeSet<Worker3>(new Comp3());//Worker3 TreeSet 传入Person3 比较器
		al.add(new Student3("lisi01"));
		al.add(new Student3("lisi02"));
		al.add(new Student3("lisi03"));
		al2.add(new Worker3("wangwu01"));
		al2.add(new Worker3("wangwu02"));
		al2.add(new Worker3("wangwu03"));
		//迭代取出
		Iterator<Student3> it = al.iterator();
		while(it.hasNext()){
			System.out.println(it.next().getName());
		}
		Iterator<Worker3> i = al2.iterator();
		while(i.hasNext()){
			System.out.println(i.next().getName());
		}
		

	}

}
//父类Person3
class Person3{
	private String name;
	private int age;
	public Person3(String name){
		this.name = name;
	}
	public String getName(){
		return name;
	}
}
//子类Student3
class Student3 extends Person3 {

	public Student3(String name) {
		super(name);
		// TODO Auto-generated constructor stub
	}
	
}
//子类Worker3
class Worker3 extends Person3{

	public Worker3(String name) {
		super(name);
		// TODO Auto-generated constructor stub
	}
	
}
//Person3 类型的比较器
class Comp3 implements Comparator<Person3> {

	@Override
	public int compare(Person3 o1, Person3 o2) {
		return o1.getName().compareTo(o2.getName());
	}

	
	
}




 

 

 


 



 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值