详细讲述Java中的对象转型

向上转型:子类对象转为父类,父类可以是接口。公式:Father f = new Son();Father是父类或接口,son是子类。

向下转型:父类对象转为子类。公式:Son s = (Son)f;

我们将形参设为父类Animal类型,当执行test.f(c)时,内存情况如下图:

c作为Cat类型传入,Animal a作为形参,相当于执行了Animal a = new Cat(),这时a和c同时指向Cat对象,但此时a不能访问Cat类扩展的数据成员,所以再将a强转成Cat类型即可。如果不存在这样的转型机制,则针对猫和狗我们还要分别写两个函数f(Cat c)和f(Dog d)。但其实上图程序的可扩展性也不是最好的。我们还可以利用动态绑定(即多态)将扩展性进一步提升。多态机制的三个前提分别是:

(1)要有继承

(2)要重写,即子类对父类中某些方法进行重新定义

(3)要向上转型,用父类引用指向子类对象。

下面来看一个例子:

class Animal { private String name; /**
  * 在Animal类自定义的构造方法
  * @param name  */
 Animal(String name) {  this.name = name;
 } /**
  * 在Animal类里面自定义一个方法enjoy  */
 public void enjoy() {
  System.out.println("动物的叫声……");
 }
}class Cat extends Animal { private String eyesColor; /**
  * 在子类Cat里面定义Cat类的构造方法
  * @param n
  * @param c  */
 Cat(String n, String c) {  /**
   * 在构造方法的实现里面首先使用super调用父类Animal的构造方法Animal(String name)。
   * 把子类对象里面的父类对象先造出来。   */
  super(n);
  eyesColor = c;
 } /**
  * 子类Cat对从父类Animal继承下来的enjoy方法不满意,在这里重写了enjoy方法。  */
 public void enjoy() {
  System.out.println("我养的猫高兴地叫了一声……");
 }
}/**
 * 子类Dog从父类Animal继承下来,Dog类拥有了Animal类所有的属性和方法。
 * @author gacl
 * */class Dog extends Animal { /**
  * 在子类Dog里面定义自己的私有成员变量  */
 private String furColor; /**
  * 在子类Dog里面定义Dog类的构造方法
  * @param n
  * @param c  */
 Dog(String n, String c) {  /**
   * 在构造方法的实现里面首先使用super调用父类Animal的构造方法Animal(String name)。
   * 把子类对象里面的父类对象先造出来。   */
  super(n);
  furColor = c;
 } /**
  * 子类Dog对从父类Animal继承下来的enjoy方法不满意,在这里重写了enjoy方法。  */
 public void enjoy() {
  System.out.println("我养的狗高兴地叫了一声……");
 }
}/**
 * 子类Bird从父类Animal继承下来,Bird类拥有Animal类所有的属性和方法
 * @author gacl
 * */class Bird extends Animal { /**
  * 在子类Bird里面定义Bird类的构造方法  */
 Bird() {  /**
   * 在构造方法的实现里面首先使用super调用父类Animal的构造方法Animal(String name)。
   * 把子类对象里面的父类对象先造出来。   */
  super("bird");
 } /**
  * 子类Bird对从父类Animal继承下来的enjoy方法不满意,在这里重写了enjoy方法。  */
 public void enjoy() {
  System.out.println("我养的鸟高兴地叫了一声……");
 }
}/**
 * 定义一个类Lady(女士)
 * @author gacl
 * */class Lady { /**
  * 定义Lady类的私有成员变量name和pet  */
 private String name; private Animal pet; /**
  * 在Lady类里面定义自己的构造方法Lady(),
  * 这个构造方法有两个参数,分别为String类型的name和Animal类型的pet,
  * 这里的第二个参数设置成Animal类型可以给我们的程序带来最大的灵活性,
  * 因为作为养宠物来说,可以养猫,养狗,养鸟,只要是你喜欢的都可以养,
  * 因此把它设置为父类对象的引用最为灵活。
  * 因为这个Animal类型的参数是父类对象的引用类型,因此当我们传参数的时候,
  * 可以把这个父类的子类对象传过去,即传Dog、Cat和Bird等都可以。
  * @param name
  * @param pet  */
 Lady(String name, Animal pet) {  this.name = name;  this.pet = pet;
 } /**
  * 在Lady类里面自定义一个方法myPetEnjoy()
  * 方法体内是让Lady对象养的宠物自己调用自己的enjoy()方法发出自己的叫声。  */
 public void myPetEnjoy() {
  pet.enjoy();
 }
}public class Jerque { public static void main(String args[]) {  /**
   * 在堆内存里面new了一只蓝猫对象出来,这个蓝猫对象里面包含有一个父类对象Animal。   */
  Cat c = new Cat("Catname", "blue");  /**
   * 在堆内存里面new了一只黑狗对象出来,这个黑狗对象里面包含有一个父类对象Animal。   */
  Dog d = new Dog("Dogname", "black");  /**
   * 在堆内存里面new了一只小鸟对象出来,这个小鸟对象里面包含有一个父类对象Animal。   */
  Bird b = new Bird();  /**
   * 在堆内存里面new出来3个小姑娘,名字分别是l1,l2,l3。
 * l1养了一只宠物是c(Cat),l2养了一只宠物是d(Dog),l3养了一只宠物是b(Bird)。
   * 注意:调用Lady类的构造方法时,传递过来的c,d,b是当成Animal来传递的,
   * 因此使用c,d,b这三个引用对象只能访问父类Animal里面的enjoy()方法。   */
  Lady l1 = new Lady("l1", c);
  Lady l2 = new Lady("l2", d);
  Lady l3 = new Lady("l3", b);  /**
   * 这三个小姑娘都调用myPetEnjoy()方法使自己养的宠物高兴地叫起来。   */
  l1.myPetEnjoy();
  l2.myPetEnjoy();
  l3.myPetEnjoy();
 }
}

