Object类
== 运算符
- == 运算符既可以判断基本类型,又可以判断引用类型。
2. 如果判断基本类型,那么判断的是 值是否相等。
3. 如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象,如果希望判断内容是否相同,则需要重写。int i = 10;double d = 10.0;System.out.println(i==d)//true
public class Test {public static void main(String[] args) {NotePad a = new NotePad();Computer b = a;//向上转型,a和b都指向同一个NotePad对象System.out.println(a==b); //true 因为a和b地址相同}}
equals方法
- 是Object类的方法,只能判断引用类型。
2. 默认判断的是地址是否相等,子类往往重写该方法,用于判断内容是否相等(比如String类)。
需要注意一点,String类是否用new来初始化还是有区别的。比如str1和str2,实际上都指向同一块内容为”shang”的区域,因此str1和str2地址相同。而str3和str4,虽然指向的内容都是相同,但是由于用到了new,开辟了两个String对象,因此str3和str4指向两个内容相同但地址不同的String对象。String str1 = "shang";String str2 = "shang";System.out.println(str1 == str2); //true,str1和str2地址相同System.out.println(str1.equals(str2)); //trueString str3 = new String("shang");String str4 = new String("shang");System.out.println(str3 == str4); //falseSystem.out.println(str3.equals(str4)); //trueSystem.out.println(str1 == str3); //falseSystem.out.println(str1.equals(str3)); //true
重写equals方法
用于判断对象的内容是否相同。public boolean equals(object obj){if(this == obj){return true;} //如果是地址相同那么就返回trueif(!(obj instanceof Doctor)){return false;}//如果obj不是Doctor类或其子类,那么返回falseDoctor doctor = (Doctor)obj; //传入的参数向下转型return this.name.equals(doctor.name)&&this.age == doctor.age;}
查看JDK源码
1. 一般来说 IDEA 配置好JDK后,jdk的源码也就自动配置好了。
2. 如果没有的话点击 菜单File —> Project Stucture —> SDKs —> Sourcepath 然后点击加号 —> 找到jdk安装目录,把 src.zip 和 javafx-src.zip 加入即可。
3. 在需要查看某个方法源码时,将光标放在该方法上,输入 ctrl + b 即可。或者在方法上点击右键 —> go to —> Declarartion or Usages。
hashCode方法
- 提高具有哈希结构的容器的效率(如HashMap,HashTable等)。
2. 两个引用如果指向的是同一个对象,则哈希值肯定是一样的。
3. 两个引用如果指向的是不同对象,则哈希值是不一样的。
4. 哈希值主要是根据地址号计算的(通过将该对象的内部地址转换成一个整数实现的),不能将哈希值等价于地址。
5. hashCode如果有需要的话,也会重写。public int hashCode() {int h = hash;if (h == 0 && value.length > 0) { //value就是把对象toString后的结果char val[] = value; //将字符串转化为字符数组for (int i = 0; i < value.length; i++) {h = 31 * h + val[i]; //哈希值计算方法}hash = h;}return h;}
toString方法
默认返回:全类名(包名+类名)+ @ + 哈希值的十六进制。
重写:子类往往重写toString方法,用于返回对象的属性信息。public String toString() {return getClass().getName() + "@" + Integer.toHexString(hashCode());}
自动调用:当输出对象时,toString方法会被自动调用(重写会影响)。public class Test {public static void main(String[] args) {Person wang = new Person(10, "wang", 20);System.out.println(wang);//com.shang.Person@1b6d3586}}
finalize方法
- 当对象被回收时,系统自动调用该对象的finalize方法。子类可以重写该方法,写自己的业务逻辑代码(数据库连接,打开文件等),如果不重写就会调用 Object类的finalize。
2. 什么时候被回收:当某个对象没有任何引用时,jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用finalize方法。
输入一个 f 就可以重写 finalize方法了。 finlize的调用类似C++的析构函数。public static void main(String[] args) {Person p1 = new Person();p1 = null; // 这时,p1就是一个垃圾,垃圾回收器会销毁对象}// 在销毁对象前,会调用该方法的finalize方法

3. 垃圾回收机制的调用,是由系统来决定(有自己的GC算法),也可以通过System.gc() 主动触发垃圾回收机制。(在实际开发中,几乎不会运用 finalize)
包装类(封装类型)
针对八种基本类型相应的引用类型——包装类。有了类的特点,就可以调用类中的方法。


装箱与拆箱
在JDK5之前,进行的是手动的装箱与拆箱。所谓装箱,就是进行 int -> Integer 的转换,而拆箱就是 Integer -> int 之间的转换(其它基本元素类似)。
int n1 = 100;Integer integer = new Integer(n1);Integer integer1 = Integer.valueOf(n1); //手动装箱(把基本数据变成对象)int n2 = integer.intValue(); // 手动拆箱
在JDK5后,就可以自动装箱和自动拆箱。自动将一个原始数据类型转换为一个封装类型称为自动装箱,自动将一个封装类型转换为一个原始数据类型被称为自动拆箱。
装箱和拆箱 是编译器要做的工作,而不是虚拟机。
int n1 = 100;Integer integer = n1; //自动装箱,底层使用的是 Integer.valueOf(n1)方法int n2 = integer; //自动拆箱,底层使用的是 intValue()方法Object obj1 = true?new Integer(1):new Double(2.0);System.out.println(obj1); //最大精度为double,输出1.0
注意输出的是1.0而不是1,因为三元运算符是一个整体,在执行时会把所数据类型的精度上升到最大的那个。
Object obj1 = true?new Integer(1):new Integer(2);System.out.println(obj1); // 最大精度为int,输出1
Integer与String相互转换
Integer -> String:
Integer n = 100;String str1 = n + ""; // 第一种方法String str2 = n.toString(); // 第二种方法String str3 = String.valueOf(n); // 第三种方法,valueOf也可以使用int作为参数
String -> Integer:
String str = "12345";Integer n1 = Integer.parseInt(str); // 第一种方法Integer n2 = new Integer(str); // 第二种方法,构造器Integer n3 = new Integer(str); // 第三种方法
常用方法
Integer创建机制
public static void main(String[] args) {Integer a = new Integer(1);Integer b = new Integer(1);System.out.println(a==b); //a和b都是new出的对象,地址肯定不相同Integer m = 1; //底层是Integer.valueOfInteger n = 1;System.out.println(m==n);Integer x = 128;Integer y = 128;System.out.println(x==y);}
对于使用 Integer.valueOf 创建的对象,注意 m和n 与 x和y 之间的区别:当使用自动装箱时,底层调用的是Integer的valueOf方法,它会根据传入数值的大小决定是否new一个对象。
public static Integer valueOf(int i) { //源码if (i >= IntegerCache.low && i <= IntegerCache.high)//low是-128,high是127return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}
通过查看源码得知,如果传入的参数在 -128~127之间,不会创建新的对象,而是直接调用内部数组cache,返回一个数(但还是Integer对象,只不过地址相同)。而在其他范围的参数就会new一个新对象。
因此m和n是一个相同的Integer对象。而x和y则是地址不同的对象。

如果基本数据类型和类比较是否相等,那么就比较数值是否相等。
public static void main(String[] args) {Integer n1 = 127;int n2 = 127;System.out.println(n1==n2); //trueInteger n3 = 128;int n4 = 128;System.out.println(n3==n4); //true}

String类
基本信息
- String 对象用于保存字符串,也就是一组字符序列。
2. 字符串常量就是双引号括起的字符序列,比如 “jack”。
3. 字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节。
4. String 类有很多构造器。
String s5 = new String(byte[] b);
- String是final类,不能被其他的类继承。
6. String 有属性 private final char value[] 用于存放字符串内容(所以本质还是字符数组)。注意value是final类型,由于数组名相当于数组首地址,因此value不能指向新的地址,但是单个字符内容是可以变化的。创建方式

方式一:先从常量池查看是否有 “hsp” 数据空间,如果有,字符串直接指向该空间。如果没有则重新创建,然后指向。s最终指向的是常量池的空间地址。
方式二:先在堆中创建空间,里面维护了value属性,如果常量池里有 “hsp”,value指向常量池的”hsp”地址。如果常量池没有 “hsp”,重新创建,然后再指向。s2 最终指向的是堆中的空间地址。
综合训练 P497String 对象特性
一共创建了两个对象,”hello”与”haha”,值得注意的是,上面说的String的value属性是final类型,不能更换地址,指的是”hello”与”haha”不能更换地址。这两个才是String对象,而s1只是一个指向String对象的指针罢了,因此s1可以指向不同的对象,而”hello”和”haha”并不能更换地址。String s1 = "hello";s1 = "haha";

创建了一个对象。String a = “hello” + “abc” 会被优化等价于 String a = “helloabc”。对于这种字符串常量相加的情况,编译器会自动优化,然后就等价于一个新的字符串常量对象赋给指针。String a = "hello" + "abc"; // 字符串常量相加
当将一个字符串与一个非字符串的值进行拼接时,后者会转换为字符串。
对于字符串对象相加,最关键的问题就是分析出 String c = a + b是怎么执行的。String a = "hello";String b = "abc";String c = a + b; //字符串对象相加
// 底层是StringBuilder s = new StringBuilder();s.append(a);s.append(b);c = s.toString();
public String toString() {return new String(value, 0, count); //截取 0~count-1}

底层是创建了一个 StringBuilder类,调用append方法把几个字符串对象相加,然后再调用toString方法返回一个新的字符串对象给c。
重要规则:String c1 = “ab” + “cd”; 常量相加,c1指向的是常量池中的地址。 String c2 = a + b; 对象相加,c2指向的是堆中的地址(对象地址)。
因此总共创建了三个对象(a,b,c分别对应的String,StringBuilder类调用后就销毁了)
分析: 主方法创建了一个Test对象,ex为对象指针,在栈中。对象实体在堆中。而在对象实体里,str为String类指针,指向String类的value属性,而value又指向常量池中的 “hsp”。ch是一个数组指针,指向堆中的数组。public class Test {String str = new String("hsp");final char[] ch = {'j','a','v','a'};public void change(String str,char ch[]){ //注意str是形参,不同于真正的strstr = "java";ch[0] = 'h';}public static void main(String[] args) {Test ex = new Test();ex.change(a.str,a.ch);System.out.println(ex.str + " " + ex.ch);}}
然后调用ex的change方法,会在栈中开辟一个方法区,在方法区中,str和ch都是形参(当然也可以改名), str本来指向value, 更改后指向常量池中的”java”(但原先的str没变化!仍然指向value),但ch因为也指向字符数组,因此修改之后保持同步(注意final表示指针的指向不能更改,而不是指针指向的内容不能修改)。调用完方法后,形参被销毁。
最终输出 hsp hava
String类常用方法






使用split时请注意:public static void main(String[] args) {String s = "aaa aaa aaa ";String[] ss = s.split(" ");for(int i=0;i<ss.length;i++){System.out.println(ss[i]);}}

“aaa aaa aaa “,中间有三个空格,因此第一个空格返回”aaa”,而第二第三个就返回一个空串,并不是把所有空格都去除了,要考虑到空串的情况。
注:如果想对String进行操作,应该先用 toCharArray 方法把String转化成一个字符数组,对这个字符数组进行操作后再转换为String。 ```java String str = “abcdef”; char[] chars = str.toCharArray(); //字符串转换为字符数组 ……String format = String.format("%s,%s .%c",name,job,id);System.out.println(format);
// 对字符数组进行一系列操作 String str1 = new String(chars); // 由字符数组建立一个新数组
<a name="lQHCk"></a>### 空串与null串空串是一个Java对象,有自己的串长度(0)和内容(空),**null串是指一个字符串中放入的特殊值null,表示目前没有任何对象与该变量关联(注意这两个是不同的概念!)。**```javaif(str == null) //判断是否为null串if(str.length()==0) //判断是否为空串if(str.equals("") //判断是否为空串
码点与代码单元
char数据类型是一个采用UTF-16编码表示Unicode码点的代码单元。最常用的Unicode字符使用一个代码单元就可以表示(a,b,c等),而辅助字符(𝕆等)需要两个代码单元表示。
码点:是指一个编码表中的某个字符对应的代码值。(也就是字符在Unicode表中的位置)
在Java中一个Unicode占2个字节(byte),一个字节等于8比特位(bit),因此,每个Unicode码占用16个比特位。若一个字符的代码长度为16位,则为一个代码单元。若一个字符的代码长度有两个16的代码长度编码,则该字符有两个代码单元。
获取方法:
String.length():返回字符串代码单元的个数。
String.codePointCount(int startIndex,int endIndex):返回startInde到endIndex-1之间的码点个数。(也就是有多少个字符,因为一个字符对应一个位置(代码值))
String.charAt(int index):返回给定位置的代码单元,尽可能不要调用这个方法。
String.codePointAt(int index):返回给定位置的码点(也就是该字符在Unicode中的位置)
String.offsetByCodePoints(int startIndex,int cpCount):返回从stratIndex码点开始,cpCount个码点后的码点索引。
举例:hi𝕆 这个字符串实际上有三个码点,四个代码单元。
1.测试length函数和codePointCount函数
public class HelloJava {public static void main(String[] args) {String greeting="hi𝕆";int t=greeting.length();int h=greeting.codePointCount(0, t);System.out.println(t);System.out.println(h);}}

首先测试的是测量字符串长度的两种方法——用length方法得出字符串代码单元个数为4,因为𝕆这个符号是由两个代码单元得到的。而用count方法得出字符串码点个数为3,也就是有多少个字符。
2.测试charAt函数
public class HelloJava {public static void main(String[] args) {String greeting="hi𝕆";char a=greeting.charAt(0);char b=greeting.charAt(1);char c=greeting.charAt(2);char d=greeting.charAt(3);System.out.println(a);System.out.println(b);System.out.println(c);System.out.println(d);}}

由于charAt函数是返回给定位置的代码单元,因此在第2个和第三个位置返回的是相同的代码单元。charAt可以在没有辅助元素的字符串中使用。
3.测试codePointAt函数
public class HelloJava {public static void main(String[] args) {String greeting="hi𝕆";int a=greeting.codePointAt(0);int b=greeting.codePointAt(1);int c=greeting.codePointAt(2);int d=greeting.codePointAt(3);System.out.println(a);System.out.println(b);System.out.println(c);System.out.println(d);}}

codePointAt函数返回的是序号对应的字符在Unicode表中的位置,可以看出h和i位置是挨在一起的,并且𝕆符号是由两个不同代码单元组成的。
4.测试offsetByCodePoints函数
public class HelloJava {public static void main(String[] args) {String greeting="hi𝕆";int a=greeting.offsetByCodePoints(0, 0);int b=greeting.offsetByCodePoints(0, 1);int c=greeting.offsetByCodePoints(0, 2);System.out.println(a);System.out.println(b);System.out.println(c);}}

经过的是码点数而不是代码单元,因此这个就可以看作是从序号为startIndex开始,经过cpCount个位置,对应的码点的序号。与代码单元就没有关系了。
总结:
String.codePointCount(int startIndex,int endIndex) 是最标准的求字符串长度的函数
int cpCount = String.codePointCount(0,String.length());
String.codePointAt(int index) 是最标准的求码点在Unicode位置的函数
String.offsetByCodePoints(int startIndex,int cpCount) 是最标准的求码点对应序号的函数
想要得到第i个码点,应该使用下列语句
int index = String.offsetByCodePoints(0,i);int cp = String.codePointAt(index);
StringBuffer
基本介绍

StringBuffer的父类有value属性用于存放字符串,这个value不是final的。
String与StringBuffer

StringBuffer里的value属性只有在内存不够需要另外开辟空间时,才会更改指向。
构造器
String与StringBuffer相互转换
String转StringBuffer
String str = "青眼究极龙";// 第一种方式:直接调用构造器StringBuffer ss = new StringBuffer(str);// 第二种方式:用append方法 (前提是先new出一个StringBuffer对象)StringBuffer ss2 = new StringBuffer();ss2 = ss2.append(str);
StringBuffer转String
// 第一种方式:StringBuffer的 toString方法String s = ss.toString();// 第二种方式:直接调用构造器String s1 = new String(ss);
常用方法


// append方法StringBuffer a = new StringBuffer("Hello");a.append(",World").append("!"); //可以连续调用System.out.println(a); // Hello,World!
String str = null;StringBuffer ss = new StringBuffer();ss.append(str); //底层调用的是 父类的 appendNull方法,传入null时自动转化为字符串System.out.println(ss.length()); // 输出4System.out.println(ss); //输出 nullStringBuffer ss2 = new StringBuffer(str); //底层调用 super(str.length()+16);//抛出 NullPointerException

源代码
// delete方法 删除[a,b)的元素StringBuffer b = new StringBuffer("AAABBBBCC");System.out.println(b.delete(3,7)); // 删除区间 [3,7)的元素 输出 AAACC// replace方法 把[0,4)的字符串替换为指定字符串StringBuffer c = new StringBuffer("BlueEyes");System.out.println(c.replace(0,4,"Red")); //输出 RedEyes// indexOf方法,返回字串第一次出现的位置StringBuffer d = new StringBuffer("AAAC");System.out.println(d.indexOf("AAA")); //输出0// insert方法,在指定索引插入指定字符串System.out.println(d.insert(0,"qqq"));//在索引为0的位置插入字符串,其他的后移 AAACqqq
StringBuilder


3. 实现了 Serializable,说明StringBuilder对象是可以串行化(对象可以网络传输,可以保存到文件)。
4. StringBuilder对象字符序列仍然是存放在其父类的 char[] value。因此字符序列是在堆中。
5. StringBuilder的方法没有做互斥处理(没有synchronized关键字),因此应在单线程的情况下使用。
String,StringBulider,StringBuffer比较
效率
StringBuilder > StringBuffer > String
基本概念
使用原则
注意事项
Math类
- abs 绝对值
System.out.println(Math.abs(-11)); //输出11
- pow 求幂
3. ceil 向上取整 floor 向下取整 round 四舍五入(实际上是 floor(n + 0.5))System.out.println(Math.pow(2,3)); //2的三次方
System.out.println(Math.ceil(1.1));System.out.println(Math.floor(1.1));System.out.println(Math.round(1.4));// Math.floor(n+0.5)System.out.println(Math.round(1.5));
- sqrt 求开方
5. random 求随机数,返回一个 [0,1) 之间的double数。System.out.println(Math.sqrt(9));
获取 [a,b] 之间的一个随机整数:公式为 int num = (int)(a + Math.random()*(b - a + 1));
返回 [2,6]之间的整数实际上就等于返回 [2,7)之间的整数。System.out.println((int)(2 + Math.random()*(6-2+1))); //返回[2,6]之间的数
6. max 求最大值,min 求最小值。Arrays类
Arrays里面包含了一系列静态方法,用于管理或操作数组(比如排序和搜索)toString 返回数组的字符串形式
int[] a = {1,2,3,4,5};System.out.println(Arrays.toString(a)); // 输出 [1, 2, 3, 4, 5]
sort排序(自然排序和定制排序)
因为数组是引用类型,因此sort会直接改变原数组。
需要重点理解的就是定制排序:它不仅需要传入一个数组,还需要实现一个匿名内部类(通过传入一个接口 Comparator 实现),传入的数组不能是基本类型,必须是包装类(如Integer),因为用到了泛型。int[] a = {31,2,5,999,-3};Arrays.sort(a); //自然排序,从小到大排列System.out.println(Arrays.toString(a));// [-3, 2, 5, 31, 999]

对 return o2 - o1 的理解:实际上sort调用了父类的一个 binarySort的方法,而 o2 - o1的结果会影响方法的走向。返回负数的时候,第一个参数排在前面。返回正数的时候,第二个参数排在前面。返回0的时候,谁在前面无所谓。public static void main(String[] args) {Integer[] a = {31,2,5,999,-3}; // 不能是基本类型Arrays.sort(a, new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2 - o1; // 从大到小排}});System.out.println(Arrays.toString(a)); //[999, 31, 5, 2, -3]}

在C++中,实现自定义排序则是通过自定义函数cmp。
而在Java并不能用boolean来代表整形,因此只能用相减是否为正来判断该走哪一步。只要记住返回 o2 - o1 是从大到小排就行了。 因为返回负数,第一个参数排在前面,因此当需要从大到小排,也就是当o1>o2时,需要让o1排在前面,那么就返回一个负数。故 return o2-o1;int cmmp(object a,object b){return a>b; // 从大到小排序// 从小到大排序是 return a<b;}
3. 用冒泡排序模拟定制排序
public static void bubbleSort(Integer a[],Comparator b){for(int i = 0;i<a.length-1;i++){for(int j = 0;j<a.length-i-1;j++){ //冒泡排序if(b.compare(a[j],a[j+1])<0){ //根据compare的返回结果判定是否交换// 这与真正的compare思想一致int temp = a[j];a[j] = a[j+1];a[j+1] = temp;}//调用Comparator接口的compare方法}}}
根据compare的具体实现,n1 - n2 < 0时进行交换,即n1小于n2时交换,也就是说最后是从大到小排列。
4. binarySearch 二分查找
通过二分搜索法进行查找,返回对应元素的索引,要求必须排好序。如果该数组中不存在该元素,则返回 -(low + 1),其中low最终是 查找元素应该位于的索引。
Integer[] a = {1,2,3,4,5};int index1 = Arrays.binarySearch(a,5); // 输出4int index2 = Arrays.binarySearch(a,6); // 输出-6 ,如果6存在的话索引应该是5
5. copyOf 数组元素的复制
Integer[] a = new Integer[]{1,2,3,4,5};Integer[] newArr = Arrays.copyOf(a,3); //复制3个元素System.out.println(Arrays.toString(newArr)); //[1, 2, 3]
如果拷贝的长度 > a.length ,那么就在新数组的后面增加 null,如果拷贝长度 < 0,就会抛出异常NegativeArraySizeException。
Integer[] newArr = Arrays.copyOf(a,10);//[1, 2, 3, 4, 5, null, null, null, null, null]Integer[] newArr = Arrays.copyOf(a,-1);// Exception in thread "main" java.lang.NegativeArraySizeException
6. fill 数组元素的填充
Integer[] a = new Integer[]{1,2,3,4,5};Arrays.fill(a,1000);System.out.println(Arrays.toString(a)); // [1000, 1000, 1000, 1000, 1000]
7. equals 比较两个数组元素内容是否完全一致
Integer[] a = new Integer[]{1,2,3,4,5};Integer[] b = new Integer[]{1,2,3,4,5};Integer[] c = new Integer[]{1,3,2,4,5};System.out.println(Arrays.equals(a,b)); // trueSystem.out.println(Arrays.equals(a,c)); // false,顺序不一样也不行
8. asList 将一组值转换成list(链表)
asList编译类型为 List(接口),运行类型为 java.util.Arrays$ArrayList,是Arrays类的。
List<Integer> asList = Arrays.asList(2,3,4,5,6,1);System.out.println(asList.getClass()); // class java.util.Arrays$ArrayList
System类
- exit 退出当前程序。
2. arraycopy:复制数组元素,比较适合底层调用。一般还是使用 Arrays.copyOf 完成复制数组。System.exit(0); // 0表示一个正常的状态。
src:源数组(提供数据) srcPos:从源数组的哪个索引位置开始拷贝 dest:目标数组。 destPos:从源数组的数据拷贝到目标数组的哪个索引 length:从源数组拷贝多少个数据。System.arraycopy(src,srcPos,dest,destPos,length);
3. currentTimeMillens:返回当前时间距离1970-1-1的毫秒数。System.out.println(System.currentTimeMillis());
- gc:运行垃圾回收机制 System.gc();
大数类
1. BigInteger适合保存比较大的整形
2. BigDecinal适合保存精度更高的浮点型。
大数不能用符号加减乘除,而需要调用方法,这里只拿BigDecinal进行演示:
BigDecimal a = new BigDecimal("1.23213131391123131");BigDecimal b = new BigDecimal("2.22222");System.out.println(a.add(b)); //加System.out.println(a.subtract(b)); //减System.out.println(a.multiply(b)); //乘
这里只需要注意一点:除法的结果可能是个无限小数,如果是这样的话会报错。为了避免报错,我们可以指定精度(保留分子的精度)。
System.out.println(a.divide(b,BigDecimal.ROUND_CEILING)); //保留分子精度
Date类
第一代日期类
引用 java.util.Date(不要引入sql的Date类)
Date a = new Date();Date b = new Date(111111);//1970-1-1开始经过的毫秒数System.out.println(a); //用国外的方式输出当前日期 Wed Sep 29 21:02:51 CST 2021System.out.println(b);System.out.println(a.getTime()); //获取某个时间对应的毫秒数
第二代日期类

1. Calendar是一个抽象类,并且构造器为 private。
2. 可以通过 getInstance() 来获取实例。
3. 提供大量的方法和字段提供给程序员。
4. Calendar 没有专门的格式化方法,所以需要程序员自己来组合显示。
public static void main(String[] args) {// Calendar a = new Calendar(); //报错,因为抽象类需要实现方法(但是超级多)Calendar a = Calendar.getInstance();// 正确的获取对象方法System.out.println(a); //输出全部信息System.out.println(Calendar.YEAR);System.out.println(a.get(Calendar.YEAR)); //输出年份System.out.println(a.get(Calendar.MONTH) + 1); // 加一是因为从0开始计数System.out.println(a.get(Calendar.DAY_OF_MONTH)); //输出第几天System.out.println(a.get(Calendar.HOUR)); //输出今天的小时(12小时表示法)System.out.println(a.get(Calendar.HOUR_OF_DAY)); //(24小时表示法)System.out.println(a.get(Calendar.MINUTE)); //小时的分System.out.println(a.get(Calendar.SECOND)); //分的秒}
注意,如果想输出当前年份,光输出 Calendar.YEAR 是不行的,因为 Calendar.YEAR 等只是一个数(1,2,3,4等),而需要调用get方法才能正确输出对应信息(里面有类似的witch语句,根据数字输出对应的东西)。
第三代日期类


1. LocalDateTime类,用于获取年月日和时分秒。
//LocalDateTime ldt = new LocalDateTime(); //错误的构造方法LocalDateTime ldt = LocalDateTime.now(); //正确的构造方法,可以获取年月日和时间System.out.println(ldt); //输出当前完整时间信息System.out.println(ldt.getYear()); //输出年份System.out.println(ldt.getMonth()); //输出月份(英文)System.out.println(ldt.getMonthValue());//输出月份(阿拉伯数字)System.out.println(ldt.getHour()); // 输出小时(当然还能得到分和秒)...
2. LocalDate类,只能获取年月日。LocalTime类,只能获取时分秒。
LocalDate now = LocalDate.now(); //用于获取年月日LocalTime now2 = LocalTime.now();//用于获取时分秒
3. DateTimeFormatter格式日期类 

public class Test{public static void main(String[] args) {LocalDateTime ldt = LocalDateTime.now();DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH小时mm分钟ss秒");//这里yyyy等不区分大小写,但必须是这个字母。DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-mm-dd HH:mm:ss");//字母对应时间,剩下的可以自己定义格式String strDate1 = dtf1.format(ldt); //调用format方法,LocalDateTime类为参数String strDate2 = dtf2.format(ldt);System.out.println(strDate1);System.out.println(strDate2);}}
4. 时间戳
1) 通过静态方法获取对象
Instant now = Instant.now();//用静态方法 now 获取表示当前时间戳的对象//Instant now = new Instant(); 错误System.out.println(now); // 2021-10-03T14:36:07.540Z
2) 通过 Date类的from静态方法 可以把 Instant类转成 Date类
Date date = Date.from(now);System.out.println(date.getTime());
3) 通过 Date对象的toInstant方法可以把 date类 转换成 Instant类
Instant instant = date.toInstant();
5. plus和minus
所有第三代日期类都可以使用,通过提供 plus 和 minus方法可以对当前时间进行加或减,注意不对原对象进行操作,而是返回一个经过操作之后的对象。


串行化:可以在网络传输(转换成JSON格式等)。




