<Java SE > 集合 ArrayList & LinkedList-
集合中接口的关系框架:
1
2
3
4
5
ArrayList:
一些方法使用示例:
package cn.edu.bupt.collection;
import java.util.ArrayList;
import java.util.List;
public class ArrayListTest1
{
public static void main(String[] args)
{
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("world");
list.add("welcome");
String s1 = list.get(0);
String s2 = list.get(1);
String s3 = list.get(2);
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
System.out.println("-------------------");
for (int i = 0; i < list.size(); i++) // size获取集合中元素的个数
{
System.out.println(list.get(i));
}
System.out.println("-------------------");
list.remove("world"); //list.remove(String s)
//list.remove(2); //list.remove(int i) 将后续元素向上移动,以填补被清除掉的元素
for (int i = 0; i < list.size(); i++)
{
System.out.println(list.get(i));
}
System.out.println("-------------------");
System.out.println("index:" + list.indexOf("hello"));
System.out.println("-------------------");
list.clear(); // list.clear()
System.out.println(list.size());
System.out.println("-------------------");
System.out.println(list.isEmpty()); // list.isEmpty()
}
}
第二个示例:
package cn.edu.bupt.array;
import java.util.ArrayList;
import java.util.List;
public class ArrayTest2
{
public static void main(String[] args)
{
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 5; i++)
{
list.add(new Integer(i + 1));
}
/*
* Object[]不能转换为Integer[],这样在运行时会发生类型转换错误,需要针对单个元素进行转换
*/
//Integer[] inte = (Integer[]) list.toArray();
Object[] inte = list.toArray();
for (int i = 0; i < inte.length; i++)
{
System.out.println(((Integer)inte[i]).intValue());
}
}
}
第三个示例:
package cn.edu.bupt.array;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ArrayTest3
{
public static void main(String[] args)
{
List<Point> list = new ArrayList<Point>();
list.add(new Point(2, 3));
list.add(new Point(3, 4));
for(Iterator<Point> itr = list.iterator(); itr.hasNext();)
{
System.out.println(itr.next());
}
System.out.println(list.toString());
}
}
class Point
{
int x;
int y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
@Override
public String toString()
{
return "x=" + this.x + ", y=" + this.y + ";";
}
}
打印结果:
ArrayList内部实现机制:
1、集合中依然存放的是对象的引用,而不是对象本身,对象存放在内存的堆中;也无法放置原生数据类型。
【javadoc 帮助文档的生成】 四十-38:00
【Project -> clean 工具的使用】 四十-41:00
【制作chm帮助文档】 四十-44:00
2、ArrayList底层采用数组实现,当采用不带参数的构造方法生成ArrayList对象时,默认情况下会在底层生成一个长度为10的Object类型的数组。
3、如果增加的元素个数超过了10个,那么ArrayList底层会新生成一个数组,长度为原来数组长度的1.5倍 + 1,然后将原数组的内容复制到新数组当中(使用Arrays.copyOf()进行拷贝),并且后续增加的内容都会放到新数组当中。当新数组无法容纳增加的元素的时候,重复该过程。
4、对于ArrayList元素的删除操作(remove()),需要将被删除元素的后续元素向前移动(通过System.arraycopy函数进行移动),代价比较高。 四十一-10:00
5、对于ArrayList元素的插入操作(add(int, E)),涉及到被插入元素位置后续元素的向后移动(仍然通过System.arraycopy函数进行移动),代价同上。 四十一-10:00
6、集合当中只能放置对象的引用,无法放置原生数据类型,我们需要使用原生数据类型的包装类才能加入到集合当中。
7、集合中放置的都是Object类型,因此取出来的也是Object类型,那么必须要使用强制类型转换将其转换为真正的类型(放置进去的类型)。
(Java编译器知道某个引用变量或接口变量所指对象的实际类型(多态))
LinkedList:
使用示例:
第一个示例
package cn.edu.bupt.array;
import java.util.Iterator;
import java.util.LinkedList;
public class LinkedListTest1
{
public static void main(String[] args)
{
LinkedList<String> list = new LinkedList<String>();
char c = 'A';
for (int i=0; i<5; i++)
{
list.add(new String(new char[]{c++}));
}
for (Iterator<String> itr=list.iterator(); itr.hasNext();)
{
System.out.println(itr.next());
}
System.out.println("--------------");
list.addLast("F"); //LinkedList.addLast()
list.addFirst("8"); //LinkedList.addFirst()
list.add(1, "A2"); //在指定索引位置插入元素
list.remove("A2"); //LinkedList.remove()
list.remove(2);
System.out.println("-------------");
String value = list.get(2);
list.set(2, value + "changed"); //LinkedList.set()方法
}
}
第二个示例,模拟单向链表操作: 四十一-30:00
package cn.edu.bupt.array;
/**
* 模拟链表操作
* @author Medow
*
*/
public class LinkedListTest2
{
public static void main(String[] args)
{
ListElement<String> le1 = new ListElement<String>("Node1");
ListElement<String> le2 = new ListElement<String>("Node2");
ListElement<String> le3 = new ListElement<String>("Node3");
le1.setNext(le2);
le2.setNext(le3);
System.out.println(le1.getNext().getNext().getData()); //通过le1获取le3中的数据
System.out.println("----------------");
//将le4插入到le1和le2之间
ListElement<String> le4 = new ListElement<String>("Node4");
le1.setNext(le4);
le4.setNext(le2);
System.out.println(le1.getNext().getNext().getNext().getData()); //再通过le1获取le3中的数据
System.out.println("-----------------");
//再将le1指向le2
le1.setNext(le2);
le4.setNext(null);
System.out.println(le1.getNext().getNext().getData()); //再通过le1获取le3中的数据
}
}
class ListElement<T>
{
//---------constructor---------------
public ListElement(T data)
{
super();
this.data = data;
}
//--------getter&setter--------------
public T getData()
{
return data;
}
public void setData(T data)
{
this.data = data;
}
public ListElement<T> getNext()
{
return next;
}
public void setNext(ListElement<T> next)
{
this.next = next;
}
public boolean hasNext()
{
return null != this.next;
}
//----------private-----------
private T data;
private ListElement<T> next;
}
第三个示例,模拟双向循环链表操作:
package cn.edu.bupt.array;
public class LinkedListTest3
{
public static void main(String[] args)
{
Node<String> node1 = new Node<String>("Node1");
Node<String> node2 = new Node<String>("Node2");
Node<String> node3 = new Node<String>("Node3");
node1.setNext(node2);
node2.setNext(node3);
node3.setNext(node1);
node1.setPrevious(node3);
node2.setPrevious(node1);
node3.setPrevious(node2);
System.out.println("-------在Node1和Node2之间插入Node4--------");
Node<String> node4 = new Node<String>("Node4");
node1.setNext(node4);
node4.setNext(node2);
node2.setPrevious(node4);
node4.setPrevious(node1);
System.out.println("-----删除Node4------");
node1.setNext(node2);
node2.setNext(node1);
node4.setNext(null);
node4.setPrevious(null);
}
}
class Node<T>
{
//--------constructor---------
public Node(T data)
{
super();
this.data = data;
}
//------getter&setter----------
public Node<T> getPrevious()
{
return previous;
}
public void setPrevious(Node<T> previous)
{
this.previous = previous;
}
public T getData()
{
return data;
}
public void setData(T data)
{
this.data = data;
}
public Node<T> getNext()
{
return next;
}
public void setNext(Node<T> next)
{
this.next = next;
}
//--------private method----------
private Node<T> previous = null;
private T data = null;
private Node<T> next = null;
}
关于ArrayList 与 LinkedList的比较分析: 四十二-25:00
1> LinkedList底层采用双向链表实现;
2> ArrayList底层采用动态分配数组实现;
3> 当执行插入或者删除操作的时候,采用LinkedList效率比较高,因为仅仅是引用操作;
4> 当执行搜索操作时,采用ArrayList效率比较高.
当向ArrayList添加一个对象的时候,实际上是将该对象的引用放置到了ArrayList底层所维护的数组当中;当向LinkedList中添加一个对象的时候,实际上LinkedList内部会生成一个Entry对象,该Entry对象的结构如下:
Entry
{
Entry previous;
Object data;
Entry next;
}
其中的Object类型的元素data就是我们向LinkedList中所添加的元素,然后Entry又构造好了向前与向后的引用previous、next,最后将生成的这个Entry对象加入到了链表中。换句话说,LinkedList中所维护的是一个个的Entry对象,而并不是我们添加的数据对象本身。