1. 🥘 Object类的概念

Object,翻译一下,对象;物体;目标;目的;物品;东西;宗旨;宾语 是的,这篇博客要讲的跟这些都没有太大关系(哈哈哈) 但有一点你必须记住!!! 它是所有类的爹!!!

言归正传,我们都知道,Object是Java默认提供的一个类。
Java中除了Object类,所有的类都是存在继承关系的。
默认所有的类会继承Object父类

这里就会有小伙伴会问了: 我没看到呀!哪里继承了!一个extends都没有! 咱们贴心的编译器会帮你继承得嘛 你看不见的就叫隐式继承 你能看见的就叫显式继承 你看不见,总不能忽略编译器的功劳吧 (编译器:啊对对对,我就是那个舔狗)

说人话:即所有类的对象都可以用Object的引用进行接收
…emmm,好像不太像人话
那就用代码再说一次人话:👇

  1. class Person{}
  2. class Student{}
  3. public class Test {
  4. public static void main(String[] args){
  5. func(new Person());
  6. func(new Student());
  7. }
  8. public static void func(Object obj){
  9. System.out.println(obj);
  10. }
  11. }

输出结果为

Person@4eec7777 Student@41629346

所以我们在开发过程中Object类是参数得最高统一类型。
Object 类位于 java.lang 包中,编译时会自动导入,我们创建一个类时,如果没有明确继承一个父类,那么它就会自动继承 Object,成为 Object 的子类。

2. 🧋 Object类的构造方法

public Object(){ … }

对,就这样,哈哈哈

3. 🍤 Object类的一些方法和属性

Object中存有一些定义好的方法
image.png
image.png
image.png
那么这里就为大家讲解一下其中的几个方法,这几个方法往往都是要牵扯到重写,以此来实现自己想要的功能,所以带大家简单回顾一下重写

3.1 🍜 重写的回顾

🍔 规则

重写的那个方法不可以比 被重写方法(就是父类中的方法) 有更严格的访问级别,可以更加广泛
父类方法中如果是包访问权限,那么子类的重写方法就可以是包访问权限或者是public访问权限

比如,Object类中有个toString方法,我们开始重写这个方法的时候总是忘记public修饰符,贴心的编译器会帮我们纠正错误,这里出错的原因就是:如果没有加上任何访问限定修饰符的方法就是包访问权限,包访问权限比public范围更小,更严格,所以会报错

那么这里又要附上那张传家宝表格了

No 范围 private defaul protected public
1 同一包中的同一类 🍉 🍉 🍉 🍉
2 同一包中的不同类 🍉 🍉 🍉
3 不同包中的子类 🍉 🍉
4 不同包的非子类
🍉

重写(override):也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等进行重新编写的一个过程,返回值和形参都不能改变即外壳不改变,核心重写
重写的好处在于子类可以根据需要,定义特定的属于子类自己的行为。
也就是说子类能够根据需要来实现父类的方法,又和父类的方法不完全一样,实现自己的特色
那么总结一下:

  • 子类在重写父类的方法时,一般必须与父类方法原型一致:修饰符 返回值类型 方法名(参数列表)要完全一致
  • JDK7以后,被重写的方法返回值类型可以不同,但是必须是具有父子关系
  • 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类方法被public修饰,则子类中重写该方法就不能声明为protected
  • 父类被static、private修饰的方法都不能被重写
  • 子类和父类在同一个包中,那么子类可以重写父类中的所有方法,除了声明为private和final的方法
  • 子类和父类不在同一个包中,那么子类只能够重写父类的 声明为public 和protected的非final方法
  • 重写的方法,可以使用 @Override 注解来显式指定。有了这个注解能够帮我们检查这个方法有没有被正确重写。例如不小心讲方法名拼写错了,此时编译器就会发现父类中并没有这个方法,就会编译报错,构不成重写。

Javaの带你攻破Object类 - 图4

🍛 重写和重载的区别

