2021-06-09 2021-6-10 2021-6-11 JAVA学习笔记

泛型

250 泛型概述

看不懂图片可以看:https://zhuanlan.zhihu.com/p/78811004
在这里插入图片描述

使用泛型最直观的例子就是:Collection<String> c1=new ArrayList<String>();,其中的String就是数据的操作类型,把数据的操作类型指定为参数就称为:泛型。

251 泛型类

泛型类就是把泛型定义在类上,用户使用该类的时候,才把类型明确下来
在这里插入图片描述

/*
    1:把泛型定义在类上
    2:类型变量定义在类上,方法中也可以使用
 */
public class ObjectTool<T> {
    private T obj;

    public T getObj() {
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }
}

测试代码:

    public static void main(String[] args) {
        //创建对象并指定元素类型,泛型的使用!!!
        ObjectTool<String> tool = new ObjectTool<>();

        tool.setObj(new String("钟福成"));
        String s = tool.getObj();
        System.out.println(s);


        //创建对象并指定元素类型,泛型的使用!!!
        ObjectTool<Integer> objectTool = new ObjectTool<>();
        /**
         * 如果我在这个对象里传入的是String类型的,它在编译时期就通过不了了.
         */
        objectTool.setObj(10);
        int i = objectTool.getObj();
        System.out.println(i);
    }

252 泛型方法

1.泛型类在使用的时候需要制定参数,而泛型方法会自动识别传入的参数类型,所以在使用方法上:使用泛型类需要写类型参数,而使用泛型方法的时候不需要写类型参数(与正常调用方法无异)
2.在定义上泛型方法也与类有很大区别,泛型符号是写在返回值类型前面滴。
在这里插入图片描述

253 泛型接口

泛型接口:

/*
    把泛型定义在接口上
 */
public interface Inter<T> {
    public abstract void show(T t);

}

泛型接口的实现类:
当子类不明确泛型类的类型参数变量时,外界使用子类的时候,也需要传递类型参数变量进来,在实现类上需要定义出类型参数变量。

/**
 * 子类不明确泛型类的类型参数变量:
 *      实现类也要定义出<T>类型的
 *
 */
public class InterImpl<T> implements Inter<T> {

    @Override
    public void show(T t) {
        System.out.println(t);

    }
}

测试类代码与泛型类基本一致。

254 泛型——类型通配符

类型通配符是在用泛型创建对象的时候使用的,目的是限制类别。
在这里插入图片描述
建议看链接中的3.4类型通配符,写的很好。

255 泛型——可变参数

需求分析:写出一个方法,要求求任意多个int类型数据之和,传入的参数的个数是不确定的,可变参数其实说的是参数的个数可变。
在这里插入图片描述
执行下列代码:

    public static void main(String[] args) {
        sum(10,15);
    }
    public static void sum(int... a){
        System.out.println(a);
    }

输出结果为:

