您的位置:首页 > 编程语言 > Java开发

java07 map

2015-09-23 21:21 393 查看
map底层,数组加链表





集合:
是一个对象,只不过这个对象可以容纳别的对象。存放对象就是操作地址。
List:是有序可重复的。
Set:无顺序,不可重复,有重复则后面把前面的覆盖。
Map:键值对。

四大接口(Collection、Set、List、Map):
--Collection(集合)
--Set(没有顺序,不可重复)
--HashSet
--List(有顺序,重复)
--Map
--HashMap

Collection为null表示容器都没有,Collection的方法:Collection为isEmpty()表示容器有,但是容器为空。Iterator<E> iterator()遍历容器,Object[] toArray()容器转换为数组,boolean add(E e)放入到容器,boolean remove(Object o)表示移除一个元素,但是这个元素还在,删除就是这个元素也没有了。boolean containsAll(Collection<?> c)有没有包含另一个容器里面所有的元素,boolean addAll(Collection<? extends E> c)把另一个容器的所有元素都包含进去, boolean removeAll(Collection<?> c)移除另一个容器中的所有元素,boolean retainAll(Collection<?> c)两个容器取交集,void clear()清除容器。

Set和List为Collection的子类,所以Set、List继承了Collection的所有方法。

List list = new ArrayList();
ArrayList数组列表,底层是private transient Object[] elementData(一个Object数组),

public class Test01 {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
List list = new ArrayList();    //ArrayList:底层实现时数组,线程不安全,效率高。所以,查询快(数组查询最快,挨个遍历)。修改、插入(插入一个后面也要移动)、删除(后面也要移动)慢。
//LinkedList:底层实现是链表,线程不安全,效率高。所以,查询慢(一个个的挨着向后找)。修改、插入(改变指针就可以了)、删除(改变指针就可以了)快。
//Vector:底层也是数组实现,线程安全的(多个线程共享的时候会有线程安全问题,但是定义成局部变量就跟线程没有关系),效率低。
list.add("aaa");
list.add("aaa");
list.add(new Date());
list.add(new Dog());
list.add(1234);  //包装类的:自动装箱!ArrayList里面用的是一个Object对象数组,1234不是对象,理论上是不能存进去的,但是会自动转为Integer对象。
list.remove(new String("aaa"));
System.out.println(list.size());
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
list.set(3, new String("3333"));
list.add(4, new String("3333"));
System.out.println(list.isEmpty());
list.remove(new Dog());      //hashcode和equals
System.out.println(list.size());
List list2 = new ArrayList();
list2.add("bbb");
list2.add("ccc");
list.add(list2);
//跟顺序的操作
String str = (String) list.get(0);//返回的是Object类型
System.out.println(str);
list.set(1, "ababa");
list.remove(0);
}
}
class Dog {
}

System.arraycopy(elementData, index+1, elementData, index,        numMoved);//原数组,原数组起点,目标数组,目标数组地点

list.remove(new String("aaa"));
list.remove("aaa");
new String("aaa")和"aaa"是2个不同的对象。

Dog a1 = new Dog();//cn.bjsxt.collection.Dog@123b25c
Dog a2 = new Dog();//cn.bjsxt.collection.Dog@2ba11b
System.out.println(a1 == a2);//false
System.out.println(a1.equals(a2));//false

