day4: 二位数组,递归和传递

二位数组:

1.实质:一维数组的数组

2.初始化格式:

格式1:
数据类型[][] 变量名 = new 数据类型[m][n];
m代表二维数组中一维数组的个数
n代表二维数组中包含的每个一维数组,所能包含的元素个数
格式2:
数据类型[][] 变量名 = new 数据类型[m][];
m表示这个二维数组有多少个一维数组
这一次没有直接给出一维数组的元素个数,可以动态的给出。
(这种存储方式更加灵活)
格式3:
数据类型[][] 变量名 = new 数据类型[][]{{元素…},{元素…},{元素…}};
简化版格式:
数据类型[][] 变量名 = {{元素…},{元素…},{元素…}};

3.二维数组的遍历:
  1. public static void traverse(int[][] array) {
  2. for (int i = 0; i < array.length; i++) {
  3. for (int j = 0; j < array[i].length; j++) {
  4. System.out.print( array[i][j] + " ");
  5. }
  6. System.out.println();
  7. }
  8. }

递归:

1.递归定义:

方法定义中调用方法本身的现象

2.注意事项:

a. 递归一定要有出口, 递归出口,指的是在某种情况下,终止自己调用自己的过程
b.次数不能太多,否则就出现 stack overflow

3.汉诺塔问题(核心思想):

把一个复杂的大规模的问题,分解成若干相似的小规模的子问题,当问题规模,足够小的是时候,我们就可以直接得到小规模问题的解,再把小规模问题的解,组合起来,——> 大规模问题提的解

4.缺点:

当子问题重叠时,会出现重复计算,如斐波那契数列的n项值 f(n) = f(n - 1) + f(n - 2)

  1. /*
  2. 计算汉诺塔问题搬运的次数
  3. */
  4. public static long countHanoi(int n) {
  5. // 递归出口
  6. if (n == 1) {
  7. return 1;
  8. }
  9. return 2 * countHanoi(n - 1) + 1;
  10. }
  11. /*
  12. n:表示待搬运的圆盘的个数
  13. start:表示待搬运的圆盘所在的起始杆的名称
  14. end: 圆盘要搬运到的目标杆的名称
  15. middle: 表示将圆盘从起始杆,搬运到目标杆过程中,所使用的辅助杆的名称
  16. */
  17. public static void hanoi(int n, char start, char end, char middle) {
  18. if (n == 1) {
  19. System.out.println(start + "——>" + end);
  20. return;
  21. }
  22. // 将最大的圆盘的只上的那n-1个圆盘,搬运到辅助杆
  23. hanoi(n - 1, start, middle, end);
  24. // 对于,最大的那一个圆盘的搬运
  25. System.out.println(start + "——>" + end);
  26. // 将在辅助杆上的n-1, 从辅助杆搬运到目标杆即可
  27. hanoi(n - 1, middle, end, start);
  28. }
  29. }

传递:

在java语言中,不管参数的类型,是数组类型,基本数据类型,实际参数和形式参数进行值传递的方式只有一种:实际参数的值 复制一份 赋值给形式参数
参数类型是基本数据类型 值传递
参数类型是引用数据类型(比如数组) 引用传递
所以,实参的值,其实就有两份,调用方法中一份,被调用方法中一份_
1. 当方法的参数是基本数据类型的参数的时候,参数有两份,同时参数对应的数据的值,也有两份
2. 当方法的参数是引用数据类型的时候参数值有两份,但是两个数组类型引用变量,对应的值(数组),只有一个

day5:面向对象基本语法和概念

面向对象基本概念及使用

1.类和对象的关系:

1.类描述了同种类型的对象,在属性和行为上的共同特征
2.类只规定有什么样的属性,有什么样的行为,但是对象的属性的取值是由对象自己决定

对象与对象的关系:
a.不同种类的对象,可能具有不同的属性和不同的行为;
b.同种类型的对象,它们的属性取值可以不同

2.类的定义

1.成员变量:描述对象的属性 定义在类中方法体之外(局部变量:类中方法体之中,或者方法的形式参数)
2.成员方法:描述对象的行为,其方法声明中,少了static修饰符

3.Student类举例

1.定义学生类:分析学生类的属性和行为,根据学生类的的属性和行为来定义学生类
2.创建学生类对象:创建对象,并给具体的学生对象相应的属性赋值
类名 对象名 = new 类名();
3.访问方式:
对象名.成员变量
对象名.成员方法

