Java11常用类1:Object类、String类及相关、Date类

Java11常用类1:目录

  • 1. Object类
    • 1.1 getClass()
    • 1.2 hashcode()
    • 1.3 equals()
      • 1.3.1 == 和 equals 的区别
      • 1.3.2 hashCode()与equals()的相关规定
    • 1.4 toString()
    • 1.5 Object转换为int类型
    • 1.6 String转换为int类型
  • 2.String类
    • 2.1 String类的理解
      • 2.1.1. 类的声明
      • 2.1.2. 内部声明的属性
    • 2.2 String的内存结构
      • 2.2.1 不可变性的理解
      • 2.2.2 String的2种实例化方式
      • 2.2.3 String的连接操作
    • 2.3 `String的常用API_1`
      • 2.3.1 String类构造器
      • 2.3.2 String与常见的其他结构之间的转换
        • 1. String和基本数据类型、包装类之间的转换:
        • 2. String和 char[] 之间的转换:
        • 3. String和 byte[] 之间的转换:
      • 2.3.3 练习一:反转String
      • 2.3.4 练习二:获取String出现的次数
    • 2.4 `String的常用API_2`
      • 2.4.1 常用方法
      • 2.4.2 查找字符串
      • 2.4.3 截取字符串
      • 2.4.4 字符/字符数组相关
      • 2.4.5 开头和结尾
      • 2.4.7 String在内存中的地址和指向
  • 3.StringBuffer、StringBuilder
    • 3.1 String/StringBuffer/StringBuilder区别:
    • 3.2 String、StringBuffer、StringBuilder
      • 3.2.1 String、StringBuffer、StringBuilder底层
      • 3.2.2 String、StringBuilder源码分析
      • 3.2.3 AbstractStringBuilder扩容机制
      • 3.2.4 源码启示
    • 3.3 StringBuilder常用方法:
    • 3.4 其他 API
    • 3.5 三者效率比较
    • 3.6 Interview 面试:地址指向问题
      • 3.6.1 问题一:StringBuffer地址指向问题
      • 3.6.2 问题二:String、StringBuffer地址传递问题
      • 3.6.3 问题三:String、StringBuffer地址指向问题
      • 3.6.4 问题四:null的问题
  • 4. Date类1:jdk1.8 之前
    • 4.1 两个Date类
    • 4.2 SimpeDateFormat
      • 4.2.1 日期和时间模式
      • 4.2.2 日期 字母含义
    • 4.3 `java.util.Calender` 日历类(建议使用)
      • 4.3.1 获取实例和常用方法
      • 4.3.2 常量含义意义
      • 4.3.3 练习:util.Date ->sql.Date
      • 4.3.4 日期字符串 保存到数据库
    • 4.4 Jdk1.8的日期类
      • 4.4.1 LocalDate、LocalTime、LocalDateTime
      • 4.4.2 Instant:瞬时;类似Date
      • 4.4.3 DateTimeFormatter
      • 4.4.4 其他API
        • 4.1 ZoneId、ZonedDateTime(了解)
        • 4.2 持续日期/时间:Period和 Duration(了解)
        • 4.3 Clock(了解)
        • 4.4 TemporalAdjuster时间校正器
      • 4.4.5 与传统日期处理的转换
      • 4.4.6 练习题:获取百天日期
    • 4.5 日期互转
      • 4.5.1 long与Date、Calendar
      • 4.5.2 Date与Calendar互转
      • 4.5.3 Date与String互转
      • 4.5.4 Calendar与String互转

1. Object类

添加链接描述

由官方介绍可见,Object属于Java.lang包内的一个类,而且提供了很多种方法, Object 是类层次结构的根类。每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。 简单的说 Object类就是所有类的父类,包括我们所写的类,我们在使用类的时候就会利用 Object类中的方法,因为所有的父类都自动的继承了这个类,所以我们在日常学习和开发中见不到 Object这个类。子类拥有 Object类的所有方法,并且可以对这些方法进行重写,满足我们的业务需求。

1.1 getClass()

