方法重写
方法重写的特性与条件
java
方法重写的特性与条件:
1. 存在于父子类之间
2. 方法名称相同
3. 参数列表相同
4. 返回值相同或者是其子类
5. 访问权限不能严于父类,子类的访问权限不能小于父类的访问权限
6. 静态方法可以被继承,但是不能被重写
7. 不能抛出、声明比父类更多的异常
注解的作用:
java
@override // 注解
public void print(){
}
辅助提示:检查方法重写是否正确。
@Override 注解,此注解只能加在方法上,表示此方法属于重写父类的方法,如果没有正确重写,则编译报错。
自定义类中方法重写
自定义类方法重写也就是自己写的类的方法进行重写。
方法重写案例:
父类
java
package com.methodRenamePart;
public class Vtuber {
String name;
int age;
char gender;
String height;
public Vtuber() {
}
public Vtuber(String name, int age, char gender, String height) {
this.name = name;
this.age = age;
this.gender = gender;
this.height = height;
}
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;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
public String getHeight() {
return height;
}
public void setHeight(String height) {
this.height = height;
}
public void info() {
System.out.println("Vtuber" +
" name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
", height='" + height + '\'');
}
}
子类
java
package com.methodRenamePart;
public class Gamer extends Vtuber{
String games;
public Gamer(String games) {
this.games = games;
}
public Gamer(String name, int age, char gender, String height, String games) {
super(name, age, gender, height);
this.games = games;
}
public String getGames() {
return games;
}
public void setGames(String games) {
this.games = games;
}
// 子类方法重写
public void info(){
// 调用父类的方法
super.info();
System.out.println("爱好的游戏是" + this.games);
}
}
测试类
java
package com.methodRenamePart;
public class Test {
public static void main(String[] args) {
// 创建对象
Gamer gamer = new Gamer("凑阿夸",5,'女',"156","Apex");
gamer.info();
}
}
Object类中方法重写
对Object类中方法进行重写
java
toString()属于Object类中方法
equals()属于Object类中方法
hashCode()属于Object类中方法
toString()方法重写
toString()属于Object类中方法,用于返回当前对象的String描述
java
直接打印一个对象,相当于调用此对象的toString方法,toString方法从顶层父类Object类中继承而来。
sout(object)
直接打印对象相当于调用了这个对象的toString方法
objcet.toString()
我们在实际开发中通常需要重写toString方法,用于将本类中的属性名和属性值进行拼接,以方便直接打印对象实现输出 属性信息的效果。
重写toSting在开发中99%的作用就是为了看对象属性。(可通过idea插件快速生成)
ts
通过 alt+insert 快捷键,然后点击toString,就可以快速生成一个toString重写方法
toString方法重写案例
java
package com.methodRenamePart;
public class Vtuber {
String name;
int age;
char gender;
String height;
public Vtuber() {
}
public Vtuber(String name, int age, char gender, String height) {
this.name = name;
this.age = age;
this.gender = gender;
this.height = height;
}
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;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
public String getHeight() {
return height;
}
public void setHeight(String height) {
this.height = height;
}
@Override
public String toString() {
return "Vtuber{" +
"name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
", height='" + height + '\'' +
'}';
}
}
equals()方法重写
equals()属于Object类中方法,用于比较两个对象是否相同
equals()源代码
java
// Object.java
public boolean equals(Object obj) {
return (this == obj);
}
== 和 equals 的区别
java
首先,当 "==" 比较基本数据类型时,比较值;当 "==" 比较引用数据类型时,比较地址;
equals()方法底层(源码)实现依然使用"=="比较地址;我们可以重写equals方法,自定义比较规则,将原本的比较地址重写,比较地址并且比较内容;
例子:String类就是对equals方法进行了重写;
例子2: 只要是new出来的两个对象 地址是绝对不相同的"=="比较就为false
细节
ts
通过鼠标点击查看源代码时,需要先看下标题文件是哪一个类。然后再看重写的方法。
在子类中的重写方法附近,可以通过点击左侧的↑箭头,查看父类的方法。
String类的equals()方法重写模拟
java
// 重写的话 形参返回值都要一样
package com.rewrite;
public class MyString {
// 定义一个静态方法
public static boolean myEquals(String str1,String str2){
// 首先判断两个对象地址是否相同
if(str1 == str2){
return true;
}
// 使用遍历比较内容是否相同
if (str1.length() != str2.length()){
return false;
}
// 将两个字符串转为char数组
char [] charArray1 = str1.toCharArray();
char [] charArray2 = str2.toCharArray();
// 比较两个char数组内容是否相同
for (int i = 0; i < charArray1.length; i++) {
if (charArray1[i] != charArray2[i]){
return false;
}
}
return true;
}
// 测试类
}
java
package com.rewrite;
public class Test {
public static void main(String[] args) {
Person per1 = new Person("sakuna","410883200205067898");
Person per2 = new Person("saba","410883200205067899");
// 访问同包中的MyString类中的静态方法
Boolean result = MyString.myEquals(per1.getIdCard(), per2.getIdCard());
System.out.println("idCard对比的结果为 "+result);
}
}
自定义类中equals方法重写
先比较地址,再比较内容。
java
package com.rewrite;
public class Person {
private String name;
private String idCard;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIdCard() {
return idCard;
}
public void setIdCard(String idCard) {
this.idCard = idCard;
}
public Person(String name, String idCard) {
this.name = name;
this.idCard = idCard;
}
public Person() {
}
public void printInfo(){
System.out.println("我的名字是" + name);
System.out.println("我的id是" + idCard);
}
// 自定义类的equals方法重写
public boolean equals(Object obj){ // 调用的过程 符合多态向上转型
// 首先判断地址
if(this == obj){
return true;
}
// 因为形参为Object类型的 而Object类中没有任何属性 所以不能直接访问 name 以及 idCard
// 如需访问 必须向下转型(强制类型转换)
Person p1 = (Person) obj;
// 如何对象确定调用的方法属于哪个类的方法
// 根据调用方法的对象 所属的类型来判断
if (this.name.equals(p1.name) && this.idCard.equals(p1.idCard)){
return true;
}else {
return false;
}
}
}
java
// 使用instanceof关键字,加一层判断
package com.rewrite;
public class Person {
private String name;
private String idCard;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIdCard() {
return idCard;
}
public void setIdCard(String idCard) {
this.idCard = idCard;
}
public Person(String name, String idCard) {
this.name = name;
this.idCard = idCard;
}
public Person() {
}
public void printInfo(){
System.out.println("我的名字是" + name);
System.out.println("我的id是" + idCard);
}
@Override
// 自定义类的equals方法重写
public boolean equals(Object obj){ // 调用的过程 符合向上转型
// 首先判断地址
if(this == obj){
return true;
}
// 加一层判断,如果类型不相同直接返回false
if (obj instanceof Person){
// 因为形参为Object类型的 而Object类中没有任何属性 所以不能直接访问 name 以及 idCard
// 如需访问 必须向下转型(强制类型转换)
Person p1 = (Person) obj;
// 如何对象确定调用的方法属于哪个类的方法
// 根据调用方法的对象 所属的类型来判断
if (this.name.equals(p1.name) && this.idCard.equals(p1.idCard)){
return true;
}
}
return false;
}
// 自定义类重写哈希值计算
// 要保证在equals比较为true的情况下 两个对象hashCode相同
// 上边重写的 equals 方法是根据人的名字和身份证号比较的
// 所以我们也要根据人的名字和身份证号来计算hash值
@Override
public int hashCode() {
int result = 1; // 哈希值结果
int prime = 31; // 权重
result = result * prime + (this.name == null ? 0 : this.name.hashCode()); // 这里使用了 String类重写的hashCode方法
result = result * prime + (this.idCard == null ? 0 : this.idCard.hashCode()); // 这里使用了 String类重写的hashCode方法
return result;
}
}
测试类
java
package com.rewrite;
public class Test {
public static void main(String[] args) {
Person per1 = new Person("sakuna","410883200205067898");
Person per2 = new Person("saba","410883200205067899");
// 使用 Person类中的方法
boolean result = per1.equals(per2);
System.out.println("idCard对比的结果为 "+result);
}
}
如何确定调用的方法属于哪个类的方法?
java
根据调用方法的对象,所属类型来判断
hashCode()方法重写
hashCode()属于Object类中方法,用于计算对象的哈希值
什么是哈希值?
java
hash值是根据杂凑算法所计算出来的一个数值。
哈希值的特性:
1.hash值并不是地址值,而是根据对象的地址等一些信息,使用杂凑算法所计算出来的一个十进制的数值。
2.Java中的地址值我们是无法获取的,计算hash值的方式也无法获取。
为什么重写哈希值?
java
1.因为默认情况下,两个对象equals比较为true,则hashCode必须是相同的
2.在后续学习的集合类中,默认是以equals比较为true,并且hashCode相同作为去除重复元素的依据。
现在我们重写了equals改变了对象的比较规则,所以应当继续重写hashCode,以维持两个对象equals比较为true,则hashCode必须是相同的,哈希值的计算运用了equals方法的比较规则。
重写哈希值示例
java
package com.rewrite;
public class Person {
private String name;
private String idCard;
......
public Person() {
}
public void printInfo(){
System.out.println("我的名字是" + name);
System.out.println("我的id是" + idCard);
}
@Override
// 自定义类的equals方法重写
public boolean equals(Object obj){ // 调用的过程 符合向上转型
// 首先判断地址
if(this == obj){
return true;
}
// 因为形参为Object类型的 而Object类中没有任何属性 所以不能直接访问 name 以及 idCard
// 如需访问 必须向下转型(强制类型转换)
Person p1 = (Person) obj;
// 如何对象确定调用的方法属于哪个类的方法
// 根据调用方法的对象 所属的类型来判断
if (this.name.equals(p1.name) && this.idCard.equals(p1.idCard)){
return true;
}else {
return false;
}
}
// 自定义类重写哈希值计算
// 要保证在equals比较为true的情况下 两个对象hashCode相同
// 上边重写的 equals 方法是根据人的名字和身份证号比较的
// 所以我们也要根据人的名字和身份证号来计算hash值
@Override
public int hashCode() {
int result = 1; // 哈希值结果
int prime = 31; // 权重
result = result * prime + (this.name == null ? 0 : this.name.hashCode()); // 这里使用了 String类重写的hashCode方法
result = result * prime + (this.idCard == null ? 0 : this.idCard.hashCode()); // 这里使用了 String类重写的hashCode方法
return result;
}
}
测试类
java
package com.rewrite;
public class Test {
public static void main(String[] args) {
Person per1 = new Person("sakuna","410883200205067898");
Person per2 = new Person("saba","410883200205067899");
// 使用 Person类中重写的 equals 方法
boolean result = per1.equals(per2);
System.out.println("idCard对比的结果为 "+result);
// 使用 Person类中重写的 hashCode 方法
System.out.println("p1的哈希值为 "+per1.hashCode());
System.out.println("p2的哈希值为 "+per1.hashCode());
}
}
为什么要使用31作为权重
java
1.因为JDK也使用31
2.因为31是一个特殊的质数 任何数乘以31 等于这个数左移5位 减去这个数 本身
n * 31 = (n << 5) - n
位运算符效率是最高 但是优先级是最低的
总结:因为使用31计算hash值效率更高