一、引用变量的两种类型

1. 编译时类型:由声明该变量时使用的类型决定

2. 运行时类型:由实际赋给该变量的对象决定

如果编译时类型和运行时类型不一致,就可能出现多态。

class BaseClass
{
public int val = 6;
public void base()
{
System.out.println("父类的普通方法");
}
public void test()
{
System.out.println("父类的被覆盖的方法");
}
} public class SubClass extends BaseClass
{
public String val = "测试多态";
public void test()
{
System.out.println("子类的覆盖父类的方法");
}
public void sub()
{
System.out.println("子类的普通方法");
} public static void main(String[] args)
{
// 编译时类型为BaseClass,运行时类型为SubClass
BaseClass bc = new SubClass(); // 访问的是父类对象的实例变量,即输出6
System.out.println(bc.val);
// 调用从父类继承到的base()
bc.base();
// 调用当前类的test()
bc.test();
// 因为bc的编译时类型是BaseClass,而该类没有提供sub(),所以下面代码编译时会出错
// bc.sub();
}
}

注:上面程序中定义的引用变量bc,其编译时类型为BaseClass,而运行时类型为SubClass。当调用引用变量bc的test()方法时,实际执行的是SubClass类中覆盖后的test()方法,这就可能出现多态了。此外,虽然引用变量bc实际所引用的对象确实包含sub()方法(例如,可以通过反射来执行该方法),但由于引用变量在编译阶段只能调用其编译时类型所具有的方法,因此编译时无法调用sub()方法。即引用变量只能调用它编译时类型的方法,而不能调用它运行时类型的方法,即使它实际所引用的对象确实包含该方法。

3. 引用变量在编译阶段只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的方法

二、多态的原理

1. Java允许把一个子类对象直接赋给一个父类引用对象,这也被称为向上转型

2. 当调用这种引用对象的方法时,其方法行为总是表现出子类方法的行为特征,而不是父类方法的行为特征

3. 这就导致:相同类型的变量调用同一个方法时呈现出多种不同的行为特征,这就是多态

三、引用变量的强制类型转换

1. 如果需要让某个引用变量调用它运行时类型的方法,则必须把它强制转换成运行时类型,即将一个引用类型变量强制转换成其子类类型

  • 引用类型之间的转换只能在具有继承关系的两个类型之间进行,否则编译时就会出现错误
  • 如果试图把一个父类实例转换成子类类型,则这个对象必须实际上是子类实例才行(即其运行时类型是子类类型)
public class ConversionTest
{
public static void main(String[] args)
{
double d = 3.14;
long l = (long)d; // objStr变量的编译时类型为Object,运行时类型为String
Object objStr = "Hello";
// 由于Object与String存在继承关系,可以强制类型转换
String str = (String)objStr; // objInt变量的编译时类型为Object,运行时类型为Integer
Object objInt = Integer.valueOf(5);
// 由于Object与Integer存在继承关系,可以强制类型转换
Integer intNum = (Integer)objInt;
// 虽然Object与String存在继承关系,可以强制类型转换
// 但是objInt的运行时类型不是String,故下面代码运行时引发ClassCastException异常
// String str = (String)objInt;
}
}

2. 由于进行强制类型转换时可能出现异常,因此进行类型转换之前应先通过instanceof运算符来判断是否可以成功转换,使程序更健壮

  • 通常先用instanceof判断一个对象是否可以强制类型转换,然后再使用(type)运算符进行强制类型转换,从而保证程序不会出现错误
		if(objInt instanceof String)
{
String str = (String)objInt;
}

四、instanceof运算符

1. instanceof是Java提供的运算符,与+、-等算术运算符的用法大致相似

2. 用法:实例 instanceof 类名(或接口名)

  • 实例的编译时类型要么与后面的类相同,要么与后面的类具有父子继承关系,否则会引起编译错误

3. 作用:判断其左侧的实例是否是右侧的类(或者其子类、实现类)的实例

  • 在进行instanceof运算时,左侧的实例以其运行时类型为判断依据
public class InstanceofTest
{
public static void main(String[] args)
{
Object objStr = "Hello"; // objStr的编译时类型是Object,故可进行instanceof运算
if(objStr instanceof Object) // 返回true
{
System.out.println("字符串是Object类的实例");
} // objStr的编译时类型是Object,Object类与String类存在继承关系
// 所以可以进行instanceof运算
if(objStr instanceof String) // 返回true
{
System.out.println("字符串是String类的实例");
} // objStr的编译时类型是Object,Object类与Math类存在继承关系
// 所以可以进行instanceof运算
if(objStr instanceof Math) // 返回false
{
}
else
{
System.out.println("字符串不是Math类的实例");
} String str = "Hello";
// String类与Math类没有继承关系,所以下面的代码无法编译通过
// if(str instanceof Math) { ... }
}
}

