java重写(Override)
重写(Override)的定义
当一个类继承另一个类时,则可以拥有父类的成员方法和成员变量,在子类中,可以创建独有的成员,如果创建了一个与父类中相同名称,相同返回类型、相同参数列表的方法,只是方法体中的实现方法不同,以实现不同于父类的功能,这种方式就称为方法的重写,又称为方法的覆盖。
重写的前提?
必须要存在继承的关系
为什么要重写?
父类的功能无法满足子类的需求。
重写(Override)的规则
- 参数列表必须完全与被重写方法的相同;
- 返回类型必须完全与被重写方法的返回类型相同;
- 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为public,那么在子类中重写该方法就不能声明为protected。
(public>protected>default>private)
- 父类的成员方法只能被它的子类重写。
- 声明为final的方法不能被重写。
- 声明为static的方法不能被重写,但是能够被再次声明。
- 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为private和final的方法。
- 子类和父类不在同一个包中,那么子类只能够重写父类的声明为public和protected的非final方法。
- 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
- 构造方法不能被重写。
- 如果不能继承一个方法,则不能重写这个方法。
或者采用更容易记的口诀法:两同两小一大规则
“两同” :即方法名相同、形参列表相同;
“两小” :(1)指的是子类方法返回值类型比父类方法的返回值类型更小或相等。
(2)子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等。
“一大”指的是子类方法的访问权限应比父类方法的访问权限更大或者相等。
(public>protected>default>private)
特别注意:覆盖方法和被覆盖方法要么都是类方法,要么都是实例方法,不能一个是类方法,一个是实例方法。
重写的示例代码
class Animal{
public void move(){
System.out.println("动物可以移动");
}
}
class Dog extends Animal{
public void move(){
System.out.println("狗可以跑和走");
}
}
public class TestDog{
public static void main(String args[]){
Animal a = new Animal(); // Animal 对象
Animal b = new Dog(); // Dog 对象,一般情况下是 Dog b = new Dog();
a.move();// 执行 Animal 类的方法
b.move();//执行 Dog 类的方法
}
}
/*
运行结果:
动物可以移动
狗可以跑和走
*/
在上面的例子中可以看到,尽管b属于Animal类型[创建对象时候用父类,而非子类],但是它运行的是Dog类的move方法。
这是由于在编译阶段,只是检查参数的引用类型。
然而在运行时,Java虚拟机(JVM)指定对象的类型并且运行该对象的方法。
因此在上面的例子中,之所以能编译成功,是因为Animal类中存在move方法,然而运行时,运行的是特定对象的方法。
java重载(Overload)
重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。
方法的重载分为 构造方法和普通方法的重载,方法的重载是java多态性的体现之一。
重载的规则
- 被重载的方法必须改变参数列表(参数个数或类型不一样);
- 被重载的方法可以改变返回类型,通俗一点就是与返回类型无关;
- 被重载的方法可以改变访问修饰符;
- 被重载的方法可以声明新的或更广的检查异常;
- 方法能够在同一个类中或者在一个子类中被重载。
- 无法以返回值类型作为重载函数的区分标准。
重载代码示例:
public class Main {
public static void main(String [] args){
System.out.println(add(1,3)); //传两个参
System.out.println(add(1,2,3));//传三个参
System.out.println(add(1.2,3.4)); //传两个double型参数
//方法名字必须相同,都为add,参数列表不同
System.out.println(mOl(1,2));//无返回值
System.out.println(mOl("大神带你学java"));//有返回值
//mOl,方法名相同,参数列表不同,返回值类型不同
}
public static int add(int x, int y){
return x+y;
}
public static int add(int x,int y,int z){
return x+y+z;
}
public static double add(double x,double y){
return x+y;
}
public void mOl(int i , int j){
System.out.println(i+2);
}
public int mOl(String str){
System.out.print(str);
return 0;
}
final关键字
final关键字的含义
final表面意思就是不可更改的,恒量的意思;类似于C语言和Objective-c中的const关键字,指的是无法改变的量,这与静态标量static是有区别的,静态变量指的是只有一份存储空间,值是可以改变的。使用final一定原因是出于软件设计的角度,因为别人看到final这个关键字就知道是什么意思,达到心领神会的效果,但也正是由于这种"语义"的存在,在程序设计中要谨慎使用,以免误用。
final需求
有时候我们我们写的变量,或者我们写的方法和类,不能被改变;
只是给用户使用特定的方法,例如基本类型中的包装类Integer,String,Booealn,好处显而易见,多线程数据共享时候不会变化,保证线程的安全.
final的作用
- 1.修饰变量,被final修饰的变量必须要初始化,赋初值后不能再重新赋值。
注意:局部变量不在我们讨论的范畴,因为局部变量本身就有作用范围,不使用private、public等词修饰。
2.修饰方法参数
3.修饰方法,被final修饰的方法代表不能重写。
4.修饰类,被final修饰的类,不能够被继承。
final修饰变量
被final修饰的变量必须显示的初始化,初始化可以以三种方式:
- 定义时初始化,
- 在构造器中设置值,
- 在非静态块中为final实例变量设置值。
public class FinalTest001{
final int x1= 10000;
final int x2;
final int x3;
{
x2 = 20000;
}
Public exe3(){
this.x3 = 3000;
}
}
final修饰变量指的是:这个变量被初始化后便不可改变,这里不可改变的意思对基本类型来说是其值不可变,而对于对象变量来说其引用不可变,即不能再指向其他的对象。
final Dog dog = new Dog() ;// Dog有一个普通变量age初始化为5
dog.age = 8;
dog.age = 11;
System.out.println(dog.age); //输出11
//上述是自定义类,即便是数组,List等集合类型,所保存的值也是可以更改的。
final修饰方法参数
前面我们可以看到,如果变量是我们自己创建的,那么使用final修饰表示我们只会给它赋值一次且不会改变变量的值。那么如果变量是作为参数传入的,我们怎么保证它的值不会改变呢?这就用到了final的第二种用法,即在我们编写方法时,可以在参数前面添加final关键字,它表示在整个方法中,我们不会(实际上是不能)改变参数的值:
public class FinalTest002 {
public void finalFunc(final int i, final Cat cat) {
// i = 5; 不能改变i的值
// cat = new Cat(); 不能改变cat对象
cat.age = 5; // 可以改变引用对象的值
}
}
final修饰方法
即用final关键字修饰方法,它表示该方法不能被覆盖。这种使用方式主要是从设计的角度考虑,即明确告诉其他可能会继承该类的程序员,不希望他们去覆盖这个方法。这种方式我们很容易理解,然而,关于private和final关键字还有一点联系,这就是类中所有的private方法都隐式地指定为是final的,由于无法在类外使用private方法,所以也就无法覆盖它。
final修饰类
了解了final关键字的其他用法,我们很容易可以想到使用final关键字修饰类的作用,那就是用final修饰的类是无法被继承的。
上面我们讲解了final的四种用法,然而,对于第三种和第四种用法,我们却甚少使用。这不是没有道理的,从final的设计来讲,这两种用法甚至可以说是鸡肋,因为对于开发人员来讲,如果我们写的类被继承的越多,就说明我们写的类越有价值,越成功。即使是从设计的角度来讲,也没有必要将一个类设计为不可继承的。Java标准库就是一个很好的反例,特别是Java 1.0/1.1中Vector类被如此广泛的运用,如果所有的方法均未被指定为final的话,它可能会更加有用。如此有用的类,我们很容易想到去继承和重写他们,然而,由于final的作用,导致我们对Vector类的扩展受到了一些阻碍,导致了Vector并没有完全发挥它应有的全部价值。
final和static的区别
static作用于成员变量用来表示只保存一份副本,而final的作用是用来保证变量不可变,看一下下面这个例子:
public class Test {
public static void main(String[] args) {
MyClass myClass1 = new MyClass();
MyClass myClass2 = new MyClass();
System.out.println(myClass1.i);
System.out.println(myClass1.j);
System.out.println(myClass2.i);
System.out.println(myClass2.j);
}
}
class MyClass {
public final double i = Math.random();
public static double j = Math.random();
}
//运行结果,两次打印,j的值都是一样的,j是static类型的属于类,因此两次值相同。i不是static的因此属于对象,但是i的值是不可变的。