文章

Java 常用基础类库

2020.12.10 ・ 共 2795 字,您可能需要 6 分钟阅读

Tags: Java, 学习笔记

  • 每一个字符串的常量都属于一个 String 类的匿名对象,不可更改。
  • String 有两个常量池:静态常量池、运行时常量池。
  • String 类对象实例化建议使用直接赋值的方式完成,这样可以将对象保存在对象池中,以便下次使用。

String类虽好,但也存在弊端,内容不允许修改,虽然大多数时间不会对字符串内容进行频繁地修改,但是依然可能会存在有这样地情况,为了解决此问题专门提供了StringBuffer类,进行内容的修改。

StringBuffer并不像String类那样拥有两种对象实例化方式,StringBuffer必须像普通类那样,进行对象实例化,然后进行调用方法进行处理,而这个时候可以考虑使用StringBuffer的如下方法。

  • 构造方法:
    • public StringBuffer()
    • pubic StringBuffer(String str)
  • 数据追加:public StringBuffer append( 各种数据类型 )相当于字符串的 +
public class Test {
  public static void main(String[] args) {
    StringBuffer sb = new StringBuffer("Hello");
    change(sb);
    System.out.println(sb);
  }

  public static void change(StringBuffer temp) {
    temp.append("World");
  }
}

大部分情况下很少出现字符串内容的改变,这种改变并不是针对静态常量池的改变。

public StringBuffer insert(int offset, 数据类型 b)

public class Test {
  public static void main(String[] args) {
    StringBuffer sb = new StringBuffer();
    sb.append("hello").insert(0, "world");
    System.out.println(sb);
  }
}

public StringBuffer delete(int start, int end)

public class Test {
  public static void main(String[] args) {
    StringBuffer sb = new StringBuffer();
    sb.append("hello").delete(0, 2);
    System.out.println(sb);
  }
}

public StringBuffer reverse()

public class Test {
  public static void main(String[] args) {
    StringBuffer sb = new StringBuffer();
    sb.append("hello");
    System.out.println(sb.reverse());
  }
}

StringBuffer类相似的还有一个StringBuider类,他们的方法功能相同,最大的区别就是StringBuffer中的方法是线程安全的,有synchronized关键字,而StringBuider没有。

CharSequence是一个描述字符串结构的接口,有三个常用的子类实现了这个接口。分别是String,StringBuffer,StringBuilder

StringBufferStringBuilder中可以将CharSequence作为参数传入。只要有字符串,就可以为CharSequence接口实例化。

public class Test {
  public static void main(String[] args) {
    CharSequence str = "hello world"; // 子类实例向父接口向上转型
  }
}

CharSequence中定义有如下操作方法。

  • char charAt(int index);查看在 index 位置的字符。
  • int length();获取字符串的长度。
  • CharSequence subSequence(int start, int end);截取部分字符串。
public class Test {
  public static void main(String[] args) {
    CharSequence str = "hello world"; // 子类实例向父接口向上转型
    CharSequence sub = str.subSequence(0, 5);
    System.out.println(sub);
  }
}

CharSequence描述的就是一个字符串。

AutoCloseable主要是用于资源开发的处理上,以实现资源的自动关闭。在进行文件、网络、数据库的开发过程之中,由于服务器的资源有限,在使用之后,应该关闭资源。

模拟消息发送处理流程:

public class Test {
  public static void main(String[] args) {
    NetMessage nm = new NetMessage("haha");
    if (nm.open()) {
      nm.send();
      nm.close();
    }
  }
}

class NetMessage implements IMessage { // 实现消息的处理机制
  private String msg;

  public NetMessage(String msg) {
    this.msg = msg;
  }

  public void send() {
    System.out.println("发送消息" + msg);
  }

  public boolean open() { // 获取资源连接
    System.out.println("获取资源连接");
    return true;
  }

  public void close() {
    System.out.println("关闭消息通道");
  }
}

interface IMessage {
  public void send();
}

既然所有的资源完成处理之后要进行关闭操作,那么为什么不进行自动关闭呢?于是为了实现这一需求,出现了AutoCloseable接口。该接口只提供有一个方法void close() throws Exception

要想实现自动关闭处理,除了要实现AutoClosed之外,还需要结合异常处理语句才能正常调用。

public class Test {
  public static void main(String[] args) throws Exception {
    try (NetMessage nm = new NetMessage("haha")) {
      nm.open();
      nm.send();
    }
  }
}

class NetMessage implements IMessage { // 实现消息的处理机制
  private String msg;

  public NetMessage(String msg) {
    this.msg = msg;
  }

  public void send() {
    System.out.println("发送消息" + msg);
  }

  public boolean open() { // 获取资源连接
    System.out.println("获取资源连接");
    return true;
  }

  public void close() throws Exception {
    System.out.println("关闭消息通道");
  }
}

interface IMessage extends AutoCloseable {
  public void send();
}

