Java基础(5)-List接口的实现

1.容器(Collection)

之前学的数组就是一种容器,它也可以存储各种不同类型的数据,但是他必须规定长度;

以下是一张各类API接口图片:
在这里插入图片描述

  1. Collection定义了一种存储一组对象的方法; list属于一种有序的可重复的集合;
  2. set是一种无序且不可重复的,如果重复,后面的数据会把前面的数据给覆盖掉;
  3. Map接口定义存储键(key)值(value)映射队,(这个就是要自己设置一个键与其中的值一一对应,详细的后面再说);
  4. 迭代器:可以用来遍历容器;
  5. ArrayList的源码里面是通过数组的方式进行存储,查询的时候速度快,但是插入的时候速度慢(例如你插入一个元素在某个位置 在数组的条件下,数组从你插入的那个位置开始,后面所有的数组元素都需要移动位置,线程不安全),ArrayList允许添加为null的元素,所以null也会占用一份空间;
  6. LinkedList底层通过链表的方式实现的,链表查的时候慢,但是插入、删除等操作速度快(效率高,线程比较vector,没那么安全);
  7. Vector :线程安全但是效率低;
    以下是模仿ArrayList的一个类:
    一定要记住什么是构造函数:没有void修饰,没有返回值

1.ArrayList基础方法模拟

//以下注释是源码的程序,数组起始长度在ArrayList中默认是10;
//ensureCapacityInternal(size + 1);  // 这个主要是判断size是否还在数组默认长度范围之内,意思就是输入的值有没有超出数组下标,并且进行自主扩容;
//elementData[size++] = e;//这是最后将值赋值给数组,并使得size+1;

//下列函數ensureCapacityInternal就是用來判斷的	;minCapacity=size+1;	
//private void ensureCapacityInternal(int minCapacity) {
//ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
//}

//private void ensureExplicitCapacity(int minCapacity) {
//modCount++;
//if (minCapacity - elementData.length > 0)
//grow(minCapacity);
//}

//grow函数
//private void grow(int minCapacity) {
//int oldCapacity = elementData.length;//定义一个oldCapacity接受数组原先的长度;
	// oldCapacity + (oldCapacity >> 1)相当于oldCapacity+(oldCapacity/2)
//int newCapacity = oldCapacity + (oldCapacity >> 1);//再定义一个newCapacity接受新增加的长度;
//if (newCapacity - minCapacity < 0)//选比较小的数
//newCapacity = minCapacity;
	// MAX_ARRAY_SIZE是一种数组最大值,详细可以去Integer类中查看
//if (newCapacity - MAX_ARRAY_SIZE > 0)
// newCapacity = hugeCapacity(minCapacity);//这个好像是压缩空间;里面用了一个三元运算;
//minCapacity is usually close to size, so this is a win:
//elementData = Arrays.copyOf(elementData, newCapacity);
//}


public class MyArrayList {

	private int size;

	private Object[] element;

	// 无参构造函数
	public MyArrayList() {
		element = new Object[10];
	}

