Java面试题大全(Java基础十一)

11 篇文章 0 订阅

56、HashMap和Hashtable的区别

HashMap与Hashtable的区别类似于ArrayList与Vector的区别。
Hashtable与Vector都是JDK 1.0就有一个一个古老的集合,因此Hashtable是一个继承自Dictionary的古老集合。
从JDK 1.2引入集合框架的Map接口之后,Java让Hashtable也实现了Map接口,因此Hashtable也新增实现了一些Map接口中定义的方法。实际上Hashtable与HashMap底层的实现很相似,它们都是基于Hash表的实现。
HashMap与Hashtable的区别主要有如下两点:
A.HashMap允许使用null作为key或value,而Hashtable不允许。
B.HashMap是线程不安全的,因此性能较好;但Hashtable是线程安全的,因此性能较差。
实际上,实际在多线程环境下,Java提供了Collections工具类把HashMap包装成线程安全的类,因此依然应该使用HashMap,如下代码所示:
Map map = Collections. synchronizedMap(new HashMap());
简单的说,编程时应该尽量避免使用Hashtable,除非在一个古老的API中强制要求Hashtable。

57、List 和 Map 区别?
表面来看,List是一个只是存放单个元素的集合,List集合所包含的元素可以重复,元素按放入的先后顺序来存放,程序可以通过元素的索引来读取元素,因此List相当于一个动态数组;Map则是一个存放key-value对的集合,Map里存放的key-value对是无需的,Map包含的key是不允许重复的。程序可以key来取出该key对应的value。
深入阐述:如果换个角度来看,我们可以把List当成Map来看,List相当于一个key都是值的Map,程序通过元素的索引读取List集合的元素时,完全也可以当成Map根据key来读取value。从另一个角度来看,Map也可以当成元素索引可以是任意类型的List集合。

58、List, Set, Map是否继承自Collection接口?
List、Set是,Map不是。

59、List、Map、Set三个接口,存取元素时,各有什么特点?
Set集合是最接近Collection的集合,因此Set集合几乎没有在Collection增加什么方法。Set集合代表了集合元素无序、几何元素不允许重复的集合。
List集合则在Collection的基础上为元素增加了索引的特性,因此List集合代表了集合元素有序、集合元素可以重复的集合。
Map则代表了存放key-value对的集合,程序可以通过key来获取其中的value。
就Set集合来说,对于开发者而言,它的集合元素是无序的,似乎显得有些杂乱、无规律,但对计算机而言这不可能,因此计算机需要快速存、取Set集合中的元素。Set集合有两个实现类:HashSet与TreeSet,其中HashSet底层其实使用了一个数组来存放所有集合元素,然后通过Hash算法来决定每个集合元素在底层数组中存放位置,因此HashSet对集合元素的存、取就是Hash算法+数组存、取——也就是说只比数组存、取多了些Hash算法开销,因此性能非常快。TreeSet底层则完全是一个红黑树,因此红黑树是折衷平衡的排序二叉树,它底层没有数组开销,存、取元素时都是基于红黑树算法的,因此性能也不错。
对于List集合而言,主要有两个实现:ArrayList与LinkedList,其中ArrayList底层是基于数组的,而且ArrayList存、取元素本身就是通过元素索引来进行的,因此ArrayList对元素的存、取性能非常好,几乎等同于存、取数组元素。但则添加、删除元素时需要对数组元素进行“整体搬家”,因此添加、删除元素时性能较差。而LinkedList底层则是基于一个链表实现的,当从链表中存、取元素时,需要定位元素的位置,系统开销较大。但添加、删除元素时,只要修改元素的引用(相当于指针)即可,因此性能非常好。

60、说出ArrayList,Vector, LinkedList的存储性能和特性
ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。
LinkedList也是线程不安全的,LinkedList提供了一些方法,使得LinkedList可以被当作堆栈和队列来使用。
实际上Java提供了Collections工具类,它可以把ArrayList、LinkedList包装成线程安全的集合,因此实际编程中应该避免使用Vector。

61、去掉一个Vector集合中重复的元素

