JAVA(多态特性)一 多态的原理以及使用
多态的原理
在学习多态原理之前我们需要先了解JVM的一些机制
前期绑定(静态绑定)
- 前期绑定也称之为静态绑定 在我们java代码编译的时候就已经执行 当我们编写java代码的时候 由private final static 修饰的方法 属性 就已经跟当前类绑定只能由本类才能调用 例如:
class Person{
private String name;
static int a = 10;
final int VERSION = 1;
public Person() {
}
private void print() {
System.out.println(name);
}
}
凡是由private static final修饰的字段或方法子类都无法继承的这就是静态绑定的特性
由上图可见变量 a 和 VERSION可以调用这不是违背了不能继承么 其实不然这是因为子类持有外部类的一个类引用 注意这个引用是类不是对象这几个变量其他任何类都可以调用通过 (类名.属性名) 的方式
后期绑定(动态绑定)
后期绑定也称为动态绑定 我们知道前期绑定是在程序编译时就已经绑定好了 而动态绑定则是在java代码运行的时候再根据实际对象进行绑定
public class Test1 {
public static void main(String[] args) {
Person p = new Student();
p.print();
}
}
class Person{
public int a = 10;
public void print() {
System.out.println(a);
}
}
class Student extends Person{
public int a = 20;
public void print() {
System.out.println(a);
}
}
上面代码运行的结果为:
20
这里结果为什么是20呢这就是动态绑定的特性和方法重写 后面我会说到。Student类继承了 Person那么它会继承非private、final、static修饰的字段
在Test1中的main方法里我 创建了一个 Person p = new Student();这个创建方式是一种多态的应用通过父类的引用指向子类对象 在代码运行时 根据实际创建对象的类型的方法来进行绑定 这就是动态绑定的机制
方法的重写
方法重写是 java继承中的一种机制 子类通过继承父类的方法 可以通过重写该方法对原父类的方法进行覆盖 覆盖的规则如下 :
- 返回值 参数类型的顺序、数量、名称 方法名 必须与父类方法一致
- 权限修饰符必须与父类方法权限修饰一样或者权限范围更广
class Person{
private int print(int a,int b) {
System.out.println(a+b);
return a+b;
}
}
class Student extends Person{
private int print(int a,int b){
System.out.println(a-b);
return a-b;
}
}
上面代码我实现了一个简单的方法重写如果没有遵守 方法重写的相关规则那么java会视为这个方法为新增方法或者为重载方法 一定遵守方法重写的规则以免带来不必要的麻烦
多态的使用
在java中如何实现一个多态呢
class Person{
public int a = 10;
private int b = 20;
public int print(int a,int b) {
System.out.println(a+b);
return a+b;
}
public int print2(int a,int b) {
System.out.println(a+b);
return a+b;
}
}
class Student extends Person{
int c = 30;
public int print(int a,int b){
System.out.println(a-b);
return a-b;
}
public int print3(int a,int b){
System.out.println(a*b);
return a*b;
}
}
这里我简单的通过方法重写实现了一个多态下面我来介绍下多态的特性:
- 只能调用引用类型里面的属性
- 能调用引用类型的方法或者实际对象重写的方法
由上图可见我们无法调用 子类新增的属性或者方法 那么为什么java中方法能重写
属性能不能重写呢? 实际上子类是无法重写父类的属性的 如果你在子类里面声明了一个与父类变量相同的属性那么java会认为这个属性是当前类的一个新增属性 而当我们调用的时候也还是调用的父类的属性 这个就是前期绑定的特性 编译时就已经绑定好了属性方法