字符串 String

Java 中,String 是一个引用类型,它本身是一个 class。因此,比较两个字符串的内容是否相同时,必须使用 equals() 方法而不能用 ==

  1. String str = "value";
  2. var equals = "value".equals(str);

String 类是不可变类

String 对象被创建后,包含在这个对象汇总的字符序列是不可以更改的,直到这个对象被销毁。

  1. public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
  2. @Stable
  3. private final byte[] value;
  4. private final byte coder;
  5. public String() {
  6. this.value = "".value;
  7. this.coder = "".coder;
  8. }
  9. public String(String original) {
  10. this.value = original.value;
  11. this.coder = original.coder;
  12. this.hash = original.hash;
  13. }
  14. }

在 Java 9 以前字符串采用 char[] 数组类保存字符,因此字符串的每个字符占 2 字节;而 Java 9 及之后的字符串采用 byte[] 数组加一个 encoding-flag 字段来保存字符,因此字符串的每个字符只占 1 字节。Java 9 及之后的字符串更加节省空间

StringBuilder

使用 + 拼接字符串非常简单,但是频繁使用 + 操作拼接可能存在 GC 效率隐患。如在循环中使用 + 拼接字符串,每次循环都会创建新的字符串对象,然后扔掉旧的字符串,整个循环过程中创建的大部分字符串都是临时对象,不仅浪费内存,还会影响 GC 效率。为了能高效拼接字符串,Java 标准库提供了 StringBuilder,它是一个不可变对象,可以预分配缓冲区,往 StringBuilder 中新增字符时,不会创建新的临时对象。

StringBuilder 性能优于 “+”

  1. TimeInterval timer = DateUtil.timer();
  2. timer.start();
  3. String str = "";
  4. for (int i = 0; i < 100000; i++) {
  5. str += i;
  6. }
  7. System.out.println("milliseconds = " + timer.interval()); // 2508 ms
  8. timer.restart();
  9. StringBuilder sb = new StringBuilder();
  10. for (int i = 0; i < 100000; i++) {
  11. sb.append(i);
  12. }
  13. var stB = sb.toString();
  14. System.out.println("milliseconds = " + timer.interval()); // 3 ms

StringBuilder 支持链式操作

  1. StringBuilder sb = new StringBuilder();
  2. sb.append(1)
  3. .append(2)
  4. .append(3);

StringBuilder 类中的定义的 append() 方法会返回 this

  1. public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, Comparable<StringBuilder>, CharSequence {
  2. @Override
  3. @HotSpotIntrinsicCandidate
  4. public StringBuilder append(String str) {
  5. super.append(str);
  6. return this;
  7. }
  8. }

StringBuilder 是构造器 Builder 模式的典型设计

StringBuffer 是 StringBuilder 的线程安全版本

StringBufferStringBuilder 接口完全相同,一般只在要求线程安全拼接字符串时才使用

  1. public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, Comparable<StringBuffer>, CharSequence {
  2. @Override
  3. @HotSpotIntrinsicCandidate
  4. public synchronized StringBuffer append(String str) {
  5. toStringCache = null;
  6. super.append(str);
  7. return this;
  8. }
  9. }

包装类型

所有的包装类型都是不可变类。包装类型都是引用类型,比较包装类型是否相等必须使用 equals()

  1. public final class Integer {
  2. private final int value;
  3. }
基本类型 对应的引用类型
boolean java.lang.Boolean
byte java.lang.Byte
short java.lang.Short
int java.lang.Integer
long java.lang.Long
float java.lang.Float
double java.lang.Double
char java.lang.Character

自动装箱 (Auto Boxing)

自动装箱和自动拆箱都是在编译期完成的(JDK>=1.5)

  1. int i = 100;
  2. Integer n = Integer.valueOf(i);
  3. int x = n.intValue();

JavaBean

JavaBean 是一种符合命名规范的 class,它通过 gettersetter 方法来定义属性;通常把一组对于的读方法和写方法称为属性,仅有 getter 的属性称为只读属性 read-only ,仅有 setter 的属性称为只写属性 write-only

  1. // private 实例字段
  2. private Type xyz;
  3. // 读方法
  4. public Type getXyz();
  5. // 写方法
  6. pubilc void setXyz(Type value);

读取 JavaBean 属性列表

