ArrayList和LinkedList的区别是什么?举例说明LinkedList可实现的功能。


对于处理一列数据项,Java提供了两个类ArrayList和LinkedList,ArrayList的内部实现是基于内部数组Object[],所以从概念上讲,它更像数组,但LinkedList的内部实现是基于一组连接的记录,所以,它更像一个链表结构,所以,它们在性能上有很大的差别。
在ArrayList的前面或中间插入数据时,必须将其后的所有数据相应的后移,这样必然要花费较多时间,所以,当你的操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;
而访问链表中的某个元素时,就必须从链表的一端开始沿着连接方向一个一个元素地去查找,直到找到所需的元素为止,所以,当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了。
如果在编程中,两种情形交替出现,这时,可以考虑使用List这样的通用接口,而不用关心具体的实现,在具体的情形下,它的性能由具体的实现来保证。
案例:LinkedList 实现堆栈
案例说明
ArrayList的查询效率比较高,增删动作的效率比较差,适用于查询比较频繁,增删动作较少的元素管理的集合。LinkedList的查询效率低,但是增删效率很高。适用于增删动作的比较频繁,查询次数较少的元素管理集合。
ArrayList,LinkedList都是线程不安全的。
实现堆栈 1)数组(ArrayList,增删效率比较低,不适合)
        2)LinkedList(实现堆栈的好方法)
        3)java.util.Stack类,Stack是Vector的子类,Vector类是一个线程安全的(是一个重量级的类),并继承了Vector的方法,Verctor类和ArrayList的功能近乎相同。(不推荐使用Stack类来实现堆栈)。
实现过程
import java.util.*;
public class TestStack {
       public static void main(String[] args) {
               MyStack ms=new MyStack();
               ms.push("Chenzq");
               ms.push("Liucy");
               ms.push("BaiLu");
               System.out.println(ms.pop());
               System.out.println(ms.pop());
               System.out.println(ms.pop());
       }
}
class MyStack{
       private LinkedList ll=new LinkedList();
       public void push(Object o){
               ll.addFirst(o);
      }
       public Object pop(){
               return ll.removeFirst();
       }
}
32.线程的概念是什么?线程之间是如何通信的?

线程是进程中的一个执行单元,同一个进程中的各个线程对应于一组CPU指令、一组CPU寄存器以及一堆栈。进程本来就具有动态的含义,然而实质上是通过线程来执行体现的,从这个意义上说,Windows中进程的动态性意义已经不是很明显了,只算是给程序所占的资源划定一个范围而已,真正具有动态性意义的是线程。
其实,Java提供了3个非常重要的方法来巧妙地解决线程间的通信问题。这3个方法分别是:wait()、notify()和notifyAll()。它们都是Object类的最终方法,因此每一个类都默认拥有它们。
虽然所有的类都默认拥有这3个方法,但是只有在synchronized关键字作用的范围内,并且是同一个同步问题中搭配使用这3个方法时才有实际的意义。
这些方法在Object类中声明的语法格式如下所示:
final void wait() throws InterruptedExceptionfinal void notify()final void notifyAll()
其中,调用wait()方法可以使调用该方法的线程释放共享资源的锁,然后从运行态退出,进入等待队列,直到被再次唤醒。而调用notify()方法可以唤醒等待队列中第一个等待同一共享资源的线程,并使该线程退出等待队列,进入可运行态。调用notifyAll()方法可以使所有正在等待队列中等待同一共享资源的线程从等待状态退出,进入可运行状态,此时,优先级最高的那个线程最先执行。显然,利用这些方法就不必再循环检测共享资源的状态,而是在需要的时候直接唤醒等待队列中的线程就可以了。这样不但节省了宝贵的CPU资源,也提高了程序的效率。
由于wait()方法在声明的时候被声明为抛出InterruptedException异常,因此,在调用wait()方法时,需要将它放入try…catch代码块中。此外,使用该方法时还需要把它放到一个同步代码段中,否则会出现如下异常:
"java.lang.IllegalMonitorStateException: current thread not owner"
这些方法是不是就可以实现线程间的通信了呢?下面将通过多线程同步的模型:生产者和消费者问题来说明怎样通过程序解决多线程间的通信问题。
案例:线程的通信
案例说明
下面这个程序演示了多个线程之间进行通信的具体实现过程。程序中用到了4个类,其中ShareData类用来定义共享数据和同步方法。在同步方法中调用了wait()方法和notify()方法,并通过一个信号量来实现线程间的消息传递。
实现过程
//CommunicationDemo.java 描述:生产者和消费者之间的消息传递过程
class ShareData
{
private char c;
private boolean isProduced = false; // 信号量
public synchronized void putShareChar(char c) // 同步方法putShareChar()
{
if (isProduced)     // 如果产品还未消费,则生产者等待
{
try{wait();        // 生产者等待
}catch(InterruptedException e){
e.printStackTrace();
}
}
this.c = c;
isProduced = true;   // 标记已经生产
notify();             // 通知消费者已经生产,可以消费
}
public synchronized char getShareChar() // 同步方法getShareChar()
{
if (!isProduced)    // 如果产品还未生产,则消费者等待
{
try
{
wait();       // 消费者等待
}catch(InterruptedException e){
e.printStackTrace();
}
}
isProduced = false; // 标记已经消费
notify();            // 通知需要生产
return this.c;
}
}
class Producer extends Thread     // 生产者线程
{
private ShareData s;
Producer(ShareData s)
{
this.s = s;
}
public void run()
{
for (char ch = ''A''; ch <= ''D''; ch++)
{
try
{
Thread.sleep((int)(Math.random()*3000));
}catch(InterruptedException e){
e.printStackTrace();
}
s.putShareChar(ch); // 将产品放入仓库
System.out.println(ch + " is produced by Producer.");
}
}
}
class Consumer extends Thread    // 消费者线程
{
private ShareData s;
Consumer(ShareData s)
{
this.s = s;
}
public void run()
{
char ch;
do{
try
{
Thread.sleep((int)(Math.random()*3000));
}catch(InterruptedException e){
e.printStackTrace();
}
ch = s.getShareChar();    // 从仓库中取出产品
System.out.println(ch + " is consumed by Consumer. ");
}while (ch != ''D'');
}
}
class CommunicationDemo
{
public static void main(String[] args)
{
ShareData s = new ShareData();
new Consumer(s).start();
new Producer(s).start();
}
}

