一.向上转型的定义
当我们用父类的(包括直接父类和间接父类)凭证去指向子类的对象实例时,就叫做向上转型.
例子:
class A{
}
class B extends A{
}
那B类是子类,A类是父类.
对于B类,如果我们想使用B类. 则正常的实例化过程如下:
B b=new B();
那向上转型表示如下:
B b=new B();
A a=b;
也可以一步到位:
A a=new B();
a.
二.向上转型的特点
①对于成员方法
去父类寻找这个方法(再次强调是通过方法名称和参数列表)
a.若这个方法父类不存在,则不能通过编译。
b.若这个方法父类存在,则访问的是子类的方法。
②对于成员变量
a.父类不存在这个成员变量,则不能通过编译
b.仅仅能访问到父类的成员变量!
③方法参数列表中的向上转型(特点同上面两点)
(提高性内容:若存在方法的重载,并且重载后的方法参数列表都是父类,则选取结构图中最近的方法调用)
三.向下转型定义
当我们用子类的凭证去指向父类的凭证时,就叫做向下转型.
class A{
}
class B extends A{
}
class C extends A{
}
那B类是子类,A类是父类.
对于B类,如果我们想使用B类. 则正常的实例化过程如下:
B b=new B();
那向下转型表示如下:
B b=new B();
A a=b;
B b=(B)a;
注意:向下转型可能会产生运行时的错误:
C c=new C();
A a=c;
B b=(B)a;
一般向下转型正确的话:
①一定经历了向上转型
②转型到的可以是对象的真实类型或者对象的父类(一个对象真正的类型是它自己本身的类)
四.向下转型的特点
①可能会产生运行时的错误(编译不会报错)
②向下转型并不一定会转到真正的类型上,如果仍然转到的是一个父类。则遵从我们上面所说的向上转型的特点.
③如果没有报错,对于转型后的访问和正常申明后(可能也涉及到向上转型)的访问没有区别
五.避免向下转型报错的办法
使用instanceof 关键字
①关键字介绍:判断 对象 是不是 该类的子类或者本身。
举例: a instance of A 即a是否是A类本身或者是A类的子类.
②具体使用:利用instanceof 判断后,进行向下转型从而使用子类特有的方法.
六.多态性
①多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编译时并不确定,而是在程序运行期间才确定,这就是多态性
②多态的存在有三个前提:
1.要有继承关系
2.子类要重写父类的方法
3.父类引用指向子类对象
下面来两题实例
class A{
int age=18;
void test(){
System.out.println("A的test");
}
void specialA(){
System.out.println("The age of A is "+age);
}
}
class B extends A{
String age="18B";
void specialB(){
System.out.println("The age of B is "+age);
}
}
class C extends B{
int height=180;
int getHeight(){
return height++;
}
void specialC(){
System.out.println("The age of C is "+age);
}
}
class D extends C{
int height=190;
void specialD(){
System.out.println("The age of D is "+age);
}
void exam(A a){
E e=(E)a;
e.specialE();
}
}
根据要求编写代码并回答问题(依靠ABCDE四个类)
1.D中exam方法体内,在方法体内写a. 能找到的方法有哪些?
Test(),specialA()
2.补充D中exam的方法体,并新建一个Entrance类,在主方法中写出满足下列要求的代码:
a.编译不报错,运行会crash的代码(要写两段代码,一个是空指针,一个是类型转换错误)
a.test();
A a = null;
new D().exam(a);
void exam(A a){
D d =(D) a;
a.specialA();
}
B b=new B();
D d = new D();
d.exam(b);
b.如果exam方法体中向下转型到C,主方法中调用传入的对象是D,则改写exam方法的参数列表避免向下转型
void exam(C c){
C c1=(C) c;
c1.specialA();
}
3.写一段具有多态性质的代码,并说明为什么具有多态性
class Animal {
void eat() {
}
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void work() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void work() {
System.out.println("看家");
}
}
class Test1 {
public static void main(String[] args) {
Animal a = new Cat(); // 向上转型
a.eat(); // 调用的是 Cat 的 eat
Cat c = (Cat) a; // 向下转型
c.work(); // 调用的是 Cat 的 work
}
}
4.为什么有些时候要使用向下转型
向下转型是因为向上转型之后,子类与父类不共同都有的方法不能使用,所以我要转回来,我要使用父类中没有但是子类拥有的方法
请说明下列代码运行结果并说明结果原因(依靠ABCDE四个类):
1.
D d=new D();
System.out.println(d.getHeight());
180
因为D类中没有getHeight()方法(没有重写这个方法),然后D又继承了C,就去调用C的getHeight()
A a=new B();
System.out.println(a.age);
18
因为向上转型仅仅能访问到父类的成员变量
3.D中的exam方法如下:
void exam(A a){
E e=(E)a;
e.specialE();
}
主方法中:
C c=new C();
D d=new D();
d.exam(c);
报错,类型转换错误,因为E是A的子类,等式左边需要是右边的父类或者本类,不然就会这样发生崩溃
4.如何改变层级图,使得3中的代码正常
让E成为C的父类
5.在D中的exam方法体中编写一段if else控制语句使得向下转型安全,并写两段代码让if为true的到执行,else也得到执行。
额外问题1:
不运行代码,考虑如下判断是否正确,为什么
A a=new C();
a instanceOf C
正确,A是C的父类,a是A变量类型
额外问题2:
继承关系为B是A的子类,C是B的子类。
A a=new C();
B b=new B();
b=a;
1.请说出如上代码中a和b变量的变量类型分别都是什么
A B
2.请说出赋值语句是否需要强转看的是变量类型还是对象类型
变量
3.如上代码如何更改可以通过编译
b= (B) a;
4.运行阶段有几个对象生成,每个对象有几个变量指向它,指向这些对象的变量的变量类型是什么?
2个对象生成,a,b指向C,B没有指向,ab都是A类型
5.运行期间,java对指向一个对象的过程变量的变量类型有什么限定么?
变量类型需要是对象的父类或者本类
另外主函数调用exam方法传参的相当于
A a =(A)c