[I@3ac3fd8b

说明a实际是一个数组,一个储存了传入所有数据(int类型)的数组,因此实现求和方法将代码改为:

    public static void main(String[] args) {
        sum(10,15);
    }
    public static void sum(int... a){
        int temp =0;
        for (int i:a){
            temp +=i;
        }
        System.out.println(temp);
    }

在这里插入图片描述
可变参数要放在最后是因为在上一个代码块中int....a会吸收所有的int形式变量,如果需要单独传入某个特殊参数不方便操作,输入int....a,int b会报错,必要时参数要写作int b,int...a

255 泛型——可变参数的使用

在这里插入图片描述
1.接口里面可以有静态方法,原来讲课的时候没有讲到,这属于新特性。(静态方法可以直接通过类名调用。)
2.注意三种形式生成的表类型有所区别,操作限权每个都不同。(都有查看的方法,都不能改变表的元素个数。)
3.对set集合没有修改方法的说明:set集合特点就是不支持带索引的操作,而set方法是带索引的方法,肯定是不支持的。

257 Map集合

在这里插入图片描述

HashMap users = new HashMap();
        users.put("11", "张浩太"); // 将学生信息键值对存储到Map中
        users.put("22", "刘思诚");
        users.put("33", "王强文");
        users.put("44", "李国量");
        users.put("55", "王路路");

需要注意的是:key不能重复,如果写入重复的key,那么新的值就会替代原来的值。换句话说put方法在key不同时就是录入数据,在key相同时,如输入再输入users.put("22", "思无邪");,那么22对应的就是思无邪了,刘思诚已经被顶替掉了。

Map-map集合基本功能

在这里插入图片描述
put会返回被顶替的值,remove会返回被删除的值

获取所有值集合返回的是Collection,不是Set是因为值是可以重复的,而Set集合不允许重复。

260 Map-map集合的遍历

方式1:找出键的集合,遍历所有键并且在遍历所有键的过程中找出键对应的值。范例:

  public static void main(String[] args) {
        Map<String,String> m1= new HashMap<>();
        m1.put("num001","zhangwuji");
        m1.put("num002","siwuxie");
        m1.put("num003","fengqingyang");
        Set<String> keySet = m1.keySet();
        for (String key:keySet){//Set集合不能使用索引方法,因此不能使用普通的遍历。
            String name = m1.get(key);
            System.out.println(key+","+name);
        }
    }

方式2:使用259最后标红的方法entrySet()方法
得到所有的键值对对象Map.Entry
遍历得到的键值对对象反找出所有得到键getKey()和值getValue()
范例代码如下:

 public static void main(String[] args) {
        Map<String,String> m1= new HashMap<>();
        m1.put("num001","zhangwuji");
        m1.put("num002","siwuxie");
        m1.put("num003","fengqingyang");
      /*  Set<String> keySet = m1.keySet();   //方式1
  	  for (String key:keySet){
            String name = m1.get(key);
            System.out.println(key+","+name);
        }*/
        Set<Map.Entry<String, String>> entrySet = m1.entrySet();//方式2
    for (Map.Entry<String, String> nic:entrySet){
        System.out.println(nic.getKey()+","+nic.getValue());
    }
    }

267 Collections(区别:Collection是接口,Collections是类)

Collections集合操作的工具类
在这里插入图片描述

IO流

File

272 File类概述和构造方法

在这里插入图片描述
三种构造方法都能达到一样的效果,三种构造方法的测试代码:

        File f1 = new File("D:\\test\\java.txt");
        File f2 = new File("D:\\test","java.txt");
        File test = new File("D:\\test");
        File f3 =new File(test,"java.txt");
        System.out.println(f1);
        System.out.println(f2);
        System.out.println(f3);
        /*最终系统输出:
D:\test\java.txt
D:\test\java.txt
D:\test\java.txt*/
    }

273 File类创建功能

在这里插入图片描述
对方法1:如果该文件不存在则创建该文件并返回true。如果该文件存在则不创建文件,并返回false。
方法2,3:创建的是目录,不过方法2只能创建一级目录,方法3可以创建多级目录。
注意:是创建文件还是目录是根据调用的方法,而不是根据创建File对象时输入的String的内容,如果在不存在的目录下直接创建文件,运行会报错。

275 File类判断和获取功能

在这里插入图片描述

276 File删除功能

在这里插入图片描述
对图片中相对路径:如果这么写前面默认带的是此项目的根目录,即如果写:

 public static void main(String[] args) {
    File file = new File("java.txt");
    System.out.println(file.getAbsolutePath());
}//此时系统输出:E:\develop\java_practice\IDEA_code\java.txt

276 递归

在这里插入图片描述
比如以前学过的不死神兔(有一对兔子,从出生起后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子, 假如兔子都不死,问第二十个月的兔子对数为多少?
* 规律: 1,1,2,3,5,8,13…
* 规则:A.从第三个月开始,每一项是前两项之和。
B.说明前两项是已知的。)
不死神兔的案例就可以使用递归的思想解决:
注意别忘了定义递归出口:在本问题中是前两个月的兔子数量。

    public static void main(String[] args) {
        System.out.println(f(20));
    }
    public static int f(int month){
        if(month ==1|| month ==2){
            return 1;
        }else {
            return f(month-1)+f(month-2);
        }
    }

