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所处方法的那个对象的引用,读起来有点绕口哈,有没有想起小学语文分析句子成份的试题,哈哈. 一点点分析的话,主干是& ...
随机推荐
- Object类—复写equals方法,hashCode方法,toString方法
Object:所有类的根类. Object是不断抽取而来,具备着所有对象都具备的共性内容. class Person extends Object { private int age; Person( ...
- java基础---java语言概述
一.计算机编程的两种范型 1.面向过程的模型---具有线性执行特点,认为是代码作用于数据. 2.面向对象的模型---围绕它的数据(即对象)和为这个数据定义的接口来组织程序:实际上是用数据控制代码的访问 ...
- Ubuntu安装Flash视频插件
http://www.linuxidc.com/Linux/2014-05/101095.htm
- 【持续更新】.Net 开发中给自己埋下的坑!
1.文件“XXX”正在由另一进程使用,因此该进程无法访问此文件. 原因剖析:文件在主线程操作,在子线程中读写操作文件,刚开始没有意识到程序的问题所在,总是在FileStream中报错,google后常 ...
- IIS6、7添加反向代理的步骤
1.安装requestRouter_amd64.msi和rewrite_x64_zh-CN.msi. 打包下载地址:http://files.cnblogs.com/files/wangwust/ii ...
- MongoDB全文检索
1. 全文检索概念: 全文检索是对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式. (暂时不支持中文) ...
- LeetCode 56. Merge Intervals (合并区间)
Given a collection of intervals, merge all overlapping intervals. For example,Given [1,3],[2,6],[8,1 ...
- 使用 LitJson 解析Json并读取数据
开发中经常要获取各种数据,而现今比较常见的数据便是Json数据格式,网上也有很多解析Json数据的方法,但是 作为小白的我,对于那些个高大上的方法理解不够,这不找了许久发了这些一个 LitJson 库 ...
- poj2635The Embarrassed Cryptographer(同余膜定理)
The Embarrassed Cryptographer Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 15069 A ...
- poj 3662 Telephone Lines
Telephone Lines Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 7115 Accepted: 2603 D ...