一、图形化直观形象深入
见附件!
二、图文式介绍及深入
1.这些类均在java.util包中
2. Collection接口
Collection是最基本的集合接口,一个Collection代表一组Object,即
Collection的元素(Elements)。一些Collection允许相同的元素而另一些不行。一些能排序而另一些不行。Java
SDK不提供直接继承自Collection的类,Java SDK提供的类都是继承自Collection的“子接口”如List和Set。
所有实现Collection接口的类都必须提供两个标准的构造函数:无参数的构造函数用于创建一个空的Collection,有一个
Collection参数的构造函数用于创建一个新的Collection,这个新的Collection与传入的Collection有相同的元素。后
一个构造函数允许用户复制一个Collection。
如何遍历Collection中的每一个元素?不论Collection的实际类型如何,它都支持一个iterator()的方法,该方法返回一个迭代子,使用该迭代子即可逐一访问Collection中每一个元素。典型的用法如下:
Iterator it = collection.iterator(); // 获得一个迭代子
while(it.hasNext()) {
Object obj = it.next(); // 得到下一个元素
}
由Collection接口派生的两个接口是List和Set。
3.List接口
List
是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。
和下面要提到的Set不同,List允许有相同的元素。
除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个
ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素,
还能向前或向后遍历。
实现List接口的常用类有LinkedList,ArrayList,Vector和Stack。
LinkedList类
LinkedList实现了List接口,允许null元素。此外LinkedList提供额外的get,remove,insert方法在
LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。
注意LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:
List list = Collections.synchronizedList(new LinkedList(...));
ArrayList类
ArrayList实现了可变大小的数组。它允许所有元素,包括null。ArrayList没有同步。
size,isEmpty,get,set方法运行时间为常数。但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。
每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并
没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。
和LinkedList一样,ArrayList也是非同步的(unsynchronized)。
Vector类
Vector非常类似ArrayList,但是Vector是同步的。由Vector创建的Iterator,虽然和ArrayList创建的
Iterator是同一接口,但是,因为Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(例
如,添加或删除了一些元素),这时调用Iterator的方法时将抛出ConcurrentModificationException,因此必须捕获该
异常。
Stack 类
Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得
Vector得以被当作堆栈使用。基本的push和pop方法,还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测
一个元素在堆栈中的位置。Stack刚创建后是空栈。
4.Set接口
Set是一种不包含重复的元素的Collection,即任意的两个元素e1和e2都有e1.equals(e2)=false,Set最多有一个null元素。
很明显,Set的构造函数有一个约束条件,传入的Collection参数不能包含重复的元素。
请注意:必须小心操作可变对象(Mutable Object)。如果一个Set中的可变元素改变了自身状态导致Object.equals(Object)=true将导致一些问题。
5.Map接口
请注意,Map
没有继承Collection接口,Map提供key到value的映射。一个Map中不能包含相同的key,每个key只能映射一个
value。Map接口提供3种集合的视图,Map的内容可以被当作一组key集合,一组value集合,或者一组key-value映射。
Hashtable类
Hashtable继承Map接口,实现一个key-value映射的哈希表。任何非空(non-null)的对象都可作为key或者value。
添加数据使用put(key, value),取出数据使用get(key),这两个基本操作的时间开销为常数。
Hashtable
通过initial capacity和load factor两个参数调整性能。通常缺省的load factor
0.75较好地实现了时间和空间的均衡。增大load factor可以节省空间但相应的查找时间将增大,这会影响像get和put这样的操作。
使用Hashtable的简单示例如下,将1,2,3放到Hashtable中,他们的key分别是”one”,”two”,”three”:
Hashtable numbers = new Hashtable();
numbers.put(“one”, new Integer(1));
numbers.put(“two”, new Integer(2));
numbers.put(“three”, new Integer(3));
要取出一个数,比如2,用相应的key:
Integer n = (Integer)numbers.get(“two”);
System.out.println(“two = ” + n);
由于作为key的对象将通过计算其散列函数来确定与之对应的value的位置,因此任何作为key的对象都必须实现hashCode和equals方
法。hashCode和equals方法继承自根类Object,如果你用自定义的类当作key的话,要相当小心,按照散列函数的定义,如果两个对象相
同,即obj1.equals(obj2)=true,则它们的hashCode必须相同,但如果两个对象不同,则它们的hashCode不一定不同,如
果两个不同对象的hashCode相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的hashCode()方法,能加快哈希
表的操作。
如果相同的对象有不同的hashCode,对哈希表的操作会出现意想不到的结果(期待的get方法返回null),要避免这种问题,只需要牢记一条:要同时复写equals方法和hashCode方法,而不要只写其中一个。
Hashtable是同步的。
线程同步即相当于“锁”的功能,也就是线程安全,因为hashtable中所有的方法均是synchronized。
HashMap类
HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null
key。,但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap
的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load factor过低。
WeakHashMap类
WeakHashMap是一种改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收。
6.总结
如果涉及到堆栈,队列等操作,应该考虑用List,对于需要快速插入,删除元素,应该使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList。
如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,其效率较高,如果多个线程可能同时操作一个类,应该使用同步的类。
要特别注意对哈希表的操作,作为key的对象要正确复写equals和hashCode方法。
尽量返回接口而非实际的类型,如返回List而非ArrayList,这样如果以后需要将ArrayList换成LinkedList时,客户端代码不用改变。这就是针对抽象编程。
同
步性Vector是同步的。这个类中的一些方法保证了Vector中的对象是线程安全的。而ArrayList则是异步的,因此ArrayList中的对
象并不是线程安全的。因为同步的要求会影响执行的效率,所以如果你不需要线程安全的集合那么使用ArrayList是一个很好的选择,这样可以避免由于同
步带来的不必要的性能开销。
数据增长
从内部实现机制来讲ArrayList和Vector都是使用数组(Array)来控制集合
中的对象。当你向这两种类型中增加元素的时候,如果元素的数目超出了内部数组目前的长度它们都需要扩展内部数组的长度,Vector缺省情况下自动增长原
来一倍的数组长度,ArrayList是原来的50%,所以最后你获得的这个集合所占的空间总是比你实际需要的要大。所以如果你要在集合中保存大量的数据
那么使用Vector有一些优势,因为你可以通过设置集合的初始化大小来避免不必要的资源开销。
使用模式
在ArrayList和
Vector中,从一个指定的位置(通过索引)查找数据或是在集合的末尾增加、移除一个元素所花费的时间是一样的,这个时间我们用O(1)表示。但是,如
果在集合的其他位置增加或移除元素那么花费的时间会呈线形增长:O(n-i),其中n代表集合中元素的个数,i代表元素增加或移除元素的索引位置。为什么
会这样呢?以为在进行上述操作的时候集合中第i和第i个元素之后的所有元素都要执行位移的操作。这一切意味着什么呢?
这意味着,你只是查找特
定位置的元素或只在集合的末端增加、移除元素,那么使用Vector或ArrayList都可以。如果是其他操作,你最好选择其他的集合操作类。比
如,LinkList集合类在增加或移除集合中任何位置的元素所花费的时间都是一样的?O(1),但它在索引一个元素的使用缺比较慢-O(i),其中i是
索引的位置.使用ArrayList也很容易,因为你可以简单的使用索引来代替创建iterator对象的操作。LinkList也会为每个插入的元素创
建对象,所有你要明白它也会带来额外的开销。
最后,在《Practical Java》一书中Peter
Haggar建议使用一个简单的数组(Array)来代替Vector或ArrayList。尤其是对于执行效率要求高的程序更应如此。因为使用数组
(Array)避免了同步、额外的方法调用和不必要的重新分配空间的操作。
AsyncTask的用法:http://www.cnblogs.com/dawei/archive/2011/04/18/2019903.html
初探异步 AsyncTask 扫描SD卡:http://www.eoeandroid.com/thread-113400-1-1.html
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <EditText android:id="@+id/editText1" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入文件类型" > <requestFocus /> </EditText> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="开始扫描" /> <TextView android:id="@+id/textView1" android:layout_width="match_parent" android:layout_height="match_parent" android:text="TextView" /> </LinearLayout>
package com.pandy.task; import java.io.File; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.app.ProgressDialog; import android.os.AsyncTask; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; public class AsyncTaskDemoActivity extends Activity { /** Called when the activity is first created. */ private Button button1; private EditText editText1; private List<String> list; private TextView textView1; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); this.setTitle("Pandy:扫描SD卡的文件类型."); button1 = (Button)findViewById(R.id.button1); editText1 = (EditText)findViewById(R.id.editText1); textView1 = (TextView)findViewById(R.id.textView1); button1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub if(editText1.getText()==null||editText1.getText().toString().trim().length()==0){ Toast.makeText(AsyncTaskDemoActivity.this, "请输入文件类型...",Toast.LENGTH_SHORT).show(); return; } list = new ArrayList<String>(); new AsyncTask<Integer,Integer,Integer>(){ private ProgressDialog dialog; @Override protected void onCancelled() { // TODO Auto-generated method stub super.onCancelled(); } //执行完成之后 @Override protected void onPostExecute(Integer result) { // TODO Auto-generated method stub dialog.dismiss(); super.onPostExecute(result); Toast.makeText(AsyncTaskDemoActivity.this, "执行完成...",Toast.LENGTH_SHORT).show(); textView1.setText(""); if(list!=null){ for(int i=0; i<list.size(); i++){ textView1.setText(textView1.getText()+list.get(i)+"\n"); } } } //执行之前 @Override protected void onPreExecute() { // TODO Auto-generated method stub dialog = ProgressDialog.show(AsyncTaskDemoActivity.this, "Title", "Load......"); super.onPreExecute(); } //修改界面 @Override protected void onProgressUpdate(Integer... values) { // TODO Auto-generated method stub super.onProgressUpdate(values); } //这里开始启动进程 @Override protected Integer doInBackground(Integer... params) { // TODO Auto-generated method stub //textView1.setText(""); //为什么放在这里就会出错???? String txt = editText1.getText()==null?"":editText1.getText().toString(); if(txt.length()<=0) { Toast.makeText(AsyncTaskDemoActivity.this, "没有输入文件类型", Toast.LENGTH_LONG); return null; } String status = android.os.Environment.getExternalStorageState(); if(android.os.Environment.MEDIA_MOUNTED.equalsIgnoreCase(status)){ File file = android.os.Environment.getExternalStorageDirectory(); scanSDCard(file,txt); return null; }else{ Toast.makeText(AsyncTaskDemoActivity.this, "不能访问SD卡.", Toast.LENGTH_LONG); return null; } } }.execute(0); } }); } public void scanSDCard(File file,String ext){ if(file.isDirectory()){ File[] files = file.listFiles(); if(files!=null){ for(int i=0; i<files.length; i++){ File tmp = files[i]; if(tmp.isFile()){ String fileName = tmp.getName(); if(fileName.indexOf(".")>=0){ fileName = fileName.substring(fileName.lastIndexOf(".")+1); if(ext!=null&&ext.equalsIgnoreCase(fileName)) list.add(tmp.getAbsolutePath()); } }else scanSDCard(tmp,ext); } } }else{ if(file.isFile()){ String fileName = file.getName(); if(fileName.indexOf(".")>=0){ fileName = fileName.substring(fileName.lastIndexOf(".")+1); if(ext!=null&&ext.equalsIgnoreCase(fileName)) list.add(file.getAbsolutePath()); } } } } }
表 A-1 AquaLogic Service Bus 错误代码
子系统
错误代码
错误消息
传输运行时错误
(BEA-380000 至 BEA-38099)
BEA-380000
常规传输错误
XML 详细信息: 收到一个错误响应
(出现在发布操作中时)
消息流运行时错误代码 (382000...382499)
BEA-382000
常规运行时错误
BEA-382030
绑定层的常规解析失败(例如,发送至 XML 服务的消息不是 XML)
BEA-382031
不符合 WS-I 标准
BEA-382032
消息必须是 soap:Envelope
XML 详细信息: 收到一个非 SOAP 或无效的信封
BEA-382033
soap:Envelope 必须包含 soap:Body
BEA-382040
为上下文变量 "{0}" 分配值失败。值必须是 {1} 的一个实例
BEA-382041
为上下文变量 "{0}" 分配值失败。变量为只读。
BEA-382042
为上下文变量 "{0}" 分配值失败。{1}
BEA-382043
更新上下文变量 "{0}" 的值失败:{1}
BEA-382045
初始化上下文变量 "{0}" 的值失败:{1}
BEA-382046
将上下文变量 "{0}" 的值编组到 XML 失败:{1}
BEA-382100
处理入站请求时发生的常规绑定错误
BEA-382101
准备入站响应时发生的常规绑定错误
BEA-382102
准备出站请求时发生的常规绑定错误
BEA-382103
处理出站响应时发生的常规绑定错误
BEA-382104
无法为服务 {0} 准备请求元数据
BEA-382105
无法为服务 {0} 准备响应元数据
BEA-382150
无法调度对服务 {0} 的请求
BEA-382151
无法调度到未知服务:{0}
操作错误代码 (382500...382999)
BEA-382500
ALSB 服务标注操作已收到 SOAP 故障响应。
XML 详细信息: 收到一个 SOAP 故障响应
BEA-382501
ALSB 服务标注操作已收到不可识别的响应。XML 详细信息: 收到一个不可识别的响应
BEA-382502
ALSB 服务标注已收到来自服务器的错误响应 XML 详细信息: 收到一个未知错误响应
BEA-382505
ALSB 验证操作验证失败。
XML 详细信息: 验证失败
BEA-382510
更新变量 "{0}" 时 ALSB 分配操作失败:{1}
BEA-382511
更新变量 "{0}" 时 ALSB 删除操作失败:{1}
BEA-382512
更新变量 "{0}" 时 ALSB 插入操作失败:{1}
BEA-382513
更新变量 "{0}" 时 ALSB 替换操作失败:{1}
BEA-382514
更新变量 "{0}" 时 ALSB 重命名操作失败:{1}
BEA-382515
针对 Java 方法 "{0}" 的标注导致出现异常:{1}
BEA-382516
计算针对 Java 方法 "{0}" 的标注的表达式失败。参数索引:{1},异常:{2}
BEA-382517
将 Java 标注的结果分配给变量时失败。方法:{0},变量:{1},异常:{2}
BEA-382518
调用 Java 方法 "{0}" 时出现安全异常。服务帐户:{1}。{2}
BEA-382600
ALSB 发布操作收到错误响应:{0}
安全错误代码 (386000...386999)
BEA-386000
常规安全错误。可能的原因如下:
已配置自定义标记或自定义用户名/密码身份验证,但是身份验证已通过 WS 安全执行。
BEA-386100
身份验证已失败。可能的原因如下:
已将 XPath 配置为用于正文或标题,但是没有此类消息部分(绑定层返回空内容)。
XPath 引擎在评估 XPath 表达式时引发异常。
用户名 XPath 或密码 XPath 的结果为非 TEXT 或 ATTR 类型的节点。
XPath 返回多个节点。
已检索到用户名/密码,但是身份验证已失败。
已检索到自定义标记,但是标识声明已失败(CSS 标识声明服务引发 LoginException 或任何其他异常)。
BEA-386101
缺少身份验证标记。可能的原因如下:
用户名 XPath 或密码 XPath 返回空结果或空字符串。
自定义标记 XPath 返回空结果、空特性值或空文本值。
BEA-386102
已拒绝消息级授权。可能的原因如下:
消息级访问控制策略拒绝访问代理服务。
BEA-386103
代理服务操作选择算法无法确定请求中的操作名称或返回无效操作(未在 WSDL 中或为空)。可能的原因如下:
计算操作时出错。
操作选择算法返回空内容。
操作选择算法返回的操作并不是 WSDL 所声明的操作。
BEA-386200
常规 Web Service 安全错误
BEA-386201
出现 Web Service 安全故障[<error-code from WSS fault>][<fault-string from WSS-fault>] XML 详细信息: 出现 WS-Security 故障
BEA-386400
常规出站 Web Service 安全错误
BEA-386401
无法将出站消息转换为 SOAP
BEA-386402
无法确定出站操作
BEA-386420
生成安全标头时出现 Web Service 安全错误
BEA-386440
处理安全标头时出现 Web Service 安全错误
BEA-386460
Web Service 安全策略验证错误
UDDI 错误代码 (394500...394999)
BEA-394500
导入资源时遇到错误
BEA-394501
查询业务实体的 UDDI 注册表时遇到错误
BEA-394502
初始化 UDDI 服务时遇到错误
BEA-394503
初始化查询端口时出错
BEA-394504
发布此服务时遇到错误
BEA-394505
无法连接到 UDDI 注册表
BEA-394506
查询业务服务的 UDDI 注册表时遇到错误
BEA-394507
注册表名称中包含不允许的字符
BEA-394508
发布 URL 缺少 UDDI 注册表配置
BEA-394509
已配置的服务帐户无效
BEA-394510
导入服务时无法导入资源
BEA-394511
导入服务期间创建服务定义时出现验证异常
BEA-394512
导入资源时遇到常规错误
BEA-394513
导入资源时遇到内部错误
BEA-394514
导入服务时无法创建 FTP 端点配置
BEA-394515
导入服务时创建电子邮件端点配置失败
BEA-394516
导入服务时在访问点 URL 中出现可能的语法错误
BEA-394517
导入服务期间解析 InstanceParms 时遇到错误
BEA-394518
导入服务时创建文件端点配置失败