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(); //包装类的:自动装箱!ArrayList里面用的是一个Object对象数组,1234不是对象,理论上是不能存进去的,但是会自动转为Integer对象。
list.remove(new String("aaa"));
System.out.println(list.size());
for(int i=;i<list.size();i++){
System.out.println(list.get(i));
}
list.set(, new String(""));
list.add(, new String(""));
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();//返回的是Object类型
System.out.println(str);
list.set(, "ababa");
list.remove();
}
}
class Dog {
} System.arraycopy(elementData, index+, 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==;
} public SxtArrayList(){
this();
} public SxtArrayList(int initialCapacity){
if(initialCapacity<){
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*+];
System.arraycopy(elementData, , newArray, , elementData.length);
for(int i=;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 - ;
if (numMoved > ){
System.arraycopy(elementData, index+, elementData, index,
numMoved);//原数组,原数组起点,目标数组,目标数组地点
}
elementData[--size] = null; // Let gc do its work
} public void remove(Object obj){
for(int i=;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 + ,
size - index);
elementData[index] = obj;
size++;
} private void ensureCapacity(){
//数组扩容和数据的拷贝
if(size==elementData.length){
Object[] newArray = new Object[size*+];
System.arraycopy(elementData, , newArray, , elementData.length);//原数组,被拷贝的起点索引。目标数组,拷贝到的起点索引,拷贝的长度。
for(int i=;i<elementData.length;i++){
newArray[i] = elementData[i];
}
elementData = newArray;
}
} private void rangeCheck(int index){
if(index<||index>=size){
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
} public static void main(String[] args) {
SxtArrayList list = new SxtArrayList();
list.add("");
list.add("");
list.add("");
list.add("");
list.add("");
list.add("");
System.out.println(list.size());
// System.out.println(list.get(6));
list.remove("");
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<||index>=size){
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
} public Object get(int index){ //
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=;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(,"BBBB");
list.add("ccc");
// list.remove(1);
System.out.println(list.get());
}
} //用来表示一个节点
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[];//SxtEntry数组
int size;
public void put(Object key,Object value){
SxtEntry e = new SxtEntry(key,value);
//解决键值重复的处理
for(int i=;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=;i<size;i++){
if(arr[i].key.equals(key)){
return arr[i].value;
}
}
return null;
} public boolean containsKey(Object key){
for(int i=;i<size;i++){
if(arr[i].key.equals(key)){
return true;
}
}
return false;
} public boolean containsValue(Object value){
for(int i=;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[]; //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=;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=;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 = ;
int result = ;
result = prime * result + ((id == null) ? : id.hashCode());
result = prime * result + ((name == null) ? : 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();
Integer s2 = new Integer();
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());
} }

java07 map的更多相关文章

  1. mapreduce中一个map多个输入路径

    package duogemap; import java.io.IOException; import java.util.ArrayList; import java.util.List; imp ...

  2. .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法

    .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法 0x00 为什么需要Map(MapWhen)扩展 如果业务逻辑比较简单的话,一条主管道就够了,确实用不到 ...

  3. Java基础Map接口+Collections工具类

    1.Map中我们主要讲两个接口 HashMap  与   LinkedHashMap (1)其中LinkedHashMap是有序的  怎么存怎么取出来 我们讲一下Map的增删改查功能: /* * Ma ...

  4. Java基础Map接口+Collections

    1.Map中我们主要讲两个接口 HashMap  与   LinkedHashMap (1)其中LinkedHashMap是有序的  怎么存怎么取出来 我们讲一下Map的增删改查功能: /* * Ma ...

  5. 多用多学之Java中的Set,List,Map

            很长时间以来一直代码中用的比较多的数据列表主要是List,而且都是ArrayList,感觉有这个玩意就够了.ArrayList是用于实现动态数组的包装工具类,这样写代码的时候就可以拉进 ...

  6. Java版本:识别Json字符串并分隔成Map集合

    前言: 最近又看了点Java的知识,于是想着把CYQ.Data V5迁移到Java版本. 过程发现坑很多,理论上看大部分很相似,实践上代码写起来发现大部分都要重新思考方案. 遇到的C#转Java的一些 ...

  7. MapReduce剖析笔记之八: Map输出数据的处理类MapOutputBuffer分析

    在上一节我们分析了Child子进程启动,处理Map.Reduce任务的主要过程,但对于一些细节没有分析,这一节主要对MapOutputBuffer这个关键类进行分析. MapOutputBuffer顾 ...

  8. MapReduce剖析笔记之七:Child子进程处理Map和Reduce任务的主要流程

    在上一节我们分析了TaskTracker如何对JobTracker分配过来的任务进行初始化,并创建各类JVM启动所需的信息,最终创建JVM的整个过程,本节我们继续来看,JVM启动后,执行的是Child ...

  9. MapReduce剖析笔记之五:Map与Reduce任务分配过程

    在上一节分析了TaskTracker和JobTracker之间通过周期的心跳消息获取任务分配结果的过程.中间留了一个问题,就是任务到底是怎么分配的.任务的分配自然是由JobTracker做出来的,具体 ...

随机推荐

  1. ruby mysql数据库操作

    require 'mysql' con=Mysql.new('localhost','root','root','test') con.query('set names utf8') rs=con.q ...

  2. 【原创】FPGA开发手记(二) VGA接口

    以下内容均以Xilinx的Nexys3作为开发板 1.VGA接口介绍 首先,先看电路图(3*5为例): 标准VGA一共15个接口,但是实际应用的接口信号只用五个:HSYNC,行同步信号:VSYNC,场 ...

  3. Android开发UI之动画侦听

    动画侦听使用了AnimationListener接口,需要实现三个方法onAnimationStart().onAnimationRepeat().onAnimationEnd() 代码: 实现But ...

  4. Android开发UI之补间动画-Tween Animation

    Tween Animation-补间动画 官网链接-http://developer.android.com/reference/android/view/animation/Animation.ht ...

  5. c/c++ void 指针

    原文 : http://blog.csdn.net/yyyuhan/article/details/3153290 1.概述 许多初学者对C/C++语言中的void及void指针类型不甚理解,因此在使 ...

  6. eclipse 代码中突然出现特殊字符

    在写代码的时候,不知道点到了 eclipse 的哪个属性,代码中就出现了一些特殊字符,也不能删除. 请问,在 eclipse 中该怎么设置,才能将这些字符去掉. 如下图所示: 解决方法: 选择Wind ...

  7. 使用 Azure Site Recovery 灾难恢复至 Azure 的功能现已正式发布

    ABHISHEK A. HEMRAJANI 云 + Enterprise项目经理 自我们宣布发布使用 Azure SiteRecovery 灾难恢复至 Azure的功能预览版以来,这几个月着实令人 ...

  8. SharePoint 2010在win7 x64 安装

    转:http://kaneboy.blog.51cto.com/1308893/328000 关于<SharePoint 2010应用程序开发指南>,我和杜伟同学正在撰写中,希望下半年早点 ...

  9. Using the Task Parallel Library (TPL) for Events

    Using the Task Parallel Library (TPL) for Events The parallel tasks library was introduced with the ...

  10. SQL Server数据库大型应用解决方案总结【转】

    [IT168 技术]随着互联网应用的广泛普及,海量数据的存储和访问成为了系统设计的瓶颈问题.对于一个大型的互联网应用,每天百万级甚至上亿的PV无疑对数据库造成了相当高的负载.对于系统的稳定性和扩展性造 ...