Java多态与泛型 ,动态绑定,静态绑定

(一)多态

1.概念

简单理解就是,一个对象可以表现出多种状态。可以看做是对抽象对象的逆过程,具体化抽象对象的行为。而它是如何实现这种表现出多种状态功能的呢。从Java语法上来讲有如下两种方式:

1.1 使用继承:

将父对象(更抽象的对象/或者说基类)设置成为一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。

class Aninal{
    
	void sound(发出声音);//sound是动物的一个叫声方法
}

class cat extend Animal{
   
	sound();
}
class dog extend Animal{
   
	sound();
}
//Animal a 可以根据其具体的子对象(cat dog)来发出声音
//这就是多态,animal根据其子类表现出了不同的特性
Animal a = new dog();
a.sound();

Animal a = new cat();
a.sound();

从上面可能并没有表现出多态的真正作用,后面我会详细解释。

1.2 实现接口(推荐):

在某种程度上来说,接口是一种更为广泛的概念,并不仅仅是Java语法中的Interface,在编程思想中,凡是一种抽象对象,作为一个中间接入的都是接口。但这里我们只说Java中通过Interface来实现多态。

其实在我看来,Java的Interface可以看做是一个特殊的对象,一个普通对象可以实现多个接口(类似于继承多个Interface)。因为Java中只允许单继承,但是很多情况下,为了提高程序的扩展性,需要支持这种实现多个接口的功能,于是才有了Interface。

interface Animal {
   
	void sound()//接口中不写具体实现
}
class cat implements Animal {
   
	//具体实现类必须要实现接口中的方法
	@Override
	public void sound(喵喵喵);
}

但是得提醒一点,实现接口并不等同于是多重继承,这种实现接口的方式,还弥补了多重继承的不足。因为实现接口,要求子类必须实现接口方法,而多重继承则不会有这种强制要求,这就有可能造成多重继承的混乱,比如砖石问题:

有两个类B和C继承自A。假设B和C都继承了A的方法并且进行了覆盖,编写了自己的实现。假设D通过多重继承继承了B和C,那么D应该继承B和C的重载方法,那么它应该继承哪个的呢?是B的还是C的呢?

另外补充说一句,像python、C++语言就没有Interface,因为他们支持多继承,所以在这些语言中,普通类就可以直接实现多继承,从而实现Java的接口功能,所以我上面才说接口不仅仅是Interface,接口更是一种程序设计的概念。

总结一下,在实现多态时,推荐通过实现Interface来实现,因为在软件开发的过程中,无法保证当前对象只需要来自于一个基类的功能,可能在后期的开发中,还要有其他功能需要实现,而由于java的单继承特性无法满足后面的扩展要求。

所以推荐将一些通用对象做成接口,这样方便以后扩展。其实Java语言中有很多这样的体现,比如说在实践开发中对于很多对象,需要同时实现序列化接口、可比较接口等,这就需要在类中重写这些接口方法。

2.作用

基本功能上来说,就是解决项目中紧偶合的问题,提高程序的可扩展性.。耦合度讲的是模块模块之间,代码代码之间的关联度,通过对系统的分析把他分解成一个一个子模块,子模块提供稳定的接口,达到降低系统耦合度的的目的,模块模块之间尽量使用模块接口访问,而不是随意引用其他模块的成员变量。

应用程序不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可。大大提高程序的可复用性。//继承

派生类的功能可以被基类的方法或引用变量所调用,这叫向后兼容,可以提高可扩充性和可维护性。 //多态的真正作用

下面举一个例子来说明,如何通过多态来降低耦合,提高程序的可扩展性。

class master {
   
	//主人对象,buy_pet,购买宠物
	List<> pets = new ArrayList<Animal>();
	public void buy_pet(Animal a){
   pets..add(a);}
}

当我们需要买dog时,我们只需要传一个dog对象即可,当我们买cat时只需要传一个cat对象,而不需要在master类中写多个关于不同参数动物对象的buy_pet方法。

而且当宠物店进了新品种,master也不需要改动,只需要新品种实现Animal接口即可。这就实现了降低master同具体宠物之间的耦合,提高了程序的可扩展性,master对象和具体宠物对象只需要通过Animal接口来进行访问。

3.多态的实现原理

说到原理,就不得不提到,Java前期(静态)绑定和后期(动态)绑定。

3.1 Java 动态绑定以及内部实现机制

