---------------------- android培训、java培训、期待与您交流! ----------------------
抓紧整理完睡觉吧,脑瓜子有点发蒙的感觉。
集合
1.0 集合特点:
1.1 Object
1.2 集合框架的工具类
1.3 泛型
1.4 集合使用技巧
1.5 foreach
集合练习
下边的挨个介绍一下吧:
集合
集合类的由来:对象用于封装特有数据,对象多了就需要存储,如果对象的个数不确定,就使用集合容器进行存储。
1.0 集合特点:
存储对象,长度可变.可进行增删改查
1.1 Object
|----- Collection接口
1.方法:
添加
boolean add(Object obj);
boolean addAll(Collection coll)
删除
boolean remove(Object obj); 集合的remove会改变集合的长度。
boolean removeAll(Collection coll); 将两个集合中的相同元素从调用removeAll的集合中删除。
void clear();
判断
boolean contains(Object obj);
boolwan containsAll(Collection coll); 是否包含另外一个集合里面所有的元素。
boolean isEmpty();判断集合中是否有元素。
获取
int size();
Iterator iterator();取出元素的方式:迭代器
迭代器: 对象必须依赖于具体的容器,因为每个容器的数据结构都不同。所以该迭代器对象是在容器中进行内部实现的。
对于使用容器者而言,具体的实现不重要,只要通过容器获取到该实现的迭代器的对象即可,也就是iterator方法。
Iterator接口就是对所有的Collection容器进行元素去除的公共接口。
使用Collcetion中的iterator()方法。调用集合中的迭代器方法,是为了获取集合中的迭代器对象。
其他
boolean retainAll(Collection coll); 取交集。与removeAll相反,保留和指定集合相同的元素,而删除不同的元素
Object [ ] toArray(); 将集合转成数组。
|-----------List
有序(存入和取出的顺序一致),元素都有索引(角标),元素可以重复。具有增删改查
特有常见方法:有一个共性特点就是都可以操作角标。
添加
void add( index,element)
void add(index,collection);
删除
Object remove(index);
修改
Object set(index,element);
获取:
Object get(index) //List特有的取出方式之一。
int indexOf(object)
int laseIndexOf(object)
List subList(from,to)//包含头,不包含尾
List特有的取出方式代码:
for(int x = 0;x
System.out.println(list.get(x));
}
List集合是可以完成对元素的增删改查。
|----------------Arraylist
内部是数据数据结构,是不同步的。替代了Vector。查找元素的速度很快
练习:
练习:用ArrayList删除里面重复的元素。
importjava.util.ArrayList;
importjava.util.Iterator;
public class ArrayListTest2 {
public static void main(String[] args) {
ArrayList a1 = newArrayList();
a1.add("abc1");
a1.add("abc2");
a1.add("abc3");
a1.add("abc4");
a1.add("abc5");
a1.add("abc2");
a1.add("abc3");
a1 = getSingleElement(a1);
Iterator it = a1.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
public static ArrayList getSingleElement(ArrayList a1) {
ArrayList temp = newArrayList();
Iterator it = a1.iterator();
while(it.hasNext()){
Object obj = it.next();
if(!temp.contains(obj)){
temp.add(obj);
}
}
return temp;
}
}
练习二:需求:同姓名同年龄视为同一个人,视为重复元素。去除同一元素。
Person类中的equals方法继承Object,判断相同的依据是Person对象的地址值。
为了按照指定的条件来判断Person对象是否相同,必须覆盖equals方法。
public class Person {
private Stringname;
private int age;
public Person() {
super();
}
public Person(String name,int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
returnname;
}
@Override
public boolean equals(Object obj) {//因为所有的类都继承了Object的equals方法,所以要进行向下转型
//记住要加健壮性的判断,如果传的不是Person直接让程序挂掉
if(!(objinstanceof Person))
throw new ClassCastException("类型错误");
Person p = (Person)obj;
return this.name.equals(p.name) &&this.age==p.age;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
returnage;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {//覆盖toString方法是为了让集合迭代器打印的不是对象的哈希值(地址值)。
return"Person :"+name+" "+age;
}
}
importjava.util.ArrayList;
importjava.util.Iterator;
importbeen.Person;
public class ArrayListTest {
/**
* @param args
*/
public static void main(String[] args) {
ArrayList a = newArrayList();
a.add(new Person("lisi1",21));
a.add(new Person("lisi2",22));
a.add(new Person("lisi3",23));
a.add(new Person("lisi4",24));
a.add(new Person("lisi3",23));
a.add(new Person("lisi4",24));
a = getSingleElement(a);
Iterator it = a.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
public static ArrayList getSingleElement(ArrayList a) {
//定义一个临时的集合容器
ArrayList temp = newArrayList();
Iterator it = a.iterator();
while(it.hasNext()){
//取出的元素都是对象
Object obj = it.next();
//进行判断,如果临时的集合容器有这个元素对象,就不进行存储
//没有的话就进行存储。
if(!temp.contains(obj))
temp.add(obj);
}
//返回这个临时集合容器
return temp;
}
}
注意:
ArrayList:当自定义对象进行取出时,一定要先进行向下转型。
ArrayList:判断里面元素是否相同,用的是对象所属的equals方法来判断是否包含。
remove和contains方法其实都是依赖于对象的equals方法来判断是否相同,相同即包含。
|----------------Linkedlist
内部是链表数据结构,是不同步的。增删元素的速度很快。
常见方法:
addFirst();
addLast();
JDK1.6
offerFirst();
offetLast();
getFirst();获取但不移除,如果链表为空,抛出NoSuchElementException.
getLast();
JDK1.6
peekFirst();获取但不移除,如果链表为空,返回null
peekLastt();
removeFirst();//获取并移除,如果链表为空,抛出NoSuchElementException
removeLast();
JDK1.6
pollFirst();//获取并移除,如果链表为空,返回null。
pollLast();
面试题:
请使用用LinkedList,来模拟一个对战或者队列数据结构。
堆栈:先进后出。 First In Last out FIFO
队列:先进先出。 First In First Out FIFO
应该描述这样一个容器,给使用提供一个容器对象完成者两种结构中的一种。
堆栈表现形式:
packageit.cast_01;
importjava.util.LinkedList;
public class DuiLie {
private LinkedList link;
public DuiLie(){
link = newLinkedList();
}
public void myAdd(Object obj){
link.add(obj);
}
public Object myGet(){
returnlink.removeLast();//如果要改成队列,link.removeFirst()
}
public boolean isNull(){
returnlink.isEmpty();
}
}
packageit.cast_01;
public class DuiLieZhanDemo {
/**
* @param args
*/
public static void main(String[] args) {
DuiLie d = new DuiLie();
d.myAdd("haha");
d.myAdd("hehe");
d.myAdd("xixi");
d.myAdd("hiahia");
while(!d.isNull()){
System.out.println(d.myGet());
}
}
}
|----------------Vector
内部是数组数据结构,是同步的。增删,查询都很慢!
Enumeration接口
此接口的功能与Iterator接口的功能是重复的,Iterator接口添加了一个可选的移除操作,并使用较短的方法名。
扩展:Arraylists和linkedlist区别:
因为Arraylist是数组结构可以通过角标操作集合里面的元素,但是linkedlist是链表结构只能操作头和尾上的元素。但是有人会问?List集合不是有序的吗?此时的有序是想相对于存入
和取出是一致的。怎样放就怎样取,ArrayList是连续的空间,而linkedlist是不连续的空间。
依角标查询是依然一个一个的向下询问。
|-----------Set
元素不可以重复,是无序。
set集合的底层就是map集合
|----------------TreeSet
TreeSet:是二叉树结构其实就是二分查找,对已有的有序元素进行折半,再确定新元素的位置。二叉树其实就是看的返回值,对象比较的大小。
二叉树结构示意图:
如果要按照怎么存入就怎么取出元素,上图可以看出,比顶层大的元素都在右边,只要在比较器里面的compare里面返回1就行。二叉树具体是看对象比较的返回值。
示例代码:
importjava.util.Comparator;
public class ComparatorByName implementsComparator {
/**
* 创建了一个根据Person类的name进行排序的比较器
*/
@Override
public int compare(Object o1, Object o2) {
Person p1 = (Person)o1;
Person p2 = (Person)o2;
/* int temp = p1.getName().compareTo(p2.getName());
return temp==0?p1.getAge()-p2.getAge():temp;*/
return 1;
}
|----------------hashSet
|-----Map集合
Map:一次添加一对元素。Collection一次添加一个元素。
Map也称为双列集合,Collection集合称为单列集合。
其实Map集合中存储的就是键值对。
Map集合中必须保证键的唯一性。
Map常用方法:
添加
value put(key,value); 返回前一个和key关联的值,如果没有返回null
删除
void clear(); 清空map集合
value remove(key); 根据指定的key删除这个键值对
判断
boolean containsKey(key);
boolean containsVaule(value);
boolean isEmpty();
获取
value get(key); 通过键获取值,如果没有该键返回null。
当然可以通过返回null,来判断是否包含指定键。
int size(); 获取键值对的个数。
|---------Hashmap
底层数据结构是哈希表,线程不同步,可以存入null键值。要保证键的唯一性,需要覆盖hashCode()方法和equals()方法
|----------LinkedHashMap
该子类基于哈希表又融入链表,可以使map集合增删时提高效率,
怎么存入就怎么取出元素
|---------Hashtable
底层结构是哈希表数据结构,线程是同步,不可以存入null键值对。效率较低,被hashmap锁替代
|-----------Properties
用来存储键值对型的配置文件的信息,可以和IO技术相结合
|---------Treemap
底层是二叉树结构,可以对map集合中的键进行排序。需要使用comparable或者comparator进行排序。
思考:
如果有映射关系应该最先想到数组,然后在思考这个映射关系是否是有序的,如果没有序的话就应该考虑到Map集合,因为Map集合存储的是键值对,映射关系是不需要有序的
1.2 集合框架的工具类
该类中的方法都是静态的。
|-------Arrays
List asList(数组)将数组转成集合
如果数组中的元素是对象,那么转成集合时,直接将数组中的元素作为集合中的元素进行集合存储。
如果数组中的元素是基本类型数值,那么会将该数组作为集合中的元素进行存储。
将数组转成集合!
好处:可以使用集合中非方法操作数组中的元素
注意:数组的长度是固定的,所以对于集合的增删方法是不可以使用的
否则会发生UnsupportedOperationException
如果数组中的元素是对象,那么转成集合时,直接将数组中的元素作为集合中的元素进行集合存储
如果数组中的元素是基本数据类型数值,那么就会将该数组作为集合中的元素进行存储
|-------Collections
reverseOrder() 获取一个比较器,用于反转集合中的内容
reverse(List> list) 反转
fill(List,T obj) 将集合中的元素一次性全部替换
shuffle(list); 随机把这些元素安放在任意位置上
给非同步的集合加锁 synchronizedList(List list)
使用的就是Collection借口中的toArray方法。
集合转成数组:可以对集合中的元素操作的方法进行限定。不允许对其进行增删。
toArray方法需要传入一个指定类型的数组。
长度该如何定义呢?
如果长度小于集合的size,那么该方法会创建一个同类型并和集合相同的size的数组。
如果长度大于集合的size,那么该方法就会使用指定的数组,存储集合中的元素,其他位置默认为null。
所以建议,最后长度就指定为集合的长度size()
1.3 泛型
泛型<>什么时候用:
当操作的引用数据类型不确定的时候,就使用<>泛型,将要操作的引用数据类型传入即可。其实<>就是一个用于接收具体引用数据类型的参数范围。
在程序中,只要用到了带有<>的类或者接口,就要明确传入的具体引用数据类型。
将泛型定义在方法上:public
void show(W str) 当方法静态时,不能访问类上定义的泛型,如果静态方法使用泛型,只能将泛型定义在方法上。如:public static
void show(Y obj); 注意:泛型必须放在修饰符后面返回值的前面。
泛型接口,将泛型定义在接口上。
示例代码:
public class GenericDemo2 {
/**
* @param args
*/
public static void main(String[] args) {
Imple1 in1 = new Imple1();
in1.show("haha");
Imple2
in2 = new Imple2 (); in2.show(new Integer(5));
}
}
interfaceInter
{ public void show(T t);
}
class Imple1 implements Inter
{ public void show(String str){
System.out.println("show "+str);
}
}
//如果实现接口也不知道传什么类型的话就自定义
classImple2
implements Inter{public void show(Q q){
System.out.println("show "+q);
}
}
泛型的擦除于补偿:(作为了解)
注意细节:
泛型技术是给编译器使用的技术,用于编译时期,确保了类型的安全。
运行时,会将泛型去掉,生成的class文件中是不带泛型的,这个称为泛型的擦除。
为什么擦除呢?因为为了兼容运行的类的加载器。
泛型的补偿:在运行时,通过获取元素的类型进行转换动作。不用使用者再强制转换了。
泛型的通配符:
泛型的通配符:?未知类型。
示例代码:
importjava.util.ArrayList;
importjava.util.Collection;
importjava.util.HashSet;
importjava.util.Iterator;
public class GenericDemo3 {
/**
* @param args
*/
public static void main(String[] args) {
ArrayList
al1 = new ArrayList (); al1.add("haha");
al1.add("xixi");
HashSet
hs = new HashSet (); hs.add(new Integer(5));
hs.add(new Integer(6));
printCollection(al1);
printCollection(hs);
}
public static void printCollection(Collection> al1) {
//如果打印的集合多,直接用父类的接口大集合作为参数类型
//如果打印的多个集合的类型不同,可以用通配符?的形式来表示
Iterator> it = al1.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
泛型类型限定:
可以对类型进行限定:? extends E :接收E类型或者E的子类型对象。叫上限。
? super E: 接收E类型或者E的父类型。 叫下限。
上限示例代码:
importjava.util.ArrayList;
importjava.util.Collection;
importjava.util.Iterator;
import bean.Person;
importbean.Student;
importbean.Worker;
public class GenericDemo4 {
public static void main(String[] args) {
ArrayList
al1 = new ArrayList (); al1.add(new Worker("工人2",20));
al1.add(new Worker("工人4",40));
ArrayList
al2 = new ArrayList (); al2.add(new Student("小明1",20));
al2.add(new Student("小四4",24));
printCollection(al1);
printCollection(al2);
}
public static void printCollection(Collection extends Person> al1) {
Iterator extends Person> it = al1.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
什么时候使用上限呢?
一般在存储元素的时候都使用上限,因为这样取出都是按照上限类型来运算的,不会出现类型安全隐患。
注意:迭代器的泛型百分之百和获取迭代器对象集合的泛型一致。
什么时候使用下限?
通常对集合中的元素进行取出操作时,可以使用下限。
下限代码示例:
importjava.util.ArrayList;
importjava.util.Collection;
import java.util.Iterator;
importbean.Person;
importbean.Student;
importbean.Worker;
public class GenericDemo5 {
/**
* @param args
*/
public static void main(String[] args) {
ArrayList
al1 = new ArrayList (); al1.add(new Worker("工人1",10));
al1.add(new Worker("工人3",30));
ArrayList
al2 = new ArrayList (); al2.add(new Student("小明1",20));
al2.add(new Student("小明4",30));
ArrayList
p2 = new ArrayList (); p2.add(new Person("人民1",40));
p2.add(new Person("人民2",59));
printCollection(al1);
printCollection(p2);
// printCollection(al2);
}
public static void printCollection(Collection super Worker> al1) {
Iterator super Worker> it = al1.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
1.4 集合使用技巧
集合查阅的一些技巧:
需要唯一吗?
需要:Set
需要制定顺序:
需要:TreeSet
不需要:HashSet
但是想要一个和存储一致的顺序(有序):LinkedHashSet
不需要:List
需要频繁增删吗?
需要:LinkedList
不需要:ArrayList
如何记录每一个容器的结构和所属体系呢?
看名字!
List
|----ArrayList
|----LinkedList
Set
|----HashSet
|----TreeSet
后缀名就是该集合的所属的体系。
前缀名就是该集合的数据结构。
看到array:就要想到数组,就要想到查询快,有角标。
看到link:就要想到链表,就要像到增删快,就要想到 add get remove+first last 的方法
看到hash:就要想到哈希表,就要想到唯一性,就要想到元素需要覆盖hashcode方法和equals方法。
看到tree:就要想到二叉树,就要想到排序,就要想到两个接口Comparable,Comparator。
而且通常这些常用的集合容器都是不同步的。
1.5 foreach
foreach语句:
格式: for(类型 变量:Collection集合|数组)
{
}
传统for和高级for的区别?
传统for可以完成对语句执行很多次,因为可以定义控制循环的增量和条件。
高级for是一种简化形式。
它必须有被便利的目标。该目标要么是数组,要么是Collection单列集合。
对于数组的遍历如果仅仅是获取数组中的元素,可以使用高级for。
如果要对数组的角标进行操作,建议使用传统for。
可以使用高级for遍历Map集合吗?
不能直接用,但是可以将Map转成单列的Set集合,就可以用了。
函数的可变参数。
其实就是一个数组,但是收的是数组的元素。
自动将这些元素封装成数组。简化了调用者的书写。
注意:可变参数类型,必须定义在参数列表的结尾。
集合练习
练习需求:
* "fdgavcbsacdfs" 获取该字符串中,每一个字母出现的次数。
* 要求打印结果是:a(2)b(1)...;
importjava.util.Iterator;
importjava.util.Map;
importjava.util.TreeMap;
/*
* 练习
* "fdgavcbsacdfs" 获取该字符串中,每一个字母出现的次数。
* 要求打印结果是:a(2)b(1)...;
* 思路:
* 对于结果的分析发现,字母和次数之间存在着映射关系。而且这种关系很多。
* 很多就需要存储,能存储映射关系的容器有数组和Map集合。
* 关系一方式中是有序编号吗?有就使用数组,没有!那就是使用Map集合。
* 又发现可以保证唯一性的一方具备着顺序如a b c.....
* 所以可以使用TreeMap集合。
*
* 这个集合中应该存储的是字母和次数的对应关系。
*
* 1,因为操作的是字符串中的字母,所以先将字符串变成一个字符数组。
* 2,遍历字符数组,用每一个字母作为键去查Map集合这个表。
* 如果该字母键不存在,就将该字母作为键1作为值存储到Map集合中,代表出现一次。
* 如果该字母键存在,就将该字母键对应值取出并自增,再将该字母和自增后的值存储到Map集合中,
* 键相同值会覆盖,这样就记录住了该字母的次数。
* 3,遍历结束,Map集合就记录所有字母的出现的次数。
*/
public class MapTest1 {
/**
* @param args
*/
public static void main(String[] args) {
String s = "fdgavcbsacdfs";
String str = getCharCount(s);
System.out.println(str);
}
public static String getCharCount(String s) {
//将字符串变成数组
char [] ch = s.toCharArray();
//建立Map集合,通过循环来记录住出现的字符和次数来对Map集合查表,没有出现的字符就存储,出现的字符就继续自增value值
//看输出的结果是有序的打印,因此可以用TreeMap来完成
Map
map = new TreeMap (); for (int i = 0; i < ch.length; i++) {
Integer value = map.get(ch[i]);
if(value==null){
map.put(ch[i], 1);
}
else
map.put(ch[i], value+1);
}
return mapToString(map);
}
private static String mapToString(Map
map) { StringBuilder sb = new StringBuilder();
Iterator
it = map.keySet().iterator(); while(it.hasNext()){
Character key = it.next();
Integer value = map.get(key);
sb.append(key+"("+value+")");
}
return sb.toString();
}
}
练习:
将"asjd+ 5568a sd SAAA Aas77dfffwe"字母出现的次数打印出来
要求打印结果是:a(2)b(1)...;
importjava.util.Iterator;
importjava.util.Map;
importjava.util.TreeMap;
public class MapTest3 {
/*
* 需求:
* "asjd 5568a sd SAAA Aas77dfffwe"获取该字符串中,每一个字母出现的次数
* 要求打印结果是:a(2)b(1)...;
*/
/**
* @param args
*/
public static void main(String[] args) {
String str = "asjd+ 5568a sd SAAA Aas77dfffwe";
String s = getCharCount(str);
System.out.println(s);
}
public static String getCharCount(String str) {
//将字符串变成数组
char [] chs = str.toCharArray();
//建立以个Map集合,通过循环来查询Map集合表。
Map
map = new TreeMap (); for (int i = 0; i < chs.length; i++) {
//判断一下,如果不大于或等于里面里面的字符就不打印,排除了里面的符号和空格
if(!(chs[i]>='a' && chs[i]<='z' || chs[i]>='A' && chs[i]<='Z'))
continue;
Integer value = map.get(chs[i]);
if(value==null){
map.put(chs[i],1);
}else{
map.put(chs[i], value+1);
}
}
return mapToString(map);
}
private static String mapToString(Map
map) { StringBuilder sb = new StringBuilder();
Iterator
it = map.keySet().iterator(); while(it.hasNext()){
Character key = it.next();
Integer value = map.get(key);
sb.append(key+"("+value+")");
}
return sb.toString();
}
}
---------------------- android培训、java培训、期待与您交流! ----------------------