区别点 重载(overloading) 重写(override)
参数列表 必须修改 不同JDK版本不一样,如果修改那必须是继承关系
返回类型 可以修改 一定不能修改
访问限定符 可以修改 不能做出更严格的限制(子类权限大于父类)

即:方法重载式一个类的多态性的表现,而方法重写式子类与父类的一种多态性表现
Javaの带你攻破Object类 - 图5
Javaの带你攻破Object类 - 图6

3.2 🍱 toString方法

Object类中的 toString() 方法用于返回对象的字符串表示形式。
就是用来返回对象里面的一些信息并用字符串的形式返回。
不用传入参数,默认返回格式为
对象的class名称 + @ + hasCode 的十六进制字符串
老规矩,概念看不懂,代码上来凑:👇

  1. /**
  2. * @author Gremmie102
  3. * @date 2022/4/16 23:32
  4. * @purpose: 调用Object中的toString方法
  5. */
  6. public class ToStringTest {
  7. public static void main(String[] args) {
  8. // toString() with Object
  9. Object obj1 = new Object();
  10. System.out.println(obj1.toString());
  11. Object obj2 = new Object();
  12. System.out.println(obj2.toString());
  13. Object obj3 = new Object();
  14. System.out.println(obj3.toString());
  15. }
  16. }

那么我们运行出来的结果为👇

java.lang.Object@776ec8df java.lang.Object@4eec7777 java.lang.Object@3b07d329

Tips:这里的哈希值(你可以当作地址值)大家如果运行出来和我的不一样也没关系的,因为对象储存的位置都是不同的
那么我们现在用Array类来调用toString方法

  1. /**
  2. * @author Gremmie102
  3. * @date 2022/4/16 23:45
  4. * @purpose : 用Array的类来调用其父类的toString方法
  5. */
  6. public class ToStringTest1 {
  7. public static void main(String[] args) {
  8. //创建数组
  9. String[] array = {"葛玉礼","is","假面骑士"};
  10. System.out.println(array.toString());
  11. //数组元素值返回一个字符串的表示形式
  12. //Array继承了Object类,子类可以直接使用父类中的方法
  13. System.out.println(array[0].toString() +
  14. array[1].toString() +
  15. array[2].toString() );
  16. }
  17. }

运行结果为👇

