instanceof
格式
对象 instanceof 类型:判断这个对象是不是这个类型的对象,如果是,输出true
System.out.println(A instanceof B);
其中A为一个对象,B表示一个类或者一个接口,当 A为B的对象,或者是其直接或间接子类,或者是其接口的实现类,则输出true,否则输出false。 (使用instanceof关键字做判断时, instanceof 操作符的左右操作数必须有继承或实现关系 )
-
如果A是基础数据类型则直接编译不通过(instanceof 运算符只能用作对象的判断)
-
如果A为null,则直接返回false(java的一种规范)
-
在判断某个类或接口的对象是不是其他类(或接口)的实例,一定要首先进行向上转型,然后才可用instanceof关键字进行判断,这是基本操作规范。
一般在写类型强转时,不确定当前拿到的对象类型是什么,只是有一个猜测,所以在这里就判断一下,把猜测的类型输入到后面,如果true就可以转
if(usb1 instanceof USBImpl) {
(USBImpl)usb1
}
Object
- Object是所有类的父类,所有类都默认继承他
- Object有一个空的无参的构造方法,所以任何类都默认有一个无参的构造方法
- 任何一个类都是Object的子类,任何一个对象都是Object的对象
下面主要来看一下Object的源码里的一些方法
1.toString()方法
public class ObservObject {
@Override //注解,有意义,只有在父类里有这个方法才不抛错
public String toString() { //Object的toString方法
//return super.toString();//这里的super代表的就是Object的,而Object里的这个方法什么都没干
return "我是ObservObject";
}
}
场景类
public class Main {
public static void main(String[] args) {
ObservObject observObject = new ObservObject();
// System.out.println(observObject);//括号里的observObject默认调用toString方法,即observObject.toString()。在ObservObject类重写toString方法之前,则调用的是Object的toString方法,会输出一串“数字”
System.out.println(observObject);//重写后输出:我是ObservObject
}
}
给一个场景,要计算的a+b算出来结果是错的,我不知道到底是传的参数是错的还是方法是错的,就可以用toString输出检查一下。
class ObservObject {
private int age = 3;
private int height = 4;
public int sum() {
return 8;
}
@Override
public String toString() {
return "我是ObservObject:"+"age是:"+age+","+"weight是:"+weight;
}
}
public class Main {
public static void main(String[] args) {
ObservObject observObject = new ObservObject();
System.out.println(observObject);//输出:我是ObservObject:age是:3,weight是:4 你可以根据这个判断
}
}
//上面的toString格式其实可以不用自己写,可以用工具自动生成(右键点击Generate),这样可以方便调试代码
2.equals()方法
父类有equals方法,但默认比较的是地址。但是为啥我们前面学的equals比较的是内容呢,这是因为所有类都默认继承Object类,当时我们调用的equals方法是String类重写的equals方法,String类的源码里写的是比较的内容
下面我们新建一个类,重写一下父类的equals方法,来实现他的内容比较
public class ObservObject {
private int a;
private int b;
public ObservObject(int a, int b) {
this.a = a;
this.b = b;
}
@Override
public boolean equals(Object obj) {
// return true;如果直接这样写,那么只要调用ObserveObject的equals方法都会返回ture;
if(this == o) {
return true;//如果地址相等,则内容一定相等
}
if(o instanceof ObservObject) { //判断一下,如果o不是ObservObject类型的那就不用做强转了,直接返回flase
ObservObject that = (ObservObject)o;
if(this.hashCode() != that.hashCode()) {//这块下面会解释
return false;
}
if(this.a != that.a) { //判断内容
return false;
}
if(this.b != that.b) {
return false;
}
return true;
} else {
return false;
}
}
}
public class Main {
public static void main(String[] args) {
ObservObject oo = new ObservObject(3,4);
ObservObject observObject = new ObservObject(3,4);
System.out.println(oo.equals(observObject));//输出true,如果在ObservObject中没有重写equals方法则返回的是false
}
}
自己写类时最好把equals重写上,除非你不做任何比较,以上还不仅仅是equals方法
3.hashCode()方法
先了解一下哈希
哈希算法:任何一个实现不可逆过程的算法都叫做哈希算法
- hash是一个函数,该函数中的实现就是一种算法,就是通过一系列的算法来得到一个hash值。
- hash函数算出的值:1.不可复原。2.按原来的值再传一次得到的结果不会变
- hashcode就是通过hash函数得来的,通俗的说,就是通过某一种算法得到的,hashcode就是在hash表中有对应的位置。
- hashcode代表对象的地址说的是对象在hash表中的位置,物理地址说的对象存放在内存中的地址
- 对象如何得到hashcode呢? 通过对象的物理地址转换成一个整数,然后该整数通过hash函数的算法就得到了hashcode。这个hashcode的值就是在hash表中对应的位置坐标。
下面重写一下Object类的hashcode方法
public class ObservObject {
private int a;
private int b;
public ObservObject(int a, int b) {
this.a = a;
this.b = b;
}
@Override
public int hashCode() {
//注意,java底层的hashcode不是这样计算的,这里只是实现了一个简单的hashcode算法(与String里面的类似)
int code = 0;
code = code + this.b*31+31;
code = code + this.a*31+31;
return code;
}
}
public class Main {
public static void main(String[] args) {
ObservObject oo = new ObservObject(3,4);
System.out.println(oo);//输出:com.yau.foo.ObservObject@117 这个@后面的数就是hashcode(十六进制表示的)
}
}
hashcode值代表这个对象特征值的编码,通过117不能推出a=3,b=4(不可逆)hashcode可以重复,比如a=4,b=3,算出来的hashcode一样。;
看一下String类中重写的hashcode方法
/*源码*/
public int hashCode() {
int h = hash; //h默认是0
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i]; //这个一直加,溢出来可以循环,字符串有多长都可以算出hashcode值,现在就有可能出现重复,因为int值是有限的,而字符串是无限的,用有限的来表示无限的,一定会发生重复。
}
hash = h;
}
return h;
}
equals方法和hashcode的关系
hashcode 在底层是做相同判断用的。Java里面规定,如果两个对象.equals为true,则他们的hashcode一定要相等(如果hashcode不相等则对象也一定不相等)。但如果两个对象的hashcode相等,不一定要equals返回true,因为很有可能两个对象得hashcode确实相等,而他们的对象确实不相等。总结一句话:equals为true则hashcode一定相等;hashcode相等,equals不一定为true;hashcode不相等则equals一定为false
所以在这里再补充一下上面得.equals方法。代码在上方
为什么equals方法重写的话,建议也一起重写hashcode方法?
比如:有个A类重写了equals方法,但是没有重写hashCode方法,看输出结果,对象a1和对象a2使用equals方法相等,按照上面的hashcode的用法,那么他们两个的hashcode肯定相等,但是这里由于没重写hashcode方法,他们两个hashcode并不一样,所以,我们在重写了equals方法后,尽量也重写了hashcode方法,通过一定的算法,使他们在equals相等时,也会有相同的hashcode值。
hashcode的学习部分参考:https://blog.csdn.net/weixin_38405253/article/details/91922340