Java_包装类、Object类(6)

包装类

byte -> Byte、 short -> Short、 int -> Integer、 long -> Long

float -> Float、 double -> Double、 char -> Character、 boolean -> Boolean

以 Integer 为例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class Test {
  public static void main(String[] args) {
    System.out.println(Integer.toBinaryString(4)); //100
    System.out.println(Integer.MAX_VALUE); //2147483647
    System.out.println(Integer.MIN_VALUE); //-2147483648
    Integer i1 = new Integer(100);
    System.out.println(i1); //100
    Integer i2 = new Integer("100");
    System.out.println(i2); //100
    Integer i3 = new Integer("abc"); //报错
  }
}

JDK1.5 之后新增了自动拆装箱

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Test {
  public static void main(String[] args) {
    Integer i2 = new Integer(100); //手动装箱
    int i3 = i2.intValue(); //手动拆箱

    Integer i4 = 100; //自动装箱
    int i5 = i4 + 100; //自动拆箱

    Integer i6 = null;
    //int i7 = i6 + 100; //空指针异常

    Integer i8 = new Integer(100);
    Integer i9 = new Integer(100);
    //显示地创建两个对象所以==为fasle
    System.out.println(i8 == i9);      //false
    System.out.println(i8.equals(i9)); //true

    Integer i10 = 100;
    Integer i11 = 100;
    //自动装箱,Integer底层实现有缓存,100在缓存范围内
    System.out.println(i10 == i11); //true

    Integer i12 = 128;
    Integer i13 = 128;
    //128超出了缓存范围,所以i12和i13指向了两个不同的对象
    System.out.println(i12 == i13); //false

  }
}

IntegerCache

上面提到的 Integer 底层实现有缓存,查看 Integer 的源码可知其定义有内部类 IntegerCache

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
private static class IntegerCache {
  static final int low = -128;
  static final int high;
  static final Integer cache[];
  static {
    // high value may be configured by property
    int h = 127;
    //获取虚拟机启动参数的配置的high
    high = h;
    cache = new Integer[(high - low) + 1];
    int j = low;
    for(int k = 0; k < cache.length; k++)
      cache[k] = new Integer(j++);
  }
 
  public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
      return IntegerCache.cache[i + (-IntegerCache.low)];
    //超过范围则新建对象
    return new Integer(i);
  }
}

Java 5 引入 IntegerCache 时范围固定为 -128 ~ 127,所以在使用 Integer 的时候要注意其底层的缓存数组可能带来的问题

Java 6 之后可以通过设置 JVM 的启动参数 -XX:AutoBoxCacheMax=size 来设置 IntegerCache 的最大值 java.lang.Integer.IntegerCache.high,但默认值仍为 127

和 String 的转换

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public class Test {
  public static void main(String[] args) {
    //int ---> String
    int i1 = 100;
    //字符串拼接
    String s1 = i1 + "";
    //调用String的valueOf()
    s1 = String.valueOf(i1);
    //调用Integer静态的toString方法
    s1 = Integer.toString(i1);
    //调用Integer对象的toString方法
    Integer i2 = i1;
    s1 = i2.toString();

    //String ---> int
    String s2 = "100";
    //调用Integer静态的parseInt方法
    int i3 = Integer.parseInt(s2);
  }
}

包装类除了 Character 都有静态的 parseXxx 方法,用于将字符串形式转换为基本类型

1
2
3
4
5
6
7
8
public class Test {	
  public static void main(String[] args) {
    String s1 = "true";
    boolean b = Boolean.parseBoolean(s1);
    String s2 = "3.1415";
    double d = Double.parseDouble(s2);
  }
}

Object 类

Object 类是所有类的顶层父类,所有类都默认继承 Object 类并实现其方法,包括数组

getClass 方法

class 为关键字,Class 是类名,Class 类的对象名一般叫 clazz

getClass 方法返回其对象对应的 Class 类的对象的引用 ,可用于反射,将在反射的部分进行讨论

1
2
3
4
5
6
7
8
public class Test {
  public static void main(String[] args) {
    Person per = new Person();
    Class clazz = per.getClass();
    System.out.println(clazz.getName()); //Person
  }
}
class Person {}

