常用类
一、Object类
超类、基类,是所有类的直接或间接父类,位于继承树的最顶层。
任何类,如没有书写extends
显示继承某个类,都默认隐式直接继承Object
类,否则为间接继承。
Object
类中所定义的方法,是所有类都具备的方法。
Object
类型可以存储任何对象。
作为参数,可接受任何对象。
作为返回值,可返回任何对象。
1.1 getClass()方法
public final native Class<?> getClass();
返回引用中存储的实际对象类型。
应用:通常用于判断两个引用中实际存储的对象类型是否一致。
案例:
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 35 36 37 38 39 40 41 public class Student { private String name; private int age; public Student () { } public Student (String name, int age) { this .name = name; this .age = age; } } class Teacher { private String name; public Teacher (String name) { this .name = name; } } class Test { public static void main (String[] args) { Object obj1 = new Student("小明" ,18 ); Object obj2 = new Student("小红" ,20 ); Object obj3 = new Teacher("王老师" ); Class class1 = obj1.getClass(); Class class2 = obj2.getClass(); if (class1 == class2){ System.out.println("obj1与obj2存储的对象类型一致" ); }else { System.out.println("obj1与obj2存储的对象类型不一致" ); } if (obj1.getClass() == obj3.getClass()){ System.out.println("obj1与obj3存储的对象类型一致" ); }else { System.out.println("obj1与obj3存储的对象类型不一致" ); } System.out.println(obj1.getClass()); System.out.println(obj2.getClass()); System.out.println(obj3.getClass()); } }
运行结果:
1.2 hashCode()方法
public native int hashCode();
返回该对象的哈希值
哈希值根据对象的地址 或字符串 或数字 使用hash算法计算处理的int类型的数值。
一般情况下,相同对象返回相同的哈希值。
案例:
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 35 36 37 38 39 40 41 42 43 44 45 46 47 public class Student { private String name; private int age; public Student () { } public Student (String name, int age) { this .name = name; this .age = age; } } class Teacher { private String name; public Teacher (String name) { this .name = name; } } class Test { public static void main (String[] args) { Object obj1 = new Student("小明" , 18 ); Object obj2 = new Student("小红" , 20 ); Object obj3 = new Teacher("王老师" ); System.out.println(obj1.hashCode()); System.out.println(obj2.hashCode()); System.out.println("---------------" ); Object obj4 = obj1; System.out.println(obj1.hashCode()); System.out.println(obj4.hashCode()); System.out.println("---------------" ); System.out.println(obj3.hashCode()); Teacher t1 = (Teacher) obj3; System.out.println(t1.hashCode()); } }
运行结果:
1.3 toString()方法
运行结果:
1.4 equals()方法
运行结果:
因为s1
与s2
分别指向两个新创建的Student
对象,虽然它们的内容是一样的,但是它们的引用是不一致的。而equals
比较的是引用是否相同,所以运行结果为false
.
案例2:
重写equals
方法,实现比较对象内容。
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 Student { private String name; private int age; public Student (String name, int age) { this .name = name; this .age = age; } @Override public boolean equals (Object o) { if (this == o) { return true ; } if (o == null || getClass() != o.getClass()){ return false ; } Student student = (Student) o; return age == student.age && Objects.equals(name, student.name); } } class Test { public static void main (String[] args) { Student s1 = new Student("小明" , 18 ); Student s2 = new Student("小明" , 18 ); System.out.println(s1.equals(s2)); } }
运行结果:
1.5 finalize()方法
protected void finalize () throws Throwable { }
<!--code5 -->
垃圾回收(garbage collection):由GC销毁垃圾对象,释放数据存储空间。
自动回收机制:JVM的内存耗尽,一次性回收所有垃圾对象。
手动回收机制:使用System.gc();
,通知JVM执行垃圾回收,但是JVM什么时候执行,需要根据具体情况,我们无法决定,仅仅只能进行通知。
案例:
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 public class Test { public static void main (String[] args) { Student s1 = new Student("aaa" ); Student s2 = new Student("bbb" ); new Student("ccc" ); new Student("ddd" ); new Student("eee" ); System.gc(); System.out.println("回收垃圾" ); } } class Student { String name; public Student (String name) { this .name = name; } @Override protected void finalize () throws Throwable { super .finalize(); System.out.println("执行了finalize,回收了" +name); } }
运行结果:
仅回收了ccc ddd eee
。多次执行结果顺序不一致,说明JVM什么时候回收哪个是不确定的。
二、包装类
基本类型所对应的引用数据类型。
Object可统一所有数据,包装类的默认值是null。
使用包装类可将原来基本类型存储在栈里的数据放入堆中。
2.1 包装类对应
基本数据类型
包装类型
byte
Byte
short
Short
int
Integer
long
Long
float
Float
double
Double
boolean
Boolean
char
Character
2.2 类型转换与装箱、拆箱
2.2.1 装箱与拆箱
装箱:将基本类型转换为引用类型的过程。
拆箱:将引用类型转换为基本类型的过程。
案例1:装箱与拆箱
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class Test1 { public static void main (String[] args) { System.out.println("装箱" ); int num1 = 19 ; Integer integer1 = new Integer(num1); Integer integer2 = Integer.valueOf(num1); System.out.println(num1); System.out.println(integer1.toString()); System.out.println(integer1); System.out.println("------------------" ); System.out.println("拆箱" ); Integer integer3 = new Integer(100 ); int num2 = integer3.intValue(); System.out.println(integer3); System.out.println(num2); } }
运行结果:
JDK1.5之后,编译器提供自动装箱、自动拆箱
案例2:自动装箱与自动拆箱
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Test2 { public static void main (String[] args) { System.out.println("自动装箱与自动拆箱" ); int age = 30 ; Integer integer = age; int age2 = integer; System.out.println(age); System.out.println(integer); System.out.println(age2); } }
运行结果:
拓展知识:自动装箱与自动拆箱其实是编译器帮我们调用了相对应的代码。通过对字节码文件反编译,可以看到代码是这样的。
2.2.2 基本类型与字符串转换
1、int转换成字符串类型
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 Test3 { public static void main (String[] args) { int n1 = 255 ; String s1 = n1 + "" ; System.out.println("方式1" ); System.out.println(s1); System.out.println("***********" ); String s2 = Integer.toString(n1); System.out.println("方式2" ); System.out.println(s2); System.out.println("***********" ); System.out.println("方式3" ); String s3 = Integer.toString(n1,16 ); System.out.println(n1+"的十六机制:" +s3); String s4 = Integer.toString(n1,2 ); System.out.println(n1+"的二机制:" +s4); } }
运行结果:
2、字符串转换成int类型
1 2 3 4 5 6 7 8 9 10 11 public class Test4 { public static void main (String[] args) { String s1 = "123" ; int n1 = Integer.parseInt(s1); System.out.println(n1); } }
运行结果:
注意:字符串不能包含非数字字符,否则将抛出异常java.lang.NumberFormatException
,无法完成转换。
3、boolean类型与字符串间的相互转换
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 Test5 { public static void main (String[] args) { System.out.println("字符串转换成boolean" ); String s1 = "true" ; boolean b1 = Boolean.parseBoolean(s1); System.out.println(b1); String s2 = "false" ; boolean b2 = Boolean.parseBoolean(s2); System.out.println(b2); String s3 = "abcdef" ; boolean b3 = Boolean.parseBoolean(s3); System.out.println(b2); System.out.println("*******************" ); System.out.println("boolean转换为为字符串" ); boolean b4 = false ; String s4 = true +"" ; String s5 = String.valueOf(b4); System.out.println(s4); System.out.println(s5); System.out.println("*******************" ); } }
运行结果:
2.3 Integer整数缓冲区
java预先创建了256个常用的整数包装类型对象。
面试题:思考为什么下面的运行结果是这样呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Test6 { public static void main (String[] args) { Integer integer1 = new Integer(100 ); Integer integer2 = new Integer(100 ); System.out.println(integer1 == integer2); Integer integer3 = 100 ; Integer integer4 = 100 ; System.out.println(integer3 == integer4); Integer integer5 = 200 ; Integer integer6 = 200 ; System.out.println(integer5 == integer6); } }
运行结果:
分析:
将上面代码字节码文件反编译可得到,如图,
实际上Integer integer=100;
自动装箱,本质上调用的是Integer.valueOf(100)
,我们再去看Integer.value()
方法,
1 2 3 4 5 public static Integer valueOf (int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
可以发现,当i
在某个范围内返回的是IntegerCache.cache[i + (-IntegerCache.low)]
中的数据,超过这个范围才会创建新的对象,我们再去看IntegerCache.low
与IntegerCache.high
,
可以发现这个范围是-128~127
,我们再去看这个数组IntegerCache.cache[]
,
存储了从-128
到127
这个范围的Integer
的值。
总结:当我们给Integer
对象直接赋int
类型值时,会涉及到自动装箱,当值的范围在-128~127
的时候,编译器会在缓冲区中取值。
三、String类
3.1 概述
java程序中的所有字符串文本都是此类的实例。
字符串字面值是常量,创建后不可被改变。
常用创建方式:
String str1 = “Hello”;
String str2 = new String(“World”);
1、String 表示字符串类型,属于 引用数据类型
,不属于基本数据类型 。
2、在java 中随便使用 双引号括起来
的都是String对象。
例如:“abc”,“def”,“hello world!”,这是3个String对象。
3、java中规定,双引号括起来的字符串,是 不可变 的,也就是说”abc”自出生到最终死亡,不可变,不能变成”abcd”,也不能变成”ab”
4、在JDK当中双引号括起来的字符串,例如:“abc” “def”都是直接存储在“方法区”的“字符串常量池”当中的。
5、为什么SUN公司把字符串存储在一个“字符串常量池”当中呢?
因为字符串在实际的开发中使用太频繁。为了执行效率,所以把字符串放到了方法区的字符串常量池当中。
String 创建的字符串存储在公共池中,而 new 创建的字符串对象在堆上(实际上也是指向字符串常量池)
1 2 3 4 5 String s1 = "hello" ; String s2 = "hello" ; String s3 = s1; String s4 = "world" ;
s1 s2 s3
都指向"hello"
,为什么说字符串创建后不可被改变,这是因为比如String s1="world"
,只是会将s1
的引用改为指向公共池中的"world"
,而不是将"hello"
值改为了"world"
。
案例1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class Test1 { public static void main (String[] args) { String s1 = "hello" ; String s2 = "hello" ; System.out.println(s1 == s2); String x = new String("world" ); String y = new String("world" ); System.out.println(x == y); } }
1 2 3 String s1 = new String("java" ); String s2 = new String("php" );
分析:这是使用new的方式创建的字符串对象。这个代码中的"java"
是从哪里来的?
凡是双引号括起来的都在字符串常量池中有一份。new对象的时候一定在堆内存当中开辟空间,然后堆内存再去指向字符串常量池。
字符串对象之间的比较不能使用“== ”,”==”不保险。应该调用String类的equals 方法。
注意: 1.为什么 System.out.println(引用) 会自动调用toString()方法?
因为println()会调用String.valueOf()方法而String.valueOf()会调用toString()方法
3.2 常用方法
1 2 3 4 5 6 7 8 9 10 11 public char charAt (int index) ;public boolean contains (String str) ;public char [] toCharArray();public int indexOf (String str) ;public int length () ;public String trim () ;public String toUpperCase () ;public boolean endWith (String str) ;public String replace (char oldChar,char newChar) ;public String[] split(String str);public String subString (int beginIndex,int endIndex) ;
案例:
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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 public class Test1 { public static void main (String[] args) { String s1 = " HEllo world! " ; char c1 = s1.charAt(3 ); System.out.println("根据下标获取字符:" +c1); boolean b1 = s1.contains("llo" ); if (b1){ System.out.println("当前字符串包含llo" ); }else { System.out.println("当前字符串不包含llo" ); } char [] charArr = s1.toCharArray(); System.out.print("将字符串装换为数组:" ); for (char c : charArr) { System.out.print(c+" " ); } System.out.println(); int r1 = s1.indexOf("wor" ); if (r1!=-1 ){ System.out.println("wor首次出现的下标为:" +r1); } System.out.println("返回字符串的长度:" +s1.length()); System.out.print("去掉字符串前后的空格:" ); System.out.print("***" +s1+"*** " ); System.out.println("***" +s1.trim()+"***" ); System.out.print("将字符串小写转换为大写:" ); System.out.println(s1+" " +s1.toUpperCase()); boolean b2 = s1.endsWith("aaa" ); if (b2){ System.out.println("字符串以aaa结尾" ); }else { System.out.println("字符串不以aaa结尾" ); } String s2 = s1.replace('l' ,'S' ); System.out.println("替换字符:" +s2); String s3 = "hellaeawolrdajavaaphpaC" ; String[] strArr = s3.split("a" ); System.out.print("将字符串按a拆分为数组:" ); for (String s : strArr) { System.out.print(s+" " ); } System.out.println(); String s4 = "However long the night,the dawn will break" ; System.out.println("截取字符串:" +s4.substring(3 ,18 )); } }
运行结果:
3.3 可变字符串
概念:可在内存中创建可变的缓冲空间,存储频繁改变的字符串。
StringBuilder
:可边长字符串,JDK5.0提供,运行效率快、线程不安全。
StringBuffer
:可边长字符串,JDK1.0提供,运行效率慢、线程安全。
StringBuffer
因为保证线程安全,所以效率要比StringBuilder
较慢一些,但是两者的速度都比String
要快很多。
常用方法:
1 2 3 4 public StringBuilder append (String str) public StringBuilder insert (int offset, String str) ;public StringBuilder replace (int start, int end, String str) ;public StringBuilder delete (int start, int end) ;
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Test2 { public static void main (String[] args) { StringBuilder str1 = new StringBuilder(); str1.append("java" ); str1.append("php" ); str1.append("python" ); System.out.println(str1); str1.insert(4 ,"i am a insert string" ); System.out.println(str1); str1.replace(0 ,5 ,"java is the best language " ); System.out.println(str1); str1.delete(10 ,15 ); System.out.println(str1); str1.delete(0 ,str1.length()); System.out.println("**" +str1+"**" ); } }
运行结果:
将上面案例中的StringBuilder
改为StringBuffer
运行结果仍然是一致的。
四、BigDecimal类
位置:java.math包中
作用:精确计算浮点数
常用方法:
1 2 3 4 BigDecimal add (BigDecimal bd) ;BigDecimal subtract (BigDecimal bd) ;BigDecimal multiply (BigDecimal bd) ;BigDecimal divide (BigDecimal bd) ;
思考:下面程序输出结果是多少?
1 2 3 4 5 6 7 8 9 public Test{ public static void main (String[] args) { double d1 = 1.0 ; double d2 = 0.9 ; System.out.println(d1-d2); System.out.println((1.4 -0.5 )/0.9 ); System.out.println(0.9 /0.9 ); } }
这是因为浮点数是近似存储的。对于要求精度高的数据,需要借助BigDecimal
,BigDecimal
是精确存储的。
案例1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Test4 { public static void main (String[] args) { BigDecimal b1 = new BigDecimal("1.0" ); BigDecimal b2 = new BigDecimal("0.9" ); BigDecimal r1 = b1.subtract(b2); System.out.println(r1); BigDecimal r2 = new BigDecimal("1.4" ) .subtract(new BigDecimal("0.5" )) .divide(new BigDecimal("0.9" )); System.out.println(r2); } }
运行结果:
案例2:当使用除法除不尽时
1 2 3 4 5 6 7 8 public class Test5 { public static void main (String[] args) { BigDecimal b1 = new BigDecimal("10" ); BigDecimal b2 = new BigDecimal("3" ); BigDecimal r1 = b1.divide(b2); System.out.println(r1); } }
运行结果:
解决方式:使用divide的重载方法,设置保留小数位数,以及保留方式。
1 2 3 4 5 6 7 8 9 public class Test6 { public static void main (String[] args) { BigDecimal b1 = new BigDecimal("10" ); BigDecimal b2 = new BigDecimal("3" ); BigDecimal r1 = b1.divide(b2, 3 , RoundingMode.HALF_UP); System.out.println(r1); } }
运行结果:
五、Date类
Date表示特定的瞬间,精确到毫秒。Date类中的大部分方法都已经被Calendar类中的方法所取代。为什么被取代,是因为Date类当初在设计的时候没有考虑地很全面,有些不完美的地方,特别是国际化的问题,所以被Calendar
类所取代了。
时间单位:1秒=1000毫秒 1毫秒=1000微妙 1微妙=1000纳秒
未过时构造方法:
方法名
功能
Date();
分配 Date
对象并初始化此对象,以表示分配它的时间(精确到毫秒)。
Date(long date);
分配 Date
对象并初始化此对象,以表示自从标准基准时间(称为“历元(epoch)”,即 1970 年 1 月 1 日 00:00:00 GMT)以来的指定毫秒数。
未过时方法:
方法名
功能
boolean after(Date when);
测试此日期是否在指定日期之后。
boolean before(Date when) ;
测试此日期是否在指定日期之前。
Object clone();
返回此对象的副本。
int compareTo(Date anotherDate);
比较两个日期的顺序。
boolean equals(Object obj);
比较两个日期的相等性。
long getTime();
返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。
void setTime(long time);
设置此 Date
对象,以表示 1970 年 1 月 1 日 00:00:00 GMT 以后 time
毫秒的时间点。
案例1:
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 public class Test1 { public static void main (String[] args) { Date date1 = new Date(); System.out.print("获取当前时间:" ); System.out.println(date1); System.out.println(date1.toLocaleString()); System.out.print("获取昨天的时间:" ); Date date2= new Date(date1.getTime()-1000 *60 *60 *24 ); System.out.println(date2.toLocaleString()); boolean b1 = date1.after(date2); System.out.println("比较时间:" +b1); boolean b2 = date1.before(date2); System.out.println("比较时间" +b2); Date date3 = (Date) date1.clone(); System.out.println("克隆一个Date副本:" +date3.toLocaleString()); int r1 = date2.compareTo(date1); System.out.println("比较两个日期时间顺序:" +r1); boolean b3 = date1.equals(date2); System.out.println("比较两个日期是否相等:" +b3); } }
运行结果:
六、Calendar类
常用方法:
方法名
功能
static Calendar getInstance();
使用默认时区和区域获取日历。
void set(int year, int month, int date, int hourOfDay, int minute, int second);
设置日历的年月日时分秒。
int get(int field);
返回日历指定字段值。
void setTime(Date date);
使用给定的Dete设置日历的时间,可使用此方法将Date转换为Calendar。
Date getTime();
返回一个Date表示此日历时间,可使用此方法将Calendar装换为Date。
abstract void add(int field, int amount);
根据日历的规则,为给定的日历字段添加或减去指定的时间量。
long getTimeInMillis();
返回此 Calendar 的时间值,以毫秒为单位。
abstract int getActualMaximum(int field);
给定此 Calendar 的时间值,返回指定日历字段可能拥有的最大值。
abstract int getActualMinimum(int field);
给定此 Calendar 的时间值,返回指定日历字段可能拥有的最小值。
案例1:
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 Test2 { public static void main (String[] args) throws IOException { Calendar calendar1 = Calendar.getInstance(); System.out.println(calendar1); System.out.println("创建一个Calendar日历类:" +calendar1.getTime().toLocaleString()); calendar1.set(2019 ,9 -1 ,1 ,12 ,19 ,30 ); System.out.println("设置日历的年月日时分秒:" +calendar1.getTime().toLocaleString()); int year = calendar1.get(Calendar.YEAR); int month = calendar1.get(Calendar.MONTH); int day = calendar1.get(Calendar.DAY_OF_MONTH); int hour = calendar1.get(Calendar.HOUR_OF_DAY); int minute = calendar1.get(Calendar.MINUTE); System.out.println("返回字段:" +year+"年" +(month+1 )+"月" +day+"日 " +hour+":" +minute); Date date1 = new Date(1646537440377L ); Calendar calendar2 = Calendar.getInstance(); calendar2.setTime(date1); System.out.println("通过Date设置日历时间:" +calendar2.getTime().toLocaleString()); calendar2.add(Calendar.DAY_OF_MONTH,2 ); calendar2.add(Calendar.HOUR_OF_DAY,1 ); System.out.println("对当前时间加2天加1小时:" +calendar2.getTime().toLocaleString()); System.out.println(calendar1.getTimeInMillis()); } }
运行结果:
案例2:获取给定字段当前时间的最大最小值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Test3 { public static void main (String[] args) { Calendar calendar1 = Calendar.getInstance(); System.out.println(calendar1.getTime().toLocaleString()); int n1 = calendar1.getActualMaximum(Calendar.DAY_OF_MONTH); System.out.println(n1); calendar1.set(Calendar.MONTH,1 ); System.out.println(calendar1.getTime().toLocaleString()); int n2 = calendar1.getActualMaximum(Calendar.DAY_OF_MONTH); System.out.println(n2); } }
运行结果:
SimpleDateFormat
是以与语言环境有关的方式来格式化和解析日期的类。
进行格式化(日期 -> 文本)、解析(文本 -> 日期)
常用的时间模式字母:
字母
日期或时间
y
年
M
年中月份
d
月中天数
H
一天中小时数(0~23)
m
分钟
s
秒
S
a毫秒
案例1:格式化Date
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Test4 { public static void main (String[] args) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss" ); Date date = new Date(); String str = simpleDateFormat.format(date); System.out.println(str); } }
运行结果:
案例 2:
1 2 3 4 5 6 7 8 9 10 11 12 public class Test5 { public static void main (String[] args) throws ParseException { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd" ); Date date = simpleDateFormat.parse("2022/03/06" ); System.out.println(date.toLocaleString()); } }
运行结果:
使用SimpleDateFormat.parse()
方法时要保证传入的字符串与定义的日期格式一致,否则会抛出异常。
八、System类
System
系统类,主要用于获取系统的属性数据和其它操作。
方法名
功能
static void arraycopy();
复制数组
static long currentTimeMilles();
获取当前系统时间,返回毫秒值
static void gc();
通知JVM启动垃圾回收
static void exit(int status);
退出JVM,参数是0表示正常退出,参数非0表示异常退出