4.语言层面对类的理解

类定义:类体中包括,成员变量和成员方法
类定义中的数据集合: 成员变量的集合
类中定义的操作集合: 成员方法集合
所以一个类定义,其实就是一种数据类型的定义,是我们自定义的数据类型,这种数据类型,比之于byte,short,int,char不一样
因为,我们自己定义的数据类型 -> 其实是coder的自定义数据类型,所以jvm天生不认识

面向对象特殊语法

1.成员变量与局部变量的区别:

与局部变量对比:
1.定义位置不同(成员变量在类中在方法体外,局部变量在内部)
2.内存中的位置不同(成员变量->堆,局部变量->栈)
3.生命周期不同 (成员变量对象销毁才销毁,局部变量随方法的结束被销毁)
4.初始化值不同(成员变量有对应类型初始值,局部变量必须我们自己赋值)

2.构造方法:

a. 构造方法的方法名,固定 ,构造方法的方法名必须和类名相同
b. 构造方法没有返回值,在方法声明中,也没有返回值类型声明

特点:

1.可以重载
2.默认有一种无参构造,但定义构造方法后默认的无参构造消失

3.关键字this

1.this关键字:代表对当前对象的引用

  1. 1. this关键字出现在构造体的时候:构造方法执行的时候,正在创建对象,此时this表示当前构造方法执行的时候,正在创建的那个对象
  2. 1. this关键字出现在普通成员方法中的时候:
  3. 1. 对于一个普通成员,我们只能通过 对象名. 的访问成员方法
  4. 1. 在对象上,访问普通成员的方法,this所表示的当前对象,就是哪个类的对象

2.this关键字的作用:

  1. 1. 解决了成员变量被隐蔽了的问题(当成员变量和局部变量同名是,会优先访问局部变量)
  2. 1. 访问对象的成员
  3. 1. 访问对象的构造方法:
  4. 1. 语法 this(要调用的构造方法的实参列表)
  5. 1. 利用this调用构造方法的语句,必须处于构造方法的方法体中,第一条语句的位置

4.关键字static

1.static关键字:可以修饰成员变量和成员方法

  1. 1. static修饰的变量:静态变量
  2. 1. static修饰的方法:静态方法

2.static关键字的特点:

  1. 1. static修饰成员变量:该成员变量的值不再存储与对象中,而是单独存储一份,被类的所有对象所共享
  2. 1. static修饰成员方法:该方法被当前类的所有对象共享

3.访问static

  1. 1. 可以通过类名直接访问,static变量
  2. 1. 可以通过类名直接调用,static成员方法

4.static变量和方法的创建时间

  1. 1. static成员变量,随着类加载完毕就已经在方法区中,分配了内存,并赋予了初值
  2. 1. static成员方法,一旦类加载完毕就可以直接访问static方法,(通过类名),而不必等待创建类的对象

5.优先于对象而存在(不依赖于对象而存在)

  1. 1. 静态变量:
  2. 1. 从成员变量的角度,static修饰的成员变量,不依赖于对象而存在(static成员变量的值在该类的每个对象中)
  3. 1. 没有被static修饰的成员变量,都依赖于对象而存在,因为他们的值,都存储在对象中
  4. 2. 静态方法:
  5. 1. 成员方法的角度,被static修饰的成员方法,在没有对象存在的情况下,也可以通过类名来调用对象访问
  6. 1. 没有被static修饰的,普通成员的方法,都依赖于对象存在

6.注意事项:
静态方法的方法体中,不能访问非静态的成员变量或非静态的成员方法。但我们可以在静态方法的方法体中,在我们自己创建的出的对象上,访问其非静态成员变量和非静态成员方法。
7.使用场景:

  1. 1. 静态变量,实现成员变量共享的特征,此时可将成员变量定义为静态变量
  2. 1. 当我们想要定义,被人使用的工具方法的时候,为了方便别人调用,可以将该方法定义为静态方法。

8.静态成员变量和普通成员变量的区别

  1. 1. 所属不同
  2. 1. 静态变量属于类,也称为类变量
  3. 1. 成员变量属于对象,也称为实例变量
  4. 2. 内存中的位置不同
  5. 1. 静态变量存储在方法区
  6. 1. 成员变量处于堆内存中
  7. 3. 内存出现的时间不同
  8. 1. 静态变量随着类的加载而加载,随着类的消失而消失
  9. 1. 成员变量随着对象的创建而存在,随着对象的消失而消失
  10. 4. 调用不同
  11. 1. 静态变量可以通过类名调用,也可以通过对象调用
  12. 1. 成员变量只能通过对象名调用