8. 多态——编译时类型&运行时类型的更多相关文章

  1. 正确理解java编译时,运行时以及构建时这三个概念

    Java中的许多对象(一般都是具有父子类关系的父类对象)在运行时都会出现两种类型:编译时类型和运行时类型,例如:Person person = new Student();这行代码将会生成一个pers ...

  2. 深入浅出OOP(三): 多态和继承(动态绑定/运行时多态)

    在前面的文章中,我们介绍了编译期多态.params关键字.实例化.base关键字等.本节我们来关注另外一种多态:运行时多态, 运行时多态也叫迟绑定. 运行时多态或迟绑定.动态绑定 在C#语音中,运行时 ...

  3. Java源文件编译成功但是运行时加载不到文件

    最近系统重装了一些,Java等环境变量都需要重新配置,配置好以后编写了一个Java源文件编译了一下,通过Javac编译源文件,编译成功,但是再通过Java运行时没找到报出找不到加载文件或者加载文件不存 ...

  4. Linux下显示运行时链接(运行时加载)

    目录 介绍 如何加载动态库 dlopen() 第一个参数: 被加载动态库的路径 第二个参数: flag表示函数符号的解析方式 dlopen 返回值 dlsym() 参数: 返回值 符号优先级 dler ...

  5. 在引用KindEditor编辑器时,运行时出现以下错误:错误46 找不到类型或命名空间名称“LitJson”(是否缺少 using 指令或程序集引用?)

    将asp.net下bin文件夹下的文件LitJSON.dll拷贝到工程的bin目录下,并在工程中添加引用 在后台加入: using LitJson;

  6. gcc新版本号引起的编译错误(命令运行时的外部库输入位置)

    昨天,遇到一个比較bug的错误,用gcc来编译几个简单的文件出错,编译环境为x86_64的Ubuntu12.04.gcc版本号号例如以下: gcc (Ubuntu/Linaro 4.6.3-1ubun ...

  7. 使用Spring4时, 运行时出现找不到MappingJacksonHttpMessageConverter的情况

    启动项目报错: [org.springframework.web.context.ContextLoader]Context initialization failed org.springframe ...

  8. Spring3升级到Spring4时, 运行时出现找不到MappingJacksonHttpMessageConverter的情况

    [org.springframework.web.context.ContextLoader]Context initialization failed org.springframework.bea ...

  9. [调试]VS2013调试时提示“运行时当前拒绝计算表达式的值”

    VS2013 下单元测试调试时遇到的问题,以前倒从未遇到过. 中文关键字在百度和谷歌中搜索均无果. Google 下搜索 “The runtime has refused to evaluate th ...

随机推荐

  1. IDEA org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):

    引用地址:https://guozh.net/idea-org-apache-ibatis-binding-bindingexception-invalid-bound-statement-not-f ...

  2. 记录C#连接数据库工具类

    一.SQL Server /// <summary> /// 数据库的通用访问代码 /// 此类为抽象类, /// 不允许实例化,在应用时直接调用即可 /// </summary&g ...

  3. chattr lsattr linux file system attributes - linux 文件系统扩展属性

    我们使用 linux 文件系统扩展属性,能够对linux文件系统进行进一步保护:从而给文件 赋予一些额外的限制:在有些情况下,能够对我们的系统提供保护: chattr命令用来改变文件属性.这项指令可改 ...

  4. 算法问题实战策略 MEETINGROOM 附一份tarjan模板

    地址 https://algospot.com/judge/problem/read/MEETINGROOM 解答  2-sat 代码样例过了 没有ac. 我又没有正确代码对拍..... 已确认是输出 ...

  5. c++用流控制成员函数输出数据

    #include<iostream> #include<iomanip> using namespace std; int main() { ; double b=314159 ...

  6. C语言程序设计100例之(13):最大子段和

    例13        最大子段和 题目描述 给出一段序列,选出其中连续且非空的一段使得这段和最大.例如在序列2,-4,3,-1,2,-4,3中,最大的子段和为4,该子段为3,-1,2. 输入格式 第一 ...

  7. numpy的一点学习

    1.Numpy模块 NumPy是Python中的一个运算速度非常快的一个数学库,它非常重视数组.它允许你在Python中进行向量和矩阵计算,并且由于许多底层函数实际上是用C编写的,因此你可以体验在原生 ...

  8. flex——justify-content属性引起的一个样式问题

     前言  在flex布局出现以前,我一般习惯使用浮动布局(float)来实现下列布局   现在尽量少用浮动布局,虽然好用,但有时会带来一些意想不到的问题,甚至导致布局错位,   一开始浮动布局只是为了 ...

  9. docker安装完报错:Failed to start docker.service: Unit docker.service is masked

    执行 systemctl start docker 报错 Failed to start docker.service: Unit docker.service is masked. 解决 syste ...

  10. 【踩坑系列】VS2019提示 ' the package could not be found in c\users\username\nuget\packages\. '

    解决步骤 1.删除对应项目下的 obj 文件夹 2.重新生成该项目