Java——容器&泛型初步体验

1.认识容器

java的容器类主要由两个接口派生而出:Collection和Map。
Collection是容器层的根接口。
JDK不提供Collection接口的具体实现,而是提供了更加具体的子接口(如Set、List和Queue)实现。

三个子接口

Set
  • 它是一个不包括重复元素的Collection,是无序的(如果后边放入相同元素,不会自动往下添加,而是覆盖前面一个元素),其里边可以存放Map对象;实现Set的有: HashSet和TreeSet等(HashSet底层实现是通过HashMap完成的)

接下来我们写一个简易的HashSet

public class THashSet {  //底层实现通过HashMap
	
	HashMap map;  
	private static final Object PRESENT =new Object();  //常量,作为value值
	
	public THashSet() {
		map = new HashMap();
	}
	
	public int size() {
		return map.size();
	}
	
	public void add(Object o)
	{
		map.put(o,PRESENT);  //利用了map里面的键对象不可重复
	}
	
	
	public static void main(String[] args) {
		SxtHashSet s = new SxtHashSet();
		s.add("aaa");
	    s.add(new String("aaa"));
		System.out.println(s.size());
	}


输出结果为:
1
List
  • List是有序的,元素可以重复。确切的讲,就是,相同的内容可以放在不同的位置,寻找时是通过位置来寻找。实现List的有:ArrayList、LinkedList、Vector、Stack等。

LinkedList是一种双向链表,可以向前获取数据,也可以向后获取数据。数据结构大多是基于C/C++的,在Java中,指针被封装起来了

手动实现LinkedList:

//结点类

public class Node{
	/*去掉private访问限制,同一个包可以访问*/
	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;
	}
}
//简写LinkedList实现
public class TLinkedList {
	private Node first;
	private Node last;
	
	private int size;
	
	/**
	 * 在结尾添加新的结点
	 * @param obj
	 */
	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);  //作为链表最后一个节点,next为空
			
			last.setNext(n);  //将当前结点与上一个结点对接
			
			last = n;
		}
		size++;
	}
	
	public int size() {
		return size;
	}
	
	/**
	 * 检查是否越界
	 * @param index
	 */
	private void rangeCheck(int index) {  //检查是否越界
		if(index<0||index>=size) {
			try {
				throw new Exception();
			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
			}
		}
	}

	/**
	 * 获取某一个结点的数据
	 * @param index
	 */
	public Object get(int index) {
		//如果越界
		rangeCheck(index);
		
		Node temp = node(index); //得到当前结点
		if(temp!=null) {
			return temp.obj;  //返回该结点的数据
		}
		return null;
	}
	
	/**
	 * 查询指定索引的结点
	 * @param index
	 */
	public Node node(int index) {  
		Node temp = null;  //借用temp中间存储
		if(first!=null) {
//			if(index<(size>>1)) {  //size>>1=size/2
//				temp = first;
//				for(int i = 0;i<index;i++) {  //当该结点下一个结点不为空,则成为下一个
//					temp = temp.next;
//				}
//			}else {
//				temp = first;
//				for(int i = size - 1;i>index;i--) {  //倒着再检测
//					//当该结点下一个结点不为空,则成为下一个
//					temp = temp.previous;
//				}
			if(first!=null) {
				temp = first;
				for(int i=0;i<index;i++) {
					temp = temp.next;
				}
			}	
		}
		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) {
		Node temp = node(index);
		Node temp1 = new Node();
		temp1.obj = obj;
		
		if(temp!=null) {
			Node up = temp.previous;
			up.next = temp1;  //头部对接
			temp1.previous = up;
			
			temp1.next = temp;//尾部对接
			temp.previous = temp1;
			
			size++;
		}
	}
	
	/**
	 * 替换当前位置的结点
	 * @param index
	 */
	public void set(int index,Object obj) {  //调用插入删除实现替换
		remove(index);
		add(index,obj);
	}
	
	public static void main(String[] args) {
		SxtLinkedList list  = new SxtLinkedList();
		list.add("aaa");
		list.add("bbb");
		list.add("ddd");
		System.out.println(list.get(0));
		//list.remove(1);
		//System.out.println(list.get(1));
		//list.add(1,"ccc");
		//System.out.println(list.get(1));
		//list.set(1,"CCC");
		System.out.println(list.get(1));
		System.out.println(list.get(2));
	}
}

输出结果:
aaa
bbb
ddd
Queue
  • Queue其中一种是双向的,可以在头尾插入删除元素,主要包括:ArrayDeque、LinkedBlockingDeque、LinkedList

Map

  • Map是一个键值对的集合。也就是说,一个映射不能包含重复的键,每个键最多映射到一个值。该接口取代了Dictionary抽象类。实现map的有:HashMap、TreeMap、HashTable等。
  • 关于HashMap和HashTable的区别:两者基本实现都差不多,但是有一些区别。同步性上:HashTable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的 。HashMap支持你的值为空.

以下是对Map简单的使用:

import java.util.HashMap;
import java.util.Map;

/**
 * 测试Map的基本用法
 *
 */
public class TestMap {
	public static void main(String[] args) {
		Map map = new HashMap();
		/*put,将相对应的映射放入map容器*/
		//前者为Key,后者为Value(以对象方式)
		map.put("李四",new Wife("王五"));
		map.put("张三",new Wife("刘六"));
		//size为2,一对一对存放
		
		Wife w = (Wife)map.get("李四");
		System.out.println(map.size());  //查询元素个数
		map.remove("张三");  //删除一对
		System.out.println(map.size());
		System.out.println(w.name);
	}

}

class Wife{ 
	String name;
	public Wife(String name) {
		this.name = name;
	}
}