Vector newVector = new Vector();
For (int i=0;i<vector.size();i++)
{
Object obj = vector.get(i);
    if(!newVector.contains(obj);
        newVector.add(obj);
}
还有一种简单的方式,HashSet set = new HashSet(vector); 

62、Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?
说明:其实这个题目本身有问题!因为Set只是一个接口,它的不同实现类判断元素是否相等的标准是不同的。笼统地说,Set里的元素是不能重复的,判断元素重复使用equals()。而不是==。
对于HashSet而言,判断两个对象是否相等是通过equals()和hashCode()方法,只要两个对象通过 equals()比较返回false、或两个对象的hashCode()不相等,那么HashSet就会把它们当成不相同。
对于TreeSet而言,判断两个对象相等的唯一标准是:两个对象通过compareTo(Object obj)比较是否返回0,与equals()方法无关。只要两个对象通过compareTo(Object obj)比较没有返回0,Java就会把它们当成两个对象处理——这一点是很多人容易误解的,不过我们可以通过一个示例来说明:

class Z implements Comparable
{
    int age;
    public Z(int age)
    {
        this.age = age;
    }
    // 重写equals()方法,总是返回true
    public boolean equals(Object obj)
    {
        return true;
    }
    //重写了compareTo(Object obj)方法,总是返回正整数
    public int compareTo(Object obj)
    {
        return 1;
    }
}
public class TreeSetTest2
{
    public static void main(String[] args)
    {
        TreeSet set = new TreeSet();
        Z z1 = new Z(6);
        set.add(z1);
        //输出true,表明添加成功
        System.out.println(set.add(z1));    //①
        //下面输出set集合,将看到有两个元素
        System.out.println(set);
        //修改set集合的第一个元素的age变量
         ((Z)(set.first())).age = 9;
        //输出set集合的最后一个元素的age变量,将看到也变成了9
        System.out.println(((Z)(set.last())).age);
    }
}

上面程序中两个Z对象通过equals()比较总会返回true,但通过compareTo(Object obj)比较总是不会返回0,因此两次向TreeSet中添加同一个元素,TreeSet会把它们当成不同的对象进行处理,最后TreeSet集合中会显示有两个对象,但实际上是同一个对象。

63、你所知道的集合类都有哪些?主要方法?
最常用的集合接口是 Set、List、Queue,它们都是Collection的子接口,除此之外还有Map接口。

对于Set集合而言,它的常用实现类包括HashSet与TreeSet。HashSet还有一个子类:LinkedHashSet。
对于List集合而言,它的常用实现类包括ArrayList、Vector与LinkedList。
对于Queue集合而言,它有一个子接口Deque(代表双端队列),它的常用实现类包括ArrayDeque与LinkedList。
对于Map集合而言,它的常用实现类是HashMap与TreeMap。HashMap还有一个子类:LinkedHashMap。
至于这些集合的方法,由于集合类也就是所谓的“容器类”,因此它的方法无非就是向容器中添加、删除、取出、遍历元素的方法。
对于List集合而言,由于它的集合元素都有有序的、有索引的,因此它包括了大量根据索引来添加、删除、取出集合元素的方法。
对于Deque集合而言,由于它是双端队列,即可当成队列使用,也可当成栈使用,因此它增加栈、队列的方法,如offer、peek、push、pop等。
对Map而言,它所包含的无非就是根据key来添加、删除、取出value的方法。

64、两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?
对。
因为equals()方法可以用开发者重写,hashCode()方法也可以由开发者来重写,因此它们是否相等并没有必然的关系。
如果对象要保存在HashSet或HashMap中,它们的equals()相等,那么,它们的hashCode()返回值也应该相等。

65、TreeSet里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的compareTo方法,还是使用的子类的compareTo方法,还是抛异常!
根据TreeSet底层的实现:TreeSet底层的实现就是红黑树,因此当程序向TreeSet中添加集合元素时,程序会多次调用该对象的compareTo()方法与TreeSet中的集合元素进行比较,直到找到该元素在红黑树中应当所在节点位置。因此该问题的答案是:当前正在添加父类对象就多次调用父类对象的compareTo()方法;当前正在添加子类对象就多次调用子类对象的compareTo()方法。
至于程序是否抛出异常,则取决于compareTo()方法的实现,如果子类在实现compareTo()方法时,试图把被比较对象转换为子类对象之后再进行比较——如果TreeSet集合中已经包括了父类对象,这就会引起ClassCastException。
示例代码如下:

class A implements Comparable
{
    int age;
    public A(int age)
    {
        this.age = age;
    }

    public int compareTo(Object obj)
    {
        System.out.println("AAAAAAAAAA");
        A target = (A)obj;
        return age > target.age ? 1 : age < target.age ? -1 : 0;
    }
    public String toString()
    {
        return getClass() + ",age:" + age;
    }

}
class B extends A implements Comparable
{
    public B(int age)
    {
        super(age);
    }
    public int compareTo(Object obj)
    {
        System.out.println("BBBBBBBBB");
        A target = (A)obj;
        return age > target.age ? 1 : age < target.age ? -1 : 0;
    }
}
public class TreeSetTest2
{
    public static void main(String[] args)
    {
        TreeSet set = new TreeSet();
        set.add(new A(3));
        set.add(new B(1));
        set.add(new A(2));
        for(Iterator it = set.iterator(); it.hasNext() ;)
        {
            System.out.println(it.next());
        }
    }
}

上面程序可以看到,输出:
AAAAAAAAAA
BBBBBBBBB
AAAAAAAAAA
AAAAAAAAAA

第一次添加A对象,所以调用A对象的compareTo()方法;第二次添加B对象,所以程序调用了B对象的compareTo()方法;第三次再次添加A对象,由于集合中已经有两个对象,因此程序两次调用了A对象的compareTo()方法与集合中的元素进行比较。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值