大数据面试-05-大数据工程师面试题

2)HashMap和HashTable,ArrayList和Vector,ArrayList和LinkedList的区别

1 HashMap不是线程安全的
hashmap是一个接口 是map接口的子接口,是将键映射到值的对象,其中键和值都是对象,并且不能包含重复键,但可以包含重复值。
HashMap允许null key和null value,而hashtable不允许。
2  HashTable是线程安全的一个Collection。
HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许空(null)键值(key),
由于非线程安全,效率上可能高于Hashtable。 HashMap允许将null作为一个entry的key或者value,而Hashtable不允许。 HashMap把
Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解。 Hashtable继承自
Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。 最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,
在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步。 Hashtable和HashMap采用的
hash/rehash算法都大概一样,所以性能不会有很大的差别。
public static void main(String args[]) { HashTable h=new HashTable(); h.put(“用户1”,new Integer(90)); 
h.put(“用户2”,new Integer(50)); h.put(“用户3”,new Integer(60)); h.put(“用户4”,new Integer(70)); 
h.put(“用户5”,new Integer(80)); Enumeration e=h.elements(); while(e.hasMoreElements()){ System.out.println(e.nextElement()); }

总结:

hashmap

线程不安全

允许有null的键和值

效率高一点、

方法不是Synchronize的要提供外同步

containsvaluecontainsKey方法

HashMap Java1.2引进的Map interface的一个实现

HashMapHashtable的轻量级实现

hashtable

线程安全

不允许有null的键和值

效率稍低、

方法是是Synchronize

contains方法方法

Hashtable 继承于Dictionary

Hashtable HashMap要旧


Vector & ArrayList 
1)  Vector的方法都是同步的(Synchronized),是线程安全的(thread-safe),而ArrayList的方法不是,由于线程的同步必然要影响性能,
因此,ArrayList的性能比Vector好。 
2) 当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小,这样,ArrayList就有利
于节约内存空间。
 linkedlist & ArrayList 
ArrayList 采用的是数组形式来保存对象的,这种方式将对象放在连续的位置中,所以最大的缺点就是插入删除时非常麻烦
LinkedList 采用的将对象存放在独立的空间中,而且在每个空间中还保存下一个链接的索引  但是缺点就是查找非常麻烦 要丛第一个索引
开始
Hashtable和HashMap类有三个重要的不同之处。第一个不同主要是历史原因。Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2
引进的Map接口的一个实现。 
也许最重要的不同是Hashtable的方法是同步的,而HashMap的方法不是。这就意味着,虽然你可以不用采取任何特殊的行为就可以在一个多
线程的应用程序中用一个Hashtable,但你必须同样地为一个HashMap提供外同步。一个方便的方法就是利用Collections类的静态的
synchronizedMap()方法,它创建一个线程安全的Map对象,并把它作为一个封装的对象来返回。这个对象的方法可以让你同步访问潜在的
HashMap。这么做的结果就是当你不需要同步时,你不能切断Hashtable中的同步(比如在一个单线程的应用程序中),而且同步增加了很多
处理费用。 
第三点不同是,只有HashMap可以让你将空值作为一个表的条目的key或value。HashMap中只有一条记录可以是一个空的key,但任意数量的
条目可以是空的value。这就是说,如果在表中没有发现搜索键,或者如果发现了搜索键,但它是一个空的值,那么get()将返回null。
如果有必要,用containKey()方法来区别这两种情况。 
一些资料建议,当需要同步时,用Hashtable,反之用HashMap。但是,因为在需要时,HashMap可以被同步,HashMap的功能比Hashtable的
功能更多,而且它不是基于一个陈旧的类的,所以有人认为,在各种情况下,HashMap都优先于Hashtable。 
关于Properties 
有时侯,你可能想用一个hashtable来映射key的字符串到value的字符串。DOS、Windows和Unix中的环境字符串就有一些例子,如key的字符串
PATH被映射到value的字符串C:\WINDOWS;C:\WINDOWS\SYSTEM。Hashtables是表示这些的一个简单的方法,但Java提供了另外一种方法。 
Java.util.Properties类是Hashtable的一个子类,设计用于String keys和values。Properties对象的用法同Hashtable的用法相象,但是类
增加了两个节省时间的方法,你应该知道。 
Store()方法把一个Properties对象的内容以一种可读的形式保存到一个文件中。Load()方法正好相反,用来读取文件,并设定Properties
对象来包含keys和values。 
注意,因为Properties扩展了Hashtable,你可以用超类的put()方法来添加不是String对象的keys和values。这是不可取的。另外,如果你将
store()用于一个不包含String对象的Properties对象,store()将失败。作为put()和get()的替代,你应该用setProperty()和getProperty(),它们用String参数。

