Java学习笔记12---向上转型-父类的对象引用指向子类对象
当父类的对象引用没有指向父类的对象,而是指向了子类的对象时,调用方法或访问变量时会怎样呢?
假设父类为Person,子类为Student,有下面的两行定义:
Student sTest = new Student();
Person pTest = sTest;
其中,pTest就是父类的对象引用,sTest是子类的对象引用;pTest和sTest指向了同一个子类对象。
那么,
(1).如果子类的成员变量与父类的成员变量的类型及名称都相同,则用sTest访问时,访问到的是子类的成员变量;用pTest访问时,访问到的是父类的成员变量;
(2).如果子类的静态成员变量与父类的静态成员变量的类型及名称都相同,则用sTest访问时,访问到的是子类的静态成员变量;用pTest访问时,访问到的是父类的静态成员变量;
(3).如果子类的静态成员方法重写了父类的静态成员方法,则用sTest调用时,调用的是子类的静态成员方法;用pTest调用时,调用的是父类的静态成员方法;
(1)、(2)、(3)都称为隐藏,可以理解成父类的这些变量和静态成员方法被放到抽屉里暂时藏起来了,当用父类对象引用访问或调用时,把抽屉拉开就可以看到了;
(4).如果子类的成员方法重写了父类的成员方法,则用sTest调用时,调用到的是子类的成员方法;用pTest调用时,调用的也是子类的成员方法;
此时称为覆盖,可以理解成父类的这些方法被子类重写后的方法用胶带给粘上了,撕不下来了,即使父类对象引用调用时也只能看到子类重写后的方法;
(5).用sTest调用未覆盖的父类成员方法时,该方法中如果使用到了被隐藏的变量或方法时,规则同上;
还是以简单的示例来详细说明。
Person类为父类,Student类为子类,TestMain类为测试类。代码分别如下:
Person类的代码为:
package human; public class Person {
String name;
int age;
String gender; public String education;
private String hobby;
protected String residence; static String citizenship = "Chinese"; public Person() { } public void setName(String n) {
this.name = n;
} public String getName() {
return name;
} public void informationPrint() {
System.out.println("My name is(getName) " + getName());
System.out.println("My name is(name) " + name);
System.out.println("I am " + getAge() + " years old"); if(getGender() == "female")
System.out.println("I am a girl");
else
if(getGender() == "male")
System.out.println("I am a boy");
else
System.out.println("Something is wrong!");
System.out.println("My hobby is " + hobby); if(citizenship == "Chinese")
System.out.println("I am a chinese");
//test:静态变量是否在构造方法之前初始化
else
if(citizenship == "US")
System.out.println("I am an American");
else
System.out.println("Oh,something is wrong");
} //test:覆盖
public void testModifierPublic() {
System.out.println("Person:Public");
} //test:隐藏
public static void staMethodHide() {
System.out.println("Person:static Method");
}
}
Student类的代码为:
package human; public class Student extends Person {
String stuNumber;
int score; //test:隐藏
String name = "ha";
static String citizenship = "US"; public Student() { } public Student(String n, String g) {
super(n,g);
} //test:隐藏
public void setName(String n) {
this.name = n;
} //test:隐藏
public String getName() {
return name;
} //test:覆盖
public void testModifierPublic() {
System.out.println("Student:Public");
} //test:super
public void testSuper() {
System.out.println("Super:");
super.testModifierPublic();
} //test:隐藏
public static void staMethodHide() {
System.out.println("Student:static Method");
}
}
TestMain类的代码为:
package human; public class TestMain { public static void main(String[] args) {
Student sTest = new Student();
Person pTest = sTest; System.out.println("下面是以子类对象sTest来访问变量、调用方法的结果:");
sTest.testModifierPublic();
System.out.println(sTest.name);
System.out.println(sTest.getName());
System.out.println(sTest.citizenship);
sTest.staMethodHide();
sTest.testSuper();
sTest.informationPrint(); System.out.println("下面是以父类对象pTest来访问变量、调用方法的结果:");
pTest.testModifierPublic();
System.out.println(pTest.name);
System.out.println(pTest.getName());
System.out.println(pTest.citizenship);
pTest.staMethodHide();
} }
输出结果为:
下面是以子类对象sTest来访问变量、调用方法的结果:
Student:Public
ha
Student:getName()
ha
US
Student:static Method
Super:
Person:Public
Student:getName()
My name is(getName) ha
My name is(name) null
I am 0 years old
Something is wrong!
My hobby is null
I am a chinese
下面是以父类对象pTest来访问变量、调用方法的结果:
Student:Public
null
Student:getName()
ha
Chinese
Person:static Method
下面对结果进行分析:
(1).前两条语句为:
Student sTest = new Student();
Person pTest = sTest;
第一条语句定义了子类对象引用sTest,并指向了一个子类对象;第二条语句定义了父类对象引用pTest,并被赋值为sTest的值;大体的内存结构见图1:
图1
其中,子类的String型成员变量name与父类的name重名,子类的name值为“ha”,父类的name默认初始化为NULL;String型静态成员变量citizenship与父类的citizenship重名,子类的citizenship值为“US”,父类的citizenship值为“Chinese”。
(2).第4条语句为:sTest.testModifierPublic();
输出结果为第2行:Student:Public
第12行语句为:pTest.testModifierPublic();
输出结果为第18行:Student:Public
sTest、pTest都调用了方法testModifierPublic(),子类重写了父类的此方法,当sTest调用时,很显然要调用子类重写后的方法;pTest调用时,由于该方法已被子类的方法覆盖,所以调用的也是子类重写后的方法。
(3).第5、6条语句分别为:
System.out.println(sTest.name);
System.out.println(sTest.getName());
输出结果为第3、4、5行:
ha
Student:getName()
ha
第13、14条语句分别为:
System.out.println(pTest.name);
System.out.println(pTest.getName());
输出结果为第19、20、21行:
null
Student:getName()
ha
sTest.name是直接访问成员变量name,sTest.getName()是通过调用getName()方法间接获得name的值;两种方式都输出了“ha”;虽然name隐藏了父类的name,getName()重写了父类的getName(),但调用者是sTest,所以使用的都是子类的变量和方法;
name虽然被隐藏,但pTest是父类对象引用,所以访问是是父类的name,所以输出为NULL;但父类的getName()被覆盖,所以调用的是子类的方法。
(4).第7、8条语句分别为:
System.out.println(sTest.citizenship);
sTest.staMethodHide();
输出结果为第6、7行:
US
Student:static Method
第15、16条语句分别为:
System.out.println(pTest.citizenship);
pTest.staMethodHide();
输出结果为第22、23行:
Chinese
Person:static Method
对静态成员变量和静态方法而言,被隐藏时,由子类对象引用访问或调用时,访问或调用到的就是子类的变量或方法;由父类对象引用访问或调用时,访问或调用到的就是父类的变量或方法。
(5).第9条语句为:sTest.testSuper();
输出结果为:
Super:
Person:Public
sTest调用子类成员方法testSuper(),方法体中用到了super.testModifierPublic();,用super来显式调用父类的方法,所以输出的是Person:Public。
(6).第10条语句为:sTest.informationPrint();
输出结果为第10到16行:
Student:getName()
My name is(getName) ha
My name is(name) null
I am 0 years old
Something is wrong!
My hobby is null
I am a chinese
<1>.子类没有重写父类的informationPrint()这个成员方法。
<2>.输出的第10、11行,通过getName()方法得到的name值是“ha”,输出的第12行,通过直接访问name得到的值为NULL;
说明调用的是子类getName(),但访问的父类的name;
也就是说,子类调用父类未重写的成员方法时,成员方法体中如果调用到某个方法被子类重写了,则实际调用子类重写后的方法;
如果访问到某个被隐藏的成员变量,则实际访问到的是父类的成员变量;
这时可以理解成,子类对象中包含了一个父类对象,由这个父类对象来访问或调用其变量或方法,如果是隐藏的情况,则访问到的是父类的值,如果是覆盖的情况,则调用的是子类重写后的方法。
<3>.输出的第16行,可以看出访问的静态成员变量也是父类的变量。
Java学习笔记12---向上转型-父类的对象引用指向子类对象的更多相关文章
- 6.5(java学习笔记)其他流(字节数组流,数据流,对象流,打印流)
一.字节数组流 之前使用输入输出流的操作的对象是文件,而这里字节数组流操作的对象是内存,内存可以看做是一个字节数组. 使用字节数组流读写就可以看做是从内存A到内存B的读写,对象时内存即字节数组. 1. ...
- java学习笔记(12) —— Struts2 通过 xml /json 实现简单的业务处理
XML 1.引入dom4j-2.0.0.jar 2.引入jquery-1.8.2.js 3.新建common.js getInfo = function(){ $.post("getXmlA ...
- Java学习笔记12
循环 打印一个字符串(例如: "Welcome to Java!") 100次,就需要吧下面的输出语句重复写100遍,这是相当繁琐的: System.out.println(&qu ...
- Java学习笔记-12.传递和返回对象
1.Clone()方法产生一个object,使用方法后必须产生的object赋值. Vector v2 = (Vector)v.clone(); 2.Clone()方法在object中是保护类型方法, ...
- Java学习笔记12(面向对象五:构造方法、this再探)
在开发中,经常需要在创建对象的同时明确对象对的属性值, 比如一个Person对象创建时候就应该有age和name等属性 那么如何做到在创建对象的同时给对象的属性初始化值呢? 这里介绍构造方法: 1.构 ...
- java学习笔记12(final ,static修饰符)
final: 意思是最终的,是一个修饰符,有时候一个功能类被开发好了,不想被子类重写就用final定义, 用final修饰的最终数据成员:如果一个类的数据成员用final修饰符修饰,则这个数据成员就被 ...
- Java学习笔记16---抽象类与接口的浅显理解
抽象类是由abstract修饰的类,定义方式如public abstract class A{...}. 接口由interface修饰,定义方式如public interface B{...}. 抽象 ...
- Java学习笔记9(面象对象9:多态)
多态概述 多态是继封装.继承后,面对对象的第三大特性. 现实事物经常会出现多态,如学生,学生是人的一种,则一个具体的同学张三既是学生也是人,即出现两种形态. Java作为面向对象的语言,同样可以描述一 ...
- Java学习笔记14---this作为返回值时返回的是什么
有时会遇到this作为返回值的情况,那么此时返回的到底是什么呢? 返回的是调用this所处方法的那个对象的引用,读起来有点绕口哈,有没有想起小学语文分析句子成份的试题,哈哈. 一点点分析的话,主干是& ...
随机推荐
- JavaEE 对象的串行化(Serialization)
什么情况下需要序列化 a)当你想把的内存中的对象写入到硬盘的时候:b)当你想用套接字在网络上传送对象的时候:c)当你想通过RMI传输对象的时候:再稍微解释一下:a)比如说你的内存不够用了,那计算机就要 ...
- 浅谈python 复制(深拷贝,浅拷贝)
博客参考:点击这里 python中对象的复制以及浅拷贝,深拷贝是存在差异的,这儿我们主要以可变变量来演示,不可变变量则不存在赋值/拷贝上的问题(下文会有解释),具体差异如下文所示 1.赋值: a=[1 ...
- 虚拟机VMware-workstation-full-12.5.2安装注册方法(附安装包下载链接)
首先,需要下载好虚拟机的安装包: 链接:http://pan.baidu.com/s/1mix3fFa 密码:6ftu 下载好后,双击安装程序,弹出安装界面,然后按照红色圈圈的指示进行安装操作,完成安 ...
- Thrift - 快速入门
简单实例 有homebrew的话,直接执行以下命令即可,brew会处理相关依赖(https://thrift.apache.org/docs/install/). brew install thrif ...
- Windows下Mysql5.7开启binlog步骤及注意事项
1.查看是否开启了binlog:show binary logs; 默认情况下是不开启的. 2.开启binlog:修改mysql的配置文件my.ini.添加如下配置: 该文件默认不允许修改,需要右键“ ...
- C# AOP 面向切面编程之 调用拦截
有时候我们需要在代码中对方法调用进行拦截,并修改参数和返回值,这种操作叫做AOP(面向切面编程) 不过需要注意的是,AOP的效率很慢,在需要高效率场合慎用. 以下是C#的AOP方法: 首先建立一个控制 ...
- MongoDB原子操作
MongoDB原子操作常用命令: 1. $set: 用来指定一个键并更新键值,若键不存在则创建并赋值. { $set : { field : value } } 2. $unset: 用来删除一个键. ...
- phalcon——访问控制列表ACL
一个完整的使用实例(将acl封装成一个插件使用): use Phalcon\Acl; use Phalcon\Acl\Role; use Phalcon\Acl\Resource; use Phalc ...
- 如何清楚微信页面的缓存(静态资源(图片,js,页面))
就不说啥子原因了,反正就是微信的缓存问题,照着下面的做法做,一定ok了. 不过就是有些麻烦,但是微信的缓存是为了提高自身的性能,我们这些开发要用人家的平台,只有自己去填坑了. 直接贴代码好了,加上去就 ...
- Ionic3 一些命令
ionic start --help E:\Projects\ionic>ionic start --help ionic start - Create a new project This c ...