2022.08.23 学习笔记

学习笔记

快速幂

思路:分治法,递归依次求出每次二分之一次方的值,再进行汇总

    public double myPow(double x, int n) {
        return n >= 0?pow(x,n):1.0/pow(x,n);
    }

    public double pow(double x, int n){
        if(n == 0){
            return 1.0;
        }
        double y = pow(x,n/2);
        return n%2==0?y*y:y*y*x;
    }

java IO

字节流和字符流

从数据传输方式的角度,IO分成字节流(计算机)和字符流(人)

字节流读取单个字节,字符流读取单个字符(一个字符根据编码的不同,对应的字节也不同,如 UTF-8 编码中文汉字是 3 个字节,GBK编码中文汉字是 2 个字节。)

字节流用来处理二进制文件(图片、MP3、视频文件),字符流用来处理文本文件(可以看做是特殊的二进制文件,使用了某种编码,人可以阅读)。

编码就是把字符转换为字节,而解码是把字节重新组合成字符。

如果编码和解码过程使用不同的编码方式那么就出现了乱码。

  • GBK 编码中,中文字符占 2 个字节,英文字符占 1 个字节;
  • UTF-8 编码中,中文字符占 3 个字节,英文字符占 1 个字节;
  • UTF-16be 编码中,中文字符和英文字符都占 2 个字节。

UTF-16be 中的 be 指的是 Big Endian,也就是大端。相应地也有 UTF-16le,le 指的是 Little Endian,也就是小端。

Java 使用双字节编码 UTF-16be,这不是指 Java 只支持这一种编码方式,而是说 char 这种类型使用 UTF-16be 进行编码。char 类型占 16 位,也就是两个字节,Java 使用这种双字节编码是为了让一个中文或者一个英文都能使用一个 char 来存储。

在这里插入图片描述

IO装饰者模式

FileInputStream fileInputStream = new FileInputStream(filePath);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);

实例化一个具有缓存功能的字节流对象时,只需要在 FileInputStream 对象上再套一层 BufferedInputStream 对象即可。

此时FileInputStream是被装饰者,BufferedInputStream是装饰者,所以这个算是较为常见的形式,多层Stream相互嵌套。

File相关操作

File 类可以用于表示文件和目录的信息,但是它不表示文件的内容。

递归地列出一个目录下所有文件:

public static void listAllFiles(File dir) {
    if (dir == null || !dir.exists()) {
        return;
    }
    if (dir.isFile()) {
        System.out.println(dir.getName());
        return;
    }
    for (File file : dir.listFiles()) {
        listAllFiles(file);
    }
}

字节流相关操作

        public static void copyFile(String src, String dist) throws IOException {

            FileInputStream in = new FileInputStream(src);
            FileOutputStream out = new FileOutputStream(dist);
            byte[] buffer = new byte[20 * 1024];

            // read() 最多读取 buffer.length 个字节
            // 返回的是实际读取的个数
            // 返回 -1 的时候表示读到 eof,即文件尾
            // in相关方法是read,将传入的字节流读进缓存中,数据流动方向是参数到in中
            // out相关方法是write,将数据从out方法中写出到out中
            while (in.read(buffer, 0, buffer.length) != -1) {
                out.write(buffer);
            }

            in.close();
            out.close();
        }

逐行输出文本文件内容

public static void readFileContent(String filePath) throws IOException {

    FileReader fileReader = new FileReader(filePath);
    BufferedReader bufferedReader = new BufferedReader(fileReader);

    String line;
    while ((line = bufferedReader.readLine()) != null) {
        System.out.println(line);
    }

    // 装饰者模式使得 BufferedReader 组合了一个 Reader 对象
    // 在调用 BufferedReader 的 close() 方法时会去调用 Reader 的 close() 方法
    // 因此只要一个 close() 调用即可
    bufferedReader.close();
}

序列化&Serializable&transient

序列化就是将一个对象转换成字节序列,方便存储和传输

序列化就是将一个对象转换成字节序列,方便存储和传输。

  • 序列化: ObjectOutputStream.writeObject()
  • 反序列化: ObjectInputStream.readObject()

