思维导图:
Java常用类 一、Object- Object 是所 Java 类的跟基类;
- 累的生命中未使用 extends 关键字指明基类时,默认基类为 Object;
默认打印:ClassName@内存地址
子类可以重写;
2. finalize不推荐使用
3. equalsJava 中的内存管理和 objc 中的管理有何异同?Android 中的内存管理又是怎样的?
== 比较的是值,因此引用类型比较的是引用的内存地址,而 Object 对象的 equals 方法默认实现是比较内存地址是否相等;
String 重写了 equals 方法;
4. hashCode该方法返回对象的内存地址经过哈希算法之后的值;
该方法的返回值可以近似的看做是对象的内存地址,如果对象相等(equals),那么hashCode() 的返回值必须一致,反之不一致;
二、String略;
详情见Java:常量池;
提一嘴:
String 类重写了 hashCode() 方法,其内部逻辑是对字符串进行 hashCode 并返回,所以只要字符串相等,那么 hashCode() 函数的返回值都相等,不能用这个返回值当做内存地址,需要调用 System.identityHashCode(instance) 来获取真实的 hashCode。该方法本质是无论类是否重写了 hashCode() 方法,都只会调用 Object 的 hashCode() 方法;
三、 包装类 1. 概念8 中基本数据类型对应有 8 中包装类。包装类属于引用数据类型,父类是 object
为什么需要包装类
面向对象的编程中,方法入参基本都是引用类型,基础类型就不能当做参数传递。所以需要一个包装类型来进行传递,在使用时在拆包;
8 中基础类型对应的包装类:
image.png 2. 拆箱和装箱- 拆箱
Number 是一个抽象类,有拆箱方法,需要子类实现;
- 装箱
在 JDK5.0之前是不允许直接将基本数据类型的数据直接赋值给其对应地包装类的,如:Integer i = 5;
但是在JDK5.0中支持这种写法,因为编译器会自动将上面的代码转换成如下代码:Integer i=Integer.valueOf(5);
这就是 Java 的装箱.JDK5.0也提供了自动拆箱:
// 自动装箱 Integer i =5; // 自动拆箱 int j = i;
特别注意:
- 双等号不会自动拆箱,只有在运算的时候才会有自动拆箱,装箱的本质还是创建了包装类对象;
来看一个例子:
代码1:
Integer a = 128; Integer b = 128; System.out.println(a == b); //false
这是因为双等号时不会自动拆箱,而 == 的本质是调用 hashCode 并判断值是否相等,所以这里是 false;
代码2:
Integer a = 127; Integer b = 127; System.out.println(a == b); //true
原因:
Java 中基本类型的包装类大部分都实现了常量池技术: Byte、Short、Integer、Long、Character、Boolean;只有浮点数类型的包装类没有实现。而且, Byte、Short、Integer、Long、Character 这 5 种类型只有在值小于 127 时才使用常量池,即对象常量池不负责创建和管理大于 127 的这些类对象;
因此,a 和 b 得到的对象都是常量池中的对象,是同一个,所以相等;
包装类具体实现详见:Java:常量池
PS:包装类没有字符串的 intern 方法,所以不能向常量池中添加新的常量对象;
Integer 整数常量池源码实现:
image.png代码逻辑:静态代码块在 Integer 第一次使用时执行,创建了 256 个 Integer 对象存放在 cache 数组中。cache 数组使用 final 修饰,存储在静态区。整数型常量池的本质就是内存缓存;
四、Enum 1. 基本使用public class EnumTest {
public static void main(String[] args) {
XKType.values()
XKType type = XKType.XKType1;
switch (type){
case XKType1:
System.out.println("Type1");
break;
case XKType2:
System.out.println("Type2");
break;
case XKType3:
System.out.println("Type3");
}
}
}
enum XKType {
XKType1,
XKType2,
XKType3
}
3. 原理
- 是一个类;
使用 javac 指令编译 java 文件之后会生成一个枚举类型对应的类:
枚举类- public static final ;
枚举类的内部会使用 public static final 生成对应的枚举值;
这里反编译代码已经没有具体实现了,但是网上看到了具体的实现代码,可能和 JDK 或者 javap 指令的版本有关,以下是一个星期一到星期天的枚举实现:
.java 文件:
// 字符串最好使用大写
enmu Day {
SUNDAY,MONDAY, TUESDAY, WEDNESDAY,THURSDAY, FRIDAY, SATURDAY
}
反编译 .class 文件:
//反编译Day.class
final class Day extends Enum
{
//编译器为我们添加的静态的values()方法
public static Day[] values()
{
return (Day[])$VALUES.clone();
}
//编译器为我们添加的静态的valueOf()方法,注意间接调用了Enum也类的valueOf方法
public static Day valueOf(String s)
{
return (Day)Enum.valueOf(com/zejian/enumdemo/Day, s);
}
//私有构造函数
private Day(String s, int i)
{
super(s, i);
}
//前面定义的7种枚举实例
public static final Day MONDAY;
public static final Day TUESDAY;
public static final Day WEDNESDAY;
public static final Day THURSDAY;
public static final Day FRIDAY;
public static final Day SATURDAY;
public static final Day SUNDAY;
private static final Day $VALUES[];
static
{
//实例化枚举实例
MonDAY = new Day("MONDAY", 0);
TUESDAY = new Day("TUESDAY", 1);
WEDNESDAY = new Day("WEDNESDAY", 2);
THURSDAY = new Day("THURSDAY", 3);
FRIDAY = new Day("FRIDAY", 4);
SATURDAY = new Day("SATURDAY", 5);
SUNDAY = new Day("SUNDAY", 6);
$VALUES = (new Day[] {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
});
}
}
原文链接:https://blog.csdn.net/javazejian/article/details/71333103
如上代码所示,枚举类的实现方式大概为:
- 按照枚举名新建一个枚举类;
- 类中按照枚举值添加成员属性,且使用 pulic static final 修饰;
- 构造方法中为 String 类型的枚举值赋 Int 类型的值,完成关联。以此达到使用 String 的形式来使用,但本质还是 Int 来进行区分;
- 静态代码块中确保类在被加载时,所有的枚举值被添加到 VALUES 数组中,供 values() 方法访问;



