java中的重写与重载
1.重写
重写(Override)是父类与子类之间的多态性,实质是对父类的函数进行重新定义,如果在子类中定义某方法与其父类有相同的名称和参数则该方法被重写,不过子类函数的访问修饰权限不能小于父类的;若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法,如需父类中原有的方法则可使用 super 关键字。
重写的规则:参数列表必须完全与被重写的方法相同,否则不能称其为重写;返回类型必须一直与被重写的方法相同,否则不能称其为重写;
访问修饰符的限制一定要大于等于被重写方法的访问修饰符;重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常,譬如父类方法声明了一个检查异常 IOException,在重写这个方法时就不能抛出 Exception,只能抛出 IOException 的子类异常,可以抛出非检查异常。
1 package FinalDemo; 2 3 //父类 4 public class Animal { 5 6 String name; 7 int no; 8 public void eat(){ 9 System.out.println("动物会吃饭"); 10 } 11 12 }
1 package FinalDemo; 2 3 //子类 4 public class Cat extends Animal{ 5 6 public static void main(String[] args){ 7 8 Cat c=new Cat(); 9 c.eat(); 10 11 } 12 13 /* 14 * 重写父类的eat()方法 15 */ 16 public void eat(){ 17 super.eat(); //如果需要保留父类中的方法,采用:super.方法名 的格式调用 18 System.out.println("白猫会吃饭"); 19 } 20 }
运行结果:
1.1 toString()方法的重写
(1)不重写
package FinalDemo; public class Animal { String name; int no; String gender; Animal(String name,int no,String gender){ this.name=name; this.no=no; this.gender=gender; } public static void main(String[] args){ Animal a=new Animal("动物",1,"M"); System.out.println(a.toString()); //没有重写toString()方法 } }
运行结果:
(2)重写toString()方法
运行结果:
1.2 equals()方法的重写
(1)不重写
1 package FinalDemo; 2 3 public class Animal { 4 5 String name; 6 int no; 7 String gender; 8 9 Animal(String name,int no,String gender){ 10 this.name=name; 11 this.no=no; 12 this.gender=gender; 13 } 14 15 16 public static void main(String[] args){ 17 Animal a=new Animal("动物",1,"M"); 18 Animal b=new Animal("动物",1,"M"); 19 20 System.out.println(a.equals(b)); 21 } 22 23 }
运行结果:
false
分析为什么为false呢?
而:
1 String a1="小狗"; 2 String b1="小狗"; 3 System.out.println(a1.equals(b1));
运行结果是:true
原因分析:
equals()在java.lang.Object下,而在Object中,equals()方法只是判断两者是否为同一个对象的引用,如下图所示:
而在String类中,对equals()方法进行了重写:
所以输出的是true
(2)重写:
1 package FinalDemo; 2 3 public class Animal { 4 5 String name; 6 int no; 7 String gender; 8 9 Animal(String name,int no,String gender){ 10 this.name=name; 11 this.no=no; 12 this.gender=gender; 13 } 14 15 //重写hashCode() 16 @Override 17 public int hashCode() { 18 final int prime = 31; 19 int result = 1; 20 result = prime * result + ((gender == null) ? 0 : gender.hashCode()); 21 result = prime * result + ((name == null) ? 0 : name.hashCode()); 22 result = prime * result + no; 23 return result; 24 } 25 26 27 //重写equals() 28 @Override 29 public boolean equals(Object obj) { 30 if (this == obj) 31 return true; 32 if (obj == null) 33 return false; 34 if (getClass() != obj.getClass()) 35 return false; 36 Animal other = (Animal) obj; 37 if (gender == null) { 38 if (other.gender != null) 39 return false; 40 } else if (!gender.equals(other.gender)) 41 return false; 42 if (name == null) { 43 if (other.name != null) 44 return false; 45 } else if (!name.equals(other.name)) 46 return false; 47 if (no != other.no) 48 return false; 49 return true; 50 } 51 52 public static void main(String[] args){ 53 Animal a=new Animal("动物",1,"M"); 54 Animal b=new Animal("动物",1,"M"); 55 String a1="小狗"; 56 String b1="小狗"; 57 //System.out.println(a1.equals(b1)); 58 System.out.println(a.equals(b)); 59 } 60 61 }
运行结果:
true
结果分析:
为什么要重写hashCode()?
因为比较时,首先比较两者的hash值,若两者的hash值不同,那么两者肯定不同,所以无需进行equals()比较,而当两者的hash值相同时,再进行equals()比较。这样做,首先会节省时间,其次,若不进行hash()的重写,会产生一下这样情况:
1 package FinalDemo; 2 3 public class Animal { 4 5 String name; 6 int no; 7 String gender; 8 9 Animal(String name,int no,String gender){ 10 this.name=name; 11 this.no=no; 12 this.gender=gender; 13 } 14 15 16 17 //重写equals() 18 @Override 19 public boolean equals(Object obj) { 20 if (this == obj) 21 return true; 22 if (obj == null) 23 return false; 24 if (getClass() != obj.getClass()) 25 return false; 26 Animal other = (Animal) obj; 27 if (gender == null) { 28 if (other.gender != null) 29 return false; 30 } else if (!gender.equals(other.gender)) 31 return false; 32 if (name == null) { 33 if (other.name != null) 34 return false; 35 } else if (!name.equals(other.name)) 36 return false; 37 if (no != other.no) 38 return false; 39 return true; 40 } 41 42 public static void main(String[] args){ 43 Animal a=new Animal("动物",1,"M"); 44 Animal b=new Animal("动物",1,"M"); 45 //String a1="小狗"; 46 //String b1="小狗"; 47 //System.out.println(a1.equals(b1)); 48 System.out.println("a的hash值:"+a.hashCode()); 49 System.out.println("b的hash值:"+b.hashCode()); 50 System.out.println(a.equals(b)); 51 } 52 53 }
结果:
可以看到,两者的hash值不同,但是用equals()判定的返回值确实ture,这部满足之前的要求,即hash值不同,equals为false,至于为什么这里出现了两者的hash值不同,而equals判定为true,我也不清楚,后面再查资料解决。
所以修改为:
1 package FinalDemo; 2 3 public class Animal { 4 5 String name; 6 int no; 7 String gender; 8 9 Animal(String name,int no,String gender){ 10 this.name=name; 11 this.no=no; 12 this.gender=gender; 13 } 14 15 16 17 18 //重写hash方法 19 @Override 20 public int hashCode() { 21 final int prime = 31; 22 int result = 1; 23 result = prime * result + ((gender == null) ? 0 : gender.hashCode()); 24 result = prime * result + ((name == null) ? 0 : name.hashCode()); 25 result = prime * result + no; 26 return result; 27 } 28 29 //重写equals方法 30 @Override 31 public boolean equals(Object obj) { 32 if (this == obj) 33 return true; 34 if (obj == null) 35 return false; 36 if (getClass() != obj.getClass()) 37 return false; 38 Animal other = (Animal) obj; 39 if (gender == null) { 40 if (other.gender != null) 41 return false; 42 } else if (!gender.equals(other.gender)) 43 return false; 44 if (name == null) { 45 if (other.name != null) 46 return false; 47 } else if (!name.equals(other.name)) 48 return false; 49 if (no != other.no) 50 return false; 51 return true; 52 } 53 54 public static void main(String[] args){ 55 Animal a=new Animal("动物",1,"M"); 56 Animal b=new Animal("动物",1,"M"); 57 //String a1="小狗"; 58 //String b1="小狗"; 59 //System.out.println(a1.equals(b1)); 60 System.out.println("a的hash值:"+a.hashCode()); 61 System.out.println("b的hash值:"+b.hashCode()); 62 System.out.println(a.equals(b)); 63 } 64 65 }
运行结果:
可以看到,重写了hash方法和equals方法后,两者的hash值相同了,equals判定的返回值也为true.
2. 重载
重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
最常用的地方就是构造器的重载。
2.1 重载规则
- 被重载的方法必须改变参数列表(参数个数或类型不一样);
- 被重载的方法可以改变返回类型;
- 被重载的方法可以改变访问修饰符;
- 被重载的方法可以声明新的或更广的检查异常;
- 方法能够在同一个类中或者在一个子类中被重载。
- 无法以返回值类型作为重载函数的区分标准。