网站首页 > java教程 正文
楠哥最近出了一本书《Java零基础实战》,这本书中整合了我多年的一线研发经验,包括我对一些技术点的理解,可能与其他书籍讲解的角度略有不同,但一定可以帮助你更好地应用这些技能点。
本书的最大特点就是实用,全书包括近 300 段代码示例,5 个项目实战案例,让每个核心知识点落地,不再只是理论上的叙述,让读者真正掌握其实际应用。今天截取书中的一部分内容,供大家试读,如果你觉得不错就下单吧,详见文末。
第5章 面向对象进阶
在前面的章节中我们学习了面向对象思想的基本概念,对面向对象的三大特征(封装、继承和多态)都做了详细的阐述,相信大家对这些概念已经有了一定的理解和掌握。面向对象更重要的是理解其编程思想,具备把程序模块化成对象的能力,思想的建立需要不断地思考,勤加练习,本章我们继续学习面向对象的高级部分。
5.1 Object类
5.1.1 认识Object类
Java是通过类来构建代码结构的,类分为两种:一种是Java提供的,无需开发者自定义,可直接调用;另外一种是由开发者根据不同的业务需求自定义的类。所以我们写的Java程序,其实就是由Java提供的类和自定义的类组成的,打开Eclipse,在JRESystem Library中存放的就是Java提供的类,开发者自定义的类存放在src目录下,如图5-1和图5-2所示。
图5-1
图5-2
JRE SystemLibrary中的类全部是编译之后的字节码文件,即class格式的文件,我们可以看到源码,但是不能修改,如图5-3所示。
图5-3
Object就是Java提供的一个类,位于java.lang包中,该类是所有类的直接父类或间接父类。无论是Java提供的类,还是开发者自定义的类,都是Object的直接子类或间接子类。或者说Java中的每一个类都是Object的后代,Object是所有类的祖先。一个类在定义时如果不通过extends指定其直接父类,系统就会自动为该类继承Object类,Object类的源码如代码5-1所示。
代码5-1: public class Object { private static native void registerNatives(); static { registerNatives(); } public final native Class<?> getClass(); public native int hashCode(); public boolean equals(Object obj) { return (this == obj); } protected native Object clone() throws CloneNotSupportedException; public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } public final native void notify(); public final native void notifyAll(); public final native void wait(long timeout) throws InterruptedException; public final void wait(long timeout, int nanos) throws InterruptedException { if (timeout < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException( "nanosecond timeout value out of range"); } if (nanos > 0) { timeout++; } wait(timeout); } public final void wait() throws InterruptedException { wait(0); } protected void finalize() throws Throwable { } }
可以看到Object类中提供了很多用public和protected修饰的方法,子类是可以直接继承这些方法的,即Java中的任何一个类,都可以调用Object类中的public和protected方法,当然private是不能调用的,如图5-4所示。
图5-4
5.1.2 重写Object类的方法
上一节我们介绍了Object是所有类的父类,每一个类都可以直接继承Object类的非私有方法,实例化对象可以直接调用这些方法。但是通常情况下不会直接调用这些方法,而是需要对它们进行重写,因为父类中统一的方法并不能适用于所有的子类。就像老爹房子的装修风格是老爹喜欢的,儿子们审美各有不同,老爹的房子并不能满足他们的需求,所以儿子们会把房子的旧装修覆盖掉,重新装修以适应他们的需求。这种方式是多态的一种体现,父类信息通过不同的子类呈现出不同的形态,接下来我们就一起看看Object类经常被子类所重写的那些方法,如表5-1所示。
先来看看这3个方法的具体实现,toString()方法的实现如图5-5所示。
图5-5
原生的toString()方法会返回对象的类名以及散列值,直接打印对象默认调用toString()方法,如代码5-2所示。
代码5-2: public class Test { public static void main(String[] args) { People people = new People(); people.setId(1); people.setName("张三"); people.setAge(22); people.setGender('男'); System.out.println(people); } }
程序的运行结果如图5-6所示。
图5-6
但是在实际开发中返回这样的信息意义不大,我们更希望看到的是对象的属性值,而非它的内存地址,所以我们需要对toString()方法进行重写,如代码5-3所示。
代码5-3: public class People { …… @Override public String toString() { return "People [id=" + id + ", name=" + name + ", age=" + age + ", gender=" + gender + "]"; } } public class Test { public static void main(String[] args) { People people = new People(); people.setId(1); people.setName("张三"); people.setAge(22); people.setGender('男'); System.out.println(people); } }
程序的运行结果如图5-7所示。
图5-7
equals()方法的实现如图5-8所示。
图5-8
通过内存地址对两个对象进行判断,即两个对象的引用必须指向同一块内存程序才会认为它们相等,但是在不同的场景下,这种方式不见得都适用。比如两个字符串“String str1 = new String(“Hello”);”和“String str2 = new String( “Hello”);”,虽然str1和str2是两个完全不同的对象,但是它们的值是相等的,就可以认为这两个字符串相等。我们需要对equals()方法进行重写,String类已经完成了重写的工作,直接使用即可,重写的代码如代码5-4所示。
代码5-4: 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; }
你可以看到String类中对equals()方法的重写,是将两个字符串中的每一个字符依次取出进行比对,如果所有字符完全相等,则认为两个对象相等,否则不相等,字符串比较的过程如代码5-5所示。
代码5-5: public class Test { public static void main(String[] args) { String str1 = new String("Hello"); String str2 = new String("Hello"); System.out.println(str1.equals(str2)); } }
程序的运行结果如图5-9所示。
图5-9
自定义类也可以根据需求对equals()方法进行重写,如我们定义一个People类,创建该类的实例化对象,认为只要成员变量的值都相等就是同一个人,用程序的语言来表述就是两个对象相等,但是如果直接调用equals()方法进行比较,结果却并不是我们所预期的,如代码5-6所示。
代码5-6: public class People { private int id; private String name; private int age; private char gender; //getter、setter方法 } public class Test { public static void main(String[] args) { People people = new People(); people.setId(1); people.setName("张三"); people.setAge(22); people.setGender('男'); People people2 = new People(); people2.setId(1); people2.setName("张三"); people2.setAge(22); people2.setGender('男'); System.out.println(people.equals(people2)); } }
程序的运行结果如图5-10所示。
图5-10
现在对People类继承自Object类的equals()方法进行重写,如果两个对象的成员变量值都相等,则它们就是同一个对象,具体实现如代码5-7所示。
代码5-7: public class People { @Override public boolean equals(Object obj) { // TODO Auto-generated method stub People people = (People) obj; if(people.getId() == this.id && people.getName().equals(this.name) && people.getGender() == this.gender && people.getAge() == this.age){ return true; } return false; } }
再次运行程序,结果如图5-11所示。
图5-11
hashCode()方法如图5-12所示。该方法返回一个对象的散列值,这个值是由对象的内存地址结合对象内部信息得出的,任何两个对象的内存地址肯定是不一样的。但是在上面举的例子中,我们认为如果两个People对象的成员变量值都相等,就是同一个对象,那么它们的散列值也应该相等,如果直接调用父类的hashCode()方法,两个对象的散列值是不相等的,如代码5-8所示。
图5-12
代码5-8: public class Test { public static void main(String[] args) { People people = new People(); people.setId(1); people.setName("张三"); people.setAge(22); people.setGender('男'); People people2 = new People(); people2.setId(1); people2.setName("张三"); people2.setAge(22); people2.setGender('男'); System.out.println(people.hashCode()); System.out.println(people2.hashCode()); } }
程序的运行结果如图5-13所示。
图5-13
现在对People的hashCode()方法进行重写,将id*name*age*gender的值作为结果返回,name是字符串类型,值相等散列值就相等,具体实现如代码5-9所示。
代码5-9: public class People { …… @Override public int hashCode() { return this.id*this.name.hashCode()*this.age*this.gender; } }
再次运行程序,结果如图5-14所示。
图5-14
如此一来,成员变量值都相等的两个People对象,散列值也是相等的。
以上内容,摘自《Java零基础实战》一书,还没有购买的小伙伴可以在当当或京东,搜索“Java零基础实战”直接购买。
关注微信公众号「Java大联盟」,关注即可获取海量学习干货,同时还有不定期送书,键盘,鼠标等粉丝福利。
猜你喜欢
- 2024-10-21 从零学java笔录-第39篇 基础第二阶段 1 面向对象思想及概述
- 2024-10-21 C/C++编程笔记:C++面向对象和Java面向对象的区别
- 2024-10-21 面向对象—java中类与对象#java基础
- 2024-10-21 Java面向对象特征(java的面向对象特征)
- 2024-10-21 Java基础语法之面向对象(java中的面向对象)
- 2024-10-21 Java面向对象概念解析(java面向对象的意思)
- 2024-10-21 java中的面向对象总结(java中的面向对象总结法是什么)
- 2024-10-21 有图有码,带你重新认识java面向对象三大特性!
- 2024-10-21 java面向对象总结(java面向对象知识点总结)
- 2024-10-21 Java基础:Java面向对象的特征(java面向对象的主要特征)
你 发表评论:
欢迎- 07-21如何将 iPhone 中的联系人导出到 Excel/CSV?
- 07-21sql查询的字段数据中有逗号。放到csv文件会分开,如何解决?
- 07-21在 WebAPI 里生成 csv zip 文件(webapi怎么发布在iis上)
- 07-21如何把csv格式转换成Excel格式(csv格式怎么转换)
- 07-21如何将高程导出为XYZ或CSV高程点(如何将高程数据导入cad)
- 07-21使用python把csv汇总成excel(python怎么将csv文件中的列存入列表)
- 07-21解决PHP导出CSV文件中文乱码问题(php导出excel文件)
- 07-21使用vba将Excel 文件转成 CSV 文件
- 最近发表
-
- 如何将 iPhone 中的联系人导出到 Excel/CSV?
- sql查询的字段数据中有逗号。放到csv文件会分开,如何解决?
- 在 WebAPI 里生成 csv zip 文件(webapi怎么发布在iis上)
- 如何把csv格式转换成Excel格式(csv格式怎么转换)
- 如何将高程导出为XYZ或CSV高程点(如何将高程数据导入cad)
- 使用python把csv汇总成excel(python怎么将csv文件中的列存入列表)
- 解决PHP导出CSV文件中文乱码问题(php导出excel文件)
- 使用vba将Excel 文件转成 CSV 文件
- python爬虫25 | 爬取的数据怎么保存?CSV了解一下
- MySQL 导出数据(mysql 导出数据 判断成功)
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)