返回此 Object 运行时的类,获取对象的真实类的全名称。比如:在使用多态时,父类引用变量,使用getClass()方法就可以看到真实的类:

应用场景:

  1. 查看当前使用该方法的对象,到底是哪个类;
  2. 在使用多态时,当代码多的时候使用 getClass()方法可以方便、快捷的知道 指向的是哪个子类。
package com.lCommonClasses.obj;
public class Object1 {
   
    public void eat(){
   
        System.out.println("吃");
    }
}
class Test{
   
    public static void main(String[] args) {
   
        Object1 obj1 = new HashTest();//使用多态
        Object1 obj2 = new Object1();
        obj1.eat(); //子类重写了父类的eat(),使用的是子类的方法
        
        /**1.getClass():查看obj1归属于哪个 class*/
        //结果:class com.lClass.HashTest
        System.out.println(obj1.getClass());
        //结果:class com.lClass.Object1
        System.out.println(obj2.getClass());
    }
}
package com.lCommonClasses.obj;

public class HashTest extends Object1{
   
    @Override
    public void eat() {
   
        System.out.println("吃水果");
    }
}

1.2 hashcode()

作用是获取哈希码,也称为散列码;它实际上是返回一个int整 数。这个哈希码的作用是
确定该对象在哈希表中的索引位置。

package com.lCommonClasses.obj;
public class Object1 {
   
    public static void main(String[] args) {
   
        HashTest hash1 = new HashTest(8);
        HashTest hash2 = new HashTest(8);

        /**1.调用hashCode()方法:
         * 460141958:这个数也就是哈希码,也称为散列码,
         * 作用:是确定该对象在哈希表中的索引位置*/
        System.out.println(hash1.hashCode());
    }
}

1.3 equals()

package com.lCommonClasses.obj;
public class Object1 {
   
    public static void main(String[] args) {
   
        HashTest hash1 = new HashTest(8);
        HashTest hash2 = new HashTest(8);
        /**2.调用equals()方法:
         * 没有重写equals方法前为false;重写之后为true*/
        System.out.println(hash1.equals(hash2));
    }
}

源码很简单,不就是两个==号,但是我们知道类的引用类型的数据,而用两个等于号去判断两个引用类型,是去判断两者的内存地址是否相同,当一个类去new一个新对象时,是在堆内存内开辟了一个新的空间;创建两个或者多个类的时候,每个类肯定有属于自己的空间,所有也有一个独一无二的地址,这就是为什么这个判断为什么不成立的原因。
但是比较对象的引用对于我们在实际开发中没有意义,我们一般还是要重写该方法,比如去判断两者的参数是否相等:

package com.lClass;
public class HashTest {
   
    private int age;

    public HashTest() {
   }
    public HashTest(int age) {
   this.age = age;}
    public int getAge() {
   return age;}
    public void setAge(int age) {
   this.age = age;}

    /*重写equals方法,只要HashTest生成的对象,
    传入age参数相等,即可判断两者一致重写后的equals,
    就不再是去判断两者的地址是否相同*/
    @Override
    public boolean equals(Object obj) {
   
        HashTest h = (HashTest) obj;    //多态
        if(this.age == h.getAge()) {
   
            return true;
        }
        return false;
    }
}

1.3.1 == 和 equals 的区别

1)== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同 一个对象。

  • (基本数据类型== 比较的是值,引用数据类型 == 比较的是内存地址)

2)equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:

  1. 若该类没有重写equals() 方法。当通过 equals() 比较该类的两个对象时, 等价于通过“==”比较这两个对象。
  2. 若该类重写了 equals() 方法。一般,我们都覆盖 equals() 方法 将两个对象 的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)

1.3.2 hashCode()与equals()的相关规定

如果两个对象相等,则hashcode一定也是相同的 两个对象相等,对两个对象分别调用equals方法都返回true, 两个对象有相同的hashcode值,它们也不一定是相等的。因此,equals 方法被重写过,则 hashCode 方法也必须被重写,hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象 指向相同的数据)

1.4 toString()