3)多线程实现方式Thread和Runnable的区别?
在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口;Thread类是在java.lang包中定义的。一个类只要继承
了Thread类同时覆写了本类中的run()方法就可以实现多线程操作了,但是一个类只能继承一个父类,这是此方法的局限。
在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口;Thread类是在java.lang包中定义的。一个类只要继承
了Thread类同时覆写了本类中的run()方法就可以实现多线程操作了,但是一个类只能继承一个父类,这是此方法的局限。
下面看例子:

[java] view plain copy
print ?
  1. package org.thread.demo;    
  2. class MyThread extends Thread{    
  3.     private String name;    
  4.     public MyThread(String name) {    
  5.         super();    
  6.         this.name = name;    
  7.     }    
  8.     public void run(){    
  9.         for(int i=0;i<10;i++){    
  10.             System.out.println(”线程开始:”+this.name+“,i=”+i);    
  11.         }    
  12.     }    
  13. }    
  14.    
  15. package org.thread.demo;    
  16.    
  17. public class ThreadDemo01 {    
  18.    
  19.     public static void main(String[] args) {    
  20.         MyThread mt1=new MyThread(“线程a”);    
  21.         MyThread mt2=new MyThread(“线程b”);    
  22.         mt1.run();    
  23.         mt2.run();    
  24.     }    
  25. }  
package org.thread.demo;  
class MyThread extends Thread{  
    private String name;  
    public MyThread(String name) {  
        super();  
        this.name = name;  
    }  
    public void run(){  
        for(int i=0;i<10;i++){  
            System.out.println("线程开始:"+this.name+",i="+i);  
        }  
    }  
}  

package org.thread.demo;  

public class ThreadDemo01 {  

    public static void main(String[] args) {  
        MyThread mt1=new MyThread("线程a");  
        MyThread mt2=new MyThread("线程b");  
        mt1.run();  
        mt2.run();  
    }  
}

但是,此时结果很有规律,先第一个对象执行,然后第二个对象执行,并没有相互运行。在JDK的文档中可以发现,一旦调用start()方法,
则会通过JVM找到run()方法。下面启动start()方法启动线程:

[java] view plain copy
print ?
  1. package org.thread.demo;    
  2. public class ThreadDemo01 {    
  3.     public static void main(String[] args) {    
  4.         MyThread mt1=new MyThread(“线程a”);    
  5.         MyThread mt2=new MyThread(“线程b”);    
  6.         mt1.start();    
  7.         mt2.start();    
  8.     }    
  9. }  
package org.thread.demo;  
public class ThreadDemo01 {  
    public static void main(String[] args) {  
        MyThread mt1=new MyThread("线程a");  
        MyThread mt2=new MyThread("线程b");  
        mt1.start();  
        mt2.start();  
    }  
}

这样程序可以正常完成交互式运行。那么为啥非要使用start();方法启动多线程呢?
在JDK的安装路径下,src.zip是全部的java源程序,通过此代码找到Thread中的start()方法的定义,可以发现此方法中使用了private 
native void start0();其中native关键字表示可以调用操作系统的底层函数,那么这样的技术成为JNI技术(java Native Interface)
Runnable接口
在实际开发中一个多线程的操作很少使用Thread类,而是通过Runnable接口完成。

[java] view plain copy
print ?
  1. public interface Runnable{    
  2.     public void run();    
  3. }  
public interface Runnable{  
    public void run();  
}

例子:

[java] view plain copy
print ?
  1. package org.runnable.demo;    
  2. class MyThread implements Runnable{    
  3.     private String name;    
  4.     public MyThread(String name) {    
  5.         this.name = name;    
  6.     }  
  7.     public void run(){    
  8.         for(int i=0;i<100;i++){    
  9.             System.out.println(”线程开始:”+this.name+“,i=”+i);    
  10.         }    
  11.     }    
  12.    
  13. }  
package org.runnable.demo;  
class MyThread implements Runnable{  
    private String name;  
    public MyThread(String name) {  
        this.name = name;  
    }
    public void run(){  
        for(int i=0;i<100;i++){  
            System.out.println("线程开始:"+this.name+",i="+i);  
        }  
    }  

}

但是在使用Runnable定义的子类中没有start()方法,只有Thread类中才有。此时观察Thread类,
有一个构造方法:public Thread(Runnable targer)此构造方法接受Runnable的子类实例,也就是说可以通过Thread类来启动Runnable
实现的多线程。(start()可以协调系统的资源):

