文章目录

  • 1.String类:字符串常量在Java中不属于基本数据类型, 而是引用/类类型
    • 1.1 使用:new String(...)
    • 1.2 判断:equals函数是用来比较两个对象是否相等
    • 1.3 比较:able to重要,or e
    • 1.4 获取:.charAt,.indexOf
    • 1.5 转换:.toCharArray,.getBytes,.replace
    • 1.6 分割:.split
    • 1.7 模拟用户登录:.nextLine,.equals
    • 1.8 遍历字符串:.charAt
    • 1.9 统计字符个数:&&
    • 1.10 字符串拼接:+
    • 1.11 字符串反转:i- -
    • 1.12 空字符串判断:.intern()
  • 2.StringBuilder类:线程不安全但速度快于stringbuffer(线程安全即每个方法上都加synchronized,效率低,抛弃)
    • 2.1 构造方法:new StringBuilder(" ")
    • 2.2 append方法:StringBuilder已经覆盖重写了Object当中的toString方法
    • 2.3 toString方法:StringBuilder对象将会转换为不可变的String对象
    • 2.4 reverse方法:.reverse()
    • 2.5 StringBuilder和String相互转换:toString()
    • 2.6 字符串拼接:定义一个方法将int[] arr = {1,2,3}输出为:[1, 2, 3]
    • 2.7 字符串反转:返回值类型:String , 参数:String s
  • 3.ArrayList类:ArrayList list = new ArrayList()
    • 3.1 引入—对象数组:基本数据类型变量只保存基本数据类型,不能保存对象。引用数据类型变量是可保存对象,但只能保存一个对象
    • 3.2 集合与数组区别:变,只对,不
    • 3.3 ArrayList类使用:public ArrayList() 构造一个内容为空的集合
    • 3.4 常用方法和遍历:对于元素的操作:增、删、查
  • 4.Object类:对象都需重写
    • 4.1 toString方法:Object中的tostring方法: 对象类型包名类名 + 内存地址
    • 4.2 equals方法:Object类中的equals方法是==比较内存地址
    • 4.3 hashCode方法和equals方法:两个对象hashCode方法返回值相同,那么这两个是否equals?或者两个对象equals,那么hashCode方法返回值是否相同?
      • 4.3.1 为什么要有如上这样的规范?牵扯到一系列hash存储
      • 4.3.2 hashCode扩展:重写hashcode方法不会在对象头中进行存储,对象头中31bit永远是0

1.String类:字符串常量在Java中不属于基本数据类型, 而是引用/类类型

Java中使用String这个类描述字符串这种常量数据,java.lang.String 类代表字符串。Java程序中所有的字符串文字(例如"abc" )都可以被看作是实现此类的实例。

1.字符串常量:它属于对象,但是它不是像之前的对象通过new的方式在中开辟空间,而是存储在字符串常量池中。说明:jdk1.7之前字符串常量池是位于方法区中的,而jdk1.7之后是位于中的。

位于堆中和之前new空间不冲突,常量池是一个单独的空间。字符串常量池中保存的就是所有的字符串数据。只要书写了双引号,不管双引号中间是什么数据,这些数据都会立刻在字符串常量池中保存,并且一直存在,不会被改变。所有在Java程序中使用双引号引用起来的数据都是一个对象。

2.字符串不变:字符串的值在创建后不能被更改。String类中描述的是所有字符串常量,一旦书写完成,它就是一个固定值,这个数据不能改变。

String s3="def";
s3="efg";
System.out.println(s3);
// 内存中有"def","efg"两个对象,s3从指向"def",改变指向,指向了"efg"。

String对象是不可变的,所以它们可以被共享。

String s1="abc"; //定义字符串对象
//int i=3;在栈中开辟空间名称叫做i,存值为3
String s2="abc";
//System.out.println(s1); //abc  //打印的不是内存地址名,是abc常量的值
System.out.println(s1==s2);//这里比较的是内存地址名是否相等 //true

如下string str 是方法中引用类型的局部变量,所以在左边栈中。

如下main中第一行,JVM会在内部的String pool中查找有没有字符串常量"hello",没有的话创建"hello"对象。

第二行JVM在String pool中查找,有则返回"hello"的地址,这里虽然没创建对象,但str1并不等于str2,因为引用的地址不一样(str1指向堆内存地址,str2指向字符串池地址)

第三行JVM同样在String pool中查找,有字符串常量"hello"则不再创建。由于使用了new,JVM又在堆中创建一个"hello"对象。

1.1 使用:new String(…)