toString 方法

toString 方法在 Object 类中的默认实现如下,所以一般需要进行重写

1
2
3
4
public String toString() {
  //默认返回对象的类名 + @ + 对象哈希值的十六进制
  return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

hashCode 方法

JVM 会为每个对象分配一个 int 的哈希值,默认是通过对象的地址来计算的,同一个对象的哈希值相同,不同对象的哈希值不同, 而 hashCode 方法就是返回该值,是一个 native 方法

1
2
3
4
5
6
public class Test {
  public static void main(String[] args) {
    Object obj = new Object();
    System.out.println(obj.hashCode()); //1163157884
  }
}

equals 方法

比较运算符 == ,比较基本数据类型比较的是值,比较引用数据类型比较的是地址值

由于 Java 不能重载运算符,所以需要通过 equals 方法来自定义如何比较引用类型

equals 方法在 Object 类中的默认实现如下,通过 == 比较地址值

1
2
3
public boolean equals(Object obj) {
  return (this == obj);
}

clone 方法

clone 方法是浅拷贝而不是深拷贝,因为 clone 方法被 protected 修饰,所以需要实现 Cloneable 接口并重写 clone 方法才能调用,可以将权限改为 public,clone 方法在 Object 类中是 native 方法

浅拷贝,创建一个拷贝对象,将当前对象的非静态成员变量复制到拷贝对象中,对于基本类型的成员直接复制其值,对于引用类型的成员则仅仅只复制其引用,至于引用指向的对象则不会被复制

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Test {
  public static void main(String[] args) throws CloneNotSupportedException {
    City c = new City();
    c.name = "c1";
    Province p = new Province();
    p.city = c;
    Province pClone = (Province) p.clone();
    System.out.println(p);      //Province@610455d6
    System.out.println(pClone); //Province@511d50c0
    System.out.println(p.city.name);       //c1
    System.out.println(pClone.city.name);  //c1
    c.name = "c2";
    System.out.println(p.city.name);       //c2
    //因为是浅拷贝,拷贝对象的引用和当前对象的引用指向同一地址,所以这里为c2
    System.out.println(pClone.city.name);  //c2
  }
}
class Province implements Cloneable {
  City city;
  @Override
  //重写并将protected权限改为public
  public Object clone() throws CloneNotSupportedException {
    return super.clone();
  }
}
class City implements Cloneable {
  String name;
}

深拷贝,即对于引用类型的成员,将引用指向的对象也复制一份

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class Test {
  public static void main(String[] args) throws CloneNotSupportedException {
    City c = new City();
    c.name = "c1";
    Province p = new Province();
    p.city = c;
    Province pClone = (Province) p.clone();
    System.out.println(p);      //Province@610455d6
    System.out.println(pClone); //Province@511d50c0
    System.out.println(p.city.name);       //c1
    System.out.println(pClone.city.name);  //c1
    c.name = "c2";
    System.out.println(p.city.name);       //c2
    //因为是深拷贝,拷贝对象的引用指向的对象也复制了一份,所以这里为c1旧值
    System.out.println(pClone.city.name);  //c1
  }
}
class Province implements Cloneable {
  City city;
  @Override
  protected Object clone() throws CloneNotSupportedException {
    Province pClone = (Province) super.clone();
    //手动对city成员进行clone,并赋值给浅拷贝的pClone对象
    pClone.city = (City) city.clone();
    return pClone;
  }
}
class City implements Cloneable {
  String name;
  @Override
  protected Object clone() throws CloneNotSupportedException {
    return super.clone();
  }
}

深拷贝还可以通过序列化来实现

wait、notify、notifyAll 方法

将线程的等待、唤醒方法,定义在 Object 类中,是因为锁 synchronized 的锁对象可以是任意对象,Object 类是所有类的顶层父类,将传入的对象向上转型为 Object 对象即可,具体在 Java 并发中进行讨论

finalize 方法

用于垃圾回收,在 JVM 中进行讨论


以上内容是玉山整理的笔记,如有错误还请指出