41.Iterator,ListIterator 和 Enumeration 的区别?
迭代器是一种设计模式,
它是一个对象,
它可以遍历并选择序列中的对象,
而开发人员不需要了解
该序列的底层结构.
迭代器通常被称为 "轻量级" 对象,
因为创建它的代价小.
Java 中的 Iterator 功能比较简单,
并且只能单向移动:
(1) 使用方法 iterator()要求容器返回一个 Iterator.
第一次调用 Iterator 的 next()方法时,
它返回序列的第一个元素.
注意: iterator()方法是 java.lang.Iterable 接口
被 Collection 继承.
(2) 使用 next()获得序列中的下一个元素.
(3) 使用 hasNext()检查序列中是否还有元素.
(4) 使用 remove()将迭代器新返回的元素删除.
Iterator 是 Java 迭代器最简单的实现,
为 List 设计的 ListIterator 具有更多的功能,
它可以从两个方向遍历 List,
也可以从 List 中插入和删除元素.
-------------
ListIterator 的特点:
它的父类接口是 Iterator,
名称是系列表迭代器,
允许程序员按任一方向遍历列表,
迭代期间修改列表,
并获得迭代器在列表中的当前位置.
ListIterator 没有当前元素,
它的光标位置始终位于调用 previous()
所返回的元素和调用 next()
所返回的元素之间.
长度为 n 的列表的迭代器有 n+1 个
可能的指针位置.
------------------
Enumeration 的特点:
API 中是这样描述的,
它主要是和 Vector 结合配套使用.
另外此接口的功能与 Iterator 接口的功能是重复的,
此外, Iterator 接口添加了
一个可选的移除操作,
并且使用较短的方法名.
新的实现应该优先
考虑使用 Iterator 接口
而不是 Enumeration 接口.
-----------------------
java 中的集合类都提供了
返回 Iterator 的方法,
就是迭代器,
它和 Enumeration 的主要区别
其实就是 Iterator 可以删除元素,
但是 Enumration 却不能.
42.Java 中 Set 与 List 有什么不同?
1,Set 不允许重复, List 允许重复
2,Set 没有顺序, List 有顺序
List 接口对 Collection 进行了简单的扩充,
它的具体实现类常用的有 ArrayList 和 LinkedList.
你可以将任何东西放到一个 List 容器中,
并在需要时从中取出.
ArrayList 从其命名中可以看出
它是一种类似数组的形式进行存储,
因此它的随机访问速度极快,
而 LinkedList 的内部实现是链表,
它适合于在链表中间
需要频繁进行插入和删除操作.
在具体应用时可以根据需要自由选择.
前面说的 Iterator 只能对容器进行向前遍历,
而 ListIterator 则继承了 Iterator 的思想,
并提供了对 List 进行双向遍历的方法.
Set 接口也是 Collection 的一种扩展,
而与 List 不同的时,
在 Set 中的对象元素不能重复,
也就是说你不能把同样的东西
两次放入同一个 Set 容器中.
它的常用具体实现有 HashSet 和 TreeSet 类.
HashSet 能快速定位一个元素,
但是你放到 HashSet 中的对象
需要实现 hashCode()方法,
它使用了前面说过的哈希码的算法.
而 TreeSet 则将放入
其中的元素按序存放,
这就要求你放入
其中的对象是可排序的,
这就用到了集合框架提供的
另外两个实用类 Comparable 和 Comparator.
一个类是可排序的,
它就应该实现 Comparable 接口.
有时多个类具有相同的排序算法,
那就不需要在每分别重复定义
相同的排序算法,
只要实现 Comparator 接口即可.
集合框架中还有两个很实用的公用类:
Collections 和 Arrays.
Collections 提供了对一个 Collection 容器
进行诸如排序, 复制, 查找和填充等
一些非常有用的方法,
Arrays 则是对一个数组进行类似的操作.
43.arraylist 与 vector 的区别?
ArrayList 与 Vector 的区别,
这主要包括两个方面:.
1. 同步性:
Vector 是线程安全的,
也就是说是它的方法之间是线程同步的,
而 ArrayList 是线程序不安全的,
它的方法之间是线程不同步的.
如果只有一个线程会访问到集合,
那最好是使用 ArrayList,
因为它不考虑线程安全,
效率会高些;
如果有多个线程会访问到集合,
那最好是使用 Vector,
因为不需要我们自己
再去考虑和编写线程安全的代码.
备注:
对于 Vector&ArrayList,Hashtable&HashMap,
要记住线程安全的问题,
记住 Vector 与 Hashtable 是旧的,
是 java 一诞生就提供了的,
它们是线程安全的,
ArrayList 与 HashMap 是 java2 时才提供的,
它们是线程不安全的.
2. 数据增长:
ArrayList 与 Vector
都有一个初始的容量大小,
当存储进它们里面的元素的个数超过了容量时,
就需要增加 ArrayList 与 Vector 的存储空间,
每次要增加存储空间时,
不是只增加一个存储单元,
而是增加多个存储单元,
每次增加的存储单元的个数
在内存空间利用与程序效率之间
要取得一定的平衡.
Vector 默认增长为原来两倍,
而 ArrayList 的增长策略
在文档中没有明确规定
从源代码看到的是增长为原来的 1.5 倍.
ArrayList 与 Vector 都可以设置初始的空间大小,
Vector 还可以设置增长的空间大小,
而 ArrayList 没有提供
设置增长空间的方法.
总结:
即 Vector 增长原来的一倍,
ArrayList 增加原来的 0.5 倍.
44. 什么类实现了 List 接口?
List 接口的实现类中
最经常使用最重要的就是这三个:
- ArrayList,
- Vector,
- LinkedList.
1. 三个都直接实现了 AbstractList 这个抽象类
2,ArrayList 和 Vector 都实现了
RandomAccess 接口.
而 LinkedList 没有.
这是什么意思呢?
在 JDK 中,
RandomAccess 接口是一个空接口,
所以它没有实际意义. 就是一个标记,
标记这个类支持高速随机訪问,
所以, arrayList 和 vector 是支持随机訪问的,
可是 LinkedList 不支持持
3.serializbale 接口表明他们都支持序列化.
45. 什么类实现了 Set 接口?
- HashSet
- LinkedHashSet
- TreeSet
HashSet 是使用哈希表 (hash table) 实现的,
其中的元素是无序的.
HashSet 的
add,
remove,
contains 方法
的时间复杂度为常量 O(1).
--------------------
TreeSet 使用树形结构
算法书中的红黑树 red-black tree
实现的.
TreeSet 中的元素是可排序的,
但 add,remove 和 contains 方法的时间
复杂度为 O(log(n)).
TreeSet 还提供了
- first(),
- last(),
- headSet(),
tailSet()等
方法来操作排序后的集合.
-----------------------
LinkedHashSet 介于 HashSet 和 TreeSet 之间.
它基于一个由链表实现的哈希表,
保留了元素插入顺序.
LinkedHashSet 中基本方法的
时间复杂度为 O(1).
46. 如何保证一个集合线程安全?
Java 提供了不同层面的线程安全支持.
在传统集合框架内部,
除了 Hashtable 等同步容器,
还提供了所谓的同步包装器(Synchronized Wrapper),
可以调用 Collections 工具类提供的包装方法,
来获取一个同步的包装容器,
例如 Collections.synchronizedMap().
但是它们都是利用非常粗粒度的同步方式,
在高并发情况下的性能比较低下.
另外, 更加普遍的选择是利用并发包(java.util.concurrent)
提供的线程安全容器类:
各种并发容器,
比如 ConcurrentHashMap,
CopyOnWriteArrayList.
各种线程安全队列(Queue/Deque),
比如 ArrayBlockingQueue,
SynchronousQueue.
各种有序容器的线程安全版本等.
具体保证线程安全的方式,
包括有从简单的 synchronized 方式,
到基于更加精细化的,
比如基于分离锁实现的 ConcurrentHashMap 等并发实现等.
具体选择要看开发的场景需求,
总体来说,
并发包内提供的容器通用场景,
远远优于早期的简单同步实现.
为什么需要 ConcurrentHashMap
首先, Hashtable 本身比较低效,
因为它的实现基本就是
将 put,get,size 等方法
简单粗暴地加上 "synchronized".
这就导致了所有并发操作都要竞争同一把锁,
一个线程在进行同步操作时,
其它线程只能等待,
大大降低了并发操作的性能.
47. 是否可以往 TreeSet 或者 HashSet 中添加 null 元素?
1.TreeSet 是二差树实现的,
Treeset 中的数据是自动排好序的,
不允许放入 null 值
2.HashSet 是哈希表实现的,
HashSet 中的数据是无序的,
可以放入 null,
但只能放入一个 null,
两者中的值都不能重复,
就如数据库中唯一约束
3.HashSet 要求放入的对象
必须实现 HashCode()方法,
放入的对象, 是以 hashcode 码作为标识的,
而具有相同内容的 String 对象,
hashcode 是一样,
所以放入的内容不能重复.
但是同一个类的对象可以放入不同的实例
48.hashCode() 和 equals() 方法的重要性? 如何在 Java 中使用它们?
Java 中的 HashMap 使用
hashCode()和 equals()方法
来确定键值对的索引,
当根据键获取值的时候
也会用到这两个方法.
如果没有正确的实现这两个方法,
两个不同的键可能会有相同的 hash 值,
因此可能会被集合认为是相等的.
而且, 这两个方法也用来发现重复元素,
所以这两个方法的实现对 HashMap 的
精确性和正确性是至关重要的.
同一个对象(没有发生过修改)
无论何时调用 hashCode(),
得到的返回值必须一样.
hashCode()返回值相等,
对象不一定相等,
通过 hashCode()和 equals()
必须能唯一确定一个对象.
一旦重写了 equals(),
就必须重写 hashCode().
而且 hashCode()生成哈希值的依据应该是
equals()中用来比较是否相等的字段.
如果两个由 equals()规定相等的对象
生成的 hashCode 不等,
对于 HashMap 来说,
他们可能分别映射到不同位置,
没有调用 equals()比较是否相等的机会,
两个实际上相等的对象可能被插入到不同位置,
出现错误.
其他一些基于哈希方法的集合类
可能也会有这个问题.
----------------
怎么判断两个对象是相同的?
使用等号 == 判断两个对象是否相同,
这种是严格的相同,
即内存中的同一个对象
Object 的 equal 方法就是使用 == 判断两个对象是否相同
------------
集合 set 要求元素是唯一的, 怎么实现?
要实现元素的唯一,
需要在往集合 set 中添加元素时,
判断集合 set 是否存在相同的元素,
如果存在, 则不添加, 反之.
那么怎么确定两个元素是否相同,
1. 如果是使用等号 == 判断两个元素是否相同,
即默认使用 Object 的 equals 的方法.
2. 如果没有使用等号 == 判断两个元素是否相同,
而是按照某种业务规则判断两个元素是否相同,
即重写了 Object 的 equals 的方法.
----------------------
当重写 equals 方法, 必须重写 hashCode 方法吗?
不是必须的,
得看具体的情况
当 equals 方法返回的结果和使用等号
比较的结果是一致的时候,
是没有必要重写 hashCode 方法.
当用等号比较对象,
只有是内存中同一个对象实例,
才会返回 true,
当然调用其 hashCode()方法
肯定返回相同的值,
这满足了满足了 hashCode 的约束条件,
所以不用重写 hashCode()方法.
当 equals 方法返回的结果
和使用等号比较的结果是不一致的时候,
就需要重写 hashCode 方法.
当重写后的 equals 方法
不认为只有是在内存中同一个对象实例,
才返回 true,
如果不重新 hashCode 方法()
Object 的 hashCode()方法 是对内存地址的映射,
hashCode 方法返回的值肯定是不同的,
这违背了 hashCode 的约束条件,
所以必须要重新 hashCode 方法,
并满足对 hashCode 的约束条件.
49.array 和 arraylist 的区别?
两者间的区别:
Array 的容量是固定的,
ArrayList 的容量是根据需求自动扩展
ArrayList 提供了 添加, 插入或移除
某一范围元素的方法
而 Array 中,
只能一次获取或设置一个元素值
用 Synchronized 方法可以
很容易地创建 ArrayList 的同步版本
而 Array 将一直保持
它知道用户实现同步为止
array 数组的用法
type [] name = new type [size];
注意: size 不能省略, type 前后要一致
缺点: 在数据间插入数据是
ArrayList 动态数组的用法
是 Array 的复杂版本
动态的增加和减少元素,
实现 ICollection 和 IList 接口
灵活的设置数组大小
50. 如何将一个字符串转换为 arraylist?
string 转 ArrayList
先将字符串按照某个字符切割, 转为 string 数组
然后用 Arrays 的 asList 方法, 将数组转为 List
- public class test1 {
- public static void main(String[] args) {
- //string 转 ArrayList
- String str1 = "a,b,c";
- ArrayList<String> list =
- new ArrayList<String>(Arrays.asList(str1.split(",")));
- System.out.println(list);
- }
- }
ArrayList 转 string
- public class test1 {
- public static void main(String[] args) {
- //ArrayList 转 string
- ArrayList<String> list = new ArrayList<String>();
- list.add("a");
- list.add("b");
- list.add("c");
- System.out.println(list);//[a, b, c]
- String list_str = StringUtils.join(list,",");
- System.out.println(list_str);//a,b,c
- }
- }
来源: http://www.jianshu.com/p/5f8ca63168e3