278 递归遍历某目录下的所有内容

范例代码:

    public static void main(String[] args) {
        File f1 = new File("E:\\develop\\java_practice\\IDEA_code");
        System.out.println(f1.getAbsolutePath());
        finAll(f1);


    }
    public static void finAll(File f1){//方法的返回值为void
        if (!f1.exists()){
            System.out.println("path error!!!");
        }
        File[] listFiles = f1.listFiles();
        if (listFiles == null) throw new AssertionError();
        for (File file:listFiles){
            if (file.isFile()){
                System.out.println(file.getAbsolutePath());
            }else {
                finAll(file);
            }
        }
    }

个人感悟:对本节278和上一节276,同样是定义递归函数,为何一个有返回值一个没有返回值呢:如果递归之后需要用到数据就返回,不需要就不返回呗。比如说:算5的阶乘,需要4的阶乘,所以必须返回4的阶乘,而本节扫描显示目录下的所有文件,当遇到目录时直接进入递归进入目录扫描显示即可,不需要返回扫描的结果啥的。

字节流

279 IO流概述和分类

在这里插入图片描述
在这里插入图片描述
因为字节流是万能的流,所以不知道用哪种流可以用字节流。
在这里插入图片描述

280 字节流写数据

在这里插入图片描述
在这里插入图片描述
注意千万不要忘记释放资源。
范例程序:

    public static void main(String[] args) throws IOException {
        FileOutputStream f1 = new FileOutputStream("Io\\java.txt");//第一步
       f1.write(57);//第二步
       f1.close();  //第三步
    }//注意写入的是字节流,在文件中看到的不是字符57,而是字符9;

281 字节流写数据三种方式(write方法的三种用法)

在这里插入图片描述
对第三种方法的说明,意思就是从off索引开始写入len长度的数据。范例程序:

    public static void main(String[] args) throws IOException {
        FileOutputStream f1 = new FileOutputStream("Io\\java.txt");
       f1.write(57);//方式1
       byte[] b = {57,58,59,60,61};//方式2
       f1.write(b);
       f1.write(b,1,1);//方式3
       f1.close();
    }

知道写入的是字节流,显示的是字符,不能同等看待,那么想显示我想显示的字符除了百度查字节码外Java中String类自带获取字符串的byte流的方法getBytes。范例程序(写入:“我爱Java!!!”):

    public static void main(String[] args) throws IOException {//个人:注意运行此程序时会将这个java.txt文件里面的内容清空再写入
        FileOutputStream f1 = new FileOutputStream("Io\\java.txt");
       f1.write("我爱Java!!!".getBytes());
       f1.clos();
    }

在这里插入图片描述
第一个构造方法在内部会调用第二个构造方法,本质上做的事情都是一样的。只是单从创建字节流来说第二个方式更简单。

282 字节流写数据如何换行和追加写入

在这里插入图片描述
换行:想写入换行同样要把\r\n换成字节。
追加写入:如281第二个代码块备注所写,每次运行都会清空,那就在定义字节流的时候申明要追加写入:

    public static void main(String[] args) throws IOException {
        FileOutputStream f1 = new FileOutputStream("Io\\java.txt",true);//注意第二个参数是false代表的也是清空原文件而不是在文件开头追加写入。
       f1.write("我爱Java111!!!\n\r".getBytes());
       f1.close();
    }

字节流写数据加异常处理

前面在数据流写入时报错采用的是抛出的方式,现在采用try...catch方式处理异常:

    public static void main(String[] args)  {
        try {
            FileOutputStream f1 = new FileOutputStream("Io\\java.txt",true);
            f1.write("我爱Java111!!!\n\r".getBytes());
            f1.close();
        }catch (Exception e){
            e.printStackTrace();
        }

    }

