Object类

== 运算符

  1. == 运算符既可以判断基本类型,又可以判断引用类型。
    2. 如果判断基本类型,那么判断的是 值是否相等。
    1. int i = 10;
    2. double d = 10.0;
    3. System.out.println(i==d)//true
    3. 如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象,如果希望判断内容是否相同,则需要重写。
    1. public class Test {
    2. public static void main(String[] args) {
    3. NotePad a = new NotePad();
    4. Computer b = a;
    5. //向上转型,a和b都指向同一个NotePad对象
    6. System.out.println(a==b); //true 因为a和b地址相同
    7. }
    8. }

    equals方法

  2. 是Object类的方法,只能判断引用类型。
    2. 默认判断的是地址是否相等,子类往往重写该方法,用于判断内容是否相等(比如String类)。
    1. String str1 = "shang";
    2. String str2 = "shang";
    3. System.out.println(str1 == str2); //true,str1和str2地址相同
    4. System.out.println(str1.equals(str2)); //true
    5. String str3 = new String("shang");
    6. String str4 = new String("shang");
    7. System.out.println(str3 == str4); //false
    8. System.out.println(str3.equals(str4)); //true
    9. System.out.println(str1 == str3); //false
    10. System.out.println(str1.equals(str3)); //true
    需要注意一点,String类是否用new来初始化还是有区别的。比如str1和str2,实际上都指向同一块内容为”shang”的区域,因此str1和str2地址相同而str3和str4,虽然指向的内容都是相同,但是由于用到了new,开辟了两个String对象,因此str3和str4指向两个内容相同但地址不同的String对象

    重写equals方法

    用于判断对象的内容是否相同。
    1. public boolean equals(object obj){
    2. if(this == obj){
    3. return true;
    4. } //如果是地址相同那么就返回true
    5. if(!(obj instanceof Doctor)){
    6. return false;
    7. }//如果obj不是Doctor类或其子类,那么返回false
    8. Doctor doctor = (Doctor)obj; //传入的参数向下转型
    9. return this.name.equals(doctor.name)&&this.age == doctor.age;
    10. }

    查看JDK源码

    1. 一般来说 IDEA 配置好JDK后,jdk的源码也就自动配置好了。
    2. 如果没有的话点击 菜单File —> Project Stucture —> SDKs —> Sourcepath 然后点击加号 —> 找到jdk安装目录,把 src.zip 和 javafx-src.zip 加入即可。
    image.png
    3. 在需要查看某个方法源码时,将光标放在该方法上,输入 ctrl + b 即可。或者在方法上点击右键 —> go to —> Declarartion or Usages。
    image.png

    hashCode方法

  3. 提高具有哈希结构的容器的效率(如HashMap,HashTable等)。
    2. 两个引用如果指向的是同一个对象,则哈希值肯定是一样的。
    3. 两个引用如果指向的是不同对象,则哈希值是不一样的。
    4. 哈希值主要是根据地址号计算的(通过将该对象的内部地址转换成一个整数实现的),不能将哈希值等价于地址。
    5. hashCode如果有需要的话,也会重写。
    1. public int hashCode() {
    2. int h = hash;
    3. if (h == 0 && value.length > 0) { //value就是把对象toString后的结果
    4. char val[] = value; //将字符串转化为字符数组
    5. for (int i = 0; i < value.length; i++) {
    6. h = 31 * h + val[i]; //哈希值计算方法
    7. }
    8. hash = h;
    9. }
    10. return h;
    11. }

    toString方法

    默认返回:全类名(包名+类名)+ @ + 哈希值的十六进制。
    1. public String toString() {
    2. return getClass().getName() + "@" + Integer.toHexString(hashCode());
    3. }
    重写:子类往往重写toString方法,用于返回对象的属性信息。
    image.png image.png
    自动调用:当输出对象时,toString方法会被自动调用(重写会影响)。
    1. public class Test {
    2. public static void main(String[] args) {
    3. Person wang = new Person(10, "wang", 20);
    4. System.out.println(wang);
    5. //com.shang.Person@1b6d3586
    6. }
    7. }

    finalize方法

  4. 当对象被回收时,系统自动调用该对象的finalize方法。子类可以重写该方法,写自己的业务逻辑代码(数据库连接,打开文件等),如果不重写就会调用 Object类的finalize
    2. 什么时候被回收:当某个对象没有任何引用时,jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用finalize方法。
    1. public static void main(String[] args) {
    2. Person p1 = new Person();
    3. p1 = null; // 这时,p1就是一个垃圾,垃圾回收器会销毁对象
    4. }
    5. // 在销毁对象前,会调用该方法的finalize方法
    输入一个 f 就可以重写 finalize方法了。 finlize的调用类似C++的析构函数。
    image.png
    3. 垃圾回收机制的调用,是由系统来决定(有自己的GC算法),也可以通过System.gc() 主动触发垃圾回收机制。(在实际开发中,几乎不会运用 finalize)