构造方法:用双引号本身就可得到一个字符串对象。String类提供了大量的构造函数,目的是可以帮助我们将其他的数据变成字符串对象。只要使用String类的构造函数创建的对象,那么这个对象就会在中出现。而在创建出的字符串对象中的字符数据保存在常量池

// 无参构造  // java.lang.String
String str = new String();//构造函数// 通过字符数组构造,将参数的字符数组转换为String类的对象
char chars[] = {'a', 'b', 'c'};
String str2 = new String(chars);// 通过字节数组构造,将参数的字节数组转换为String类的对象
byte bytes[] = { 97, 98, 99 };
String str3 = new String(bytes);

1.2 判断:equals函数是用来比较两个对象是否相等

public class String_Demo01 {public static void main(String[] args) {// 创建字符串对象String s1 = "hello";String s2 = "hello";String s3 = "HELLO";// boolean equals(Object obj):比较字符串的内容是否相同System.out.println(s1.equals(s2)); // trueSystem.out.println(s1.equals(s3)); // false//boolean equalsIgnoreCase(String str):比较字符串的内容是否相同,忽略大小写System.out.println(s1.equalsIgnoreCase(s2)); // trueSystem.out.println(s1.equalsIgnoreCase(s3)); // true}
}

如果想比较两个字符串相等,我们不应该使用 == (恒等符号),因为 == 是用来比较具体常量数值的。而由于字符串是对象,所以我们应该使用String类中的equals函数对两个字符串进行比较。

1.3 比较:able to重要,or e

package com.atguigu.test05;
/** java.util.Comparator:定制比较,定制顺序,是对自然比较的补充*      int compare(Object o1, Object o2)://接口的抽象方法(要重写)*                o1与o2比较,o1>o2,返回正整数*               o1与o2比较,o1<o2,返回负整数*               o1与o2比较,o1=o2,返回0* java.lang.Comparable:自然比较,自然顺序,核心默认不用导包。*        int compareTo(Object obj)  // 接口的抽象方法(要重写)*                 this与obj对象比较,this > obj,返回正整数*                 this与obj对象比较,this < obj,返回负整数*                 this与obj对象比较,this = obj,返回0*/
public class TestComparable {public static void main(String[] args) {Student s1 = new Student("杨洪强", 24, 89);Student s2 = new Student("苏海波", 23, 100);        //按成绩比较,不用第三个对象了if(s1.compareTo(s2)>0){System.out.println("s1 > s2成绩");}else if(s1.compareTo(s2)<0){System.out.println("s1 < s2成绩");}else{System.out.println("s1 = s2成绩");}       }
}
class Student implements Comparable{  //希望学生对象本身就具备比较大小的能力。private String name;private int age;private int score;public Student(String name, int age, int score) {super();this.name = name;this.age = age;this.score = score;}public Student() {super();}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 int getScore() {return score;}public void setScore(int score) {this.score = score;}@Overridepublic String toString() {return "Student [name=" + name + ", age=" + age + ", score=" + score + "]";}@Overridepublic int compareTo(Object obj) {  Student other = (Student) obj; //this与obj比较,this和obj都是学生对象//例如:对于学生对象来说,最常用的是按成绩排名,那么我就可以把自然顺序定位成绩升序/* if(this.score > other.score){return 1;}else if(this.score < other.score){return -1;}return 0;*/       return this.score - other.score;}
}

package com.atguigu.test05;
import java.util.Arrays;
/** Arrays的sort方法有两种:(1)void sort(Object[] arr):* 根据元素的 自然顺序 对指定对象数组按升序进行排序。数组中的所有元素都必须实现 Comparable 接口* (2)void sort(Object[] arr, Comparator c):* 根据“指定比较器”产生的顺序对指定对象数组进行排序。数组中的所有元素都必须是通过“指定比较器”可相互比较*/
public class TestArrays {public static void main(String[] args) {Student[] all = new Student[5];all[0] = new Student("杨洪强", 24, 89);all[1] = new Student("苏海波", 23, 100);all[2] = new Student("张三",23,88);all[3] = new Student("李四",24,44);all[4] = new Student("王五",25,45);        //如果我们的学生类Student,实现了java.lang.Comparable接口,//能不能按照自然排序的规则进行排序呢?//Arrays中有这样的方法:public static void sort(Object[] a)        Arrays.sort(all);//这里面排序过程中,调用了元素本身的compareTo()方法for (int i = 0; i < all.length; i++) {System.out.println(all[i]);}}
}

如下按成绩升序,因为Student类本身实现了Comparable接口重写了compareTo方法。


如上结果为:[Alice,chai,hello,Hi,Java]

1.4 获取:.charAt,.indexOf

package com.itheima.demo01;
import java.lang.String;public class HelloWorld {public static void main(String[] args) {// String concat (String str):将指定的字符串连接到该字符串的末尾.String s = "helloworld";String s2 = s.concat("**hello itheima");System.out.println(s2);// helloworld**hello itheima// char charAt(int index):获取指定索引处的字符System.out.println(s.charAt(0)); // hSystem.out.println(s.charAt(1)); // e// int indexOf(String str):获取str在字符串对象中第一次出现的索引,没有返回-1System.out.println(s.indexOf("l")); //2System.out.println(s.indexOf("owo")); //4System.out.println(s.indexOf("ak")); //-1// String substring(int start):从start开始截取字符串到字符串结尾System.out.println(s.substring(0)); // helloworldSystem.out.println(s.substring(5)); // world// String substring(int start,int end):从start到end截取字符串。含start,不含end。System.out.println(s.substring(0, s.length())); // helloworldSystem.out.println(s.substring(3,8)); // lowor,不含8即l}
}

1.5 转换:.toCharArray,.getBytes,.replace

package com.itheima.demo01;
import java.lang.String;class String_Demo03 {public static void main(String[] args) {String s = "abcde";char[] chs = s.toCharArray(); // 把字符串转换为字符数组for(int x = 0; x < chs.length; x++) {System.out.println(chs[x]);  // a b c d e}byte[] bytes = s.getBytes(); //把字符串转换为字节数组for(int x = 0; x < bytes.length; x++) {System.out.println(bytes[x]); // 97 98 99 100 101}String str = "itcast itheima";String replace = str.replace("it", "IT");System.out.println(replace); // ITcast ITheima}
}

1.6 分割:.split

public class String_Demo03 {public static void main(String[] args) {String s = "aa,bb,cc";String[] strArray = s.split(","); // ["aa","bb","cc"],字符串对象拆为字符串数组for(int x = 0; x < strArray.length; x++) {System.out.println(strArray[x]); // aa bb cc}}
}

1.7 模拟用户登录:.nextLine,.equals

package com.itheima.demo01;
import java.util.Scanner;
// 需求:已知用户名和密码,用程序实现模拟用户登录,一共给3次机会,登陆后给出相应提示。
class StringTest01 {public static void main(String[] args) {//已知用户名和密码,定义两个字符串表示即可String username = "itheima";String password = "czbk";//用循环实现多次机会,这里的次数明确,采用for循环实现,并在登录成功的时候,使用break结束循环for(int i=0; i<3; i++) {//键盘录入要登录的用户名和密码,用 Scanner 实现Scanner sc = new Scanner(System.in);System.out.println("请输入用户名:");String name = sc.nextLine();System.out.println("请输入密码:");String pwd = sc.nextLine();//拿键盘录入的用户名、密码和已知的用户名、密码进行比较,给出相应的提示。字符串的内容比较,用equals() 方法实现if (name.equals(username) && pwd.equals(password)) {System.out.println("登录成功");break;} else {if(2-i == 0) {System.out.println("你的账户被锁定,请与管理员联系");} else {//2,1,0//i为0,1,2System.out.println("登录失败,你还有" + (2 - i) + "次机会");}}}}
}

class CodeDemo {public static void main(String[] args) throws IOException {String username = "ta";String password = "123";Scanner sc = new Scanner(System.in);System.out.println("请输入用户名:");String name = sc.nextLine();        if(name.length() == 0){System.out.println("登录失败");return;}System.out.println("请输入密码:");String pwd = sc.nextLine();        if(pwd.length() == 0){System.out.println("登录失败");}if (name.equals(username) && pwd.equals(password)){System.out.println("登录成功");} else {System.out.println("登录失败");}
}}

1.8 遍历字符串:.charAt

public class StringTest02 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);System.out.println("请输入一个字符串:");String line = sc.nextLine();     for(int i=0; i<line.length(); i++) {System.out.println(line.charAt(i)); //空字符也遍历}}
}

1.9 统计字符个数:&&

public class StringTest2 {public static void main(String[] args) {//键盘录入一个字符串数据,统计字符串大小写字母及数字字符个数Scanner sc = new Scanner(System.in);System.out.println("请输入一个字符串数据:");String s = sc.nextLine();//定义三个统计变量,初始化值都是0int bigCount = 0;int smallCount = 0;int numberCount = 0;//遍历字符串,得到每一个字符for(int x=0; x<s.length(); x++) {char ch = s.charAt(x);//拿字符进行判断if(ch>='A'&&ch<='Z') {bigCount++;}else if(ch>='a'&&ch<='z') {smallCount++;}else if(ch>='0'&&ch<='9') {numberCount++;}else {System.out.println("该字符"+ch+"非法");}}System.out.println("大写字符:"+bigCount+"个");System.out.println("小写字符:"+smallCount+"个");System.out.println("数字字符:"+numberCount+"个");}
}

1.10 字符串拼接:+

public class StringTest1 {public static void main(String[] args) {int[] arr = {1, 2, 3};String s = arrayToString(arr);System.out.println("s:" + s); //s:[1#2#3]}/** 写方法实现把数组中的元素按照指定的格式拼接成一个字符串* 两个明确:返回值类型:String。 参数列表:int[] arr*/public static String arrayToString(int[] arr) {//String s = new String("[");String s="[";// 遍历数组,并拼接字符串for (int x = 0; x < arr.length; x++) {if (x == arr.length - 1) {s = s+arr[x]+"]";} else {s = s+arr[x]+"#";}}return s;}
}

1.11 字符串反转:i- -

public class StringTest05 {public static void main(String[] args) {//键盘录入一个字符串,用 Scanner 实现Scanner sc = new Scanner(System.in);System.out.println("请输入一个字符串:");String line = sc.nextLine();String s = reverse(line); //调用方法,用一个变量接收结果System.out.println("s:" + s); //输出结果}// 两个明确:返回值类型:String。参数:String s  public static String reverse(String s) {//在方法中把字符串倒着遍历,然后把每一个得到的字符拼接成一个字符串并返回String ss = "";for(int i=s.length()-1; i>=0; i--) {ss += s.charAt(i);}return ss;}
}

1.12 空字符串判断:.intern()

/** (1)常量 + 常量 在常量池* (2)变量 +常量 在堆* (3)变量 + 变量 在堆* (4)xx.intern():在常量池* * 空字符串:(1)""*          (2)new String()*            (3)new String("")* * 四种判空方式:(1)if(str != null && str.length() == 0)*                (2)if(str != null && str.equals("")){*                 (3)if("".equals(str))  推荐*              (4)if(str!=null && str.isEmpty())* /

2.StringBuilder类:线程不安全但速度快于stringbuffer(线程安全即每个方法上都加synchronized,效率低,抛弃)

StringBuilder又称为可变字符序列,它是一个类似于 String 的字符串缓冲区,通过某些方法调用可以改变该序列的长度和内容。String类(内容是不可变的),StringBuilder类(内容和长度是可变的,将任意数据都转成字符串进行存储)。

StringBuilder和数组最大的不同就是数组存储完可以单独操作每一个元素,每一个元素都是独立的。字符串缓冲区,所有存储的元素都会被转成字符串,而且变成了一个更长的字符串。

2.1 构造方法:new StringBuilder(" ")

public class StringBuilderDemo {public static void main(String[] args) {StringBuilder sb1 = new StringBuilder();System.out.println(sb1); // (空白)//使用带参构造 public StringBuilder(String str)StringBuilder sb2 = new StringBuilder("itcast");System.out.println(sb2); // itcast}
}

2.2 append方法:StringBuilder已经覆盖重写了Object当中的toString方法

append方法具有多种重载形式,可以接收任意类型的参数。任何数据作为参数都会将对应的字符串内容添加到StringBuilder中。

public class Demo02StringBuilder {public static void main(String[] args) {StringBuilder builder = new StringBuilder(); //创建对象StringBuilder builder2 = builder.append("hello");System.out.println("builder:"+builder);  //builder:helloSystem.out.println("builder2:"+builder2); //builder2:helloSystem.out.println(builder == builder2); //true// 可以添加 任何类型builder.append("hello");builder.append("world");builder.append(true);builder.append(100);// 在我们开发中,会遇到调用一个方法后,返回一个对象的情况。然后使用返回的对象继续调用方法。// 这种时候,我们就可以把代码现在一起,如append方法一样,代码如下builder.append("hello").append("world").append(true).append(100); //链式编程System.out.println("builder:"+builder); //builder:hellohelloworldtrue100helloworldtrue100}
}

2.3 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}
}

2.4 reverse方法:.reverse()

public class Demo16StringBuilder {public static void main(String[] args) { //public StringBuilder reverse():返回相反的字符序列StringBuilder sb = new StringBuilder("Hello").append("World").append("Java");sb.reverse();System.out.println("sb:" + sb); //sb:avaJdlroWolleH}
}

2.5 StringBuilder和String相互转换:toString()

public class StringBuilderDemo02 {public static void main(String[] args) {        //111111111111111111111StringBuilder转换为StringStringBuilder sb = new StringBuilder();sb.append("hello");//String s = sb; //这个是错误的做法        String s = sb.toString(); System.out.println(s); //hello//111111111111111111String转换为StringBuilderString s = "hello";//StringBuilder sb = s; //这个是错误的做法StringBuilder sb = new StringBuilder(s);//public StringBuilder(String s):通过构造方法就可以实现把 String 转换为 StringBuilderSystem.out.println(sb); //hello}
}

2.6 字符串拼接:定义一个方法将int[] arr = {1,2,3}输出为:[1, 2, 3]

/*1:定义一个 int 类型的数组,用静态初始化完成数组元素的初始化2:定义一个方法,用于把 int 数组中的数据按照指定格式拼接成一个字符串返回。返回值类型 String,参数列表 int[] arr3:在方法中用 StringBuilder 按照要求进行拼接,并把结果转成 String 返回4:调用方法,用一个变量接收结果5:输出结果*/
public class StringBuilderTest01 {public static void main(String[] args) {        int[] arr = {1, 2, 3};//定义一个 int 类型的数组,用静态初始化完成数组元素的初始化System.out.println(arr); //[I@14ae5a5String s = arrayToString(arr);System.out.println("s:" + s); //s:[1, 2, 3]}// 两个明确:返回值类型:String   参数:int[] arrpublic static String arrayToString(int[] arr) {//在方法中用 StringBuilder 按照要求进行拼接,并把结果转成 String 返回StringBuilder sb = new StringBuilder();sb.append("[");for(int i=0; i<arr.length; i++) {if(i == arr.length-1) {sb.append(arr[i]);} else {sb.append(arr[i]).append(", ");}}sb.append("]");String s = sb.toString();return  s;}
}

2.7 字符串反转:返回值类型:String , 参数:String s

public class StringBuilderTest02 {public static void main(String[] args) {        Scanner sc = new Scanner(System.in);  System.out.println("请输入一个字符串:");String line = sc.nextLine();String s = myReverse(line);System.out.println("s:" + s);}public static String myReverse(String s) {//在方法中用StringBuilder实现字符串的反转,并把结果转成String返回//String --- StringBuilder --- reverse() --- String
//        StringBuilder sb = new StringBuilder(s);
//        sb.reverse();
//        String ss = sb.toString();
//        return ss;return new StringBuilder(s).reverse().toString();}
}

3.ArrayList类:ArrayList list = new ArrayList()

3.1 引入—对象数组:基本数据类型变量只保存基本数据类型,不能保存对象。引用数据类型变量是可保存对象,但只能保存一个对象

package cn.itcast.sh.demo;public class Student {String name;int age; public Student(String name, int age) { //定义构造函数给属性初始化值this.name = name;this.age = age;}   public String getName() { //给属性生成get和set方法return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
package cn.itcast.sh.demo;public class ArrayDemo {public static void main(String[] args) {       Student[] arr=new Student[3]; //创建Student类型的数组     Student s1=new Student("heixuanfeng",19); //创建Student类的对象Student s2=new Student("bandao",18);Student s3=new Student("zhujiao",20);     arr[0]=s1; //将学生对象存储到数组中arr[1]=s2;arr[2]=s3;for (int i = 0; i < arr.length; i++) {         Student s=arr[i]; //通过数组名和下标取出Student类的数组中的数据 arr[i]System.out.println(s.getName()+"====="+s.getAge());}}
}

目前只学习了2种存储数据的容器:变量 、数组集合容器可解决上面用数组重复代码太多。

3.2 集合与数组区别:变,只对,不

1)长度
数组:需要固定长度。
集合:长度可以改变,可以根据保存的数据进行扩容。
2)存储内容
数组:可以存储基本类型数据,还可以存储引用类型的数据。
集合:只能存储引用类型的数据,也就是说集合只能存储类的对象。
3)存储类型
数组:只能存储相同类型的数据。
集合:可以存储不同类型的数据。

3.3 ArrayList类使用:public ArrayList() 构造一个内容为空的集合

java.util.ArrayList <E><E> 表示一种指定的数据类型,叫做泛型。E 取自Element(元素)的首字母。在出现E 的地方,我们使用一种引用数据类型将其替换即可,表示我们将存储哪种引用类型的元素。

ArrayList<String>,ArrayList<Student>

JDK 7后,右侧泛型的尖括号之内可以留空,但是<>仍然要写。简化格式:

ArrayList<String> list = new ArrayList<>();

成员方法: public boolean add(E e) : 将指定的元素添加到此集合的尾部。参数 E e ,在构造ArrayList对象时,<E>指定了什么数据类型,那么add(E e)方法中只能添加什么数据类型的对象。

//需求:使用ArrayList类,存储三个字符串元素
public class Test02StudentArrayList {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>(); //创建集合对象String s1 = "曹操";String s2 = "刘备";String s3 = "孙权";        System.out.println(list); //[] //打印ArrayList集合list.add(s1);list.add(s2);list.add(s3);System.out.println(list); //[曹操, 刘备, 孙权]}
}

3.4 常用方法和遍历:对于元素的操作:增、删、查

public class Demo01ArrayListMethod {public static void main(String[] args) {ArrayList<String> list = new ArrayList<String>();list.add("hello");list.add("world");list.add("java");//public E get(int index):返回指定索引处的元素System.out.println("get:"+list.get(0));  //get:helloSystem.out.println("get:"+list.get(1));  //get:worldSystem.out.println("get:"+list.get(2));  //get:java//public int size():返回集合中的元素的个数System.out.println("size:"+list.size());  //size:3//public E remove(int index):删除指定索引处的元素,返回被删除的元素System.out.println("remove:"+list.remove(0)); //remove:hellofor(int i = 0; i < list.size(); i++){System.out.println(list.get(i));  //world java}}
}

4.Object类:对象都需重写

package com.itheima00.question;public class Demo01 {public static void main(String[] args) {//        C c = new C();
//        c.method02(); // 可以 //static,final修饰的方法都是可以被继承,但不能重写
//        c.method01(); // 错误 //interface静态方法不能被继承,但是class静态方法可以被继承B b = new C(); //向上转型,静态和对象无关,属于类的。所以面向对象三大特性和静态无关// B b = null;这样写下行也一样,因为和对象无关b.method02(); //b method02,不是c method02 (多态), 静态 和 多态 冲突了}
}//111111111111111111111111111111111111111111111111111111111111111111111111111
interface A{static void method01(){ //接口中静态方法不能继承,肯定不能重写}
}class B{static int i;static void method02(){//类中静态方法可以继承,但不能重写(原因: 静态方法属于类的->重写就多态冲突了,如上b.method02();)System.out.println("b method02");}
}class C extends B implements A{static void method04(){System.out.println("c method02");}void method03(){ //如下都可以,但注意权限问题super.method02();System.out.println(i);}
}

4.1 toString方法:Object中的tostring方法: 对象类型包名类名 + 内存地址

package com.itheima01.object;
import java.util.ArrayList;
/*
*   Object类 : 所有类除Object本身之外(包括数组)的父类是Object
*   1.  String toString()  返回该对象的字符串表示。
*   2.  boolean equals(Object obj)  指示其他某个对象是否与此对象“相等”。
*
*   toString方法:
*       1. 结论: 如果直接打印对象,调用这个对象的toString方法*       println(String s) : s会被直接打印*       println(Object obj) 源码*           (obj == null) ? "null" : obj.toString(); 判空 : 避免空指针异常   2. 运用:*          1. 打印对象内存地址是没有意义, 想要打印对象的属性值 (方便测试)*          2. 解决: 这个类重写toString方法*/
public class ObjectDemo01 {public static void main(String[] args) {//        method01(); //        Person p = new Person();Person p = new Person("zs",18);System.out.println(p); //com.itheima01.object.Person@1540e19d  类型包名类名+ 内存地址System.out.println(p.toString()); //同上 //类中重写了toString方法后,p和p.toString()两个都打印出:Person{name='zs',age=18}ArrayList<String> list = new ArrayList<>();list.add("zs");list.add("ls");list.add("ww"); //打印引用类型,如果打印的不是内存地址,说明重写了toStringSystem.out.println(list.toString()); // [zs,ls,ww]}public static void method01(){int[] array = {1,2,3};System.out.println(array.length); //3String json = array.toString();boolean result = array instanceof Object; //验证数组的父类是不是ObjectSystem.out.println(result); //true}
}//111111111111111111111111111111111111111111111111111111111111111111
class Person{String name;int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}/* @Overridepublic String toString() {
//        return super.toString();String msg = "name:" + name + ",age=" + age;return msg;}*///快捷键: alt + insert -> toString 效果如下@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}
}

4.2 equals方法:Object类中的equals方法是==比较内存地址

package com.itheima01.object;
import java.util.Objects;
/*
*   == : java只有值传递,所以==不管是比较基本数据类型还是引用数据类型变量,本质比较的都是值,只是引用数据 类型变量存的值是对象地址
*
*     1. 比较内存地址已经有== , equals这样设计没有意义的
*     2. 想要比较两个对象的属性(包括身份证号)是否完全一致 , 实际推断为是同一对象
*      (实际含义和java内存含义不一样,虽然各自new内存不一样)
*
*     解决: 重写equals (两个对象逐一比较每个属性,如果两个对象每个属性都相同,返回true,否则返回false)
*     快捷键:  alt + insert -> equals and hashcode。  equals最主要运用: 哈希表
*/
public class ObjectDemo02 { public static void main(String[] args) {Student s1 = new Student("zs", 18);Student s2 = new Student("zs", 18);System.out.println(s1 == s2);//false:引用类型比较的是内存地址(new出来的内存地址肯定不一样)System.out.println(s1.equals(s2)); // false同上,比较的是内存地址,如下重写equals()后为true}
}//1111111111111111111111111111111111111111111111111111111111111111111
class Student{String name;int age;public Student(String name, int age) {this.name = name;this.age = age;}    @Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}/*this : s1obj : s2name ,age -> Student*//* @Overridepublic boolean equals(Object obj) {boolean result = obj instanceof Student; //如果是学生类型才继续往下走//boolean result = this.getClass() == obj.getClass();//源码中这样写,同上        if (!result){ //如果你传入不是student类型, 两个绝不一样,直接return falsereturn false; //result为false时,!result为true进入if内return false}    Student s2 = (Student) obj; //向下转型: 调用子类特有属性和方法boolean result2 = this.name.equals(s2.name);        if(!result2){return false;}        return this.age == s2.age;}*/@Overridepublic 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);}@Overridepublic int hashCode() {return Objects.hash(name, age);}
}
public class test1 {public static void main(String[] args) {String a = new String("ab"); // a 为一个引用String b = new String("ab"); // b为另一个引用,对象的内容一样String aa = "ab"; // 放在常量池中String bb = "ab"; // 从常量池中查找if (aa == bb) // trueSystem.out.println("aa==bb");if (a == b) // false,非同一对象System.out.println("a==b");if (a.equals(b)) // true //因为a为String,String中的equals方法是被重写过(比较对象的值)System.out.println("aEQb");if (42 == 42.0) { // trueSystem.out.println("true");}}
}

4.3 hashCode方法和equals方法:两个对象hashCode方法返回值相同,那么这两个是否equals?或者两个对象equals,那么hashCode方法返回值是否相同?


两个方法没有任何联系,因为我们可随意重写这两个方法如上,但是重写这两个方法时应该满足下面3个规范:1.对于同一个对象,没有任何属性变化:则多次求hashCode返回值应该是相同的,多次和另一个对象equals比较,返回值也应相同。如下random随机不稳定不符合规范。2.equals源码决定。3.hashmap存储结构决定,如下第二张图不符合第3个规范。

4.3.1 为什么要有如上这样的规范?牵扯到一系列hash存储

如下以hashmap为例,在hashmap中通过hashcode计算得到出的值就是数组的下标,例如下标=1,就在1这个桶中找对于元素,1这个桶可能存储的是链表或红黑树,假如是链表,就要在这个链式存储中挨个查找是否是我们想要的元素,挨个查找的时候我们需要equals方法对比每个节点的key和我们需要找的key是否equals。

所以如果hashcode值不稳定,那么每次查找时就打到不同桶里面。如果两个对象equals但hashcode不相等就会导致两次求index下标时求得不同下标。

4.3.2 hashCode扩展:重写hashcode方法不会在对象头中进行存储,对象头中31bit永远是0

1.无锁对象的对象头中有31个bit用来存储hashcode(int是4字节是32bit),hashcode是31bit,因为缺少了一个符号位,也就是说全是正数或0

2.java中对象的引用是4个字节的即32bit,所以hashcode返回值31bit显然对应不了,因而hashcode返回值肯定不是对象地址。

【Java5】String类,StringBuilder类,ArrayList类,Object类(toString,equals,hashCode)相关推荐

  1. java构造一个水果类_Java基础入门之Object类、匿名内部类、构造方法的继承解析...

    前言 大家好,我是Java进阶者.这篇文章我们主要介绍Java基础中的Object类.匿名内部类.构造方法的继承知识,一起来学习下吧! 一.Object类 1.Object类是所有类的父类,所有类都继 ...

  2. java object类的方法,JAVA中Object类中 有几个方法?

    慕标5265247 1.所有方法:1. getClass()2. hashCode()3. equals()4. toString()5. clone()6. wait()...7. notify() ...

  3. Java:继承之super关键字,继承之私有权限,继承之方法重写,继承之object类,继承之简单工厂模式

    一.继承的概念及用法       继承背后的思想就是        基于已存在的类来构建新类         当从已存在类继承时,就重用了它的方法和属性,还可以添加新的方法和属性来定制新类以应对需求 ...

  4. Java基础知识(二)(Object类的常用方法、日期时间类、System类、StringBuilder类、包装类、Collection集合、Iterator迭代器、泛型、list集Set接口...)

    文章目录 Java基础知识(二) 1.Object类的常用方法 1.1 toString方法 1.2 equals方法 1.3 Objects类 2.日期时间类 2.1 Date类 2.2 DateF ...

  5. JAVA day13,14 API、Object类、日期时间类(long,Date,Calendar,DateFormat)、String类(字符串,可变长字符串)、正则表达式、包装类

    1.API API(Application Programming Interface),应⽤程序编程接⼝.Java API是⼀本程序员的"字 典",是JDK提供给我们使⽤的类的说 ...

  6. String类 Object类 System类 Math类 Date类 Calendar类 DateFormat类

    API 全称Application Programming Interface,即应用程序编程接口. API是一些预先定义函数,目的是用来提供应用程序与开发人员基于某软件或者某硬件得以访问一组例程的能 ...

  7. JavaSE学习总结(八)常用类(上)Object类==与equals方法的区别浅克隆的特点Scanner类String类String两种创建对象方式的区别String类的各种功能

    JavaSE学习总结(八)常用类(上)/Object类/==与equals方法的区别/浅克隆的特点/Scanner类/String类/String两种创建对象方式的区别/String类的各种功能 常用 ...

  8. Object类、常用API

    # [Object类.常用API] ## 主要内容 * Object类 * Date类 * DateFormat类 * Calendar类 * System类 * StringBuilder类 * 包 ...

  9. Object类和常用的API

    第一章Object类 1.1 概述 1),Object 类是Java语言所有"引用类型"的父类,括我们自定义的类.类库中的类,数组,集合,字符串. 2),所有的的引用类型都从Obj ...

  10. 一、Java 面向对象高级——Object类、常用API

    day01[Object类.常用API] 主要内容 Object类 Date类 DateFormat类 Calendar类 System类 StringBuilder类 包装类 教学目标 -[ ] 能 ...

最新文章

  1. 谷歌开源NLP模型可视化工具LIT,模型训练不再「黑箱」
  2. Bugku-CTF之前女友(SKCTF)
  3. java restful接口测试_详解SpringBoot restful api的单元测试
  4. 从Jupyter Notebook切换到脚本的5个理由
  5. onenote 思维导图_学生党做笔记,我为什么更推荐OneNote?看后你就明白了
  6. SVG与CSS的特殊性
  7. CentOS7虚拟机克隆,且成功互ping
  8. 交换机短路_如何正确使用工业级交换机?
  9. chrome插件开发入门实战——CSDN免登陆拷贝、免关注查看
  10. 使用PHP自带的ZipArchive的一些问题
  11. Android多媒体技术(二)浅析Camera视频实时采集中涉及的参数配置
  12. 一个农村小伙的淘宝创业故事
  13. aardio - API调用分析
  14. 什么是CRM系统,它如何支持客户营销管理?
  15. Ubuntu U盘权限只读的解决方案
  16. 梯度与Roberts、Prewitt、Sobel、Lapacian算子
  17. 通过css设置img的src
  18. java将字符串中大写字母转换成小写将小写转换成大写
  19. 【Rust日报】 2019-04-09
  20. Only no-arg methods may be annotated with @Scheduled

热门文章

  1. 我和我的广告前端代码(六):webpack工程合并、也许我不需要gulp
  2. OV7725学习之SCCB协议(一)
  3. evernote100个做笔记的好方法
  4. 代码生成器1.0正式发布
  5. java链表交集并集,一个链表求集合并集交集的异常
  6. c语言 bmp白底黑字,用c语言把bmp格式的彩色图片转换成黑白的
  7. Integer’s Power HDU - 3208(容斥原理)
  8. git 使用详解(3)—— 最基本命令 + .gitignore 文件
  9. 复杂链表的复制(递归的两种实现方式)
  10. bzoj1878: [SDOI2009]HH的项链