------- android培训、java培训、期待与您交流! ----------
Collection
---List:元素是有序的,元素可以重复,因为该集合体系有索引***新建了一个类要复写equals()方法
------ArrayList: 底层的数据结构使用的是数组结构. 特点:查询速度很快,但是增删稍慢,线程不同步 初始化数组长度为10,当超过10之后以之前容器的百分之125%再新建一个容器,把以前的数据copy过去
------LinkedList:底层使用的是链表数据结构.特点:增删速度快,查询稍慢
------Vector:底层是数组数据结构.线程同步,被ArrayList替代了
---Set:元素是无序的(存入和取出的顺序不一定一致),元素不可以重复,线程是非同步的,Set功能和Collection的功能是一致的,***新建了一个类要复写hashCode()方法和equals()方法
------HashSet:数据结构是哈希表,判断元素哈希值是否相同,如果相同还会判断元素的equals方法,是否为true
HashSet是如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成
如果元素的hashCode的值相同,才会判断equals是否为true
如果元素的hashCode的值不同,才会调用equals
------TreetSet:可以对Set集合中的元素进行排序.
TreeSet排序的原理是:存第一次数据的时候除外,每次往里存数据都调用compareto方法,如果存进来的对象小于集合里的对象,返回负数通常都写-1,如果等于就返回0,如果大于就返回整数通常都写1
TreeSet底层数据结构是二叉树,保证元素唯一性的依据:compareTo方法return 0表示两个数相等
TreeSet排序的第一种方式:让元素自身具备比较性.类型要实现Comparable接口,覆盖compareTo方法.这种方式也称为元素的自然顺序
TreeSet排序的第二种方式:当元素自身不具备比较性,或者局部的比较性不是所需要的这时需要让容器自身具备比较性
定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数实现Comparator接口,覆盖compare方法
当两种排序都存在时,以比较器为主定义一个类,
TreeSet取数也是按照元素大小来取的,原来进来的时候,集合把小的放在左边,大的放在右边,像个二叉树一样
注意:
要想取出来的顺序和添加的时候一样,复写compareTo方法的时候返回1就行了
要想取出来的顺序和添加的时候相反,复写compareTo方法的时候返回-1就行了
1 为什么出现集合类
数据多了要封装称为对象,对象多了也要进行存储,集合是用来存储对象的
2 数组和集合类都是容器,有何不同?
数组虽然也可以存储对象,但长度是固定的;集合长度是可变的
数组中可以存储基本数据类型,集合只能存储对象
3为什么会出现这么多的容器呢?
因为每一个容器对数据的存储方式都有不同
这个存储方式称为:数据结构
4 ArrayList
先建一个Collection的子集ArrayList来验证一下
伪代码演示
ArrayList al=new ArrayList(); ArrayList a2=new ArrayList();
//添加元素
al.add("java01");
al.add("java01");
al.add("java01");
//删除元素
al.remove("java01");//删除指定元素 返回值类型是bolean类型
al.removeAll(a2); //删除al集合里包含a2集合的元素 返回值类型是boolean
al.clear(); //清空集合 返回值类型是void
//获取长度 返回值类型是int
al.size();
//判断集合是否为空
al.isEmpty(); //如果为空就true
//判断是否包含contains一些元素 返回值类型是boolean类型
a1.contains("java01");
//al保留al和a2中的交集 返回值类型是boolean,有交集就返回true,没有false
al.retainAll(a2);
4 ArrayList al=new ArrayList();
Person p=new Person();
al.add(p); //把p对象存储进集合,不是把整个对内存里的人对象放到集合里面去,只是把人对象的地址值放到了集合中
4 怎样获取集合中的元素呢?迭代器 例子:电玩成里的夹公仔游戏!
每个集合里的数据结构都不一样,所以取出方式跟添加元素的方法就不同了,但是每个集合取出元素的时候都要作:判断和取出的操作,于是就把这个共同点抽取出来,定义一个抽象类(接口)叫做Iteratro,并且这个接口是定义在集合里面的,集合提供了一个方法让我们获取到这个接口的对象,当我们要从集合中取出元素时,只要获取到Iterator的对象就可以操作集合里的元素了
伪代码:
使用集合的时候要导入:import java.util.*;
ArrayList al=new ArrayList();
al.add("java01").add("java02").add("java03");
Iterator it=al.iterator(); //调用iterator()方法,返回一个Iterator对象
while(it.hasNext()) //it.hasNext()判断集合还有没有下一个元素,返回类型是 boolean
{
System.out.println(it.next()); //it.next()取出集合的下一个元素
}
也可以写for循环,主要区别是for循环结束后it对象会在内存中消失,节约空间
for(Iterator it=al.iterator();it.hasNext();)
{
System.out.println(it.next());
}
5 List体系中的元素是有序的,元素可以重复,因为该集合体系有索引
凡是可以操作角标的都是List体系特有的方法
list体系特有的方法:
增:add(inedx,element); addAll(index,Collection);
删:remove(index);
改:set(index,element);
查:get(index);
subList(from to); 返回值是List
6 ListIterator是Iterator的子接口
在迭代时不可以通过集合的方法操作集合中的元素,会发生异常
所以在迭代器时,只能用迭代器的方法操作元素,可是Iterator方法是有限的,只能对元素进行判断,取出和删除操作
如果想要其他的操作如,添加,修改等,就需要使用其子接口,ListIterator
该子接口只能通过List集合的listIterator方法获取
ListIterator it=al.listIterator();//假设al是list集合,获取ListIterator迭代器
while(it.haxNext())
{
Object obj=it.next();
if(obj.equals("java01"))
it.remove()
System.out.println(0bj); //这里打印是会有java01的因为it.next()把从集中中取出的"java01"的引用赋值给了obj,所以obj就指向了内存里的java01, it.remov()只是把集中"java 01"的引用删除了
}
System.out.println(al);
7 Vector
枚举方法是Vector体系特有的,跟Iterator方法是一样的,以前都是用枚举方法的
Enumeration en=new Vector().elements();//取得迭代器
while(en.hasMoreElements())
{
System.out.println(en.nextElement());
}
8 LinkedList特有方法:
添加 addFirst();//把元素添加到第一位 addLast();//添加到最后一位
获取 getFirst();/得到第一位的元素 getLast(); //获取元素但不删除元素
删除 removeFirst(); removeLast(); //获取元素并删除元素
上面是老版本的方法,当集合没有元素时程序会抛出NoSuchElementException异常
在JDK1.6出现了替代方法
添加 offerFirst(); offerLast(); //当集合没有元素, 返回null
获取 peekFirst(); peekLast() //当集合没有元素,返回null
删除 poolFirst(); poolLast() //当集合没有元素,返回null
9 使用LinkedList模拟一个堆栈或者队列数据结构
堆栈:先进后出 如同一个杯子
/*
模拟一个堆栈,先进后出
*/
import java.util.*;
class DuiZhan
{
private LinkedList lin;
DuiZhan()
{
lin=new LinkedList();
}
public void myAdd(Object obj)
{
lin.addFirst(obj);
}
public Object myGet()
{
return lin.removeFirst();
}
public boolean isNull()
{
return lin.isEmpty();
}
}
class LinkedTest
{
public static void main(String[] args)
{
DuiZhan dz=new DuiZhan();
dz.myAdd("java01");
dz.myAdd("java02");
dz.myAdd("java03");
dz.myAdd("java04");
while(!(dz.isNull()))
{
System.out.println(dz.myGet());
}
}
}
队列:先进先出 如同一个水管
10 例子:去除ArrayList中的重复元素
分析:
自己新建一个Person类,把Person类放进ArrayList集合中当调用contains或者remove等方法时,系统会调用Object的equals方法,这个equals方法默认比较的是元素的地址值,这时我们要对equals方法复写
Iterator it=al.iterator();
while(it.hasNext())
{
Object obj=it.next();
if(newAl.contains(obj))
/*
newAl集合把obj接受进来,obj就循环调用equals方法,跟newAl集合每个元素进行比较,比较的是地址值是否相等,如果equals返回真,就表示newAl集合里已经有了这个元素了,如果返回假就表示集合里没有这个元素,这题把每个人对象传进去进行比较,因为对新建的不同人对象,所以地址值肯定是不相等的,所以要复写equals才能进行比较
*/
newAl.add(obj);
}
/*
去除ArrayList集中的重复元素
*/
import java.util.*;
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name=name; //把name赋值给对象的name
this.age=age; //把age赋值给对象的age
}
public boolean equals(Object obj)
{
if(!(obj instanceof Person))//判断obj是否为Person的子类
{
new RuntimeExcption("类型不匹配");
}
Person p=(Person)obj;//把obj强转为Person类型
return this.name.equals(p.name)&&this.age==p.age;
}
}
class ArrayListTest
{
public static void main(String[] args)
{
ArrayList al=new ArrayList(); //定义一个集合al
al.add(new Person("zhangSan01",30));
al.add(new Person("zhangSan01",30));
al.add(new Person("zhangSan02",31));
al.add(new Person("zhangSan02",31));
al.add(new Person("zhangSan03",32));
al.add(new Person("zhangSan03",32));
System.out.println(al);
System.out.println(myGet(al));
}
public static ArrayList myGet(ArrayList al)
{
ArrayList newal=new ArrayList(); //定义一个新集合
Iterator it=al.iterator(); //获取迭代器
while(it.hasNext()) //判断是否有下一个元素
{
Object obj=it.next(); //把获取到的元素的地址值赋给obj
判断新集合里没有obj元素,如果没有就把obj添加到新集合
if(!newal.contains(obj))
newal.add(obj);
}
return newal; //返回新集合
}
}
注意:如果我们用Object去接受集合中的元素,那么这个元素会自动提升为Object
while(it.hasNext())
{
Object obj=it.next(); //这里it.next()返回的是一个人对象相当于
Object obj=new Person(); 多态了,父类引用指向了子类对象,obj.name这是父类没有的东西,肯定会编译失败的,所以要强转为子类型
Prson p=(Person)obj;
sop(p.name+......+p.age);
}
11 HashSet
集合存储的元素是唯一的,无序的,都是按照哈希值来存储的,先存进来的元素的哈希值不一定比后进来的元素的哈希值小,所以打印出来的元素,是跟存的时候顺序是不同的,所以说HashSet集合是无序的,存储进来的元素先计算哈希值,如果哈希值不相同就继续存下一个元素,如果哈希值相同就调用equals方法,判断两个对象是否相同
/**
HashSet集合存储的元素是唯一的,无序的,都是按照哈希值来存储的,先存进来的元素的哈希值不一定比后进来的元素的哈希值小,所以打印出来的元素,是跟存的时候顺序是不同的,所以说HashSet集合是无序的
存储进来的元素先计算哈希值,如果哈希值不相同就继续存下一个元素,如果哈希值相同就调用equals方法,判断两个对象是否相同
*/
class Person
{
private String naem;
private int age;
Person()
{
this.name=name;
this.age=age;
}
public boolean equals(Object obj)
{
if(!obj instanceof Person)
return false
Person p=(Person)obj;
}
public int hashCode()
{
return name.hashCode()+age*3;
}
}
class HashSetTest
{
public static void main(String[] args)
{
HashCode hc=new HashCode();
hc.add(new Person("zhansan01",30));
hc.add(new Person("zhansan01",30));
hc.add(new Person("zhansan02",31));
hc.add(new Person("zhansan02",31));
hc.add(new Person("zhansan03",32));
hc.add(new Person("zhansan03",32));
}
}
12 TreeSet
为什么TreeSet集合调用的是comparto方法呢?
我们看到LinkedList集合也是不可以存重复元素的,但是他存元素的时候,底层调用的是equals方法,而TreeSet集合调用的是compareto方法为什么呢?
这是因为,LinkedList只需要判断两个元素是否相同,不需要排序,equals满足这个需要,所以调用equals
而TreeSet不仅要判断重复元素,还要对存进来的元素进行比较,compareto的功能是比较两个元素大小,返回负数,0或者整数,符合这个需求
注意1:
自己创建的类,要具有比较性,必须要实现Comparable类,并且覆盖compareto()方法
注意2:下面代码的执行顺序是,if(true)就执行if框里面的东西,如果是false,就直接跳过框里的东西,执行下面的语句,条件不满足会自动跳到下面的语句,加不加else都会自动跳过框里的数据,执行下面的语句,如果else后只有一条语句,else可以省略,但是如果else后有多条语句,要把用到else语句里的数据的代码用{}括起来
if(obj instanceof Person)//判断obj是否为Person的子类
{
Person p=(Person)obj;//把obj强转为Person类型
return this.name.equals(p.name)&&this.age==p.age;
}
return false; //这里改为else return false;也行
写集合框架程序的时候一定要先导入java.util.*包
不然会出现:找不到符号的错误
/*
用TreeSet集合按照字符串的长度排序
*/
import java.util.*;
class StrLenCompare implements Comparator
{
public int compare(Object o1,Object o2)
{
String s1=(String)o1;
String s2=(String)o2;
int num=new Integer(s1.length()).compareTo(new Integer(s2.length()));
if(num==0)
return s1.compareTo(s2);
return num;
}
}
class TreeSetTest
{
public static void main(String[] args)
{
TreeSet st=new TreeSet(new StrLenCompare());
st.add("a");
st.add("ab");
st.add("abc");
st.add("abcd");
st.add("abwc");
System.out.println(st);
}
}
/*
这是关于TreeSet的功能演示.
需求:向TreeSet集合存入Student学生对象,并按照年龄进行排序
*/
import java.util.*;
class Student implements Comparable //创建学生类并实现Comparable类
{
private String name;
private int age;
Student(String name,int age) //构造函数初始化
{
this.name=name;
this.age=age;
}
public String getName() //定义获取姓名的函数
{
return this.name;
}
public int getAge() //定义获取年龄的函数
{
return this.age;
}
public void setName(String name) //定义改变姓名的函数
{
this.name=name;
}
public void setAge(int age) //定义改变年龄的函数
{
this.age=age;
}
public int compareTo(Object obj) //复写compareTo方法
{
if(!(obj instanceof Student))
throw new RuntimeException(); //抛出RuntimeException异常
Student s=(Student)obj;
System.out.println(this.name+"...compareTO..."+s.name);
if(this.age>s.age)
{
return 1;
}
if(this.age==s.age)
{
return this.name.compareTo(s.name);
}
return -1;
}
}
class MyCompare implements Comparator
{
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;
}
}
class TreeSetDemo
{
public static void main(String[] args)
{
TreeSet ts=new TreeSet(new MyCompare()); //创建容器
//ts.add(new Student("xiaochen01",31));
ts.add(new Student("xiaochen01",34));
ts.add(new Student("xiaochen02",33));
ts.add(new Student("xiaochen03",32));
ts.add(new Student("xiaochen04",31));
ts.add(new Student("xiaochen05",30));
ts.add(new Student("xiaochen06",30));
Iterator it=ts.iterator(); //获取迭代器
//遍历并输出容器中的数据
while(it.hasNext())
{
Student s=(Student)it.next();
sop(s.getName()+"......"+s.getAge());
}
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
13 泛型
泛型类定义的泛型,在整个类中有效,如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了
为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上,泛型<>放在返回值前面
泛型:?是通配符,也可以理解为占位符
泛型的限定
? 表示不知道要传入什么
? extends E 可以接受E或E的子类类型
? super E 可以接受E或者E的父类类型
/*泛型的由来
*/
import java.util.*
class TreeSetTest3
{
public static voia main(String[] args)
{
treeSet st=new TreeSet();
st.add("a");
st.add("ab");
st.add("ab");
st.add("3"); //3是一个对象,相当于Object obj=new Integer();程序会自动装箱
Iterator it=st.iterator();
while(it.hasNext())
{
String s=(String)it.next();//当遍历到3这个对象的时候,把integer类型强制转换为String类型,会出错
System.out.println(s.length());
}
}
}
例子1:
定义在类上:
class Demo<T>
{
public void show(T t)
{
System.out.println(t);
}
public void print(T t)
{
System.out.println(t);
}
}
例子2:
定义在方法上:
class Demo
{
public <T> void show(T t) //这个T跟print没关系
{}
public <T> void print(T t)
{}
}
例子三:
既在类上定义泛型又在方法上定义泛型:
class Demo<T>
{
public <T> void show(T t) //这个T跟着类的T走
{}
public <Q> void print(Q q)//这个Q跟类的泛型没干系,传入什么就是什么
{}
}
例子四:
在静态方法中定义泛型
class Demo<T>
{
public static <T> void show(T t) //这是错误的,因为T建立对象的时候才有,但是静态方法类一加载就有了
{}
public static <Q> void print(Q t)//静态方法定义泛型,应该这样
{}
}
例子五:
泛型定义在接口上:
interface Inter<T>
{
public void show(T t);
}
class Test<T> implements Inter<T>
{
public void show(T t);
{
System.out.println(t);
}
}
Map 集合
---Hashtable 底层是哈希表数据结构,不可以存入null键和null值,该集合线程是同步的. jdk1.0 效率低
---HashMap 底层是哈希表数据结构,可以存入null键和null值,该集合线程是非同步的 jdk1.2 效率高
---TreeMap 底层是二叉树数据结构,下层不同步,可以用于给Map集合中的键进行排序
和Set很像,其实大家,Set底层就是使用了Map集合
1.Map集合:该集合存储键值对.一对一对往里存,而且要保证键的唯一性
/*
这是Map的共性功能
*/
import java.util.*;
class MapDemo
{
public static void main(String[] args)
{
Map<String,String> map=new HashMap<String,String>();
Map<String,String> map2=new HashMap<String,String>();
map2.put("05","zhangsan05");
map2.put("06","zhangsan06");
map.put("01","zhangsan01");
map.put("01","wangwu");
map.put("02","zhangsan02");
map.put("03","zhangsan03");
map.put("04","zhangsan04");
System.out.print((map.put("01","zhangsan02")));
sop(map);
//Collection col=map.values();
//sop(map.put("01","zhangsan01"));
//sop(map.put("01","wangwu"));
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
1添加.
put(Key,V value); 返回值是前一次同样的键的值,如果没有同样的键,则返回null
putAll(Map ? extends K,<?extends V> m);
2删除
clear() 清空集合
remove(Object key) 返回值是这个键对应的值,如果没有这个值和这个键对应的值是null时,则返回null
3判断
containsValue(Object value) 返回值boolean, 如果输入的值有对应的键则true ,如果没有则返回false
containsKey(Object key) 返回值boolean
isEmpty() boolean 如果不是null,则返回true,如果是null,false
4获取
get(Object key) 返回值是这个键对应的值,如果没有或者键对应的值是null则返回null
size() 返回值是int 当集合是null时返回null,当集合没有元素时返回0,集合里有几个元素就返回几个元素
values() 返回值是Map集合中的所有值,返回值类型是Collection
entrySet()
2 获取Map集合中的键值对
方法一:先获取所有的键,再通过每一个键获取每一个值
例子:
Set<String> s=map.ketSet(); // 获取map集合的所有键
Iterator<String> it=s.iterator() //获取迭代器
while(it.hasNext())
{
String s1=it.next(); //获取每一个键
String s2=map.get(s1);//获取每一个键对应的值
System.out.println(s1+"="+s2);
}
/**
利用keySet方法来取出Map集合中对应的键和值
*/
import java.util.*;
class MapDemo2 //定义一个类
{
public static void main(String[] args)
{
//定义一个HahsMap集合
Map<String,String> map=new HashMap<String,String>();
//向HashMap集合添加元素
map.put("01","wangwu01");
map.put("02","wangwu02");
map.put("03","wangwu03");
map.put("04","wangwu04");
map.put("05","wangwu05");
Set<String> s=map.keySet();
//取得迭代器
Iterator<String> it=s.iterator();
//通过循环获取键值对
while(it.hasNext())
{
String s1=it.next();
String s2=map.get(s1);
System.out.println(s1+"="+s2);
}
}
}
方法二:
先获取Map集合中的映射关系,再通过其映射关系获取,键值对
Set<Map.Entry<String,String>> s=map.entrySet(); //通过entrySet()方法获取map集合中的映射关系,就像获取到结婚证书,返回类型是Set<Map.Entry<String,String>>
Map.Entry<String,String>是结婚证书,里面存放的是男人和女人.
然后通过Set的迭代器,遍历得到键值对
Iterator<Map.Entry<String,String>> it=s.iterator();
while(it.hasNext())
{
Map.Entry<String,String> me=it.next();
me.getKey();
me.getValue();
}
原理:
interface Map //Map接口
{
public static interface Enter //内部接口
{
public int getKey();
public String getValue();
}
}
HashMap复写Map集合:
class HashMap implements Map //实现Map接口
{
class Hashs implements Map.Entry //实现Entry接口
public static interface Enter
{
public int getKey();
public String getValue();
}
}
/*
需求:把学生和其所属户籍存到HashMap集合中
因为学生不唯一的,户籍可以相同,所以在HashMap中以学生为键,户籍为值
学生类中,姓名和年龄相同视为一个学生
*/
import java.util.*;
class Student implements Comparable<Student>//实现Comparable比较器
{
private String name;
private int age;
Student(String name,int age) //构造函数
{
this.name=name;
this.age=age;
}
public void setName(String name) //设置名字
{
this.name=name;
}
public String getName() //获取获取名字
{
return name;
}
public void setAge(int age)//设置年龄
{
this.age=age;
}
public int getAge()//获取年龄
{
return age;
}
public int compareTo(Student obj) //覆盖compareTo方法
{
if(!(obj instanceof Student))
throw new RuntimeException();
Student s=(Student)obj;
int num=new Integer(this.age).compareTo(new Integer(s.age));
if(num==0)
return this.name.compareTo(s.name);
return num;
}
public int hashCode() //覆盖hashCode方法
{
return name.hashCode()+age*6;
}
public boolean equals(Student obj) //覆盖equals方法
{
if(!(obj instanceof Student))
return false;
Student s=(Student)obj;
return this.name.equals(s.name)&&this.age==s.age;
}
public String toString()
{
return name+":"+age;
}
}
class HashMapStudent
{
public static void main(String[] args)
{
//创建一个容器
HashMap<Student,String> hs=new HashMap<Student,String>();
hs.put(new Student("zhangsan",11),"guangzhou01");
hs.put(new Student("zhangsan",12),"guangzhou02");
hs.put(new Student("zhangsan",13),"guangzhou03");
hs.put(new Student("zhangsan",14),"guangzhou04");
hs.put(new Student("zhangsan",15),"guangzhou05");
//得到映射关系
Set<Map.Entry<Student,String>> s=hs.entrySet();
//得到迭代器
Iterator<Map.Entry<Student,String>> it=s.iterator();
//循环输出每一个键值对
while(it.hasNext())
{
Map.Entry<Student,String> me=it.next();
System.out.println(me.getKey()+"="+me.getValue());
}
/*
Set<Student> s=hs.keySet();
Iterator<Student> it=s.iterator();
while(it.hasNext())
{
Student s1=it.next();
String s2=hs.get(s1);
System.out.println(s1+"="+s2);
}
*/
}
}
3 注意类comparable<? super E>表示传入E或者E的父类都行,当第二个student对象进来之后这个对象就调用compareTo()方法,把另外一个Student传到该方法中,进行比较,如果Student implements Comparable<Person>,Student自身就具备了比较性,传进来的是Student,但是实现的时候规定传的是Person对象,所以Student对象会自动提升为Person对象,然后再进行比较,因为Student拥有父类的东西,所以comparable<? super E>可以传入自己或者自己的父类
4 如果Student覆盖了Object的String()方法,那么对象打印的是toString()里面的东西,这里返回的是return name"+"age;
public String toString()
{
return name"+"age;
}
5 TreeMap能够排序,而HashMap不能排序