包装类(封装类型)

针对八种基本类型相应的引用类型——包装类。有了类的特点,就可以调用类中的方法。
image.png
image.png
image.pngimage.png

装箱与拆箱

在JDK5之前,进行的是手动的装箱与拆箱。所谓装箱,就是进行 int -> Integer 的转换,而拆箱就是 Integer -> int 之间的转换其它基本元素类似)。

  1. int n1 = 100;
  2. Integer integer = new Integer(n1);
  3. Integer integer1 = Integer.valueOf(n1); //手动装箱(把基本数据变成对象)
  4. int n2 = integer.intValue(); // 手动拆箱

在JDK5后,就可以自动装箱和自动拆箱。自动将一个原始数据类型转换为一个封装类型称为自动装箱,自动将一个封装类型转换为一个原始数据类型被称为自动拆箱。
装箱和拆箱 是编译器要做的工作,而不是虚拟机。

  1. int n1 = 100;
  2. Integer integer = n1; //自动装箱,底层使用的是 Integer.valueOf(n1)方法
  3. int n2 = integer; //自动拆箱,底层使用的是 intValue()方法
  4. Object obj1 = true?new Integer(1):new Double(2.0);
  5. System.out.println(obj1); //最大精度为double,输出1.0

注意输出的是1.0而不是1,因为三元运算符是一个整体,在执行时会把所数据类型的精度上升到最大的那个。

  1. Object obj1 = true?new Integer(1):new Integer(2);
  2. System.out.println(obj1); // 最大精度为int,输出1

Integer与String相互转换

Integer -> String:

  1. Integer n = 100;
  2. String str1 = n + ""; // 第一种方法
  3. String str2 = n.toString(); // 第二种方法
  4. String str3 = String.valueOf(n); // 第三种方法,valueOf也可以使用int作为参数

String -> Integer:

  1. String str = "12345";
  2. Integer n1 = Integer.parseInt(str); // 第一种方法
  3. Integer n2 = new Integer(str); // 第二种方法,构造器
  4. Integer n3 = new Integer(str); // 第三种方法

常用方法

image.pngimage.png

Integer创建机制

  1. public static void main(String[] args) {
  2. Integer a = new Integer(1);
  3. Integer b = new Integer(1);
  4. System.out.println(a==b); //a和b都是new出的对象,地址肯定不相同
  5. Integer m = 1; //底层是Integer.valueOf
  6. Integer n = 1;
  7. System.out.println(m==n);
  8. Integer x = 128;
  9. Integer y = 128;
  10. System.out.println(x==y);
  11. }

对于使用 Integer.valueOf 创建的对象,注意 m和n 与 x和y 之间的区别:当使用自动装箱时,底层调用的是Integer的valueOf方法,它会根据传入数值的大小决定是否new一个对象。

  1. public static Integer valueOf(int i) { //源码
  2. if (i >= IntegerCache.low && i <= IntegerCache.high)
  3. //low是-128,high是127
  4. return IntegerCache.cache[i + (-IntegerCache.low)];
  5. return new Integer(i);
  6. }

通过查看源码得知,如果传入的参数在 -128~127之间,不会创建新的对象,而是直接调用内部数组cache,返回一个数(但还是Integer对象,只不过地址相同)而在其他范围的参数就会new一个新对象。
因此m和n是一个相同的Integer对象。而x和y则是地址不同的对象。
image.pngimage.png
如果基本数据类型和类比较是否相等,那么就比较数值是否相等。

  1. public static void main(String[] args) {
  2. Integer n1 = 127;
  3. int n2 = 127;
  4. System.out.println(n1==n2); //true
  5. Integer n3 = 128;
  6. int n4 = 128;
  7. System.out.println(n3==n4); //true
  8. }

