容器是一个Java 所编写的程序,原先必须自行编写程序以管理对象关系,现在容器都会自动帮您做好。
List特点:元素有放入顺序,元素可重复
Set特点:元素无放入顺序,元素不可重复(注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其位置其实是固定的)
Map特点:元素按键值对存储,无放入顺序 。
一、List接口
ArrayList:线程不安全,效率高。 底层实现是数组,查询块,修改删除慢。
LinkedList: 线程不安全,效率高。 底层实现是链表,查询慢,修改删除快。
Vector:线程安全,效率低。底层实现是数组。
package Collection;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
@SuppressWarnings("all")
public class Demo01 {
public static void main(String[] args) {
List list = new ArrayList();
list.add("dds");
list.add(new Date());
list.add(new Dog());
list.add(324);//包装类的自动装箱
System.out.println(list.size());
System.out.println(list.isEmpty());
list.remove("dds");
System.out.println(list.size());
System.out.println("---------------");
List list2 = new ArrayList();
list2.add("dsaf");
list2.add("fdsf");
list.add(list2);
System.out.println(list.size());
System.out.println("---------------");
String string;
for(int i=0;i<list.size();i++)
{
string=(String) list.get(i).toString();
System.out.println(string);
}
}
}
class Dog{
Dog(){
}
}
运行结果:
4
false
3
---------------
4
---------------
Tue May 12 16:22:29 CST 2015
[email protected]
324
[dsaf, fdsf]
package Collection;
/**
* 自己实现ArrayList
* @author liguodong
*
*/
public class MyArrayList {
private Object[] elementData;
private int size;
public int size(){
return size;
}
public MyArrayList(){
this(10);
}
public MyArrayList(int initialCapacity) {
if(initialCapacity<0)
{
try {
throw new Exception();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
elementData = new Object[initialCapacity];
}
//实现数组扩容和数据的拷贝
public boolean add(Object obj) {
if(size>=elementData.length)//如果size大于初始的大小,进行扩容
{
Object[] newArray = new Object[size*2+1];
System.arraycopy(elementData, 0, newArray, 0, elementData.length);
elementData = newArray;
}
elementData[size] = obj;
size++;
return true;
}
public boolean isEmpty() {
return size==0;
}
public Object get(int index) {
rangeCheck(index);
return elementData[index];
}
//移除指定位置的对象
public Object remove(int index) {
rangeCheck(index);
Object oldValue = elementData[index];
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
return oldValue;
}
private void rangeCheck(int index)
{
if(index>=size){
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
}
public static void main(String[] args) {
MyArrayList list = new MyArrayList(3);
list.add("324");
list.add("343");
list.add("3dsaf4");
list.add("3432");
list.add("3432");
System.out.println(list.size());
System.out.println(list.get(3));//第四个数据
list.remove(2);//第三个数据
System.out.println(list.size());
System.out.println("----------");
list.remove(new String("3432"));
String string;
for(int i=0;i<list.size();i++)
{
string=(String) list.get(i).toString();
System.out.println(string);
}
}
}
运行结果:
5
3432
4
----------
324
343
3432
package Collection;
/**
* 自己写一个双向链表
* @author liguodong
*
*/
public class MyLinkedList
{
/**
* 用来表示一个节点
*/
private static class Node {
Node previous;//上一个节点
Object obj;
Node next;//下一个节点
public Node getPrevious() {
return previous;
}
public void setPrevious(Node previous) {
this.previous = previous;
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
public Node() {
super();
}
}
private Node first;
private Node last;
private int size;
//新增一个元素
public void add(Object obj)
{
Node node = new Node();
if(first == null)
{
node.setPrevious(null);
node.setObj(obj);
node.setNext(null);
first = node;
last = node;
}
else {
//直接往last后新增新的节点
node.setPrevious(last);
node.setObj(obj);
node.setNext(null);
last.setNext(node);
last = node;
}
size++;
}
public int size()
{
return size;
}
//判断是否合法
private void rangeCheck(int index)
{
if(index>=size)
{
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public Object get(int index)
{
rangeCheck(index);//判断是否合法
Node temp=iteratorNode(index);//遍历到指定节点
if(temp != null){
return temp.getObj();
}
return null;
}
//遍历到指定节点
public Node iteratorNode(int index)
{
Node tempNode = null;
if(first != null){
tempNode = first; //先指到链表头,很重要。
for(int i=0;i<index;i++)
{
tempNode = tempNode.getNext();
}
}
return tempNode;
}
//移除索引位置的对象
public Object remove(int index)
{
Node tempNode =iteratorNode(index);
if(tempNode != null)
{
Node up = tempNode.getPrevious();//tempNode.previous
Node down = tempNode.getNext();//tempNode.next
up.setNext(down);//up.next = down
down.setPrevious(up);//down.previous = up;
}
size--;
return true;
}
public void add(int index,Object obj)
{
Node tempNode = iteratorNode(index);//指定位置节点
Node newNode = new Node();//新节点
newNode.setObj(obj);//newNode.obj = obj;
if(tempNode != null)
{
//上一个节点
Node upNode = tempNode.getPrevious();//tempNode.previous;
upNode.setNext(newNode);//upNode.next = newNode;
newNode.setPrevious(upNode);//newNode.previous = upNode;
newNode.setNext(tempNode);//newNode.next = tempNode;
tempNode.setPrevious(newNode);//tempNode.previous = newNode;
size++;
}
}
public void set(int index,Object obj)
{
Node tempNode = iteratorNode(index);
tempNode.setObj(obj);//tempNode.obj = obj;
}
public static void main(String[] args) {
MyLinkedList list = new MyLinkedList();
list.add("探险家");
list.add("齐天大圣");
list.add("风暴之怒");
list.add(1,"德玛西亚皇子");
list.set(3, "盲僧");
System.out.println(list.get(1));
System.out.println(list.size());
//System.out.println(list.remove(1));
for(int i=0;i<list.size();i++)
System.out.println(list.get(i));
}
}
运行结果:
德玛西亚皇子
4
探险家
德玛西亚皇子
齐天大圣
盲僧
二、Map接口
实现Map接口的类用来存储键值对(key-value)。
Map接口的实现类有HashMap和TreeMap等。
Map类中存储的键值对通过键来标识,所以键不能重复。
HashMap 效率高 线程不安全
Hashtable 效率低 线程安全
两则的用法都是一样的
package Collection;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings("all")
public class Demo02 {
public static void main(String[] args) {
Map map = new HashMap();
map.put("习大大", new Wife("彭麻麻"));
map.put("灰太狼", new Wife("红太狼"));
map.put("猪八戒", "嫦娥");
Wife wife = (Wife) map.get("灰太狼");
map.remove("灰太狼");//从容器中移除
System.out.println(wife.name);
System.out.println(map.containsKey("习大大"));
System.out.println(map.containsValue("彭麻麻"));
System.out.println(map.containsValue("嫦娥"));
}
}
class Wife{
String name;
public Wife(String name){
this.name = name;
}
}
运行结果:
红太狼
true
false
true
package Collection;
public class MyMap{
//Map HashMap Hashtable
MyEntry[] arr = new MyEntry[990];
int size;
public void put(Object key,Object value){
MyEntry entry = new MyEntry(key,value);
for(int i=0; i<size; i++){
//解决键值重复的处理
if(arr[i].key.equals(key)){
arr[i].value = value;
return;
}
}
arr[size++] = entry;
}
public Object get(Object key){
for(int i=0; i<size; i++){
if(arr[i].key.equals(key))
{
return arr[i].value;
}
}
return null;
}
public MyEntry remove(Object key){
for(int i=0; i<size; i++){
if(arr[i].key.equals(key))
{
MyEntry oldValue = arr[i];
int numMoved = size - i - 1;
if (numMoved > 0)
System.arraycopy(arr, i+1, arr, i,numMoved);
arr[--size] = null; // Let gc do its work
return oldValue;
}
}
return null;
}
public boolean containsKey(Object key) {
for(int i=0;i<size;i++)
{
if(arr[i].key.equals(key))
return true;
}
return false;
}
public boolean containsValue(Object value)
{
for(int i=0;i<size;i++)
{
if(arr[i].value.equals(value))
return true;
}
return false;
}
public int Size(){
return size;
}
public static void main(String[] args) {
MyMap map = new MyMap();
map.put("习大大", new Wife("彭麻麻"));
map.put("灰太狼", new Wife("红太狼"));
map.put("猪八戒", "嫦娥");
MyEntry entry = map.remove("猪八戒");
System.out.println(map.Size());
System.out.println(entry.key+" "+entry.value);
}
}
//键值对
class MyEntry{
Object key;
Object value;
public MyEntry(Object key, Object value) {
super();
this.key = key;
this.value = value;
}
}
存在问题:效率较低
Map的底层实现是数组+链表
package Collection;
import java.util.LinkedList;
/**
* 升级版
* 提高查询效率
*/
@SuppressWarnings("all")
public class MyMapNext{
LinkedList[] arr = new LinkedList[999];//Map的底层实现是数组+链表
int size;
public void put(Object key,Object value)
{
MyEntry e = new MyEntry(key, value);//键值对
int a = key.hashCode()%arr.length;
if(arr[a] == null){
LinkedList list = new LinkedList();
//将链表放进数组里面
arr[a] = list;
list.add(e);
size++;
}
else{
LinkedList list = arr[a];
for(int i=0;i<list.size();i++)
{
MyEntry entry = (MyEntry) list.get(i);
if(entry.key.equals(key))
{
entry.value = value;//键值重复直接覆盖
}
}
arr[a].add(e);
}
}
public Object get(Object key)
{
int a = key.hashCode()%arr.length;
if(arr[a] != null)
{
LinkedList list = arr[a];
for(int i=0;i<list.size();i++)
{
MyEntry entry = (MyEntry) list.get(i);
if(entry.key.equals(key))
{
return entry.value;
}
}
}
else{
size--;
}
return null;
}
public int Size(){
return size;
}
public static void main(String[] args) {
MyMapNext map = new MyMapNext();
map.put("习大大", new Wife("彭麻麻"));
map.put("灰太狼", new Wife("红太狼"));
map.put("猪八戒", "嫦娥");
System.out.println(map.Size());
Wife wife = (Wife)map.get("灰太狼");
System.out.println(wife.name);
}
}
运行结果:
3
红太狼
Collection类对象在调用remove、contains等方法时,需要比较对象是否祖等。这会涉及到对象类型的equals方法和hashCode方法;对于自定义类型,需要重写equals方法和hashCode方法以实现自定义的对象相等规则。
Java中规定,两个内容相同的对象应该具有相等的hashcode。即equals相等,则hashcode相等;hashcode相等,则equals不一定相等。
Object里面hashCode和equals的native与操作系统有关的解决方法。
String类有对它们重写。
hashCode和equals 可以通过eclipse自动生成。
重写equals方法和hashCode方法
package Collection;
public class Student {
//Object String Integer Date
private int id;
@Override
public int hashCode() {
final int prime = 31;//一般是质数
int result = 1;
result = prime * result + id;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (id != other.id)
return false;
return true;
}
}
package Collection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SuppressWarnings("all")
public class EqualsTest {
public static void main(String[] args) {
List list = new ArrayList();
String s1 = new String("lgd");
String s2 = new String("lgd");
list.add(s1);
list.add(s2);
System.out.println(list.size());
Map map = new HashMap();
//key不能重复,通过equals判断,如果重复,对其value进行覆盖。
map.put(s1, "NB");
map.put(s1,"SB");
System.out.println(map.get("lgd"));//判断是否相等,同样依赖于equals。
}
}
运行结果:
2
SB
查询优化:遍历的时候可以先看要遍历的数的大小与size/2做比较 如果大于size/2遍历后面。否则,遍历前面。JDK源码如下:
/**
* Returns the (non-null) Node at the specified element index.
*/
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
hashCode()算完之后有可能是负数,所以一般做完了应该
int a = key.hashCode()%arr.length;
hash = hash<0?-hash:hash;
三、Set接口
Set接口是Collection接口的子接口,Set接口没有提供额外的方法,Set接口的特性是容器类中的元素是没有顺序的,而且不可以重复。
Set容器可以与数学中”集合”的概念相对应。
J2SDK API中所提供的Set容器类有HashSet,TreeSet等。
HashSet的底层是HashMap实现的。
package Collection;
import java.util.HashSet;
import java.util.Set;
@SuppressWarnings("all")
public class Demo03 {
public static void main(String[] args) {
Set set = new HashSet();
set.add("aaa");
set.add("bbb");
set.add(new String("aaa"));
System.out.println(set.size());
for (Object object : set) {
System.out.println(object);
}
System.out.println(set.contains("bbb"));
}
}
运行结果:
2
aaa
bbb
true
package Collection;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings("all")
public class MyHashSet {
HashMap hashMap;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
public MyHashSet() {
hashMap = new HashMap();
}
public Boolean add(Object o){
return hashMap.put(o, PRESENT)==null;//set的不可重复就是利用了map里面键对象的不可重复!
}
public boolean remove(Object o) {
return hashMap.remove(o)==PRESENT;
}
public void clear() {
hashMap.clear();
}
public int size() {
return hashMap.size();
}
public static void main(String[] args) {
MyHashSet myHashSet = new MyHashSet();
myHashSet.add("大宝");
myHashSet.add("吃饭");
myHashSet.add("傻瓜");
System.out.println(myHashSet.size());
myHashSet.clear();
System.out.println(myHashSet.size());
}
}
运行结果:
3
0
四、容器存储数据综合实例
一个列对应一个属性,一个对象对应一行记录,一个类对应一个表结构。
1、List实现表结构
package Collection;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
//JavaBean实体类
public class Hero {
private int id;
private String name;
private int price;
private String tag;
private Date ontime;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return price;
}
public void setSalary(int price) {
this.price = price;
}
public String getDepartment() {
return tag;
}
public void setDepartment(String tag) {
this.tag = tag;
}
public Date getHiretime() {
return ontime;
}
public void setHiretime(Date ontime) {
this.ontime = ontime;
}
public Hero(int id, String name, int price, String tag,
String ontime) {
super();
this.id = id;
this.name = name;
this.price = price;
this.tag = tag;
DateFormat format = new SimpleDateFormat("yyyy-MM");
try {
this.ontime=format.parse(ontime);
} catch (ParseException e) {
e.printStackTrace();
}
}
public Hero() {
super();
}
}
package Collection;
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings("all")
public class Demo04 {
public static void main(String[] args) {
Hero hero1 = new Hero(1001,"九尾狐",3150,"请宠爱我吧","2012-10");
Hero hero2 = new Hero(1002,"探险家",4800,"是时候表演真正的技术了","2013-5");
Hero hero3 = new Hero(1003,"蛮王",1350,"我的大刀早已饥渴难耐","2014-8");
List list = new ArrayList();
list.add(hero1);
list.add(hero2);
list.add(hero3);
printHeroName(list);
}
public static void printHeroName(List<Hero> list){
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).getName());
}
}
}
运行结果:
九尾狐
探险家
蛮王
2、Map-List实现表结构
package Collection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SuppressWarnings("all")
public class MapList {
public static void main(String[] args) {
Map map1 = new HashMap();
map1.put("id", 1001);
map1.put("name", "刀妹");
map1.put("salary", 3050);
map1.put("department", "项目部");
map1.put("hireDate", "2007-10");
Map map2= new HashMap();
map2.put("id", 1002);
map2.put("name", "战争女神");
map2.put("salary", 3050);
map2.put("department", "教学部");
map2.put("hireDate", "2006-10");
Map map3 = new HashMap();
map3.put("id", 1003);
map3.put("name", "苍井空");
map3.put("salary", 3050);
map3.put("department", "外交部");
map3.put("hireDate", "2009-10");
List<Map> list = new ArrayList<Map>();
list.add(map1);
list.add(map2);
list.add(map3);
printName(list);
}
public static void printName(List<Map> list){
for(int i=0; i<list.size(); i++)
{
System.out.println(list.get(i).get("name") + "--" + list.get(i).get("salary"));
}
}
}
运行结果:
刀妹–3050
战争女神–3050
苍井空–3050
五、Iterator接口
所有实现了Collection接口的容器类都有一个iterator方法用以返回一
个实现了Iterator接口的对象。
Iterator对象称作迭代器,用以方便的实现对容器内元素的遍历操作。
Iterator接口定义了如下方法:
Boolean hasNext() //判断是否有元素没有被遍历
Object next() //返回游标当前位置的元素并将游标移动到下一个位置
void remove() //删除游标左边的元素。在执行完next之后,该操作只能执行一次。
List/Set遍历
package Collection;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@SuppressWarnings("all")
public class Demo05 {
public static void main(String[] args) {
List list = new ArrayList();
list.add("spack");
list.add("storm");
list.add("mahout");
//通过索引遍历
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i)+" ");
}
System.out.println();
//通过迭代器遍历
Iterator iterator01 = list.iterator();
while(iterator01.hasNext()){
String string = (String) iterator01.next();
System.out.print(string+" ");
}
System.out.println();
Set set = new HashSet();
set.add("嫦娥1号");
set.add("嫦娥2号");
set.add("嫦娥3号");
for (Object object : set) {
System.out.print(object + " ");
}
System.out.println();
Iterator iterator02 = set.iterator();
while(iterator02.hasNext()) {
String string = (String) iterator02.next();
System.out.print(string+" ");
}
System.out.println();
for (Iterator iterator03 = set.iterator(); iterator03.hasNext();) {
Object object = (Object) iterator03.next();
System.out.print(object+" ");
}
System.out.println();
}
}
运行结果:
spack storm mahout
spack storm mahout
嫦娥2号 嫦娥1号 嫦娥3号
嫦娥2号 嫦娥1号 嫦娥3号
嫦娥2号 嫦娥1号 嫦娥3号
Map遍历两种方式
package Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@SuppressWarnings("all")
public class Demo06 {
public static void main(String[] args) {
Map map = new HashMap();
map.put("赵信", "枪出如龙");
map.put("蛮王", "我的大刀早已饥渴难耐");
//方式一
Set keys = map.keySet();
for (Object key : keys) {
System.out.println(key+"-->"+map.get(key));
}
for (Iterator iterator = keys.iterator(); iterator.hasNext();) {
String keyString = (String) iterator.next();
System.out.println(keyString+"-->"+map.get(keyString));
}
//方式二
//注意这个Entry是java.util.Map.Entry,导包不要出现错误。
Set entrySet = map.entrySet();
for (Iterator iterator = entrySet.iterator(); iterator.hasNext();) {
Entry entry = (Entry) iterator.next();
String key = (String)entry.getKey();
String value = (String)entry.getValue();
System.out.println(key + "----->" + value);
}
Iterator entryIte = entrySet.iterator();
while (entryIte.hasNext()) {
// 通过迭代返回的是一个entry
Entry entry = (Entry) entryIte.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
System.out.println(key + "----->" + value);
}
}
}
运行结果:
蛮王-->我的大刀早已饥渴难耐
赵信-->枪出如龙
蛮王-->我的大刀早已饥渴难耐
赵信-->枪出如龙
蛮王----->我的大刀早已饥渴难耐
赵信----->枪出如龙
蛮王----->我的大刀早已饥渴难耐
赵信----->枪出如龙