集合
1. List
1.1. ArrayList(常用)
内部基于数组实现的一个集合类。查询比较快,添加和删除相对比较慢;
不是同步的(存在线程安全问题);
遍历方式:
ArrayList bag = new ArrayList();
for(int i=0;i<bag.size();i++){
System.out.println(bag.get(i));
}
for (ArrayList ele : bag){
System.out.println(ele);
}
//使用迭代器遍历集合ArrayList bag获得一个迭代器
// 获得双向的迭代器
Iterator it = bag.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
while(iterator.hasPrevious()){
System.out.println(iterator.previous());
}
1.2. LinkedList
1、 内部是基于链表结构实现的。添加和删除比较快,查询相对ArrayList比较慢
2、 内部相对于ArrayList而言多了一些操作头和尾的方法
3、 可以充当队列,堆栈
4、 不是线程安全的(同步的)
这种一般记住一些常用的,然后可以去查看API。
2. Set
2.1. HashSet(任意类型)
1.不能够添加重复元素 hashCode 和 equals()
2.无序(不保证和添加和打印顺序一致)
3.添加任意类型
2.2. TreeSet(同类型)
1.无序:不保证(不记录)我们的添加顺序;
2.不重复:不能够添加重复元素
3.感觉内部存储有一定的顺序
4.不能存在不同的数据类型
注意:TreeSet一旦添加了第一个元素后就不能添加其它数据类型的元素了,只能添加相同数据类型的元素,除非将容器中所有的元素全部清空,才能添加新的数据类型的元素
虽然说TreeSet没有顺序,但其实内部还是有顺序的
1.TreeSet内部 是按照大小进行排序的,大小有对象与对象之间比较进行决定的
2.设计TreeSet之前:Java设计了一个接口Comparable接口,其中提供了对象之间比较的方法CompareTo
3.TreeSet会调用对象的CompareTo方法,比较对象,所以我们放入的对象需实现Comparable
如果采用的是自然排序调用对象的compareTo方法,如果返回0 表示相等;
大于且返回正数,升序排列 。大于且返回负数,降序排列 (测试得出结论)
3. Map
3.1. 基本结构
Map 接口
|-- TreeMap : 判断重复的规则和TreeSet一样
TreeMap中的键(key)要么是具有自然排序能力;或者TreeMap中提供一个比较器
如果key是自然或者定制排序,返回值是0表示,key是重复的,如果是正数,则按照key的升序排序,否则是降序
|-- HashMap : key判断键是否重复和HashSet判断重复一样: 1. hashCode 2.equals()
|-- HashTable : 就是一个线程安全的HashMap
|-- LinkedHashMap: 就是一个内部维护了一个链表的HashMap,可以保证存入和取出顺序
|-- Properties:特殊的HashTable,只不过key-value都是String类型,一般用来做
配置文件
3.2. 方法
1、 Collection values() 返回一个Map中的所有的value值 Collection集合
2、 Set keySet() 返回所有的key值的集合**(key是唯一的,所以返回的是Set集合)**
3、 Set entrySet() 返回所有的entry对象**(key是唯一的,所以返回的是Set集合)**
3.2.1 拿出数据
失败的方法
1、foreach 失败!
原因:Map和Iterable没有任何关系
2、普通for/ while / do-while 失败!
原因: Map中没有通过索引来获得数据的方法
正确的方法:
1、遍历方式一:get(Object key)
Map m = new HashMap();
Set keys = m.keySet(); // 先获得所有的key -> set
for (Object k : keys) {
System.out.println(k+"<---->"+m.get(k)); // 通过调用Object get(Object key) 获得对应的value
}
2、遍历方式二:entrySet()
Map m = new HashMap();
Set entrys = m.entrySet(); // 通过entrySet方法得到全部的Entry对象
for (Object en : entrys) {
// 需要把en强制转成 Entry类型
Entry e = (Entry)en;
System.out.println(e.getKey()+"--"+e.getValue()); // 遍历集合,依次取出数据
}
3.3. Map特点及使用场景选择
Key 唯一且无序【不保证添加顺序和打印顺序一致】
1.HashMap中k的值没有顺序,常用来做统计。 根据hashCode保存,jdk1.8以后hashMap源码 变了,底层优化了
表示当相同hash值相同的元素大于8个时候,存储结构会变成红黑树来存储,而之前是链表结构
2.LinkedHashMap它内部维护了一个链表,保持Key插入的顺序。迭代的时候,也是按照插入顺序迭代。
3.TreeMap的顺序是Key的自然顺序(如整数从小到大,默认是按键值的升序排序),也可以指定比较函数。Comparator
4.Hashtable与 HashMap类似,不同的是:它不允许记录的键或者值为null;它支持线程的同步、即任一时刻只有一个线程能写Hashtable,因此也导致了 Hashtable在写入时会比较慢。
注意:LinkedHashMap在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会 比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和值无关,而HashMap的遍历速度和他的容量有关
3.4. Map使用的选择
1、Map中,HashMap具有超高的访问速度,如果我们只是在Map 中插入、删除和定位元素,而无关线程安全或者同步问题,HashMap 是最好的选择。
2、如果考虑线程安全或者写入速度的话,可以使用HashTable,JDK8后建议使用ConcurrentHashMap替代HashTable,既能获取超高的访问速度,又能保证线程安全
3、如果想按怎么存的顺序怎么取,比如队列形式,排队,那么使用LinkedHashMap
4、如果需要让Map按照key进行升序或者降序排序,那就用TreeMap
3.5. Properties
3.5.1 特点
1、表示了一个持久的属性集。
2、放入Properties中的key-value都是String类
3、Properties中提供了特殊的存值和取值的方法,尽量不要用Map的方法
4、void list(PrintStream out) 简单理解: 此方法可以把Properties中的数据写入磁盘文件
5、void load(InputStream inStream) 简单理解: 可以把磁盘文件中的数据读取到Properties中
3.5.2 使用
Properties properties = new Properties();
properties.setProperty("username", "xw");
properties.setProperty("password", "123456");
PrintStream ps = new PrintStream("F:/user.txt");
properties.list(ps); // 写入磁盘文件
//-------------------------------------------//
FileInputStream fis = new FileInputStream("F:/user.txt")
properties.load(fis); // 读取到properties里面
String property = properties.getProperty("username");
System.out.println(property);
3.6. Collections工具类
使用方法:
ArrayList list = new ArrayList();
// 所有的数据填充到集合
Collections.addAll(list,1,2,3,4,5);
3.7. 示例:统计字符串中每个字符出现的次数
用Map来实现
void strCount() {
String str = "aabbbcccc";
Map<Character, Integer> map = new HashMap<>();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i); // 取出每一个字符
if(map.containsKey(c)){ // 如果已经存在就+1
map.put(c,map.get(c)+1);
}else {
map.put(c,1); // 如果之前不存在就设置出现了一次
}
}
System.out.println(map);
// 格式不对,用entrySet取出来格式化一下
Set<Map.Entry<Character, Integer>> entrySet = map.entrySet();
for (Map.Entry<Character, Integer> entry : entrySet) { System.out.println(entry.getKey()+"="+entry.getValue());
}
}
4. 文件File
4.1. 基本方法
创建对象:File(String pathname)
创建文件夹:mkdir(),如果路径不存在则异常,用 **mkdirs()**可以生成不存在的路径
创建文件:createNewFile()
isDirectory() 判断是否是一个目录
isFile() 判断是否是一个文件
exists() 测试此抽象路径名表示的文件或目录是否存在
list的一系列方法
File[] listRoots() 列出可用的文件系统根(操作系统上面的盘符)
eg:C:\ D:\ E:\
String[] list() 返回当前的文件夹对象下面一层的所有的文件(文件夹)的名字
eg:文件夹1 文件夹2 a.txt b.txt
File[] listFiles() 返回当前的文件夹对象下面一层的所有的文件(文件夹)(File对象的形式
eg:C:\文件夹1 C:\文件夹2 C:\a.txt C:\b.txt
4.2. 过滤器
自己写一个MyFilter实现类库的FilenameFilter接口,重写一个accept方法,书写自定义的过滤规则。
在调用list的时候传入实例化的MyFilter对象,之后返回的list就是一个符合规则的。
需要理解一下源码具体是怎么实现的:
5. IO流
5.1. 字节流
字节输入流:FileInputStream
主要是read()方法,没有参数的一次读取一个数据字节(不常用),有参数的可以自定义(中文会乱码,因为中文是两个字节表示的)
FileInputStream fis = new FileInputStream("cc.txt");
int len;//读取的字节的个数
byte[] arr = new byte[1024];//五个字节的数据,缓存在该数组的
while( (len = fis.read(arr)) != -1 ){
// 字节数组转为字符串(解码)
System.out.println(new String(arr,0,len) );
}
fis.close();
字节输出流:FileOutputStream
主要是write()方法,用完之后记得close()关闭流资源
// 创建一个字节输出流
FileOutputStream fos = new FileOutputStream("output.txt",true); // true表示追加append
// 调用方法,字符串转为字节数组(编码)
byte[] bytes = "abcde".getBytes();
fos.write(bytes);
fos.close();
拷贝一个图片
// 源文件
FileInputStream fis = new FileInputStream("source.jpg");
// 拷贝之后的文件
FileOutputStream fos = new FileOutputStream("D:/copy.jpg");
// 边读边写
byte[] bytes = byte[1024];
int len; // 记录每次读取的个数
while( (len = fis.read(bytes)) != -1){
fos.write(bytes,0,len);
}
// 先开后关
fos.close();
fis.close();
5.2. 字符流
文件输入流:FileReader
与字节不同的是这里是char[] 字节是byte[]
FileReader reader = new FileReader("D:/123.txt");
char[] cbuf = new char[3];
int len;
while( (len = reader.read(cbuf)) != -1 ){
System.out.println(new String(cbuf,0,len));
}
reader.close();
文件输出流:FileWriter
一个缓冲,需要刷新才能存数据进去
FileWriter writer = new FileWriter("write.txt");
writer.write("我是刚才写入磁盘的字符");
// 在此之前这样数据是存不进去的,需要刷新
write.flush();
write.close(); // 其实在关闭流的同时也刷新了的
5.3. 字节流和字符流的区别
1、操作的单位不一样,一个是字节byte,一个是字符char
2、操作中文的时候使用字符流更方便,字节流更广泛:文本、视频、音频、图片…
3、字符流中有可以直接写字符串的方法
4、字节输出流 : 程序 —> 磁盘文件 如果不关闭流也会写入
字符输出流 : 程序—>缓冲区—> 磁盘文件 如果不关闭流或者刷新缓冲区,不会写入文件
·字符输出流,关闭的时候会先刷新;
·关闭之后不能够再操作;
·刷新之后可以继续操作;
什么时候会用到刷新 : 写入的数据比较多,可以在中途手动调用刷新的方法提交数据
5.4. 转换流
当别人的接口需要的参数是字节流,而我们要操作的是字符流(有中文),就需要在方法体中将字节流转字符流。
字节流转为字符流
在创建此类的对象时候,构造方法中的数据来源是一个InputStream(字节输入流)
eg:输入的
FileInputStream fis = new FileInputStream("D:/a.txt");
// 传入字节输入流对象
InputStreamReader reader = new InputStreamReader(fis);
// 读字符流
char[] cbuf = new char[10];
int len;
while((len = reader.read(cbuf))!=-1){
System.out.println(new String(cbuf,0,len));
}
reader.close();
在创建此类的对象时候,构造方法中的数据输出是一个OutputStream(字节输出流)
eg:输出的
FileOutputStream fos = new FileOutputStream("D:/a.txt");
OutputStreamWriter writer = new OutputStreamWriter(fos);
writer.write("测试Hello World");
5.5. 缓冲流
空间换时间【效率】
FileInputStream fis = new FileInputStream("D:/a.txt");
// 转化为缓冲流
BufferedInputStream bis = new BufferedInputStream(fis);
byte[] bytes = new byte[1024];
int len;
while( (len = bis.read(bytes)) !=-1){
System.out.println(new String(bytes,0,len));
}
bis.close();
fis.cloes();
注意:如果数据量比较大用这个缓冲流比较好,但是如果数据量比较小,用缓冲流反而会比较慢 (例子:搬家打包衣服,如果衣服多,打包的多,就用缓冲流,如果只有一件衣服,一件也打包,就太麻烦了)
5.6. IO异常处理
针对上面那个拷贝图片的示例,如果值抛出异常而不处理,是不行的。
我们需要用try catch来解决,在catch中接收异常然后提示错误信息
最后一定都需要在finally中关闭流。
注意jdk特性
//自动关闭的流资源,必须是实现了AutoCloseable
try(需要自动关闭的流资源){
可能发生异常的代码块
}catch(){
捕获异常之后要做的处理
}
try(
FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(dest);
){
byte[] b = new byte[1024];
int len;
while((len = fis.read(b)) != -1){
fos.write(b,0,len);
}
}catch(Exception e){
e.printStackTrace();
}
6. TCP、UDP
URL(Uniform Resource Locator)是统一资源定位符,俗称请求网址。
URI(Uniform Resource Identifier) 是统一资源标识符,俗称请求资源路径。
http://localhost:8080/myweb/hello.html以上web地址
加粗部分+非加粗部分=URL。 非加粗部分=URI;