java基础总结13-面向对象9(对象转型)

2024-09-07 21:08

本文主要是介绍java基础总结13-面向对象9(对象转型),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这里写图片描述
对象转型分为两种:一种叫向上转型(父类对象的引用或者叫基类对象的引用指向子类对象,这就是向上转型),另一种叫向下转型。转型的意思是:如把float类型转成int类型,把double类型转成float类型,把long类型转成int类型,这些都叫转型。把一种形式转成另外一种形式就叫转型。除了基础数据类型的转型之外(基础数据类型的转型:大的可以转成小的,小的也可以转成大的。),对象领域里面也有对象之间的转型。

1 对象转型实例一

package javastudy.summary;/*** 父类Animal* @author gacl**/
class Animal {public String name;public Animal(String name) {this.name = name;}
}/*** 子类Cat继承Animal* @author gacl**/
class Cat extends Animal {/*** Cat添加自己独有的属性*/public String eyeColor;public Cat(String n, String c) {super(n);//调用父类Animal的构造方法this.eyeColor = c;}
}/*** 子类Dog继承Animal* @author gacl**/
class Dog extends Animal {/*** Dog类添加自己特有的属性*/public String furColor;public Dog(String n, String c) {super(n);//调用父类Animal的构造方法this.furColor = c;}}/*** 下面是这三个类的测试程序* @author gacl**/
public class TestClassCast {/*** @param args*/public static void main(String[] args) {Animal a = new Animal("name");Cat c = new Cat("catname","blue");Dog d = new Dog("dogname", "black");/*** a instanceof Animal这句话的意思是a是一只动物吗?* a是Animal这个类里面的是一个实例对象,所以a当然是一只动物,其结果为true。*/System.out.println(String.format("a instanceof Animal的结果是%s",a instanceof Animal));//true/*** c是Cat类的实例对象的引用,即c代表的就是这个实例对象,* 所以“c是一只动物”打印出来的结果也是true。* d也一样,所以“d是一只动物”打印出来的结果也是true。*/System.out.println(String.format("c instanceof Animal的结果是%s",c instanceof Animal));//trueSystem.out.println(String.format("d instanceof Animal的结果是%s",d instanceof Animal));//true/*** 这里判断说“动物是一只猫”,不符合逻辑,所以打印出来的结果是false。*/System.out.println(String.format("a instanceof Cat的结果是%s",a instanceof Cat));/*** 这句话比较有意思了,a本身是Animal类的实例对象的引用,* 但现在这个引用不指向Animal类的实例对象了,而是指向了Dog这个类的一个实例对象了,* 这里也就是父类对象的引用指向了子类的一个实例对象。*/a = new Dog("bigyellow", "yellow");System.out.println(a.name);//bigyellow/*** 这里的furColor属性是子类在继承父类的基础上新增加的一个属性,是父类没有的。* 因此这里使用父类的引用对象a去访问子类对象里面新增加的成员变量是不允许的,* 因为在编译器眼里,你a就是Animal类对象的一个引用对象,你只能去访问Animal类对象里面所具有的name属性,* 除了Animal类里面的属性可以访问以外,其它类里面的成员变量a都没办法访问。* 这里furColor属性是Dog类里面的属性,因此你一个Animal类的引用是无法去访问Dog类里面的成员变量的,* 尽管你a指向的是子类Dog的一个实例对象,但因为子类Dog从父类Animal继承下来,* 所以new出一个子类对象的时候,这个子类对象里面会包含有一个父类对象,* 因此这个a指向的正是这个子类对象里面的父类对象,因此尽管a是指向Dog类对象的一个引用,* 但是在编译器眼里你a就是只是一个Animal类的引用对象,你a就是只能访问Animal类里面所具有的成员变量,* 别的你都访问不了。* 因此一个父类(基类)对象的引用是不可以访问其子类对象新增加的成员(属性和方法)的。*///System.out.println(a.furColor);System.out.println(String.format("a指向了Dog,a instanceof Animal的结果是%s",a instanceof Animal));//true/*** 这里判断说“a是一只Dog”是true。* 因为instanceof探索的是实际当中你整个对象到底是什么东西,* 并不是根据你的引用把对象看出什么样来判断的。*/System.out.println(String.format("a instanceof Dog的结果是%s",a instanceof Dog));//true/*** 这里使用强制转换,把指向Animal类的引用对象a转型成指向Dog类对象的引用,* 这样转型后的引用对象d1就可以直接访问Dog类对象里面的新增的成员了。*/Dog d1 = (Dog)a;System.out.println(d1.furColor);//yellow}}

运行结果:
这里写图片描述

内存分析:
这里写图片描述
在内存中可以看到,指向Dog类实例对象的引用对象a是一个Animal类型的引用类型,这就比较有意思了,Animal类型指向了Dog这个对象,那么,在程序的眼睛里会把这只Dog当成一只普通的Animal,既然是把Dog当成一只普通的Animal,那么Dog类里面声明的成员变量furColor就不能访问了,因为Animal类里面没有这个成员变量。因此,从严格意义上来讲,这个a眼里只看到了这个子类对象里面的父类对象Animal,因此能访问得到的也只是这个Animal对象里面的name属性,而这个Animal对象外面的furColor属性是访问不到的,虽然Dog对象确实有这个属性存在,但a就是看不到,a门缝里看Dog——把Dog看扁了,不知道Dog还有furColor这个属性存在,因此a访问不了furColor属性,因此从严格意义上来讲,a指向的只是这个Dog对象里面的Animal对象,也就是黄色箭头指向的那部分,a就只看到了Dog里面这部分,而Dog外面的部分都看不到了。这就是父类引用指向子类对象,父类引用指向子类对象的时候,它看到的只是作为父类的那部分所拥有的属性和方法,至于作为子类的那部分它没有看到。