image.png

String类

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

基本信息

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

    创建方式

    image.png
    方式一:先从常量池查看是否有 “hsp” 数据空间,如果有,字符串直接指向该空间。如果没有则重新创建,然后指向。s最终指向的是常量池的空间地址。
    方式二:先在堆中创建空间,里面维护了value属性,如果常量池里有 “hsp”,value指向常量池的”hsp”地址。如果常量池没有 “hsp”,重新创建,然后再指向。s2 最终指向的是堆中的空间地址。
    image.png
    综合训练 P497

    String 对象特性

    1. String s1 = "hello";
    2. s1 = "haha";
    一共创建了两个对象,”hello”与”haha”,值得注意的是,上面说的String的value属性是final类型,不能更换地址,指的是”hello”与”haha”不能更换地址这两个才是String对象,而s1只是一个指向String对象的指针罢了因此s1可以指向不同的对象,而”hello”和”haha”并不能更换地址
    image.png
    1. String a = "hello" + "abc"; // 字符串常量相加
    创建了一个对象String a = “hello” + “abc” 会被优化等价于 String a = “helloabc”。对于这种字符串常量相加的情况,编译器会自动优化,然后就等价于一个新的字符串常量对象赋给指针。
    当将一个字符串与一个非字符串的值进行拼接时,后者会转换为字符串。
    1. String a = "hello";
    2. String b = "abc";
    3. String c = a + b; //字符串对象相加
    对于字符串对象相加,最关键的问题就是分析出 String c = a + b是怎么执行的
    1. // 底层是
    2. StringBuilder s = new StringBuilder();
    3. s.append(a);
    4. s.append(b);
    5. c = s.toString();
    1. public String toString() {
    2. return new String(value, 0, count); //截取 0~count-1
    3. }
    image.pngimage.png
    底层是创建了一个 StringBuilder类,调用append方法把几个字符串对象相加,然后再调用toString方法返回一个新的字符串对象给c
    重要规则:String c1 = “ab” + “cd”; 常量相加,c1指向的是常量池中的地址。 String c2 = a + b; 对象相加,c2指向的是堆中的地址(对象地址)。
    因此总共创建了三个对象(a,b,c分别对应的String,StringBuilder类调用后就销毁了)
    1. public class Test {
    2. String str = new String("hsp");
    3. final char[] ch = {'j','a','v','a'};
    4. public void change(String str,char ch[]){ //注意str是形参,不同于真正的str
    5. str = "java";
    6. ch[0] = 'h';
    7. }
    8. public static void main(String[] args) {
    9. Test ex = new Test();
    10. ex.change(a.str,a.ch);
    11. System.out.println(ex.str + " " + ex.ch);
    12. }
    13. }
    分析: 主方法创建了一个Test对象,ex为对象指针,在栈中。对象实体在堆中。而在对象实体里,str为String类指针,指向String类的value属性,而value又指向常量池中的 “hsp”。ch是一个数组指针,指向堆中的数组
    然后调用ex的change方法,会在栈中开辟一个方法区,在方法区中,str和ch都是形参(当然也可以改名), str本来指向value, 更改后指向常量池中的”java”(但原先的str没变化!仍然指向value),但ch因为也指向字符数组,因此修改之后保持同步(注意final表示指针的指向不能更改,而不是指针指向的内容不能修改)。调用完方法后,形参被销毁。
    最终输出 hsp hava
    image.pngimage.png

    String类常用方法

    image.png
    image.png
    image.png
    image.png
    image.png
    image.png
    使用split时请注意:
    1. public static void main(String[] args) {
    2. String s = "aaa aaa aaa ";
    3. String[] ss = s.split(" ");
    4. for(int i=0;i<ss.length;i++){
    5. System.out.println(ss[i]);
    6. }
    7. }
    image.png
    “aaa aaa aaa “,中间有三个空格,因此第一个空格返回”aaa”,而第二第三个就返回一个空串,并不是把所有空格都去除了,要考虑到空串的情况。
    image.png
    1. String format = String.format("%s,%s .%c",name,job,id);
    2. System.out.println(format);
    注:如果想对String进行操作,应该先用 toCharArray 方法把String转化成一个字符数组,对这个字符数组进行操作后再转换为String。 ```java String str = “abcdef”; char[] chars = str.toCharArray(); //字符串转换为字符数组 ……
    // 对字符数组进行一系列操作 String str1 = new String(chars); // 由字符数组建立一个新数组
  1. <a name="lQHCk"></a>
  2. ### 空串与null串
  3. 空串是一个Java对象,有自己的串长度(0)和内容(空),**null串是指一个字符串中放入的特殊值null,表示目前没有任何对象与该变量关联(注意这两个是不同的概念!)。**
  4. ```java
  5. if(str == null) //判断是否为null串
  6. if(str.length()==0) //判断是否为空串
  7. 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函数

  1. public class HelloJava {
  2. public static void main(String[] args) {
  3. String greeting="hi𝕆";
  4. int t=greeting.length();
  5. int h=greeting.codePointCount(0, t);
  6. System.out.println(t);
  7. System.out.println(h);
  8. }
  9. }

