跟随狂神学Java
作者:joker2yue
链接:https://github.com/Joker2Yue/Joker2Yue-Blog
来源:Github
著作权归原作者所有。商业转载请联系原作者获得授权,非商业转载请注明出处。
第十六天:Object类
那日云淡天高,我们正值年少
狂神未更新,转千锋教育 (bilibili.com)
学习内容
Object类的概念
- 超类、基类,所有类的直接或间接父类,位于继承树的最顶层(也就是所有的类都会直接或间接继承这个类)
- 任何类,如果没有显式的指明
extends
继承某个类,都会默认继承Object类,否则为间接继承
- Object类中所定义的方法,是所有对象都具备的方法
- Object类型可以储存任何对象
- 作为参数,可接受任何对象
- 作为返回值,可返回任何对象
- 位于java.lang.Object包中
Object类中的一些方法
getClass()方法
- pubic final
Class<?>
getClass() {}
- 返回引用中储存的==实际对象类型==
- 应用:通常用于判断两个引用中实际储存==对象是否一致==
- 返回值:Class类型
我们来试试:
我们先创建一个类,随便啥的都行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
package com.joker_yue.javalearn.object;
public class Student { private String name; private int age;
public Student(){ }
public Student(String name, int age){ super(); this.name= name; this.age=age; }
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; } }
|
然后我们创建它的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
package com.joker_yue.javalearn.object;
public class TestStudent { public static void main(String[] args) { Student s1 = new Student("aaa",20); Student s2 = new Student("bbb",22);
} }
|
我们来使用getClass()方法,判断二者是否相等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
package com.joker_yue.javalearn.object;
public class TestStudent { public static void main(String[] args) { Student s1 = new Student("aaa",20); Student s2 = new Student("bbb",22); Class class1 = s1.getClass(); Class class2 = s2.getClass();
if(class1 == class2){ System.out.println("s1与s2是同一个类型"); }else{ System.out.println("s1与s2不是同一个类型"); }
} }
|
最后的运行输出结果为:
hashCode()方法
- public int hashCode() {}
- 返回该对象的哈希值(int)
- 哈希值:根据堆中的==对象的地址==或==字符串==或==数字==使用hash算法来计算出来的int类型的数值
- 一般情况下, 相同的对象会返回相同的哈希值
我们还是拿之前的例子来举例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
package com.joker_yue.javalearn.object;
public class TestStudent { public static void main(String[] args) {
Student s1 = new Student("aaa",20); Student s2 = new Student("bbb",22);
Class class1 = s1.getClass(); Class class2 = s2.getClass();
if(class1 == class2){ System.out.println("s1与s2是同一个类型"); }else{ System.out.println("s1与s2不是同一个类型"); }
System.out.println(s1.hashCode()); System.out.println(s2.hashCode());
} }
|
最后的输出结果为:
1 2 3
| s1与s2是同一个类型 1324119927 990368553
|
那我们再创建一个s3对象,并使s3=s1;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
package com.joker_yue.javalearn.object;
public class TestStudent { public static void main(String[] args) {
Student s1 = new Student("aaa",20); Student s2 = new Student("bbb",22);
Class class1 = s1.getClass(); Class class2 = s2.getClass();
if(class1 == class2){ System.out.println("s1与s2是同一个类型"); }else{ System.out.println("s1与s2不是同一个类型"); }
System.out.println(s1.hashCode()); System.out.println(s2.hashCode()); Student s3 = s1; System.out.println(s3.hashCode());
} }
|
我们会发现s3和s1的hashCode是一样的
1 2 3 4
| s1与s2是同一个类型 1324119927 990368553 1324119927
|
因为我们是将s1的内存赋值给了s3。在栈中有两个变量s1和s3,但是这两个变量都指向了堆里面的同一个对象
toString()方法
- public String toString() {}
- 返回该对象的字符串表示(表现形式)
- 可以根据项目需求覆盖该方法,如:展示对象各个属性值
我们还是按照上面一样的,尝试toString()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
package com.joker_yue.javalearn.object;
public class TestStudent { public static void main(String[] args) {
Student s1 = new Student("aaa",20); Student s2 = new Student("bbb",22);
Class class1 = s1.getClass(); Class class2 = s2.getClass();
if(class1 == class2){ System.out.println("s1与s2是同一个类型"); }else{ System.out.println("s1与s2不是同一个类型"); }
System.out.println("-----------------");
System.out.println(s1.hashCode()); System.out.println(s2.hashCode());
Student s3 = s1; System.out.println(s3.hashCode());
System.out.println("-----------------");
System.out.println(s1.toString()); System.out.println(s2.toString());
} }
|
最后的输出结果为:
1 2 3 4 5 6 7 8
| s1与s2是同一个类型 ----------------- 1324119927 990368553 1324119927 ----------------- com.joker_yue.javalearn.object.Student@4eec7777 com.joker_yue.javalearn.object.Student@3b07d329
|
我们可以发现它打印的是我们软件包的全名称加上此对象的哈希值(十六进制)
在IDEA中我们可以按住Ctrl+鼠标左键然后点击toString()来查看源码:
我们也可以将toString()进行重写来让其符合我们的需求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
package com.joker_yue.javalearn.object;
public class Student { private String name; private int age;
public Student(){ }
public Student(String name, int age){ super(); this.name= name; this.age=age; }
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; }
@Override public String toString() { return name+":"+age; } }
|
然后运行TestStudent.java我们可以得到如下输出:
1 2 3 4 5 6 7 8
| s1与s2是同一个类型 ----------------- 1324119927 990368553 1324119927 ----------------- aaa:20 bbb:22
|
发现返回的是自己的定义的功能
equals()方法
- public boolean equals(Object obj) {}
- 默认实现为(this == obj),比较两个对象是否相同
- 可进行覆盖,比较两个对象的内容是否相同
先分清楚equals()和==的区别
使用 == 比较
Java中的8种===基本数据类型==(byte
,short
,char
,int
,long
,float
,double
,boolean
)比较他们之间的==值==是否相等。
==引用数据类型==(类Class引用
、接口interface引用
、数组引用
),比较的是他们在堆==内存地址==是否相等。每新new一个引用类型的对象,会重新分配堆内存空间,使用==比较返回false。
使用 equals() 比较
equals()方法是Object类的一个方法,Java当中所有的类都是继承于Object这个超类。
JDK1.8 Object类equals方法源码如下,即返回结果取决于两个对象的使用==判断结果。
1 2 3
| public boolean equals(Object obj) { return (this == obj); }
|
默认情况下,比较内存地址值是否相等。可以按照需求逻辑,重写对象的equals()方法。
来自CSDN博主「ConstXiong」的博客
我们来试试
一样的,我们还是这样举例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
|
package com.joker_yue.javalearn.object;
public class TestStudent { public static void main(String[] args) {
Student s1 = new Student("aaa",20); Student s2 = new Student("bbb",22);
Class class1 = s1.getClass(); Class class2 = s2.getClass();
if(class1 == class2){ System.out.println("s1与s2是同一个类型"); }else{ System.out.println("s1与s2不是同一个类型"); }
System.out.println("-----------------");
System.out.println(s1.hashCode()); System.out.println(s2.hashCode());
Student s3 = s1; System.out.println(s3.hashCode());
System.out.println("-----------------");
System.out.println(s1.toString()); System.out.println(s2.toString());
System.out.println("-----------------");
System.out.println(s1.equals(s2)); System.out.println(s1.equals(s3));
} }
|
最后的输出结果为:
1 2 3 4 5 6 7 8 9 10 11
| s1与s2是同一个类型 ----------------- 1324119927 990368553 1324119927 ----------------- aaa:20 bbb:22 ----------------- false true
|
可以发现 s1.equals(s2)
输出为false
,这是因为他们是两个不同的对象
同样的 s1.equals(s3)
输出为ture
,原因是因为他们是相同的对象
即使我们重新new一个对象
1
| Student s4 = new Student("aaa",20);
|
然后将其s4.equals(s1)
,输出结果也是false
。因为我们每new
一个对象,就会在堆中重新开辟空间,所以他们(s1,s4)的地址不相同,便会输出false
但是总是有聪明的脑袋们会问,啊~String类不是也有equals()方法嘛,像这样:
1 2 3
| String s1 = "我最帅"; String s2 = "我最帅"; System.out.println(s1.equals(s2));
|
明明就是两个不同的对象为什么会输出ture
啊?
这是因为String类重写了equals()方法,让他们比较值而不是比较地址(别混淆了我们现在讲的是Object类!)
这时候又会有聪明的脑袋们问,啊~怎么重写
equals()方法的重写
步骤:
- 比较两个引用是否指向同一个对象
- 判断obj是否为null
- 判断两个引用指向的实际对象类型是否一致
- 强制类型转换
- 依次比较各个属性值是否相等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
|
package com.joker_yue.javalearn.object;
public class Student extends Object{ private String name; private int age;
public Student(){ }
public Student(String name, int age){ super(); this.name= name; this.age=age; }
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; }
@Override public String toString() { return name+":"+age; }
@Override public boolean equals(Object obj) { if(this==obj) { return true; } if(obj==null){ return false; }
if(obj instanceof Student){ Student s = (Student) obj; if(this.name.equals(s.getName()) && this.age==s.getAge()){ return true; }
}
return false; } }
|
finalize()方法
- 当对象被判定为垃圾对象时,由JVM自动调用此方法,用以标记垃圾对象,进入回收队列
- 垃圾对象:没有有效引用指向此对象时,为垃圾对象
- 垃圾回收:由GC销毁垃圾对象,释放数据储存空间
- 自动回收机制:JVM的内存耗尽,一次性回收所有垃圾对象
- 手动回收机制:使用
System.gc();
通知JVM执行垃圾回收
我们来试试,让其在垃圾回收的时候自动输出一句话
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
|
package com.joker_yue.javalearn.object;
public class Student extends Object{ private String name; private int age;
public Student(){ }
public Student(String name, int age){ super(); this.name= name; this.age=age; }
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; }
@Override public String toString() { return name+":"+age; }
@Override public boolean equals(Object obj) { if(this==obj) { return true; } if(obj==null){ return false; }
if(obj instanceof Student){ Student s = (Student) obj; if(this.name.equals(s.getName()) && this.age==s.getAge()){ return true; }
}
return false; }
@Override protected void finalize() throws Throwable { System.out.println("对象被回收:"+this.name); } }
|
然后我们来创建一个mian方法用来测试重写的finalize()是否成功执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
package com.joker_yue.javalearn.object;
public class TestStudent2 { public static void main(String[] args) { Student s1 = new Student("aaa",20); Student s2 = new Student("bbb",20); Student s3 = new Student("ccc",20); Student s4 = new Student("ddd",20); Student s5 = new Student("eee",20); System.gc(); System.out.println("回收垃圾"); } }
|
上述代码的运行结果为
可以发现我们的重写并没有执行,那我们就换一种写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
package com.joker_yue.javalearn.object;
public class TestStudent2 { public static void main(String[] args) {
new Student("aaa",20); new Student("bbb",20); new Student("ccc",20); new Student("ddd",20); new Student("eee",20); System.gc(); System.out.println("回收垃圾"); } }
|
上述代码执行后,理应输出如下信息:
1 2 3 4 5 6
| aaa对象被回收了 bbb对象被回收了 ccc对象被回收了 ddd对象被回收了 eee对象被回收了 回收垃圾
|
但是finalize()方法从Java9之后就被弃用了,所以我们可能还是看不到”对象被回收了“