不会对静态变量进行序列化,因为序列化只是保存对象的状态,静态变量属于类的状态。

Serializable

序列化的类需要实现 Serializable 接口,它只是一个标准,没有任何方法需要实现,但是如果不去实现它的话而进行序列化,会抛出异常。

public static void main(String[] args) throws IOException, ClassNotFoundException {
    A a1 = new A(123, "abc");
    String objectFile = "file/a1";
    ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(objectFile));
    objectOutputStream.writeObject(a1);
    objectOutputStream.close();

    ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(objectFile));
    A a2 = (A) objectInputStream.readObject();
    objectInputStream.close();
    System.out.println(a2);
}

private static class A implements Serializable {
    private int x;
    private String y;

    A(int x, String y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public String toString() {
        return "x = " + x + "  " + "y = " + y;
    }
}
transient

transient 关键字可以使一些属性不会被序列化

Java中的网络支持

InetAddress: 用于表示网络上的硬件资源,即 IP 地址;

URL: 统一资源定位符;

Sockets: 使用 TCP 协议实现网络通信;

Datagram: 使用 UDP 协议实现网络通信。

InetAddress

没有公有的构造函数,只能通过静态方法来创建实例。

InetAddress.getByName(String host);
InetAddress.getByAddress(byte[] address);
URL

可以直接从 URL 中读取字节流数据。

public static void main(String[] args) throws IOException {
        
        URL url = new URL("http://www.baidu.com");
        BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream(),"utf-8"));
        String line;
        while ((line = br.readLine()) != null){
            System.out.println(line);
        }
        br.close();
}
Sockets
  • ServerSocket: 服务器端类
  • Socket: 客户端类
  • 服务器和客户端通过 InputStream 和 OutputStream 进行输入输出。
Datagram
  • DatagramSocket: 通信类
  • DatagramPacket: 数据包类

装饰者模式

装饰者和具体组件都继承自组件,具体组件的方法实现不需要依赖于其它对象,而装饰者组合了一个组件,这样它可以装饰其它装饰者或者具体组件。所谓装饰,就是把这个装饰者套在被装饰者之上,从而动态扩展被装饰者的功能。装饰者的方法有一部分是自己的,这属于它的功能,然后调用被装饰者的方法实现,从而也保留了被装饰者的功能。可以看到,具体组件应当是装饰层次的最低层,因为只有具体组件的方法实现不需要依赖于其它对象。

具体实例:

设计不同种类的饮料,饮料可以添加配料,比如可以添加牛奶,并且支持动态添加新配料。每增加一种配料,该饮料的价格就会增加,要求计算一种饮料的价格。

下图表示在 DarkRoast 饮料上新增新添加 Mocha 配料,之后又添加了 Whip 配料。DarkRoast 被 Mocha 包裹,Mocha 又被 Whip 包裹。它们都继承自相同父类,都有 cost() 方法,外层类的 cost() 方法调用了内层类的 cost() 方法。

在这里插入图片描述

public interface Beverage {
    double cost();
}   
public class DarkRoast implements Beverage {
    @Override
    public double cost() {
        return 1;
    }
}
public class HouseBlend implements Beverage {
    @Override
    public double cost() {
        return 1;
    }
}    
public abstract class CondimentDecorator implements Beverage {
    protected Beverage beverage;
}   
public class Milk extends CondimentDecorator {

    public Milk(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public double cost() {
        return 1 + beverage.cost();
    }
}
public class Mocha extends CondimentDecorator {

    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public double cost() {
        return 1 + beverage.cost();
    }
}    
public class Client {
    public static void main(String[] args) {
        Beverage beverage = new HouseBlend();
        beverage = new Mocha(beverage);
        beverage = new Milk(beverage);
        System.out.println(beverage.cost());
    }
}

类应该对扩展开放,对修改关闭: 也就是添加新功能时不需要修改代码。饮料可以动态添加新的配料,而不需要去修改饮料的代码。

参考链接:https://pdai.tech/md/java/io/java-io-basic-category.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值