[Ljava.lang.String;@776ec8df 葛玉礼is假面骑士

那么我们现在自己定义一个类,去重写它父类Object中的toString方法

  1. /**
  2. * @author Gremmie102
  3. * @date 2022/4/17 9:53
  4. * @purpose :重写Object中的toString中的方法
  5. */
  6. public class Student {
  7. String name;
  8. int age;
  9. double score;
  10. public Student() {
  11. }
  12. public Student(String name, int age, double score) {
  13. this.name = name;
  14. this.age = age;
  15. this.score = score;
  16. }
  17. public void study(){
  18. System.out.println(name+" is studying");
  19. }
  20. @Override
  21. public String toString() {
  22. return "Student{" +
  23. "name='" + name + '\'' +
  24. ", age=" + age +
  25. ", score=" + score +
  26. '}';
  27. }
  28. }

我们在重写的方法中自定义了需要显现出来的内容
那么我们写个main方法来测试一下

  1. public static void main(String[] args) {
  2. Student student = new Student("Gremmie",19,95);
  3. System.out.println(student);
  4. }

那么运行结果为:

Student{name=’Gremmie’, age=19, score=95.0}

这里为啥直接输入一个引用变量就可以直接显示出这么一堆信息捏?
带大家调试一下,看清它的真面目
image.png
👆首先第一行代码new了一个对象,并进入构造方法进行初始化
image.png
?不给机会,直接就跳到toString方法那里去了,可能这里是编译器暗中捣鬼,我们就不再深究,会用就OK啦

3.3 🍰 equals方法

我们在Java中使用 == 进行比较的时候遵循以下几点:

  1. 如果==左右两边是基本类型变量,那么比较的就是变量中的值是否相同
  2. 如果==左右两边是引用类型变量,那么比较的就是引用变量的地址是否相同
  3. 如果要比较对象中的内容,那就必须要重写Object中的equals方法,因为equals方法也是默认按照地址来比较的

那么用代码来演示一下没有重写之前的用法

  1. /**
  2. * @author Gremmie102
  3. * @date 2022/4/17 10:27
  4. * @purpose :介绍Object中的equals方法
  5. */
  6. public class EqualsTest1 {
  7. public static void main(String[] args) {
  8. // Object 类使用 equals() 方法
  9. // 创建两个对象
  10. Object object1 = new Object();
  11. Object object2 = new Object();
  12. // 判断 obj1 与 obj2 是否相等
  13. // 不同对象,内存地址不同,不相等,返回 false
  14. System.out.println(object1.equals(object2)); // false
  15. // obj1 赋值给 obj3
  16. // String 重写了 equals() 方法
  17. // 对象引用,内存地址相同,相等,返回 true
  18. Object object3 = object1;
  19. System.out.println(object1.equals(object3)); // true
  20. }
  21. }
  22. /**
  23. * 运行结果:
  24. * E:\develop\Java\jdk-11\bin\java.exe "-javaagent:E:\IDEA\IntelliJ IDEA Community Edition 2021.3.2\lib\idea_rt.jar=51082:E:\IDEA\IntelliJ IDEA Community Edition 2021.3.2\bin" -Dfile.encoding=UTF-8 -classpath E:\JAVAcode\gyljava\ObjectTest\out\production\ObjectTest EqualsTest1
  25. * false
  26. * true
  27. *
  28. * Process finished with exit code 0
  29. */

那么我们再写一个Person类,首先是未重写版

  1. /**
  2. * @author Gremmie102
  3. * @date 2022/4/17 10:33
  4. * @purpose :未重写equals的Person类的Person类
  5. */
  6. public class Person {
  7. private String name;
  8. private int age;
  9. public Person(String name,int age){
  10. this.age = age;
  11. this.name = name;
  12. }
  13. public static void main(String[] args) {
  14. int a = 10;
  15. int b = 10;
  16. Person p1 = new Person("Gremmie",19);
  17. Person p2 = new Person("Gremmie",19);
  18. System.out.println(a==b);
  19. System.out.println(p1==p2);
  20. System.out.println(p1.equals(p2));
  21. }
  22. }
  23. /**
  24. * 运行结果
  25. * E:\develop\Java\jdk-11\bin\java.exe "-javaagent:E:\IDEA\IntelliJ IDEA Community Edition 2021.3.2\lib\idea_rt.jar=51109:E:\IDEA\IntelliJ IDEA Community Edition 2021.3.2\bin" -Dfile.encoding=UTF-8 -classpath E:\JAVAcode\gyljava\ObjectTest\out\production\ObjectTest Person
  26. * true
  27. * false
  28. * false
  29. *
  30. * Process finished with exit code 0
  31. */

那么下面重写equals方法

  1. @Override
  2. public boolean equals(Object o) {
  3. if (this == o) return true;
  4. if (!(o instanceof Person)) return false;
  5. Person person = (Person) o;//这里向下转型来比较属性值
  6. return Objects.equals(name, person.name);
  7. //这里运用了方法递归
  8. }

结论:比较对象中内容是否相同的时候,我们就一定要重写equals方法了

3.4 🍟hashCode方法

Object hashCode() 方法用于获取对象的 hash 值。
我们看一下hashCode的源码
image.png
这个方法是由native修饰的,返回一个内存地址值
方法的底层是由C/C++编写,我们看不到

  1. /**
  2. * @author Gremmie102
  3. * @date 2022/4/17 11:39
  4. * @purpose :演示了 hashCode() 方法的使用
  5. */
  6. public class HashCodeTest1 {
  7. public static void main(String[] args) {
  8. // Object 使用 hashCode()
  9. Object obj1 = new Object();
  10. System.out.println(obj1.hashCode());
  11. Object obj2 = new Object();
  12. System.out.println(obj2.hashCode());
  13. Object obj3 = new Object();
  14. System.out.println(obj3.hashCode());
  15. }
  16. }
  17. /**
  18. * 运行结果
  19. * E:\develop\Java\jdk-11\bin\java.exe "-javaagent:E:\IDEA\IntelliJ IDEA Community Edition 2021.3.2\lib\idea_rt.jar=51403:E:\IDEA\IntelliJ IDEA Community Edition 2021.3.2\bin" -Dfile.encoding=UTF-8 -classpath E:\JAVAcode\gyljava\ObjectTest\out\production\ObjectTest HashCodeTest1
  20. * 2003749087
  21. * 1324119927
  22. * 990368553
  23. *
  24. * Process finished with exit code 0
  25. */

那么我们在String和ArrayList类使用hashCode()方法
因为所有的类都继承了Object,所以可以直接调用

  1. /**
  2. * @author Gremmie102
  3. * @date 2022/4/17 11:43
  4. * @purpose :String 和 ArrayList 类使用 hashCode() 方法
  5. */
  6. import java.util.ArrayList;
  7. public class HashCodeTest2 {
  8. public static void main(String[] args) {
  9. // String 使用 hashCode()
  10. String str = new String();
  11. System.out.println(str.hashCode()); // 0
  12. // ArrayList 使用 hashCode()
  13. ArrayList<Integer> list = new ArrayList<>();
  14. System.out.println(list.hashCode()); // 1
  15. }
  16. }

那么如果两个引用变量指向的对象都是一样的,那么它们所调用返回的哈希值也是相等的

  1. /**
  2. * @author Gremmie102
  3. * @date 2022/4/17 11:45
  4. * @purpose :引用变量指向一个对象情况下,它们调用hashCode方法
  5. */
  6. public class HashCodeTest3 {
  7. public static void main(String[] args) {
  8. // Object 使用 hashCode()
  9. Object obj1 = new Object();
  10. // obj1 赋值给 obj2
  11. Object obj2 = obj1;
  12. // 判断两个对象是否相等
  13. System.out.println(obj1.equals(obj2)); // true
  14. // 获取 obj1 与 obj2 的哈希值
  15. System.out.println(obj1.hashCode());
  16. System.out.println(obj2.hashCode());
  17. }
  18. }
  19. /**
  20. * 运行结果
  21. * E:\develop\Java\jdk-11\bin\java.exe "-javaagent:E:\IDEA\IntelliJ IDEA Community Edition 2021.3.2\lib\idea_rt.jar=51415:E:\IDEA\IntelliJ IDEA Community Edition 2021.3.2\bin" -Dfile.encoding=UTF-8 -classpath E:\JAVAcode\gyljava\ObjectTest\out\production\ObjectTest HashCodeTest3
  22. * true
  23. * 2003749087
  24. * 2003749087
  25. *
  26. * Process finished with exit code 0
  27. */

那么同样,我们也可以重写hashCode方法
现在我们想要两个对象如果所有属性都相同,调用hashCode返回的值都相同

  1. import java.util.Objects;
  2. /**
  3. * @author Gremmie102
  4. * @date 2022/4/17 11:51
  5. * @purpose :重写hashCode()方法
  6. */
  7. class Human{
  8. public String name;
  9. public int age;
  10. public Human(String name, int age) {
  11. this.name = name;
  12. this.age = age;
  13. }
  14. @Override
  15. public int hashCode() {
  16. return Objects.hash(name,age);
  17. }
  18. }
  19. public class HashCodeTest4 {
  20. public static void main(String[] args) {
  21. Human human1 = new Human("Gremmie",19);
  22. Human human2 = new Human("Gremmie",19);
  23. System.out.println(human1.hashCode());
  24. System.out.println(human2.hashCode());
  25. }
  26. }
  27. /**
  28. * 运行结果
  29. * E:\develop\Java\jdk-11\bin\java.exe "-javaagent:E:\IDEA\IntelliJ IDEA Community Edition 2021.3.2\lib\idea_rt.jar=51508:E:\IDEA\IntelliJ IDEA Community Edition 2021.3.2\bin" -Dfile.encoding=UTF-8 -classpath E:\JAVAcode\gyljava\ObjectTest\out\production\ObjectTest HashCodeTest4
  30. * 277247006
  31. * 277247006
  32. *
  33. * Process finished with exit code 0
  34. */

这样,我们就可以让属性相同的对象返回相同的哈希值了
结论:

  1. hashCode方法用来确定对象在内存中存储的位置是否相同
  2. 事实上hashCode()在散列表中才有用,其他情况下是没用的,在散列表中hashCode()的作用是获取对象的散列码,进而去确定该对象在散列表中的位置

这个方法牵扯到了数据结构,等学习进度差不多了再重新为大家讲解,看不懂没关系

3.5 🍫用来接受引用数据类型

我们已经知道Object类可以接受任意类型的对象,因为Object是所有类的父类,但是Object其实并不仅限于接受类的对象,它可以接受所有的数据类型
比如:类、数组、接口

🌭 接收数组对象

  1. /**
  2. * @author Gremmie102
  3. * @date 2022/4/17 12:30
  4. * @purpose :接收数组对象
  5. */
  6. public class ObjectTest1 {
  7. public static void main(String[] args) {
  8. //Object接收数组对象,向上转型
  9. Object obj = new int[]{1,2,3,4,5,6};
  10. //向下转型,需要强制转换
  11. int[] data = (int[])obj;
  12. for (int i :data) {
  13. System.out.print(i+" ");
  14. }
  15. }
  16. }
  17. /**
  18. * 运行结果
  19. * E:\develop\Java\jdk-11\bin\java.exe "-javaagent:E:\IDEA\IntelliJ IDEA Community Edition 2021.3.2\lib\idea_rt.jar=52075:E:\IDEA\IntelliJ IDEA Community Edition 2021.3.2\bin" -Dfile.encoding=UTF-8 -classpath E:\JAVAcode\gyljava\ObjectTest\out\production\ObjectTest ObjectTest1
  20. * 1 2 3 4 5 6
  21. * Process finished with exit code 0
  22. */

🍲 接收接口引用的对象

在Java中,接口本身是不能继承任何类的,它只能继承接口,但Object是很特殊的例子,是强制规定的

  1. /**
  2. * @author Gremmie102
  3. * @date 2022/4/17 12:35
  4. * @purpose :用Object接收接口对象
  5. */
  6. interface IMessage {
  7. String getMessage();
  8. }
  9. class Message implements IMessage {
  10. String str = "我爱Java";
  11. @Override
  12. public String toString() {
  13. return "Life is not satisfactory";
  14. }
  15. @Override
  16. public String getMessage() {
  17. return str;
  18. }
  19. }
  20. public class ObjectTest2 {
  21. public static void main(String[] args) {
  22. IMessage message = new Message();
  23. // 子类向父接口转型
  24. Object object = message;
  25. // 接口向Object转型
  26. System.out.println(object);
  27. IMessage temp = (IMessage) object;
  28. System.out.println(temp.getMessage());
  29. }
  30. }
  31. /**
  32. *运行结果
  33. * E:\develop\Java\jdk-11\bin\java.exe "-javaagent:E:\IDEA\IntelliJ IDEA Community Edition 2021.3.2\lib\idea_rt.jar=52215:E:\IDEA\IntelliJ IDEA Community Edition 2021.3.2\bin" -Dfile.encoding=UTF-8 -classpath E:\JAVAcode\gyljava\ObjectTest\out\production\ObjectTest ObjectTest2
  34. * Life is not satisfactory
  35. * 我爱Java
  36. * Process finished with exit code 0
  37. */

我们可以通过合理运用Object来真正达到参数的统一
如果一个类编写的时候希望能够接收所有的数据类型,那么就用Object来完成。
对于Object就介绍到这里,如果哪里讲解的不到位还请大家指出
感谢阅读~