概要图

一 多态

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的更多相关文章

  1. 理解JAVA - 面向对象(object) - 属性,方法

    理解JAVA - 面向对象(object) - 属性,方法 多态的体现:    向上造型,父类接收子类对象:向上造型:    从父类角度看不到子类独有的方法:面向对象,人类认知世界的方式:生活中每天都 ...

  2. C++和java多态的区别

    C++和java多态的区别 分类: Java2015-06-04 21:38 2人阅读 评论(0) 收藏 举报  转载自:http://www.cnblogs.com/plmnko/archive ...

  3. 【转】java多态详解

    1.        Java中除了static和final方法外,其他所有的方法都是运行时绑定的.private方法都被隐式指定为final的,因此final的方法不会在运行时绑定.当在派生类中重写基 ...

  4. 关于Java多态的总结.

    [圣思源笔记]JAVA SE Lesson 11. 类是一种抽象的概念,对象是类的一种具体表示形式,是具体的概念.先有类,然后由类来生成对象(Object).对象又叫做实例(Instance).2. ...

  5. 从JVM角度看Java多态

    首先,明确一下,Java多态的三个必要条件: 1. 继承 2. 子类重写父类方法 3. 父类引用指向子类对象 然后看一个例子 package test.xing; class Father{ prot ...

  6. JDK1.8源码(一)——java.lang.Object类

    本系列博客将对JDK1.8版本的相关类从源码层次进行介绍,JDK8的下载地址. 首先介绍JDK中所有类的基类——java.lang.Object. Object 类属于 java.lang 包,此包下 ...

  7. Java - 22 Java 多态

    Java 多态 多态是同一个行为具有多个不同表现形式或形态的能力. 多态性是对象多种表现形式的体现. 比如我们说"宠物"这个对象,它就有很多不同的表达或实现,比如有小猫.小狗.蜥蜴 ...

  8. 从虚拟机角度看Java多态->(重写override)的实现原理

    工具与环境:Windows 7 x64企业版Cygwin x64jdk1.8.0_162 openjdk-8u40-src-b25-10_feb_2015Vs2010 professional 0x0 ...

  9. Java多态之向上转型

    目录 Java多态之向上转型 多态的优点 向上转型 概念 向上转型好在哪 Java多态之向上转型 多态性是面向对象的第三大特征. 多态的优点 改善代码的组织结构和可读性. 能够创建可扩展的程序.(随时 ...

  10. Java多态之动态绑定

    目录 Java多态之动态绑定 引用变量的类型 编译时类型 运行时类型 方法绑定 静态绑定 动态绑定 方法表 Java多态之动态绑定 上篇回顾:多态是面向对象程序设计非常重要的特性,它让程序拥有 更好的 ...

随机推荐

  1. raft学习

    http://thesecretlivesofdata.com/raft/ 选举 角色:  leader 领导者 Follower跟随者  Candidate候选者 如果跟随者在一定时间内,么有收到领 ...

  2. vue2 + koa2全栈部署

    1.首先打包前端上传 修改config下的index.js 代理地址为服务器IP index: path.resolve(__dirname, '../dist/index.html'), asset ...

  3. 菜鸟nginx源码剖析数据结构篇(十) 自旋锁ngx_spinlock[转]

    菜鸟nginx源码剖析数据结构篇(十) 自旋锁ngx_spinlock Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.csd ...

  4. System.Text.Encoding.cs

    ylbtech-System.Text.Encoding.cs 1.程序集 mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77 ...

  5. Java—重写与重载的区别

    1.重写(Override) 子类继承了父类原有的方法,但有时子类并不想原封不动的继承父类中的某个方法,所以在方法名,参数列表,返回类型(除了子类中方法的返回值是父类中方法返回值的子类时)都相同的情况 ...

  6. CentOS 8上安装Docker

    前言 这几天,想玩玩docker,方便漏洞复现,我去学docker搭建了,感觉不错,挺方便的 安装步骤: 1.下载docker-ce的repo curl https://download.docker ...

  7. java实现从实体到SQL语句的转换

    使用过Hibernate,EF之类的ORM框架都知道一般的CRUD之类的简单操作,只要调用框架封装好了的方法,框架就自动生成相应的SQL语句了,参照实习公司给的代码,那个是C#版的,今天弄了一下jav ...

  8. (Eclipse) 安装Subversion1.82(SVN)插件

    简介    :SVN是团队开发的代码管理工具,它使我们得以进行多人在同一平台之下的团队开发. 解决问题:Eclipse下的的SVN插件安装. 学到    :Eclipse下的的SVN插件安装. 资源地 ...

  9. Windows API 第17篇 GetLogicalDriveStrings 获取本机所有逻辑驱动器,以根目录的形式表示

    函数原型:DWORD GetLogicalDriveStrings(  DWORD nBufferLength,  // size of buffer                          ...

  10. [Swoole系列入门教程 3] 心跳检测

    一.Swoole 的4大知识点: 1.TCP/UDP服务器 2.微服务 3.协程 二.同步与异步: 同步买奶茶:小明点单交钱,然后等着拿奶茶: 异步买奶茶:小明点单交钱,店员给小明一个小票,等小明奶茶 ...