	// 有参构造函数
	public MyArrayList(int usize) {
		if (usize >= 0) {//判断输入参数是否合理
			element = new Object[usize];
		} else {
			try {
				throw new Exception("is wrong");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

	}

	// 判断是否为空
	public boolean isEmpty(int size) {
		return size == 0;
	}

	public Object get(int index) {
	//判断输入的下标是否合适;
		if (index < 0 || index > size) {
			try {
				throw new Exception("is wrong");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return element[index];
	}

	public void add(Object obj) {
		//下面是进行扩容,这是我的这个1.8的源码
		if (size == element.length) {
			Object[] values = new Object[(3 * size)/2 + 1];
			System.arraycopy(element, 0, values, 0, element.length);
			element = values;
		}
		element[size++] = obj;
	}

	public static void main(String[] args) {
		MyArrayList ma = new MyArrayList(10);
		ma.add("dd");
		ma.add("dased");
		ma.add("ssd");
		ma.add("sdsew");
		System.out.println(ma.get(1));
	}
}

一个使用过的名为复制的方法:
System.arraycopy(要复制的数组名, 复制的起始位置, 目标数组, 复制到目标数组的位置, 复制的长度);
下方代码是ArrayList的源码set()方法;

public E set(int index, E element) {
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;//为什么返回值是oldValue?以后的学习我一定会知道的
    }

2.LinkedList基础使用

下图是一张双向链表,linkedList图,指一个节点含有链接他的其他节点的信息;
可以把一个节点看成三部分,第一部分存它上一个节点位置,中间存放自己的值,最后一部分则存下一个 节点的信息;
第一个节点,第一部分为null,因为它没有上一个节点,最后一个节点则是最后一个部分为null,因为它后面没有节点;
图是手绘

  • 这里定义一个节点类,然后主要就是get(),set()方法;
  • 如果不记得get,set方法有什么用了,简单来说就是:可以通过get,set方法来改变或取得这个类中的某些私有值。(用private修饰的,无法直接获取的)
  • 在这里也可以不用private修饰,如果不用private修饰那么在MylinkedList类中就可以不需要set,get方法,直接可以调用其属性;但是最好还是使用private吧;因为使用private的时候,外部调用该属性时,不能直接使用对象.属性值直接进行修改;而且set,get方法中还可以创建一些条件,阻止一些非法的赋值,比如可以添加一个if语句进行判断,这个值是否可以输入之类的;
//定义的一个节点类;
public class Node {
	private Node next;
	private Object obj;
	private Node previous;
	
	//提供一个空构造器的理由是有时需要创造一个对象,但是不需要太多的参数;如果不设置,那么就只能使用下面的构造器;
	public Node() {
	}
	public Node(Node next, Object obj, Node previous) {
		super();
		this.next = next;
		this.obj = obj;
		this.previous = previous;
	}
	public Node getNext() {
		return next;
	}
	public void setNext(Node next) {
		this.next = next;
	}
	public Object getObj() {
		return obj;
	}
	public void setObj(Object obj) {
		this.obj = obj;
	}
	public Node getPrevious() {
		return previous;
	}
	public void setPrevious(Node previous) {
		this.previous = previous;
	}
}

以下发代码中有部分linkedList的主要方法,为了记忆更加深刻,我照着源码全部学了一遍,方便了解LinkedList的基本结构;除此之外还有一些方法,就不一一执行了,希望我以后看的时候还看的懂,哈哈哈哈哈

public class MyLinkedList {
	Node first;
	Node last;
	private int size;
	
	public int size() {
		return size;
	}
	
	//添加一个set方法;
	public void set(int index,Object obj) {//用于更换一个指定节点的值
		checkrange(index);
		Node x = node(index);
		Object oldnode = x.getObj();
		x.setObj(obj);
	}
	
	//添加一个add方法,添加一个节点
	public void add(Object obj) {
		Node node = new Node();
		if(first==null) {
			node.setPrevious(null);//前节点为null
			node.setObj(obj);//赋给节点的值
			node.setNext(null);//节点的下一个节点也不知道是谁,所以为null;
			
			first = node;//这是第一个节点,自然这个节点的first就应该赋值给自己,
			last = node;//最后一个节点位置也应该赋值给自己
		}else {
			node.setPrevious(last);
			node.setObj(obj);
			node.setNext(null);
			
			last.setNext(node);//使得上一个节点的下一个节点时node,就是为了形成一条链。last是指上一个节点;
			last = node;//把这个节点赋值为last,因为现在他才是最后一个节点;
		}
		size++;
	}
	//用于指定一个判断index是否非法的方法;非法则抛出异常;
	private void checkrange(int index) {
		if(size<index||index<0) {
			try {
			throw new Exception("out of bounds");
			}catch(Exception e){
				e.printStackTrace();
			}
		}
	}
	
	//定义一个get方法,得到一个节点的值
	public Object get(int index) {
		checkrange(index);
		return node(index).getObj();
	}
	
	//定义一个方法node用于移除和获得;
	public Node node(int index) {
		if(index<(size/2)) {
			Node node = first;
			for(int i=0;i<index;i++) {
				node=node.getNext();
			}
			return node;
		}else {
			Node node = last;
			for(int i=size-1;i>index;i--) {
				node=node.getPrevious();
			}
			return node;
		}
		
	}
	
	//定义一个移除所需要的方法unlink
	public  Node unlink(Node node) {
		Node up = node.getPrevious();
		Node down = node.getNext();
		if(up==null) {
			first=down;//这里面first属于一种变量,千万别当成常量看;
		}else {
			up.setNext(down);
			//在这里的时候,由于是链式,所以只需要确定一条链,再取消掉那个要删除的链子和前面链子的链接;就可以重新规划一条链子了;
			node.setNext(null);
		}
		
		if(down==null) {
			last=up;
		}else {
			down.setPrevious(up);
			node.setPrevious(null);
		}
		size--;
		return node;
	}
	
	//定义一个移除节点的方法;
	public Node remove(int index) {
		checkrange(index);
		Node temp = node(index);
		return unlink(temp);
	}
	
	public static void main(String[] args) {
		MyLinkedList ml = new MyLinkedList();
		ml.add("dsd");
		ml.add("ddd");
		ml.add("jkdhf");
		ml.add("sd");
		ml.add("ddd");
		ml.set(0, "1111");
//		ml.remove(2);
		System.out.println(ml.get(2));
		System.out.println(ml.get(0));
//		System.out.println(ml.get(2));
//		System.out.println(ml.get(3));
//		System.out.println(ml.get(4));
		System.out.println(ml.size());
	}
}

虽然在写的时候由于理解不深刻出现了错误,但是写完的时候感觉还是学到了很多,希望继续努力;

明天必须把Map相关的重要子类全部了解一遍,加油!加油!加油!

猜你喜欢

转载自blog.csdn.net/dxsdcyy/article/details/104796459
今日推荐