image.png
首先测试的是测量字符串长度的两种方法——用length方法得出字符串代码单元个数为4,因为𝕆这个符号是由两个代码单元得到的。而用count方法得出字符串码点个数为3,也就是有多少个字符。
2.测试charAt函数

  1. public class HelloJava {
  2. public static void main(String[] args) {
  3. String greeting="hi𝕆";
  4. char a=greeting.charAt(0);
  5. char b=greeting.charAt(1);
  6. char c=greeting.charAt(2);
  7. char d=greeting.charAt(3);
  8. System.out.println(a);
  9. System.out.println(b);
  10. System.out.println(c);
  11. System.out.println(d);
  12. }
  13. }

image.png
由于charAt函数是返回给定位置的代码单元,因此在第2个和第三个位置返回的是相同的代码单元。charAt可以在没有辅助元素的字符串中使用。
3.测试codePointAt函数

  1. public class HelloJava {
  2. public static void main(String[] args) {
  3. String greeting="hi𝕆";
  4. int a=greeting.codePointAt(0);
  5. int b=greeting.codePointAt(1);
  6. int c=greeting.codePointAt(2);
  7. int d=greeting.codePointAt(3);
  8. System.out.println(a);
  9. System.out.println(b);
  10. System.out.println(c);
  11. System.out.println(d);
  12. }
  13. }

image.png
codePointAt函数返回的是序号对应的字符在Unicode表中的位置,可以看出h和i位置是挨在一起的,并且𝕆符号是由两个不同代码单元组成的。
4.测试offsetByCodePoints函数

  1. public class HelloJava {
  2. public static void main(String[] args) {
  3. String greeting="hi𝕆";
  4. int a=greeting.offsetByCodePoints(0, 0);
  5. int b=greeting.offsetByCodePoints(0, 1);
  6. int c=greeting.offsetByCodePoints(0, 2);
  7. System.out.println(a);
  8. System.out.println(b);
  9. System.out.println(c);
  10. }
  11. }

image.png
经过的是码点数而不是代码单元,因此这个就可以看作是从序号为startIndex开始,经过cpCount个位置,对应的码点的序号。与代码单元就没有关系了。
总结:
String.codePointCount(int startIndex,int endIndex) 是最标准的求字符串长度的函数

  1. int cpCount = String.codePointCount(0,String.length());

String.codePointAt(int index) 是最标准的求码点在Unicode位置的函数
String.offsetByCodePoints(int startIndex,int cpCount) 是最标准的求码点对应序号的函数
想要得到第i个码点,应该使用下列语句

  1. int index = String.offsetByCodePoints(0,i);
  2. int cp = String.codePointAt(index);

image.png

StringBuffer

image.png

基本介绍

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

String与StringBuffer

image.png
StringBuffer里的value属性只有在内存不够需要另外开辟空间时,才会更改指向。

构造器

image.png
对于第四种方法,数组大小为 指定的字符串长度 + 16

String与StringBuffer相互转换

String转StringBuffer

  1. String str = "青眼究极龙";
  2. // 第一种方式:直接调用构造器
  3. StringBuffer ss = new StringBuffer(str);
  4. // 第二种方式:用append方法 (前提是先new出一个StringBuffer对象)
  5. StringBuffer ss2 = new StringBuffer();
  6. ss2 = ss2.append(str);

