摘要:如果我们想要多次输出类中的成员信息,就需要多次书写方法每用一次就得写而调用就简单多了补充两者等价输出结果。注一般选择重写方法,比较对象的成员变量值是否相同,不过一般重写都是自动生成。
第三阶段 JAVA常见对象的学习 第一章 常见对象——Object类 引言:
在讲解Object类之前,我们不得不简单的提一下什么是API,先贴一组百度百科的解释:
API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。
简单的说:就是 Java 中有好多现成的类库,其中封装了许多函数,只提供函数名和参数,但隐藏了函数的具体实现,这些可见的部分作为与外界联系的桥梁,也就是我们所称的 API ,不过由于Java是开源的,所以这些隐藏的实现我们也是可以看到的。
(一) Object 类的概述(1) Object是类层次结构的根类,所有的类都隐式的(不用写extends)继承自Object类。
(2) Java 所有的对象都拥有Object默认方法
(3) Object类的构造方法有一个,并且是无参构造
这就对应了前面学习中的一句话,子类构造方法默认访问父类的构造是无参构造
我们需要了解的方法又有哪些呢?
A: hashCode() B: getClass() C: finalize() D: clone
E: notify() F: notifyAll()
我们需要掌握的方法又有哪些呢?
A: toString() B: equals()
(1) hashCode返回对象的哈希值(散列码),不是实际地址值,不过可以理解为地址值。
它实际上返回一个int型整数,用于确定该对象在哈希表中的索引位置
暂时了解即可,学习集合框架内容后将会专篇深入学习
//Student类 public class Student extends Object { }
//StudentDemo类 public class StudentDemo { public static void main(String[] args) { Student s1 = new Student(); System.out.println(s1.hashCode()); Student s2 = new Student(); System.out.println(s2.hashCode()); Student s3 = s1; System.out.println(s3.hashCode()); } } //运行结果: 460141958 1163157884 460141958(2) getClass
返回对象的字节码文件对象,在反射篇章详细解释, 暂做简单了解。
public class StudentDemo { public static void main(String[] args) { Student s = new Student(); Class c = s.getClass(); String str = c.getName(); System.out.println(str); //链式编程 String str2 = s.getClass().getName(); System.out.println(str2); } } //运行结果 cn.bwh_02_getClass.Student cn.bwh_02_getClass.Student(3) finalize()
在对象将被垃圾回收器清除前调用,但不确定时间,并且对象的finalize()方法只会被调用一次,调用后也不一定马上清除该对象。
(4) clone()以实现对象的克隆,包括成员变量的数据复制,但是它和两个引用指向同一个对象是有区别的。
我们先来解释一下后半句话
如果我们想要复制一个变量,可以这样做 Eg:
int a = 20; int b = a;
那么我们想要复制一个对象,是不是也可以这样做呢?
//Student public class Student { int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
//StudentDemo public class StudentDemo { public static void main(String[] args) { Student s1 = new Student(); s1.setAge(20); Student s2 = s1;//将引用赋值 System.out.println("学生1年龄:" + s1.getAge()); System.out.println("学生2年龄:" + s2.getAge()); System.out.println("------------------------------"); s2.setAge(25); System.out.println("学生1年龄:" + s1.getAge()); System.out.println("学生2年龄:" + s2.getAge()); } } //运行结果 学生1年龄:20 学生2年龄:20 --------------------------- 学生1年龄:25 学生2年龄:25
很明显,即使将对象s1赋值给对象s2,但是通过set传值的时候,两者仍然会同时变化,并没有起到克隆(独立)的作用,这是因为赋值时只是将存储在栈中,对对象的引用赋值,因此它们两个的引用指向同一个对象(堆中),所以无论如何赋值,只要堆中的对象属性发生了变化,通过引用显示属性的时候,均是相同的。
实现Cloneable接口
重写clone方法
浅拷贝: 仅拷贝对象,不拷贝成员变量,仅复制了变量的引用,拷贝前后变量使用同一块内存,内存销毁后,必须重新定义(两者同生共死)深拷贝: 不仅拷贝对象,也拷贝成员变量(真正意义上的复制, 两者独立无关)
//浅拷贝 public class Person implements Cloneable{ private int age = 20; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
//深拷贝 public class Person implements Cloneable { public int age = 20; @Override protected Object clone() throws CloneNotSupportedException { //拷贝对象 Person person = (Person) super.clone(); //拷贝成员变量 person.age = (int) age.clone(); //返回拷贝对象 return person; } }
我们来利用浅拷贝解决刚开始那个问题
//Person类,写出get、set方法、重写clone方法 //PersonDemo类 public class PersonDemo { public static void main(String[] args) throws CloneNotSupportedException { Person p1 = new Person(); p1.setAge(20); Person p2 = (Person) p1.clone(); System.out.println("第一个人的年龄:"+ p1.getAge() ); System.out.println("第二个人的年龄:"+ p2.getAge() ); System.out.println("--------------------------"); p2.setAge(25); System.out.println("第一个人的年龄:"+ p1.getAge() ); System.out.println("第二个人的年龄:"+ p2.getAge() ); } } 运行结果: 第一个人的年龄:20 第二个人的年龄:20 -------------------------- 第一个人的年龄:20 第二个人的年龄:25(5) wait、notify和notifyAll
三者属于线程通信间的Api,此部分放在日后讲
(6) toString()——重要public static toString(): 返回该对象的字符串表示
//Student类 public class Student { private String name; public int 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; } }
//StudentDemo类 package cn.bwh_04_toString; public class StudentDemo { public static void main(String[] args) { Student s = new Student(); s.setName("admin"); s.setAge(20); //直接输出s也会默认的调用toString方法 System.out.println(s.toString()); } } //通过set方法赋值后,直接调用toString() 运行结果: cn.bwh_04_toString.Student@1b6d3586
很明显,给我们返回这样的信息意义是不大的,所以我们建议对所有子类重写该方法
//在Student类中重写 toString() @Override public String toString() { return "Student[" + "name=" + name + ", " + "age=" + age + "]"; //运行结果: Student[name=admin, age=20]
通过重写toString后,结果按照我们所定的规则以字符串的形式输出
(重写后会优先使用类中的toString方法)
主要目的还是为了简化输出
在类中重写toString()后,输出类对象就变得有了意义(输出s 和 s.toString()是一样的 ,不写也会默认调用),变成了我们实实在在的信息,而不是上面的cn.bwh_04_toString.Student@1b6d3586。
如果我们想要多次输出 类中的成员信息,就需要多次书写get方法(每用一次就得写)
System.out.println("Student[" + "name=" + s.getName() + ", " + "age=" + s.getAge() + "]");
而调用toString()就简单多了
//两者等价 toString(); getClass().getName()+ "@" + Integer.toHexString(hashCode()) //输出结果 cn.bwh_04_toString.Student@1b6d3586。(7) equals()——重要
比较两个对象是否相同
默认情况下,比较的是地址值是否相同。
而比较地址值是没有意义的,所以,一般子类也会重写该方法。
在诸多子类,如String、Integer、Date 等均重写了equals()方法
改进思路:
我们可以将比较地址值转变为比较成员变量
因为name为String类型,而String类型为引用类型,所以不能够用==比较,应该用equal()
String中默认重写过的equal()方法是用来比较字符串内容是否相同
我们要使用的是学生类的成员变量,所以父类 Object不能调用子类Student的特有功能
所以使用向下转型
//重写v1.0 public boolean equals(Object o) { Student s = (Student) o; if (this.name.equals(s.name) && this.age == s.age) { return true; } else { return false; } }
//重写v2.0 (可作为最终版) public boolean equals(Object o) { if (this.name == o) { return true; } //测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型。 if (!(o instanceof Student)) { return false; } Student s = (Student) o; return this.name.equals(s.name) && this.age == s.age; }
//idea自动生成版 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; return age == student.age && Objects.equals(name, student.name); }
== 的作用:
基本类型:比较值是否相同
引用类型:比较的就是堆内存地址是否相同
equals 的作用:
引用类型:默认情况下,比较的是地址值。
注:一般选择重写方法,比较对象的成员变量值是否相同 ,不过一般重写都是自动生成。
结尾:如果内容中有什么不足,或者错误的地方,欢迎大家给我留言提出意见, 蟹蟹大家 !^_^
如果能帮到你的话,那就来关注我吧!(系列文章均会在公众号第一时间更新)
在这里的我们素不相识,却都在为了自己的梦而努力 ❤一个坚持推送原创Java技术的公众号:理想二旬不止
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/74865.html
摘要:采用完全独立于任何程序语言的文本格式,使成为理想的数据交换语言为什么需要提到,我们就应该和来进行对比。也是一种存储和交换文本信息的手段。那么好在哪里呢比更小更快,更易解析。使用的时候,也支持将转成但是,我们不一定使用框架来做开发呀。 什么是JSON JSON:JavaScript Object Notation 【JavaScript 对象表示法】 JSON 是存储和交换文本信息的语法...
摘要:前言上一次我们对的应用进行了一次全面的分析,这一次我们来聊聊。 showImg(https://segmentfault.com/img/remote/1460000020077803?w=1280&h=853); 前言 上一次我们对Paging的应用进行了一次全面的分析,这一次我们来聊聊WorkManager。 如果你对Paging还未了解,推荐阅读这篇文章: Paging在Recy...
摘要:目录前言架构安装第一个爬虫爬取有道翻译创建项目创建创建解析运行爬虫爬取单词释义下载单词语音文件前言学习有一段时间了,当时想要获取一下百度汉字的解析,又不想一个个汉字去搜,复制粘贴太费劲,考虑到爬虫的便利性,这篇文章是介绍一个爬虫框架, 目录 前言 架构 安装 第一个爬虫:爬取有道翻译 创建项目 创建Item 创建Spider 解析 运行爬虫-爬取单词释义 下载单词语音文件 ...
摘要:前言由于写的文章已经是有点多了,为了自己和大家的检索方便,于是我就做了这么一个博客导航。 前言 由于写的文章已经是有点多了,为了自己和大家的检索方便,于是我就做了这么一个博客导航。 由于更新比较频繁,因此隔一段时间才会更新目录导航哦~想要获取最新原创的技术文章欢迎关注我的公众号:Java3y Java3y文章目录导航 Java基础 泛型就这么简单 注解就这么简单 Druid数据库连接池...
摘要:丰富的特性还支持通知过期等等特性。到这个就说明测试通过了。主要针对方法配置,能够根据方法的请求参数对其进行缓存,常用于查询操作主要针对方法配置,能够根据方法的请求参数对其进行缓存,常用于修改操作清空缓存,主要用于删除操作。 [TOC] Redis简介 Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存亦可持久化的日志型、Key-Value 数...
阅读 631·2021-11-22 15:32
阅读 2720·2021-11-19 09:40
阅读 2312·2021-11-17 09:33
阅读 1263·2021-11-15 11:36
阅读 1864·2021-10-11 10:59
阅读 1475·2019-08-29 16:41
阅读 1779·2019-08-29 13:45
阅读 2149·2019-08-26 13:36