首先是方法的参数是父类对象,传入子类对象是否可行,然后引出Parent p = new Children();这句代码不是很理解,google的过程中引出向上转型,要理解向上转型又引出了动态绑定,从动态绑定又引出了静态绑定。

程序绑定的概念

绑定指的是一个方法的调用与方法所在的类(方法主体)关联起来。对Java来说,绑定分为静态绑定和动态绑定,或者叫做前期绑定和后期绑定。

(1)静态绑定:
在程序执行前方法已经被绑定,此时由编译器或其它连接程序实现。例如:C。
针对Java简单的可以理解为程序编译期的绑定;这里特别说明一点,Java当中的方法只有final、static、private和构造方法是前期绑定。

(2)动态绑定:
后期绑定:在运行时根据具体对象的类型进行绑定。
若一种语言实现了后期绑定,同时必须提供一些机制,可在运行期间判断对象的类型,并分别调用适当的方法。
也就是说,编译器此时依然不知道对象的类型,但方法调用机制能自己去调查,找到正确的方法主体。不同的语言对后期绑定的实现方法是有所区别的。但我们至少可以这样认为:它们都要在对象中安插某些特殊类型的信息。

动态绑定的过程:

  1. 虚拟机提取对象的实际类型的方法表;
  2. 虚拟机搜索方法签名;
  3. 调用方法。
关于final、static、private和构造方法是前期绑定的理解
  1. 对于private的方法,首先一点它不能被继承,既然不能被继承那么就没办法通过它子类的对象来调用,而只能通过这个类自身的对象来调用。因此就可以说private方法和定义这个方法的类绑定在了一起。

  2. final方法虽然可以被继承,但不能被重写(覆盖),虽然子类对象可以调用,但是调用的都是父类中所定义的那个final方法,(由此我们可以知道将方法声明为final类型,一是为了防止方法被覆盖,二是为了有效地关闭Java中的动态绑定)。

  3. 构造方法也是不能被继承的(网上也有说子类无条件地继承父类的无参数构造函数作为自己的构造函数,不过个人认为这个说法不太恰当,因为我们知道子类是通过super()来调用父类的无参构造方法,来完成对父类的初始化, 而我们使用从父类继承过来的方法是不用这样做的,因此不应该说子类继承了父类的构造方法),因此编译时也可以知道这个构造方法到底是属于哪个类。

  4. 对于static方法,具体的原理我也说不太清。不过根据网上的资料和我自己做的实验可以得出结论:static方法可以被子类继承,但是不能被子类重写(覆盖),但是可以被子类隐藏。(这里意思是说如果父类里有一个static方法,它的子类里如果没有对应的方法,那么当子类对象调用这个方法时就会使用父类中的方法。而如果子类中定义了相同的方法,则会调用子类的中定义的方法。唯一的不同就是,当子类对象上转型为父类对象时,不论子类中有没有定义这个静态方法,该对象都会使用父类中的静态方法。因此这里说静态方法可以被隐藏而不能被覆盖。这与子类隐藏父类中的成员变量是一样的。隐藏和覆盖的区别在于,子类对象转换成父类对象后,能够访问父类被隐藏的变量和方法,而不能访问父类被覆盖的方法)

由上面我们可以得出结论,如果一个方法不可被继承或者继承后不可被覆盖,那么这个方法就采用的静态绑定。

Java的编译与运行

Java的编译过程是将Java源文件编译成字节码(JVM可执行代码,即.class文件)的过程,在这个过程中Java是不与内存打交道的,在这个过程中编译器会进行语法的分析,如果语法不正确就会报错。

Java的运行过程是指JVM(Java虚拟机)装载字节码文件并解释执行。在这个过程才是真正的创立内存布局,执行Java程序。

Java字节码的执行有两种方式:
(1)即时编译方式:解释器先将字节编译成机器码,然后再执行该机器码;
(2)解释执行方式:解释器通过每次解释并执行一小段代码来完成java字节码程序的所有操作。(这里我们可以看出Java程序在执行过程中其实是进行了两次转换,先转成字节码再转换成机器码。这也正是Java能一次编译,到处运行的原因。在不同的平台上装上对应的Java虚拟机,就可以实现相同的字节码转换成不同平台上的机器码,从而在不同的平台上运行)

关于绑定相关的总结:

在了解了三者的概念之后,很明显我们发现Java属于后期绑定。
在Java中几乎所有的方法都是后期绑定的,在运行时动态绑定方法属于子类还是基类。
但是也有特殊,针对static方法和final方法由

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小山研磨代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值