10多态_Object
导语:
想到在写
- 引出了多态的好处。通过动物示例发现操作父类型可以提高扩展性
- 动物的示例,了解了多态的体现,好处,弊端,前提,向上向下转型,以及什么时候用?★★★★★
- 毕老师和毕姥爷的故事。将多态的知识点串一下。自动动手写!★★★★★
- 分三个阶段 完成笔记本电脑使用外围设备。并通过接口解耦,并通过多态提高程序的扩展性。★★★★★★★
- 多态调用时,成员变量,成员函数,静态函数的特点。以及规律
- 一定要画图,得出结果。有点难!没视频,★★★★★
- 了解Object类中的equals toString方法的使用
1. 引出了多态的好处。通过动物示例发现操作父类型可以提高扩展性
//多态技术的引出。解决什么问题?程序扩展性的问题。
//描述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();
}
*/
}
2. 动物的示例,了解了多态的体现,好处,弊端,前提,向上向下转型,以及什么时候用?★★★★★
//多态
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();
}
/*
多态:
【体现】
父类的引用或者接口的引用指向了自己的子类对象。
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异常。
所以为了避免这个问题,需要在向下转型前,做类型的判断。
判断类型用的是关键字 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
*/
class DuoTaiDemo2
{
public static void main(String[] args)
{
Dog d = new Dog();
// d.eat();
// d.lookHome();
/*
Animal a = new Dog();
a.eat();//可以的。
// a.lookHome();//不可以的。
*/
method(d);
Cat c = new Cat();
method(c);
}
public static void method(Animal a)
{
a.eat();
// Dog d = (Dog)a;//ClassCastException:类型转换异常。
// d.lookHome();
// a.lookHome();//不可以,因为动物不具备这个功能。
}
}
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.看电影();
}
//自始至终都是子类对象做着类型的变化。
}
}
4. 分三个阶段 完成笔记本电脑使用外围设备。并通过接口解耦,并通过多态提高程序的扩展性。★★★★★★★
/*
阶段一需求:笔记本电脑运行。
按照面向对象的思想,用代码体现。
名称提炼法。
笔记本电脑。
行为:运行。
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 NoteBook
{
//运行功能。
public void run()
{
System.out.println("notebook run");
}
// 使用鼠标功能。
public void useMouse(Mouse m)
{
if(m!=null)
{
m.open();
m.close();
}
}
}
//问题:如果想要加入一个键盘呢?
只要描述一个键盘类,并在电脑类中加入一个使用键盘的功能就哦了。
但是发现从鼠标开始这个问题就已经产生了,一旦需要添加新设备的时候,
都需要改变电脑的源码。这个扩展性是非常差的。
设计上该如何改进呢?
之前的问题在于外围设备的增加和笔记本电脑之间的耦合性过高。
如何降低外围设备和笔记本电脑的耦合性呢?
外围设备还不确定,我们不要面对外围具体设备。
为了让笔记本可以使用这些设备,可以事先定义好一些规则,
笔记本只要使用这些规则就可以了。
有了这些规则就可以进行笔记本的功能扩展。
后期这些外围设备只要符合这些规则就可以被笔记本使用了。
那么规则在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());
}
}
5. 多态调用时,成员变量,成员函数,静态函数的特点。以及规律
/*
多态中,成员调用的特点。
1,成员变量。
当子父类中出现同名的成员变量时。
多态调用该变量时:
编译时期:参考的是引用型变量所属的类中是否有被调用的成员变量。没有,编译失败。
运行时期:也是调用引用型变量所属的类中的成员变量。
简单记:编译和运行都参考等号的左边。
编译运行看左边。
2,成员函数。
编译,参考左边,如果没有,编译失败。
运行,参考右边的对象所属的类。
编译看左边,运行看右边。
对于成员函数是动态绑定到对象上。
3,静态函数。
编译和运行都参考左边。
静态函数是静态的绑定到类上。
【结论】
对于成员变量和静态函数,编译和运行都看左边。
对于成员函数,编译看左边,运行看右边。
*/
class Fu
{
int num = 3;
void show()
{
System.out.println("fu show run");
}
static void method()
{
System.out.println("fu static method run");
}
}
class Zi extends Fu
{
int num = 5;
void show()
{
System.out.println("zi show run..");
}
static void method()
{
System.out.println("zi static method run");
}
}
class DuoTaiDemo3
{
public static void main(String[] args)
{
/*
//测试成员变量的多态调用。
Fu f = new Zi();
System.out.println(f.num);//3
Zi z = new Zi();
System.out.println(z.num);//5
*/
/*
//测试成员函数的多态调用。
Fu f = new Zi();
f.show();
*/
//测试静态函数的多态调用。
Fu f = new Zi();
f.method();
//注意:真正开发静态方法是不会被多态调用的,因为静态方法不所属于对象,而是所属于类。
Fu.method();
Zi.method();
}
}
6. 一定要画图,得出结果。有点难!没视频,★★★★★
//练习:看程序画图,得出结果!
class Fu
{
int x = 4;
Fu()
{
System.out.println("A fu() : "+this.getNum());
}
int getNum()
{
System.out.println("B fu getnum run...."+x);
return 100;
}
}
class Zi extends Fu
{
int x = 5;
Zi()
{
System.out.println("C zi() : "+getNum());
}
int getNum()
{
System.out.println("D zi getnum run...."+x);
return 200;
}
}
class DuoTaiTest3
{
public static void main(String[] args)
{
Fu f = new Zi();
//System.out.println("main :" +f.getNum());
//Person p = new Person(20):
}
}
7. 了解Object类中的equals toString方法的使用
/*
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方法。】
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方法,建立Person对象自己的字符串表现形式。
public String toString()
{
return "Person[age = "+age+"]";
}
/*
public boolean compare(Person p)
{
return this.age == p.age;
}
*/
}
class Dog
{
}
class ObjectDemo
{
public static void main(String[] args)
{
Person p1 = new Person(12);
Person p2 = new Person(15);
// System.out.println(p1.equals(p2));
System.out.println(p1.toString());//Person@da4b71//想要建立自定义对象的字符串表现实行。咋办、覆盖toString方法就哦了。
System.out.println(p2);
// -----------------------------
// System.out.println(p1.compare(p2));
// System.out.println(p1 == p2);
// System.out.println(p1.equals(p2));
}
}