Java - 工具篇

  1. 异常:错误在我们编写程序的过程中会经常发生,包括编译期间和运行期间的错误(Throwable:有两个重要的子类:Exception和Error)。
    Java - 工具篇_第1张图片
    Java - 工具篇_第2张图片
    a、Error是程序无法处理的错误,表示运行应用程序中较严重问题。
    b、Exception是程序本身可以处理的异常。异常处理通常指针对这种类型异常的处理。
    c、非检查异常(Unchecked Exception):编译器不要求强制处。
    d、检查异常(Checked Exception):编译器要求必须处置的异常。
    Java - 工具篇_第3张图片
    Java - 工具篇_第4张图片
    Ps:finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,不管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的。
  2. 异常处理:在Java应用程序中,异常处理机制为:抛出异常、捕捉异常。
    Java - 工具篇_第5张图片
    a、打印错误信息:e.printStackTrace();
    b、try块后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块;如果没有try,catch or finally都无法单独使用;当然try也无法单独使用。
    c、异常父类必须放在子类的后面,否则CE,因为按照顺序下来,下面的子类异常就变成闲鱼了。
    Java - 工具篇_第6张图片
    d、一组try...catch...中,不能出现同类型的异常。
    e、推荐在 catch 最后都补上 Exception 类型。
    f、终止 finally 方法:箭头所标识的地方都不会被执行到。System.exit(非零值即可);
      i、System.exit(0)是将你的整个虚拟机里的内容都停掉了 ,而dispose()只是关闭这个窗口,但是并没有停止整个application exit() 。无论如何,内存都释放了!也就是说连JVM都关闭了,内存里根本不可能还有什么东西。
      ii、System.exit(0)是正常退出程序,而System.exit(1)或者说非0表示非正常退出程序。
      iii、System.exit(status)不管status为何值都会退出程序。和return 相比有以下不同点:return是回到上一层,而System.exit(status)是回到最上层。

    Java - 工具篇_第7张图片
    g、如果在finally中写return,不管try or catch中是否有return,最后都以finally的return为最终结果(不建议在finally中写return,否则失去把上面的try or catch的return屏蔽掉了)。
    Java - 工具篇_第8张图片
  3. throws
    - 可以通过throws声明将要抛出何种类型的异常,通过throw将产生的异常抛出。
    - 如果一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明抛出异常。
    - throws语句用在方法定义时声明该方法要抛出的异常类型。
    - 当方法抛出异常列表中的异常时,方法将不对这些类型及其子类类型的异常作处理,而抛向调用该方法的方法,由他去处理。
    - 当子类重写父类抛出异常的方法时,声明的异常必须是父类方法所声明异常的同类或子类。
    Java - 工具篇_第9张图片
    public class TryDemoThree {
    
    	public static void main(String[] args) {
    		
    		/*try {
    			int result = test();
    			System.out.println("one和two的商是:" + result);
    		} catch (ArithmeticException e) {
    			System.out.println("除数不允许为零");
    			e.printStackTrace();
    		}catch(InputMismatchException e){
    			System.out.println("请输入整数");
    			e.printStackTrace();
    		}*/
    		
    		try{
    			int result = test(); // 如果写的catch中的异常类型范围缺少了一些就会CE
    			System.out.println("one和two的商是:" + result);
    		}catch(ArithmeticException e){
    			
    		}catch(InputMismatchException e){
    			
    		}catch(Exception e){ 
    			
    		}
    		
    		// 因为Exception包含检查型异常,所以没有进行处理会CE,而 ArithmeticException,InputMismatchException 都是非检查型异常,所以不会CE
    		// 若调用的函数抛出的是非检查型异常,可以通过文档注释来获取提示
    		int result2=test(); //CE
    	}
    
    	/* 通过throws抛出异常时,针对可能出现的多种异常情况,解决方案:
    	 * 1、throws后面接多个异常类型,中间用逗号分隔
    	 * 2、throws后面接Exception
    	 * */
    	/**
    	 * 测试接收数据相除结果的方法
    	 * @return 两个接收数据的商
    	 * @throws ArithmeticException
    	 * @throws InputMismatchException
    	 */
    	/*public static int test() throws ArithmeticException,InputMismatchException{
    		Scanner input = new Scanner(System.in);
    		System.out.println("=====运算开始=====");
    		System.out.print("请输入第一个整数:");
    		int one = input.nextInt();
    		System.out.print("请输入第二个整数:");
    		int two = input.nextInt();
    		System.out.println("=====运算结束=====");
    		return one / two;
    	}*/
    
    	public static int test() throws Exception{
    		Scanner input = new Scanner(System.in);
    		System.out.println("=====运算开始=====");
    		System.out.print("请输入第一个整数:");
    		int one = input.nextInt();
    		System.out.print("请输入第二个整数:");
    		int two = input.nextInt();
    		System.out.println("=====运算结束=====");
    		return one / two;
    	}
    }

     

  4. throw & 自定义异常
    - throw用来抛出一个异常。
    - 例如:throw new IOException0;
    - throw 抛出的只能够是可抛出类Throwable或者其子类的实例对象。
    - 例如:throw new String(“出错啦”);是错误的。
    - 若在 main 方法 throws 抛出的时候就是抛给虚拟机了。
    - 所谓自定义异常,就是定义一个类,去继承Throwable类或者它的子类。

    作用:
    1、规避可能出现的风险。
    2、完成一些程序的逻辑。

    Java - 工具篇_第10张图片
    public class HotelAgeException extends Exception {
    	public HotelAgeException(){
    		super("18岁以下,80岁以上的住客必须由亲友陪同");
    	}
    }
    public class TryDemoFour {
    
    	public static void main(String[] args) {
    		try {
    			testAge();
    		} catch (HotelAgeException e) {
    			System.out.println(e.getMessage());
    			System.out.println("酒店前台工作人员不允许办理入住登记");
    		}catch(Exception e){
    			e.printStackTrace();
    		}
    	}
    
    	/* throw抛出异常对象的处理方案:
    	 * 1、通过try..catch包含throw语句--自己抛自己处理
    	 * 2、通过throws在方法声明出抛出异常类型--谁调用谁处理--调用者可以自己处理,也可以继续上抛
    	 *    Ps:此时可以抛出与throw对象相同的类型或者其父类,不能是其子类。
    	 * 3、若向上抛出和自己处理都存在的情况下,按照就近原则,优先选择自己处理
    	 */
    	/*public static void testAge() { // 描述酒店的入住规则:限定年龄,18岁以下,80岁以上的住客必须由亲友陪同
    		try {
    			System.out.println("请输入年龄:");
    			Scanner input = new Scanner(System.in);
    			int age = input.nextInt();
    			if (age < 18 || age > 80) {
    				throw new Exception("18岁以下,80岁以上的住客必须由亲友陪同");
    			} else {
    				System.out.println("欢迎入住本酒店");
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}*/
    	
    	public static void testAge() throws HotelAgeException { // 此时可以抛出与throw对象相同的类型或者其父类,不能是其子类。
    		System.out.println("请输入年龄:");
    		Scanner input = new Scanner(System.in);
    		int age = input.nextInt();
    		if (age < 18 || age > 80) {
    			//throw new ArithmeticException(); // 即使没有throws也不会CE,因为属于非检查型异常
    			//throw new Exception("18岁以下,80岁以上的住客必须由亲友陪同"); // 若没有throws会CE,因为里面包含检查型异常
    			throw new HotelAgeException();
    		} else {
    			System.out.println("欢迎入住本酒店");
    		}
    	}
    }

     

  5. 异常链
    - 有时候我们会捕获一个异常后在抛出另一个异常。
    - 顾名思义就是:将异常发生的原因一个传一个串起来,即把底层的异常信息传给上层,这样逐层抛出。
    - 操作:方案一:initCause(e); 或 方案二:通过在 new 异常(第一参数,e); 中的第二参数中,把 e 传过去即可。
    public class TryDemoFive {
    
    	public static void main(String[] args) {
    		try {
    			testThree();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    
    	public static void testOne() throws HotelAgeException {
    		throw new HotelAgeException();
    	}
    
    	public static void testTwo() throws Exception {
    		try {
    			testOne();
    		} catch (HotelAgeException e) {
    			throw new Exception("我是新产生的异常1",e);
    		}
    	}
    
    	public static void testThree() throws Exception {
    		try {
    			testTwo();
    		} catch (Exception e) {
    			// 方案一
    			Exception e1=new Exception("我是新产生的异常2");
    			e1.initCause(e);
    			throw e1;
    			
    			// 方案二
    //			throw new Exception("我是新产生的异常2",e);
    		}
    	}
    }

    Java - 工具篇_第11张图片
  6. Java - try、catch、finally(包含 return):点击打开链接
  7. Java常见异常类型及原因分析
    Java - 工具篇_第12张图片
    Java - 工具篇_第13张图片
    Java - 工具篇_第14张图片
    Java - 工具篇_第15张图片
    Java - 工具篇_第16张图片
    Java - 工具篇_第17张图片
    Java - 工具篇_第18张图片
  8. 包装类
    Java - 工具篇_第19张图片
    - Java中的包装类都是用 final 修饰的,是无法被继承的。
    - 除了 Boolean 和 Character 包装类是 extends Object 之外,其余的包装类都是 extends Number。
    - 包装类的默认值为null。
  9. 拆箱 & 装箱
    Java - 工具篇_第20张图片
    public class WrapTestOne {
    
    	public static void main(String[] args) {
    		//装箱:把基本数据类型转换成包装类
    		//1、自动装箱
    		int t1=2;
    		Integer t2=t1;
    		
    		//2、手动装箱
    		Integer t3=new Integer(t1);
    		
    		//测试
    		System.out.println("int类型变量t1="+t1);
    		System.out.println("Integer类型对象t2="+t2);
    		System.out.println("Integer类型对象t3="+t3);
    		System.out.println("*************************");
    		
    		//拆箱:把包装类转换成基本数据类型
    		//1、自动拆箱
    		int t4=t2;
    		
    		//2、手动拆箱
    		int t5=t2.intValue();
    		
    		//测试
    		System.out.println("Integer类型对象t2="+t2);
    		System.out.println("自动拆箱后,int类型变量t4="+t4);
    		System.out.println("手动拆箱后,int类型变量t5="+t5);
    		double t6=t2;
    		System.out.println("自动拆箱后,double类型变量t6="+t6);
    		t6=t2.doubleValue();
    		System.out.println("手动拆箱后,double类型变量t6="+t6);
    	}
    }
    
    Console:
    int类型变量t1=2
    Integer类型对象t2=2
    Integer类型对象t3=2
    *************************
    Integer类型对象t2=2
    自动拆箱后,int类型变量t4=2
    手动拆箱后,int类型变量t5=2
    自动拆箱后,double类型变量t6=2.0
    手动拆箱后,double类型变量t6=2.0
    public class WrapTestTwo {
    
    	public static void main(String[] args) {
    		//基本数据类型转换为字符串
    		int t1=2;
    		String t2=Integer.toString(t1);
    		
    		//测试
    		System.out.println("int类型转换为String类型对象t2="+t2);
    		System.out.println("********************************");
    		
    		//字符串转换为基本数据类型
    		//1、包装类的parse
    		int t3=Integer.parseInt(t2);
    		//2、包装类的valueOf 先将字符串转换为包装类,再通过自动拆箱完成基本类型转换
    		int t4=Integer.valueOf(t2);
    		
    		//测试
    		System.out.println("String类型转换为int类型变量t3="+t3);
    		System.out.println("String类型转换为int类型变量t4="+t4);
    	}
    }
    
    Console:
    int类型转换为String类型对象t2=2
    ********************************
    String类型转换为int类型变量t3=2
    String类型转换为int类型变量t4=2
    public class WrapperTest {
    
    	public static void main(String[] args) {
    
    		Integer one=new Integer(100);
    		Integer two=new Integer(100);
    		System.out.println("one==two的结果:"+(one==two));//1
    		
    		Integer three=100;//自动装箱
    		//等价于 Integer three=Integer.valueOf(100);
    		System.out.println("three==100的结果:"+(three==100));//2 自动拆箱,相当于两个int基本数据类型在做比较
    		
    		//Integer four=100;
    		Integer four=Integer.valueOf(100);
    		System.out.println("three==four的结果:"+(three==four));//3
    		
    		Integer five=200;
    		System.out.println("five==200的结果:"+(five==200));//4
    		
    		Integer six=200;
    		System.out.println("five==six的结果:"+(five==six));//5
    		
    		Double d1=Double.valueOf(100);
    		System.out.println("d1==100的结果:"+(d1==100));
    		
                    // 除了 Float、Double 包装类,其它的都可以应用对象常量池概念。
    		Double d2=Double.valueOf(100);
    		System.out.println("d1==d2的结果:"+(d1==d2));
    	}
    }
    
    Console:
    one==two的结果:false
    three==100的结果:true
    three==four的结果:true
    five==200的结果:true
    five==six的结果:false
    d1==100的结果:true
    d1==d2的结果:false

    注意:Integer.valueOf() 方法原理如图(若不在该数值范围内,走实例化路线-->new)(对于 Float、Double 包装类不适用这规则):
    Java - 工具篇_第21张图片

  10. 包装类型与基本数据类型
    Java - 工具篇_第22张图片
    Java - 工具篇_第23张图片
  11. 包装类及常用方法
    Java - 工具篇_第24张图片
    Java - 工具篇_第25张图片
    Java - 工具篇_第26张图片
    Java - 工具篇_第27张图片
    注意:Boolean 中 equals 比较的是值而不是址。
    Java - 工具篇_第28张图片
    Java - 工具篇_第29张图片
    Java - 工具篇_第30张图片
    Java - 工具篇_第31张图片
    Java - 工具篇_第32张图片
  12. 字符串(String)
    Java - 工具篇_第33张图片
    Java - 工具篇_第34张图片
    a、在 windows 系统下,安装eclipse编码为GBK;在 mac 系统下,安装eclipse编码为UTF-8。
    b、在UTF-8下,每个汉字占3个字节。
    c、汉字为负数是因为超过了128,溢出。
    d、UnsupportedEncodingException为不支持编码异常,在字符编码有问题时触发。
    e、字符串和byte数组间的相互转换 & 编码问题:GBK编码和UTF-8编码(图:UTF-8 IDE默认下的结果)
    /*
     getBytes(String charsetName): 使用指定的字符集将字符串编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
    
     getBytes(): 使用平台的默认字符集将字符串编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
    */
    
    public class StringDemo3 {
    
    	public static void main(String[] args) throws UnsupportedEncodingException {
    		
    		// 字符串和byte数组之间的相互转换
    		// 定义一个字符串
    		String str=new String("JAVA 编程 基础");
    		
    		// 将字符串转换为byte数组,并打印输出
    		byte[] arrs=str.getBytes("GBK");
    		for(int i=0;i

    Java - 工具篇_第35张图片
    f、字符串内存中的分配【★★★★★】
    Java - 工具篇_第36张图片
    栈:存放引用。
    常量池:存放常量。
    堆:存放new。

    g、字符串的不可变性【★★★★★】
    - 定义:字符串本身不发生变化,都是通过赋值来改变的。
    - 缺点:如果字符串比较复杂的话,会生成很多中间变量。
    - 常量池中完成:"..."+"..."、"..."+str
    Java - 工具篇_第37张图片
    Java - 工具篇_第38张图片

  13. 字符串(StringBuilder & StringBuffer)
    Java - 工具篇_第39张图片
    Java - 工具篇_第40张图片
    public class StringBuilderDemo1 {
    
    	public static void main(String[] args) {
    		
    		// 定义一个字符串"你好"
    		StringBuilder str=new StringBuilder("你好");
    		//在"你好"后面添加内容,将字符串变成"你好,imooc!"
    	    // str.append(',');
    	    // str.append("imooc!");
    	    // System.out.println("str="+str);
    		System.out.println("str="+str.append(',').append("imooc!"));
    
    		// 将字符串变成"你好,iMOOC!"
    		// 两种方式:
    		// 1、使用delete方法删除mooc,然后在插入MOOC
    		// System.out.println("替换后:"+str.delete(4, 8).insert(4, "MOOC"));
    		// 2、使用replace方法直接替换
    		System.out.println("替换后:"+str.replace(4, 8, "MOOC"));
    		
    		// 在字符串"你好,iMOOC"中取出"你好"并输出
    		System.out.println(str.substring(0,2));
    	}
    }

    Java - 工具篇_第41张图片
    Java - 工具篇_第42张图片
    a、在单线程下基本都使用StringBuilder,在多线程中才会考虑使用StringBuffer。

  14. 集合框架
    - Collection:类的对象。
    - Map:键值对。
    Java - 工具篇_第43张图片
    集合中的for循环删除对象时,千万注意:删除后,因为集合是动态增减的,但是for循环是定死了的,所以会出现越界或误删状况。所以,两种解决方法:
    a、如果满足情景需要时,删除第一个就break掉。
    b、把符合条件的都保存在一个新的集合里,用removeAll来进行删除。
  15. List(列表)
    Java - 工具篇_第44张图片
  16. ArrayList
    Java - 工具篇_第45张图片
    a、remove(Object obj):如果有多个的话,只会删除第一个遇到的obj,想要删除全部obj的话,用removeAll(Collection c)。
  17. Set:Set是元素无序并且不可以重复的集合,被称为集。
  18. HashSet
    Java - 工具篇_第46张图片
    @Override
    public String toString() {
    	return "[姓名:" + name + ", 年龄:" + month + ", 品种:" + species + "]";
    }
    
    @Override
    public int hashCode() {
    	final int prime = 31;
    	int result = 1;
    	result = prime * result + month;
    	result = prime * result + ((name == null) ? 0 : name.hashCode());
    	result = prime * result + ((species == null) ? 0 : species.hashCode());
    	return result;
    }
    
    @Override
    public boolean equals(Object obj) {
    	// 判断对象是否相等,相等则返回true,不用继续比较属性了
    	if(this==obj)
    		return true;
    	
    	// 判断obj是否是Cat类的对象
    	if(obj.getClass()==Cat.class){
    		Cat cat=(Cat)obj;
    		return cat.getName().equals(name)&&(cat.getMonth()==month)&&(cat.getSpecies().equals(species));
    	}
    	
    	return false;
    }

    a、自定义类在用Set集合去重时,需要在自定义类重写hashCode方法和equals方法,一般情况hashCode方法不需要修改。

  19. Iterator(迭代器)
    Java - 工具篇_第47张图片
    Ps:it.next()输出调用该对象的toString()方法(默认输出的对象是地址),可以重写该对象对应的类的toString()方法。
  20. 哈希表原理
    Java - 工具篇_第48张图片
    Ps:先通过hashCode计算放在对应的桶里,然后在该桶里通过equals判断是否存在。
  21. Map
    Java - 工具篇_第49张图片
  22. HashMap
    Java - 工具篇_第50张图片
    public class DictionaryDemo {
    
    	public static void main(String[] args) {
    		
    		Map animal=new HashMap();
    		System.out.println("请输入三组单词对应的注释,并存放到HashMap中");
    		Scanner console=new Scanner(System.in);
    		
    		// 添加数据
    		int i=0;
    		while(i<3){
    			System.out.println("请输入key值(单词):");
    			String key=console.next();
    			System.out.println("请输入value值(注释):");
    			String value=console.next();
    			animal.put(key, value);
    			i++;
    		}
    		
    		// 打印输出value的值(直接使用迭代器)
    		System.out.println("使用迭代器输出所有的value:");
    		Iterator it=animal.values().iterator();
    		while(it.hasNext()){
    			System.out.print(it.next()+"    ");
    		}
    		System.out.println();
    		
    		// 通过单词找到注释并输出
    		// 使用keySet方法
    		System.out.println("请输入要查找的单词:");
    		String strSearch=console.next();
    		// 1.取得keySet
    		Set keySet=animal.keySet();
    		// 2.遍历keySet
    		for(String key:keySet){
    			if(strSearch.equals(key)){
    				System.out.println("找到了!"+"键值对为:"+key+"-"+animal.get(key));
    				break;
    			}
    		}
    		
    		// 打印输出key和value的值
    		// 通过entrySet方法
    		System.out.println("通过entrySet方法得到key-value:");
    		Set> entrySet=animal.entrySet();
    		for(Entry entry:entrySet){
    			System.out.print(entry.getKey()+"-");;
    			System.out.println(entry.getValue());
    		}
    		System.out.println();
    	}
    }
    // 判断商品编号id是否存在
    if (goodsMap.containsKey(goodsId)) {
    	System.out.println("该商品编号已经存在!请重新输入!");
    	continue;
    }
    
    // 价格格式错误处理
    double goodsPrice = 0;
    try {
    	goodsPrice = console.nextDouble();
    } 
    catch (java.util.InputMismatchException e) {
    	System.out.println("商品价格的格式不正确,请输入数值型数据!");
    	console.next(); // 吸收上个价格的错误字符串
    	continue;
    }

     

  23. LinkList(实现堆栈、双端队列、双向列表)
    Java - 工具篇_第51张图片
    Java - 工具篇_第52张图片
    Java - 工具篇_第53张图片
    Java - 工具篇_第54张图片
    Java - 工具篇_第55张图片
    Java - 工具篇_第56张图片
    Java - 工具篇_第57张图片
    Java - 工具篇_第58张图片
  24. 线程
    a、进程的概念:进程是指可执行程序并存放在计算机存储器的一个指令序列,它是一个动态执行的过程。
    b、线程是比进程还要小的运行单位,一个进程包含多个线程。
    c、线程可以看做一个子程序。
    Java - 工具篇_第59张图片
    Ps:之所以看起来好像它们是同时运行是因为时间片单位很小的时候,当它们属于轮流运行时,看起来就像“同时运行”。
  25. Thread 类
    Java - 工具篇_第60张图片
    Java - 工具篇_第61张图片
  26. Runnable 接口
    a、只有一个方法run()。
    b、Runnable是Java中用以实现线程的接口。
    c、任何实现线程功能的类都必须实现该接口。
  27. 线程的创建
      - 创建一个Thread类,或者一个Thread子类的对象。
      - 创建一个实现Runnable接口的类的对象。
    a、通过继承Thread类的方式创建线程类,重写run()方法:
      i、线程.start() 只能被启动一次,再次启动的话不会报CE,但会报RE。
      ii、启动线程不是 run() 方法。
      iii、线程运行的结果能顺序、交错执行都是有可能的。
    class MyThread extends Thread{
    	public void run(){
    		System.out.println(getName()+"该线程正在执行!");
    	}
    }
    
    public class ThreadTest {
    
    	public static void main(String[] args) {
    		System.out.println("主线程1");
    		MyThread mt=new MyThread();
    		mt.start();//启动线程
    //		mt.start();
    		System.out.println("主线程2");
    	}
    }
    
    Console:
    主线程1
    主线程2
    Thread-0该线程正在执行!
    class MyThread extends Thread{
    	
    	public MyThread(String name){
    		super(name);
    	}
    	
    	public void run(){
    		for(int i=1;i<=10;i++){
    			System.out.println(getName()+"正在运行"+i);
    		}
    	}
    }
    
    public class ThreadTest {
    
    	public static void main(String[] args) {
    		MyThread mt1=new MyThread("线程1");
    		MyThread mt2=new MyThread("线程2");
    		mt1.start();
    		mt2.start();
    	}
    }
    
    Console:
    线程2正在运行1
    线程1正在运行1
    线程2正在运行2
    线程1正在运行2
    线程1正在运行3
    线程1正在运行4
    线程1正在运行5
    线程1正在运行6
    线程1正在运行7
    线程1正在运行8
    线程1正在运行9
    线程1正在运行10
    线程2正在运行3
    线程2正在运行4
    线程2正在运行5
    线程2正在运行6
    线程2正在运行7
    线程2正在运行8
    线程2正在运行9
    线程2正在运行10

    b、通过实现Runnable接口的方式创建(推荐):
    优点:为什么要实现Runnable接口?
      - Java不支持多继承。
      - 不打算重写Thread类的其他方法。
    class PrintRunnable implements Runnable {
    	@Override
    	public void run() {
    		int i = 1;
    		while (i <= 10)
    			System.out.println(Thread.currentThread().getName() + "正在运行" + (i++));
    	}
    }
    
    public class Test {
    
    	public static void main(String[] args) {
    		PrintRunnable pr = new PrintRunnable();
    		Thread t1 = new Thread(pr);
    		t1.start();
    		
    		PrintRunnable pr1 = new PrintRunnable();
    		Thread t2 = new Thread(pr1);
    		t2.start();
    	}
    }
    
    Console:
    Thread-0正在运行1
    Thread-1正在运行1
    Thread-0正在运行2
    Thread-1正在运行2
    Thread-0正在运行3
    Thread-1正在运行3
    Thread-0正在运行4
    Thread-1正在运行4
    Thread-0正在运行5
    Thread-1正在运行5
    Thread-0正在运行6
    Thread-1正在运行6
    Thread-0正在运行7
    Thread-1正在运行7
    Thread-0正在运行8
    Thread-1正在运行8
    Thread-0正在运行9
    Thread-1正在运行9
    Thread-0正在运行10
    Thread-1正在运行10
    class PrintRunnable implements Runnable {
    	@Override
    	public void run() {
    		int i = 1;
    		while (i <= 10)
    			System.out.println(Thread.currentThread().getName() + "正在运行" + (i++));
    	}
    }
    
    public class Test {
    
    	public static void main(String[] args) {
    		PrintRunnable pr = new PrintRunnable();
    		Thread t1 = new Thread(pr);
    		t1.start();
    		
    		Thread t2 = new Thread(pr);
    		t2.start();
    	}
    }
    
    Console:
    Thread-0正在运行1
    Thread-1正在运行1
    Thread-0正在运行2
    Thread-1正在运行2
    Thread-1正在运行3
    Thread-0正在运行3
    Thread-1正在运行4
    Thread-1正在运行5
    Thread-0正在运行4
    Thread-1正在运行6
    Thread-1正在运行7
    Thread-1正在运行8
    Thread-1正在运行9
    Thread-0正在运行5
    Thread-1正在运行10
    Thread-0正在运行6
    Thread-0正在运行7
    Thread-0正在运行8
    Thread-0正在运行9
    Thread-0正在运行10
    /* 模拟多线程共享资源 i */
    class PrintRunnable implements Runnable {
    	int i = 1;
    	
    	@Override
    	public void run() {
    		while (i <= 10)
    			System.out.println(Thread.currentThread().getName() + "正在运行" + (i++));
    	}
    }
    
    public class Test {
    
    	public static void main(String[] args) {
    		PrintRunnable pr = new PrintRunnable();
    		Thread t1 = new Thread(pr);
    		t1.start();
    		
    		Thread t2 = new Thread(pr);
    		t2.start();
    	}
    }
    
    Console:
    Thread-0正在运行1
    Thread-0正在运行3
    Thread-1正在运行2
    Thread-0正在运行4
    Thread-1正在运行5
    Thread-0正在运行6
    Thread-1正在运行7
    Thread-0正在运行8
    Thread-1正在运行9
    Thread-0正在运行10

     

  28. 线程的状态
    - 新建(New)
    - 可运行(Runnable)
    - 正在运行(Running)
    - 阻塞(Blocked)
    - 终止(Dead)
  29. 线程的生命周期
    Java - 工具篇_第62张图片
    a、正在运行->阻塞的情况与阻塞->可运行的情况的解决办法从上到下一一对应。
    b、stop() 方法已过期,这里是为了理解方便,所以才如此标注。
  30. sleep 方法
    Java - 工具篇_第63张图片
    a、暂停执行:阻塞状态。
    b、因为sleep到运行状态中间还有一些步骤要处理,所以如果遇到非常需要精确时间的应用时,会误差一点时间。
    c、sleep应用:定时刷新数据。
    class MyThread implements Runnable{
    
    	@Override
    	public void run() {
    		for(int i=1;i<=10;i++){
    			System.out.println(Thread.currentThread().getName()+"执行第"+i+"次!");
    			try {
    				Thread.sleep(1000);
    			} 
    			catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}	
    }
    
    public class SleepDemo {
    
    	public static void main(String[] args) {
    		MyThread mt=new MyThread();
    		Thread t=new Thread(mt);
    		t.start();
    		
    		Thread t1=new Thread(mt);
    		t1.start();
    	}
    }
    
    Console:
    Thread-0执行第1次!
    Thread-1执行第1次!
    Thread-0执行第2次!
    Thread-1执行第2次!
    Thread-0执行第3次!
    Thread-1执行第3次!
    Thread-0执行第4次!
    Thread-1执行第4次!
    Thread-0执行第5次!
    Thread-1执行第5次!
    Thread-0执行第6次!
    Thread-1执行第6次!
    Thread-0执行第7次!
    Thread-1执行第7次!
    Thread-0执行第8次!
    Thread-1执行第8次!
    Thread-0执行第9次!
    Thread-1执行第9次!
    Thread-0执行第10次!
    Thread-1执行第10次!

    Ps:一般情况,会交错执行,因为当线程-0运行一次后,休眠,这时,线程-1有很大概率抢占;依此类推。

  31. join 方法
    Java - 工具篇_第64张图片
    Java - 工具篇_第65张图片
    class MyThread extends Thread{
    	public void run(){
    		for(int i=1;i<=75;i++)
    		System.out.println(getName()+"正在执行"+i+"次!");
    	}
    }
    
    public class JoinDemo {
    
    	public static void main(String[] args) {
    		MyThread mt=new MyThread();
    		mt.start();
    		try {
    			mt.join(1);
    		} 
    		catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		
    		for(int i=1;i<=50;i++){
    			System.out.println("主线程运行第"+i+"次!");
    		}
    		System.out.println("主线程运行结束!");
    	}
    }
    
    Console:
    Thread-0正在执行1次!
    Thread-0正在执行2次!
    Thread-0正在执行3次!
    Thread-0正在执行4次!
    Thread-0正在执行5次!
    Thread-0正在执行6次!
    Thread-0正在执行7次!
    Thread-0正在执行8次!
    Thread-0正在执行9次!
    Thread-0正在执行10次!
    Thread-0正在执行11次!
    Thread-0正在执行12次!
    Thread-0正在执行13次!
    Thread-0正在执行14次!
    Thread-0正在执行15次!
    Thread-0正在执行16次!
    Thread-0正在执行17次!
    Thread-0正在执行18次!
    Thread-0正在执行19次!
    Thread-0正在执行20次!
    Thread-0正在执行21次!
    Thread-0正在执行22次!
    Thread-0正在执行23次!
    Thread-0正在执行24次!
    Thread-0正在执行25次!
    Thread-0正在执行26次!
    Thread-0正在执行27次!
    Thread-0正在执行28次!
    Thread-0正在执行29次!
    Thread-0正在执行30次!
    Thread-0正在执行31次!
    Thread-0正在执行32次!
    Thread-0正在执行33次!
    Thread-0正在执行34次!
    Thread-0正在执行35次!
    Thread-0正在执行36次!
    Thread-0正在执行37次!
    Thread-0正在执行38次!
    Thread-0正在执行39次!
    Thread-0正在执行40次!
    Thread-0正在执行41次!
    Thread-0正在执行42次!
    Thread-0正在执行43次!
    Thread-0正在执行44次!
    Thread-0正在执行45次!
    Thread-0正在执行46次!
    Thread-0正在执行47次!
    Thread-0正在执行48次!
    Thread-0正在执行49次!
    Thread-0正在执行50次!
    Thread-0正在执行51次!
    Thread-0正在执行52次!
    Thread-0正在执行53次!
    Thread-0正在执行54次!
    Thread-0正在执行55次!
    Thread-0正在执行56次!
    Thread-0正在执行57次!
    Thread-0正在执行58次!
    主线程运行第1次!
    Thread-0正在执行59次!
    主线程运行第2次!
    主线程运行第3次!
    Thread-0正在执行60次!
    主线程运行第4次!
    Thread-0正在执行61次!
    主线程运行第5次!
    主线程运行第6次!
    主线程运行第7次!
    主线程运行第8次!
    主线程运行第9次!
    主线程运行第10次!
    主线程运行第11次!
    主线程运行第12次!
    主线程运行第13次!
    主线程运行第14次!
    Thread-0正在执行62次!
    主线程运行第15次!
    主线程运行第16次!
    主线程运行第17次!
    主线程运行第18次!
    主线程运行第19次!
    主线程运行第20次!
    主线程运行第21次!
    主线程运行第22次!
    主线程运行第23次!
    主线程运行第24次!
    主线程运行第25次!
    主线程运行第26次!
    Thread-0正在执行63次!
    主线程运行第27次!
    Thread-0正在执行64次!
    主线程运行第28次!
    Thread-0正在执行65次!
    主线程运行第29次!
    Thread-0正在执行66次!
    主线程运行第30次!
    Thread-0正在执行67次!
    主线程运行第31次!
    Thread-0正在执行68次!
    主线程运行第32次!
    主线程运行第33次!
    主线程运行第34次!
    主线程运行第35次!
    主线程运行第36次!
    主线程运行第37次!
    主线程运行第38次!
    主线程运行第39次!
    主线程运行第40次!
    主线程运行第41次!
    主线程运行第42次!
    主线程运行第43次!
    主线程运行第44次!
    主线程运行第45次!
    主线程运行第46次!
    主线程运行第47次!
    Thread-0正在执行69次!
    主线程运行第48次!
    Thread-0正在执行70次!
    主线程运行第49次!
    Thread-0正在执行71次!
    主线程运行第50次!
    Thread-0正在执行72次!
    主线程运行结束!
    Thread-0正在执行73次!
    Thread-0正在执行74次!
    Thread-0正在执行75次!

     

  32. 线程的优先级
    a、Java为线程类提供了10个优先级。
    b、优先级可以用整数1-10表示,超过范围会抛出异常。
    c、主线程默认优先级为5。
    d、不一定优先级高的线程优先执行,具体看环境:操作系统的规则 + CPU运行方式。
    e、优先级常量
      - MAXPRIORITY:线程的最高优先级10
      - MIN_PRIORITY:线程的最低优先级1
      - NORM_PRIORITY:线程的默认优先级5
    Java - 工具篇_第66张图片
    class MyThread extends Thread{
    	private String name;
    	
    	public MyThread(String name){
    		this.name=name;
    	}
    	
    	public void run(){
    		for(int i=1;i<=50;i++){
    			System.out.println("线程"+name+"正在运行"+i);
    		}
    	}
    }
    
    public class PriorityDemo {
    
    	public static void main(String[] args) {
    		//获取主线程的优先级
    		int mainPriority=Thread.currentThread().getPriority();
    		//System.out.println("主线程的优先级为:"+mainPriority);
    		MyThread mt1=new MyThread("线程1");
    		MyThread mt2=new MyThread("线程2");
    		//mt1.setPriority(10);
    		mt1.setPriority(Thread.MAX_PRIORITY);
    		mt2.setPriority(Thread.MIN_PRIORITY);
    		mt2.start();
    		mt1.start();
    		//System.out.println("线程1的优先级为:"+mt1.getPriority());
    	}
    }

     

  33. 多线程运行问题
    - 各个线程是通过竞争CPU时间而获得运行机会的。
    - 各线程什么时候得到CPU时间,占用多久,是不可预测的。
    - 一个正在运行着的线程在什么地方被暂停是不确定的。
  34. 线程的同步(互斥)
    a、一个线程访问一个对象中的synchronized(this)同步代码块时,其他试图访问该对象的线程将被阻塞。
    b、当一个线程访问对象的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该对象中的非synchronized(this)同步代码块。
    Java - 工具篇_第67张图片
    Java - 工具篇_第68张图片
    package com.imooc.bank;
    
    public class Bank {
    	private String account;// 账号
    	private int balance;// 账户余额
    
    	public Bank(String account, int balance) {
    		this.account = account;
    		this.balance = balance;
    	}
    
    	public String getAccount() {
    		return account;
    	}
    
    	public void setAccount(String account) {
    		this.account = account;
    	}
    
    	public int getBalance() {
    		return balance;
    	}
    
    	public void setBalance(int balance) {
    		this.balance = balance;
    	}
    
    	@Override
    	public String toString() {
    		return "Bank [账号:" + account + ", 余额:" + balance + "]";
    	}
    
    	// 存款
    	public synchronized void saveAccount() {
    
    		// 获取当前的账号余额
    		int balance = getBalance();
    		try {
    			Thread.sleep(1000);
    		} 
    		catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		// 修改余额,存100元
    		balance += 100;
    		// 修改账户余额
    		setBalance(balance);
    		// 输出存款后的账户余额
    		System.out.println("存款后的账户余额为:" + balance);
    	}
    
    	public void drawAccount() {
    		synchronized (this) {
    			// 在不同的位置处添加sleep方法
    			// 获得当前的帐户余额
    			int balance = getBalance();
    			// 修改余额,取200
    			balance = balance - 200;
    			try {
    				Thread.sleep(1000);
    			} 
    			catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			// 修改帐户余额
    			setBalance(balance);
    			System.out.println("取款后的帐户余额:" + balance);
    		}
    	}
    }
    package com.imooc.bank;
    //取款
    public class DrawAccount implements Runnable{
    	Bank bank;
    	public DrawAccount(Bank bank){
    		this.bank=bank;
    	}
    	@Override
    	public void run() {
    		bank.drawAccount();
    	}
    }
    
    
    package com.imooc.bank;
    //存款
    public class SaveAccount implements Runnable{
    	Bank bank;
    	public SaveAccount(Bank bank){
    		this.bank=bank;
    	}
    	public void run(){
    		bank.saveAccount();
    	}
    }
    package com.imooc.bank;
    
    public class Test {
    
    	public static void main(String[] args) {
    		// 创建帐户,给定余额为1000
    		Bank bank=new Bank("1001",1000);
    		//创建线程对象
    		SaveAccount sa=new SaveAccount(bank);
    		DrawAccount da=new DrawAccount(bank);
    		Thread save=new Thread(sa);
    		Thread draw=new Thread(da);
    		save.start();
    		draw.start();
    		try {
    			// 不分先后顺序,取决于(同步 + 上面的start()顺序)
    			draw.join();
    			save.join();
    		} 
    		catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println(bank);
    	}
    }
    
    Console:
    Bank [账号:1001, 余额:1000]
    存款后的账户余额为:1100
    取款后的帐户余额:900

     

  35. 线程间的通信
    - wait)方法:中断方法的执行,使线程等待。
    - notify()方法:唤醒处于等待的某一个线程,使其结束等待。
    - nofifyAll()方法:唤醒所有处于等待的线程,使它们结束等待。
    package com.imooc.queue;
    
    public class Consumer implements Runnable{
    	Queue queue;
    	
    	Consumer(Queue queue){
    		this.queue=queue;
    	}
    
    	@Override
    	public void run() {
    		while(true){
    			queue.get();
    			try {
    				Thread.sleep(1000);
    			} 
    			catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    }
    
    
    package com.imooc.queue;
    
    public class Producer implements Runnable{
    	Queue queue;
    	
    	Producer(Queue queue){
    		this.queue=queue;
    	}
    
    	@Override
    	public void run() {
    		int i=0;
    		while(true){
    			queue.set(i++);
    			try {
    				Thread.sleep(1000);
    			} 
    			catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    }
    
    
    package com.imooc.queue;
    
    public class Test {
    
    	public static void main(String[] args) {
    		Queue queue=new Queue();
    		new Thread(new Producer(queue)).start();
    		new Thread(new Consumer(queue)).start();
    	}
    }
    package com.imooc.queue;
    
    public class Queue {
    	private int n;
    	
    	public synchronized int get() {
    		System.out.println("消费:"+n);
    		return n;
    	}
    
    	public synchronized void set(int n) {
    		System.out.println("生产:"+n);
    		this.n = n;
    	}
    }


    Java - 工具篇_第69张图片
    Ps:会发生生产了没有进行消费等不想看到的状况。
     

    package com.imooc.queue;
    
    public class Queue {
    	private int n;
    	boolean flag=false;
    	
    	public synchronized int get() {
    		if(!flag){
    			try {
    				wait();
    			} 
    			catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    		System.out.println("消费:"+n);
    		flag=false; // 消费完毕,容器中没有数据
    		notifyAll(); // 干脆全部唤醒,反正有flag作控制;如果不唤醒,可能会发生死锁
    		return n;
    	}
    
    	public synchronized void set(int n) {
    		if(flag){
    			try {
    				wait();
    			} 
    			catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    		System.out.println("生产:"+n);
    		this.n = n;
    		flag=true; // 生产完毕,容器中已经有数据
    		notifyAll();
    	}
    }

    Java - 工具篇_第70张图片
    Ps:如果不加 notifyAll() 发生死锁。
    Java - 工具篇_第71张图片
    Ps:成功~

  36. 输出流
    Java - 工具篇_第72张图片
    a、流就是指一连串流动的字符,以先进先出的方式发送信息的通道。
  37. 输入流
    Java - 工具篇_第73张图片
    a、文件输入——读
    b、文件输出——写
  38. File 类
    Q:什么是文件?
    A:文件可认为是相关记录或放在一起的数据的集合。在Java中,使用java.io.File类对文件进行操作。
    package com.imooc.file;
    
    import java.io.File;
    import java.io.IOException;
    
    public class FileDemo {
    
    	public static void main(String[] args) {
    		// 创建 File 对象
    		File file1=new File("c:\\imooc\\io\\score.txt"); // 方法1
    		File file2=new File("c:\\imooc","io\\score.txt"); // 方法2
    		File file3=new File("c:\\imooc"); // 方法3
    		File file4=new File(file3,"c:\\imooc");
    		
    		// 判断是文件 or 目录,返回 false 的两种情况:
    		// 1、字面意思,非我族类
    		// 2、路径不存在
    		System.out.println("is 目录:"+file4.isDirectory());
    		System.out.println("is 文件:"+file4.isFile());
    		
    		// 创建目录
    		File file5=new File("c:\\imooc\\set\\HashSet");
    		File file6=new File("c:\\imooc\\set\\HashSet\\asd.txt");
    		if(!file5.exists()) 
    		{
    //			file5.mkdir(); // 失败,只能创建单级目录
    			file5.mkdirs(); // 可创建多级目录
    			file6.mkdirs(); // asd.txt 是目录不是文件
    		}
    		
    		// 创建文件
    		File file7=new File("c:\\imooc\\set\\HashSet\\abc");
    		if(!file7.exists())
    		{
    			try {
    				file7.createNewFile(); // abc 是一个无后缀名的文件
    			} 
    			catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    }

    a、Windows目录“\\”(因为“\”转义字符,所以多加一个);Linux目录“/”即可。

  39. 字节流
    - 字节输入流InputStream
    - 字节输出流OutputStream
    Java - 工具篇_第74张图片
    Java - 工具篇_第75张图片
  40. FileInputStream
    a、从文件系统中的某个文件中获得输入字节。
    b、用于读取诸如图像数据之类的原始字节流。
    Java - 工具篇_第76张图片
    public class FileInputDemo1 {
    
    	public static void main(String[] args) {
    		// 创建一个FileInputStream对象
    		try {
    			FileInputStream fis=new FileInputStream("imooc.txt");
    			// 常规写
    //			int n=fis.read();
    //			while(n!=-1){
    //				System.out.print((char)n);
    //				n=fis.read();
    //			}
    			
    			// 简写
    			int n=0;
    			while((n=fis.read())!=-1){
    				System.out.print((char)n);
    			}
    			
    			fis.close();
    		}
    		catch (FileNotFoundException e) {
    			e.printStackTrace();
    		} 
    		catch(IOException e){
    			e.printStackTrace();
    		}
    	}
    }
    public class FileInputDemo2 {
    
    	public static void main(String[] args) {
    		// 创建一个FileInputStream对象
    		try {
    			FileInputStream fis = new FileInputStream("imooc.txt");
    			byte[] b=new byte[100];
    			fis.read(b,2,5); // 从下标为2个开始存储,一共存储5个字符
    			System.out.println(new String(b)); // 如图
    			fis.close();
    		} 
    		catch (FileNotFoundException e) {
    			e.printStackTrace();
    		} 
    		catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }

  41. FileOutputStream
    Java - 工具篇_第77张图片
    public class FileOutputDemo {
    
    	public static void main(String[] args) {
    		FileOutputStream fos;
    		FileInputStream fis;
    		try {
    			fos = new FileOutputStream("imooc.txt",true); // 第二参数,是否追加,默认为重新覆盖
    			fis = new FileInputStream("imooc.txt");
    			// 可能有编码问题,但是不影响写入读取的最终结果
    			fos.write(50);
    			fos.write('a');
    			System.out.println(fis.read());
    			System.out.println((char)fis.read());
    			fos.close();
    			fis.close();
    		} 
    		catch (FileNotFoundException e) {
    			e.printStackTrace();
    		} 
    		catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }
    /* 图片Copy */
    public class FileOutputDemo1 {
    
    	public static void main(String[] args) {
    		// 文件拷贝
    		try {
    			FileInputStream fis=new FileInputStream("happy.gif");
    			FileOutputStream fos=new FileOutputStream("happycopy.gif");
    			
    			int n=0;
    			byte[] b=new byte[1024];
    			while((n=fis.read(b))!=-1){
    //				fos.write(b); // 之前都会填充满,最后一次会在实际大小中增加了 1024-最后一次实际内容 的大小
    				fos.write(b,0,n); // 第三个参数 n 代表:实际大小,这样就不会造成空间的浪费
    			}
    			fis.close();
    			fos.close();
    		} 
    		catch (FileNotFoundException e) {
    			e.printStackTrace();
    		}
    		catch(IOException e){
    			e.printStackTrace();
    		}
    	}
    }

     

  42. BufferedInputStream & BufferedOutputStream
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class BufferedDemo {
    
    	public static void main(String[] args) {
    		try {
    			FileOutputStream fos=new FileOutputStream("imooc.txt");
    			BufferedOutputStream bos=new BufferedOutputStream(fos);
    			FileInputStream fis=new FileInputStream("imooc.txt");
    			BufferedInputStream bis=new BufferedInputStream(fis);
    			
    			// 测试使用BufferedIO效率更高
    			long startTime=System.currentTimeMillis();
    			
    			bos.write(50);
    			bos.write('a');
    			bos.flush();
    			
    			System.out.println(bis.read());
    			System.out.println((char)bis.read());
    			long endTime=System.currentTimeMillis();
    			System.out.println(endTime-startTime);
    			
    			fos.close();
    			bos.close();
    			fis.close();
    			bis.close();
    		} 
    		catch (FileNotFoundException e) {
    			e.printStackTrace();
    		}
    		catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }

     

  43. 字符流
    - 字符输入流Reader。
    - 字符输出流Writer。
    Java - 工具篇_第78张图片
    Java - 工具篇_第79张图片
  44. Java - 字节流 & 字符流区别 点击打卡链接
  45. 缓冲流
    - 缓冲输入流BufferedInputStream。
    - 缓冲输出流BufferedOutputStream。
    a、缓冲区如果满了会自动执行写操作,如果没满,需要强制 flush() 方法 or close() 方法才执行写操作。
  46. 字节字符转换流(附:缓冲区)
    - InputStreamReader。
    - OutputStreamWriter。
    /* 字节字符转换流 + 缓冲区 */
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    
    public class ReaderDemo {
    
    	public static void main(String[] args) {
    		try {
    			FileInputStream fis=new FileInputStream("imooc.txt");
    			InputStreamReader isr=new InputStreamReader(fis,"GBK"); // 不写编码方式,默认为IDE的编码;用什么编码方式读取,下面就对应用什么编码方式写入
    			BufferedReader br=new BufferedReader(isr);
    			FileOutputStream fos=new FileOutputStream("imooc1.txt");
    			OutputStreamWriter osw=new OutputStreamWriter(fos,"GBK");
    			BufferedWriter bw=new BufferedWriter(osw);
    			
    			int n=0;
    			char[] cbuf=new char[10];
    			
    //		    while((n=isr.read())!=-1){ // 这里的 n 代表实际内容
    //		    	   System.out.print((char)n);
    //		    }
    			
    //			while((n=isr.read(cbuf))!=-1){ // 这里的 n 代表实际内容大小
    //				String s=new String(cbuf,0,n);
    //				System.out.print(s);
    //			}
    			
    			while((n=br.read(cbuf))!=-1){
    				//String s=new String(cbuf,0,n);
    				bw.write(cbuf, 0, n);
    			}
    			bw.flush();
    			
    			// 注意关闭顺序
    			br.close();
    			bw.close();
    			isr.close();
    			osw.close();
    			fis.close();
    			fos.close();
    		} 
    		catch (FileNotFoundException e) {
    			e.printStackTrace();
    		}
    		catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }

    Ps:FileInputStream + InputStreamReader == FileReader,依此类推。

  47. 对象序列化
    - 序列化:把Java对象转换为字节序列的过程。
    - 反序列化:把字节序列恢复为Java对象的过程。

    - 对象输入流ObjectInputStream。
    - 对象输出流ObjectOutputStream。

    步骤:
    - 创建一个类,继承Serializable接口。
    - 创建对象。
    - 将对象写入文件。
    - 从文件读取对象信息。
    import java.io.Serializable;
    
    public class Goods implements Serializable{
    	private String goodsId;
    	private String goodsName;
    	private double price;
    	
    	public Goods(String goodsId,String goodsName,double price){
    		this.goodsId=goodsId;
    		this.goodsName=goodsName;
    		this.price=price;
    	}
    	// getters/setters...
    	
    	@Override
    	public String toString() {
    		return "商品信息 [编号:" + goodsId + ", 名称:" + goodsName 
    				+ ", 价格:" + price + "]";
    	}
    }
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    
    public class GoodsTest {
    
    	public static void main(String[] args) {
    		// 定义Goods类的对象
    		Goods goods1 = new Goods("gd001", "电脑", 3000);
    		try {
    			FileOutputStream fos = new FileOutputStream("imooc.txt"); 
    			ObjectOutputStream oos = new ObjectOutputStream(fos);
    			FileInputStream fis = new FileInputStream("imooc.txt");
    			ObjectInputStream ois = new ObjectInputStream(fis);
    			
    			// 将Goods对象信息写入文件,如果文件里面是乱码不要紧,只要读出来显示正常即可
    			oos.writeObject(goods1);
    			oos.writeBoolean(true);
    			oos.flush();
    			
    			// 读对象信息
    			// 注意:读顺序和写顺序符合先进先出规则,如果把readBoolean方法放首先会RE,因为第一个是对象而不是boolean
    			Goods goods = (Goods) ois.readObject();
    			System.out.println(goods);
    			System.out.println(ois.readBoolean());
    
    			fos.close();
    			oos.close();
    			fis.close();
    			ois.close();
    		} 
    		catch (ClassNotFoundException e) {
    			e.printStackTrace();
    		}
    		catch (FileNotFoundException e) {
    			e.printStackTrace();
    		} 
    		catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }
    a)序列化时,只对对象的状态进行保存,而不管对象的方法;
    b)当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
    c)当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;
    d)并非所有的对象都可以序列化,,至于为什么不可以,有很多原因了,比如:
         1.安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行rmi传输  等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的。
         2. 资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是没有必要这样实现。
  48. 绝对路径 & 相对路径
    - 绝对路径:是从盘符开始的路径。
    - 相对路径:是从当前路径开始的路径。
  49. 待更新...

你可能感兴趣的:(Java,异常,字符串,线程,IO流,#,Java)