返回一个字符串来标识当前对象,就是 类名+符号@+对象的哈希码值

class Test{
   
    public static void main(String[] args) {
   
		Object1 obj1 = new HashTest();//使用多态
        Object1 obj2 = new Object1();
/**4.toString():但是这个返回值视乎没什么意义,
         * 所以为了返回值有更多的意义,我们可以重写这个方法*/
        System.out.println(obj1);
        System.out.println(obj1.toString());
        System.out.println(obj2.toString());
	}
}

其他方法
clone()
notify()
wait()

1.5 Object转换为int类型

class Test{
   
    public static void main(String[] args) {
   
        /**5.将Object类型转换为int类型*/
        Object obj = "-416464";
        try{
   
            Integer.parseInt(obj.toString());
        } catch (NumberFormatException e) {
   
            System.out.println("输入不是 int类型");
        }finally {
   
            System.out.println("obj="+obj);
        }
    }
}

1.6 String转换为int类型

class Test{
   
    public static void main(String[] args) {
   
		/**6.将String类型转换为int类型
		两个结果不同:false;true;
		底层是:-128 ~ 127时,两者相同,超出范围后就不同*/
        String str= "129";
        System.out.println(Integer.valueOf(str) == Integer.valueOf("129"));
        //当数值超出范围后,用`equals()方法`
        if (Integer.valueOf(str).equals(Integer.valueOf("129"))){
   
            System.out.println("true");
        }else{
   
            System.out.println("false");
        }
    }
}

2.String类

特点不可变性 final-操作量较少
String类、StringBuilder类、StringBuffer类是三个字符串相关类。String类的对象代表不可变的字符序列,StringBuilder类和StringBuffer类代表可变字符序列

2.1 String类的理解

2.1.1. 类的声明

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
   }

final:String类是不可以被继承的
Serializable:可序列化接口。凡是实现此接口的对象就可以通过网络 或本地流进行数据的传输;
Comparable:凡是实现此接口的类,其对象都可以比较大小。

2.1.2. 内部声明的属性

/**Jdk1.8中:
1.存储字符串数据的容器
2.final:指明此 value数组一旦初始化,其地址就不可变。 */
private final char value[];

/**Jdk1.9开始:为了节省内部空间
1.存储字符串数据的容器 */
private final byte value[];	

2.2 String的内存结构

