java的多态以及重载,重写,前期绑定,后期绑定
多态的定义: 一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用
在java中多态是通过动态绑定实现的. java的多态体现在动态绑定和父类引用指向子类对象实例(这也包括了协变), 而逆变则不属于多态!(这个也是我做题时, 滴滴的一个大牛告诉我的, 强制类型转换仅仅是rtti的一种体现, 而非多态).
多态的作用是: 消除了类型之间的耦合性, 也就是实际不同的类型可以对同一个调用做出相应(比如A,B,C类, B,C类是A的子类, A中定义了一个方法x(), B,C分别对x()进行了重写, 那么实际调用时, B和C都可以对x()的调用做出相应, 如: 存在方法void doX(A a){a.x() ; }
多态存在的三个必要条件
一、要有继承;
二、要有重写;
三、父类引用指向子类对象。
之前学基础的时候只是了解重载, 重写的概念, 但是具体是什么, 涉及到父子类继承就不知所措了, 今天抽了一下午时间看了许多的blog, 顺带复习一下tij的这部分内容, 记一下以便今后使用吧.
1. 重载和重写的区别
在说明这一点之前要知道的是子类是可以继承父类的静态方法的, 具体子类可以继承父类的哪些方面, 还得再看看tij, 抽空总结吧.
重载overload,
方法名相同, 参数列表不同的方法之间构成重载; 参数列表不同又包括参数数量, 参数类型, 参数顺序的不同.
重载的判断只有这两条, 与方法的修饰符, 返回值类型都无关, 比如 static void x(){} 与void x(int a){}这也叫重载; 子类继承父类的方法与子类的方法也可以构成重载.如:
class A
{
public void a() {}
} class B extends A
{
public void a(int x){}
}
class A
{
public static void a() {}
} class B extends A
{
public static void a(int x){}
}
class FatherClass
{
static void getA()
{
System.out.println("facther...");
}
}
class SubClass extends FatherClass
{
static void getA() //对于这个getA()并不能说它覆盖了父类的getA(), 只能说它将父类的getA()隐藏了
{
System.out.println("sub ..");
}
static void getA(int x)
{
System.out.println("child");
}
}
重写override
也叫覆盖, 它是指子类重写改写父类中某个方法的实现, 也就是被改写的方法名与参数列表一定是与父类的某个类相同的.
重写有以下几个原则:
1. 三同一大: 返回值类型, 方法名, 参数列表必须与父类相同(返回值类型在java1.5中允许协变返回类型, 就是重写之后的方法的返回值可以是重写之前方法的子类); 一大是指访问权限大于等于父类的访问权限
2. 子类方法只能抛出比父类方法更小的异常或者不抛出异常
3. 被重写的方法不能有final,private, static修饰符. 因为final不允许被子类继承; 而private方法隐含是final类型, 且只能在类中被访问, 子类是无权访问的. 子类中只能定义一个与父类完全相同的方法, 而不能称之为重写; 至于static方法, 后面会提到
绑定: 将一个方法调用与一个方法主体关联起来被称为绑定, 如果这个绑定是发生在程序执行之前(如: 由编译器或链接程序实现的), 那么这种绑定成为前期绑定; 如果这个绑定是发生在程序运行之后, 根据对象的具体类型进行绑定的, 那么这种绑定就是动态绑定.
2. 后期绑定
又叫动态绑定或运行时绑定, java的多态就是通过后期绑定实现的, 它是指编译器在编译时不能确定这个引用调用的是哪一个方法, 这个方法具体是什么要到运行时才能确定, 比如:
public class Main
{
public static void main(String[] args)
{
A a = new A() ;
A b = new B() ; a.a() ;
b.a() ;
}
} class A
{
public void a(){
System.out.println("a");
}
} class B extends A{
public void a()
{
System.out.println("b");
}
}
a和b的调用的a方法在编译时是无法确定的, 不知道是父类的a还是子类的a, 要到运行时才能通过具体的类型得知.
因此方法的动态绑定是基于对象的实际类型而非对象的引用类型的.
在java中动态绑定发生在除了static方法和final方法之外的所有方法绑定(private方法默认是final类型),构造函数也不是动态绑定(构造函数其实是一种特殊的static方法, 是隐式的), 因此不具有多态性.
3. 前期绑定
前期绑定又叫编译器绑定, 是指编译器在编译阶段就完成的绑定.
如果一个方法有static, private,final修饰或者是构造函数, 那么就是前期绑定
所有的静态方法都是前期绑定, 因为静态方法可以通过类名进行访问, 而不会用到引用的对象的实际类型信息, 因此在编译时就可以通过类型信息确定是哪一个具体的方法, 这也就揭示了为什么静态方法不能重写了, 因为重写的目的是为了实现多态.
与静态方法相同, 成员变量也属于前期绑定, 如:
public class Main
{
public static void main(String[] args)
{
A a = new A() ;
A b = new B() ; a.a() ;
b.a() ; System.out.println(a.a);
System.out.println(b.a);
}
} class A
{
int a = 22 ;
public void a(){
System.out.println("a");
}
} class B extends A{
int a = 33 ;
public void a()
{
System.out.println("b");
}
}
在java中重载方法的选择是静态绑定, 也就是一个方法的参数选择是静态绑定的, 如:调用了一个重载的方法, 在编译时根据参数列表就可以确定方法, 如果这个方法是非静态方法, 那么具体调用的是父类的方法还是子类的方法就需要动态绑定来确定;
public class Main
{
public static void main(String[] args)
{
Base b = new Base();
Derived d = new Derived(); whichFoo(b,b);
whichFoo(b,d);
whichFoo(d,b);
whichFoo(d,d);
}
public static void whichFoo(Base arg1, Base arg2){
arg1.foo(arg2);
}
} class Base{
public void foo(Base x){
System.out.println("Base.Base");
} public void foo(Derived x){
System.out.println("Base.Derived");
}
} class Derived extends Base{
public void foo(Base x){
System.out.println("Derived.Base");
} public void foo(Derived x){
System.out.println("Derived.Derived");
}
}
对于whichFoo中的foo方法构成了重载(无论是base还是derived), 由于是前期绑定, 所以无论arg2的实际类型是什么, 都会选择public void foo(Base), 具体是父类的foo(base)还是子类的foo(base) 这就需要运行时动态绑定来确定了.
在编译阶段,最佳方法名依赖于参数的静态和控制引用的静态类型所适合的方法。在这一点上,设置方法的名称,这一步叫静态重载。
决定方法是哪一个类的版本,这通过由虚拟机推断出这个对象的运行时类型来完成,一旦知道运行时类型,虚拟机就唤起继承机制,寻找方法的最终版本。这叫做动态绑定。
---
由于对象既可以当作它自己本身的类型使用, 也可以当作它的基类类型使用, 因此将对某个对象的引用是其基类型的引用的行为称为向上转型, 也就是通俗讲为java的向上转型是指子类对象赋值给父类引用; 父类引用调用方法表现出不同的形态, 叫多态. 多态是有动态绑定实现的
前面已经说了对于java当中的方法而言,除了final,static,private和构造方法是前期绑定外,其他的方法全部为动态绑定。而动态绑定的典型发生在父类和子类的转换声明之下:
比如:Parent p = new Children();
其具体过程细节如下:
1:编译器检查对象的声明类型和方法名。假设我们调用x.f(args)方法,并且x已经被声明为C类的对象,那么编译器会列举出C类中所有的名称为f的方法和从C类的超类继承过来的f方法
2:接下来编译器检查方法调用中提供的参数类型。如果在所有名称为f 的方法中有一个参数类型和调用提供的参数类型最为匹配,那么就调用这个方法,这个过程叫做“重载解析”
3:当程序运行并且使用动态绑定调用方法时,虚拟机必须调用同x所指向的对象的实际类型相匹配的方法版本。假设实际类型为D(C的子类),如果D类定义了f(String)那么该方法被调用,否则就在D的超类中搜寻方法f(String),依次类推
域域静态方法也不具有多态性, 只有普通方法具有多态性, 所有的域访问操作都是由编译器解析的, 因此不具有多态性, 其实类似于静态绑定, 但是绑定这个概念只是针对方法的, 对于域而言不具有这个概念.
能力有限, 不能很好的表达, 原文地址如下:
//http://www.cnblogs.com/yyyyy5101/archive/2011/08/02/2125324.html(这个是写的最好的)
//http://www.importnew.com/7751.html
//http://blog.csdn.net/fsz521/article/details/8739236
多态//http://www.cnblogs.com/jack204/archive/2012/10/29/2745150.html
暂时就记录到这儿吧, 现在拿来实际的例子可以说明白, 但是理论还是讲不来, 记录也写的歪七扭八的.. 整理下思路改天再写吧
java的多态以及重载,重写,前期绑定,后期绑定的更多相关文章
- 关于JAVA中的前期绑定 后期绑定(动态绑定)
前期绑定,在程序执行前根据编译时类型绑定,调用开销较小,如C语言只有前期绑定这种方法调用. 后期绑定,是指在运行时根据对象的类型进行绑定,又叫动态绑定或运行时绑定.实现后期绑定,需要某种机制支持,以便 ...
- C#早期绑定&后期绑定
早期绑定(early binding),又可以称为静态绑定(static binding).在使用某个程序集前,已知该程序集里封装的方法.属性等.则创建该类的实例后可以直接调用类中封装的方法. 后期绑 ...
- [转]Java中继承、多态、重载和重写介绍
什么是多态?它的实现机制是什么呢?重载和重写的区别在那里?这就是这一次我们要回顾的四个十分重要的概念:继承.多态.重载和重写. 继承(inheritance) 简单的说,继承就是在一个现有类型的基础上 ...
- [Java]重载,重写以及继承,多态的区别
转自:http://android.blog.51cto.com/268543/53181 什么是多态?它的实现机制是什么呢?重载和重写的区别在那里?这就是这一次我们要回顾的四个十分重要的概念:继承. ...
- 2017.10.10 java中的继承与多态(重载与重写的区别)
1. 类的继承 继承是面向对象编程技术的主要特征之一,也是实现软件复用的重要手段,使用继承特性子类(subclass) 可以继承父类(superclass)中private方法和属性,继承的目的是使程 ...
- Java中,方法的重写、重载的区别,以及多态的实例
首先我们要明白什么是重写和重载 重写(override):子类方法覆盖了父类的方法. (类与类之间继承的关系) 例:父类代码 public class Deng { public void Qi ...
- 类与接口(五)java多态、方法重写、隐藏
一.Java多态性 面向对象的三大特性:封装.继承.多态. 多态的类型,分为以下两种: 编译时多态: 指的是 方法重载.编译时多态是在编译时确定调用处选择那个重载方法,所以也叫 静态多态,算不上真正的 ...
- 理解Java中的前期绑定和后期绑定
前期绑定,在程序执行前根据编译时类型绑定,调用开销较小,如C语言只有前期绑定这种方法调用. 后期绑定,是指在运行时根据对象的类型进行绑定,又叫动态绑定或运行时绑定.实现后期绑定,需要某种机制支持,以便 ...
- C#中区别多态、重载、重写的概念和语法结构
C#中区别多态.重载.重写的概念和语法结构 重写是指重写基类的方法,在基类中的方法必须有修饰符virtual,而在子类的方法中必须指明override. 格式: 基类中: public virtual ...
随机推荐
- ThreadLocal 的分析
http://blog.csdn.net/LHQJ1992/article/details/52451136 个人感觉这是所有关于ThreadLocal里中最靠谱的一篇文章. ps:其实官方文档才是最 ...
- js-dom-EventUtil
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 【01】在 issue 中创建 list
[01]在 issue 中创建 list 你想在你的 issue中看到可多选的 list 么? 当你查看问题时,你想不想让它变成 2 of 5 这样的形式. 如果想,你可以在 issue 中使用以下句 ...
- 检测SQLserver数据库链接是否正常
select * From [数据库链接名].master.dbo.sysdatabases where name='数据库名' and status<>512
- json的两种表示结构(对象和数组).。
JSON有两种表示结构,对象和数组.对象结构以”{”大括号开始,以”}”大括号结束.中间部分由0或多个以”,”分隔的”key(关键字)/value(值)”对构成,关键字和值之间以”:”分隔,语法结构如 ...
- 【bzoj4519】[Cqoi2016]不同的最小割 分治+最小割
题目描述 学过图论的同学都知道最小割的概念:对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割.对于带权图来说,将所有顶点处在不同 ...
- BZOJ 2246 [SDOI2011]迷宫探险 ——动态规划
概率DP 记忆化搜索即可,垃圾数据,就是过不掉最后一组 只好打表 #include <cstdio> #include <cstring> #include <iostr ...
- uva 11806 容斥原理+dfs
In most professional sporting events, cheerleaders play a major role in entertaining the spectators. ...
- dedecms--需要注意的细节
在系统的系统配置参数里面修改一些参数 1:站点设置: (1):站点根网址:本地测试的话:就是你设置的虚拟主机:http://www.abc.cc (2):网页主页链接:为空 2:核心设置: DedeC ...
- php——离线执行任务
<?php//设置忽略是否关闭终端窗口ignore_user_abort(true);ini_set('max_execution_time', '0');//采集页面函数,看不懂执行百度cur ...