/**
* 自己实现一个ArrayList,帮助我们更好的理解ArrayList类的底层结构!
*
*/
public class SxtArrayList /*implements List*/ {

private Object[] elementData;
private int size;

public int size(){
return size;
}

public boolean isEmpty(){
return size==0;
}

public SxtArrayList(){
this(10);
}

public SxtArrayList(int initialCapacity){
if(initialCapacity<0){
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
elementData = new Object[initialCapacity];
}

public void add(Object obj){
//数组扩容和数据的拷贝
if(size==elementData.length){
Object[] newArray = new Object[size*2+1];
System.arraycopy(elementData, 0, newArray, 0, elementData.length);
for(int i=0;i<elementData.length;i++){
newArray[i] = elementData[i];
}
elementData = newArray;
}

elementData[size++]=obj;
size++;
}

public Object get(int index){
rangeCheck(index);

return elementData[index];
}

public void remove(int index){
rangeCheck(index);
//删除指定位置的对象
//a b d e
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 void remove(Object obj){
for(int i=0;i<size;i++){
if(get(i).equals(obj)){  //注意:底层调用的equals方法而不是==.
remove(i);
}
}
}

public Object set(int index,Object obj){
rangeCheck(index);

Object oldValue =  elementData[index];
elementData[index] = obj;
return oldValue;
}

public void add(int index,Object obj){
rangeCheck(index);

ensureCapacity();  //数组扩容

System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = obj;
size++;
}

private void ensureCapacity(){
//数组扩容和数据的拷贝
if(size==elementData.length){
Object[] newArray = new Object[size*2+1];
System.arraycopy(elementData, 0, newArray, 0, elementData.length);//原数组,被拷贝的起点索引。目标数组,拷贝到的起点索引,拷贝的长度。
for(int i=0;i<elementData.length;i++){
newArray[i] = elementData[i];
}
elementData = newArray;
}
}

private void rangeCheck(int index){
if(index<0||index>=size){
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
}

public static void main(String[] args) {
SxtArrayList list = new SxtArrayList(3);
list.add("333");
list.add("444");
list.add("5");
list.add("344433");
list.add("333");
list.add("333");
System.out.println(list.size());
//        System.out.println(list.get(6));
list.remove("444");
System.out.println(list.size());
}
}

//链表操作链表操作链表操作链表操作链表操作链表操作链表操作
//链表操作链表操作链表操作链表操作链表操作链表操作链表操作
import java.util.LinkedList;
//双向链表
public class SxtLinkedList /*implements List*/ {
private Node first;//由于是双向链表所以有首尾节点,而且只维护了首尾节点。
private Node last;
private int size;
public void add(Object obj){
Node n = new Node();
if(first==null){
n.setPrevious(null);
n.setObj(obj);
n.setNext(null);
first = n;
last = n;//赋值就是改变栈中变量的地址值的指向
}else{
//直接往last节点后增加新的节点
n.setPrevious(last);
n.setObj(obj);
n.setNext(null);
last.setNext(n);//堆中这个对象的里面的值改变
last = n;//改变栈中last的地址值的指向。
}
size++;
}
public int size(){
return size;
}

private void rangeCheck(int index){
if(index<0||index>=size){
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
}

public Object get(int index){   //2
rangeCheck(index);
// 0 1 2 3 4
Node temp = node(index);
if(temp!=null){
return temp.obj;
}
return null;
}

public Node node(int index){
Node temp = null;
if(first!=null){
temp = first;//temp指向第一个节点对象
for(int i=0;i<index;i++){
temp = temp.next;//这里的赋值就是temp的地址值的指向依次向下移动。
}
}
LinkedList l;
return temp;
}

public void remove(int index){
Node temp = node(index);
if(temp!=null){
Node up = temp.previous;//对象赋值就是传递地址
Node down = temp.next;
up.next = down;
down.previous = up;
size--;
}
}

public void add(int index,Object obj){//数组列表的插入要做数组的copy,链表的插入直接打断连接。
Node temp = node(index);
Node newNode = new Node();
newNode.obj = obj;
if(temp!=null){
Node up = temp.previous;//对象的赋值赋的是地址的值,
//互相指向
up.next = newNode;
newNode.previous = up;
//互相指向
newNode.next = temp;
temp.previous = newNode;
size++;
}
}

public static void main(String[] args) {
SxtLinkedList list = new SxtLinkedList();
list.add("aaa");
list.add("bbb");
list.add(1,"BBBB");
list.add("ccc");
//        list.remove(1);
System.out.println(list.get(1));
}
}

//用来表示一个节点
public class Node {
Node previous;   //上一个节点
Object obj;
Node next;        //下一个节点

public Node() {
}

public Node(Node previous, Object obj, Node next) {
super();
this.previous = previous;
this.obj = obj;
this.next = 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;
}
}
//链表操作链表操作链表操作链表操作链表操作链表操作链表操作

Map
map中的key,value也是对象,key不能重复,Map中存的也是对象的地址。map.remove("高琪");表示只是把这个对象从容器中移除,这个对象并没有删除还在。
HashMap效率高线程不安全,HashTable效率低线程安全。

Map实现1:
/**
*自定义实现Map的功能!
*暂不完美!
*Map:存放键值对,根据键对象找对应的值对象.键不能重复!
*
*/
public class SxtMap001 {
SxtEntry[]  arr  = new SxtEntry[990];//SxtEntry数组
int size;
public void put(Object key,Object value){
SxtEntry e = new SxtEntry(key,value);
//解决键值重复的处理
for(int i=0;i<size;i++){
if(arr[i].key.equals(key)){
arr[i].value=value;
return ;
}
}
arr[size++] = e;
}

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 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 static void main(String[] args) {
SxtMap001 m = new SxtMap001();
m.put("高琪", new Wife("杨幂"));
m.put("高琪", new Wife("李四"));
Wife w = (Wife) m.get("高琪");
System.out.println(w.name);
}

}

class  SxtEntry {//定义一个类Entry(条目),里面是键值对。
Object key;
Object value;

public SxtEntry(Object key, Object value) {
super();
this.key = key;
this.value = value;
}
}

Map实现2,提高查询的效率。
对象的地址是根据哈希码生成的一个数。
Map的底层结构就是数组+链表(一个Map整体是一个数组,每个数组元素是一个链表,每个链表的节点是一个键值对的对象).
public class SxtMap002 {
//底层仍然是数组,每个数组元素是一个链表,链表的每个节点是key、value对。就是说一个数组元素里面,可以存多个值,取的时候遍历这个数组元素的链表。
LinkedList[]  arr  = new LinkedList[9]; //Map的底层结构就是:数组+链表!
int size;
public void put(Object key,Object value){
SxtEntry  e = new SxtEntry(key,value);

int a = key.hashCode()%arr.length;
if(arr[a]==null){
LinkedList list = new LinkedList();
arr[a] = list;//数组的每个元素是链表,
list.add(e);//链表的每个节点是键值对。
}else{
LinkedList list = arr[a];
for(int i=0;i<list.size();i++){
SxtEntry e2 = (SxtEntry) list.get(i);
if(e2.key.equals(key)){
e2.value = value;  //键值重复直接覆盖!
return;
}
}
arr[a].add(e);
}
//a:1000-->1   b:10000-->13
}

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++){//遍历这个链表(某一个数组元素)
SxtEntry e = (SxtEntry) list.get(i);
if(e.key.equals(key)){
return e.value;
}
}
}
return null;
}

public static void main(String[] args) {
SxtMap002 m = new SxtMap002();
m.put("高琪", new Wife("杨幂"));
m.put("高琪", new Wife("李四"));
Wife w = (Wife) m.get("高琪");
System.out.println(w.name);
}

}

public class Wife {
public Wife(String string) {
}
}

HashCode:
java中,两个内容相同的对象有相同的hashcodes,2个对象调用equals方法返回true则hashcodes一定相等。哈希算法可以快速定位这个对象存放的地方。
HashCode方法和equals要重写的话,这2个方法要一起重写,保证equals方法为true则hashcode一定相等。
=是判断2个对象是不是同一个对象,equals方法是判断2个对象的内容是不是相等。
Object类的equals方法是用=实现的,即比较对象的地址是不是相等。
string也重写了equals方法,即比较值是不是相等。

public class Student  extends Object{
//类的equals、hashCode方法有一个重写则2个都要重写。
private Integer id;//Integer(包装类)的equals、hashCode重写了,即比较数值是不是相等。
private String name;//String的equals、hashCode方法重写了,比较字符串值。
private Date birthday;//Date类的equals、hashCode,比较毫秒数是不是相等。
//如果这2个方法不重写,默认hashCode是返回对象的地址,equals是比较地址(比较是不是同一个对象)
//重写后,这里根据id和name进行重写,如果是同一个对象则为true,如果id和name相等就是true
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
//这里的equals是比较2个对象的id和name是不是一样的,一样则这2个对象相等(equals为true)。
@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 == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}

public class TestEquals {

public static void main(String[] args) {
List list = new ArrayList();//List有顺序可重复
Integer s1 = new Integer(243);
Integer s2 = new Integer(243);
list.add(s1);
list.add(s2);
System.out.println(list.size());

Map map = new HashMap();
//键不能重复(判断键是不是重复了是通过equals方法)。
map.put(s1, "AAAA");
map.put(s2, "BBBBBB");
System.out.println(map.get(243));
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: