Object根父类
如何理解根父类
类 java.lang.Object是类层次结构的根类,即所有类的父类。每个类都使用 Object 作为超类。
Object类型的变量与除Object以外的任意引用数据类型的对象都多态引用
所有对象(包括数组)都实现这个类的方法。
如果一个类没有特别指定父类,那么默认则继承自Object类。例如:
public class MyClass /*extends Object*/ {
// ...
}
Object类的API
API(Application Programming Interface),应用程序编程接口。Java API是一本程序员的字典 ,是JDK中提供给我们使用的类的说明文档。所以我们可以通过查询API的方式,来学习Java提供的类,并得知如何使用它们。在API文档中是无法得知这些类具体是如何实现的,如果要查看具体实现代码,那么我们需要查看src源码。
根据JDK源代码及Object类的API文档,Object类当中包含的方法有12个。我只记录了几个常用的方法,详细的自己可以去看源码。
equals()方法
public boolean equals(Object obj):用于判断当前对象this与指定对象obj是否“相等”
①默认情况下,equals方法的实现等价于与“==”,比较的是对象的地址值
②我们可以选择重写,重写有些要求:
A:如果重写equals,那么一定要一起重写hashCode()方法,因为规定:
a:如果两个对象调用equals返回true,那么要求这两个对象的hashCode值一定是相等的;
b:如果两个对象的hashCode值不同的,那么要求这两个对象调用equals方法一定是false;
c:如果两个对象的hashCode值相同的,那么这个两个对象调用equals可能是true,也可能是false
B:如果重写equals,那么一定要遵循如下几个原则:
a:自反性:x.equals(x)返回true
b:传递性:x.equals(y)为true, y.equals(z)为true,然后x.equals(z)也应该为true
c:一致性:只要参与equals比较的属性值没有修改,那么无论何时调用结果应该一致
d:对称性:x.equals(y)与y.equals(x)结果应该一样
e:非空对象与null的equals一定是false
class User{
private String host;
private String username;
private String password;
public User(String host, String username, String password) {
super();
this.host = host;
this.username = username;
this.password = password;
}
public User() {
super();
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User [host=" + host + ", username=" + username + ", password=" + password + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((host == null) ? 0 : host.hashCode());
result = prime * result + ((password == null) ? 0 : password.hashCode());
result = prime * result + ((username == null) ? 0 : username.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (host == null) {
if (other.host != null)
return false;
} else if (!host.equals(other.host))
return false;
if (password == null) {
if (other.password != null)
return false;
} else if (!password.equals(other.password))
return false;
if (username == null) {
if (other.username != null)
return false;
} else if (!username.equals(other.username))
return false;
return true;
}
}
==和equals()方法的区别
一、==的使用
== :运算符
1.即可以用于比较两个基本数据类型的变量,也可以用于比较两个引用数据类型的变量当中。
2.如果比较的是基本数据类型的变量:比较的是两个变量保存的数据是否相等。(不一定类型相同)
如果比较的是引用数据类型的变量:比较的是两个对象在内存中存储的地址值是否相同,即两个引用是否指向同一个对象实体。
二、equals()方法的使用
1.是一个方法,而非运算符。
2.只能用于比较引用数据类型的变量。
3.Object类中equals()的定义:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
说明:
Object类中定义的equals()和==的作用是相同的:比较的是两个对象在内存中存储的地址值是否相同,
即两个引用是否指向同一个对象实体。
4.像String、Date、File、包装类等都重写了Object中的equals()方法。重写以后,比较的不是两
个引用的地址是否相同,而是比较的两个对象的"实体内容"是否相同。
5.通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体类容"是否相同。
那么我们就需要对Object类中的equals()方法进行重写。
重写的原则:比较两个对象的实体内容是否相同。
总结:
==和equals的区别?
“==”是运算符,如果是基本数据类型变量间的比较,则比较存储的值;如果是引用数据类型间的比较,则比较该对象在堆中存储的内存地址。
equals()是Object的方法。
equals ()方法不能用于比较基本数据类型,如果没有对 equals 方法进行重写,则相当于“==”,比较的是内存地址,
如果重写了就是比较存储的实际内容是否相等。
toString()方法
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
①默认情况下,toString()返回的是“对象的运行时类型 @ 对象的hashCode值的十六进制形式"
②通常是建议重写,如果在eclipse中,可以用Alt +Shift + S-->Generate toString()
③如果我们直接System.out.println(对象),默认会自动调用这个对象的toString()
④像String、Date、File、包装类等都重写了Object类中的toString()方法。
使得在调用对象的toString()时,返回的是"实体内容"信息。而不是地址值。
⑤自定义类也可以重写toString()方法,当调用此方法时,返回的是对象的"实体内容",而非地址值。
因为Java的引用数据类型的变量中存储的实际上是对象的内存地址,但是Java对程序员隐藏内存地址信息,所以不能直接将内存地址显示出来,所以当你打印对象时,JVM帮你调用了对象的toString()。
例如自定义的Person类:
public class Person {
private String name;
private int age;
@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
}
// 省略构造器与Getter Setter
}
getClass()方法
public final native Class<?> getClass();
获取对象的运行时类型
因为Java有多态现象,所以一个引用数据类型的变量的编译时类型与运行时类型可能不一致,因此如果需要查看这个变量实际指向的对象的类型,需要用getClass()方法
public static void main(String[] args) {
Object obj = new String();
System.out.println(obj.getClass());//运行时类型
}
finalize()方法
protected void finalize() throws Throwable { }
public class TestFinalize {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyData my = new MyData();
}
System.gc();//通知垃圾回收器来回收垃圾
try {
Thread.sleep(2000);//等待2秒再结束main,为了看效果
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyData{
@Override
protected void finalize() throws Throwable {
System.out.println("轻轻的我走了...");
}
}
对finalize()的理解?
当对象被GC确定为要被回收的垃圾,在回收之前由GC帮你调用这个方法,不是由程序员手动调用。
这个方法与C语言的析构函数不同,C语言的析构函数被调用,那么对象一定被销毁,内存被回收,而finalize方法的调用不一定会销毁当前对象,因为可能在finalize()中出现了让当前对象“复活”的代码
每一个对象的finalize方法只会被调用一次。
子类可以选择重写,一般用于彻底释放一些资源对象,而且这些资源对象往往是通过C/C++等代码申请的资源内存
hashCode()方法
public native int hashCode();//返回对象的哈希码值
hashCode 的常规协定:
如果两个对象的hash值是不同的,那么这两个对象一定不相等;
如果两个对象的hash值是相同的,那么这两个对象不一定相等。
主要用于后面当对象存储到哈希表等容器中时,为了提高存储和查询性能用的。
native关键字的使用
native:本地的,原生的用法:
只能修饰方法
表示这个方法的方法体代码不是用Java语言实现的,而是由C/C++语言编写的。
但是对于Java程序员来说,可以当做Java的方法一样去正常调用它,或者子类重写它。
JVM内存的管理:
区域名称 | 作用 |
程序计数器 | 程序计数器是CPU中的寄存器,它包含每一个线程下一条要执行的指令的地址 |
本地方法栈 | 当程序中调用了native的本地方法时,本地方法执行期间的内存区域 |
方法区 | 存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。 |
堆内存 | 存储对象(包括数组对象),new来创建的,都存储在堆内存。 |
虚拟机栈 | 用于存储正在执行的每个Java方法的局部变量表等。局部变量表存放了编译期可知长度的各种基本数据类型、对象引用,方法执行完,自动释放。 |
外部类 | 成员变量 | 代码块 | 构造器 | 方法 | 局部变量 | |
public | √ | √ | × | √ | √ | × |
protected | × | √ | × | √ | √ | × |
private | × | √ | × | √ | √ | × |
static | × | √ | √ | × | √ | × |
final | √ | √ | × | × | √ | √ |
abstract | √ | × | × | × | √ | × |
native | × | × | × | × | √ | × |
不能和abstract一起使用的修饰符?
(1)abstract和final不能一起修饰方法和类
(2)abstract和static不能一起修饰方法
(3)abstract和native不能一起修饰方法
(4)abstract和private不能一起修饰方法
static和final一起使用:
(1)修饰方法:可以,因为都不能被重写
(2)修饰成员变量:可以,表示静态常量
(3)修饰局部变量:不可以,static不能修饰局部变量
(4)修饰代码块:不可以,final不能修改代码块
(5)修饰内部类:可以一起修饰成员内部类,不能一起修饰局部内部类