字符串常量都存储在字符串常量池(StringTable)中;
字符串常量池:不允许存放两个相同的字符串常量
字符串常量池:在不同 Jdk 版本中存储位置不同:
(1)jdk1.7之前: 字符串常量池存放在方法区(jdk1.8称其为元空间
(2)jdk1.7之后(包括jdk1.7):存放在空间

2.2.1 不可变性的理解

package com.kString;
import org.junit.Test;
public class String0 {
   
    @Test
    public void test1() {
   
        String str1 = "hello";//字面量的定义
        String str2 = "hello";
        //字面量相同时使用同一个对象,即引用的地址相同
        System.out.println(str1 == str2);//true
    }

    @Test
    public void test2() {
   
        /**
         * String的不可变性
         * ①当对字符串变量重新赋值时,需要重新指定一个字符串常量的
         * 位置进行赋值,不能在原有的位置修改;
         */
        String str1 = "hello";
        String str2 = "hello";

        str2 = "hi";
        System.out.println(str1);//hello
        System.out.println(str2);//hi
    }

    @Test
    public void test3() {
   
        /**
         * String的不可变性;
         * ②在对现有字符串进行拼接操作时,需要重新开辟空间保存拼接
         * 以后的字符串,不能在原有的位置修改;
         */
        String str1 = "hello";
        String str2 = "hello";

        /* 在`堆`中开辟了一处新空间,str2指向这个新空间
        String str2 = new String();
        str2 = str2 + " hi";
         */
        str2 += " hi";
        System.out.println(str1);//hello
        System.out.println(str2);//hello hi
    }

    @Test
    public void test4() {
   
        String str1 = "hello";
        String str2 = "hello";
/**
 * String的不可变性;
 * ③当调用字符串的 replace()替换现有的字符时,需要重新开辟空间后,
 * 保存修改后的字符串,不能在原有的位置修改;
 */
        /* 取代:replace(char oldChar, char newChar)
        返回的是一个新的 字符串*/
        String str3 = str2.replace('l', 'o');
        System.out.println(str1);//hello
        System.out.println(str2);//hello
        System.out.println(str3);//heooo
    }
}

不可变性练习

    String str="good";
    char[] ch = {
   't','e','s','t'};
    //传参时:基本数据类型传的是值,引用数据类型传的是地址
    public void change(String str, char[] ch){
   
        //这里是 new了一个对象用来存储改变后的值
        str="test ok";
        System.out.println(str);//test ok
        ch[0]='b';
    }
    @Test
    public void test10(){
   
        String0 s0 = new String0();
        s0.change(s0.str,s0.ch);
        System.out.println(s0.str);//good
        System.out.println(s0.ch);//best
    }

2.2.2 String的2种实例化方式

String实例化的两种方式:
(1) String str1 = “hello”;
(2) String str2 = new String(“hello”);

package com.kString;
import org.junit.Test;
public class String0 {
   
    @Test
    public void test5() {
   
        String str1 = "hello";
        String str2 = "hello";
        String s1 = new String("hello");
        String s2 = new String("hello");

        //==:比较对象时是地址; equals比较的是内容
        System.out.println(str1 == str2);//true
        System.out.println(str1 == s1);//false
        System.out.println(s1 == s2);//false
        System.out.println(str1.equals(s1));//true
        System.out.println(s1.equals(s2));//true
    }
}

思考:String s1 = new String(“hello”);在内存中创建了几个对象?
两个对象:①在堆空间 new的对象;②在字符串常量池中生成的字面量

package com.kString;

import org.junit.Test;

public class String0 {
   
    @Test
    public void test6() {
   
        Person p1 = new Person();
        Person p2 = new Person();
        
        /*
        ①p1 和 p2 在堆中的地址不同,在常量池中指向的值都是 Tom
        ②常量池添加新的字面量 Jerry;
        ③将 p1指向的地址变为 Jerry的地址
         */
        p1.name= "Tom";
        p2.name= "Tom";
        p1.name= "Jerry";
        System.out.println(p1.name);//Jerry
        System.out.println(p2.name);//Tom
    }
}
class Person{
   
    String name;
}

2.2.3 String的连接操作

  1. 常量 + 常量:结果仍存储在字符串常量池中,返回此字面量的地址。注:此时的常量可能是字面量,也可能是final修饰的常量;
  2. 常量 + 变量 变量 + 常量:都会通过 new的方式创建一个新的字符串,返回的是堆空间中此字符串对象的地址,和concat(String otherString)一样创建新的对象;
  3. 调用String.intern():返回的是字符串在常量池中字面量的地址,而不是对象的地址。
package com.kString;
import org.junit.Test;
/**情况Ⅰ~Ⅲ */
public class String0 {
   
    @Test
    public void test7() {
   
        String s1 = "Hello";
        String s2 = "World";

        String s3 = "HelloWorld";
        String s4 = "Hello" + "World";
        /*底层new 了一个StringBuilder调用了调用了它的
         toString() 方法,就是在该方法中 new 了一个新对象*/
        String s5 = s1 + "World";
        String s6 = "Hello" + s2;//
        String s7 = s1   + s2;

        System.out.println(s3 == s4);//true
        System.out.println(s3 == s5);//false
        System.out.println(s3 == s6);//false
        System.out.println(s3 == s7);//false
        System.out.println(s5 == s6);//false
        System.out.println(s5 == s7);//false
        System.out.println(s6 == s7);//false

        /*返回的是字符串在常量池中字面量的地址,
        而不是对象的地址。*/
        String s8=s5.intern();
        System.out.println(s4 == s8);//true
    }

	@Test
    public void test8() {
   
        final String s1 = "Hello";
        final String s2 = 

你可能感兴趣的:(Java,java)