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所处方法的那个对象的引用,读起来有点绕口哈,有没有想起小学语文分析句子成份的试题,哈哈. 一点点分析的话,主干是& ...
随机推荐
- 【计算机网络基础】数据交换技术和多路复用技术的正(nao)确(can)打开方式
交换的作用 数据交换是计算机网络中两个终端进行数据传输的方式,它又可以分成两种类型:电路交换和分组交换.很显然,问题的核心在于“交换”,那么我们首先要思考的是:交换的作用是什么? “交换”的作 ...
- banner幻灯片
emmm本来想用js写的,但是感觉难就换了jquery. 1.把图片的位置.透明度.宽高.z-index信息用数组datas保存起来,移动的时候直接把位置等信息赋值给li. 2.点击next,即显示下 ...
- Fedora 下 Google-Chrome 经常出现僵尸进程的权宜办法
对于Chrome_ProcessL 和Chrome_FileThre这两僵尸进程,估计遇到过的人都对其各种无奈吧,放任不管吧,越来越多,然后卡死,只能另开个X环境或者在其他的TTY里干掉他俩再切回去, ...
- JS的简单用法
JS的简单用法 参考:http://www.w3school.com.cn/js/js_switch.asp JavaScript 是网络的脚本语言 JavaScript 是可插入 HTML 页面的编 ...
- 【译】10分钟学会Pandas
十分钟学会Pandas 这是关于Pandas的简短介绍主要面向新用户.你可以参考Cookbook了解更复杂的使用方法 习惯上,我们这样导入: In [1]: import pandas as pd I ...
- sqoop1.4.6从mysql导入hdfs\hive\hbase实例
//验证sqoop是否连接到mysql数据库sqoop list-tables --connect 'jdbc:mysql://n1/guizhou_test?useUnicode=true& ...
- Ionic3 启动非常慢
优化: ionic cordova build android --prod --release
- 2017 多校训练 1002 Balala Power!
Balala Power! Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)T ...
- linux进程资源占用高原因分析命令记录
1.查看进程的线程: ps -eLf|egrep 'gateserver|UID' 2.跟踪线程调用: strace -p 15530 3.统计线程中函数的调用小号CPU时间: strace -p 1 ...
- sersync实现数据实时同步
1.1 第一个里程碑:安装sersync软件 1.1.1 将软件上传到服务器当中并解压 1.上传软件到服务器上 rz -E 为了便于管理上传位置统一设置为 /server/tools 中 2.解压软件 ...