5.代码块

  1. 1. .定义:使用{}括起来的代码称为代码块
  2. 1. 分类(根据位置不同):
  3. 1. 局部代码块:
  4. 1. 声明方式:定义在方法体中的一块代码
  5. 1. 执行时机:随方法的执行而执行
  6. 1. 优点:限定变量生命周期,及早释放,提高内存利用率(但效果微乎其微)
  7. 2. 构造代码块:
  8. 1. 声明方式:定义在方法体中的{}第一段代码
  9. 1. 执行时机:在创建对象的时候执行,每次创建对象必须执行
  10. 1. 与构造方法的区别:
  11. 1. _ _虽然都是在创建对象的时候执行,但是构造代码块优先于构造方法执行
  12. 1. 成员变量的初始化语句 VS 构造方法: 构造方法是创建对象的最后一步执行,所以成员变量的初始化语句先执行
  13. 1. 成员变量的初始化语句 VS 构造代码块: 它们的执行顺序和书写的先后顺序有关,谁写在前面,谁先执行

所以我们总共有3种方式,完成成员变量的初始值

  1. 1. 成员变量的初始化语句
  2. 1. 构造代码块
  3. 1. 构造方法

c. 静态代码块:

  1. 1. 声明位置和声明方式: static {}, 声明在类中方法体之外
  2. 1. 随类加载而执行, 因为一个类,在一个jvm中,最多一只会被加载一次,所以静态代码块最多执行一次
  3. 1. 使用场景:如果,有一段代码,我们希望整个java程序运行期间,只执行一次,就可以将这段代码放在静态代码块中

3.使用场景:

  1. 1. 可以完成对象成员变量值的初始化工作
  2. 1. 可以将,原来方法在,所有构造方法中的公共代码,放到构造代码块中执行

6.package

包名通常由多个名字字符串构成,中间用句点“.”分隔,每个名字表示的包称为其前面的名字表示的包的子包。通常以组织机构的域名反转形式作为其所有包的通用前缀,
比如:com.somecompany.apps
1. 同一个包下不能定义同名类,不同包中可以定义同名类
2. 即使在一个java文件中,没有用package关键字声明,该文件中定义的类所属的包,
所有没有用package关键的声明其所属包的类,都属于java语言中的默认包

7.import

用途:可以通过一个类的全限定类名唯一确定一个类,简称全类名: 包名.类名
当在类体中使用了与当前类不同包的类名时,编译器编译时因为无法找到该类的定义而失败, 有两个解决办法:
1.使用不同包类的完全限定名
2.使用import声明,为编译器提供该类的定义信息
注意事项:
1.import声明一般紧跟在package声明之后,必须在类声明之前,其基本语法如下:
import <类的完全限定名>;
2.Java语言核心包java.lang包中的类将被隐式导入,可以直接使用其中的类
3. import声明提供了一种包的智能导入方式:
import <包名>.*;
a. 包中的类将根据需要导入,避免使用多条import声明
b. 不会递归导入

day6:访问权限,封装和继承

1.访问控制权限:

  1. 1. 类中成员(成员变量和成员方法)的访问权限:
  2. 1. public:类体中:可以直接访问;同包其他类:可以通过创建对象访问;非同包其他类:可以通过创建对象访问
  3. 1. protected:类体中:可以直接访问,也可以通过创建对象访问;同包其他类:可以通过创建对象访问;非同包的类:在非同包的子类中,直接访问父类中protected修饰的成员;
  4. 1. 默认(缺省):类体中:可以直接访问,可以创建对象访问;同包其他类:可以通过创建独像访问;非同包的类:无法通过创建对象访问
  5. 1. private:类体中:可以直接访问,可以通过创建对象访问;非同包中的其他类:无法通过创建对象的形式访问;非同包的类:无法通过创建对象访问
  6. 2. 类:
  7. 1. public:被public修饰的类,同包或非包都可以访问到,比如不管同包非同包,都可以创建该类的修饰符
  8. 1. 默认(缺省):只有同包的类可以访问,比如在同包其他类中,创建对象访问

