Java 编程基础教程系列:Java 编程进阶之路【从入门到精通】 ,从入门到精通一站学习,买不了吃亏,买不了上当!!
Object 类是 Java 默认提供的一个类,是所有 Java 类的祖先类,每个类都使用 Object 作为父类。
那么我们就可以使用 Object 类的引用变量指向任何类的对象。在没有明确给出一个类的父类时,Java 默认把 Object 类作为该类的父类,继承了 Object 类的所有方法。
示例:
public class Test {
public static void main(String[] args) {
function(new Person());
function(new Student());
}
public static void function(Object obj){
System.out.println(obj);
}
}
class Person{
private int age;
private String name;
}
class Student{
private int grade;
private String sno;
}
在上面创建了两个不同类型的对象,并且作为实参传递给了 function 方法,此时相当于:
Object obj =new Person();
输出的是对象引用的值,也就是其指向对象的地址。
Object 类中提供了一些方法,其中常用的方法有 toString()
方法,equals()
方法,hashcode()
方法等。在使用前导入 Object 类:
import java.util.Objects;
JDK源码中的toString方法:
//Object类中的toString()方法实现:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
toString()
方法定义在 Object 类中,返回值是 String 类型,根据调用它的对象返回类名和它的引用地址。
示例:
public class Test {
public static void main(String[] args) {
Person person=new Person();
System.out.println(person.toString());
System.out.println(person);
}
}
class Person{
public String name;
}
在我们打印对象的引用时,实际上是默认调用了这个对象的toString
方法。返回此对象所在的类及对应的堆空间对象实体的首地址值。
该方法一般要重写后使用,一般重写是将类的对象的属性返回。在没有被重写时,返回的字符串格式是 类名@哈希值,哈希值是十六进制的。示例:
public class Test {
public static void main(String[] args) {
Person person=new Person();
System.out.println(person.toString());
System.out.println(person);
}
}
class Person{
private String name="张三";
private int age=20;
public String toString(){
return "Person:name "+name+" age "+age;
}
}
/*
Person:name 张三age 20
Person:name 张三age 20
*/
JDK 源码中的equals()
方法:
// Object类中的equals方法
public boolean equals(Object obj){
return (this == obj);
// 使用引用中的地址直接来进行比较
}
equal()
方法定义在 Object 类中,返回值是 boolean 类型,其作用是比较两个对象在堆区的地址是否相同。示例:
public class Test {
public static void main(String[] args) {
Person person1=new Person("张三",18);
Person person2=new Person("李四",20);
boolean b=person1.equals(person2);
System.out.println(b);
}
}
class Person{
private String name;
private int age;
public Person(String name,int age){
this.name=name;
this.age=age;
}
}
/*
false
*/
需要注意的是比较的是两个引用的值是否相同,即引用执行的地址。如果想要比较对象中的内容,可以重写该方法实现。示例:
public class Test {
public static void main(String[] args) {
Person person1=new Person("张三",18);
Person person2=new Person("张三",18);
boolean b=person1.equals(person2);
System.out.println(b);
}
}
class Person{
private String name;
private int age;
public Person(String name,int age){
this.name=name;
this.age=age;
}
@Override
public boolean equals(Object obj) {
//判断是否为空
if (obj == null) {
return false ;
} if(this == obj) {
return true ;
}
// 不是Person类对象
if (!(obj instanceof Person)) {
return false ;
}
Person per = (Person) obj ; // 向下转型,比较属性值
//此时比较时按照重写后的equal()方法的规则
return this.name.equals(per.name) && this.age==per.age ;
}
}
/*
true
*/
此时,我们重写了equals()
方法,用来比较对象中的内容是否相同,这部分比较难,可以仔细推敲这段代码,理解其含义。
JDK源码中的hashcode()
方法:
public native int hashCode();
hashcode()方法定义在Object类中,用于放回对象的 hash 代码值,确定对象在内存中存储的位置是否相同。
重写该方法使用:
import java.util.Objects;
public class Test {
public static void main(String[] args) {
Person person1=new Person("张三",18);
Person person2=new Person("张三",18);
System.out.println(person1.hashCode());
System.out.println(person2.hashCode());
}
}
class Person{
private String name;
private int age;
public Person(String name,int age){
this.name=name;
this.age=age;
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
/*
24022538
24022538
*/
事实上 hashCode() 在散列表中才有用,在其它情况下没用,在散列表中hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。
重写 equals() 方法时,也必须重写 hashcode() 方法吗?
答:必须,hashCode 和 equals 两个方法是用来协同判断两个对象是否相等的,采用这种方式的原因是可以提高程序插入和查询的速度,当重写equals方法后有必要将hashCode方法也重写,这样做才能保证不违背hashCode方法中相同对象必须有相同哈希值
的约定。
== 和 equals 的区别是什么?
答:对于基本类型和引用类型 == 的作用效果是不同的,如下所示:
基本类型:比较的是值是否相同;
引用类型:比较的是引用是否相同
例如在比较两个字符串时:
public class Test {
public static void main(String[] args) {
String s1=new String("HelloWorld");
String s2=new String("HelloWorld!");
String s3="HelloWorld";
System.out.println(s1.equals(s2));
System.out.println(s1.equals(s3));
}
}
运行结果是
false
true
为什么会出现这样的结果呢?这里就引出了一个新的概念,字符串常量值。字符串有两种赋值方式,一种是字面值的方式赋值,另一种是 new 一个新的对象,这两种方式在性能和内存方面都存在差异。
当使用字面值的方式创建一个对象时,JVM 会在字符串常量池中寻找是否存在这个对象 "HelloWorld"
,如果不存在,则创建这个对象,并将这个对象的引用地址返回给字符串常量 s3,如果存在,则不创建对象,直接返回池中这个对象的地址。这样我们就不难理解上面这段的代码为什么会出现这样的情况了!
Object 类是 Java 默认提供的一个类,是所有 Java 类的祖先类,每个类都使用Object作为父类。Object 类中提供了一些方法,这些方法为了达到想要的效果,我们一般在类中重写使用!
欢迎订阅学习Java编程进阶之路专栏,专栏文章持续更新!