  如果真的想访问Dog对象的furColor属性,那就采用对象转型的办法,把父类对象的引用转型成子类对象的引用。Dog d1 = (Dog)a;这里采用的就是对象转型的办法,把a强制转换成一只Dog对象的引用,然后将这个引用赋值给Dog型的引用变量d1,这样d1和a都是指向堆内存里面的Dog对象了,而且d1指向的就是这只Dog所有的部分了,通过这个d1就可以访问Dog对象里面所有的成员了。

2 对象转型实例二

public class TestClassCast {public void  f(Animal a) {System.out.println(a.name);if (a instanceof Cat) {Cat cat = (Cat)a;System.out.println(cat.eyeColor+" eye");}else if (a instanceof Dog) {Dog dog = (Dog)a;System.out.println(dog.furColor+" fur");}}/*** @param args*/public static void main(String[] args) {Animal a = new Animal("name");Cat c = new Cat("catname","blue");Dog d = new Dog("dogname", "black");TestClassCast testClassCast = new TestClassCast();testClassCast.f(a);testClassCast.f(c);testClassCast.f(d);}
}

这里的这些代码是对前面声明的三个类Animal,Dog,Cat测试的延续,这里我们在TestClassCast这里类里面测试这个三个类,这里我们在TestClassCast类里面new了一个testClassCast对象,为的是调用TestClassCast类里面声明的f(Animal a)这个方法,这个f()方法里面的参数类型是Animal类型,如果是Animal类型的参数,那么我们可以把这个Animal类型的子类对象作为参数传进去,这是可以的。如把一只Dog或者是一只Cat丢进f()方法里面这都是可以的,因为Dog和Cat也是Animal。因此当程序执行到testClassCast.f(a);,testClassCast.f(c);,testClassCast.f(d);的时候,因为f()方法里面的参数是Animal类型的,所以我们可以把一个Animal对象传进去,除此之外,我们还可以直接把从Animal类继承下来的Dog类和Cat类里面的Dog对象和Cat对象作为实参传递过去,即是把Animal类型的子类对象作为参数传进去。这里就体现出了继承和父类对象的引用可以指向子类对象的好处了,如果说没有继承关系的存在,如果说父类的引用不可以指向子类对象,那么我们就得要在Test类里面定义三个f()方法了,即要定义这样的f()方法:

f(Animal a)、f(Dog d)、f(Cat c)分别用来处理Animal、Dog和Cat,使用三个方法来处理,将来程序的扩展起来就不是很容易了,因为面向对象可以帮助我们这些年来编程苦苦追求的一个境界是可扩展性比较好。可扩展性比较好的一个典型例子就是说当你建好一个建筑之后或者是你写好这个程序之后,把这个主建筑给建好了,将来你要加一些其他的功能的时候,尽量不要去修改主结构,这叫可扩展性好,你盖了一座大楼,你现在要在大楼的旁边添加一个厨房,那你在它旁边一盖就行了,如果有人告诉你,我添加一个厨房我需要把你整个大楼的主要柱子都给拆了然后再盖一遍,这你干吗,肯定不干。如果结构设计成这样,那就是设计得不好,可扩展性不好。所以这里如果要把f()方法写成三个重载的f()方法,那么将来我输出一只鸟的时候又得要添加一个f(Bird b)方法来处理鸟。这样扩展起来就太麻烦了,因为每处理一只动物都要添加一个新的方法,但是如果存在继承关系,如果父类对象的引用可以指向子类对象,那扩展起来就简单了,你可以把处理动物的方法写在一个方法f(Animal a)里面就够了,因为所有动物的种类都是从Animal类继承下来,因此给f()方法传递Animal类型的参数的时候可以直接把这个Animal类的子类对象传进去,这样不管是要增加什么动物的输出,我都可以调用f(Animal a)方法去处理,这种扩展性比每次都要增加一个新的处理方法的扩展性要好得多,这就是继承的一个好处,这就是对象转型对于可扩展性来的好处:“对象的引用可以指向子类对象”,是因为面向对象的编程里面存在这样的继承关系,使得程序的可扩展性比较好。
对象转型可以使父类对象的引用可以指向子类对象,给程序带来了比较好的可扩展性:我们可以在一个方法的参数里面定义父类的引用,然后实际当中传的时候传的是子类的对象,然后我们再在方法里面判断这个传过来的子类对象到底属于哪个子类,然后再去执行这个子类里面的方法或者调用这个子类里面的成员变量,因此程序的可扩展性比单独定义好多个方法要好一些。不过这个可扩展性还没有达到最好,使用多态就可以让程序的扩展性达到极致。

这篇关于java基础总结13-面向对象9(对象转型)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1146166

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;