2.封装:

  1. 1. 概念:将数据和基于数据的操作封装在一起
  2. 1. 优点:
  3. 1. 数据被保护在内部
  4. 1. 系统的其他部分只有通过在数据外面的的被授权的操作才能进行交互
  5. 1. 将类使用者class user和类设计者class creator分开
  6. 3. 代码中的体现:
  7. 1. 在定义成员变量和成员方法的时候要考虑,通常只赋予其最小的访问权限
  8. 1. 如果用private修饰的成员变量,通常还要考虑提供对应的get,set方法

3.继承:

  1. 1. 含义:
  2. 1. java的一种代码复用机制
  3. 1. 表示子类与父类两种数据类型之间的一种继承或者从属关系
  4. 2. 概念:子类也叫派生类或导出类,父类也叫超类或者基类
  5. 2. 优缺点:
  6. 1. 优点:
  7. 1. 代码复用
  8. 1. 提高了代码的可维护性
  9. 1. 弱化了java语言中的类型约束
  10. 2. 缺点:
  11. 1. 父类的修改可能会出现在所有子类中,我们无法选择这些修改可以反应在哪些子类中
  12. 4. 特点:extends关键字后只跟一个类名
  13. 4. 注意事项:子类只能访问父类所有非私有的成员,子类不会继承父类的构造方法
  14. 4. 子类对象的初始化:
  15. 1. 研究的问题:有两部分数据:父类中声明的成员变量的值 子类中自己定义的成员变量的值 这两部分数据赋值先后的问题
  16. 1. 先后顺序规定:java语言要求,必须先初始化父类成员变量的值,在初始化子类成员变量的值
  17. 1. 理解方式:子类继承父类,父在先,子在后,父类成员变量先初始化,然后才是子类定义的成员变量值得初始化; 初始化子类成员的时候,子类成员变量的初值,和父类成员变量的值有关系
  18. 1. 实现方式:目的:保证父类的构造方法先执行
  19. 1. 隐式初始化:父类中存在默认的构造方法;子类构造方法在执行时没有显示的调用父类的其他构造方法 这样子类构造方法先执行会自动调用父类的默认值构造方法
  20. 1. super关键字:super代表对象的内存空间标识,也可以理解为父类对象的引用
  21. 1. 作用:
  22. 1. 访问父类对象的成员变量值
  23. 1. 访问父类中定义的成员方法
  24. 1. 调用父类的构造方法
  25. 3. 显示初始化(由我们自己写代码保证):
  26. 1. 自己在子类构造方法中通过super(实参列表)的方式调用父类构造方法
  27. 1. super语句必须置于子类构造方法的第一句语句的位置
  28. 1. 若父类没有默认构造方法,子类构造方法必须在第一条语句的位置,通过super调用父类某个构造方法
  29. 7. 域隐藏问题:在子类中可以定义和父类成员变量同名的成员变量
  30. 1. 子类中定义了和父类中成员变量相同的成员变量:在子类方法体中访问同名变量名-->访问到子类;在父类方法体中访问-->访问到父类对应的成员变量
  31. 1. 访问原理:在子类对象上,对象.成员变量的方式来访问变量的值,先在子类对象,子类自己定义的成员变量的栈中,找到就访问,如果没找到,就继续去父类对象中,相应的成员变量,找到就访问
  32. 8. 方法覆盖:子类中可以定义和父类中一模一样的方法,但在子类类体重调用该方法,调用的是子类中定义的方法,在父类类体中调用该方法,调用的到的也是子类类体重定义的方法;在子类的类体中,可以通过super.的方法,访问到父类中定义的那个和子类相同的方法。
  33. 1. 在子类对象中调用方法是,jvm的执行步骤,首先会在子类对象对应的子类中去找,要执行的方法,如果找到就执行,没有找到才回去父类中找
  34. 1. 方法覆盖的条件:
  35. 1. 子类方法的权限不能小于父类方法的权限
  36. 1. 方法返回值类型和父类方法返回值类型相同,子类方法返回值类型,是父类方法返回值的子类型
  37. 1. 方法签名:方法名相同,方法形参列表相同
  38. 3. 方法覆盖的作用:
  39. 1. 在子类类体中,修改父类中定义方法的实现
  40. 4. 注意事项:
  41. 1. 父类的私有方法不能被子类覆盖
  42. 1. 静态方法不能被覆盖
  43. 9. final关键字:
  44. 1. 修饰类:被final修饰的类不能被其他类继承
  45. 1. 修饰方法:被final修饰的方法不能被覆盖
  46. 1. 修饰变量:修饰成员变量:对象创建完毕之前被赋值,且仅能被赋值一次;修饰局部成员变量:使用之前必须被赋值,且仅能被赋值一次