看似完美,但是有一个隐藏的问题,在IO处理的时候一定要保证流关闭,上述代码玩意在创建或写入字节流的时候错误了,f1将无法关闭,于是引入finally
在这里插入图片描述
将代码改进为:
在这里插入图片描述
又出现错误,因为f1是在try里面被定义的,有可能错误,在外面想被看到于是改为在外面定义null,在内部再赋值,于是:
在这里插入图片描述
但是又出现了新问题,就是由于f1可能一直为null,所以close可能出现空指针异常,于是在clos那加入try....catch,:

public static void main(String[] args) {
    FileOutputStream f1 = null;
    try {
        f1 = new FileOutputStream("Io\\java.txt", true);
        f1.write("我爱Java111!!!\n\r".getBytes());

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            f1.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

284 字节流读数据(一次读一个)

在这里插入图片描述
一个一个读字节调用的是类里面的read()方法。
为了下面演示,现补充一个知识点,在c语言中赋值a=666整个式子的值为1.
在Java中,赋值的是多少整个赋值式子值就是多少如:

        int a;
        System.out.println(a = 666);

系统输出为666。
再学习一个知识点,当FileIpuStream类里面的read方法已经读到数据末尾,会返回Byte数据值为-1。
综上,读数据的范例程序:也是字节流读数据的标准代码

    public static void main(String[] args) throws IOException {

        FileInputStream f2 =new FileInputStream("Io\\java.txt");
        int temp;
        while ((temp =  f2.read())!= -1){
            System.out.print((char)temp);
        }
        f2.close();
    }//经过验证,汉字读取有问题!!!注意这点,后面字符流与这有关

字节流一次读一个字节数组数据

新知识点:1.一次读入byte数组长度的字符串的read方法,此方法返回值为实际读取到的字符的个数,如果一个都没有读取到,那么和读一个字节一样返回-1;
2.String的新构造方法,将byte数组转换为字符串
3.
范例代码:

    public static void main(String[] args) throws IOException {
        FileInputStream fRead = new FileInputStream("Io\\java.txt");
        byte[] byteRead = new byte[1024];
        System.out.println(fRead.read(byteRead));
        System.out.print(new String(byteRead));//将byte数组转化为字符串
    }

由于测试的文件为425个字符,所以先显示425,然后显示文件内容,最后显示了很多在这里插入图片描述
十分丑陋,为了避免这样的情况的发生,利用上读取到的字符的长度:在这里插入图片描述

    public static void main(String[] args) throws IOException {
        FileInputStream fRead = new FileInputStream("Io\\java.txt");
        byte[] byteRead = new byte[1024];//一般给1024及其整数倍
        int length = fRead.read(byteRead); 
        System.out.print(new String(byteRead, 0, length));//改进后的代码,只有读取到数据的那块的byte数组转化为了字符串
    }

288 字节缓冲流读/写数据

在这里插入图片描述
在写数据时,一个字节一个字节的写,写的次数明显很多,效率就会变得很低。
缓冲输出流的特点是:在流里维护了一个缓冲区,写字节时,先将字节写入缓冲区(缓冲区大小为8k),当缓冲区写满时,在一次性的将数据写到文件里。这样就降低了写的次数,提高了效率。读数据也是同理。
在使用方法,字节缓冲流读写数据和前面讲的FileInputStream只有在创建的时候有区别,其他使用都是一样的,字节缓冲流创建范例代码:

BufferedInputStream fread = new BufferedInputStream(new FileInputStream("Io\\1.jpg"));//传入输入流
BufferedOutputStream fwrite = new BufferedOutputStream(new FileOutputStream("Io\\2.jpg"));

字符流

在GBK编码中一个字节占两个Byte,UTF-8编码中一个字节占三个Byte,在如284的每次读取一个字节就显示时中文显示不出来,为了方便中文显示操作,出现了字符流
在这里插入图片描述

编码表


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

字符串中的编码解码问题

在这里插入图片描述

字符流的编码/解码问题

在这里插入图片描述
对中文的读取而言,如果采用以前的方法:

FileInputStream f1 =new FileInputStream("Io\\java.txt");
System.out.println((char) f1.read());

程序不会识别到中文需要多个byte因此无法正常显示中文,但是如果采用字符流定义:

 InputStreamReader reader = new InputStreamReader(new FileInputStream("Io\\java.txt"), "UTF-8");
        System.out.println((char) reader.read());

那么按上述代码块执行,就算是中文也能正常显示。

字符流写数据的五种方式

在这里插入图片描述
因为是字符流,所以将字节数组改为了字符数组。
首先需要注意字符流也必须要关闭,其次还要注意字符流本身是编码表+字节流,所以本身还是依靠字节流实现,但是字符流有缓冲区,因此在写入的时候必须使用flush()方法冲洗一下,这样才会刷新缓冲区实现写入,当然执行close()方法的时候也会默认先刷新一下,再写入:
在这里插入图片描述

295 字符流读数据的两种方式(一次一个/一次好多个)

注意到方法里,字节流读写数据都是字节/字节数组,字符流读写数据都是字符/字符数组。
在这里插入图片描述
关于使用字节流复制图片正常,而字节流复制图片错误的说明:
这是编码、解码的问题:

字符流按字符读数据:一次读两个字节,返回了这两个字节所对应的字符的int型数值(编码)。
写入文件时把这两个字节的内容解码成这个字符在Unicode码下对应的二进制数据写入。
即把原始文件中的二进制数据以字符形式读出,再将字符以二进制形式写入,所以得到的文件以字符方式存储。而图片的数据是按字节存储的,所以打开图片时解码出错了!

字节流按字节读数据:而字节不需要编码、解码,只有字节与字符之间转换时才需要编码、解码!所以可以正常读取图片数据。

所以,非纯文本不要用字符流
————————————————
版权声明:本文为CSDN博主「山淼」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43229056/article/details/106137920

297 字符流读写数据简化版

改进的背景:由于使用InputStreamReaderOutPutSreamWriter时常常使用的也是默认编码,所以在使用默认编码时候提供了一种简单的写法(新写法是InputStreamReaderOutPutSreamWriter的子类),需要注意的是如果使用的不是默认编码,或者设计到编码问题,还得换回InputStreamReaderOutPutSreamWriter,不能使用新学的简单写法。
记忆:有reader和writer关键词的就是字符流。
在这里插入图片描述

299 字符缓冲流

BufferedReaderBufferedWriterBufferedReaderBufferedWriterFileReaderFileWriter的关系就好比:BufferedInputStreamBufferedOutputStreamFileInputStreamFileOutputStream的关系,名字都是少了个File,然后创建方式也可以类比。字符缓冲流创建方式范例代码如下:

		BufferedReader reader = new BufferedReader(new FileReader("Io\\java.txt"));
        BufferedWriter writer = new BufferedWriter(new FileWriter("Io\\java1.txt"));

在这里插入图片描述
不包含任何终止符号也就是readline()方法只读一行的内容读不到换行符,也就输出不了换行符。
其实想一想这两个特有功能是配套的,因为读是读内容读不到换行符,如果读完之后要写入文件还得自己手动输入换行符,因此提供一个输入换行符的功能来配套。

302 Io流小节

字节流:
读写方法
在这里插入图片描述
具体实现类:
在这里插入图片描述
在这里插入图片描述
字符流:
读写方式;
在这里插入图片描述
具体实现类:FileReaderFileWriter只是图中上面的简便写法,使用方法都是一样的,只是定义格式简单,还有就是只能使用默认编码。
在这里插入图片描述
此外还可参加:

https://www.cnblogs.com/hopeyes/p/9736642.html

311 复制文件的异常处理

在这里插入图片描述
注意在JDK9改进方案中,虽然会自动释放资源,但是最终还是要抛出异常(输入,输出流对象中间那个是分号,不是逗号)。
总结:第二种方案简便。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值