*HashMap集合本身基于哈希表
* 它可以保证键的唯一性(Map都是针对键有效),对象作为键要保证重写了equals()方法
* HashMap
例子:
public static void main(String[] args) {
HashMap map = new HashMap();
Student s1 = new Student("西施", 27) ;
Student s2 = new Student("杨贵妃", 35) ;
Student s3 = new Student("王昭君", 30) ;
Student s4 = new Student("貂蝉",28) ;
Student s5 = new Student("西施", 27) ;
//添加元素
map.put(s1, "元朝") ;
map.put(s2, "宋朝") ;
map.put(s3, "唐朝") ;
map.put(s4, "清朝") ;
map.put(s5, "金") ;
Set set = map.keySet();
for(Student s : set) {
String value = map.get(s);
System.out.println(s.getName()+"---"+s.getAge()+"---"+value);
}
}
结果:
杨贵妃---35---宋朝
王昭君---30---唐朝
西施---27---金
貂蝉---28---清朝
*LinkedHashMap
*哈希表保证键的唯一性
*链接列表保证元素有序性(存储和取出一致)
例子:
public static void main(String[] args) {
LinkedHashMap map = new LinkedHashMap() ;
//添加元素
map.put("it001", "hello");
map.put("it002", "mysql");
map.put("it003", "world");
map.put("it004", "javaweb");
map.put("it001", "javaee");
Set set = map.keySet() ;
for(String key :set) {
String value = map.get(key) ;
System.out.println(key+"----"+value);
}
}
结果:
it001----javaee
it002----mysql
it003----world
it004----javaweb
*TreeMap基于红黑树结构的Map接口的实现
数据按一定的规则进行排序存储,自定义类作为键有两种排序方法:
1)自然排序(自定义类实现Comparable接口并且重写其中的compareTo方法
2)比较器排序,Comparator 重写compare方法
实例:
public static void main(String[] args) {
//创建一个TreeMap集合,使用比较器排序的方式
//匿名内部类的方式
TreeMap tm = new TreeMap(new Comparator() {
@Override
public int compare(Student s1, Student s2) {
//主要条件:年龄从小到大
int num =s1.getAge() -s2.getAge() ;
//年龄相同,不一定姓名一样
int num2 = num ==0 ? s1.getName().compareTo(s2.getName()): num ;
return num2 ;
}
} );
//创建学生对象
Student s1 = new Student("唐伯虎", 28) ;
Student s2 = new Student("杜甫", 35) ;
Student s3 = new Student("李白", 40) ;
Student s4 = new Student("李清照", 32) ;
Student s5 = new Student("唐伯虎", 28) ;
Student s6 = new Student("苏轼", 35) ;
//添加到集合中
tm.put(s1, "宋代") ;
tm.put(s2, "唐代") ;
tm.put(s3, "唐代") ;
tm.put(s4, "宋代") ;
tm.put(s5, "清代") ;
tm.put(s6, "清代") ;
//遍历
Set set = tm.keySet() ;
for(Student key :set) {
String value = tm.get(key) ;
System.out.println(key.getName()+"---"+key.getAge()+"---"+value);
}
}
结果:
唐伯虎---28---清代
李清照---32---宋代
杜甫---35---唐代
苏轼---35---清代
李白---40---唐代
* HashMap集合和Hashtable的区别?
* 共同点:都是map接口的实现类,都是基于哈希表的实现类
* HashMap集合线程不安全的类,不同步,执行效率高(允许键和值是null的)
* Hashtable集合线程安全的类,同步,执行效率低(不允许有null键和null值)
* 线程安全的类:
* StringBuffer :字符串缓冲区
* Vector :List集合
* Hashtable :Map集合的
*Collection和Collections的区别:
* Collection:顶层次单列集合的根接口,它是一个集合,是一个接口
* Collections:是针对集合操作的工具类,有一些功能:随机置换,集合里面的二分查找,将集合的元素进行反转
*
*集合的二分查找
* public static
* static T max(Collection coll):获取集合中的最大值
* public static void reverse(List list):将集合中的元素顺序反转
* public static void shuffle(List list):将集合中的元素打乱
* public static void sort(List
public static void main(String[] args) {
// 1. 创建两个集合:HashMap,ArrayList
HashMap hm = new HashMap();
ArrayList array = new ArrayList();
// 2.装牌
// 2.1 定义花色数组和点数数组
String[] colors = { "♥", "♠", "♣", "♦" };
String[] numbers = { "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2" };
// 从0开始编号,将编号和编号对应的牌都存储到HashMap集合中,同时往ArrayList单独存储编号
int index = 0;
// 拼接
for (String number : numbers) {
for (String color : colors) {
String poker = color.concat(number);
hm.put(index, poker);
array.add(index);
index++;
}
}
// 装小王和大王
hm.put(index, "小王");
array.add(index);
index++;
hm.put(index, "大王");
array.add(index);
// 不能++了,角标越界
// 洗牌
Collections.shuffle(array);
// System.out.println(array);
// 4)发牌
// 发的也是编号,为了保证牌有序,集合由TreeSet集合接收
TreeSet player1 = new TreeSet();
TreeSet player2 = new TreeSet();
TreeSet player3 = new TreeSet();
TreeSet diPai = new TreeSet();
// 有规律的:遍历ArrayList集合 使用普通for循环,获取到集合的元素
// 通过元素 % 人数 = 0 /1/2 /..
for (int x = 0; x < array.size(); x++) {
// 获取到每一个元素
if (x >= array.size() - 3) {
diPai.add(array.get(x));
} else if (x % 3 == 0) {
// 玩家1
player1.add(array.get(x));
} else if (x % 3 == 1) {
// 玩家2
player2.add(array.get(x));
} else if (x % 3 == 2) {
player3.add(array.get(x));
}
}
// 5)看牌 封装功能
lookPoker("玩家1", player1, hm);
lookPoker("玩家2", player2, hm);
lookPoker("玩家3", player3, hm);
lookPoker("底牌", diPai, hm);
}
public static void lookPoker(String name,TreeSet ts,
HashMap hm) {
System.out.print(name+"的牌是:");
//遍历TreeSet集合获取到每一个编号
for(Integer key :ts) {
//获取到编号,通过编号找牌(在HashMap中找)
String value = hm.get(key) ;
System.out.print(value+" ");
}
System.out.println();
}
*当程序出现一些问题的,可以是严重问题,可以是一种异常,将这些通常为Throwable
*Throwable 类是 Java 语言中所有错误或异常的超类
* Throwable
* error
* exception
异常:
* 编译时期异常:只要出现的不是运行时期异常,统称为编译时期 日期的文本格式---解析 java.util.Date类 型:ParseException:解析异常
* 编译时期异常:开发者必须处理!
* 运行时期异常:RuntimeException
* 编译通过了,但是开发者代码不严谨(NullPointerExceptino等等...)
异常的处理分为两种:
* 1)try...catch...finally (标准格式) :捕获异常
* 2)throws ... 抛出异常
*
*
*变形格式...
* try...catch...
* try...catch...catch...
* catch....
*
* try{
* 一些代码
* try里面的代码越少越好
* 代码包含了可能会出现问题的代码
* }catch(异常类 异常类对象){
* try出现异常了,描述的异常刚好就是catch的异常类,就会执行catch里面代码
* //处理异常
如何处理多个异常
* 两个或两个以上的异常的时候怎么办?
*
* try{
* 可能出现问题的代码
* }catch(异常类 对象名){
* 处理异常的代码
* }
*
*
* try{
* 可能出现问题的代码
* int[] arr = {1,2,3} ;
* Sop(arr[3]);
* int a = 10 ;
* int b =0 ;
* Sop(a/b) ;
*
*
* }catch(异常类名1 对象名1){
* //异常处理
* }catch(异常类名2 对象名2(){
*
* //异常处理
* }
Jdk7以后出现另一种方式处理多个异常
*
* try{
* 可能出现问题的代码;
* }catch(异常类名1 | 异常类名2 |... 对象名){
*
* 处理异常
* }
注意: catch中多个异常类属于同一个级别
*编译时期异常和运行时期异常的区别?
*
* 编译时期:开发者必须进行显示处理,不处理,编译不能通过,
* 运行时期异常:无需进行显示处理,可以像编译时期一样进行处理
*
*
* 处理异常的第二种方式:使用throws 抛出异常 (跟在方法的后面)
* xxx 返回值 方法名() throws 异常类名{
* }
* 标准格式 try{ ... }catch(异常类 对象){ // 异常处理 } 执行try里面的代码
* ,如果出现了问题,它会通过代码的问题创建一个异常对象,然后通过异常对象和catch里面的异常类是否一致
* 如果一致的情况,就会出现catch里面的代码,执行Throwable里面的方法
*
* public String getMessage() :消息字符串
* public String toString(): 异常的简短描述 ":
* ":由冒号和空格组成
*
* public void printStackTrace():返回值void 直接调用, 包含了消息字符串,还有": "
* 信息描述,具体出现异常的代码定位以及定位的源码上
*throw:表示也是抛出异常,抛出的一个异常对象 (throw new 异常类名() :匿名对象的方式)
*面试题:
* throws和throw的区别?
* throws:也是表示抛出异常,它后面跟的异常类名,并且可以多个异常类名中间逗号开
* 举例:
* public void show() throws IoException,ClassNotFoundException{...}
* 在方法上抛出,由调用者处理
* 它表示抛出异常的可能性
* throw:抛出的一个异常对象
* 在语句体中抛出的,由语句体进行处理
* 它表示抛出异常的肯定性
*try...catch...finally
* finally语句体是一定会执行的,除非是Jvm退出了
*
*面试题:
* 如果catch里面有return 语句,finally中的代码还会执行,是在return语句之前执行
测试:
public static void main(String[] args) {
System.out.println(getInt());
}
private static int getInt() {
int a ;
try {
a = 10 ;
System.out.println(a/0);
a = 20 ;
}catch(Exception e) {
a= 30 ;
return a ;
/**
* try的代码出现问题了,执行catch中的语句,30赋值a,
* return 30(已经形成了一个回路径)finally代码一定会执行(除非Jvm) a = 40 ,在fianlly外面
* 有return a: a记录回路径的那个a,返回30
*/
}finally {
//除非jvm退出了
a = 40 ;
}
return a;//30
}
结果:30
自定义异常类,两种方式
* 1)自定义一个类,这个继承自Exception
* 2)继承RuntimeException
异常中的注意事项:
* 子类继承父类的时候的注意事项
* 1)子类重写父类的方法的时候,子类的方法的抛出的异常必须要么是父类的方法异常一样,要么是父类方法异常的子类
* 2)子类重写父类方法的时候,如果父类中的这个方法没有抛出异常,那么子类重写的这个方法也不能抛出异常,只能try...catch
*public File(File parent, String child):根据一个file对象和一个文件路径来构造File实例
跟创建相关的功能:
* public boolean createNewFile():创建文件,当文件不存在的时候,创建此抽象路径下的文件
* public boolean mkdir():创建一个文件夹,如果文件夹存在,不创建
* public boolean mkdirs():创建文件夹,如果父目录不存在,会创建此目录
删除功能
* public boolean delete() :删除文件或者文件夹(目录不能是空的) :逐一删除文件或者目录的
* 如果创建一个文件/目录,没有写盘符的时候, 会创建在当前项目路径下
File 的重命名功能:
* public boolean renameTo(File dest)重新命名此抽象路径名表示的文件。
* 如果路径名一致的情况,那么只是重命名
* 如果两次路径名称不一致,那么不只是重命名,并且剪切
File类的判断功能(个人认为是重点)
* public boolean isDirectory():判断是否是文件夹
* public boolean isFile() :判断是否是文件
* public boolean canRead(): 是否可读
* public boolean canWriter():是否可写
* public boolean exists() :是否存在
* public boolean isHidden():是否是隐藏文件
File类的获取功能:
* public String getAbsolutePath():获取抽象文件的绝对路径
* public String getPath():获取相对路径的字符串
* public String getName()返回由此抽象路径名表示的文件或目录的名称
* public long length()返回由此抽象路径名表示的文件的长度。
* public long lastModified():文件最后一次被修改的时间(时间毫秒值)
File的高级功能
* public String[] list() :获取当前某个路径下的所有的文件夹以及文件名称的字符串数组
* public File[] listFiles() :获取当前某个路径下所有的文件夹以及文件的File数组
File的高级功能
public String[] list(FilenameFilter filter)
public File[] listFiles(FilenameFilter filter)
FilenameFilter:一个接口: 文件名称过滤器
boolean accept(File dir, String name)测试指定文件是否应该包含在某一文件列表中。
文件是否包含在文件列表中,取决于返回值,true;false表示不包含
IO:在设备和设备之间的一种数据传输!
* IO流的分类:
* 按流的方向分:
* 输入流: 读取文件 (e:\\a.txt):从硬盘上文件读取出来后输出这个文件的内容
* 输出流: 写文件:将e:\\a.txt 内容读出来--->写到f盘下
* 按数据的类型划分:
* 字节流
* 字节输入流:InputStream :读取字节
* 字节输出流:OutputStream :写字节
* 字符流
* 字符输入流:Reader :读字符
* 字符输出流:Writer :写字符
* 需求:在当项目下输出一个文件,fos.txt文件(文本文件)
* 只要文本文件,优先采用字符流,字符流在字节流之后出现的
* 使用字节流进行操作
* 无法创建字节输出流对象:OutputSteam :抽象类,不能实例化
* 又学习过File类,并且当前是对文件进行操作,子类:FileOutputSteam进行实例化
*
* File+InputStream
* File+OutputStream
* FileXXX (FileReader)
* FileXXX (FileWriter)
*
* 开发步骤:
* 1)创建字节输出流对象
* 2)写数据
* 3)关闭资源
关于字节输出流写数据的方法
* public void write(int b):一次写一个字节
* public void write(byte[] b) :一次写一个字节数组
* public void write(byte[] b, int off,int len):一次写一部分字节数组
问题:
* 写一些数据,这些数据并没有换行,如何实现换行的效果...
* 针对不同的操作系统,里面的换行符合不一样的
*
* windows: \r\n
* Linx:\n
* mac:\r
问题:如何末尾追加数据呢
* public FileOutputStream(File file, boolean append):指定为true,末尾追加数据
读数据方式:
* public abstract int read():一次读取一个字节
* public int read(byte[] b):一次读取一个字节数组 (读取实际的字节数)
应用实例:找图片然后读取写入到指定文件中
public static void main(String[] args) throws Exception {
File file = new File("e:\\");
File[] fl = file.listFiles();
if(fl != null) {
for(File f : fl) {
File f1 = f;
if(f.isFile()) {
if(f.getName().endsWith(".jpg")) {
System.out.println(f);
FileInputStream fis = new FileInputStream(f1);
FileOutputStream fos = new FileOutputStream("c.jpg");
byte[] bys = new byte[1024];
int len = 0;
while((len = fis.read(bys))!=-1) {
fos.write(bys, 0, len);
}
fos.close();
fis.close();
}
}
//System.out.println(f);
}
}
}
递归压缩文件夹并测试(解压还很迷):
package org.westos.dataoutputstream;
import java.io.*;
import java.util.zip.*;
public class CopyDemo {
private int k = 1; // 定义递归次数变量
private void zip(String zipFileName, File inputFile) throws Exception {
System.out.println("压缩中...");
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFileName));
BufferedOutputStream bo = new BufferedOutputStream(out);
zip(out, inputFile, inputFile.getName(), bo);
bo.close();
out.close(); // 输出流关闭
System.out.println("压缩完成");
}
private void zip(ZipOutputStream out, File f, String base, BufferedOutputStream bo) throws Exception { // 方法重载
if (f.isDirectory()) {
File[] fl = f.listFiles();
if (fl.length == 0) {
out.putNextEntry(new ZipEntry(base + "/")); // 创建zip压缩进入点base
System.out.println(base + "/");
}
for (int i = 0; i < fl.length; i++) {
zip(out, fl[i], base + "/" + fl[i].getName(), bo); // 递归遍历子文件夹
}
System.out.println("第" + k + "次递归");
k++;
} else {
out.putNextEntry(new ZipEntry(base)); // 创建zip压缩进入点base
System.out.println(base);
FileInputStream in = new FileInputStream(f);
BufferedInputStream bi = new BufferedInputStream(in);
int b;
while ((b = bi.read()) != -1) {
bo.write(b); // 将字节流写入当前zip目录
}
bi.close();
in.close(); // 输入流关闭
}
}
/**
* 测试
*
* @param args
*/
public static void main(String[] args) {
CopyDemo book = new CopyDemo();
try {
book.zip("D:\\FtpServer.zip", new File("D:\\FtpServer"));
} catch (Exception e) {
e.printStackTrace();
}
}
}
递归:只的是方法调用方法本身的一种现象
方法递归的三个必要条件:
* 1)方法递归必须有出条件
* 2)必须满足一些规律
* 3)一定要写方法
注意:构造方法不存在方法递归的
实例:不死神兔问题
public static void main(String[] args) {
int[] rabbit = new int[20]; //数组形式
rabbit[0] = 1;
for(int x = 1; x < rabbit.length; x++) {
if(x-2<0) {
rabbit[x] = rabbit[x-1];
}else {
rabbit[x] = rabbit[x-2]+rabbit[x-1];
}
int m = x + 1 ;
System.out.println("第"+m+"个月有不死神兔"+rabbit[x]+"对");
}
System.out.println("第20个月有"+undeadRabbit(20)+"对不死神兔");
}
public static int undeadRabbit(int x) { //方法递归
//int i = x-2;
if(x==1 || x==2) {
return 1;
}else {
return undeadRabbit(x-1)+undeadRabbit(x-2);
}
}
重点是Collection接口下的子接口以及实现类的存储模式以及特点,还有基于Map的存储模式和特点
重点掌握对于文件的读写,将会在后面的学习中大量应用