day7:多态、抽象类和接口

1.多态:

  1. 1. 多态的含义:“同一个对象”的行为,在不同的时刻或条件下,表现出不同的效果
  2. 1. 前提条件:
  3. 1. 继承
  4. 1. 方法覆盖(重写)
  5. 1. 父类引用指向子类实例
  6. 3. 成员访问特征:
  7. 1. 成员变量:编译看左边,运行看左边
  8. 1. 成员方法:编译看左边,运行看右边
  9. 1. 解释:
  10. 1. 多态中,父类节点引用指向子类实例,相当于给子类对象披上了父类的外衣,因此,子类对象的外貌看起来就是父类对象,因此多态成员变量的访问特征是编译看左边,运行看左边
  11. 1. 虽然看起来是父类对象的样子,但是因为父类引用实际指向的是一个子类对象,因此,其行为,表现得是子类对象的行为
  12. 4. 多态的优点:
  13. 1. 提高了代码的维护性(由继承保证)
  14. 1. 提高了程序的扩展性(由多态保证)
  15. 5. 多态的缺点:
  16. 1. 不能访问子类特有的功能(因为父类引用指向子类的实例)
  17. 1. 解决方案:
  18. 1. 判断对象所属类型是否是目标类型
  19. 1. 强制类型转换:
  20. 1. 子类引用:——&gt,父类引用(向上转型)
  21. 1. 父类引用:——&gt,子类引用(向下转型)

2.抽象类:

  1. 1. 概念:包含有抽象方法的类或被abstract修饰的类
  2. 1. 注意事项:
  3. 1. 抽象类和抽象方法必须由abstract关键字修饰:abstract class 类名() public abstract void eat()
  4. 1. 抽象类不一定有抽象方法,有抽象方法的类一定是抽象类
  5. 3. 抽象类特征:
  6. 1. 抽象类不能直接实例化,只能间接实例化
  7. 1. 抽象类的子类可以是抽象类,也可以是具体类(当子类是具体类的时候,必须实现父类中所有的抽象方法)
  8. 4. 抽象类的组成特征:
  9. 1. 构造方法:
  10. 1. 和普通类相同
  11. 1. 抽象类不能直接实例化还有构造方法的原因,--> 抽象类中可以定义成员变量;为了使在子类,方便初始化抽象父类中成员变量的值
  12. 1. 成员变量:同普通类相同
  13. 1. 成员方法:既可以有抽象方法,也可以有非抽象方法
  14. 5. abstract冲突的关键字:
  15. 1. private
  16. 1. static
  17. 1. final

(冲突原因:abstract定义抽象方法,对于抽象方法而言,如果在代码中要使用,其实永远是通过多态,覆盖实现的抽象父类的抽象方法,而被private,final,static关键字修饰的方法,都不能在子类中被覆盖,意味着这些方法,无法在程序中运行。)

