第十六讲 java进阶-重写equals方法的深度解读

1 接口的补充

  • 接口为什么不能new对象?有没有必要new对象?或者是说如果能new对象,new出来的是什么东西?有什么内容,是否符合对象的特征?

    • 接口中属性只能是常量,常量并不是对象的成员属性。接口中的方法只能是抽象的方法,没有方法体。
    • 对象要有成员属性,每个对象的成员属性值都不一样。要有成员方法,每个对象的成员方法,对象的引用都能调用。
    • 如果接口能new对象,那么接口对象的属性是没有的,接口对象的方法都是不能执行的。它违背对象的定义。
    • 接口的本身就是一个抽象的定义。
    • 抽象类为什么也不能new对象呢?道理是一样的。一旦抽象类中有抽象方法之后,这个方法不能被对象的引用调用。
  • 关于接口的应用:

public interface IOpen
{// 所有的遥控器都有一个开关电视的功能。遥控器上有开关。能打开电视void open();
} public interface ITV
{// 所有的电视都能播放public void play();
} public class YaoKongQi implements IOpen
{// 万能遥控器// 可以打开小米牌电视,可以打开长虹牌电视,可以打开任何电视private ITV itv;//昨天说的接口也是引用类型// ITV itv,这是接口类型的引用,也是引用类型,我们可以看做是父类型的引用。// 继承:就是扩展。接口说的实现,实现的本质也是扩展。所以,你可以将接口看成是父类。// 这就满足了多态的机制。接口类型的引用指向接口实现类类型的对象。// 这也符合多态的语法机制。public void setTV(ITV itv) {this.itv = itv;}public void open() {itv.play();}
} public class XiaoMiTV implements ITV
{public void play() {System.out.println("小米电视play!!");}
} public class ChangHongTV implements ITV
{public void play() {System.out.println("长虹电视Play");}
}public class Test
{public static void main(String[] args) {XiaoMiTV xmtv = new XiaoMiTV();YaoKongQi ykq = new YaoKongQi();ykq.setTV(xmtv);ykq.open();ChangHongTV chtv = new ChangHongTV();ykq.setTV(chtv);ykq.open();}
}// 面向对象编程的时候,我们要面向抽象,不要面向具体。要面向接口,不要面向具体的实现。
  • 接口隔离

    • 我们知道,接口定义之后,实现类一定要实现接口中所有的抽象方法。
    • 问题来了,如果一个接口,有5个方法,它的某一个实现类只要用到其中的一个,那么另外4个也一定要实现,否则编译都过不去。那么就会造成代码的冗余。
    • 所以,接口要隔离,接口的功能要单一。

2 API 和 API帮助文档

  • 什么是API,什么是API帮助文档

    • API:application programming Interface 说白了API就是SUN公司提供的java源代码
    • API帮助文档,是通过javadoc指令,将java源代码中/** */注释的内容提取出来,形成了这个帮助文档。
    • 以后,我们要用的时候,是直接看API还是用帮助文档?文档
    • 以后我们开发怎么使用SUN公司提供的API呢?导包、调用方法。导包,创建实例(有的甚至不用),然后“.”方法。

3 Object类探究(equals方法深度解读)

@Override : 这是一个注解。加上这个注解的,说明这个方法是父类中的方法,被子类重写了。这个方法的原型在父类中,子类重写了父类的方法。
  • 我们写一个User类,将它作为一个实体类,具体的写法如下:
package com.demo01.pojo;import java.util.Objects;public class User {private int id;private String name;public User() {}public User(int id, String name) {this.id = id;this.name = name;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;User user = (User) o;return id == user.id &&Objects.equals(name, user.name);}@Overridepublic int hashCode() {return Objects.hash(id, name);}
}// 测试类
public class Demo01 {public static void main(String[] args) {User user = new User(100, "张三" );System.out.println(user);User user1 = new User(100, "张三");System.out.println(user1);System.out.println(user.equals(user1));// ?不重写 false 重写后 true//        public boolean equals(Object obj) {//            return (this == obj);
//        }//com.tj.demo01.pojo.User@16d3586// 我们想要看看user这个对象在内存中到底有哪些属性和值,// 但是父类中的toString给我们提供的是com.tj.demo01.pojo.User@16d3586// 这不是我们想要的,因为我们根本看不懂这个东西User@16d3586// 你能判断赋值成功了吗?对象的成员属性有值还是没值,值是多少?这些是我们能看懂的// 怎么办?// 重写父类的toString()方法。}
}

如果我们不重写父类Object中的toString()方法,那么在测试类中我们希望打印对象的引用,所得结果如下:com.tj.demo01.pojo.User@16d3586

对我们而言,我们希望看到对象的属性和赋值情况,而Object类中的toString()方法只是告诉我们对象创建成功。这不符合我们的预期,因此我们需要在User类中重写toString()方法。

在Object类中有很多native修饰的方法,其具体的实现是用C++实现,具体的实现方式可以找资料阅读。但其提供的方法是可以直接调用的。

toString()方法的重写,我们可以通过IDEA来自动生成,也可以根据我们需要的方式进行重写。

Object类是所有类的superclass,因此该类中的所有成员方法都是其他类所产生的对象直接调用的。如果不符合我们的预期,我们可以对其进行重写。

重点介绍Object类中的equals()方法:

Object类中提供的equals(Object obj)方法,具体的实现如下:

public boolean equals(Object obj) {return (this == obj);}
// equals方法的目的是给我们提供比较两个对象是否是一个对象的工具
// Object类中原生的方法实现只能比较两个对象的引用是否相等
// 引用如果相等,说明两个引用指向了同一个对象,这当然是同一个对象
// 如果,一个类的两个对象,拥有同样的属性值,
// 虽然引用不相等,我们也需要将其认定为是相同的对象,是同一个对象
// 那么,Object类中的原生的方式就无法满足我们的需求,因此需要重写
// 一下是重写的equals方法:
@Override
public boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;User user = (User) o;return id == user.id &&Objects.equals(name, user.name);
}// 以上代码满足了我们上述的需求,两个不同引用指向的对象,
// 拥有相同的属性值我们也认定为是相同的对象
// 就好比,一个人的身份证号 和 姓名 与另一个人的身份证号、姓名完全一致
// 我们就可以断定这是同一个人,虽然他可能出现在上海,过段时间出现在北京
// 不管是在上海还是在北京,都是同一个人无疑// 以上代码要如何阅读呢?
// 第一步:我们看返回值类型,boolean 最后的结果一定是布尔值,即相等为true,不等为false
// 第二步:我们看参数列表,形参是Object o,
//      我们要比较的是User类型的对象,传入的实参一定是User类型的对象引用
//      这里就有多态的语法机制,因为User是Object的子类。
//      即:传参的时候是这样做的:Objcet o = new User();
//      这是父类型的引用指向了子类型的对象,这一点至关重要。
//      那么在equals(Object o)方法被调用的时候,实际上传入的是:
//      指向了子类型User对象的父类型引用Object o
//      该equals(Object o)是成员方法,该方法中还有一个隐藏的参数this,是第一个形参
//      它的原型是这样的equals(Object this, Object o);
//      方法的调用者给这个this传实际值,然后同Object o所指向的类型进行比较
// 第三步:我们看方法体。方法体中第一条语句:if (this == o) return true;
//      这就是Object类中原生的equals()方法,它只是判定了两个对象的引用是不是同一个
//      如果是,就表示是同一个对象,这毫无疑问。
//      栈(堆)内存中的两个引用类型的变量指向了堆内存中的同一个对象,
//      这肯定是同一个对象,好比一个人书名叫张三,它的小名叫二狗子,都是同一个人。
//      第二条语句:if (o == null || getClass() != o.getClass()) return false;
//      如果传入的实参为null,为空意味着它还没有指向堆内存中的对象,这当然没得比。
//      如果不为null,说明堆中已经有了一个对象,
//      如果this所代表的对象的类型和传入的实参对象的类型不一样,
//      都不是一个类,那也没得比较。
// 第四步:最重要也是最难懂的一步:User user = (User)o;
//      看懂这一步,说明对向下转型、多态都有了一定的理解。
//      为什么能这么转型?回答清楚这个问题,这个方法的解读就毫无压力了。
//      首先,我们要知道,o所指向的是子类型的对象,因为O是传入的实参
//      我们在第一步中解释了它的由来。Object o = new User();
//      父类型的引用指向了子类型的对象,这是向上转型,自动类型转换。
//      只有在这个前提下,我们才能进行向下转型,也就是说才能将o这个父类型的引用
//      转为子类型的引用,否则无法转。
//      User user = (User)o;
//      这里还要回答另一个问题,就是ClassCastException异常为什么不会发生?
//      我们没有使用instanceof来判定,但这段代码中确保了异常是不会发生的。
//      因为,第三条语句保证了,如果不是一个类型,方法就直接返回false,结束了。
//      所以,我们不用考虑类型的问题。
//      也就是说在类型转换异常的问题处理上,我们又多了一个思路。
//      当然,对于初学者来说,这段代码略显得有些高深。后面再详细讲解。
// 第五步:return id == user.id && Objects.equals(name, user.name);
//      这是最后一条语句,使用了短路与&&
//      这条语句的前局很简单,就是比较两个整型的数据是否相等。
//      如果User这个对象的id属性相等,我们就进行下一步:
//      比较两个String类型的name属性是否相等
//      这一步也蕴含了很多信息,首先我们可以断定,这里调用了一个静态的equals()方法
//      该方法是Objects类中的,是另外一个类。
//      这个类是一个工具类,java.util包下的。因为直接"类名."的方式调用的equals方法
//      经查实,确实是这样的。
//      equals(name, user.name)这个方法的原型如下:
public static boolean equals(Object a, Object b) {return (a == b) || (a != null && a.equals(b));}
//      我们依然看到了这里的两个形参是两个Object类型的引用
//      name 和 user.name作为实际参数值传进来,是怎么回事?
//      这一步理解了,User类中重写的equals()方法阅读也就完成了
//      首先,name 和 user.name是String类型的,String类型也是一个引用类型
//      String没有显式的继承任何类,它的父类是Object
//      这里的这种写法,根本上就是父类型的引用指向子类型对象
//      即 Object a = new String(name);
//      所以如果a,b代表的实参都指向了同一个String类型的对象
//      仔细想,这里a==b指的是a、b同时为空,如果同时为空,id又相等
//      那两个User类型的对象当然是同一个
//      如果a不为空,那么我们再看看,a是否与b相同,
//      这里调用的equals方法本质上调用的是String中重写的equals方法。
//      这就是多态的机制。如果想要了解这里如何做的比较,可以去看String类中
//      重写的equals方法。这里不做赘述。
//      再次解释一下:这里为何调用的是String的equals方法,
//      因为运行时,会先去绑定子类型中重写的方法。
//      补充String中重写的equals方法如下:
public boolean equals(Object anObject) {if (this == anObject) {return true;}if (anObject instanceof String) {String anotherString = (String)anObject;int n = value.length;if (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false;}

第十六讲 java进阶-API相关推荐

  1. Linux性能优化实战学习笔记:第四十六讲=====实战分析

    Linux性能优化实战学习笔记:第四十六讲 一.上节回顾 不知不觉,我们已经学完了整个专栏的四大基础模块,即 CPU.内存.文件系统和磁盘 I/O.以及网络的性能分析和优化.相信你已经掌握了这些基础模 ...

  2. C#锐利体验 第十六讲 映射

    C#锐利体验 南京邮电学院 李建忠(lijianzhong@263.net.cn) 第十六讲 映射 动态类型查询 我们知道,C#编译后的PE文件主要由IL代码和元数据组成,元数据为.NET组件提供了丰 ...

  3. 趣谈网络协议笔记-二(第十六讲上)

    趣谈网络协议笔记-二(第十六讲上) 流媒体协议:如何在直播里看到美女帅哥? 自勉 给岁月以文明,而不是给文明以岁月!--<三体> 在触不到的獠牙上点火--就像不必仰望那星星就能够解决--就 ...

  4. 第四十六讲 设备驱动kobject

    第四十六讲 设备驱动 文章目录 第四十六讲 设备驱动 一.sysfs 1.发展 2.sysfs简介 3.kobject 4.kobj_type 二.设备驱动实验 1.代码 2.Makefile 3.实 ...

  5. 好文章,《李录:现代化十六讲》

    目录 李录先生的<现代化十六讲> 李录是谁 李录谈做人与投资 新的改变 功能快捷键 合理的创建标题,有助于目录的生成 如何改变文本的样式 插入链接与图片 如何插入一段漂亮的代码片 生成一个 ...

  6. MachineLearning(Hsuan-Tien Lin)第十六讲

    三个锦囊妙计 1 Occam's  Razor "如无需要,勿增实体entities must not be multiplied beyond necessity" 就是说要用越 ...

  7. 第五十六讲 pinctrl子系统

    第五十六讲 pinctrl子系统 文章目录 第五十六讲 pinctrl子系统 一.前言 二.iomuxc 节点 1.作用 2.节点信息 3.节点格式 4.引脚配置信息 三.imx_pinctrl和pi ...

  8. java中过滤流_第十四讲 Java中的字节流和过滤流

    第十四讲Java中的字节流和过滤流 主要内容 InputStream和FileInputStream OutputStream和FileOutputStream 文件字节IO流应用举例 过滤流类和常用 ...

  9. 名词解释第二十六讲:热钱包

    这里是王团长区块链学院,与最优秀的区块链人一起成长!今天给大家讲讲热钱包. 点击观看视频教程:名词解释第二十六讲:热钱包 2013年夏天,英国小伙子豪威尔在家大扫除时,扔掉了一块旧硬盘,硬盘里保存着7 ...

最新文章

  1. Global.asax
  2. SMOTE过采样方法
  3. 汇编语言笔记14-端口
  4. 【MM模块】Cycle Counting 周期盘点
  5. 链家java_链家2018春招Java工程师编程题题解
  6. Document Builder: 如何分析rule执行逻辑
  7. MybatisPlus 通用枚举无法正确取值
  8. 数组之间的计算matlab,matlab中的矩阵运算和数组运算方法
  9. mysql密码加强_MySQL密码增强插件
  10. [Ubuntu] 16.04 卸载旧内核并禁止内核更新
  11. Apache Tomcat 官网下载
  12. 2018五大网络小说在线阅读APP推荐
  13. 小米路由器r2d_小米路由器二代R2D怎样设置无线中继模式
  14. spring boot整合SpringSecurity-04 使用jwt的方式认证
  15. SEO个人整理全套学习资料
  16. 利用python模拟ios屏幕点击器_iOS模拟屏幕点击事件
  17. MongoDB——MongoDB安装和增删改查操作
  18. 您的连接并不安全问题的解决
  19. 教你如何打韩文---韩语键盘及打字技巧
  20. 爱的1000+篇文章总结

热门文章

  1. php 生成带有小数的随机数
  2. 2、phpstudy本地搭建网站
  3. 一些鲜为人知的编程真相
  4. 菜鸟网络业务支撑平台
  5. 安川e7变频器接线_西安安川变频器接线图
  6. 网卡设置监听模式,抓取数据包
  7. KFC门店信息获取 爬虫实战
  8. 引擎TA校园招聘: 搜狐畅游 追光者计划简介
  9. 互联网需要70老兵-祝贺杜红超再次创业
  10. 算法补完计划(五) 二分图匹配