Runtime描述的是运行时的状态,在整个 JVM 中,Runtime类是唯一一个与 JVM 运行状态有关的类,并且都会默认提供一个该类的实例化对象。

由于在每一个 JVM 进程里面只允许提供有一个Runtime类的对象,所以这个类的构造方法是默认私有的,则证明该类使用的是单类设计模式,所以就会提供一个静态方法获取本类实例。

如果想获取实例化对象,那么就可以依靠类中的public static Runtime getRuntime()完成。

public class Test {
  public static void main(String[] args) {
    Runtime run = Runtime.getRuntime();
    System.out.println(run.availableProcessors()); // 获取当前可用线程数
    System.out.println(run.maxMemory()); // 获取最大可用内存空间
    System.out.println(run.totalMemory()); // 获取可用内存空间
    System.out.println(run.freeMemory()); // 获取空闲内存空间
    run.gc(); // 手工进行垃圾回收
  }
}
  • 数组复制:public static native void arraycopy(Object src, int srcPos,Object dest, int destPos, int length);
  • 获取当前时间:public static native long currentTimeMillis();
  • 垃圾回收:
public static void gc() {
        Runtime.getRuntime().gc();
    }

Cleaner类主要是进行finalize()的替代。

import java.lang.ref.Cleaner;

public class Test {
  public static void main(String[] args) {
    try (MemberCleaning mc = new MemberCleaning()) {
      ;
    } catch (Exception ignored) {
    }
  }
}

class Member implements Runnable {
  public Member() {
    System.out.println("构造");
  }

  public void run() {
    System.out.println("回收");
  }
}

class MemberCleaning implements AutoCloseable {
  private static final Cleaner cleaner = Cleaner.create();
  private final Cleaner.Cleanable cleanable;

  public MemberCleaning() {
    Member member = new Member();
    this.cleanable = cleaner.register(this, member);
  }

  public void close() {
    this.cleanable.clean();
  }
}

在当前进行回收的时候,更注重于对于多线程的使用,防止有可能造成的延迟处理。所以很多对象回收前的单独处理都是单独通过一个线程完成的。

所谓的对象克隆指的就是对象复制,而且属于全新的复制,需要使用Object中的clone()。所有的类都有clone(),但不是所有的类都希望被克隆。如果想实现对象克隆,那么对象所在的类需要实现接口Cloneable。此接口没有一个方法,因为它描述的是一种能力。

public class Test {
  public static void main(String[] args) throws CloneNotSupportedException {
    Member member = new Member("haha", 12);
    Member memberB = (Member) member.clone();
    System.out.println(member);
    System.out.println(memberB);
  }
}

class Member implements Cloneable {
  private String name;
  private int age;

  public Member(String name, int age) {
    this.name = name;
    this.age = age;
  }

  public String toString() {
    return super.toString() + " name:" + name + " age:" + age;
  }

  @Override
  protected Object clone() throws CloneNotSupportedException {
    return super.clone(); // 调用父类的克隆方法
  }
}

主要的功能是进行数学计算的操作类,提供有基础的数学公式。这个类的继承方法是私有化的,该类提供的所有方法都是静态的。

主要方法是用来提供随机数,这个类主要是依靠内部提供的方法来完成。

  • 产生一个在 [0, bound) 的整数:public int nextInt(int bound)

假设一个数字很大,超过了 double 的范围,这个时候没有一种数据类型可以保存下此内容,为了解决此问题,提供有两个大数字操作类。

import java.math.BigInteger;

public class Test {
  public static void main(String[] args) {
    BigInteger bigA = new BigInteger("41231231312");
    BigInteger bigB = new BigInteger("1123123131231");
    System.out.println(bigA.add(bigB)); // 加
    System.out.println(bigA.divide(bigB)); // 除
    System.out.println(bigA.subtract(bigB)); // 减
    System.out.println(bigA.multiply(bigB)); // 乘
    BigInteger[] result = bigA.divideAndRemainder(bigB);
    System.out.println(result[0] + "" + result[1]); // 商,余数
  }
}

使用基本同上,但是在BigDecimal中有一个数据进位的问题,使用如下方式进行进位控制。

import java.math.BigDecimal;
import java.math.RoundingMode;

public class Test {
  public static void main(String[] args) {
    BigDecimal bigA = new BigDecimal("1231.15752");
    double result = bigA.divide(new BigDecimal("1.0"), 3, RoundingMode.HALF_DOWN).doubleValue();
    System.out.println(result);
  }
}

Math的处理由于使用的都是基本数据类型,所以性能一定是高于大数字处理类。

在 Java 里提供一个java.util.Date,这个类如果直接实例化就可以获取当前的日期。Date只是对 long 的一种包装,所以一定提供相互转换。

  • 将 long 转为 Date public Date(long date)
  • 将 Date 转为 long public long getTime()
import java.util.Date;

public class Test {
  public static void main(String[] args) {
    Date date = new Date();
    System.out.println(date);
    long current = date.getTime();
    current += 86400000; // 毫秒
    System.out.println(new Date(current));
  }
}