StringBuffer转String

  1. // 第一种方式:StringBuffer的 toString方法
  2. String s = ss.toString();
  3. // 第二种方式:直接调用构造器
  4. String s1 = new String(ss);

常用方法

image.pngimage.png

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

image.pngimage.png 源代码

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

StringBuilder

image.png
image.png
3. 实现了 Serializable,说明StringBuilder对象是可以串行化(对象可以网络传输,可以保存到文件)。
4. StringBuilder对象字符序列仍然是存放在其父类的 char[] value。因此字符序列是在堆中。
5. StringBuilder的方法没有做互斥处理(没有synchronized关键字),因此应在单线程的情况下使用。

String,StringBulider,StringBuffer比较

效率

StringBuilder > StringBuffer > String

基本概念

image.png
复用率 —— 可以有多个指针指向String。

使用原则image.png

注意事项

image.pngimage.png

Math类

  1. abs 绝对值
    1. System.out.println(Math.abs(-11)); //输出11
  2. pow 求幂
    1. System.out.println(Math.pow(2,3)); //2的三次方
    3. ceil 向上取整 floor 向下取整 round 四舍五入(实际上是 floor(n + 0.5))
    1. System.out.println(Math.ceil(1.1));
    2. System.out.println(Math.floor(1.1));
    3. System.out.println(Math.round(1.4));
    4. // Math.floor(n+0.5)
    5. System.out.println(Math.round(1.5));
  3. sqrt 求开方
    1. System.out.println(Math.sqrt(9));
    5. random 求随机数,返回一个 [0,1) 之间的double数。
    获取 [a,b] 之间的一个随机整数:公式为 int num = (int)(a + Math.random()*(b - a + 1));
    1. System.out.println((int)(2 + Math.random()*(6-2+1))); //返回[2,6]之间的数
    返回 [2,6]之间的整数实际上就等于返回 [2,7)之间的整数。
    6. max 求最大值,min 求最小值。

    Arrays类

    Arrays里面包含了一系列静态方法,用于管理或操作数组(比如排序和搜索)

    toString 返回数组的字符串形式

    1. int[] a = {1,2,3,4,5};
    2. System.out.println(Arrays.toString(a)); // 输出 [1, 2, 3, 4, 5]

    sort排序(自然排序和定制排序)

    因为数组是引用类型,因此sort会直接改变原数组。
    1. int[] a = {31,2,5,999,-3};
    2. Arrays.sort(a); //自然排序,从小到大排列
    3. System.out.println(Arrays.toString(a));// [-3, 2, 5, 31, 999]
    需要重点理解的就是定制排序它不仅需要传入一个数组,还需要实现一个匿名内部类通过传入一个接口 Comparator 实现),传入的数组不能是基本类型,必须是包装类(如Integer),因为用到了泛型。
    image.png
    1. public static void main(String[] args) {
    2. Integer[] a = {31,2,5,999,-3}; // 不能是基本类型
    3. Arrays.sort(a, new Comparator<Integer>() {
    4. @Override
    5. public int compare(Integer o1, Integer o2) {
    6. return o2 - o1; // 从大到小排
    7. }
    8. });
    9. System.out.println(Arrays.toString(a)); //[999, 31, 5, 2, -3]
    10. }
    对 return o2 - o1 的理解:实际上sort调用了父类的一个 binarySort的方法,而 o2 - o1的结果会影响方法的走向。返回负数的时候,第一个参数排在前面。返回正数的时候,第二个参数排在前面。返回0的时候,谁在前面无所谓。
    image.png
    在C++中,实现自定义排序则是通过自定义函数cmp。
    1. int cmmp(object a,object b){
    2. return a>b; // 从大到小排序
    3. // 从小到大排序是 return a<b;
    4. }
    而在Java并不能用boolean来代表整形,因此只能用相减是否为正来判断该走哪一步。只要记住返回 o2 - o1 是从大到小排就行了。 因为返回负数,第一个参数排在前面,因此当需要从大到小排,也就是当o1>o2时,需要让o1排在前面,那么就返回一个负数。故 return o2-o1;

