java学习总结(二)

HashMap

 *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---清朝

LinkedList

 *LinkedHashMap :是Map接口基于哈希表和链接列表实现的
 *哈希表保证键的唯一性

 *链接列表保证元素有序性(存储和取出一致)

  例子:

                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

 *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---唐代

Hashtable

 *        HashMap集合和Hashtable的区别?
 *        共同点:都是map接口的实现类,都是基于哈希表的实现类
 *        HashMap集合线程不安全的类,不同步,执行效率高(允许键和值是null的)
 *        Hashtable集合线程安全的类,同步,执行效率低(不允许有null键和null值)
 *    线程安全的类:
 *            StringBuffer :字符串缓冲区    
 *            Vector         :List集合

 *            Hashtable     :Map集合的

Collections工具类及其常用方法

 *Collection和Collections的区别:
 *        Collection:顶层次单列集合的根接口,它是一个集合,是一个接口
 *        Collections:是针对集合操作的工具类,有一些功能:随机置换,集合里面的二分查找,将集合的元素进行反转
 *
 *集合的二分查找
 * public static int binarySearch(List list, T key)
 * static  T max(Collection coll):获取集合中的最大值
 * public static void reverse(List list):将集合中的元素顺序反转
 * public static void shuffle(List list):将集合中的元素打乱
 * public static void sort(List 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

File类

 表示文件或者目录的路径的抽象表现形式.  IO流就是对文件进行操作的
 *public File(String pathname):表示pathname的抽象路径表现的形式 (开发中使用这种方式)
 *public File(String parent,String child) : 根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例

 *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      FileInputStream/FileOutputStream  

 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的存储模式和特点

        重点掌握对于文件的读写,将会在后面的学习中大量应用

你可能感兴趣的:(java学习总结(二))