一、Object类
1.1 概述
java.lang.Object
类是Java语言中的根类,即所有类的父类。它中描述的所有方法子类都可以使用。在对象实例化的时候,最终找的父类就是Object。
如果一个类没有特别指定父类, 那么默认则继承自Object类。例如:
public class MyClass /*extends Object*/ {
// ...
}
Object类当中包含的方法有11个(JDK9),这里主要介绍toString
和equals
方法
1.2 toString方法
方法摘要
public String toString()
:返回该对象的字符串表示。
作用:打印对象信息
toString方法返回该对象的字符串表示,其实该字符串内容就是【包名类名+@+内存地址值】。
由于toString方法返回的结果是内存地址,而在开发中,经常需要按照对象的属性得到相应的字符串表现形式,因此也需要重写它。
- 重写前:打印的是【包名类名@地址值】
- 重写后:打印的是【对象中的属性值】(成员变量的值)
Student类:
public class Student /*extends Object*/{
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
@Override // 可以快捷键重写toString方法
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
}
使用:
public class Test01 {
public static void main(String[] args) {
String str = "abc";
System.out.println(str/*toString()*/); // 显示的是 abc
// str 相当于 str.toString()
// 因为在 String 类当中,已经重写了toString方法,可以直接打印出字符串
Student s = new Student("张三",23);
// 没在Student类中重写toString方法时
System.out.println(s/*toString()*/); // 显示的是 包名@b4c966a
System.out.println(s.toString()); // 显示的是 包名@b4c966a
// 在Student类中重写toString方法后(IDEA直接快捷键生成重写的toString)
System.out.println(s); // 显示:Student{name='张三', age='23'}
}
}
1.3 equals方法
方法摘要
-
public boolean equals(Object obj)
:指示其他某个对象是否与此对象“相等”。
作用:比较两个对象 -
重写前:比较的是两个对象的地址值
-
重写后:比较对象中的属性值(成员变量)
Student类:
import java.util.Objects; // 注意,重写了equals方法,就会导入这个包
public class Student /*extends Object*/{
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override // 重写toString方法
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
@Override // 重写equals方法
public boolean equals(Object o) {
// 比较地址是否相同
if (this == o) return true;
// 判断参数是否为null, 判断两个对象是否来自于同一个类
if (o == null || getClass() != o.getClass()) return false;
// 向下转型
Student student = (Student) o;
// 比较内容是否相同
return age == student.age &&
Objects.equals(name, student.name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
使用:
public class Test02 {
public static void main(String[] args) {
String s1 = "abc";
String s2 = "abc";
// String类里面,已经重写了equals方法,直接比较对象的属性值,而非地址值
System.out.println(s1.equals(s2)); // true
Student stu1 = new Student("张三",23);
Student stu2 = new Student("张三",23);
// 在重写 Students 类的 equals 方法之前,比较的是二者的地址值
System.out.println(stu1.equals(stu2)); // false
// 快捷键,重写 Students 类的 equals 方法之后,比较的是二者的属性值.
// 认为同姓名同年龄的就是同一个人
System.out.println(stu1.equals(stu2)); // true
}
}
二、Objects类中的equals方法
回到目录
Objects类中的equals方法:比较两个对象是否相同,但是加了一些健壮性的判断。
在刚才IDEA自动重写equals代码中,使用到了java.util.Objects
类(要导包)。Objects类是对象的工具类。
在JDK7添加了一个Objects工具类,它提供了一些方法来操作对象,它由一些静态的实用方法组成,这些方法是null-save(空指针安全的)或null-tolerant(容忍空指针的),用于计算对象的hashcode、返回对象的字符串表示形式、比较两个对象。
在比较两个对象的时候,Object的equals方法容易抛出空指针异常,而Objects类中的equals方法就优化了这个问题。方法如下:
public static boolean equals(Object a, Object b)
:判断两个对象是否相等。
import java.util.Objects;
public class Test03 {
public static void main(String[] args) {
String s1 = null;
String s2 = "abc";
// System.out.println(s1.equals(s2)); // 将产生空指针异常,NullPointerException
boolean result = Objects.equals(s1,s2);
System.out.println(result); // 显示的是 false
}
}
三、日期相关类
3.1 Date类
java.util.Date
类 表示特定的瞬间,精确到毫秒。
- 构造方法:
Date(); : 根据当前系统时间创建日期对象
Date(long time); : 根据传入的毫秒值创建日期对象
- 成员方法
long getTime(); : 获取当前日期对象的毫秒值时间
String toLocaleString(); : 根据本地格式转换日期对象
import java.util.Date;
public class Test01 {
public static void main(String[] args) {
// 空参构造方法
Date d1 = new Date();
System.out.println(d1); // Sat May 02 08:56:51 CST 2020
System.out.println(d1.toLocaleString()); // 本地时间的格式:2020年5月2日 上午8:56:51
Date d2 = new Date(3000L); // 3000毫秒. long类型的构造参数, 可以指定毫秒数
System.out.println(d2.toLocaleString()); // 1970年1月1日 上午8:00:03
// 计算机时间原点是1970年1月1号0点0分0秒,中国是东八区,所以是8点0分0秒
}
}
3.2 DateFormat类和SimpleDateFormat类
由于DateFormat为抽象类,不能直接使用,所以需要常用的子类java.text.SimpleDateFormat
。这个类需要一个模式(格式)来指定格式化或解析的标准。SimpleDateFormat类:
- 构造方法
SimpleDateFormat(String s);
根据指定模板创建日期格式化对象 - 成员方法
String format(Date d);
根据指定格式格式化日期对象
Date parse(String s);
根据指定格式解析字符串
格式规则
常用的格式规则为:
标识字母(区分大小写) | 含义 |
---|---|
y | 年 |
M | 月 |
d | 日 |
H | 时 |
m | 分 |
s | 秒 |
备注:更详细的格式规则,可以参考SimpleDateFormat类的API文档0。
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Test01 {
public static void main(String[] args) throws ParseException {
// 空参构造方法
Date d1 = new Date();
System.out.println(d1); // Sat May 02 08:56:51 CST 2020
System.out.println(d1.toLocaleString()); // 本地时间的格式:2020年5月2日 上午8:56:51
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String format = sdf.format(d1); // 利用SimpleDateFormat类中的format方法,按照sdf的格式,格式化日期显示
System.out.println(format); // 2020年05月02日 09:17:04
String str = "2088年08月08日 08:08:08";
Date parse = sdf.parse(str); // 要抛出异常。将字符串类型日期按找sdf的格式进行解析,解析为一个日期对象
System.out.println(parse); // Sun Aug 08 08:08:08 CST 2088
}
}
3.3 Calendar类
java.util.Calendar
是日历类,在Date后出现,替换掉了许多Date的方法。
Calendar为抽象类,由于语言敏感性,Calendar类在创建对象时不能直接创建,而是通过要通过其静态方法创建,返回子类对象,如下:
- 创建对象方式(比较特殊)
Calendar c = Calendar.getInstance(); // 根据日历类创建一个对象, 类名.静态方法名(参数列表);
- 成员方法
int get(int n); 获取指定日历字段信息
void set(int n, int value); 将指定日历字段设置为指定的字段值
void add(int n, int value); 将指定日历字段增加或减少指定的值
Date getTime(); 返回一个表示此Calendar时间值(从历元到现在的毫秒偏移量)的【Date对象】
Calendar中的getTime方法并不是获取毫秒时刻,而是拿到对应的Date对象
Calendar类中提供很多成员常量,代表给定的日历字段:
字段值 | 含义 |
---|---|
YEAR | 年 |
MONTH | 月(从0开始,可以+1使用) |
DAY_OF_MONTH | 月中的天(几号) |
HOUR | 时(12小时制) |
HOUR_OF_DAY | 时(24小时制) |
MINUTE | 分 |
SECOND | 秒 |
DAY_OF_WEEK | 周中的天(周几,周日为1,可以-1使用) |
import java.util.Calendar;
import java.util.Date;
public class Test03 {
public static void main(String[] args) {
// 获取日历类对象
Calendar c = Calendar.getInstance();
// get方法
int year = c.get(Calendar.YEAR);
System.out.println(year); // 2020
int month = c.get(Calendar.MONTH)+1; //国外的月份从0开始,要加1 ?
System.out.println(month); // 5
// set方法
c.set(Calendar.YEAR,2088);
year = c.get(Calendar.YEAR);
System.out.println(year); // 2088
// add方法
c.add(Calendar.YEAR,2);
year = c.get(Calendar.YEAR);
System.out.println(year); // 2090
c.add(Calendar.YEAR,-2);
year = c.get(Calendar.YEAR);
System.out.println(year); // 2086
Calendar cal = Calendar.getInstance(); // 创建了一个对象,对象名为cal
Date date = cal.getTime(); // 拿到对应的Date对象,地址是date
System.out.println(date); // 打印出实际的时间:Sat May 02 09:59:36 CST 2020
}
}
四、 System类
回到目录
java.lang.System
类中提供了大量的静态方法,常用的方法有:
public static long currentTimeMillis()
:返回以毫秒为单位的当前时间。public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
:将数组中指定的数据拷贝到另一个数组中。
4.1 currentTimeMillis()方法
实际上,currentTimeMillis()方法就是 获取当前系统时间与1970年01月01日00:00点之间的毫秒差值(中国东八区是8点)。
练习:验证for循环打印数字1-9999所需要使用的时间(毫秒)
public class SystemTest1 {
public static void main(String[] args) {
long start = System.currentTimeMillis(); // 起始时间
for (int i = 0; i < 10000; i++) {
System.out.print(i + " ");
}
long end = System.currentTimeMillis(); // 打印好了的时间
System.out.println("共耗时毫秒:" + (end - start));
}
}
4.2 arraycopy()方法
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
:将数组中指定的数据拷贝到另一个数组中。
数组的拷贝动作是系统级的,性能很高。System.arraycopy方法具有5个参数,含义分别为:
参数序号 | 参数名称 | 参数类型 | 参数含义 |
---|---|---|---|
1 | src | Object | 源数组 |
2 | srcPos | int | 源数组索引起始位置 |
3 | dest | Object | 目标数组 |
4 | destPos | int | 目标数组索引起始位置 |
5 | length | int | 复制元素个数 |
arraycopy(int[] src, int srcIndex, int[] dest, int destIndex, int count)参数列表解释:
int[] src —— 要拷贝的数组; int srcIndex —— 从数组的第几位开始拷贝;
int[] dest —— 要接收的数组; int destIndex —— 从要接收数组的第几位开始接收; int count —— 接收几个
示例:
public class Test1 {
public static void main(String[] args) {
// 获取一下当前系统毫秒值时间
long time = System.currentTimeMillis();
System.out.println(time); // 距离计算机时间原点的毫秒数 1588389810888
// arraycopy(int[] src, int srcIndex, int[] dest, int destIndex, int count)拷贝数组
int[] arr1 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int[] arr2 = {9, 8, 7, 6, 5, 4, 3, 2, 1};
// 将 arr1 数组中的前四个数字拷贝到 arr2 数组中
System.arraycopy(arr1, 0, arr2, 0, 4); // 是直接替换掉前四个!
for (int i = 0; i < arr2.length; i++) {
System.out.print(arr2[i] + " "); // 1 2 3 4 5 4 3 2 1
// 直接将 arr2 数组的前四个数给替换掉了
}
}
}
五、StringBuilder类
回到目录
String类的对象创建后就不可以改变(字符串是常量,它们的值在创建后不能被更改)。所以每当进行字符串拼接时,总是会在内存中创建一个新的String对象。每次拼接,都会构建一个新的String对象,既耗时,又浪费空间。为解决这一问题,可使用java.lang.StringBuilder
类。
StringBuilder又称为可变字符序列,它是一个类似于 String 的字符串缓冲区,通过某些方法调用可以改变该序列的长度和内容。
StringBuilder类的原理如下图所示:(默认16字符空间,超过自动扩充)
5.1 StringBuilder类的常用构造方法
public StringBuilder()
:构造一个空的StringBuilder容器。public StringBuilder(String str)
:构造一个StringBuilder容器,并将字符串添加进去。
public class StringBuilderDemo {
public static void main(String[] args) {
// 使用无参构造
StringBuilder sb1 = new StringBuilder();
System.out.println(sb1); // 打印出来的是空白
// 使用有参构造
StringBuilder sb2 = new StringBuilder("aabbcc");
System.out.println(sb2); // aabbcc
}
}
5.2 StringBuilder类的常用方法
public StringBuilder append(...)
:添加任意类型数据的字符串形式,返回的还是当前对象本身。public StringBuilder reverse()
:反转所有内容,注意返回的还是对象自己。public String toString()
:将当前StringBuilder对象转换为String对象。
String对象与StringBuilder对象的相互转化
- 由String对象转化为StringBuilder对象:用StringBuilder类的有参构造方法
- 由StringBuilder对象转化为String对象:用StringBuilder类中重写过的toString方法
5.2.1 append方法
append方法具有多种重载形式,可以接收任意类型的参数。任何数据作为参数都会将对应的字符串内容添加到StringBuilder对象中。
例如:
public class Demo02StringBuilder {
public static void main(String[] args) {
//创建对象
StringBuilder builder1 = new StringBuilder();
//public StringBuilder append(任意类型)
StringBuilder builder2 = builder1.append("hello");
// StringBuilder类中的append方法,返回的还是builder1,即builder1和builder2是一摸一样的
System.out.println("builder:" + builder1); // hello
System.out.println("builder2:" + builder2); // hello
System.out.println(builder1 == builder2); // true append方法返回的还是对象自身
// append方法的参数列表中可以添加 任何类型
builder1.append("hello");
builder1.append("world");
builder1.append(true);
builder1.append(100);
// 在我们开发中,会遇到调用一个方法后,返回一个对象的情况。然后使用返回的对象继续调用方法。
// 这种时候,我们就可以把代码现在一起,如append方法一样,代码如下
//链式编程
builder1.append("hello").append("world").append(true).append(100);
System.out.println("builder:"+builder1);
}
}
5.2.2 reverse方法
public StringBuilder reverse()
:反转内容,注意返回的还是对象自己。
public class Test2 {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append("Hello, ").append("World ").append("Java ").append(1234);
// append()方法的链式写法
System.out.println(sb); // Hello, World Java 1234
sb.reverse();
System.out.println(sb); // 4321 avaJ dlroW ,olleH
}
}
5.2.3 toString方法
备注:StringBuilder类中已经重写了Object类中的toString方法。
通过toString方法,StringBuilder对象将会被转换为不可变的String对象(将缓冲区内容转换为字符串数据)。如:
public class Demo16StringBuilder {
public static void main(String[] args) {
// 链式创建
StringBuilder sb = new StringBuilder("Hello").append("World").append("Java");
// 调用方法
String str = sb.toString();
System.out.println(str); // HelloWorldJava
}
}
六、包装类
回到目录
Java提供了两个类型系统,基本类型与引用类型,使用基本类型在于效率,然而很多情况,会创建对象使用,因为对象可以做更多的功能,如果想要我们的基本类型像对象一样操作,就可以使用基本类型对应的包装类,如下:
基本类型 | 对应的包装类(位于java.lang包中) |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
6.1 自动拆装箱
- 装箱:从基本类型转换为对应的包装类对象。
- 拆箱:从包装类对象转换为对应的基本类型。
从Java 5(JDK 1.5)开始,基本类型与包装类的装箱、拆箱动作可以自动完成。
Integer i = 4; // 自动装箱,相当于Integer i = Integer.valueOf(4);
i = i + 5; // 等号右边:将i对象转成基本数值(自动拆箱) i.intValue() + 5;
// 加法运算完成后,再次装箱,把基本数值转成对象。
6.2 基本类型与字符串类型的相互转换
6.2.1 基本类型转换为String类型
- 基本类型的值 + “” ; 这是最简单的方法(最常用);
int i1 = 100;
String s1 = i1+""; // 这样,s1就是字符串100了
System.out.println(s1+200); //100200 字符串100加上数字200,先将数字转换为字符串,再用字符串的拼接
- 使用【包装类】(java.lang包)中的静态方法toString(参数),不是Object类的toString() 重载;
static String toString(int i) 返回一个表示指定整数的 String 对象
- String类的静态方法valueOf(参数)
static String valueOf(int i) 返回 int 参数的字符串表示形式。
示例:
方法2:
String s2 = Integer.toString(100);
System.out.println(s2+200); //100200
方法3:
String s3 = String.valueOf(100);
System.out.println(s3+200); //100200
6.2.2 String类型转换为对应的基本类型
除了Character类之外,其他所有包装类都具有parseXxx静态方法可以将字符串参数转换为对应的基本类型:
public static byte parseByte(String s)
:将字符串参数转换为对应的byte基本类型。public static short parseShort(String s)
:将字符串参数转换为对应的short基本类型。public static int parseInt(String s)
:将字符串参数转换为对应的int基本类型。public static long parseLong(String s)
:将字符串参数转换为对应的long基本类型。public static float parseFloat(String s)
:将字符串参数转换为对应的float基本类型。public static double parseDouble(String s)
:将字符串参数转换为对应的double基本类型。public static boolean parseBoolean(String s)
:将字符串参数转换为对应的boolean基本类型。
代码使用(仅以Integer类的静态方法parseXxx为例)如:
public class Demo18WrapperParse {
public static void main(String[] args) {
int num = Integer.parseInt("100"); // 静态方法,直接用类名称.静态方法就行
}
}
注意: 如果字符串参数的内容无法正确转换为对应的基本类型,则会抛出
java.lang.NumberFormatException
异常(数字格式化异常)。
例如: int a = Integer.parseInt("a"); // NumberFormatException 数字格式化异常