3. 用冒泡排序模拟定制排序

  1. public static void bubbleSort(Integer a[],Comparator b){
  2. for(int i = 0;i<a.length-1;i++){
  3. for(int j = 0;j<a.length-i-1;j++){ //冒泡排序
  4. if(b.compare(a[j],a[j+1])<0){ //根据compare的返回结果判定是否交换
  5. // 这与真正的compare思想一致
  6. int temp = a[j];
  7. a[j] = a[j+1];
  8. a[j+1] = temp;
  9. }//调用Comparator接口的compare方法
  10. }
  11. }
  12. }

根据compare的具体实现,n1 - n2 < 0时进行交换,即n1小于n2时交换,也就是说最后是从大到小排列。
4. binarySearch 二分查找
通过二分搜索法进行查找,返回对应元素的索引,要求必须排好序如果该数组中不存在该元素,则返回 -(low + 1),其中low最终是 查找元素应该位于的索引

  1. Integer[] a = {1,2,3,4,5};
  2. int index1 = Arrays.binarySearch(a,5); // 输出4
  3. int index2 = Arrays.binarySearch(a,6); // 输出-6 ,如果6存在的话索引应该是5

5. copyOf 数组元素的复制

  1. Integer[] a = new Integer[]{1,2,3,4,5};
  2. Integer[] newArr = Arrays.copyOf(a,3); //复制3个元素
  3. System.out.println(Arrays.toString(newArr)); //[1, 2, 3]

如果拷贝的长度 > a.length ,那么就在新数组的后面增加 null,如果拷贝长度 < 0,就会抛出异常NegativeArraySizeException。

  1. Integer[] newArr = Arrays.copyOf(a,10);
  2. //[1, 2, 3, 4, 5, null, null, null, null, null]
  3. Integer[] newArr = Arrays.copyOf(a,-1);
  4. // Exception in thread "main" java.lang.NegativeArraySizeException

6. fill 数组元素的填充

  1. Integer[] a = new Integer[]{1,2,3,4,5};
  2. Arrays.fill(a,1000);
  3. System.out.println(Arrays.toString(a)); // [1000, 1000, 1000, 1000, 1000]

7. equals 比较两个数组元素内容是否完全一致

  1. Integer[] a = new Integer[]{1,2,3,4,5};
  2. Integer[] b = new Integer[]{1,2,3,4,5};
  3. Integer[] c = new Integer[]{1,3,2,4,5};
  4. System.out.println(Arrays.equals(a,b)); // true
  5. System.out.println(Arrays.equals(a,c)); // false,顺序不一样也不行

8. asList 将一组值转换成list(链表)
asList编译类型为 List(接口),运行类型为 java.util.Arrays$ArrayList,是Arrays类的。

  1. List<Integer> asList = Arrays.asList(2,3,4,5,6,1);
  2. System.out.println(asList.getClass()); // class java.util.Arrays$ArrayList

System类

  1. exit 退出当前程序。
    1. System.exit(0); // 0表示一个正常的状态。
    2. arraycopy:复制数组元素,比较适合底层调用。一般还是使用 Arrays.copyOf 完成复制数组。
    1. System.arraycopy(src,srcPos,dest,destPos,length);
    src:源数组(提供数据) srcPos:从源数组的哪个索引位置开始拷贝 dest:目标数组。 destPos:从源数组的数据拷贝到目标数组的哪个索引 length:从源数组拷贝多少个数据。
    3. currentTimeMillens:返回当前时间距离1970-1-1的毫秒数。
    1. System.out.println(System.currentTimeMillis());
  2. gc:运行垃圾回收机制 System.gc();

大数类

1. BigInteger适合保存比较大的整形
2. BigDecinal适合保存精度更高的浮点型。
大数不能用符号加减乘除,而需要调用方法,这里只拿BigDecinal进行演示:

  1. BigDecimal a = new BigDecimal("1.23213131391123131");
  2. BigDecimal b = new BigDecimal("2.22222");
  3. System.out.println(a.add(b)); //加
  4. System.out.println(a.subtract(b)); //减
  5. System.out.println(a.multiply(b)); //乘

这里只需要注意一点:除法的结果可能是个无限小数,如果是这样的话会报错。为了避免报错,我们可以指定精度(保留分子的精度)。

  1. System.out.println(a.divide(b,BigDecimal.ROUND_CEILING)); //保留分子精度

Date类

第一代日期类