Java 核心库提供 Introspector 类获取 JavaBean 的所有属性

  1. import java.beans.*;
  2. public class Main {
  3. public static void main(String[] args) throws Exception {
  4. BeanInfo info = Introspector.getBeanInfo(Person.class);
  5. for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
  6. System.out.println(pd.getName());
  7. System.out.println(" " + pd.getReadMethod());
  8. System.out.println(" " + pd.getWriteMethod());
  9. }
  10. }
  11. }

枚举 Enum

当一个类的对象是有限且固定时推荐使用 enum 定义枚举类,枚举类是一个特殊的类,它一样可以有自己的成员变量、方法,可以实现一个或者多个接口,也可以定义构造器。

  • 定义的 enum 类型总是继承自 java.lang.Enum,它被编译器编译为 final class Xxx extends Enum { … }。且无法被继承
  • 只能定义除 enum 的实例,而无法通过 new 操作符创建 enum 的实例
  • 定义的每个实例都是引用类型的唯一实例
  • enum 类型适用于 switch 语句 ```java public enum SeasonEnum { /**

    • 春季 */ SPRING(1, “春季”),

      /**

    • 夏季 */ SUMMER(2, “夏季”),

      /**

    • 秋季 */ FALL(3, “秋季”),

      /**

    • 冬季 */ WINTER(4, “冬季”);

      private final int value; private final String desc;

      private SeasonEnum(int value, String desc) { this.value = value; this.desc = desc; }

      @Override public String toString() { return “[“ + SeasonEnum.class + “]” + this.value + “:” + this.desc; } }

  1. <a name="WpDw5"></a>
  2. ### enum 的比较
  3. `enum` 定义的枚举类是引用类型。通常情况下,引用类型比较需要使用 `equals()` 方法,如果使用 `==` 比较,它比较的是两个引用类型的变量是否指向同一个对象。但是因为 `enum` 类型的每个常量在 `JVM` 中只有一个唯一实例,所以可以直接使用 `==` 比较
  4. ```java
  5. var season = SeasonEnum.SPRING;
  6. if(season == SeasonEnum.FALL){
  7. // true
  8. }
  9. if(season.equals(SeasonEnum.FALL)){
  10. // true
  11. }

ordinal()

枚举定义的常量顺序从 0 开始计数。ordinal() 返回定义的常量的顺序,返回值随枚举定义顺序改变而改变

name() 和 toString()

判断枚举常量的名字,始终使用 name() 方法,绝不能使用 toString() 方法

name() 返回枚举常量名称

  1. String s = SeasonEnum.SPRING.name(); // SPRING

toString() 多用于覆写打印输出

  1. SeasonEnum.FALL.toString(); // [class com.dev.SeasonEnum]3:秋季

eunm 实现单例模式

利用 enum 类型常量在 JVM 中只会存在一个唯一实例规则实现单例,此方法线程安全且不存在反序列化攻击

  1. public enum SingletonEnum {
  2. INSTANCE;
  3. public void doSomething(){
  4. System.out.println("INSTANCE = " + INSTANCE);
  5. }
  6. }

BigInteger 和 BigDecimal

Java 中,由 CPU 原声提供的整型最大范围是 64long 型长整数。超过 long 型整数用 java.math.BigInteger 来表示。BigInteger 内部用一个 int[] 数组来模拟一个非常大的整数

  1. BigInteger bi = new BigInteger("1234567890");
  2. System.out.println(bi.pow(5)); // 2867971860299718107233761438093672048294900000

Random 、ThreadLocalRandom 和 SecureRandom

Random 类专门用于生成一个伪随机数。伪随机数是指只要给定一个初始的种子,产生的随机数序列是完全一样的

  1. Random r1 = new Random(50);
  2. var i1 = r1.nextInt(); // -1160871061
  3. Random r2 = new Random(50);
  4. var i2 = r2.nextInt(); // -1160871061

为了避免两个 Random 对象产生相同的数字序列,通常使用当前时间作为 Random 对象的种子

  1. Random random = new Random(System.currentTimeMillis());

ThreadLocalRandomSecureRandom 都继承自 Random 类。ThreadLocalRandom 位于 java.util.concurrent 包中,它是 Random 的线程安全增强版,在并发访问环境下可以减少多线程资源竞争;SecureRandom 位于 java.security 包中,它是真随机数类

  1. package java.util.concurrent
  2. public class ThreadLocalRandom extends Random {}
  3. package java.security
  4. public class SecureRandom extends java.util.Random {}