[java] view plain copy
print ?
  1. package org.runnable.demo;    
  2. import org.runnable.demo.MyThread;    
  3. public class ThreadDemo01 {    
  4.     public static void main(String[] args) {    
  5.         MyThread mt1=new MyThread(“线程a”);    
  6.         MyThread mt2=new MyThread(“线程b”);    
  7.         new Thread(mt1).start();    
  8.         new Thread(mt2).start();    
  9.     }    
  10. }  
package org.runnable.demo;  
import org.runnable.demo.MyThread;  
public class ThreadDemo01 {  
    public static void main(String[] args) {  
        MyThread mt1=new MyThread("线程a");  
        MyThread mt2=new MyThread("线程b");  
        new Thread(mt1).start();  
        new Thread(mt2).start();  
    }  
}

两种实现方式的区别和联系:
在程序开发中只要是多线程肯定永远以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类有如下好处:
避免点继承的局限,一个类可以继承多个接口。
适合于资源的共享
以卖票程序为例,通过Thread类完成:

[java] view plain copy
print ?
  1. package org.demo.dff;    
  2. class MyThread extends Thread{    
  3.     private int ticket=10;    
  4.     public void run(){    
  5.         for(int i=0;i<20;i++){    
  6.             if(this.ticket>0){    
  7.                 System.out.println(”卖票:ticket”+this.ticket–);    
  8.             }    
  9.         }    
  10.     }    
  11. }  
package org.demo.dff;  
class MyThread extends Thread{  
    private int ticket=10;  
    public void run(){  
        for(int i=0;i<20;i++){  
            if(this.ticket>0){  
                System.out.println("卖票:ticket"+this.ticket--);  
            }  
        }  
    }  
}

下面通过三个线程对象,同时卖票:

[java] view plain copy
print ?
  1. package org.demo.dff;    
  2. public class ThreadTicket {    
  3.     public static void main(String[] args) {    
  4.         MyThread mt1=new MyThread();    
  5.         MyThread mt2=new MyThread();    
  6.         MyThread mt3=new MyThread();    
  7.         mt1.start();//每个线程都各卖了10张,共卖了30张票    
  8.         mt2.start();//但实际只有10张票,每个线程都卖自己的票    
  9.         mt3.start();//没有达到资源共享    
  10.     }    
  11. }  
package org.demo.dff;  
public class ThreadTicket {  
    public static void main(String[] args) {  
        MyThread mt1=new MyThread();  
        MyThread mt2=new MyThread();  
        MyThread mt3=new MyThread();  
        mt1.start();//每个线程都各卖了10张,共卖了30张票  
        mt2.start();//但实际只有10张票,每个线程都卖自己的票  
        mt3.start();//没有达到资源共享  
    }  
}

如果用Runnable就可以实现资源共享,下面看例子:

[java] view plain copy
print ?
  1. package org.demo.runnable;    
  2. class MyThread implements Runnable{    
  3.     private int ticket=10;    
  4.     public void run(){    
  5.         for(int i=0;i<20;i++){    
  6.             if(this.ticket>0){    
  7.                 System.out.println(”卖票:ticket”+this.ticket–);    
  8.             }    
  9.         }    
  10.     }    
  11. }    
  12.    
  13. package org.demo.runnable;    
  14.    
  15. public class RunnableTicket {    
  16.    
  17.     public static void main(String[] args) {    
  18.         MyThread mt=new MyThread();    
  19.         new Thread(mt).start();//同一个mt,但是在Thread中就不可以,如果用同一    
  20.         new Thread(mt).start();//个实例化对象mt,就会出现异常    
  21.         new Thread(mt).start();    
  22.     }    
  23. };  
package org.demo.runnable;  
class MyThread implements Runnable{  
    private int ticket=10;  
    public void run(){  
        for(int i=0;i<20;i++){  
            if(this.ticket>0){  
                System.out.println("卖票:ticket"+this.ticket--);  
            }  
        }  
    }  
}  

package org.demo.runnable;  

public class RunnableTicket {  

    public static void main(String[] args) {  
        MyThread mt=new MyThread();  
        new Thread(mt).start();//同一个mt,但是在Thread中就不可以,如果用同一  
        new Thread(mt).start();//个实例化对象mt,就会出现异常  
        new Thread(mt).start();  
    }  
};

虽然现在程序中有三个线程,但是一共卖了10张票,也就是说使用Runnable实现多线程可以达到资源共享目的。

你可能感兴趣的:(面试)