输出结果:
2
1
王五

实现简易的Map

package com.mtli.collection1;

/**
 * 自定实现Map的功能
 *
 */
public class TMap {

	TEntry[] arr = new TEntry[990];  //构建一个数组
	//自己手写,不必向List那样进行扩容
	int size;
	
	public void put(Object key,Object value) {  //加入映射
		TEntry e = new TEntry(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 void remove(Object key) {  //删除(只能单线程)
		for(int i = 0;i<size;i++) {
			if(arr[i].key.equals(key)) {  //形参对应的数值是否与遍历中的相等
				 arr[i].value=arr[i].key=null;
			}	
		}
		size--;
	}
	
	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].key.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);
		System.out.println(m.size);
		m.remove("张三");
		System.out.println(m.size);
	}
}

class TEntry{  //存放键值
	Object key;
	Object value;
	public TEntry(Object key, Object value) {
		super();
		this.key = key;
		this.value = value;
	}
}

输出结果:
刘六
2
1

总结:

出处:https://blog.csdn.net/softwave/article/details/4166598

Vector和ArrayList
1.vector是线程同步的,所以它也是线程安全的,而ArrayList是线程异步的,是不安全的。如果不考 虑到线程的安全因素,一般用ArrayList效率比较高。

2,如果集合中的元素的数目大于目前集合数组的长度时,Vector增长率为目前数组长度的100%,而ArrayList增长率为目前数组长度的50%.如过在集合中使用数据量比较大的数据,用Vector有一定的优势。

3,如果查找一个指定位置的数据,Vector和ArrayList使用的时间是相同的,都是0(1),这个时候使用Vector和ArrayList都可以。而如果移动一个指定位置的数据花费的时间为0(n-i)n为总长度,这个时候就应该考虑到使用LinkedList,因为它移动一个指定位置的数据所花费的时间为0(1),而查询一个指定位置的数据时花费的时间为0(i)。

ArrayList 和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,都允许直接序号索引元素,但是插入数据要设计到数组元素移动等内存操作,所以索引数据快插入数据慢,Vector由于使用了synchronized方法(线程安全)所以性能上比ArrayList要差,LinkedList使用双向链表实现存储,按序号索引数据需要进行向前或向后遍历,但是插入数据时只需要记录本项的前后项即可,所以插入数度较快!

Aarraylist和Linkedlist
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。

2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。

3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。

这一点要看实际情况的。若只对单条数据插入或删除,ArrayList的速度反而优于LinkedList。但若是批量随机的插入删除数据,LinkedList的速度大大优于ArrayList. 因为ArrayList每插入一条数据,要移动插入点及之后的所有数据。

HashMap与TreeMap
1、HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。HashMap中元素的排列顺序是不固定的)。

2、 HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。集合框架”提供两种常规的Map实现:HashMap和TreeMap (TreeMap实现SortedMap接口)。

3、在Map 中插入、删除和定位元素,HashMap 是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。使用HashMap要求添加的键类明确定义了hashCode()和 equals()的实现。 这个TreeMap没有调优选项,因为该树总处于平衡状态。

HashTable与HashMap
1、历史原因:Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现 。

2、同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的 。

3、值:只有HashMap可以让你将空值作为一个表的条目的key或value 。

2.泛型

JDK5.0支持的一个新功能——Java的泛型。

定义:泛型只是编译时的概念,是供编译器进行语法检查用的。所谓泛型,就是在定义(类型的定义,方法的定义,形式参数的定义,成员变量的定义等等)的时候,指定它为通用类型,也就是数据类型可以是任意的类型(但尖括号里面只能是引用类型),如List<?> list = null,具体调用时,要将通用类型转换成指定的类型。泛型提高了大型程序的类型安全和可维护性(避免了强制类型转换)。

以下是一个将容器和泛型相结合的例子

import java.util.*;

/**
 * 测试表格数据的存储
 */
public class Test01 {
    public static void main(String[] args) {
        Map<String,Object> map = new HashMap();  //一个map装一行
        map.put("id",1001);
        map.put("name","张三");
        map.put("salary",3000);
        map.put("department","项目部");
        map.put("hireDate","2017-10");

        Map<String,Object> map2 = new HashMap();
        map2.put("id",1002);
        map2.put("name","李四");
        map2.put("salary",3001);
        map2.put("department","人事部");
        map2.put("hireDate","2017-12");

        Map<String,Object> map3 = new HashMap();
        map3.put("id",1003);
        map3.put("name","王五");
        map3.put("salary",3002);
        map3.put("department","市场部");
        map3.put("hireDate","2017-11");

        List<Map<String,Object>>list = new ArrayList<>();

        list.add(map);
        list.add(map2);
        list.add(map3);

        for(Map<String,Object> row:list){
            Set<String> keySet = row.keySet();

            for(String key:keySet){
                System.out.println(key+":"+row.get(key)+"\t");
            }
        }
        //printEmpName(list); //同样可以输出,可自行尝试
    }

    public static void printEmpName(List<Map>list) {
        for(int i = 0;i<list.size();i++) {
            Map tempMap = list.get(i);
            System.out.println(tempMap.get("name")+"---"+"薪水:"+tempMap.get("salary")+"--"+"部门:"+tempMap.get("department"));
        }
    }
}

输出结果:
hireDate:2017-10	
name:张三	
id:1001	
salary:3000	
department:项目部	
hireDate:2017-12	
name:李四
id:1002	
salary:3001	
department:人事部	
hireDate:2017-11	
name:王五	
id:1003	
salary:3002	
department:市场部
发布了24 篇原创文章 · 获赞 15 · 访问量 6128

猜你喜欢

转载自blog.csdn.net/weixin_42173451/article/details/89480595