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

黑马程序员-----笔记整理(java基础十----集合)

2012-05-24 08:46 459 查看
---------------------- 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<list.size();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 <W> void show(W str)

当方法静态时,不能访问类上定义的泛型,如果静态方法使用泛型,只能将泛型定义在方法上。如:public static<Y> void show(Y obj);

注意:泛型必须放在修饰符后面返回值的前面。

泛型接口,将泛型定义在接口上。

示例代码:

public class GenericDemo2 {

/**
* @param args
*/
public static void main(String[] args) {
Imple1 in1 = new Imple1();
in1.show("haha");
Imple2<Integer> in2 = new Imple2<Integer>();
in2.show(new Integer(5));
}

}
interfaceInter<T>{
public void show(T t);
}

class Imple1 implements Inter<String>{
public void show(String str){
System.out.println("show "+str);
}
}
//如果实现接口也不知道传什么类型的话就自定义
classImple2<Q> implements Inter<Q>{
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<String> al1 = new ArrayList<String>();
al1.add("haha");
al1.add("xixi");
HashSet<Integer> hs = new HashSet<Integer>();
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<Worker> al1 = new ArrayList<Worker>();
al1.add(new Worker("工人2",20));
al1.add(new Worker("工人4",40));
ArrayList<Student> al2 = new ArrayList<Student>();
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<Worker> al1 = new ArrayList<Worker>();
al1.add(new Worker("工人1",10));
al1.add(new Worker("工人3",30));
ArrayList<Student> al2 = new ArrayList<Student>();
al2.add(new Student("小明1",20));
al2.add(new Student("小明4",30));
ArrayList<Person> p2 = new ArrayList<Person>();
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<Character,Integer> map = new TreeMap<Character,Integer>();
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<Character, Integer> map) {
StringBuilder sb = new StringBuilder();
Iterator<Character> 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<Character,Integer> map = new TreeMap<Character,Integer>();
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<Character, Integer> map) {
StringBuilder sb = new StringBuilder();
Iterator<Character> 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培训、期待与您交流! ----------------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: