JAVASE之集合框架



集合:Collection

属于java.util包
数据多了封装成为对象,对象多了就存储到集合
数组和集合的区别,数组的长度不变,存储的类型单一
而集合的长度是可变的,可以存储不同类型的对象。


先看顶层的框架,具体使用就再往下看。


Collection两个常见的子接口,list ,set。
|--list常见的有ArrayList,LinkedList,Vector


|--Set里面常见的有HashSet,TreeSet.


每一个容器的存储方式不一样,这也叫作 数据结构。

容器中常见的共性方法,增,删,改,查。
add(E e),clear(),remove(Object obj).


集合中存放的不是对象实体,和数组一样,都是存放的是对象的地址值。






package com.Collection;
import java.util.*;
public class DemoCollection
{
public void collectionDemo()
{
//定义ArrayList集合
ArrayList al = new ArrayList();
ArrayList al2 = new ArrayList();

//向集合里面增加元素
al2.add("c++");
al2.add("c");
al.add("java01");
al.add("c");
al.add("c++");
al.add("php");
al.add(".net");
al.add("c#");
//打印原集合
sop(al);
//打印集合的长度
sop(al.size());
//删除集合中指定的元素
al.remove(0);
//打印删除后的集合内容
sop(al);
//看看集合是否为空
sop(al.isEmpty());
//清空元素。
// al.clear();
sop(al.size());
//al是否全部包含al2
sop(al.containsAll(al2));
//求两个集合的交集
// sop(al.retainAll(al2));
sop(al);

}
public <T>void sop(T t)
{
System.out.println(t);
}
public static void main(String[] args)
{
new DemoCollection().collectionDemo();
}


}
sop(al)只是把集合打印出来,并没有取出来。所以,要想另外的办法把集合取出来。
--------------------------------------------------------------------------------


Iterator是一个接口,也叫迭代器。专门用于取出集合中的元素。
也就是取出对象,集合中的元素也叫对象。
有三个方法。hasNext(),next(),remove();
Iterator 类似于游戏厅中夹玩具夹子。


迭代器是通过方法调用迭代出来的,不是直接创建对象。




------------------------------------------------------------------------------------------
|--Collection 
|--List集合:元素是有序的,元素可以重复,因为该集合体系中有索引
|--ArrayList:底层使用数组结构,特点在于查询修改快,
增删稍慢,当元素越多时,越能体现增删慢。不同步。


|--LinkedList:底层使用的是链表结构。


|--Vector:底层也是数组数据结构,与ArrayList功能一样。
版本早期出现的,Vector是同步的。增删查询都慢。被ArrayList替代了。
枚举就是Vector的特有取出方式。发现枚举和迭代器很像。




|--set集合:元素是无序,元素不可以重复。


list集合有索引,所以,操作与索引相关的方法比较多。
基本上有角标的方法可以说是list集合中特有的方法
list集合中特有的方法,
增:add(index,element),addAll(index,Collection)
删:remove(index);
改:set(index,element);
查:get(index),subList(from,to),listIterator();


列表迭代器,ListIterator是List集合中特有的迭代器,是迭代器Iterator的子接口


package com.Collection;
import java.util.*;
public class DemoList
{
public void listMethod()
{ //list集合中特有的方法
ArrayList al = new ArrayList();
// 向集合中增加元素
al.add("java");
al.add("c++");
al.add(new Object());
al.add(new Integer(313));
//打印集合
sop("原集合::"+al);
//增,向集合中指定位置增加元素
al.add(0,new Integer(520));
System.out.println("增加元素后的集合"+al);
//删,删除指定位置的元素。
al.remove(al.size()-1);
System.out.println("删除元素后的集合"+al);
//改,修改特定位置的元素。
al.set(0, "940");
System.out.println("修改元素后的集合"+al);
//查,获取所有或者特定位置的元素。
for(int x=0; x<al.size(); x++)
{
sop("al"+"("+x+")"+al.get(x));
}
//迭代器获取元素的方法
for(Iterator it=al.iterator(); it.hasNext();)
{
sop("next::"+it.next());
}
}

//列表迭代器
public void listIteratorDemo()
{
ArrayList al = new ArrayList();
//增加元素。
al.add("java");
al.add("c++");
al.add(".net");
al.add("php");
sop("原集合:::"+al);
//需要就是在迭代过程中可以操作元素,比如增加或者删除元素。ListIterator
for(ListIterator it = al.listIterator(); it.hasNext();)
{
Object obj = it.next();
if(obj.equals("c++"))
it.add("c");
if(obj.equals("php"))
it.set("app");
}
sop("处理后的集合::"+al);

}
//演示Vector
public void vectorDemo()
{
Vector v = new Vector();
//增加元素。
v.add("java");
v.add("c");
v.add("c++");
v.add("php");

//枚举
for(Enumeration en = v.elements(); en.hasMoreElements();)
{
sop(en.nextElement());
}


}
public <T>void sop(T t)
{
System.out.println(t);
}
public static void main(String[] args)
{
new DemoList().vectorDemo();
// new DemoList().listIteratorDemo();
// new DemoList().listMethod();
}


}


----------------------------------------------------------------------------------------------
LinkedList集合,底层是链表结构。


/*
 linkedList方法演示
 */


package com.Collection;
import java.util.*;
public class LinkedListDemo
{
//LinkedList特有传统方法
public void linkedListMethod()
{
LinkedList ll = new LinkedList();
//JDK1.6版本以前的方法
//增加元素。
ll.addFirst("java");
ll.addFirst("new Integer(45)");
ll.addFirst(new Integer(32));
ll.addFirst(new Object());
ll.addLast(new String("c++"));
sop("原始集合::"+ll);
//获取元素
sop(ll.getFirst());
sop(ll.getFirst());
sop(ll.getLast());
sop(ll.getLast());


//删除元素
ll.removeFirst();
ll.removeLast();

//不使用迭代器取出元素。
for(;!ll.isEmpty();)
{
sop(ll.removeFirst());
}

}
//JDK1.6以后的替代方法
public void newMethod()
{
LinkedList ll = new LinkedList();
//增加元素。
ll.offerFirst("java01");
ll.offerFirst("java02");

//获取元素
sop(ll.peekFirst());
sop(ll.peekFirst());

//获取并删除元素。
// ll.pollFirst();
// ll.pollFirst();

//迭代元素。
for(ListIterator it = ll.listIterator(); it.hasNext();)
{
sop(it.next());
}

}
public <T>void sop(T t)
{
System.out.println(t);
}
public static void main(String[] args)
{
new LinkedListDemo().newMethod();
// new LinkedListDemo().linkedListMethod();
}


}




在迭代循环中,不要同时使用两次it.next();
如果是偶数没有问题,但如果是奇数就会出异常,
因为next()调用一次,hasNext()就要判断一次


List集合元素是否相同,依据是元素的equals()方法。


在集合中增删操作比较多可以选用LinkedList
如果查询比较多可以选用ArrayList,
一般情况下查询比较多,所以,ArrayList是最常用的。


----------------------------------------------------------------------------------------


set集合的特点:元素无序(存入和取出的顺序不一定一致),元素不可以重复,
set集合的功能和colletion一致。
常见子类:HashSet和TreeSet。
|--HashSet:底层数据结构是哈希表,线程是非同步的。
HashSet保证元素的唯一性的依据,是通过元素的两个方法,hashCode和
equals来完成,如果元素的HashCode值相同,才会判断equals是否为true.
如果元素的hashCode值不同,不会调用eqauls。
所以,通常在建立对象的时候通常要覆写hashcode和equals。

对于判断元素是否存在,以及删除元素的操作,依赖的方法是元素的hashcode和equals方法。
而ArrayList只依赖于equals。


哈希表是存放了一些哈希值的表。

Demo@c17164
Demo@1fb8ee3


/*
 向hashset里面存入自定义对象
 需求:当姓名和年龄相同时,视为同一个人,。去除重复元素。
 */
package com.Collection;
import java.util.*;
public class DemoHashSet
{
public static void main(String[] args)
{
HashSet hs = new HashSet();
hs.add(new Person2("abc",23));
hs.add(new Person2("abc2",24));
hs.add(new Person2("abc3",25));
// hs.add(new Person2("abc3",25));

//判断元素是否存在
System.out.println(hs.contains(new Person2("abc",23)));
hs.remove(new Person2("abc",23));

//取出元素
for(Iterator it=hs.iterator(); it.hasNext();)
{
Person2 p = (Person2)it.next();
System.out.println("name:"+p.getName()+";age:"+p.getAge());
}
}


}
class Person2
{
private String name;
private int age;
Person2(String name,int age)
{
this.name=name;
this.age=age;
}
//覆盖Object里面的方法hashcode和equals
public int hashCode()
{
//为了看清楚hashcode的底层是如何调用的,可以在这里写在这么一句话,
System.out.println(this.name+"...hashcode...");
//为了保证哈希值的唯一性,尽量使哈希值不一样,
//尽量不要调用equals方法,以此来提高效率
return name.hashCode()+age*23;
}
public boolean equals(Object obj)
{
if(!(obj instanceof Person2))
return false;
Person2 p = (Person2)obj;
System.out.println(this.name+"...equals..."+this.age );
return this.name.equals(p.name)&&this.age==p.age;
}
//getname与getage
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}




-------------------------------------------------------------------------------------


|--TreeSet:底层是二叉树数据结构,也叫红叉树,
保证元素唯一性的依据是compareTo 方法 return 0;
当元素很多的时候会取折中值。
默认取出顺序就是从小到大取,也叫从左到右取。
左边的数比上面的数。上面的比下面的数大,取出的时候,是从左往右取。
可以对Set集合中的元素进行字母的自然顺序排序。


TreeSet排序的第一种方式:
让元素自身具备比较性,元素需要实现Comparable接口,覆盖
compareTo方法,这种方式称为元素的自然顺序,或者叫做默认顺序。


TreeSet排序的第二种方式:
当元素自身不具备比较性时,或者具备的比较性不是所需要的,
这时就要让集合自身具备比较性,在集合初始化时,就有了比较方式。
也就是TreeSet的构造方法。




当compareTo(Object obj){}方法返回1的时候,存入与取出的顺序是一样。
这是因为返回1表示比较的元素大于本身,所以都往右存入,而取出时则按照默认的
顺序从左往右取。如果返回-1则是倒序,返回0则只能存入一个元素。




/*
 把自定义的工人对象存入TreeSet集合中。
 需求:按照工人的年龄进行排序,如果年龄相同则按照名字排序
 */
package com.Collection;
import java.util.*;
public class DemoTreeSet
{

public static void main(String[] args)
{
TreeSet ts = new TreeSet();
//存入元素
ts.add(new Worker("woker1",21));
ts.add(new Worker("woker2",21));
ts.add(new Worker("woker3",31));
ts.add(new Worker("woker4",41));


//取出元素
for(Iterator it=ts.iterator(); it.hasNext();)
{
Worker w = (Worker)it.next();
System.out.println("name:"+w.getName()+";age:"+w.getAge());
}
}


}
class Worker implements Comparable
{
private String name;
private int age;
Worker(String name,int age)
{
this.name=name;
this.age=age;
}

public int compareTo(Object obj)
{
if(!(obj instanceof Worker))
throw new RuntimeException("不是工人对象");
Worker w = (Worker)obj;
if(this.age-w.age==0)
return this.name.compareTo(w.name);
else
return this.age-w.age;

}
//覆盖hashcode和equals
public int hashCode()
{
return name.hashCode()+age*21;
}

public boolean equals(Object obj)
{
if(!(obj instanceof Worker))
throw new RuntimeException("不是Worker对象");
Worker w = (Worker)obj;
return this.name==w.name&&this.age==w.age;
}

//getName and getAge
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}






----------------------------------------------------------------------------


/*
 当元素自身没有比较性,或者是元素的比较性不适用的时候,
 可以使集合具备比较性,让元素按照集合的比较性进行比较。
 */
package com.Collection;
import java.util.*;
public class DemoTreeSetComparetor
{


public static void main(String[] args)
{
TreeSet ts = new TreeSet(new myComparator());

//增加元素
ts.add(new Dog("dog1",21));
ts.add(new Dog("dog2",11));
ts.add(new Dog("dog4",31));
ts.add(new Dog("dog3",421));
ts.add(new Dog("dog2",21));

//取出元素
for(Iterator it=ts.iterator(); it.hasNext();)
{
Dog d = (Dog)it.next();
System.out.println("name:"+d.getName()+";age:"+d.getAge());
}
}


}
//定义一个Dog类
class Dog
{
private String name;
private int age;
Dog(String name,int age)
{
this.name=name;
this.age=age;
}
//set and get method
public String getName()
{
return name;
}

public int getAge()
{
return age;
}
}


//做一个自己的比较器
class myComparator implements Comparator
{
//覆盖Comparator里面的compare方法
public int compare(Object obj1, Object obj2)
{
if(!(obj1 instanceof Dog && obj2 instanceof Dog))
throw new RuntimeException("不是这个类异常");
Dog d1 = (Dog)obj1;
Dog d2 = (Dog)obj2;

if(d1.getAge()==d2.getAge())
return d1.getName().compareTo(d2.getName());
return d1.getAge()-d2.getAge();

}
}




---------------------------------------------------------------------------------------




泛型:JDK1.5版本以后出现的新特性,用于解决安全问题的,是一个类型安全机制。
升级的三部分,高效,安全,简化书写。这里是安全性的提高。


ArrayList<String> al = new ArrayList<String>();
尖括号里面的String就是指定了这个集合存入的元素类型,相当于数组int[]一样,指定了int数组里面
只能存放int类的数据,而这里也是指定了只能存入String类型的数据,存入其他类型就会编译失败,
在编译时期就可以发现问题,安全性就提高了很多。


泛型的好处:
1.把问题的出现从运行时期提前转移到了编译时期,
方便程序员更加早的解决问题,提高了安全性。
2.避免了强制转换的麻烦。


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


在使用JAVA提供的对象时,什么时候写泛型呢?
通常在集合框架中很常见,只要见到<>就要定义泛型。


Collection<E> 尖括号里面的E相当于一个参数变量,也就是element单词首写字母,
意思就是说元素的类型,当然如果不用E用其他字母也可以,只是一个参数名字而已。
其实<>尖括号就是用来接受类型用的,当使用集合时,
将集合中要存储的数据类型作为参数传递到<>中即可,与函数传参数类似。


泛型类:
什么时候使用泛型类呢?
当类中要操作的引用数据不确定的时候,早期定义Object来完成扩展,
现在定义泛型来完成扩展,这里只能是引用数据类型,基本数据类型不可以使用泛型。


/*
  带泛型的类。
 */
package com.Collection;
import java.util.*;
public class DemoGenericClass
{
public static void main(String[] args)
{

Tool<Integer> t = new Tool<Integer>(new Integer(131));
System.out.println(t.getT());;
}


}
//一个简单的泛型类、
class Tool<T>
{
private T t;
Tool(T t)
{
this.t=t;
}
public T getT()
{
return t;
}
}


泛型方法:泛型定义在方法上,T这个代表类型应该放在方法返回值类型的前面,修饰符的后面。
如:public static <T>void method(T t){}


泛型类定义的泛型在整个类中有效,如果被方法使用,
那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经
固定了,为了让不同方法可以操作不同类型,而且类型还不确定,那么
可以将泛型定义在方法上。


/*
 泛型方法,就是把泛型定义在方法上。
 */
package com.Collection;
import java.util.*;
public class DemoGenericMethod
{
//泛型方法
public static <T>void printAll(T t)
{
System.out.println(t);
}
//泛型方法
public static <T>void showAll(T t)
{
System.out.println(t);
}
public static void main(String[] args)
{
DemoGenericMethod.printAll(new Integer(54));
DemoGenericMethod.printAll("hello world");
DemoGenericMethod.showAll(new Integer(5324));
DemoGenericMethod.printAll(new String("false"));

}


}


------------------------------------------------------------------------------
class Demo<T>
{
//这个方法的泛型和类的泛型是一样的。
public void show(T t)
{
System.out.println(t);
}
//这个是泛型独立的方法,不随着类的泛型
public <Q>void print(Q q)
{
System.out.println(q);
}
}


------------------------------------------------------------------------


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

class Demo<T>
{ //泛型方法
public  void print(T t)
{
System.out.println(t);
}
//静态泛型方法
public static <T>void showAll(T t)
{
System.out.println(t);
}
---------------------------------------------------------------------------
泛型定义在接口上:


interface Inter<T>
{
void show(T t){};
}
class Dog implements Inter<String>
{
public void show (String t){};


}


class Dog2 implements Inter<T>
{
public void show (T t){};


}


-----------------------------------------------------


泛型的高级应用:
?通配符,也可以理解为点位符。




泛型限定:简单理解就是限定泛型的范围。
上限 ? extends E: 可以接收E类型或者E的子类型
下限 ?super E: 可以接收E类型或者E的父类型。

泛型提高了扩展性,但不能使用元素的特有方法。


ArrayList<Person> al = new ArrayList<Person>();原则上左右两边定义的泛型要一样。




/*
 泛型的限定,限定泛型的范围。
 */
package com.Collection;
import java.util.*;
public class DemoGeneric3
{

public static void main(String[] args)
{
TreeSet<Worker2> ts = new TreeSet<Worker2>(new PeopleComparator());
ts.add(new Worker2("worker1",13));
ts.add(new Worker2("worker2",33));
ts.add(new Worker2("worker5",43));
ts.add(new Worker2("worker3",23));

//取出元素
for(Iterator<Worker2> it=ts.iterator(); it.hasNext();)
{
System.out.println(it.next().getName());
}

// TreeSet<Person3> ts = new TreeSet<Person3>(new PeopleComparator());
// ts.add(new Person3("name2",230));
// ts.add(new Person3("name1",203));
// ts.add(new Person3("name4",123));
// ts.add(new Person3("name3",238));
//
// //取出元素
// for(Iterator<Person3> it=ts.iterator(); it.hasNext();)
// {
// System.out.println(it.next().getName());
// }



}


}
class People
{
private String name;
private int age;
People(String name,int age)
{
this.name=name;
this.age=age;
}
//set and get method
public String getName()
{
return name;
}

public int getAge()
{
return age;
}
}
class Worker2 extends People
{
private String name;
private int age;
Worker2(String name,int age)
{
super(name,age);
}
}


class Person3 extends People
{
private String name;
private int age;
Person3(String name,int age)
{
super(name,age);
}
}


////普通比较器
//class WorkerComparator implements Comparator<Worker2>
//{
// public int compare(Worker2 w1,Worker2 w2)
// {
// return w1.getName().compareTo(w2.getName());
// }
//}


////普通比较器
//class PersonComparator implements Comparator< Person3>
//{
// public int compare(Person3 p1,Person3 p2)
// {
// return p1.getName().compareTo(p2.getName());
// }
//}


//通用比较器
class PeopleComparator implements Comparator< People>
{
public int compare(People p1,People p2)
{
return p1.getName().compareTo(p2.getName());
}
}




--------------------------------------------------------------------------------
Map集合与Colletion集合同级

接口 Map<K,V>  key ,value  键 值。键和值也就是元素的类型。
一次存两个元素。

|--Hashtable:底层是哈希表数据结构,不可以存入null键null值,
该集合是线程同步的,JDK1.0出现的,效率低。
|--HashMap:底层是哈希表数据结构,可以使用null值和null键,
该集合线程不同步,JDK1.2出现,效率高。
|--TreeMap:底层是二叉树数据结构,线程不同步,可以用于map集合中的键进行排序。
TreeMap可以传比较器,