上面的例子中,我们发现,如果我们想要加入新的动物,只需定义相应的类继承Animal,完全不用动任何一处代码,因为这里运用了面向对象最核心的东西——多态。与之前的例子不同,虽然我们一直强调当用父类的引用指向子类对象,父类无法访问子类自己的成员,但是方法与数据成员不同,具体调哪一个方法是等到运行时决定的,new出了什么对象就调用相应对象的方法,取决于实际new出的对象而不是指向对象的引用,所以当传入不同动物类型,mypetEnjoy()就会去执行不同的方法

(0)

相关推荐

  • 实例分析java对象中浅克隆和深克隆

    引言: 在Object基类中,有一个方法叫clone,产生一个前期对象的克隆,克隆对象是原对象的拷贝,由于引用类型的存在,有深克隆和浅克隆之分,若克隆对象中存在引用类型的属性,深克隆会将此属性完全拷贝一份,而浅克隆仅仅是拷贝一份此属性的引用.首先看一下容易犯的几个小问题 clone方法是Object类的,并不是Cloneable接口的,Cloneable只是一个标记接口,标记接口是用用户标记实现该接口的类具有某种该接口标记的功能,常见的标记接口有三个:Serializable.Cloneable

  • java中对象的序列化与反序列化深入讲解

    引言: 序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化.可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间.序列化是为了解决在对对象流进行读写操作时所引发的问题. 把对象转换为字节序列的过程称为对象的序列化. 把字节序列恢复为对象的过程称为对象的反序列化. 在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存.比如最常见的是Web服务器中的Session对 象,当有 10万用户并发访问,就有可能出现10万个Session对

  • 实例分析java对象的序列化和反序列化

    引言: 序列化是将对象的状态信息转换为可以存储或传输的形式的过程,在序列化期间,对象将其带你过去的状态写入到临时或持储存区,反序列化就是重新创建对象的过程,此对象来自于临时或持久储存区. 序列化的作用: 就好比如存储数据到数据库,将一些数据持久化到数据库中,而有时候需要将对象持久化,虽然说将对象状态持久化的方式有很多,但是java给我们提供了一种很便捷的方式,那就是序列化,序列化可以实现对象到文件之间的直接转换,实现细节对我们隐藏. 具体的三种用途: •将对象的状态信息持久化保存到硬盘上 •将对

  • java对象转型实例分析

    本文实例讲述了java对象转型的概念,分享给大家供大家参考.具体方法如下: 对象转型(casting)注意事项如下: 1.一个基类的引用类型变量可以"指向"其子类的对象. 2.一个基类的引用不可以访问其子类对象新增加的成员(属性和方法). 3.可以使用 引用变量 instanceof 类名 来判断该引用型变量所"指向"的对象是否属于该类或该类的子类. 4.子类的对象可以当做基类的对象来使用称作向上转型(upcasting),反之成为向下转型(downcasting)

  • Java对象序列化操作详解

    本文实例讲述了Java对象序列化操作.分享给大家供大家参考,具体如下: 当两个进程在进行远程通信时,彼此可以发送各种类型的数据.无论是何种类型的数据,都会以二进制序列的形式在网络上传送.发送方需要把这个Java对象转换为字节序列,才能在网络上传送:接收方则需要把字节序列再恢复为Java对象. 只能将支持 java.io.Serializable 接口的对象写入流中.每个 serializable 对象的类都被编码,编码内容包括类名和类签名.对象的字段值和数组值,以及从初始对象中引用的其他所有对象

  • java线程池对象ThreadPoolExecutor的深入讲解

    使用线程池的好处 1.降低资源消耗 可以重复利用已创建的线程降低线程创建和销毁造成的消耗. 2.提高响应速度 当任务到达时,任务可以不需要等到线程创建就能立即执行. 3.提高线程的可管理性 线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配.调优和监控 ThreadPoolExecutor 介绍: java 提供的线程池类: ThreadPoolExecutor 作用: 两个作用: 1,用于分离执行任务和当前线程: 2,主要设计初衷:重复利用T

  • 详细讲述Java中的对象转型

    向上转型:子类对象转为父类,父类可以是接口.公式:Father f = new Son();Father是父类或接口,son是子类. 向下转型:父类对象转为子类.公式:Son s = (Son)f; 我们将形参设为父类Animal类型,当执行test.f(c)时,内存情况如下图: c作为Cat类型传入,Animal a作为形参,相当于执行了Animal a = new Cat(),这时a和c同时指向Cat对象,但此时a不能访问Cat类扩展的数据成员,所以再将a强转成Cat类型即可.如果不存在这样

  • JS自定义对象实现Java中Map对象功能的方法

    本文实例讲述了JS自定义对象实现Java中Map对象功能的方法.分享给大家供大家参考.具体分析如下: Java中有集合,Map等对象存储工具类,这些对象使用简易,但是在JavaScript中,你只能使用Array对象. 这里我创建一个自定义对象,这个对象内包含一个数组来存储数据,数据对象是一个Key,可以实际存储的内容!   这里Key,你要使用String类型,和Java一样,你可以进行一些增加,删除,修改,获得的操作. 使用很简单,我先把工具类给大家看下: 复制代码 代码如下: /**  *

  • Java中的对象和对象引用实例浅析

    本文实例讲述了Java中的对象和对象引用.分享给大家供大家参考.具体分析如下: 在Java中,有一组名词经常一起出现,它们就是"对象和对象引用",很多朋友在初学Java的时候可能经常会混淆这2个概念,觉得它们是一回事,事实上则不然.今天我们就来一起了解一下对象和对象引用之间的区别和联系. 1.何谓对象? 在Java中有一句比较流行的话,叫做"万物皆对象",这是Java语言设计之初的理念之一.要理解什么是对象,需要跟类一起结合起来理解.下面这段话引自<Java编

  • java中response对象用法实例分析

    本文实例讲述了java中response对象用法.分享给大家供大家参考,具体如下: <jsp:forward>动作元素用于运行时在服务器端结束当前页面的执行,并从当前页面转向指定页面. 使用response对象的setHeader()方法可以设置页面的自动刷新时间间隔.实现每隔60秒重新加载本页面的语句为: 复制代码 代码如下: response.setHeader("refresh",60); 而实现3秒后浏览器加载新页面http://www.jb51.net的语句为:

  • java中List对象排序通用方法

    本文实例讲述了java中List对象排序通用方法.分享给大家供大家参考.具体分析如下: 在数据库中查出来的列表list中,往往需要对不同的字段重新排序,一般的做法都是使用排序的字段,重新到数据库中查询.如果不到数据库查询,直接在第一次查出来的list中排序,无疑会提高系统的性能. 只要把第一次查出来的结果存放在session中,就可以对list重新排序了.一般对list排序可以使用Collections.sort(list),但如果list中包含是一个对象的话,这种方法还是行不通的.那要怎么排序

  • java中request对象各种方法的使用实例分析

    本文实例讲述了java中request对象各种方法的使用.分享给大家供大家参考,具体如下: request对象是从客户端向服务器端发出请求,包括用户提交的信息以及客户端的一些信息.request对象是javax.servlet.http.HttpServletRequest类的实现实例. request对象封装了浏览器的请求信息,通过request对象的各种方法可以获取客户端以及用户提交的各项请求信息. 使用request对象获取客户端提交的请求参数的常用方法如下: 1.String getPa

  • Java中的对象、类、抽象类、接口、继承之间的联系

    正文: 举个例子:如果现在要想定义一个动物,那么动物肯定是一个公共的标准,而这个公共标准就可以通过接口来完成. 在动物中又分为两类:哺乳动物.卵生动物,而这个标准属于对动物的标准进一步细化,应该称为子标准,所以此种关系可以使用接口的继承来表示. 而哺乳动物可以继续划分为人.狗.猫等不同的类型,由于这些类型不表示具体的事物标准,所以可以使用抽象类进行表示. 如果要表示出工人或者学生这样的概念,则肯定是一个具体的定义,则使用类的方式. 然后每个学生或者每个工人都是具体的,那么就通过对象来表示: 由下

  • 详细总结Java中常用的原子类

    一.什么是原子类 Java中提供了一些原子类,原子类包装了一个变量,并且提供了一系列对变量进行原子性操作的方法.我们在多线程环境下对这些原子类进行操作时,不需要加锁,大大简化了并发编程的开发. 二.原子类的底层实现 目前Java中提供的原子类大部分底层使用了CAS锁(CompareAndSet自旋锁),如AtomicInteger.AtomicLong等:也有使用了分段锁+CAS锁的原子类,如LongAdder等. 三.常用的原子类 3.1 AtomicInteger与AtomicLong At

  • 详细介绍Java中的各种锁

    一.一张图了解21种锁 二.乐观锁 应用 CAS 思想 一种乐观思想,假定当前环境是读多写少,遇到并发写的概率比较低,读数据时认为别的线程不会正在进行修改 实现 写数据时,判断当前 与期望值是否相同,如果相同则进行更新(更新期间加锁,保证是原子性的) 三.悲观锁 应用 synchronized.vector.hashtable 思想: 一种悲观思想 ** ,即认为写多读少,遇到并发写的可能性高 实现 每次读写数据都会认为其他线程会修改,所以每次读写数据时都会上锁 缺点 他线程想要读写这个数据时,

  • Java中的对象流总结(必看篇)

    Java中可以通过对象流将一个序列化的对象保存到硬盘中,或者硬盘中读取一个对象.对象流的存储和读取包含以下几点内容: 1.所保存的对象必须实现Serializable接口. 2. 所保存的对象的属性也必须实现Serializable接口. 3. 最好要给该对象提供一个版本号,private static final long serialVersionId. 下面是一个对象流存储和读取一个对象的流程图: class Person implements Serializable { //实现序列化

随机推荐