java-多态-object
概要图

一 多态
1.1 多态的产生
下面的 红色部分降低了代码的可扩展性
Dog d = new Dog();
method(d); Cat c = new Cat();
method(c);
} //接收Dog,让dog做事。
public static void method(Dog d)
{
d.eat();
}
//接收Cat,让cat做事。
public static void method(Cat c)
{
c.eat();
}
对其改进 见下面红色部分
//多态技术的引出。解决什么问题?程序扩展性的问题。 //描述Dog
class Dog extends Animal
{
public void eat()
{
System.out.println("骨头");
}
public void lookHome()
{
System.out.println("看家");
}
} //描述猫
class Cat extends Animal
{
public void eat()
{
System.out.println("鱼");
}
public void catchMouse()
{
System.out.println("抓老鼠");
}
}
//进行抽取。将共性的功能抽取到父类Animal中。
abstract class Animal
{
public abstract void eat();
} class DuoTaiDemo
{
public static void main(String[] args)
{
Dog d = new Dog();
// d.eat();
method(d); Cat c = new Cat();
method(c);
}
/*
发现,每多一个动物,都需要为这个动物单独定义一个功能,
让这个动物的对象去做事。
这个程序扩展性就很差。
如何提高这个扩展性呢?
发现既然是让动作去eat,无论是dog,还是cat,
eat是它们共性,干脆,将eat进行抽取。抽取到父类Animal中。 Dog是Animal中的一种。
Dog d = new Dog();
Animal a = new Dog();
Cat c = new Cat();
Animal aa = new Cat();
*/
//只要建立animal的引用就可以接收所有的dog cat对象进来。让它们去eat。
//提高了程序的扩展性。
public static void method(Animal a)
{
a.eat();
} /*
//接收Dog,让dog做事。
public static void method(Dog d)
{
d.eat();
}
//接收Cat,让cat做事。
public static void method(Cat c)
{
c.eat();
}
*/ }
1.2 多态的一些问题
【体现】
父类的引用或者接口的引用指向了自己的子类对象。
Dog d = new Dog();//Dog对象的类型是Dog类型。
Animal a = new Dog();//Dog对象的类型右边是Dog类型,左边Animal类型。
【好处】
提高了程序的扩展性。
【弊端】
通过父类引用操作子类对象时,只能使用父类中已有的方法,不能操作子类特有的方法。
子类是父类的对象,父类不是子类的对象
【前提】
1,必须有关系:继承,实现。
2,通常都有重写操作。
【子类的特有方法如何调用呢?】
Animal a = new Dog();//Animal是父类型,new Dog()是子对象。
但是父类型引用指向子类对象时,这就是让子类对象进行了类型的提升(向上转型)。
向上转型好处:提高了扩展性,隐藏了子类型。弊端:不能使用子类型的特有方法。
如果要想使用子类的特有方法,只有子类型可以用。
可以向下转型,强制转换。
Animal a = new Dog();
a.eat();
Dog d = (Dog)a;//将a转型为Dog类型。向下转型。
d.lookHome();
向下转型什么时候用?当需要使用子类型的特有内容时。
注意:无论向上还是向下转型,最终都是子类对象做着类型的变化。
【向下转型的注意事项】
Animal a = new Dog();
//Cat c = (Cat)a;向下转型因为不明确具体子类对象类型,所以容易引发ClassCastException异常。(代码下面红色)
public class Test {
public static void main(String[] args)
{
Dog d = new Dog();
method(d);
Cat c = new Cat();
method(c);
}
public static void method(Animal a)
{
a.eat();
Dog d = (Dog)a;
d.lookHome();
}
}
class Dog extends Animal
{
public void eat()
{
System.out.println("骨头");
}
public void lookHome()
{
System.out.println("看家");
}
}
//描述猫
class Cat extends Animal
{
public void eat()
{
System.out.println("鱼");
}
public void catchMouse()
{
System.out.println("抓老鼠");
}
}
//进行抽取。将共性的功能抽取到父类Animal中。
abstract class Animal
{
public abstract void eat();
}
Exception in thread "main" 骨头
看家
鱼
java.lang.ClassCastException: test.Cat cannot be cast to test.Dog
所以为了避免这个问题,需要在向下转型前,做类型的判断。
判断类型用的是关键字 instanceof
if(a instanceof Cat)//a指向的对象的类型是Cat类型。
{
//将a转型Cat类型。
Cat c = (Cat)a;
c.catchMouse();
}
else if(a instanceof Dog)
{
Dog d = (Dog)a;
d.lookHome();
}
【转型总结】
1,什么时候使用向上转型呢?
提高程序的扩展性,不关系子类型(子类型被隐藏)。
需要用子类的特有方法吗?不需要,哦了。向上转型。
2,什么时候使用向下转型呢?
需要使用子类型的特有方法时。
但是一定要使用 instanceof 进行类型的判断。避免发生 ClassCastException
1.3 多态的例子
第一个例子
class 毕姥爷
{
public void 讲课()
{
System.out.println("讲管理");
}
public void 钓鱼()
{
System.out.println("钓鱼");
}
} class 毕老师 extends 毕姥爷
{
public void 讲课()
{
System.out.println("Java");
}
public void 看电影()
{
System.out.println("看电影");
}
} class DuoTaiTest
{
public static void main(String[] args)
{
毕姥爷 x = new 毕老师();//多态,向上转型。
x.讲课();
x.钓鱼();
// x.看电影();//不行。
//想要使用毕老师的特有方法时,需要向下转型。
if(x instanceof 毕老师)
{
毕老师 y = (毕老师)x;
y.看电影();
}
//自始至终都是子类对象做着类型的变化。 }
}
注意:无论向上还是向下转型,最终都是子类对象做着类型的变化
第二个例子
/*
阶段一需求:笔记本电脑运行。
按照面向对象的思想,用代码体现。
名称提炼法。
笔记本电脑。
行为:运行。
class NoteBook
{
//运行功能。
public void run()
{
System.out.println("notebook run");
}
}
阶段二需求:想要在笔记本电脑上加上一个手握式鼠标。
多了个对象:鼠标。
行为:开启,关闭。
class Mouse
{
public void open()
{
System.out.println("mouse open");
}
public void close()
{
System.out.println("mouse close");
}
}
笔记本怎么用鼠标呢?
在笔记本中多一个使用鼠标的功能。
需要修改原来的笔记本类中的内容,添加一个功能。
这样的做法相当于把笔记本打开,把鼠标焊到里面
因为他直接在改原代码
class Mouse
{
public void open()
{
System.out.println("mouse open");
}
public void close()
{
System.out.println("mouse close");
}
}
public class Test {
public static void main(String[] args)
{
NoteBook n =new NoteBook();
n.run();
n.userMouse(null);
}
}
class NoteBook {
public void run (){
System.out.println("notebook run");
}
public void userMouse(mouse m){
if(m!=null){
m.open();
m.close();
}
}
}
class mouse {
public void open (){
System.out.println("mouse open");
}
public void close (){
System.out.println("mouse close");
}
}
结果 notebook run
//问题:如果想要加入一个键盘呢?
只要描述一个键盘类,并在电脑类中加入一个使用键盘的功能就哦了。
但是发现从鼠标开始这个问题就已经产生了,一旦需要添加新设备的时候,
都需要改变电脑的源码。这个扩展性是非常差的。
设计上该如何改进呢?
之前的问题在于外围设备的增加和笔记本电脑之间的耦合性过高。
如何降低外围设备和笔记本电脑的耦合性呢?
外围设备还不确定,我们不要面对外围具体设备。
为了让笔记本可以使用这些设备,可以事先定义好一些规则,
笔记本只要使用这些规则就可以了。
有了这些规则就可以进行笔记本的功能扩展。
后期这些外围设备只要符合这些规则就可以被笔记本使用了。
那么规则在java中该如何体现呢?接口。
//1,描述接口。USB。
//2,描述笔记本电脑:运行功能,使用USB接口的功能。
*/
//USB接口定义。
interface USB
{
void open();
void close();
} //描述笔记本电脑。
class NoteBook
{
public void run()
{
System.out.println("notebook run");
} //使用usb接口的功能。
public void useUSB(USB usb)//接口类型的变量。接口类型的变量指向自己的子类对象。
//USB usb = new Mouse();
{
if(usb!=null)
{
usb.open();
usb.close();
}
}
}
//需要鼠标 。想要被笔记本电脑使用,该鼠标必须符合规则。
//描述鼠标。
class Mouse implements USB
{
public void open()
{
System.out.println("mouse open");
}
public void close()
{
System.out.println("mouse close");
}
} class KeyBoard implements USB
{
public void open()
{
System.out.println("KeyBoard open");
}
public void close()
{
System.out.println("KeyBoard close");
}
} /*
发现,接口的出现,
1,扩展了笔记本电脑功能。
2,定义了规则。
3,降低了笔记本电脑和外围设备之间的耦合性。
*/ class DuoTaiTest2
{
public static void main(String[] args)
{
NoteBook book = new NoteBook();
book.run();
book.useUSB(null);
book.useUSB(new Mouse());
book.useUSB(new KeyBoard());
}
}
1.4 多态中成员调用的特点。
1,成员变量。
当子父类中出现同名的成员变量时。
多态调用该变量时:
编译时期:参考的是引用型变量所属的类中是否有被调用的成员变量。没有,编译失败。
运行时期:也是调用引用型变量所属的类中的成员变量。
简单记:编译和运行都参考等号的左边。
编译运行看左边。
2,成员函数。
编译,参考左边,如果没有,编译失败。
运行,参考右边的对象所属的类。
编译看左边,运行看右边。
可以看作是方法的重写.当然要运行右边了
对于成员函数是动态绑定到对象上。(动态是指对象不确定)
3,静态函数。
编译和运行都参考左边。
也可以看作是重写.按理说应该是和上面的成员函数是一个结果的,但是静态函数是与对象无关的,
所以运行的是左边Fu 的method,只和调用者有关系
静态函数是静态的绑定到类上。(静态 是指在那个类中)
下面红色部分
package test;
public class Test {
public static void main(String[] args)
{
Fu f = new Zi();
System.out.println(f.num);// 3
f.show(); // zi show run..
f.method(); // fu static method run
}
}
class Fu
{
int num = ;
void show()
{
System.out.println("fu show run");
}
static void method()
{
System.out.println("fu static method run");
}
}
class Zi extends Fu
{
int num = ;
void show()
{
System.out.println("zi show run..");
}
static void method()
{
System.out.println("zi static method run");
}
}
【结论】
对于成员变量和静态函数,编译和运行都看左边。
对于成员函数,编译看左边,运行看右边。
二 object
2.1 object 常用方法
API(应用程序接口(接口:指的是一些公共的东西))文 档
/*
Object类中的常用方法。
Object类是所有类的根类,定义了所有对象都具备的功能。
API(应用程序接口)文档
*/
class Person extends Object
{
private int age;
Person(int age)
{
this.age = age;
}
//判断是否是同龄人。这个方法也是在比较两个person对象是否相等。
//注意:Person类中是否有比较两个Person对象相等的方法?有的!因为继承Object,它本身就具备着equals方法。
//既然有,还需要定义compare方法吗?不需要。
//但是,equals方法判断的是地址,不是我们所需要的内容。
//咋办?继续使用Object的equals方法,但是建立子类的自己的内容。传说中的重写。
【记住:以后判断对象是否相同,就需要覆盖equals方法。】
重写equals
注意:
1 参数是object obj
2 要向下转型
public boolean equals(Object obj)
{ //建立Person自己的判断相同的依据。判断年龄是否相同。
// return this.age == obj.age;//obj所属类型Object,Object中没有定义age,所以编译失败。 //如果调用该方法的对象和传递进来的对象是同一个。就不要转型和判断,直接返回true。效率高一点。
if(this == obj)
return true; //age是Person类型的属性。既然要用到子类型的内容,需要向下转型。
if(!(obj instanceof Person))
// return false;
throw new ClassCastException("类型是不对的!请改正。");
Person p = (Person)obj; return this.age == p.age; }
重写toString
//覆盖toString方法,建立Person对象自己的字符串表现形式。
public String toString()
{
return "Person[age = "+age+"]";
}
三 习题
,描述图书:book
作者,书名,价格。
行为:6个set get
建立book比较相同的依据。只要书名相同就视为同一本书。
字符串判断相同:请查api文档。equals方法,String类重写Object类中的equals
建立book对象的字符串表现形式。 Book[作者:+ 书名 + 价格] ,写出结果。如果编译失败,请注明原因。 class Super
{
int i=;
public Super(String a)
{
System.out.println("A");
i=;
}
public Super()
{
System.out.println("B");
i+=;
}
}
class Demo extends Super
{
public Demo(String a)
{//super();
System.out.println("C");
i+=;
}
public static void main(String[] args)
{
int i=;
Super d=new Demo("A");
System.out.println(d.i);
}
}
//B C 7 .
选择题,写出错误答案错误的原因,用单行注释的方式。
class Demo
{
int show(int a,int b){return ;}
}
下面那些函数可以存在于Demo的子类中。
A.public int show(int a,int b){return ;}// 可以的,重写了。权限大于父类方法权限。
B.private int show(int a,int b){return ;}// 不可以的,要重写,但是权限不够。
C.private int show(int a,long b){return ;}// 可以。相当于重载。
D.public short show(int a,int b){return ;}// 不可以的。调用的不确定性。
E.static int show(int a,int b){return ;}// 不可以的,static只能重写静态。 ,
写出程序结果,如果编译失败,请注明原因。 interface A{}
class B implements A
{
public String test()
{
return "yes";
}
}
class Demo
{
public static A get()
{
return new B();
}
public static void main(String[] args)
{ A a=get();
System.out.println(a.test());//编译失败,因为a所属的A接口中没有Test()方法。
// A a = new B();相当于这句。
// a.test(); 是多态调用不?是!test()是非静态成员函数不?是! 规律:编译看左边,有吗?没有,所以编译失败。
java-多态-object的更多相关文章
- 理解JAVA - 面向对象(object) - 属性,方法
理解JAVA - 面向对象(object) - 属性,方法 多态的体现: 向上造型,父类接收子类对象:向上造型: 从父类角度看不到子类独有的方法:面向对象,人类认知世界的方式:生活中每天都 ...
- C++和java多态的区别
C++和java多态的区别 分类: Java2015-06-04 21:38 2人阅读 评论(0) 收藏 举报 转载自:http://www.cnblogs.com/plmnko/archive ...
- 【转】java多态详解
1. Java中除了static和final方法外,其他所有的方法都是运行时绑定的.private方法都被隐式指定为final的,因此final的方法不会在运行时绑定.当在派生类中重写基 ...
- 关于Java多态的总结.
[圣思源笔记]JAVA SE Lesson 11. 类是一种抽象的概念,对象是类的一种具体表示形式,是具体的概念.先有类,然后由类来生成对象(Object).对象又叫做实例(Instance).2. ...
- 从JVM角度看Java多态
首先,明确一下,Java多态的三个必要条件: 1. 继承 2. 子类重写父类方法 3. 父类引用指向子类对象 然后看一个例子 package test.xing; class Father{ prot ...
- JDK1.8源码(一)——java.lang.Object类
本系列博客将对JDK1.8版本的相关类从源码层次进行介绍,JDK8的下载地址. 首先介绍JDK中所有类的基类——java.lang.Object. Object 类属于 java.lang 包,此包下 ...
- Java - 22 Java 多态
Java 多态 多态是同一个行为具有多个不同表现形式或形态的能力. 多态性是对象多种表现形式的体现. 比如我们说"宠物"这个对象,它就有很多不同的表达或实现,比如有小猫.小狗.蜥蜴 ...
- 从虚拟机角度看Java多态->(重写override)的实现原理
工具与环境:Windows 7 x64企业版Cygwin x64jdk1.8.0_162 openjdk-8u40-src-b25-10_feb_2015Vs2010 professional 0x0 ...
- Java多态之向上转型
目录 Java多态之向上转型 多态的优点 向上转型 概念 向上转型好在哪 Java多态之向上转型 多态性是面向对象的第三大特征. 多态的优点 改善代码的组织结构和可读性. 能够创建可扩展的程序.(随时 ...
- Java多态之动态绑定
目录 Java多态之动态绑定 引用变量的类型 编译时类型 运行时类型 方法绑定 静态绑定 动态绑定 方法表 Java多态之动态绑定 上篇回顾:多态是面向对象程序设计非常重要的特性,它让程序拥有 更好的 ...
随机推荐
- raft学习
http://thesecretlivesofdata.com/raft/ 选举 角色: leader 领导者 Follower跟随者 Candidate候选者 如果跟随者在一定时间内,么有收到领 ...
- vue2 + koa2全栈部署
1.首先打包前端上传 修改config下的index.js 代理地址为服务器IP index: path.resolve(__dirname, '../dist/index.html'), asset ...
- 菜鸟nginx源码剖析数据结构篇(十) 自旋锁ngx_spinlock[转]
菜鸟nginx源码剖析数据结构篇(十) 自旋锁ngx_spinlock Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.csd ...
- System.Text.Encoding.cs
ylbtech-System.Text.Encoding.cs 1.程序集 mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77 ...
- Java—重写与重载的区别
1.重写(Override) 子类继承了父类原有的方法,但有时子类并不想原封不动的继承父类中的某个方法,所以在方法名,参数列表,返回类型(除了子类中方法的返回值是父类中方法返回值的子类时)都相同的情况 ...
- CentOS 8上安装Docker
前言 这几天,想玩玩docker,方便漏洞复现,我去学docker搭建了,感觉不错,挺方便的 安装步骤: 1.下载docker-ce的repo curl https://download.docker ...
- java实现从实体到SQL语句的转换
使用过Hibernate,EF之类的ORM框架都知道一般的CRUD之类的简单操作,只要调用框架封装好了的方法,框架就自动生成相应的SQL语句了,参照实习公司给的代码,那个是C#版的,今天弄了一下jav ...
- (Eclipse) 安装Subversion1.82(SVN)插件
简介 :SVN是团队开发的代码管理工具,它使我们得以进行多人在同一平台之下的团队开发. 解决问题:Eclipse下的的SVN插件安装. 学到 :Eclipse下的的SVN插件安装. 资源地 ...
- Windows API 第17篇 GetLogicalDriveStrings 获取本机所有逻辑驱动器,以根目录的形式表示
函数原型:DWORD GetLogicalDriveStrings( DWORD nBufferLength, // size of buffer ...
- [Swoole系列入门教程 3] 心跳检测
一.Swoole 的4大知识点: 1.TCP/UDP服务器 2.微服务 3.协程 二.同步与异步: 同步买奶茶:小明点单交钱,然后等着拿奶茶: 异步买奶茶:小明点单交钱,店员给小明一个小票,等小明奶茶 ...