 一般老版本的方法或者类是线程同步的。
Map和Set很像,其实,Set底层就是使用了Map集合。去掉值就是一个了,也就是Set了。




特点:该集合存储键值对,一对一对往里存,而且要保证键的唯一性。
该集合应用最广泛,也是最多的。


1.增加,put(K,V);
2.删除,remove(K); 
3.判断,containsKey(K);
4.获取,get(K);values();


添加元素,如果出现添加时,相同的键,那么后添加的值会覆盖原有键对应值
并且put方法会返回被覆盖的值。


Map集合的两种取出元素的方式:
1.Set<K> keySet:将Map中所有的键存入Set集合中,因为Set集合具备迭代器,
所以可以通过迭代方式取出所有的值,再根据get方法,获取每一个键对应值。
Map集合取出元素的原理:将Map集合转成Set集合,再通过迭代器取出。





2.Set<Map.Entry<k,v>> entrySet:将Map集合中的映射关系存入到了Set集合中,
而这个关系的数据类型就是:Map.Entry




/*
 Map集合中的常见方法练习,
 增,删,判断,获取。
 Map集合的中KeySet方法
 
 */
package com.Collection;
import java.util.*;
public class DemoMapKeySet
{
public static <T>void sop(T t)
{
System.out.println(t);
}
public static void main(String[] args)
{
HashMap<String ,String> hm = new HashMap<String,String>();
//增加元素
hm.put("01", "String1");
hm.put("02", "String2");
hm.put("03", "String3");
hm.put(null, "String4");

//获取Map集合中的元素的第二种方式
Set<Map.Entry<String, String>> entrySet = hm.entrySet();
for(Iterator<Map.Entry<String, String>> it=entrySet.iterator(); it.hasNext();)
{
Map.Entry<String, String> me = it.next();
sop(me.getKey()+":"+me.getValue());
}

// //keySet获取Map集合中的元素的第一种方式
// Set<String> keySet = hm.keySet(); 
// for(Iterator<String> it=keySet.iterator(); it.hasNext();)
// {
// String str = it.next();
// sop(str+"::"+hm.get(str));
// }

// //获取出元素
// sop(hm.get("03"));
// sop(hm.get(null));
//
// //判断元素是否存在
// sop(hm.containsKey("02"));
// sop(hm.containsValue("String1"));
// sop(hm.size());
//
// sop(hm.values());
// //删除元素
// sop(hm.remove("03"));



}
}




-------------------------------------------------------------------------------


什么时候使用Map集合呢?
当数据之间存在映射关系时,就要先想到Map集合。
泛型里面接受的是引用数据类型,也就是说基本数据类型不能被接收。


StringBuilder 缓冲区,什么类型的数据都可以往里面存。


映射可以分为一对一映射,也可以分为一对多映射。
一对一映射就是一个键对应一个值,
一对多映射就是一个键对应多个值。




Collections 与Collection的区别


Collections里面的方法都是静态的,没有对外提供构造函数。
专门用于操作集合的工具类


Collections可以给List排序,不用给Set排序了,
因为Set里面已经有了KeySet排序方式了。




Arrays数据工具类。
list asList(int[] arr) 将数组变成集合。
数组变集合的好处,变成数组以后可以使用集合的方法操作数组中的元素。


 高级for循环:是迭代器的一种简写形式,但有一定的局限性,
就是只能获取集合中的元素,不能进行其他操作。
格式:
for(数据类型  变量名 : 被遍历的集合(Collection)或者数组)



























































































































































































 








































































































































































































































阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页