| 版本 |
说明 |
发布日期 |
| 1.0 |
发布文章第一版 |
2022-06-09 |
前言
- 这篇文章不是面面俱到的基础知识集合,只是我个人的学习笔记。
- 以下所有内容仅代表个人观点,不一定正确,请大家辩证地阅读。
- 以下内容基于java 1.8。
常用类库总览
| 包名 | 说明 |
|---|
| java.lang | 核心包,包含了一些比较重要的类,该包中的所有内容由Java虚拟机自动导入。例如System、String。这个lang其实是language的缩写。 |
| java.util | 工具包,提供了工具类和集合类。如Scanner、Random、List。 |
| java.io | 输入输出包,提供了大量流相关的类。如FileInputStream。 |
| java.net | 网络包,提供了网络编程相关的类。如ServerSocket、Socket。 |
| java.sql | 数据包,提供了大量数据库操作相关的类。如DriverManager、Connection |
Object类——这就是万物皆对象~
基本概念
- 位于java.lang.Object。
- 是java中所有类的根类,也就是说是java所有类的直接或者间接父类。
- 一个人只能有一个对象,但是一个java它可以有很多很多个对象(说到这里,有些小伙伴流下了羡慕的口水)。
- java表示自己对象太多,不好管啊!所以用一个Object类统一管理。这么一说Object有点像曾经的东厂哈哈哈。
- 如果一个类定义的时候没有extends关键字,则默认会extends Object。这就是上面说的直接父类。
常用方法
| 方法声明 | 功能介绍 |
|---|
| Object() | 无参构造方法。 |
| boolean equals(Object obj) | 用于判断两个对象是否相等。Object类中的逻辑是比较地址是否相等,与 == 运算符的结果一致。所以该方法通常需要重写。若该方法被重写,同时则应该重写hashCode方法,以保证结果的一致性。 |
| int hashCode() | 用于获取调用对象的哈希码值(可通俗理解为内存地址的编号)。若两个对象调用equals方法相等,则各自调用该方法的结果必须相同;若两个调用对象equals方法不相等,则各自调用该方法的结果应该不相同。所以该方法通常需要与equals方法同时重写。 |
| String toString() | 用于获取调用对象的字符串形式。该方法默认返回的字符串为:包名.类名@哈希码值的十六进制。为了返回更有意义的数据,该方法通常需要重写。使用print打印引用或使用字符串拼接引用时,都会自动调用该方法。 |
| Class<?> getClass() | 用于获取调用对象的Class对象,反射机制使用。 |
boolean equals(Object obj)
- Java API文档对于equals方法提出了几个特性,当我们重写equals时,应当自觉遵循这些特性。
- 自反性:对于任何非空引用x,x.equals(x)应该返回true。
- 对称性:对于任何非空引用x和y,x.equals(y)应该返回true,当且仅当y.equals(x)返回true。
- 传递性:对于任何非空引用x、y和z。如果x.equals(y)返回true、y.equals(z)返回true。则x.equals(z)也应该返回true。
- 一致性:对于任何非空引用x和y,如果未修改对象上用于equals比较的信息,则多次调用x.equals(y)应该始终返回true或始终返回false。
- 非空性:对于任何非空引用x,x.equals(null)应该返回false。
- 下面给一个最常见的equals重写模板,可以完全满足上面的所有特性。当然方法不是绝对的,只要能满足这些特性就OK啦~
public class Person {
private String id;
public Person(String id) {
this.id = id;
}
public void setId(String id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Person) {
return this.id.equals(((Person) obj).id);
}
return false;
}
@Override
public int hashCode(){
return id.hashCode();
}
public static void main(String[] args) {
Person yu = new Person("1996817");
Person angel = new Person("1997414");
System.out.println("angel.equals(yu):" + angel.equals(yu));
System.out.println("更改id");
yu.setId("1997414");
System.out.println("angel.equals(yu):" + angel.equals(yu));
System.out.println("yu.equals(angel):" + yu.equals(angel));
System.out.println("angel.equals(angel):" + angel.equals(angel));
System.out.println("angel.equals(null):" + angel.equals(null));
}
}
angel.equals(yu):false
更改id
angel.equals(yu):true
yu.equals(angel):true
angel.equals(angel):true
angel.equals(null):false
int hashCode()
- hashCode是在使用哈希集合(例如HashMap)时,在键值散列表中用到,这一点从API文档中也能看到。
- 因此,equals不等的对象,hashCode需要尽量不等;equals相等的对象,hashCode必须相等。
- 上面说过,重写了equals方法,必然还需要重写hashCode方法。但是怎么重写呢?
- 通常,我们会分别对equals中的比较特征值(例如上例的id)求hash,然后将他们的和作为hash结果。
- Objects类提供了一个静态方法:hash(Object... values)。获取比较特征值的hash时,经常会用到。
自动生成equals、hashCode、toString
- 如果你用的idea,恭喜你,这三个方法可以自动按照模板生成(默认快捷键:Alt + Insert)。
- 上面的例子,如果使用idea的自动生成,代码将会如下。
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(id, person.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
@Override
public String toString() {
return "Person{" +
"id='" + id + ''' +
'}';
}
包装类
基本概念
- 位于java.lang.Byte、java.lang.Short等。
- 用于将基本数据类型包装成对象,以满足Java“万物皆对象”的理念。
- 目前包装类有以下几种:Byte、Short、Integer、Long、Float、Double、Boolean、Character。分别对应一种基本数据类型。
- 数字类型的包装类统一继承了抽象类Number。
- 将基本数据类型转换为包装类,称为装箱;将包装类转换为基本数据类型,称为拆箱。从Java1.5开始,增加了大量自动拆箱和装箱的机制。
- 下面讲解几种典型的包装类。
Integer
常用常量
| 常量声明 | 功能 |
|---|
| public static final int MAX_VALUE | 表示int类型可以描述的最大值,即2^31-1 |
| public static final int MIN_VALUE | 表示int类型可以描述的最小值,即-2^31 |
| public static final int SIZE | 表示int类型二进制形式的位数 |
| public static final int BYTES | 表示int类型所占的字节个数 |
| public static final Class TYPE | 表示int类型的Class实例 |
常用方法
| 方法声明 | 功能介绍 |
|---|
| int intValue() | 获取调用对象中的整数值并返回。作为拆箱的标准方法。 |
| static Integer valueOf(int i) | 根据参数指定整数值得到Integer类型对象。作为装箱的标准方法。 |
| boolean equals(Object obj) | 比较调用对象与参数指定的对象是否相等 |
| String toString() | 返回描述调用对象数值的字符串形式 |
| static int parseInt(String s) | 将字符串类型转换为int类型并返回。字符串不合理时会抛出NumberFormatException。 |
| static String toString(int i) | 获取参数指定整数的十进制字符串形式。注意和上面的toString的区别:静态且参数为int。 |
| static String toBinaryString(int i) | 获取参数指定整数的二进制字符串形式 |
| static String toHexString(int i) | 获取参数指定整数的十六进制字符串形式 |
| static String toOctalString(int i) | 获取参数指定整数的八进制字符串形式 |
自动装箱机制
- Java1.5之后有了自动装箱机制,从而让下面两行代码的效果是等价的。也就是说Integer对整数类型的赋值运算,会自动调用valueOf。
Integer a = 100;
Integer b = Integer.valueOf(100);
- 如果想看下自动装箱池是什么样的,可以去看源码:Integer类的静态内部类IntegerCache。
自动装箱池(常量池)
public class IntegerTest {
public static void main(String[] args){
Integer a = 1;
Integer b = 1;
Integer c = Integer.valueOf(1);
Integer d = new Integer(1);
Integer e = 128;
Integer f = 128;
System.out.println(a==b);
System.out.println(c==b);
System.out.println(d==b);
System.out.println(f==e);
}
}
true
true
false
false
- 有的小伙伴又懵了:怎么着?说好的==比地址呢?怎么结果看起来如此木有规律!?
- 但是这个真的比的是地址!为什么呢?因为包装类有一个叫自动装箱池的东西,对于-128~127的整数,对应的包装类都作为常量存放在了内存当中。所以a、b、c都是直接指向的内存中的这些常量,地址也就理所当然是相同的了。
- 需要注意的是,如果是通过直接调用构造方法,则不会用到自动装箱池,而是指向的新new出来的内存。
自动拆箱机制
Integer a = 1;
Integer b = 2;
Long g = 3L;
System.out.println(g == (a + b));
System.out.println(g.equals(a + b));
true
false
- 为什么呢?
- 对于第一个比较:大家可能第一时间会想到==比较的是地址,所以理应为false。但是包装类在进行运算符运算的时候,会触发“自动拆箱机制”,也就是说
a + b这东西,计算结果会从Integer变为int。而Long与int进行==比较,Long也会变为long。所以最终就变成了基本数据类型的比较,结果自然是true。
- 对于第二个比较:这个比较简单,因为Long类重写了equals方法,自己去看一下就知道了。如果比较的是非Long类型,则直接为false。
Double
- Double和Integer基本大同小异,只是有一个方法需要提及一下:
boolean isNaN()
- 这个方法是非静态的,所以肯定是Double的引用来调用,也就是说调用这个方法的肯定是一个数字。所以为啥还要判断是否是数字呢?
- 然后看一下下面这个例子就明白了哈哈哈。此非数字不是彼非数字。
public class DoubleTest {
public static void main(String[] args) {
Double a = 0/0.0;
System.out.println(a);
System.out.println(a.isNaN());
}
}
- 运行结果如下。也就是说这个方法是用来判断是否存在0/0.0的情况的。顺道提一句,0/0直接编译器报算术运算错误哈。之所以0.0可以除,0不能除,终究还是因为误差的问题。
NaN
true
- 还有一个
boolean isInfinite()方法也是同理。无穷大嘛,一个非零数字除以0.0的情况。
Boolean
- 同样是大同小异,但是依然有一个小东东需要说明一下,这个东东就是
boolean parseBoolean(String s)方法
- 这个方法通过查看源码可以看到,当s是"true"时(且不区分大小写),则返回true;否则,其他任何情况下都是返回false。
- 还有一个小小细节。别的包装类都有常量SIZE和BYTES,但Boolean没有哦~看过我写的《Java基础(一)》的小伙伴肯定都明白是怎么肥四。
Character
- 大家猜猜我要说什么?没错!同样是大同小异!但是Character有几个方法还是比较常用的,下面列一下:
| 方法声明 | 功能 |
|---|
| static boolean isUpperCase(char ch) | 判断是否为大写字符 |
| static boolean isLowerCase(char ch) | 判断是否为小写字符 |
| static boolean isDigit(char ch) | 判断是否为数字字符 |
| static char toUpperCase(char ch) | 转换为大写字符 |
| static char toLowerCase(char ch) | 转换为小写字符 |
总而言之~
- 总而言之,手动装箱方式:
valueOf()
- 总而言之,手动拆箱方式:
xxxValue()
- 总而言之,字符串转换为基本数据类型的方式:
parseXxx()
Math
- 位于java.lang.Math。提供了各种和数学相关的方法,例如对数、幂、根、三角函数等。
- 这个包其实没啥好讲的,因为用不用得好,和编程水平没啥关系,主要取决于数学水平。哈哈哈哈!!!不过还是放几个常用的方法来感受一下吧:
| 方法声明 | 功能 |
|---|
| static int max(int a, int b) | 返回两个参数中的最大值 |
| static int min(int a, int b) | 返回两个参数中的最小值 |
| static double pow(double a, double b) | 返回a的b次幂 |
| static int abs(int a) | 返回参数的绝对值 |
| static long round(double a) | 返回参数四舍五入到整数的结果 |
| static double sqrt(double a) | 返回参数的平方根 |
| static double random() | 返回0.0到1.0的随机数。不过不推荐用这个方法,因为Random类更加强大。 |
- 哦对了,提一句。这个类除了构造方法,其他的所有东西都是static修饰的哦!