03.常用的API

顶级父类Object:

Object的常用方法:

toString() : Object中的默认实现:打印对象的地址值

​ 子类student中重写后:打印对象的类型+属性名+属性值

equals( ) :

Object中的默认实现 : ==比较,比较的是两个对象的地址值

​ 子类Student中重写后 : 比较的是对象的 类型+属性名+属性值

hashCode( ) : Object的默认实现:根据对象的地址值生成哈希码值

​ 子类Student重写后:根据对象的属性生成哈希码值

在每个重写了equals方法的类中,你必须也要重写hashCode方法。如果不这样做的话,就会违反Object.hashCode的通用约定,从而导致该类无法与所有基于散列值(hash)的集合类结合在一起正常运行。

示例:

package cn.tedu.api;
import java.util.Objects;
/**本类用于顶级父类Object的入门案例*/
//1.查API手册
//2.连点两下shift打开IDEA的搜索,注意勾选"include non-project item",再搜Object双击就可以找到Object源码
//3.在拓展External Libraries->jdk->rt.jar->java->lang->Object就可以找到Object源码
//4.按住ctrl点hashCode(),也可以进入Object类
public class TestObject {
    public static void main(String[] args) {
        //4.创建学生类对象进行测试
        Student s = new Student();
        Student s1 = new Student("海绵宝宝",3);
        Student s2 = new Student("海绵宝宝",3);
        //5.测试hashCode()
        /*本方法的作用是返回对应对象的int类型的哈希码值
        * 本方法力求不同的对象返回的哈希码值不同
        * 这样我们就可以根据哈希码值区别不同的对象*/
        System.out.println(s.hashCode());
        System.out.println(s1.hashCode());
        System.out.println(s2.hashCode());
        //6.测试toString()
        //打印s对象的是println(),这个方法会层层调用,一直到Object中的toString
        /*Object中toString()的默认实现:对象的地址值[对象类型@十六进制的哈希码值]*/
        /*子类重写了toString()以后,打印的是:对象的类型+属性+属性值*/
        System.out.println(s);
        System.out.println(s1);
        //8.测试equals()
        /*Object中equals()的默认实现使用的是==比较
        * ==比较的是左右两边的值,如果是基本类型,比较的就是字面值,比如1和1,3.4和3.4
        * 如果是引用类型,比较的是引用类型变量保存的地址值
        * 子类重写了equals()与hashCode()以后,比较的就是对象的类型+属性+属性值*/
        //没重写equals()和hashCode()前,比较的是地址值,栈内存的地址值不一样,所以是false
        //System.out.println(s1.equals(s2));//false
        //重写equals()和hashCode()后,比较的就是对象的类型+属性+属性值
        System.out.println(s1.equals(s2));//true
        System.out.println(s.equals(s1));//false
    }
}
//1.创建学生类
class Student{
    //2.定义属性
    String name;//姓名
    int age;//年龄
    //3.1添加本类的无参构造
    public Student() {
        System.out.println("这是无参构造~");
    }
    //3.2添加本类的全参构造
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("这是全参构造~");
    }
    //7.在Student类中添加重写的toString()
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    //9.添加重写的equlas与hashCode
    /*equals()与hashCode()逻辑要保持一致,要重写都重写,要不重写,都不重写
    * Object默认实现:hashCode()的哈希码值根据地址值生成
    *               equals()底层使用==比较两个对象的地址值
    * Student类重写后:hashCode()的哈希码值根据重写后传入的对象的属性生成
    *                equals()比较两个对象的类型+所有属性+属性值*/
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age &&
                Objects.equals(name, student.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

String是一个封装char[]数组的对象,字符串不可变
通过下图中的底层实现可以看出:被final修饰,是常量
String str = “abc”; 等效于:char[] data= {‘a’, ‘b’, ‘c’};

String s1 = new String(value);//触发String(char[])的含参构造来创建对象

String s11 = new String(value);//触发String(char[])的含参构造来创建对象

这两种方式创建的字符串是和对象一样,在堆中新建内容,然后把地址值交给s1和s11这两个引用变量来保存

String s2 = “abc”;

String s22 = “abc”;
String s3 = “ccc”;

这三种方式创建字符串,是在堆中的常量池中,如果常量池中没有这个字符串,则在常量池中新建字符串,然后把常量池中的地址交给变量保存

如果常量池中有相同的内容,则不用新建,直接把这个内容的地址交给变量来保存.

示例:

package cn.tedu.api;

import sun.java2d.pipe.SpanIterator;

/**本类用于测试String类的使用*/
public class TestString {
    public static void main(String[] args) {
        //1.创建String的方式1
        /*1.字符串类型底层维护的是char[]*/
        char[] value = {'a','b','c'};
        String s1 = new String(value);//触发String(char[])的含参构造来创建对象
        String s11 = new String(value);//触发String(char[])的含参构造来创建对象

        //2.创建String的方式2
        String s2 = "abc";
        String s22 = "abc";
        String s3 = "ccc";
        //3.测试
        System.out.println(s1==s2);//false,一个在堆里,一个在常量池里
        System.out.println(s1==s11);//false,两个不同的对象,地址值不同
        System.out.println(s2==s22);//true,都在堆中常量池,并且内容相同,所以是同一个地址池
        System.out.println(s2==s3);//false,都在堆中常量池,由于内容不同,所以指向两个不同的地址值

        /*Object类中equals()的默认实现的通过==来比较的
        * 但是,String类已经重写过了继承自Object中的equals()
        * 重写后,不再按照==比较,而是比较两个字符串的具体内容
        * 也就是说,不论创建方式,只要字符串的内容一致,equals()就返回true*/
        System.out.println(s1.equals(s2));//true
        System.out.println(s1.equals(s11));//true
        System.out.println(s2.equals(s3));//false
    }
}

String类里面的18种方法及使用:

int hashCode() 返回此字符串的哈希码。
boolean equals(Object anObject) 将此字符串与指定的对象比较,比较的是重写后的串的具体内容
String toString() 返回此对象本身(它已经是一个字符串!)。

int length() 返回此字符串的长度。
String toUpperCase() 所有字符都转换为大写。
String toLowerCase() 所有字符都转换为小写
boolean startsWith(String prefix) 测试此字符串是否以指定的元素开头。
boolean endsWith(String suffix) 测试此字符串是否以指定的字符串结束。

char charAt(int index) 返回指定索引/下标处的 char 值/字符
int indexOf(String str) 返回指定字符在此字符串中第一次出现处的索引。
int lastIndexOf(String str) 返回指定字符在此字符串中最后一次出现处的索引。
String concat(String str) 将指定字符串连接/拼接到此字符串的结尾,注意:不会改变原串
String[] split(String regex) 根据给定元素来分隔此字符串。

String trim() 返回去除首尾空格的字符串
byte[] getBytes() 把字符串存储到一个新的 byte 数组中
String substring(int beginIndex) 返回一个新子串,从指定下标处开始,包含指定下标 [beginIndex , 结束]
String substring(int beginIndex, int endIndex) 返回一个新子串,从执定下标开始,到结束下标为止,但不包含结束下标(含头不含尾) [ beginIndex , endIndex )
static String valueOf(int i) 把int转成String

代码实例:

package cn.tedu.api;
import java.util.Arrays;
/**本类用于测试String类里面的各种方法及使用*/
public class TestString2 {
    public static void main(String[] args) {
        //1.使用两种方式创建数组
        char[] value = {'a','b','c'};
        String s1 = new String(value);
        String s2 = "abc";

        //2.测试常用方法
        /*String equals()和hashCode()得保持逻辑一致,两个都方法都一起重写了
        重写了hashCode(),是根据字符串的具体内容生成哈希码值,而不是根据地址值生成
        * 所以虽然s1和s2的地址值不同,但是它们的哈希码值是一样的*/
        System.out.println(s1.equals(s2));//true
        System.out.println(s1.hashCode());//96354
        System.out.println(s2.hashCode());//96354

        /*String也重写了Object中的toString()方法,打印的是字符串的具体内容*/
        System.out.println(s1);//abc

        /*String里面的方法*/
        System.out.println(s1.length());//3,查看当前字符串的长度
        System.out.println(s1.toUpperCase());//ABC,将本字符串转为全大写
        System.out.println(s1.toLowerCase());//abc,将本字符串转为全小写
        System.out.println(s1.startsWith("a"));//true,判断本字符串是否以指定元素"a"开头
        System.out.println(s1.endsWith("a"));//false,判断本字符串是否以指定元素"a"结尾
        System.out.println(s1.charAt(0));//a,根据下标索引获取本字符串中对应位置上的元素

        String s3 = "abcddbba";
        System.out.println(s3.indexOf("b"));//1,返回指定字符第一次出现的下标值
        System.out.println(s3.indexOf("5"));//-1,返回指定字符第一次出现的下标值,如果没有这个字符,则返回-1
        System.out.println(s3.lastIndexOf("b"));//6,返回指定字符最后一次出现的下标值
        System.out.println(s2.concat("cxy"));//s2是"abc",则结果为"abccxy",将指定字符串拼接到本字符串中的结果
        System.out.println(s2);//abc,说明上面的拼接是临时的,没有赋值,不会改变原字符串s2的内容
        String s4 = s2.concat("aaa");//如果想多次使用拼接后的结果,需定义一个字符串保存结果
        System.out.println(s4);//"abcaaa",s4为拼接后得出的结果

        //返回值类型是String[],所以需要Arrays.toString()打印
        //split()方法,字符串分割符,以指定字符作为分割符,分割当前的字符串
        String s5 = "afbfcfdfe";
        String[] a = s5.split("f");
        //遍历数组
        System.out.println(Arrays.toString(a));
        //遍历数组
        for(String i:a){
            System.out.print(i+" ");
        }
        System.out.println();
        //遍历数组
        for (int i = 0; i < a.length; i++) {
            System.out.print(a[i]+" ");
        }
        System.out.println();

        //trim()方法去除字符串首尾两端的空格
        String s6 = "     hhh   hh    ";
        System.out.println(s6.trim());//hhh   hh,去除字符串首尾两端的空格

        //substring()方法,截取子字符串,参数为字符串下标
        String s7 = "abcdefgh";
        System.out.println(s7.substring(3));//defgh,从指定下标处开始截取子串[3,结束]
        System.out.println(s7.substring(3,6));//def,从指定下标处开始截取子串[3,6),含头不含尾

        //valueof()静态方法,把int类型转为String类型
        System.out.println(10+20);//30,int+int->计算结果
        System.out.println("20"+10);//2010,String+int->拼接效果
        System.out.println(String.valueOf(10));//10
        System.out.println(String.valueOf(80)+10);//8010,拼接效果,将int类型的80转为字符串

        //getBytes[],将指定字符串转为byte[]
        byte[] bs = s7.getBytes();//将指定字符串转为byte[]
        System.out.println(Arrays.toString(bs));
    }
}

StringBuilder/StringBuffer的用法:

package cn.tedu.api;
/**本类用于测试字符串的拼接*/
public class TestString3 {
    public static void main(String[] args) {
        //需求:将26个字母拼接10000次
        String s = "abcdefghijklmnopqrstuvwxyz";
        //method1(s);
        method2(s);
    }

    private static void method2(String s) {
        //创建一个变量用来保存拼接后的效果
        String result = "";
        //1.创建工具类对象
        //StringBuffer sb = new StringBuffer();
        StringBuilder sb2 = new StringBuilder();
        //2.拼接10000次
        //5.给程序添加一个计时的功能
        //5.1获取循环开始时的系统当前时间,作为开始时间
        long t1 = System.currentTimeMillis();
        for (int i= 0; i < 10000; i++) {
            //3.使用工具类对象的append()进行拼接
           // sb.append(s);
           sb2.append(s);
        }
        //5.2获取循环结束时的系统当前时间,作为结束时间
        long t2 = System.currentTimeMillis();
        //4.拼接完毕打印拼接的效果
        //System.out.println(sb);
        System.out.println(sb2);
        //6.打印拼接总共耗费的毫秒值
        System.out.println(t2-t1);

    }

    private static void method1(String s) {
        //1.定义一个变量用来保存拼接后的效果
        String result = "";
        //5.给程序添加一个计时的功能
        //5.1获取循环开始时的系统当前时间,作为开始时间
        long t1 = System.currentTimeMillis();
        System.out.println(t1);
        //2.创建循环执行10000次
        for (int i = 0; i < 10000; i++) {
            //3.进行字符串的拼接
            result+=s;
        }
        //5.2获取循环结束时的系统当前时间,作为结束时间
        long t2 = System.currentTimeMillis();
        //4.打印拼接后的结果
        System.out.println(result);
        //6.打印拼接总共耗费的毫秒值
        System.out.println(t2-t1);
    }
}

正则表达式:

正确的字符串格式规则。
常用来判断用户输入的内容是否符合格式的要求,注意是严格区分大小写的。

Matches(正则) : 当前字符串能否匹配正则表达式
replaceAll(正则,子串) : 替换子串
split(正则) : 拆分字符串

package cn.tedu.api;
import java.util.Scanner;
/**本类用于正则表达式的入门案例*/
//需求:接收户输入的身份证号,将判断的结果输出
public class TestRegex {
    public static void main(String[] args) {
        //1.编辑正则表达式
        //身份证号的规律:一共是18位,前17位是数字,第18位有可能是数字有可能是X
//        String regex = "[0-9]{17}[0-9X]";
        /*单个\在java中有特殊的含义,表示转义符号,不认为是一个单纯的斜杠
        * 所以如果想要表示斜杠,需要在它的前面加一具用来转义的\
        * 也就是\\才表示成一个单纯的斜杠
        * \t制表符 \r回车符 \n换行符*/
        String regex = "\\d{17}[0-9X]";
        //2.接收用户输入的身份证号
        System.out.println("请您输入您的身份证号:");
        String input = new Scanner(System.in).nextLine();

        //3.判断用户的身份证号是否正确
        if(input.matches(regex)){
            System.out.println("恭喜你!输入正确!");
        }else{
            System.out.println("您输入的身份证号有误!");
        }

    }
}

八十基本类型的包装类:

package cn.tedu.api;
/**本类用于测试包装类*/
public class TestNumber {
    static Integer io;
    public static void main(String[] args) {
        /*包装类也是引用类型,默认值是null*/
        System.out.println(io);//null,成员变量io要用static修饰符,才可以被静态方法main调用,静态只和静态玩

        //3.创建int类型对应的包装类型Integer的对象---方式1
        Integer i1 = new Integer(5);
        Integer i11 = new Integer(5);
        System.out.println(i1==i11);//false

        //4.创建int类型对应的包装类型Integer的对象---方式2
        /*Integer有一个高效的效果,如果使用valueOf()的创建方式
        * 并且数据在-128~127范围内,相同的数据只会存一次
        * 后续再存都是使用之前存过的数据*/
        Integer i2 = Integer.valueOf(127);
        Integer i22 = Integer.valueOf(127);
        System.out.println(i2==i22);//true

        //满足高效效果的3个条件:Integer  valueOf()  -128~127才能高效
        Integer i3 = Integer.valueOf(300);
        Integer i33 = Integer.valueOf(300);
        System.out.println(i2==i22);//false

        //5.创建double类型对应在的包装类型Double的对象---方式1
        Double d1 = new Double(3.14);
        Double d2 = new Double(3.14);
        System.out.println(d1==d2);//false

        //6.创建double类型对应的包装类型Double的对象---方式2
        Double d3 = Double.valueOf(3.14);
        Double d4 = Double.valueOf(3.14);
        System.out.println(d1==d3);//false
        System.out.println(d3==d4);//false

        //7.测试常用方法
        //parseInt():将String类型的数据转成int类型
        System.out.println(Integer.parseInt("800")+8);//808
        //parseDouble():将String类型的数据转成double类型
        System.out.println(Double.parseDouble("2.2")+1.1);//3.3
    }
}

包装类的自动装箱与自动拆箱 :

package cn.tedu.api;
/**本类用于测试自动装箱与自动拆箱*/
public class TestBox {
    public static void main(String[] args) {
        //1.使用Integer的两种创建方式,创建Integer对象,存入数据127
        Integer i = new Integer(127);
        Integer i1 = Integer.valueOf(127);

        //2.现在的方式
        /*1.自动装箱:编译器会自动把基本类型int 5,包装成包装类型Integer
        * 然后交给引用类型的变量i3来保存,自动装箱时底层发生的代码:Integer.valueOf(5);
        * valueOf()的方向:基本类型int -> 引用类型 Integer*/
        Integer i3 = 127;

        /*2.自动拆箱:编译器会自动把包装类型的i拆掉"箱子",变回基本类型的数据127
        * 然后把这个值交给int类型的变量i4来保存,自动拆箱时底层发生的代码i.intValue()
        * intValue()的方向:Integer -> int*/
        /* int intValue():以 int 类型返回该 Integer 的值。*/
         /* static Integer valueOf(int i):返回一个表示指定的 int 值的 Integer 实例。*/
          /*两个相互转换的方法*/
        int i4 = i;
        System.out.println(i4);
    }
}
BigDecimal:常用来解决精确的浮点数运算不精确的问题

除法运算:除不尽时会抛出异常:ArithmeticException

所以我们应该使用重载的divide(m,n,o)

m是要除以哪个对象

n是除不尽时保留的位数

o是舍入方式,常用的是四舍五入

舍入方式解析
ROUND_HALF_UP 四舍五入,五入 如:4.4结果是4; 4.5结果是5
ROUND_HALF_DOWN 五舍六入,五不入 如:4.5结果是4; 4.6结果是5
ROUND_HALF_EVEN 公平舍入(银行常用)
比如:在5和6之间,靠近5就舍弃成5,靠近6就进位成6,如果是5.5,就找偶数,变成6
ROUND_UP 直接进位,不算0.1还是0.9,都进位
ROUND_DOWN 直接舍弃,不算0.1还是0.9,都舍弃
ROUND_CEILING(天花板) 向上取整,取实际值的大值
朝正无穷方向round 如果为正数,行为和round_up一样,如果为负数,行为和round_down一样
ROUND_FLOOR(地板) 向下取整,取实际值的小值
朝负无穷方向round 如果为正数,行为和round_down一样,如果为负数,行为和round_up一样

package cn.tedu.api;

import java.math.BigDecimal;
import java.util.Scanner;

/**本类用于解决浮点数运算不精确的问题*/
//需求:接收用户输入的两个小数,做四则运算,并打印计算结果
public class TestBigDecimal {
    public static void main(String[] args) {
        //f1();//使用普通的+ - * / 四则运算,暴露浮点数运算不精确的问题
       f2();//使用BigDecimal解决浮点数运算不精确的问题
    }
    private static void f1() {
        //1.提示并接收用户输入的两个小数
        System.out.println("请您输入要计算的第1个数:");
        double d1 = new Scanner(System.in).nextDouble();
        System.out.println("请您输入要计算的第2个数:");
        double d2 = new Scanner(System.in).nextDouble();
        //2.做运算
        System.out.println(d1+d2);
        System.out.println(d1-d2);
        System.out.println(d1*d2);
        System.out.println(d1/d2);
    }
    private static void f2() {
        //1.提示并接收用户输入的两个小数
        System.out.println("请您输入要计算的第1个数:");
        double d1 = new Scanner(System.in).nextDouble();
        System.out.println("请您输入要计算的第2个数:");
        double d2 = new Scanner(System.in).nextDouble();
        //2.创建工具类BigDecimal的对象,把接收到d1 d2分别交给工具类对象保存
        /*1.最好不要使用double作为构造方法的参数类型,不然还会有不精确的现象,有坑!!!
        * 2.最好使用重载的,参数类型为String的构造方法*/
        BigDecimal bd1 = new BigDecimal(d1+"");
        BigDecimal bd2 = new BigDecimal(d2+"");

        //3.通过BigDecimal的对象来调用其方法,实现精确运算
        //3.1定义一个BigDecimal类型的变量来保存结果
        BigDecimal bd3;
        //3.2做加法运算
        bd3 = bd1.add(bd2);
        System.out.println("加法结果:"+bd3);

        //3.3做减法运算
        bd3 = bd1.subtract(bd2);
        System.out.println("减法结果:"+bd3);

        //3.4做乘法运算
        bd3 = bd1.multiply(bd2);
        System.out.println("乘法结果:"+bd3);

       //3.5做除法运算
        /*除法运算:除不尽时会抛出异常:ArithmeticException
        * 所以我们应该使用重载的divide(m,n,o)*/
        /*m是要除以哪个对象
        * n是除不尽时保留的位数
        * o是舍入方式,常用的是四舍五入*/
        bd3 = bd1.divide(bd2,3,BigDecimal.ROUND_HALF_UP);
        System.out.println("除法的结果:"+bd3);
    }
}

IO流 :

在这里插入图片描述

在学习IO流之前,我们首先需要学习的概念就是Stream流
为了方便理解,我们可以把数据的读写操作抽象成数据在"管道"中流动,但需注意:
1.流只能单方向流动
2.输入流用来读取 → in
3.输出流用来写出 → out
4.数据只能从头到尾顺序的读写一次
所以以程序的角度来思考,In/out 相对于程序而言的输入(读取)/输出(写出)的过程.

文件类File:

package cn.tedu.file;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
/**本类用于测试文件类File*/
public class TestFile {
    public static void main(String[] args) throws IOException {
        //1.创建file类对象
        /*1.File需要导包:import java.io.File;
        * 2.路径是String类型,必须写正确,不然找不到文件
        * 3.完整的文件名包含两部分:文件名+后缀名
        * 4.ready文件夹与1.txt需要自己手动创建*/
        File file = new File("E:\\ready\\1.txt");
        //2.测试常用方法
        System.out.println(file.length());//获取当前文件的字节量
        System.out.println(file.exists());//true,判断文件是否存在
        System.out.println(file.isFile());//true,判断当前file对象是否为文件?
        System.out.println(file.isDirectory());//false,判断当前file对象是文件夹吗?
        System.out.println(file.getName());//1.txt,获取文件完整的名字
        System.out.println(file.getParent());//E:\ready 获取文件的父级路径(所在文件夹的路径)
        System.out.println(file.getAbsolutePath());//E:\ready\1.txt  获取带盘符的文件的绝对路径

        //3.测试创建与删除
        /*new只会在内存中创建一个File类型的对象
        * 并不会帮你在磁盘中创建一个真实存在的2.txt*/
        File file2 = new File("E:\\ready\\2.txt");
        //创建一个之前不存在的文件2.txt,如果创建成功,会返回true
        /*如果指定创建文件的路径不对,会抛出异常
        * 所以我们需要提前处理这个问题,暂时选择在main()上抛出
        * 这个IO异常是目前我们遇到的强制要求必须预先处理的异常
        * 如果不处理,方法的调用会报错,通不过编译*/
        System.out.println(file2.createNewFile());//创建文件

        File file3 = new File("E:\\ready\\m");
        System.out.println(file3.mkdir());//创建不存在的单层文件夹

        File file4 = new File("E:\\ready\\a\\b\\c");
        System.out.println(file4.mkdirs());//创建不存在的多层文件夹

        /*delete()只能删除文件和空文件夹*/
        file2.delete();//删除文件2.txt
        file4.delete();//删除空文件夹c
        file3.delete();//直接删除了空文件夹m

        //4.测试展现文件列表
        File file5 = new File("E:\\ready");
        String[] list = file5.list();/*不常用*///1.txt, a,显示文件名,String类型数组
        System.out.println(Arrays.toString(list));
        //下面这句话会报错,因为这个是一个String[],所以数组中的每个元素都是String类型
        //那么我们只能使用String类中的方法,getName()是File类的方法,在这里不能用
        //System.out.println(list[0].getName());

        File[] fs = file5.listFiles();/*常用*/
        System.out.println(Arrays.toString(fs));//[E:\ready\1.txt, E:\ready\a],显示绝对路径,返回File数组
        System.out.println(fs[0].getName());//获取File数组里面的元素的文件名

    }
}

在这里插入图片描述

流的分类:

1.按照流的方向:输入流 , 输出流

2.按照传输的单位: 字节流 , 字符流

四种组合情况:

一 : 字节输入流 :

  1. InputStream : 抽象父级,此抽象类是表示字节输入流的所有类的超类。
  1. FileInputStream:操作文件的字节输入流

构造方法 :

FileInputStream(File file) : 通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。

FileInputStream(String name) :通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。

  1. BufferedInputStream : 高效字节输入流----构造方法:

​ BufferedInputStream(InputStream in) :创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。

二 : 字节输出流:

1.OutputStream:抽象父级,不可实例化

2.FileOutputStream: 操作文件的字节输出流

​ 构造方法:

​ FileOutputStream(File file) : 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。覆盖输出

​ FileOutputStream(File file, boolean append) : 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。追加输出

​ FileOutputStream(String name) : 创建一个向具有指定名称的文件中写入数据的输出文件流。覆盖输出

​ FileOutputStream(String name, boolean append) : 创建一个向具有指定 name 的文件中写入数据的输出文件流。追加输出

  1. BufferedOutputStream : 高效字节输出流

    ​ 构造方法:

    ​ BufferedOutputStream(OutputStream out) : 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。

三 : 字符输入流:

1.Reader : 抽象父级,不可实例化,抽象类是表示字符输入流的所有类的超类.

2.FileReader:操作文件的字符输入流

​ 构造方法:

​ FileReader(File file):在给定从中读取数据的 File 的情况下创建一个新 FileReader。

​ FileReader(String path):在给定从中读取数据的文件名的情况下创建一个新 FileReader。

3.BufferedReader:高效字符输入流

​ 构造方法:

​ BufferedReader(Reader in) : 创建一个使用默认大小输入缓冲区的缓冲字符输入流。

四 : 字符输出流:

  1. Writer : 抽象父级,不可以实例化

  2. FileWriter : 操作字符输出流

    ​ 构造方法:

    ​ FileWriter(File file) : 根据给定的 File 对象构造一个 FileWriter 对象。

    ​ FileWriter(File file, boolean append) : 根据给定的 File 对象构造一个 FileWriter 对象。

    ​ FileWriter(String fileName) :根据给定的文件名构造一个 FileWriter 对象。

    ​ FileWriter(String fileName, boolean append) :根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。

  3. BufferedWriter

    ​ 构造方法:

    ​ BufferedWriter(Writer out) : 创建一个使用默认大小输出缓冲区的缓冲字符输出流。

字节输入流练习:

package cn.tedu.file;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**本类用于练习字节输入流*/
public class TestIn {
    public static void main(String[] args) {
        Method1();//使用普通字节输入流读取
        //method2();//使用高效字节输入流读取
    }
    
    private static void method2() {

    }

    private static void Method1(){
        //1.创建字节输入流对象用于读取
        //InputStream in = new InputStream();//报错,抽象类不能直接创建对象
        //定义一个在本方法中都生效的局部变量
        InputStream in2 = null;
        try {
            //InputStream in = new FileInputStream(new File("E:\\ready\\1.txt"));//两种方式都可以创建流对象
            in2 = new FileInputStream("E:\\ready\\1.txt");

            //2.开始读取
            /*read()每次调用都会读取一个字节,如果读到了数据的末尾,没有数据了,返回-1*/
//            System.out.println(in2.read());
//            System.out.println(in2.read());
//            System.out.println(in2.read());
//            System.out.println(in2.read());
//            System.out.println(in2.read());
            //需求:需要循环读取文件中的所有内容,直至读完
            //定义变量,记录读到的数据
            int b;
            while ((b =in2.read())!=-1){
                System.out.println(b);
            }
        } catch (Exception e) {
            e.printStackTrace();//打印错误栈轨迹,出错了给程序猿看,方便调错
            /*finally{}是try-catch结构在的第3个部分
            * 这部分不论是否捕获到异常,是一定会被执行到的代码块,常用于关流*/
        }finally {
            //3.关闭流,流资源使用完毕必须释放!!
            try {
                in2.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

}

Day12回顾复习:

包装类新建,运用与自动装箱:

package cn.tedu.review;
/**本类用于回顾包装类*/
public class TestBox {
    public static void main(String[] args) {
        //1.使用3种创建方式,创建Integer类型的对象
        Integer i1 = new Integer(123);
        Integer i2 = Integer.valueOf(127);//-128~127的范围,Integer有高效的效果
        Integer i3 = 127;//自动装箱
        System.out.println(i1==i2);//false,两种方式创建的对象不一样,地址值也不同
        int i4 = i1;//自动拆箱,包装类Integer拆箱转成int类型
        Double d1 = new Double(3.14);
        Double d2 = Double.valueOf(3.14);
        Double d3 = 3.5;
    }
}

复习浮点数运算不精确的解决方案:

package cn.tedu.review;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Scanner;
/**本类用于复习浮点数运算不精确的解决方案*/
public class TestBigDecimal {
    public static void main(String[] args) {
        //1.提示拼接收两个小数
        System.out.println("请输入要计算的第一个数:");
        double a = new Scanner(System.in).nextDouble();
        System.out.println("请输入要计算的第二个数:");
        double b = new Scanner(System.in).nextDouble();

        //2.将接收到的小数交给工具类BigDecimal
        BigDecimal b1 = new BigDecimal(a+"");//参数用String类型,才能解决,如果用double型,依然会运算不精确
        BigDecimal b2 = new BigDecimal(b+"");//参数用String类型,才能解决,如果用double型,依然会运算不精确

        //3.进行运算输出结果
        System.out.println("加法:"+b1.add(b2));
        System.out.println("减法:"+b1.subtract(b2));
        System.out.println("乘法:"+b1.multiply(b2));
        //divide(),除法有除不尽的异常,divide(m,n,RoundingMode.HALF_UP),m为除数,n为保留小数点的为数,RoundingMode.HALF_UP表示4舍5入的规则
        System.out.println("除法:"+b1.divide(b2,2, RoundingMode.HALF_UP));

    }
}

复习File的创建与使用

package cn.tedu.review;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;

/**本类用于复习File的使用*/
public class TestFile {
    public static void main(String[] args) {
        //1.创建File类的对象
        File file = new File("E:\\ready\\11.txt");
        //2.测试文件与文件夹属性的方法
        System.out.println(file.length());//4,获取文件的字节量
        System.out.println(file.exists());//true,判断文件是否存在
        System.out.println(file.isFile());//true,判断当前file指定的内容是文件吗
        System.out.println(file.isDirectory());//false,判断当前file指定的内容是文件夹吗
        System.out.println(file.getName());//11.txt,获取文件的名字
        System.out.println(file.getParent());//E:\ready,获取父级路径
        System.out.println(file.getAbsolutePath());//E:\ready\11.txt,获取带盘符与文件名的绝对路径

        //3.文件的创建与删除
        //3.1创建一个2.txt
        File file2 = new File("E:\\ready\\2.txt");
        try {
            file2.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //3.2在E:\ready目录下,创建一个bbb的文件夹
        File f3 = new File("E:\\ready\\bbb");
        f3.mkdir();

        //3.3在E:\ready目录下,创建多个文件夹
        File f4 = new File("E:\\ready\\aaa\\bbb\\ccc\\ddd");
        f4.mkdirs();

        //3.4删除2.txt文件
        file2.delete();

        //3.5删除bbb文件夹
        f3.delete();

        //3.6如果f4.delete(),谁被删除了?ddd文件夹,因为ddd是空文件夹
        f4.delete();

        //4.获取文件列表的两种方式
        //方式1
        File f5 = new File("E:\\ready");
        String[] list = f5.list();//数组的每个元素都是String对象
        System.out.println(Arrays.toString(list));//直接打印看结果
        //方式2
        File f6 = new File("E:\\ready");
        File[] files = f6.listFiles();//数组的每个元素都是File对象
        System.out.println(files[0].getName());//可以随意调用File对象的方法
        System.out.println(files[0].isDirectory());
        System.out.println(files[0].isFile());
        System.out.println(Arrays.toString(files));//直接打印看结果
    }
}

Day13:

1.测试字节输入流 : FileInputStream 和 BufferedInputStream

package cn.tedu.file;
import java.io.*;
/**本类用于测试字节输入流*/
public class TestIn {
    public static void main(String[] args) {
        //method1();//用于测试普通字节输入流FIS
        method2();//用于测试高效字节输入流BufferedInputStream
    }


    private static void method2() {
        InputStream in = null;
        try {
            //1.创建流对象
//            三步拆分
//            File f1 = new File("E:\\ready\\1.txt");
//            InputStream i1 = new FileInputStream(f1);
//            BufferedInputStream b1 =new BufferedInputStream(i1);
            //方式一创建
            //InputStream in = new BufferedInputStream(new FileInputStream(new File("E:\\ready\\1.txt")));
            //方式二创建
            in = new BufferedInputStream(new FileInputStream("E:\\ready\\1.txt"));
            //2.使用流对象
            int b = 0;
            while (true){
                    b = in.read();
                    if(b ==-1){
                        break;
                    }else{
                        System.out.println(b);
                    }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                //3.关流
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static void method1() {
        //4.定义一个在本方法中都生效的局部变量,注意手动赋值为null;
        InputStream in = null;
        try {
            //1.创建流对象
            //InputStream in = new FileInputStream(new File("E:\\ready\\1.txt"));//方式1:创建流对象
            in = new FileInputStream("E:\\ready\\1.txt");//方式2:创建流对象

            //2.使用流对象
            //2.1定义变量用来保存读到的数据
            int b;
            while ((b = in.read()) != -1) {
                System.out.println(b);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                //3.关流
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

2.测试字符输入流的读取: FileReader普通字符输入流 / BufferedReader高效字符输入流

package cn.tedu.file;
import java.io.*;
/**本类用于测试字符输入流的读取*/
public class TestIn2 {
    public static void main(String[] args) {
        //method1();//普通字符输入流
        method2();//高效字符输入流
    }
    private static void method1() {
        //定义一个在本方法中都生效的局部变量,手动初始化值为null
        Reader in = null;
        try {
            //in = new FileReader("E:\\ready\\1.txt");//方式一
            in = new FileReader(new File("E:\\ready\\1.txt"));//方式二
            //使用流对象进行读取
            int b;
            while ((b = in.read()) != -1){
                System.out.println(b);
            }
            /*
            不能省略定义变量b,这样会导致结果跳着读数据!!!!
            while(in.read()!=-1){
                System.out.println(in.read());
            }
             */
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                //关流
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    private static void method2() {
        //1.定义一个在本方法中都生效的局部变量,手动始化值为null
        BufferedReader in = null;
        try {
            //2.创建高效字符输入流对象BufferedReader
            in = new BufferedReader(new FileReader("E:\\ready\\1.txt"));//方式一
            //in = new BufferedReader(new FileReader(new File("E:\\ready\\1.txt")));//方式二
            int b;
            while(true){
                b = in.read();
                if(b==-1){
                    break;
                }else {
                    System.out.println(b);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

测试字节输出流 : FileOutputStream / BufferedOutputStream

package cn.tedu.file;
import java.io.*;
/**本类用于测试字节输出流*/
public class TestOut1 {
    public static void main(String[] args) {
      //method1();
      method2();
    }

    private static void method1() {
        //1.定义一个在本方法中都生效的局部变量
        FileOutputStream out = null;
        try {
            //2.创建字节输出流对象FOS-FileOutputStream
            out = new FileOutputStream("E:\\ready\\2.txt");//方式一,覆盖输出的方式
            out = new FileOutputStream(new File("E:\\ready\\2.txt"));//方式二,覆盖输出的方式
            out = new FileOutputStream("E:\\ready\\2.txt",true);//追加输出的方式
            out = new FileOutputStream(new File("E:\\ready\\2.txt"),true);//追加输出的方式

            //3.使用流对象
            out.write(97);
            out.write(98);
            out.write(99);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    private static void method2() {
        //1.定义一个在本方法中都生效的局部变量
        BufferedOutputStream out = null;
        //2.由于IO操作容易抛出异常,所以完成try-catch-finallya结构
        try{
            //3.创建高效字节输出流对象BufferedOutputStream
            out = new BufferedOutputStream(new FileOutputStream(new File("E:\\ready\\2.txt")));//方式一,覆盖输出
            out = new BufferedOutputStream(new FileOutputStream("E:\\ready\\2.txt"));//方式二,覆盖输出
            //方式三,追加输出
            out = new BufferedOutputStream(new FileOutputStream(new File("E:\\ready\\2.txt"),true));
            //方式三,追加输出
            out = new BufferedOutputStream(new FileOutputStream("E:\\ready\\2.txt",true));
            //4.使用流对象进行输出
            out.write(100);
            out.write(100);
            out.write(100);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                out.close();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
}

测试字符输出流 FileWriter字符输出流 / bufferedWriter 高效字符输出流

package cn.tedu.file;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

/**本类用于测试字符输出流*/
public class TestOut2 {
    public static void main(String[] args) {
//        method1();
        method2();
    }

    private static void method1() {
        //1.定义局部变量
        FileWriter out = null;
        //2.完成异常捕获处理结构
        try{
            //3.创建流对象
            //out = new FileWriter("E:\\ready\\2.txt");//方式一,覆盖
            //out = new FileWriter(new File("E:\\ready\\2.txt"));//方式二,覆盖
            out = new FileWriter("E:\\ready\\2.txt",true);//方式三,追加
            out = new FileWriter(new File("E:\\ready\\2.txt"),true);//方式四,追加

            //4.使用流对象
            out.write(97);
            out.write(98);
            out.write(99);
            out.write(100);

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                //5.关流
                out.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
    private static void method2() {
        //1.定义局部变量
        BufferedWriter out = null;
        //2.完成异常处理结构
        try{
            out = new BufferedWriter(new FileWriter(new File("E:\\ready\\2.txt")));//覆盖输出
            out = new BufferedWriter(new FileWriter("E:\\ready\\2.txt",true));//追加输出
            out = new BufferedWriter(new FileWriter(new File("E:\\ready\\2.txt"),true));//追加输出
            out = new BufferedWriter(new FileWriter("E:\\ready\\2.txt"));//覆盖输出
            //使用流对象
            out.write(977);
            out.write(978);
            out.write(979);
            out.write(980);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

IO流综合练习之文件复制案例:

package cn.tedu.file;

import java.io.*;
import java.util.Scanner;

/**本类用于实现IO综合练习之文件复制案例*/
public class TestCopyFile {
    public static void main(String[] args) {
        //1.提示并接收用户输入的两个路径
        System.out.println("请输入原文件路径:");
        String f = new Scanner(System.in).nextLine();
        System.out.println("请输入新文件路径:");
        String t = new Scanner(System.in).nextLine();

        //2.调用自己创建好的方法完成文件的复制
        //ZFCopy(f,t);
        ZJCopy(f,t);
    }

    //本方法使用字符流完成文件的复制
    private static void ZFCopy(String f, String t) {
        //1.定义在整个方法都生效的局部变量
        Reader in = null;
        Writer out = null;
        //2.由于代码可能会发生异常,所以需要编写try-catch-finally结构
        try{
            //3.1创建高效字符输入流对象
            in = new BufferedReader(new FileReader(f));
            //3.2创建高效字符输出流对象
            out = new BufferedWriter(new FileWriter(t));

            //4.创建好流对象就可以使用流对象完成业务
            //4.1定义变量用来保存读到的数据
            int b;
            //4.2循环读取源文件,直接返回值为-1,说明没数据了,就结束循环
            while ((b = in.read())!=-1){
                //4.3将本轮循环读取到的数据写入到新文件中(在循环里面,读到一个就写入一个)
                out.write(b);
            }
            System.out.println("恭喜您!文件复制成功!");

        }catch (Exception e){
            System.out.println("很抱歉,文件复制失败!");
            e.printStackTrace();
        }finally {
            /*关闭流是有顺序的,如果有多个流,最后创建的流是要最先关闭的*/
            /*多条关流语句需要各自try-catch*/
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //本方法使用字节流完成文件的复制
    private static void ZJCopy(String f, String t) {
        //1.定义在整个方法中都生效的局部变量,注意手动初始化,默认值为null
        BufferedInputStream in = null;
        BufferedOutputStream out = null;

        try {
            //2.创建流对象
            in = new BufferedInputStream(new FileInputStream(new File(f)));
            out = new BufferedOutputStream(new FileOutputStream(new File(t)));

            //3.定义变量保存数据
            int b;
            //4.使用流对象
            while ((b=in.read())!=-1){
                out.write(b);
            }
            System.out.println("复制成功!");

        } catch (Exception e) {
            System.out.println("复制失败!");
            e.printStackTrace();
        }finally {
            //5.关闭流
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

学习Junit单元测试框架

package cn.tedu.file;

import org.junit.Test;

/**本类用于学习Junit单元测试框架*/
public class Demo {

        /*单元测试方法的语法要求:
        * public + void + 没有参数 + @Test
        * */
    /*下载JUnit框架jar包:Add Junit4 classPath*/
        @Test
        public void eat(){
                System.out.println("哈哈哈");
        }
        @Test
        public void eat2(){
                System.out.println("哈哈哈2");
        }

}

Day14:

序列化是指将对象的状态信息转换为可以存储或传输形式的过程.在序列化期间,对象将其当前状态写入到临时或持久性存储区.以后可以通过从存储区中读取或者反序列化对象的状态,重新创建该对象.

序列化:利用ObjectOutputStream,把对象的信息,按照固定的格式转成一串字节值输出并持久保存到磁盘
反序列化:利用ObjectInputStream,读取磁盘中之前序列化好的数据,重新恢复成对象

序列化 : 程序对象 -> 磁盘 输出,写入,ObjectOutputStream

反序列化 : 磁盘 -> 程序对象 输入,读取 , ObjectInputStream

序列化: 对象转字节值反序列化:字节值(之前序列化生成的) 转 对象

封装学生类,用作测试序列化与反序列化

如果一个类的对象想要被序列化,必须实现可序列化的接口Serializable,否则会报错
Serializable接口是一个空接口,里面一个方法也没有,作用是当做标志,标志这个类可以被序列化

序列化:是指把程序中的java对象,永久保存在磁盘中,相当于是写出的过程
方向:out,用到的流是:ObjectOutputStream
反序列化:是指把已经序列化在文件中保存的数据,读取/恢复到java程序中的过程

方向:in,用到的流是:ObjectInputStream

package cn.tedu.seri;
import java.io.*;

/**本类用于测试序列化与反序列化
 * 序列化:是指把程序中的java对象,永久保存在磁盘中,相当于是写出的过程
 * 方向:out,用到的流是:ObjectOutputStream
 * 反序列化:是指把已经序列化在文件中保存的数据,读取/恢复到java程序中的过程
 * 方向:in,用到的流是:ObjectInputStream*/
public class TestSerializable {
    public static void main(String[] args) {
        //method1();//本方法用于完成序列化的功能
        method2();//本方法用于完成反序列化的功能
    }

    /*序列化方法*/
    private static void method1() {
        //1.声明在本方法内都生效的局部变量,局部变量需要初始化,值为null
        ObjectOutputStream out = null;
        //2.由于IO操作可能会产生异常,所以需要完成try-catch-finally结构
        try {
            //3.创建序列化流对象
            out = new ObjectOutputStream(new FileOutputStream(new File("E:\\ready\\1.txt")));//方式一
            //out = new ObjectOutputStream(new FileOutputStream("E:\\ready\\1.txt"));//方式二
            //4.指定要序列化输出的对象
            Student obj = new Student("海绵宝宝",3,"大海里",'男');
            //5.通过ObjectOutputStream流对象来序列化输出Student对象
            out.writeObject(obj);
            System.out.println("恭喜您,序列化成功");
        }catch (Exception e){
            System.out.println("很抱歉!序列化失败!");
            e.printStackTrace();
        }finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /*反序列化方法*/
    private static void method2() {
        //1.声明在本方法内都生效的局部变量
        ObjectInputStream in = null;
        //2.由于IO操作可能会发生异常,所以需要先完成try-catch-finally结构
        try {
            //3.创建反序列化的流对象
            in = new ObjectInputStream(new FileInputStream(new File("E:\\ready\\1.txt")));
            //4.通过ObjectInputStream反序列化读取对象
            System.out.println(in.readObject());
            System.out.println("反序列化成功");
        }catch(Exception e){
            System.out.println("反序列化失败");
            e.printStackTrace();
        }finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

/*定义学生类*/
class Student {
    //1.定义学生相关的属性+private封装
    private String name;//姓名
    private  int age;//年龄
    private String addr;//地址
    private char gender;//性别

    //2.1创建本类的无参构造
    public Student(){
        System.out.println("我是Student类的无参构造 ");
    }
    public Student(String name, int age, String addr, char gender) {
        super();
        this.name = name;
        this.age = age;
        this.addr = addr;
        this.gender = gender;
        System.out.println("我是Student类的全参构造");
    }

    //1.2生成所有封装属性的get和set方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }
}

我们在反序列化时,JVM会拿着反序列化流中的serialVersionUID与序列化时相应的实体类中的serialVersionUID来比较,如果不一致,就无法正常反序列化,出现序列化版本不一致的异常InvalidClassException。

而且我们在定义需要序列化的实体类时,如果没有手动添加UID,
Java序列化机制会根据编译的class自动生成一个,那么只有同一次编译生成的class才是一样的UID。

如果我们手动添加了UID,只要这个值不修改,就可以不论编译次数,进行序列化和反序列化操作。

1.同时执行序列化与反序列化方法—不会报错

2.先执行序列化,再给Student类添加属性,然后反序列化—会报错

3.先执行序列化,然后不修改Student,然后反序列化----不会报错

4.我们手动添加了UID,只要这个值不修改,就可以不论编译次数,进行序列化和反序列化操作

总结
1.需要序列化的文件必须实现Serializable接口,用来启用序列化功能
2.不需要序列化的数据可以修饰成static,原因:static资源属于类资源,不随着对象被序列化输出
3.每一个被序列化的文件都有一个唯一的id,如果没有添加此id,编译器会自动根据类的定义信息计算产生一个
4.在反序列化时,如果和序列化的版本号不一致,无法完成反序列化
5.常用与服务器之间的数据传输,序列化成文件,反序列化读取数据
6.常用使用套接字流在主机之间传递对象
7.不需要序列化的数据也可以被修饰成transient(临时的),只在程序运行期间在内存中存在,不会被序列化持久保存

集合前的一些测试:

package cn.tedu.collection;
import org.junit.Test;
import java.util.Arrays;

/**本类用于集合前的一些测试*/
public class Demo {
    //单元测试方法:public + void + 没有参数 +@Test
    //1.完成单元测试方法saveStudent
    //2.独立完成Student类,包含属性:name age gender与全参构造
    //3.创建数组,用来存放Student类的3个对象s1 s2 s3,并打印查看
    @Test
    public void saveStudent(){

    }

    public static void main(String[] args) {
        Student s1 = new Student("二狗",18,'男');
        Student s2 = new Student("三猪",20,'男');
        Student s3 = new Student("四猫",22,'女');
        Student[] s = new Student[3];
        s[0] = s1;
        s[1] = s2;
        s[2] = s3;
        //System.out.println(Arrays.toString(s));
        for(Student i:s){
            System.out.println(i);
        }
        for (int i = 0; i < s.length; i++) {
            System.out.println(s[i]);
        }
    }
}


//独立完成Student类,包含属性:name age gender与全参构造
class Student {
    String name;
    int age;
    char gender;

    public Student(String name, int age, char gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender=" + gender +
                '}';
    }
}

泛型

那泛型有什么作用呢?
我们可以把泛型理解成一个“语法糖”,本质上就是编译器为了提供更好的可读性而提供的一种小手段,小技巧,虚拟机层面是不存在所谓“泛型”的概念的。是不有点神奇,不知所云,别着急等我讲完你就清楚了。

我们可以通过泛型的语法定义<>,来约束集合中元素的类型,编译器可以在编译期根据泛型约束提供一定的类型安全检查,这样可以避免程序运行时才暴露BUG,代码的通用性也会更强
泛型可以提升程序代码的可读性,但是它只是一个“语法糖”(编译后这样的部分会被删除,不出现在最终的源码中),所以不会影响JVM后续运行时的性能.

测试泛型的优点1:

package cn.tedu.collection;
import javax.lang.model.element.NestingKind;
import java.util.ArrayList;
import java.util.List;

/**本类用于测试泛型的优点1*/
public class TestGeneric1 {
    public static void main(String[] args) {
        /*1.泛型是怎么来的?-----集合想要模拟数组的数据类型检查*/
        String[] a = new String[5];//创建一个用来存放String类型数据的数组,长度5
        a[2] = "泡泡";
        a[4] = "涛涛";
        //数组的好处:在编译时期检查数据的类型,如是不是要求的数据类型就会报错
        //a[0] = 1;
        //a[1] = 3.3;
        //a[3] = 'c';

        /*2.泛型通常结合着集合一起使用*/
        /*3.引入泛型--主要目的是想通过泛型来约束集合中的元素类型
        * 4.引入泛型的好处:可以把报错的时机提前,在编译期就报错,而不是运行后才抛出异常
        * 向集合中添加元素时,会先检查元素的数据类型,不是要求的类型就编译失败*/
        List list = new ArrayList();//注意导包:java.util
        //没有泛型,数据类型没有约束---太自由!
        list.add("江江");
        list.add(1);
        list.add(8.8);
        list.add('a');
        System.out.println(list);

        List<String> list2 = new ArrayList();
        list2.add("雷神");//约束了类型以后,只可以传String类型的数据
        //list2.add(1);//报错,只能存String类型的数据
        //list2.add(2.2);//报错,只能存String类型的数据
        //list2.add('c');//报错,只能存String类型的数据

        //创建一个存放数据100 200 300的集合
        /*5.<type>--type的值应该如何写?
        * 需要查看集合要存放的数据类型是什么,根据类型来定义
        * 但注意:type必须是引用类型,不是基本类型*/
        List<Integer> list3 = new ArrayList();
        list3.add(100);
        list3.add(200);
        list3.add(300);
        System.out.println(list3);
        
    }
}

增强for循环(foreach)案例与泛型的优点2:

package cn.tedu.collection;
/**本类用于测试泛型的优点2*/
public class TestGeneric2 {
    public static void main(String[] args) {
        Integer[] a = {1,2,3,4,5,6,7,8,9,10};
        printabc(a);//创建方法打印数组a
        String[] b = {"大哥","二哥","三哥","四哥","五哥","六哥","小弟"};
        printabc(b);
        Double[] c = {6.0,6.6,6.66,6.666,6.66666};
        printabc(c);
    }

    /*1.泛型可以实现通用代码的编写,使用E表示元素的类型是Element类型
    * 2.泛型的语法要求:
    * 如果在方法上使用泛型,必须两处同时出现,一个是传入参数的类型
    * 一个是返回值类型前的泛型类型,表示这是一个泛型的方法*/
    private static <E>void printabc(E[] e) {
        for(E i:e){
            System.out.println(i);
        }
    }


//    private static void printabc(Double[] c) {
//        for(Double i:c){
//            System.out.println(i);
//        }
//    }
//    private static void printabc(String[] b) {
//        for(String i:b){
//            System.out.println(i);
//        }
//    }
//    //创建方法打印数组a
//    private static void printabc(Integer[] a) {
        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }
//        /*高效for循环/foreach循环
//        * 好处:比普通的for循环写法简便,并且效率还高
//        * 坏处:没有办法按照下标来操作值,只能从头到尾依次遍历
//        * 语法:for(2 3:1){循环体}*/
//        /*1号是要遍历的内容,2,3是每轮遍历到的具体元素的类型与名字*/
//        for(Integer i:a){
//            System.out.println(i);
//        }
//    }
}

集合:

1.学习父类提供的共性方法

2.学习子类如何创建对象

在这里插入图片描述

Java语言的java.util包中提供了一些集合类,这些集合类又称之为容器
提到容器不难想到数组,集合类与数组最主要的不同之处是,数组的长度是固定的,集合的长度是可变的,而数组的访问方式比较单一,插入/删除等操作比较繁琐,而集合的访问方式比较灵活

集合的英文名称是Collection,是用来存放对象的数据结构,而且长度可变,可以存放不同类型的对象,并且还提供了一组操作成批对象的方法.Collection接口层次结构 中的根接口,接口不能直接使用,但是该接口提供了添加元素/删除元素/管理元素的父接口公共方法.
由于List接口与Set接口都继承了Collection接口,因此这些方法对于List集合和Set集合是通用的.

测试Collection接口:

package cn.tedu.collection2;
import java.util.*;
/**本类用于测试Collection接口*/
public class TestCollection {
    public static void main(String[] args) {
        //1.创建Collection相关的集合对象
        //Collection c = new Collection();//报错,接口不能实例化
        //Collection<Integer> c = new ArrayList<Integer>();//三种方式都可以,类型自动匹配
        //Collection<Integer> c1 = new ArrayList<>();//三种方式都可以,类型自动匹配
        Collection<Integer> c = new ArrayList();//三种方式都可以,类型自动匹配
        //2.测试集合中的常用方法
        for (int i =100 ; i <= 500; i+=100) {
            c.add(i);
        }
        System.out.println(c);//直接打印集合对象的名字,可以查看集合存入的具体元素
        //c.clear();//[],清空集合,把集合里面的数据全部删除
        //System.out.println(c);
        System.out.println(c.hashCode());//获取集合对象的哈希码值
        /*false,集合为Integer类弄,200会自动装箱,转成Integer类型,集合对象c与元素200不等*/
        System.out.println(c.equals(200));
        System.out.println(c.contains(200));//true,判断集合是否包含指定元素200
        System.out.println(c.isEmpty());//false,判断集合是否为空
        System.out.println(c.remove(100));//删除集合中的指定元素100
        System.out.println(c);
        System.out.println(c.size());//4,集合的元素个数
        Object[] array = c.toArray();//将指定集合转为数组Object[]
        System.out.println(Arrays.toString(array));

        /*测试多个集合间的操作*/
        Collection<Integer> c2 = new ArrayList<>();//创建第2个集合
        c2.add(2);
        c2.add(4);
        c2.add(5);
        c.addAll(c2);//将c2集合的所有元素添加到c集合中
        System.out.println(c);
        System.out.println(c2);

        System.out.println(c.containsAll(c2));//true,判断c集合是否包含c2的所有元素
        c.retainAll(c2);//保留c和c2集合的交集,即是c集合中那些也属于c2集合的公共元素
        System.out.println(c);
        c.removeAll(c2);//删除c集合中属于c2集合的所有元素
        System.out.println(c);//[]

        //3.集合的迭代/遍历
        /*迭代步骤
        * 1.获取集合对应的迭代器
        * 2.通过迭代器判断集合中是否有下一个元素可以迭代
        * 3.通过迭代器获取当前迭代到的元素*/
        Iterator<Integer> it = c2.iterator();//获取集合的迭代器
        while (it.hasNext()){//如果有下一个元素
            System.out.println(it.next());//打印本轮循环到的元素
        }
    }
}

测试List集合中独有的方法:

package cn.tedu.collection2;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/*本类用于测试List集合中独有的方法*/
public class TestList {
    public static void main(String[] args) {
        //1.创建List的多态对象,注意List是接口,不可实例化
        List<String> list = new ArrayList();

        //2.测试继承自Collection中的方法
        list.add("大力娃");
        list.add("千顺娃");
        list.add("头铁娃");
        list.add("喷火娃");
        list.add("喷水娃");
        list.add("隐身娃");
        list.add("小紫娃");
        System.out.println(list);

        //list.clear();
        //System.out.println(list);
        System.out.println(list.contains("喷火娃"));//true
        System.out.println(list.equals("喷水娃"));//false
        System.out.println(list.isEmpty());//false
        System.out.println(list.remove("隐身娃"));
        System.out.println(list.size());//6
        System.out.println(Arrays.toString(list.toArray()));//先转数组再打印
        System.out.println();

        //2.List集合有自己的方法
        /*List集合是有序的,所以可以根据索引来操作集合中的元素
        * 可以存放重复的数据*/
        list.add("小蝴蝶");//添加元素,默认添加在集合的未尾
        list.add(1,"蛇精");//在指定的索引处添加元素
        list.add(3,"小蝴蝶");//在指定的索引处添加元素
        System.out.println(list);

        System.out.println(list.indexOf("小蝴蝶"));//3,获取元素第1次出现的下标
        System.out.println(list.lastIndexOf("小蝴蝶"));//8,获取元素最后1次出现的索引
        System.out.println(list);
        list.remove(5);//删除喷火娃,根据索引下标删除元素
        System.out.println(list);

        System.out.println(list.get(3));//小蝴蝶,根据索引下标获取元素
        System.out.println(list.set(7,"蝎子精"));//修改指定下标处的元素为蝎子精
        System.out.println(list);

        //4.测试集合间的操作
        List<String> ls = new ArrayList<>();
        ls.add("1");
        ls.add("2");
        ls.add("3");
        ls.add("4");
        System.out.println(ls);//查看集合中的元素

        list.addAll(ls);//将集合ls的元素全部添加到list集合中,默认追加到集合的最后
        System.out.println(list);
        list.addAll(1,ls);//指定下标,将集合ls的所有元素添加到list集合中
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

guan_xfeng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值