3.接口:

  1. 1. 概念:
  2. 1. 表示一组特殊功能的集合(往往只包含这组特殊功能的声明)
  3. 1. java语言中,接口interface和类主语同等地位都表示数据类型
  4. 2. 类和接口的对比:
  5. 1. 类定义了一个数据集合(成员变量)和基于这个数据集合的一组操作(成员方法),操作之间有一定的联系(操作同一个数据集合)
  6. 1. 接口中通常只包含方法声明,即接口中的方法都是抽象方法(jdk8之前)
  7. 3. 语法:接口用关键字interface表示 格式:interface接口名{}
  8. 3. 类和接口的关系:
  9. 1. 类可以实现接口,类实现接口用implement表示
  10. 1. 实现关系,其实是一种实质性的继承关系
  11. 5. 接口特征:
  12. 1. 接口不能直接实例化,只能间接实例化
  13. 1. 接口的子类,可以是抽象类也可以是具体类(具体类必须实现接口中所有的方法)
  14. 6. 接口的组成特征:
  15. 1. 无构造方法
  16. 1. 只能是常量,默认修饰符 public static final
  17. 1. 成员方法:只能是抽象方法,默认修饰符public abstractjdk8之前)
  18. 7. 接口实现了java语言的多重继承
  19. 1. 接口与接口之间可以是多重继承
  20. 1. 一个类可以在继承另一个类的情况下,实现多个接口(实现关系,实质上也是一种继承关系)
  21. 8. 抽象类和接口的区别:
  22. 1. 成员区别:
  23. 1. 成员变量:抽象类的成员变量可以是变量也可以是常量;接口中的成员变量只能是常量
  24. 1. 成员方法:抽象类的成员方法可以是抽象方法,也可以是非抽象方法;接口中的成员方法,只能是抽象方法(jdk8之前)
  25. 2. 关系的区别:
  26. 1. 类与抽象类:继承关系,而且是单重继承
  27. 1. 类与接口:实现关系,一个类可以实现多个接口
  28. 1. 接口与接口:继承关系,接口与接口之间可以实现多重继承
  29. 3. 设计理念的区别:
  30. 1. 抽象类 被继承的体现是:“is a ”的关系,共性功能
  31. 1. 接口被实现体现的是:“like a”的关系,扩展功能
  32. 9. jdk8中引入的特殊方法:
  33. 1. 默认方法:在接口中定义的非静态的可以有方法体的方法,而且在接口中添加默认方法,不会影响实现接口的子类
  34. 1. 静态方法:接口中定义的,可以有方法体的静态方法,只能在定义静态方法的接口或者通过定义接口的接口名.静态方法()的方式访问

day8:Object类

  1. 1. 概述:Object类是类层次结构的根类,所有类都直接或者间接的继承自该类
  2. 1. 构造方法:public Object() 这也解释了之前我们为什么默认系统赠送一个无参构造方法
  3. 1. Object的成员方法:
  4. 1. public final Class getClass():返回此类对象的运行时类——表示此对象运行时类的Class对象 输出可得到此对象的类的全名如:class com.cskaoyan.object.api.GetClass
  5. 1. public String toString():
  6. 1. 返回该对象的字符串表示
  7. 1. 通常,toString方法会返回一个“以文本方式表示”此对象的字符串
  8. 1. 结果应是一个简明但易于读懂的的信息表达式
  9. 1. 建议所有子类都重写此方法(Object类中提供的toString得到的结果:_com.cskaoyan.object.api.Demo2ToString@4554617c_)在类中可用快捷键alt+insert
  10. 3. public boolean equals(Object obj):
  11. 1. 我们对于相等的理解:
  12. 1. 类相同
  13. 1. 对应成员变量的值相同
  14. 2. equals方法在非空对象引用上的实现关系:
  15. 1. 自反性:对于任何非空引用值x,x.equals(x)都应返回true
  16. 1. 对称性:对于任何非空引用值xy,当且仅当 y.equals(x)返回true时,x.equalsy)才应返回true
  17. 1. 传递性:对于任何非空引用值xyz,如果x.equals(y)返回true,并且y.equals(z)返回true,那么x.equals(z)也应返回true
  18. 1. 一致性:对于任何非空引用值xy,多次调用x.equals(y)始终返回true或始终返回false。前提是对象上equals比较中所用的信息没有被修改 信息:指待比较的两对象的成员变量值
  19. 1. 对于任何非空引用值xx.equals(null)都应返回false
  20. 3. StringtoString方法很实用,可以考虑转化为字符串再进行比较
  21. 4. _public int hashCode()_
  22. 1. Object类定义的hashCode方法会针对不同的对象返回不同的整数(这一般是通过该对象的内部地址转换成一个整数来实现的)
  23. 1. hashCode的常规协定:
  24. 1. Java应用程序执行期间,在对同一对象多次调用hashCode方法时,必须一致的返回相同的整数,前提是将对象进行equals比较时所用的信息没有修改。(一般hashCode的值是根据其成员变量的值计算出来的) 从某一引用程序的一次执行到引用程序的另一次执行,该整数无需保持一致
  25. 1. 如果根据equals.(Object)方法,两个对象是相等的,那么这两个对象中每个对象调用的hashCode方法都必须生成相同的整数结果
  26. 1. 如果根据equals(java.lang.Object)方法,两个对象不相等,那么这两个对象中每个对象调用hashCode方法不 要求 一定生成不同的整数结果
  27. 1. 程序员应该意识到,为不相等的对象生成不同的整数结果可以提高哈希表的性能