引用 java.util.Date(不要引入sql的Date类)

  1. Date a = new Date();
  2. Date b = new Date(111111);//1970-1-1开始经过的毫秒数
  3. System.out.println(a); //用国外的方式输出当前日期 Wed Sep 29 21:02:51 CST 2021
  4. System.out.println(b);
  5. System.out.println(a.getTime()); //获取某个时间对应的毫秒数

image.png
image.png

第二代日期类

image.png
1. Calendar是一个抽象类,并且构造器为 private。
2. 可以通过 getInstance() 来获取实例。
3. 提供大量的方法和字段提供给程序员。
4. Calendar 没有专门的格式化方法,所以需要程序员自己来组合显示。

  1. public static void main(String[] args) {
  2. // Calendar a = new Calendar(); //报错,因为抽象类需要实现方法(但是超级多)
  3. Calendar a = Calendar.getInstance();// 正确的获取对象方法
  4. System.out.println(a); //输出全部信息
  5. System.out.println(Calendar.YEAR);
  6. System.out.println(a.get(Calendar.YEAR)); //输出年份
  7. System.out.println(a.get(Calendar.MONTH) + 1); // 加一是因为从0开始计数
  8. System.out.println(a.get(Calendar.DAY_OF_MONTH)); //输出第几天
  9. System.out.println(a.get(Calendar.HOUR)); //输出今天的小时(12小时表示法)
  10. System.out.println(a.get(Calendar.HOUR_OF_DAY)); //(24小时表示法)
  11. System.out.println(a.get(Calendar.MINUTE)); //小时的分
  12. System.out.println(a.get(Calendar.SECOND)); //分的秒
  13. }

注意,如果想输出当前年份,光输出 Calendar.YEAR 是不行的,因为 Calendar.YEAR 等只是一个数(1,2,3,4等),而需要调用get方法才能正确输出对应信息(里面有类似的witch语句,根据数字输出对应的东西)。

第三代日期类

image.png
image.png
1. LocalDateTime类,用于获取年月日和时分秒。

  1. //LocalDateTime ldt = new LocalDateTime(); //错误的构造方法
  2. LocalDateTime ldt = LocalDateTime.now(); //正确的构造方法,可以获取年月日和时间
  3. System.out.println(ldt); //输出当前完整时间信息
  4. System.out.println(ldt.getYear()); //输出年份
  5. System.out.println(ldt.getMonth()); //输出月份(英文)
  6. System.out.println(ldt.getMonthValue());//输出月份(阿拉伯数字)
  7. System.out.println(ldt.getHour()); // 输出小时(当然还能得到分和秒)
  8. ...

2. LocalDate类,只能获取年月日。LocalTime类,只能获取时分秒。

  1. LocalDate now = LocalDate.now(); //用于获取年月日
  2. LocalTime now2 = LocalTime.now();//用于获取时分秒

3. DateTimeFormatter格式日期类
image.pngimage.png

  1. public class Test{
  2. public static void main(String[] args) {
  3. LocalDateTime ldt = LocalDateTime.now();
  4. DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH小时mm分钟ss秒");
  5. //这里yyyy等不区分大小写,但必须是这个字母。
  6. DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-mm-dd HH:mm:ss");
  7. //字母对应时间,剩下的可以自己定义格式
  8. String strDate1 = dtf1.format(ldt); //调用format方法,LocalDateTime类为参数
  9. String strDate2 = dtf2.format(ldt);
  10. System.out.println(strDate1);
  11. System.out.println(strDate2);
  12. }
  13. }

4. 时间戳
1) 通过静态方法获取对象

  1. Instant now = Instant.now();
  2. //用静态方法 now 获取表示当前时间戳的对象
  3. //Instant now = new Instant(); 错误
  4. System.out.println(now); // 2021-10-03T14:36:07.540Z

2) 通过 Date类的from静态方法 可以把 Instant类转成 Date类

  1. Date date = Date.from(now);
  2. System.out.println(date.getTime());

3) 通过 Date对象的toInstant方法可以把 date类 转换成 Instant类

  1. Instant instant = date.toInstant();

5. plus和minus
所有第三代日期类都可以使用,通过提供 plus 和 minus方法可以对当前时间进行加或减,注意不对原对象进行操作,而是返回一个经过操作之后的对象。
image.pngimage.png