Object类
相信有一双善于观察的眼睛的你一定发现了,我们每次使用对象去.的时候,总是会有很多我们自己没有写过的方法。
就像这些:
我们明明没有写这些,为什么会有呢?这就必须得提到我们的类的鼻祖:Object类了。
1.Object是什么?
所有的类都直接或者间接的继承了Object类。如果该类继承了除Object类的其它类,则该类为间接的继承Object类,若没有继承其它类,则为直接的继承Object类,可以省略extends Object,也可以写上。
那我怎么知道这些方法是干嘛的呀!又不是我写的。
这个时候就需要我们的api帮助文档出场了,里面详细的记载了Object类的所有内容,包括所有方法的含义和使用等等。
2.api的使用
api是Application Programming Interface的缩写,即应用程序编程接口。而api文档,,就像是说明书,里面包含了Java已经定义好的类、接口、抽象类的详细内容。
今后的学习几乎都是参考api文档去学习api里面的类、接口、抽象类的内容。
首先我们需要按照索引来搜索我们想要查询的内容:
输入内容之后按回车:
但是可能有多个,因为有的是类,有的是接口(后续内容会讲)
我们找到Object类:(可以先点击进去,不是就再搜索一次点击另外一个)
可以看到关于这个类有特别详细的解释,往下滑有关于方法的特别详细的解释,(小tip:点击蓝色的方法名就能直接跳转),所以api文档是我们需要好好利用的一个工具。
api百度网盘链接
链接:https://pan.baidu.com/s/1t_cKercpOW3uWReREcf8ug
提取码:p8yj
有需要自取~
3.Object常用方法
所有的类都拥有Object类的所有方法。
以下几个方法必须掌握!
(1)hashcode()
//返回对象的哈希码值
public int hashCode()
hashcode()用于返回对象的哈希码值。哈希码值是对象在内存中的逻辑地址,是相对于真实地址经过一定的运算得到的一个整数,对象的引用地址存储在栈中,真实的值存放在堆中,栈中的引用地址指向堆中的值。
例:
package com.dh.object;
public class HashcodeDemo {
public static void main(String[] args) {
//实例化一个对象
HashcodeDemo hashcodeDemo = new HashcodeDemo();
//得到对象的哈希码值
int hashCode = hashcodeDemo.hashCode();
//输出该对象的哈希码值
System.out.println(hashCode);
//每个对象的哈希码值是不一样的
HashcodeDemo hashcode2 = new HashcodeDemo();
System.out.println(hashcode2.hashCode());
}
}
结果:每个对象的哈希码值一般来讲是不一样的
既然我们继承了Object类,那我们也能重写其方法。
如果要让某个类的所有对象都返回相同的值,只需要重写hashcode():
原本调用的是父类的hashcode()
@Override
public int hashCode() {
return super.hashCode();
}
重写:让hashcode()的返回值为固定的数,则每一个对象都会返回这个值,就会让每个对象hashcode()结果都相同。
package com.dh.object;
public class HashcodeDemo {
@Override
public int hashCode() {
return 1000; //任意int类型整数
}
public static void main(String[] args) {
//实例化一个对象
HashcodeDemo hashcodeDemo = new HashcodeDemo();
//得到对象的哈希码值
int hashCode = hashcodeDemo.hashCode();
//输出该对象的哈希码值
System.out.println(hashCode);
//实例化新对象,返回其哈希码值
HashcodeDemo hashcodeDemo2 = new HashcodeDemo();
System.out.println(hashcodeDemo2.hashCode());
//重写了hashCode()之后,该类的每个对象的哈希码值都一样
System.out.println(hashcodeDemo.hashCode() == hashcodeDemo2.hashCode());
}
}
结果:
(2)getClass()
//返回此Object的运行时类
//<>是泛型,后续会讲到,可暂时去掉
public final Class<?> getClass()
首先需要明确的是,Java是强类型语言,严格区分大小写,Class 是一个类型,和我们定义类使用的 class 关键字是不一样的!
在执行Java程序的时候,首先会将.java文件编译成.class字节码文件,如何把字节码文件加载进内存,在Java中,万事万物皆为对象,所以jvm就认为该字节码文件为一个对象,Class类型对应的对象就是:字节码文件(.class)对象。
每个类只有一个.class文件,可想而知,同一个类的实例同属一个.class字节码文件,所以getClass()的值也都是一样的。
例:
package com.dh.object;
public class GetClassDemo {
public static void main(String[] args) {
//new一个对象
GetClassDemo getClassDemo = new GetClassDemo();
//使用getClass()获得一个Class类型的对象
Class aClass = getClassDemo.getClass();
//输出该对象
System.out.println(aClass);
//同一个类的实例使用getClass()因返回同一个值
GetClassDemo getClassDemo2 = new GetClassDemo();
System.out.println(getClassDemo2.getClass());
}
}
结果:
getClass()的结果为:class 包名.类名。
getClass()是final修饰的,所以不能被重写。
(3)toString()
//返回对象的字符串表现形式
//返回值为:getClass().getName() + '@' + Integer.toHexString(hashCode())
//可以在IDEA这鼠标放在toString()上,按ctrl,鼠标左键进去看源码,源码例就是这样写的输出
//Integer.toHexString():将十进制转换为十六进制
public String toString()
例:
package com.dh.object;
public class ToStringDemo {
public static void main(String[] args) {
//new一个对象
ToStringDemo toStringDemo = new ToStringDemo();
//使用toString,返回该对象的字符串表示形式
String s = toStringDemo.toString();
//输出该对象的字符串表现形式
System.out.println(s);
//不同对象的字符串表现形式
ToStringDemo toStringDemo2 = new ToStringDemo();
System.out.println(toStringDemo2.toString());
}
}
结果:
我们输出对象,看看结果会是什么:
System.out.println("============");
System.out.println(toStringDemo);
System.out.println(toStringDemo2);
观察结果可得:直接输出对象和输出对象的toString()是一样的。
如果输出对象的值为这样的话,就没有什么意义了是不是,这字符串又看不懂,所以我们可以重写一下toString(),用来输出我们想要看到的对象,比如对象的属性。
重写toString():
package com.dh.object;
public class ToStringOverride {
public String name;
public int age;
public ToStringOverride(String name, int age) {
this.name = name;
this.age = age;
}
@Override
//重写Object的toString()
public String toString() {
return "name = "+this.name+"\tage = "+this.age;
}
public static void main(String[] args) {
ToStringOverride toStringOverride = new ToStringOverride("Tom",18);
//调用重写后的toString()
String s = toStringOverride.toString();
System.out.println(s);
}
}
结果:按照我们的格式输出了数据。
可以看到,只是输出当前的属性,是很简单的操作,但是却要重复的写,强大的IDEA已经给我们提供了快捷方式:alt+ins,选择toString,再选择你要的属性:
@Override
public String toString() {
return "ToStringOverride{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
方便快捷!
(4)equals()
//指示一些其他对象是否等于此。
public boolean equals(Object obj)
==和equals()都是用来判断相等的,那它们有什么区别呢?
== 和 equals()的区别
-
==
-
基本数据类型:比较的是值
-
引用数据类型:比较的是内存地址
package com.dh.object; public class EqualsDemo { public static void main(String[] args) { int a = 1; int b = 1; EqualsDemo equalsDemo1 = new EqualsDemo(); EqualsDemo equalsDemo2 = new EqualsDemo(); //==比较基本数据类型,比较的是值,值相等,结果为true System.out.println(a == b); //==比较引用数据类型,比较的是地址,每个对象的地址都不一样,结果为false System.out.println(equalsDemo1 == equalsDemo2); } }
-
-
equals()
-
引用数据类型:比较的是内存地址。(未重写该方法时)
源码:
public boolean equals(Object obj) { return (this == obj); }
equal方法本质上还是==比较。
在上述代码中,添加使用equals比较的输出语句:
System.out.println("================"); System.out.println(equalsDemo1.equals(equalsDemo2));//内存地址不一样,输出false
结果:
-
字符串:比较的是字符串的内容。(重写了该方法)
-
String类重写equals()
因为==就可以用来比较两个引用数据类型的地址,如果equals()也是的话,就多余了,所以,我们可以重写equals()方法,让它具有别的功能。String类就已经帮我们实现了这个功能。
String类重写了equals(),用于比较字符串的内容是否相等:
package com.dh.object;
public class EqualsOverride {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
System.out.println(s1.equals(s2));
}
}
我们将鼠标移到equals上,ctrl+鼠标左键点击进入源码:
//实现字符串的值比较(看不懂可暂时不看)
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String aString = (String)anObject;
if (coder() == aString.coder()) {
return isLatin1() ? StringLatin1.equals(value, aString.value)
: StringUTF16.equals(value, aString.value);
}
}
return false;
}
本人水平有限,若有错误,望指正,感激~