这辈子没办法做太多事情,所以每一件都要做到精彩绝伦!
People can't do too many things in my life,so everything will be wonderful
本资料只进行简单介绍说明以及相关重要问题的解答;关于类的详细说明及使用请参考java API文档
本文参考的依据是:JDK API 1.6.0 中文版,下载地址:http://down.51cto.com/data/2300228
面向对象语言对事物的体现都是以对象的形式,所以,为了方便对多个对象的操作,java就提供了集合类。
数组和集合同是容器,有何不同?
数组可以存储基本类型和引用类型(对象)数据,长度固定;
集合只能存储对象,长度可变。
集合特点:
集合只用于存储对象,长度可变,可以存储不同类型的对象。
1.1 Collection接口
Collection层次结构中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。
成员方法:
boolean add(E e)
boolean remove(Object o)
void clear()
boolean contains(Object o)
boolean isEmpty()
int size()
boolean addAll(Collection c)
boolean removeAll(Collection c)
boolean containsAll(Collection c)
boolean retainAll(Collection c)
Object[] toArray()
把集合转成数组,可以实现集合的遍历
Iterator iterator()
迭代器,集合的专用遍历方式
boolean hasNext()
E next()
1.1.1 Iterator接口
是一个接口,还不是具体类?
注意:不要多次使用hasNext()方法,因为每次都是访问的同一个对象。
1.1.2 List接口
特点:有序(存储顺序和取出顺序一致),可重复。
1.1.2.1 常见数据结构
A:栈 先进后出
B:队列 先进先出
C:数组 查询快,增删慢
D:链表 查询慢,增删快
E:树:
F:哈希表:
1.1.2.2 List子类特点
l ArrayList类概述
底层数据结构是数组,查询快,增删慢
线程不安全,效率高
l Vector类概述
底层数据结构是数组,查询快,增删慢
线程安全,效率低
l LinkedList类概述
底层数据结构是链表,查询慢,增删快
线程不安全,效率高
使用场景:要安全吗?
要:Vector(即使要,也不使用这个,后面再说)
不要:ArrayList或者LinkedList
查询多;ArrayList
增删多:LinkedList
什么都不知道,就用ArrayList
1.1.3 泛型
泛型:是一种特殊的类型,是一种把明确类型的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型。
格式:<泛型类型>
注意:该类型只能是引用类型。
好处:
1, 把运行时期的问题提前到了编译期间;
2, 避免了强制类型转换;
3, 优化了程序设计,解决了×××警告线问题,让程序更安全。
泛型的由来:
Object类型作为任意类型的时候,在向下转型的时候,会隐含一个转型问题。泛型就是为了解决这个问题
泛型类
把泛型定义在类上
格式:public class 类名<泛型类型1,…>
注意:泛型类型必须是引用类型
泛型方法
把泛型定义在方法上
格式:public <泛型类型> 返回类型 方法名(泛型类型 .)
泛型接口
把泛型定义在接口上
格式:public interface 接口名<泛型类型1…>
泛型之通配符
l 泛型通配符>
任意类型,如果没有明确,那么就是Object以及任意的Java类了
l ? extends E
向下限定,E及其子类
l ? super E
向上限定,E及其父类
1.1.4 Set接口
一个不包含重复元素的collection
l HashSet类概述
不保证 set 的迭代顺序
特别是它不保证该顺序恒久不变。
l HashSet如何保证元素唯一性
底层数据结构是哈希表(元素是链表的数组)
哈希表依赖于哈希值存储
添加功能底层依赖两个方法:
l int hashCode()
l boolean equals(Object obj)
执行顺序:
首先比较哈希值是否相同:
相同:继续执行equals()方法
返回true:元素重复了,不添加
返回false:直接把元素添加到集合
不同:就直接把元素添加到集合
l LinkedHashSet类概述
元素有序唯一
由链表保证元素有序
由哈希表保证元素唯一
l TreeSet类概述
使用元素的自然顺序对元素进行排序
或者根据创建 set 时提供的 Comparator进行排序
a:自然排序(元素具备比较性)
让元素所属的类实现Comparable接口
b:比较器排序(集合具备比较性)
让集合构造方法接收Comparator的实现类对象
具体取决于使用的构造方法。
l TreeSet是如何保证元素的排序和唯一性的
底层数据结构是红黑树(红黑树是一种自平衡的二叉树)
1.1.5 Collection总结:
Collection:
|--List有序,可重复
|--ArrayList:底层是数组,查询快,增删慢;线程不安全;
|--Vector:底层是数组,查询快,增删慢;线程安全;
|--LinkedList:底层是链表,查询慢,增删快;线程不安全;
|--Set无序或有序,唯一
|--HashSet:底层是哈希表;依赖hashCode和equals方法保证元素唯一(开发中自动生成这两个方法即可)
|--LinkedHashSet:底层是链表和哈希表,由链表保证元素有序,由哈希表保证唯一
|--TreeSet:底层是红黑树(一种自平衡的二叉树),由自然排序和比较器排序保证元素有序;根据比较的返回值是否是0决定唯一。
到底使用谁?
唯一吗?
是:Set
排序吗?
是:TreeSet
否:HashSet
如果你知道是Set,但是不知道是哪个Set,就用HashSet。
否:List
要安全吗?
是:Vector
否:ArrayList或者LinkedList
查询多:ArrayList
增删多:LinkedList
如果你知道是List,但是不知道是哪个List,就用ArrayList。
如果你知道是Collection集合,但是不知道使用谁,就用ArrayList。
如果你知道用集合,就用ArrayList
1.2 Map接口
将键映射到值的对象;一个映射不能包含重复的键;每个键最多只能映射到一个值。
Map和Collection的区别:
1,Map是双列的,Collection是单列的
2,Map的键唯一,Collection的子体系Set是唯一的
3,Map集合的数据结构值针对键有效,跟值无关
4,Collection集合的数据结构是针对元素有效
Map接口成员方法
V put(K key,V value)
V remove(Object key)
void clear()
boolean containsKey(Object key)
boolean containsValue(Object value)
boolean isEmpty()
int size()
V get(Object key)
Set
Collection
Set
l HashMap类概述
键是哈希表结构,可以保证键的唯一性
LinkedHashMap :Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序
l TreeMap类概述
键是红黑树结构,可以保证键的排序和唯一性
遍历MAP以及效率比对
我们都知道遍历Map一般有3种方法,values(),keySet()和entrySet(),常见的是keySet用的多,简单容易理解,entrySet()是返回Map中的静态内部类Entry类类型的Set实例,当然了你别说forEach,forEach只是一种代替for(int i=0;;)和while()遍历的一种方式,底层也是用迭代器实现的,只不过把部分东西隐藏了,建议大家平常开发中能用forEach遍历,尽可能的用这个,《Effective java》中也明确表示了,简单而不容易出错。
如果Map中有大量的元素,而且并发量又很高,这就涉及到采用哪种遍历方法的问题,下面就来测试一下:
[java] view plain copy
Map
for(int i=0;i<10000;i++){
mapTest.put(String.valueOf(i),String.valueOf(i) );
}
//一种遍历,keySet()方法
longstart=System.nanoTime();
Set
for(String key:setEach){
String value=mapTest.get(key);
}
long end=System.nanoTime();
System.out.println("keySet遍历map耗时"+(end-start)/1000+"微秒");
[java] view plain copy
//二种遍历,可用values()返回Collection
start=System.nanoTime();
Collection
for(String value:co){
//遍历中也在创建value
}
end=System.nanoTime();
System.out.println("values遍历map(只得到值)耗时"+(end-start)/1000+"微秒");
[java] view plain copy
//三种遍历,用entrySet()方法返回Set
start=System.nanoTime();
Set
for(Map.Entry
String key=entry.getKey();
String value=entry.getValue();
}
end=System.nanoTime();
System.out.println("entrySet遍历map耗时"+(end-start)/1000+"微秒");
经过多次运行,结果大概都是这样的:
[java] view plain copy
keySet遍历map耗时9867微秒
values遍历map(只得到值)耗时2539微秒
entrySet遍历map耗时2783微秒
values()是返回Map的所有value的集合collection,只能遍历到值,很难遍历到key所以一般不用,除非在某种特殊场合,所以一般采用的第一种和第三种方式。而测试表明entrySet()方式遍历效率更高。
entrySet()方式遍历之所以快与keySet(),一个原因是keySet相当与遍历了2次,一次是对key的Set集合的遍历,二次是每次遍历过程都要通过key和map.get(key)来获取value值。第二个原因是map.get(key)获取的时候,底层其实根据key的hashcode值经过哈希算法得到一个hash值然后作为索引映射到对应table数组的索引位置,这是一次密集型计算,很耗费CPU,如果有大量的元素,则会使CPU使用率飙升,影响响应速度,而entrySet()返回的set里边元素都是Map.Entry类型,key和value就是这个类的一个属性,entry.getKey()和entry.getValue()效率肯定很高。
所以平常开发过程中,如果对Map讲究效率的遍历的话,还是采用entrySet()方法。
1.3 Collections类
Collections类概述
针对集合操作 的工具类
Collections成员方法
public static
public static
public static
public staticvoid reverse(List> list)
public staticvoid shuffle(List> list)
2. IO流
IO流用来处理设备之间的数据传输
上传文件和下载文件
Java对数据的操作是通过流的方式
Java用于操作流的对象都在IO包中
2.1 File类
File类的概述
文件和目录路径名的抽象表示形式
构造方法
public File(String pathname)
public File(String parent,String child)
public File(File parent,String child)
2.2 递归
递归
方法定义中调用方法本身的现象
递归注意实现
要有出口,否则就是死递归
次数不能太多,否则就内存溢出
构造方法不能递归使用
递归解决问题的思想
找到出口
找到规律
2.3 IO流分类
按照数据流向
输入流 读入数据
输出流 写出数据
按照数据类型
字节流
字符流
什么情况下使用哪种流呢?
如果数据所在的文件通过windows自带的记事本打开并能读懂里面的内容,就用字符流。其他用字节流。
如果你什么都不知道,就用字节流
IO流常用基类
l 字节流的抽象基类:
InputStream ,OutputStream。
l 字符流的抽象基类:
Reader , Writer。
l 注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
如:InputStream的子类FileInputStream。
如:Reader的子类FileReader。
2.4 IO读写数据
FileOutputStream写出数据
A:操作步骤
a:创建字节输出流对象
b:调用write()方法
c:释放资源
B:代码体现:
FileOutputStreamfos = new FileOutputStream("fos.txt");
fos.write("hello".getBytes());
fos.close();
C:要注意的问题?
a:创建字节输出流对象做了几件事情?
b:为什么要close()?
c:如何实现数据的换行?
d:如何实现数据的追加写入?
FileInputStream读取数据
A:操作步骤
a:创建字节输入流对象
b:调用read()方法
c:释放资源
B:代码体现:
FileInputStreamfis = new FileInputStream("fos.txt");
//方式1
intby = 0;
while((by=fis.read())!=-1){
System.out.print((char)by);
}
//方式2
byte[]bys = new byte[1024];
intlen = 0;
while((len=fis.read(bys))!=-1){
System.out.print(newString(bys,0,len));
}
fis.close();
字节缓冲区流
A:BufferedOutputStream
B:BufferedInputStream
2.5 转换流
由于字节流操作中文不是特别方便,所以,java就提供了转换流。
字符流=字节流+编码表。
2.5.1 编码表
编码表
由字符及其对应的数值组成的一张表
常见编码表
ASCII: 字符集 美国标准信息交换码。用一个字节的7位可以表示。
ISO-8859-1: 拉丁码表。欧洲码表;用一个字节的8位表示。
GB2312:中国的中文编码表。
GBK:中国的中文编码表升级,融合了更多的中文文字符号。
GB18030:GBK的取代版本
BIG5:通行于台湾、香港地区的一个繁体字编码方案,俗称“大五码”
Unicode:国际标准码,融合了多种文字。所有文字都用两个字节来表示,Java语言使用的就是unicode
UTF-8:最多用三个字节来表示一个字符
UTF-8不同,它定义了一种“区间规则”,这种规则可以和ASCII编码保持最大程度的兼容:
它将Unicode编码为00000000-0000007F的字符,用单个字节来表示
它将Unicode编码为00000080-000007FF的字符用两个字节表示
它将Unicode编码为00000800-0000FFFF的字符用3字节表示
字符串中的编码问题
编码
String-- byte[]
解码
byte[]-- String
2.5.2 转换流概述
A:OutputStreamWriter
OutputStreamWriter(OutputStreamos):默认编码,GBK
OutputStreamWriter(OutputStreamos,String charsetName):指定编码。
B:InputStreamReader
InputStreamReader(InputStreamis):默认编码,GBK
InputStreamReader(InputStreamis,String charsetName):指定编码默认编码
字符流
Reader
|--InputStreamReader
|--FileReader
|--BufferedReader
Writer
|--OutputStreamWriter
|--FileWriter
|--BufferedWriter
2.6 IO流总结:
IO流
|--字节流
|--字节输入流
InputStream
intread():一次读取一个字节
intread(byte[] bys):一次读取一个字节数组
|--FileInputStream
|--BufferedInputStream
|--字节输出流
OutputStream
voidwrite(int by):一次写一个字节
voidwrite(byte[] bys,int index,int len):一次写一个字节数组的一部分
|--FileOutputStream
|--BufferedOutputStream
|--字符流
|--字符输入流
Reader
intread():一次读取一个字符
intread(char[] chs):一次读取一个字符数组
|--InputStreamReader
|--FileReader
|--BufferedReader
StringreadLine():一次读取一个字符串
|--字符输出流
Writer
voidwrite(int ch):一次写一个字符
voidwrite(char[] chs,int index,int len):一次写一个字符数组的一部分
|--OutputStreamWriter
|--FileWriter
|--BufferedWriter
voidnewLine():写一个换行符
voidwrite(String line):一次写一个字符串
3. 其他操作流
1:数据操作流(操作基本类型数据的流)(理解)
(1)可以操作基本类型的数据
(2)流对象名称
DataInputStream
DataOutputStream
2:内存操作流(理解)
(1)有些时候我们操作完毕后,未必需要产生一个文件,就可以使用内存操作流。
(2)三种
A:ByteArrayInputStream,ByteArrayOutputStream
B:CharArrayReader,CharArrayWriter
C:StringReader,StringWriter
3:打印流(掌握)
(1)字节打印流,字符打印流
(2)特点:
A:只操作目的地,不操作数据源
B:可以操作任意类型的数据
C:如果启用了自动刷新,在调用println()方法的时候,能够换行并刷新
D:可以直接操作文件
问题:哪些流可以直接操作文件呢?
看API,如果其构造方法能够同时接收File和String类型的参数,一般都是可以直接操作文件的
(3)复制文本文件
BufferedReaderbr = new BufferedReader(new FileReader("a.txt"));
PrintWriterpw = new PrintWriter(new FileWriter("b.txt"),true);
Stringline = null;
while((line=br.readLine())!=null){
pw.println(line);
}
pw.close();
br.close();
4:标准输入输出流(理解)
(1)System类下面有这样的两个字段
in标准输入流
out标准输出流
(2)三种键盘录入方式
A:main方法的args接收参数
B:System.in通过BufferedReader进行包装
BufferedReaderbr = new BufferedReader(new InputStreamReader(System.in));
C:Scanner
Scannersc = new Scanner(System.in);
(3)输出语句的原理和如何使用字符流输出数据
A:原理
System.out.println("helloworld");
PrintStreamps = System.out;
ps.println("helloworld");
B:把System.out用字符缓冲流包装一下使用
BufferedWriterbw = new BufferedWriter(new OutputStreamWriter(System.out));
5:随机访问流(理解)
(1)可以按照文件指针的位置写数据和读数据。
(2)案例:
A:写数据
B:读数据
C:获取和改变文件指针的位置
6:合并流(理解)
(1)把多个输入流的数据写到一个输出流中。
(2)构造方法:
A:SequenceInputStream(InputStreams1, InputStream s2)
B:SequenceInputStream(Enumeration e)
7:序列化流(理解)
(1)可以把对象写入文本文件或者在网络中传输
(2)如何实现序列化呢?
让被序列化的对象所属类实现序列化接口。
该接口是一个标记接口。没有功能需要实现。
(3)注意问题:
把数据写到文件后,在去修改类会产生一个问题。
如何解决该问题呢?
在类文件中,给出一个固定的序列化id值。
而且,这样也可以解决×××警告线问题
8:Properties(理解)
(1)是一个集合类,Hashtable的子类
(2)特有功能
A:publicObject setProperty(String key,String value)
B:publicString getProperty(String key)
C:publicSet
(3)和IO流结合的方法
把键值对形式的文本文件内容加载到集合中
publicvoid load(Reader reader)
publicvoid load(InputStream inStream)
把集合中的数据存储到文本文件中
publicvoid store(Writer writer,String comments)
publicvoid store(OutputStream out,String comments)
10:NIO(了解)
(1)JDK4出现的NIO,对以前的IO操作进行了优化,提供了效率。但是大部分我们看到的还是以前的IO
(2)JDK7的NIO的使用
Path:与平台无关的路径。
Paths:包含了返回Path的静态方法。
publicstatic Path get(URI uri):根据给定的URI来确定文件路径。
Files:操作文件的工具类。提供了大量的方法,简单了解如下方法
publicstatic long copy(Path source,OutputStream out):复制文件
publicstatic Path write(Path path,Iterable lines,Charset cs,OpenOption... options):
把集合的数据写到文件。
//复制文件
Files.copy(Paths.get("Demo.java"),newFileOutputStream("Copy.Java"));
//把集合中的数据写到文件
List
list.add("hello");
list.add("world");
list.add("java");
Files.write(Paths.get("list.txt"),list, Charset.forName("gbk"));
4. 异常
4.1 异常概述:
异常就是Java程序在运行过程中出现的错误。
异常由来:问题也是现实生活中一个具体事务,也可以通过java 的类的形式进行描述,并封装成对象。其实就是Java对不正常情况进行描述后的对象体现。
4.2 异常分类图:
4.3 异常的体系
Throwable
|--Error 严重问题,我们不处理。
|--Exception
|--RuntimeException 运行期异常,我们需要修正代码
|--非RuntimeException编译期异常,必须处理的,否则程序编译不通过
异常分三类:
骑车去旅行:
Error:走到半路上,发生山路塌陷,或者出现了泥石流,这个问题很严重,不是班长能够立马解决的。
Exception:出门前,班长要看看车轮子以及车链子等是否还在
RuntimeException:在骑车的过程中,有好路不走,偏偏要走石子路
1,编译时异常
除了RuntimeException及其子类,Exception中所有的子类都是,这种异常必须要处理,要不编译通不过
2,运行时异常
RuntimeException及其子类都是,这种异常不用处理,编译会通过,不过这样的程序会有安全隐患,遇到这种异常是需要改代码的
3,严重错误问题
用Error进行描述,这个问题发生后,一般不编写针对代码进行处理,而是要对程序进行修正.通常都是由虚拟机抛出的问题
4.4 异常的处理:
A:JVM的默认处理
把异常的名称,原因,位置等信息输出在控制台,但是呢程序不能继续执行了。
B:自己处理
a:try...catch...finally
自己编写处理代码,后面的程序可以继续执行
b:throws
把自己处理不了的,在方法上声明,告诉调用者,这里有问题
4.5 finally
finally的特点
被finally控制的语句体一定会执行
特殊情况:在执行到finally之前jvm退出了(比如System.exit(0))
finally的作用
用于释放资源,在IO流操作和数据库操作中会见到
4.6 自定义异常
继承自Exception或者RuntimeException,只需要提供无参构造和一个带参构造即可
异常的注意实现
A:父的方法有异常抛出,子的重写方法在抛出异常的时候必须要小于等于父的异常
B:父的方法没有异常抛出,子的重写方法不能有异常抛出
C:父的方法抛出多个异常,子的重写方法必须比父少或者小
4.7 异常类
ConcurrentModificationException异常
并发修改异常
A:出现的现象
迭代器遍历集合,集合修改集合元素
B:原因
迭代器是依赖于集合的,而集合的改变迭代器并不知道。
C:解决方案
a:迭代器遍历,迭代器修改(ListIterator)
元素添加在刚才迭代的位置
b:集合遍历,集合修改(size()和get())
元素添加在集合的末尾
ArithmeticException数学运算异常
面试题
HashMap和Hashtable的区别:
1、HashMap是非线程安全的,HashTable是线程安全的。
2、HashMap的键和值都允许有null值存在,而HashTable则不行。
3、因为线程安全的问题,HashMap效率比HashTable的要高。
5.2 List,Set,Map等接口是否都继承子Map接口:不是!
5.3 Collection和Collections的区别
A:Collection是单列集合的顶层接口,有两个子接口List和Set
B:Collections是针对集合进行操作的工具类,可以对集合进行排序和查找等
5.4 编译期异常和运行期异常的区别?
编译期异常 必须要处理的,否则编译不通过
运行期异常 可以不处理,也可以处理
5.5 throw和throws的区别
throws
用在方法声明后面,跟的是异常类名
可以跟多个异常类名,用逗号隔开
表示抛出异常,由该方法的调用者来处理
throws表示出现异常的一种可能性,并不一定会发生这些异常
throw
用在方法体内,跟的是异常对象名
只能抛出一个异常对象名
表示抛出异常,由方法体内的语句处理
throw则是抛出了异常,执行throw则一定抛出了某种异常
5.6 final,finally,finalize的区别?
百度
5.7 如果catch里面有return语句,请问finally的代码还会执行吗?如果会,请问是在return前还是return后。
会,前。
5.8 面试题:
什么时候序列化?
如何实现序列化?
什么是反序列化?
对象序列化是将对象状态转换为可保持或传输的过程。一般的格式是与平台无关的二进制流,可以将这种二进制流持久保存在磁盘上,也可以通过网络将这种二进制流传输到另一个网络结点。
对象反序列化,是指把这种二进制流数据还原成对象。
java基础系列:
java基础(一)java语法
java基础(二)面向对象
java基础(三)继承/多态/接口
java基础(四)常用类/算法
java基础(五)集合/IO流/异常
java基础(六)多线程/设计模式
java基础(七)网络编程/反射/动态代理