第十六天:Object类
那日云淡天高,我们正值年少
狂神未更新,转千锋教育 (bilibili.com)
学习内容
Object类的概念
-
超类、基类,所有类的直接或间接父类,位于继承树的最顶层(也就是所有的类都会直接或间接继承这个类)
-
任何类,如果没有显式的指明extends
继承某个类,都会默认继承Object类,否则为间接继承
-
Object类中所定义的方法,是所有对象都具备的方法
-
Object类型可以储存任何对象
- 作为参数,可接受任何对象
- 作为返回值,可返回任何对象
-
位于java.lang.Object包中
Object类中的一些方法
getClass()方法
我们来试试:
-
我们先创建一个类,随便啥的都行
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()方法
我们还是拿之前的例子来举例
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()方法
我们还是按照上面一样的,尝试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()方法
先分清楚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之后就被弃用了,所以我们可能还是看不到”对象被回收了“