### 回答1: ArrayListLinkedList都是Java中的集合类,它们的主要区别在于底层数据结构和性质。 ArrayList是基于数组实现的动态数组,它的内部是由一个数组实现的。它支持随机访问,可以在O(1)时间内访问指定位置的元素。但是如果需要在中间插入或删除元素,则需要移动后面的元素,时间复杂度为O(n)。 LinkedList是基于链表实现的双向链表,它的内部是由一个链表实现的。它不支持随机访问,需要从头开始遍历链表找到指定位置的元素。但是如果需要在中间插入或删除元素,则只需要调整前后元素的指针,时间复杂度为O(1)。 因此,ArrayList适用于需要频繁随机访问集合元素的场景,而LinkedList适用于需要频繁插入或删除集合元素的场景。 ### 回答2: ArrayListLinkedList都是Java中的集合类,用于存储和操作元素,但它们有一些不同之处。 首先,ArrayList是基于动态数组实现的,而LinkedList是基于双向链表实现的。这意味着在ArrayList中,元素按照索引进行存储和访问,而在LinkedList中,元素通过节点之间的链接进行存储和访问。 其次,由于底层数据结构不同,ArrayListLinkedList在插入和删除元素时的性能表现有所不同。在ArrayList中,如果需要在中间位置插入或删除元素,需要将后续的元素依次移动,因此时间复杂度为O(n);而LinkedList不需要移动元素,只需要改变节点的链接,因此插入和删除元素的时间复杂度为O(1)。 另外,由于ArrayList是基于数组实现的,它的内存空间是连续分配的,因此可以通过索引进行快速访问。而LinkedList的节点不连续存储,访问元素需要从头节点开始遍历到指定位置,因此访问元素的性能较差。所以,在需要频繁访问元素的情况下,ArrayList的性能更好。 最后,ArrayListLinkedList在内存消耗上也有所不同。由于ArrayList基于动态数组,它的内存消耗是固定的,而LinkedList的内存消耗会随着元素的增加而增加,因为每个元素需要一个节点来存储。 总之,ArrayList适用于需要快速访问元素的场景,而LinkedList适用于频繁插入和删除元素的场景。根据具体的使用情况选择合适的集合类可以提高程序性能。 ### 回答3: ArrayListLinkedList都是Java中常用的集合类,它们的主要区别在于底层的数据结构和性能。 1. 数据结构: ArrayList内部使用数组来存储元素,当插入或删除元素时,需要将后面的元素进行移动,因此插入和删除操作效率较低。而查询元素时,ArrayList可以通过索引快速访问元素。 LinkedList使用双向链表来存储元素,每个节点都包含元素本身、前驱节点和后继节点的引用。当插入或删除元素时,只需要修改相应节点的前驱和后继引用,因此插入和删除操作效率较高。但是查询元素时,LinkedList需要遍历链表,因此效率相对较低。 2. 内存占用: ArrayList在内存中分配连续的存储空间,所以每个元素占用的内存是连续的。LinkedList则是通过链表结构存储元素,每个元素可以在内存的不同位置上,因此每个元素占用的内存不一定是连续的。 3. 对于随机访问和顺序访问的效率: ArrayList通过索引可以直接访问指定位置的元素,所以随机访问的效率较高。而LinkedList只能从头开始遍历链表来查找元素,所以顺序访问的效率较高。 综上所述,如果需要频繁进行插入和删除操作,可以选择LinkedList;如果需要频繁进行随机访问操作,可以选择ArrayList。根据具体的使用场景和需求,选择适合的集合类能提高代码的效率和性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值