静态方法的隐藏与非静态方法的重写的区别
重写”只能适用于可观察的实例方法.不能用于静态方法和final、private.对于静态方法,只能隐藏。一方面这是Java的规定,另一方面其实也有一定的道理这里边。
静态方法
首先谈谈java方法是何时绑定的:话不多说,上一个简简单单的代码
Person.java父类
public class Person {
public static void test(){
System.out.println("person被调用");
}
}
Student.java子类
public class Student extends Person {
public static void test(){
System.out.println("student被调用");
}
}
测试类Application.java
public class Application {
public static void main(String[] args) {
//new一个子类对象
Student student = new Student();
//父类的引用指向子类对象
Person person = new Student();
student.test();//student被调用
person.test();//person被调用
//静态方法的调用只和左边的,定义的数据类型有关
//静态方法不能重写
}
}
知识点
- 静态方法的调用只和左边的,定义的数据类型有关,所以效果如上
- 那么请问大家知道test()是该调用父类Person 的方法呢还是该调用子类Student的方法呢。实际情况是:在运行期的时候取决于是哪个对象调用他的,规则是优先调用自己的这个test()方法,如果自己没有这个方法就调用父类的test()方法。这里声明成Person类型变量,是让我们忘记它的具体实现类型,将做什么和怎么做分离,这就是java的多态。
- 但是我们每个方法的调用者并不都是由对象来调用他的。比如说static方法,可能有人会觉得这个static方法调用者是类对象啊,但我告诉你类对象是Class类型,也就是每个类的class静态域,比如String.class、ArrayList.class,他们并不包含我们要调用的目标静态方法。
- 在Java中我们静态方法的的选择是编译期就选择好的,是编译器自动根据声明类型帮我们选择的,它不依赖与任何对象。
- 所以说从语义就可以看出static、final、private方法本身都是编译期绑定的(也叫前期绑定)这些方法不存在多态,他们是在还没有运行的时候,程序在编译器里面就知道该调用哪个类的哪个方法了,而其他可观察的普通方法的绑定是在运行的时候根据具体的对象决定的,因为从语义上看这些方法是可被继承的,有了多态而造成了不确定性。
- 通俗的讲就是父类的方法和子类的方法是两个没有关系的方法,具体调用哪一个方法是看是哪个对象的引用;这种父子类方法也不在存在多态的性质。
非静态方法
- 如上面,上一个简简单单的代码,帮助理解
A.java父类
public class A {
public void test(){
System.out.println("A==>父类");
}
public void eat(){
System.out.println("父类喜欢吃肉夹馍");
}
}
B.java子类
public class B extends A {
@Override
public void test(){
System.out.println("B==>子类");
}
public void play(){
System.out.println("子类喜欢打篮球");
}
}
Application.java测试类
public class Application {
public static void main(String[] args) {
/*
非静态方法:子类重写了父类的方法
*/
//new一个子类对象
B b = new B();
//多态:父类的引用指向子类的对象
A a = new B();
b.test();//B==>子类
a.test();//B==>子类
//play()子类独有方法
b.play();
((B)a).play();//父类调用子类的独有方法,必须强转
//eat()父类独有的方法
b.eat();
a.eat();
}
}
知识点
- 一个对象的实际类型(右边)是确定的。但是,可以指向的的引用类型(左边)就不确定了,例如,父类的引用指向子类的对象(多态)。
- 多态性指在运行时确定类型,在这里的非静态方法就实现了多态。
- 对象能执行那些方法,主要看左边的引用,和右边的实际类型关系不大。