Java面向对象的多态
Java中多态的概念是面向对象中除封装和继承外非常重要的知识点,也是Java面向对象三大特性最后一个特性
多态其实就是指对象存在的多种形态,多态分为引用多态和方法多态
引用多态的含义就是:父类的引用可以指向它本类的对象,不仅如此父类的引用还可以指向子类的对象,这就是引用多态
用简单的代码来看一下引用多态的含义:
动物类:Animal
public class Animal {
public Animal(){
System.out.println("Animal类的构造方法被执行");
}
}
狗类:Dog
public class Dog extends Animal{
public Dog(){
System.out.println("Dog类的构造方法被调用");
}
}
然后来测试一下:
public class Initail {
public static void main(String[] args){
Animal animal = new Animal(); //父类的引用指向本类对象
Animal dog = new Dog(); //父类的引用指向了子类对象
Dog dog1 = new Dog(); //子类引用只能指向子类对象
}
}
由代码可以看出,父类的引用既可以指向本类对象,也可以指向子类对象,体现了引用多态,但是注意子类引用不能指向父类的对象,只能指向本类的对象
另外看一下方法多态,当我们使用引用多态创建对象时,如果是创建的本类对象,那么调用方法是本类的方法,如果创建的是子类对象,那么调用的方法是子类重写的方法或者未重写直接继承父类的方法,这个和前面继承只是多了个引用,其实还是很好理解的,正因为引用的多态,所以方法的调用也存在多态性,这就是方法多态
另外,如果我们在子类中定义了一个子类独有的方法,而不是父类继承过来或者重写的方法,只有子类中有方法,那么我们只能用子类的引用去访问该方法,比如实例中只能通过dog1去访问独有的方法,用父类的引用指向子类对象的方式是无法访问的
引用类型转换
因为多态有多种引用类型,因此我们会经常用到引用类型转换,引用类型转换也分为以下两种:
首先是向上类型转换,这种转换有时候也是系统隐式进行转换的,这个时候编译器自动完成小类型到大类型的转换,我们也可以手动转换
然后是向下类型转换,也叫强制类型转换,这是大类型到小类型的转换
向上类型转换是不存在风险的,就好像把水杯的水倒在水壶里一样,因为由小到大所以不存在任何问题
但是向下类型转换是存在风险的,我们可以强制进行转换,但是我们必须对引用类型有个明确的认识,否则有可能产生溢出等严重的错误
下面看一个简单的例子:
Dog dog = new Dog();
Animal animal = dog; //向上类型转换,自动类型转换
//Dog dog2 = animal;虽然这样是可以的,但是为了安全,编译器还是报错
Dog dog2 = (Dog)animal; //向下强制类型转换,给出警告但不报错
Cat cat = (Dog)animal; //强制类型转换,不报错但程序无法执行
我们实例化了dog对象,那么第2行是子类对象转换为父类对象,所以是安全的,第3行虽然根据前面的引用,直接转换是可行的,但是编译器不允许这么做,因为程序存在风险,所以第4行中进行了强制类型转换是可以转换的,只是编译器还是提示有风险,在第5行,虽然进行了强制类型转换,编译器也没有报错,但是程序执行会发生异常,因为cat对象和dog对象两个对象是实例化自不同的类本身就没有什么关系,类型不存在转换关系,所以是无法强制转换的;
那么怎么解决引用类型转换中的问题实现安全转换呢? 我们可以使用instanceof关键字来避免类型转换的安全问题,代码如下:
Dog dog = new Dog();
Animal animal = dog; //自动类型转换无需做任何处理
if(animal instanceof Dog){
Dog dog2 = (Dog)animal; //可以进行强制类型转换
}else{
System.out.println("animal无法进行强制类型转换为Dog");
}
if(animal instanceof Cat){
Cat cat = (Cat)animal; //可以转换
}else{
System.out.println("animal无法进行强制类型转换为Cat");
}
所以这个程序执行输出是:
animal无法进行强制类型转换为Cat
所以前者可以转换,后面无法转换,因此通过instanceof关键字可以很好地解决引用类型转换的问题
抽象类
抽象类也是类的一种,前面使用abstract修饰,来表示为抽象类
抽象类是作为某个类的父类,只知道子类中应该包含哪些方法,而并不关注子类如何实现这些方法,所以抽象类的存在是主要目的就是为了约束子类内部必须拥有某些方法;
另外我们可以把具有大量共同特点的类抽象出来,总结一系列系统的方法,所有的子类都以该抽象类为模板进行设计,简单来说,抽象类就是一个包含特定方法名的模板,子类必须去一一实现他,这样避免了子类设计的随意性,导致设计混乱
总结一句话:抽象类规定了子类必须有这些方法,但不考虑如何实现
public abstract class Telphone{
//抽象方法定义
public abstract void call(); //直接以分号结束
public abstract void message();
}
如同上面类就是一个抽象类,定义的是一个手机类,意思是不管是什么类型的手机,必须具备打电话和发短信的方法,注意抽象方法没有实现,直接在方法后加分号即可
下面我们可以写一个类继承这个抽象类
public class Cellphone extends Telphone{
//普通手机类继承电话类
public void call(){
//具体实现打电话方法,用键盘拨号打电话
}
public void message(){
//具体实现发短信方法,用键盘打字发短信
}
}
我们定义了一个普通手机类来继承了手机类,并且具体根据实际情况实现了手机类中全部的抽象方法,
public class Smartphone extends Telphone{
//智能手机类继承手机类
public void call(){
//具体实现打电话方法,用触屏拨号打电话
}
public void message(){
//具体实现发短信方法,用语音直接发短信
}
}
现在我们又定义了一个智能手机类来继承手机类,并且以另一种新的实现方法实现了打电话和发短信的功能
通过这个例子,手机抽象类其实就是一个模板,里面定义了作为手机必须要实现的方法,而不考虑怎么实现,具体实现由不同的手机类型来实现各自的方法,这样体现了同一个抽象类的子类既有共性,又有特点
在引用的时候,我们可以根据引用多态的方式,统一创建父类抽象类的引用指向具体的不同对象,这样提高了程序设计的灵活性,让程序更加清晰
接口
接口可以认为是java中非常重要而又特殊的一种类,类是一种具体实现体,而接口定义了某一批类所要遵守的规范,接口和抽象类类似,也是不关注这些类的内部数据,也不关心这些类里方法的实现细节,它只是规定这些类里面必须提供某些方法,满足我们的某些需要,所以接口也是约束类的一个规范;
接口定义的语法如下:
public interface 接口名 [extends 父接口1,父接口2,....]
{
多个常量定义....
多个抽象方法定义...
}
接口的存在就是约束类的一个规范,所以必须被类继承、实现的,所以访问修饰符就用public,不要用private或者protected来修饰,否则就失去了接口的作用
因为接口内部全部是常量或者抽象方法的定义,所以接口也是abstract抽象类型的,所以准确来说在public和interface之间应该加上abstract来修饰,因为系统会自动添加抽象关键字,所以我们一般就不写了
接口里面的属性都是常量,定义属性应该是:public static final int a = 1;即使我们定义的时候不写那么全,系统也会自动补全
接口中的方法都是抽象公共的方法,定义方法应该是:public abstract void call();即使我们不写abstract和public,系统也会自动补全
类是单继承的,但是接口是多继承的,接口可以继承一个或多个接口,也可以不继承接口
具体类可以实现某个接口,并且可以实现一个或多个接口,所以这样使用起来更加灵活,实现方法如下:
public class 类名 implements 接口1,接口2,...
{
//要实现接口中规定的抽象方法
}
所以实现接口的关键字是implements,一个类还可以在继承某一个类的同时实现接口
public class 类名 extends 父类 implements 接口1,接口2,...
{
//实现接口中的抽象方法
}
并且上面的顺序不能颠倒,extends必须在implements前面
和抽象类一样,一个类继承了一个抽象类,则必须实现抽象类中所有的抽象方法,如果一个类实现了接口,则必须实现接口所规定的所有抽象方法,根据编程的习惯,抽象类一般以大写字母I开头,代表定义的接口
举个例子看一下:
public interface IPlayGame {
//定义一个玩游戏的接口,规定一个玩游戏的方法
public void playGame();
}
public class Psp implements IPlayGame {
public void playGame() {
// Psp实现了游戏接口中的玩游戏方法
System.out.println("我用Psp玩游戏");
}
}
public class SmartPhone extends Telphone implements IPlayGame{
public void call() {
// 实现抽象类中的打电话方法
System.out.println("通过触屏拨号打电话");
}
public void message() {
// 实现抽象类中发短信的方法
System.out.println("通过语音发短信");
}
public void playGame() {
// 手机也实现接口中的玩游戏方法
System.out.println("我用手机也可以玩游戏");
}
}
由上面的代码可以看出,对于一个玩游戏的接口,我可以用Psp来实现玩游戏这个方法,也可以用手机来实现玩游戏这个方法,手机实现玩游戏这个方法的同时还继承了手机抽象类,同时实现了抽象类中的所有抽象方法,个人感觉利用抽象类和接口可以让程序功能分工明确,管理系统,各司其职
public class Initail {
/**
* @param args
*/
public static void main(String[] args) {
IPlayGame ip1 = new SmartPhone();
ip1.playGame();
IPlayGame ip2 = new Psp();
ip2.playGame();
}
}
对于抽象类和接口,都可以使用抽象类和接口的引用具体指向某个类,接口的方法用接口指向,抽象类的方法用抽象类指向,让方法的调用更加简单统一
接口还有另外一种使用方式,就是和前面封装特性中提到的匿名内部类配合使用,匿名内部类就是没有名字的内部类,作用是关注具体的实现细节而不关注实现类的名称,只在使用的同时定义一次,下面看一下简单的匿名内部类实现接口:
public class Initail {
/**
* @param args
*/
public static void main(String[] args) {
IPayGame ip = new IPayGame(){
//接口的具体实现
public void playGame(){
System.out.println("使用匿名内部类的方式实现接口");
}
};//这里用分号结束
ip.playGame(); //直接调用匿名内部类的playGame方法
}
}
注意匿名内部类花括号必须后面紧跟分号结尾,另外还有一种更简单的匿名内部类实现接口的方法:
public class Initail {
/**
* @param args
*/
public static void main(String[] args) {
new IPayGame(){
//接口的具体实现
public void playGame(){
System.out.println("使用匿名内部类的方式实现接口");
}
}.playGame(); //通过点直接通过匿名内部类的实现接口的playGame方法
}
}
通过以上这种方式也可以直接连贯的实现接口,避免的其他的过渡,这样更加直接了当,其实在Android开发中以及Java高级框架中,经常会使用匿名内部类直接实现接口的方法
以上就是多态的特性介绍和抽象类接口的简单理解和使用,特别是接口概念,随着开发的不断进步,对接口的认识每次都不一样,对接口的理解也是不断深入的,只能不断通过实践加深认识和激发新的思考,如果有心得再继续补充
Java面向对象的多态的更多相关文章
- Java面向对象之多态(来源于身边的案例)
2019年1月3日 星期四 Java面向对象之多态(来源于身边的案例) 1. 为什么要用多态? 1.1 多态是面向对象的三大特性之一 1.2 多态是基于接口设计的模型 1.3 多态具有横向扩展特性 1 ...
- java面向对象之 多态 Polymorphism
多态(Polymorphism):用我们通俗易懂的话来说就是子类就是父类(猫是动物,学生也是人),因此多态的意思就是:父类型的引用可以指向子类的对象. 1.多态的含义:一种类型,呈现出多种状态 主要讨 ...
- Java面向对象特性--多态
Java是一种面向对象的编程语言,面向对象的三大特性就是继承,封装,多态.下面细细说一说多态. 多态的定义:一个事物的多种形态,指允许不同类的对象对同一消息做出响应.即同一消息可以根据发送对象的不同而 ...
- JavaSE入门学习18:Java面向对象之多态
一Java多态 多态是同一个行为具有多个不同表现形式或形态的能力. 多态性是对象多种表现形式的体现.比方我们说"宠 物"这个对象.它就有非常多不同的表达或实现,比方有小猫.小狗.蜥 ...
- Java 面向对象_多态
多态图解 代码中体现多态性 父类名称 对象名 = new 子类名称(); or 接口名称 对象名 = new 实现类名称(); // 父类 public class Father { public v ...
- 对Java面向对象中多态的理解
理解的要点:多态意味着父亲的变量可以指向子类对象 面向对象程序设计的三大支柱是封装.继承和多态 封装对外把相应的属性和方法实现的细节进行了隐藏.继承关系使一个子类继承父亲的特征,并且加上了一些新的特征 ...
- Java面向对象11——多态
多态 package oop.demon01.demon06; public class Application { public static void main(String[] a ...
- Java面向对象:多态
多态:具有表现多种形态的能力的特征(同一个实现接口,使用不同的实例而执行不同的操作) 实现多态的优点:为了方便统一调用! 实现多态的三种方式! 1:子类到父类的转换: 例: 1 Dog dog=new ...
- Java面向对象之多态
多态:具有表现多种形态的能力的特征(同一个实现接口,使用不同的实例而执行不同的操作) 实现多态的优点:为了方便统一调用! 实现多态的三种方式! 1:子类到父类的转换: 例: Dog dog=new D ...
随机推荐
- Spring-如何实现事物管理的
事务的实现方式 实现方式共有两种:编码方式:声明式事务管理方式.基于AOP技术实现的声明式事务管理,实质就是:在方法执行前后进行拦截,然后在目标方法开始之前创建并加入事务,执行完目标方法后根据执行情况 ...
- Java虚拟机的功能
1:通过ClassLoader寻找和装载class文件 2:解释字节码成为指令并执行,提供class文件的运行环境.即将字节码转换为不同OS下可执行的机器码指令. 3:进行垃圾回收. 4:提供与硬件交 ...
- sprintf、strcpy和memcpy的区别
做某题用到了sprintf把一个字符数组(字符串)写到二维字符数组里,然后耗时挺长的,想了想strcpy好像也可以,事实证明strcpy效率果然更高,然后想了想觉得memcpy好像也可以.实践了一下的 ...
- 在网络7层协议中,如果想使用UDP协议达到TCP协议的效果,可以在哪层做文章?(QQ 为什么采用 UDP 协议,而不采用 TCP 协议实现?)
为了解决这题,可以具体看看下面这个讨论. 解灵运工程师 185 人赞同 某次架构师大会上那个58同城做即时通信的人说:原因是因为当时没有epoll这种可以支持成千上万tcp并发连接的技术,所以他们使用 ...
- Spring AOP中定义切点(PointCut)和通知(Advice)
如果你还不熟悉AOP,请先看AOP基本原理,本文的例子也沿用了AOP基本原理中的例子.切点表达式 切点的功能是指出切面的通知应该从哪里织入应用的执行流.切面只能织入公共方法.在Spring AOP中, ...
- POJ2049Finding Nemo(bfs + 构图)
Finding Nemo Time Limit: 2000MS Memory Limit: 30000K Total Submissions: 8456 Accepted: 1975 Desc ...
- java 内存分析
Java堆内存(heap memory)的十个要点: 1. Java堆内存是操作系统分配给JVM的内存的一部分. 2. 当我们创建对象时,它们存储在Java堆内存中. 3. 为了便于垃圾回收,Java ...
- Hibernate检索策略(抓取策略)(Hibernate检索优化)
一.查询方法中get方法采用策略是立即检索,而load方法采用策略是延迟检索,延迟检索是在使用数据时才发送SQL语句加载数据 获取延迟加载数据方式:1.使用的时候,如果Customer c=sessi ...
- Unity3d三大光照渲染介绍
重要:在目前市面上常见的游戏引擎中,主要采用以下三种灯光实现方式: 顶点照明渲染路径细节 Vertex Lit Rendering Path Details 正向渲染路径细节 Forward Re ...
- DedeCms 5.x 本地文件包含漏洞(respond方法)
漏洞版本: DedeCms 5.x 漏洞描述: DedeCms是免费的PHP网站内容管理系统. plus/carbuyaction.php里没有对变量进行严格的过滤 出现漏洞的两个文件为: Inclu ...