面向对象-多态

.面向对象-多态

1.什么是多态:事物存在的多种形态

比如说有一个男人,我们可以说:来了个男人,也可以说来了个人,甚至说来了个生物;我们说的都是那个指定的男人对象;

class Animal{

}

class Cat extends Animal{

}

Cat c = new Cat();

Animal a = new Cat();

我现在new了一个猫的实体,我可以把这个实体装到专门装猫的一和盒子c

也可以把它装到撞门装动物的盒子a里面,都是可以的;

现在这个猫的实体就有多了各种表现形态.Animal a = new Cat(); 这就是多态!

分析:

猫和动物的关系.猫类是动物类的所属,他们是继承关系.猫继承动物.装猫这个实体对象的盒子必须是猫类型,或动物类型.也就是猫本身或父类类型的变量;

现在加一个狗类

class Animal{

public void sleep(){

System.out.println("睡觉");

}

}

class Cat extends Animal{

}

class Dog extends Animal{

}

以前我们要让猫睡觉,或狗睡觉. 就得

Cat c = new Cat();

Dog d = new Dog();

c.sleep();

d.sleep();

现在不管是猫还是狗

Animal a1 = new Cat();

Animal a2 = new Dog();

a1.sleep();

a2.sleep();

用另一种说法就是:把猫这个对象的地址值指向a1,只要a1的变量类型是猫或者猫的父类类型,就可以用多态!

现在测试类写一个方法,让猫或者狗睡觉

public class AnimalTest {

public static void main(String[] args) {

}

public static void toSleep(Cat c){

c.sleep();

}

public static void toSleep(Dog d){

d.sleep();

}

}

我现在传一只猫进去,就可以让猫睡觉,传一狗进去可以让狗睡觉.如果说,我动物里面有很多子类,,,,龙什么的.这里岂不是要写很多个toSleep

那么怎么用多态的形式来优化一下;

public static void toSleep(Animal a){

a.sleep();

}

不管你来什么动物,只要是Animal的子类我都可以用Animal的变量来接收.这样只需要一个方法就行了大家看到这幅图

 

2.多态的代码体现

就是父类的引用(变量)指向了自己的子类对象

Animal a = new Cat(); 必须有继承关系

3.多态的好处:提高代码的扩展性,简化代码

4.多态的向上向下转型

我们刚才传一个子类的对象进来,只能调用sleep()睡觉方法.如果说子类里边有自己独有的功能

public void catchFish(){

System.out.println("抓鱼");

}

public void kanJia(){

System.out.println("看家");

}

我现在传一个猫进来让他抓鱼!

public static void toSleep(Animal a){

a.catchFish();

}

报错了.因为动物类里边没有抓鱼的方法,抓鱼只能是猫的特有功能,动物不具备抓鱼的功能;

Animal a = new Cat();

现在这样的表达式,我们可以看成这个猫对象向上转型了,转成动物型了,可以暂时把他看成一个动物类型.动物类型就不具备抓鱼的功能;

所以多态:父类的引用只能使用父类的方法(成员)这就是向上自动转型

如果现在我就要调用子类的方法可以吗?因为现在可以看成是一个动物,我们现在只能把这个动物转成猫类型才能调用抓鱼的方法;

向下强制转型

跟基本数据类型强转差不多

public static void toSleep(Animal a){

Cat c = (Cat)a;

c.catchFish();

}

把这个a动物类型强转成猫类型,就可以调用猫里边特有的方法;

现在又要变魔术了啊!如果说我现在想要 狗看家

public static void main(String[] args) {

Dog d = new Dog();

toSleep(d);

}

public static void toSleep(Animal a){

Cat c = (Cat)a;

}

这时候强转就要报错!

 

类型的转换异常,说得很清楚, Dog这个类不能转换为Cat这个类;

为什么呢,我们说这个狗传到a变量里边就自动向上转型为动物了.然后把动物转换成猫没问题啊!其实是有问题的,这里要涉及到向下强转的本质:

强转的本质是:只是转换了他的引用类型,变量.而不是转换了那个实体对象

这里a变量里面的本质是一个狗的对象,狗的对象你现在强转把它放到装猫的盒子里,不适合了吧!

:向下强转,首先得看实体对象的类型,使用多态后,才能强转回原来的类型!

那么现在我的需求是来一个狗,我让它看家,来一个猫我就让它抓鱼!

5.instanceof关键字

判断是不是什么类型!返回一个boolean

public static void main(String[] args) {

Dog d = new Dog();

toSleep(d);

}

public static void toSleep(Animal a){

boolean b = a instanceof Cat;

System.out.println(b);

}

boolean isDog = a instanceof Animal;

boolean isDog = a instanceof Cat;

通过测试我们看出instanceof可以判断是一个类型本身和父类类型?

所以说这儿就可以判断出我们拿到的实体是猫还是狗,然后做出相应的动作!

public static void toSleep(Animal a){

if(a instanceof Cat){

Cat c = (Cat)a;

c.catchFish();

}

if(a instanceof Dog){

Dog d = (Dog)a;

d.kanJia();

}

}

有人说:如果有很多中动物怎么办,岂不是要写很多的判断!是的.必须写,这个是没有办法的;除非以后接触到反射,就可以不写.直接一反射一句话搞定;

现在思考:

System.out.println(a instanceof Object);

毫无疑问,皆成立嘛! 如果是

System.out.println(null instanceof Object);

null是没有任何实体的.没任何动物.所以不属于任何类型!

这儿讲一下默认值!

public class AnimalTest {

private static String name;

private static int age;

private static double high;

private static boolean sex;

private static Animal a;

public static void main(String[] args) {

System.out.println(name);

System.out.println(age);

System.out.println(high);

System.out.println(sex);

System.out.println(a);

}

}

作为成员变量不赋值,他是有默认值的.基本数据类型都有自己的默认值!

如果是对象(引用数据类型)默认都为null;没任何内容;

当对象为null 的时候,如果调用他的方法就报错!

 

空针对异常.也就是找不到这个对象

这个错误,是我们最常见的错误!

二.equals方法

昨天我们学到了toString方法给对象用字符串的形式打印出来.

今天我们学另外一个常用的方法equals

equals的作用: 判断与某个对象是否”相等”!

 

我们看到这个方法返回的是一个boolean值如果相等就返回true 如果不相等就返回false

我们要比较两个对象是否相等,得再传一个对象过来比较吧,传什么对象,我们暂时不确定嘛,不管你传什么对象,我都可以用Object来接收,这里用了多态!

先来试试什么效果吧

public class Student {

public static void main(String[] args) {

Student s1 = new Student();

Student s2 = new Student();

Student s3 = s1;

System.out.println(s1==s2);

System.out.println(s1==s3);

System.out.println(s1.equals(s3));

}

}

首先看s1==s2 他比的是对象的地址值,也就是hashCode()的值,如果不相等就false,这里是两个对象所以是false

然后s1==s3 开始s1指向了一个地址值,现在s3=s1  s3也指向了这个地址值.所以为true

第三个s1.equals(s3) 其实就是比的地址值

对象与对象之间==equals没什么区别

在咱们生活当中,只要两个学生的姓名和年龄都相等,我们就可以认为他们是同一个学生!

public class Student {

private String name;

private int age;

Student(String name ,int age){

this.name = name;

this.age = age;

}

public static void main(String[] args) {

Student s1 = new Student("张三",20);

Student s2 = new Student("张三",20);

System.out.println(s1.equals(s2));

}

}

现在判断出来是false,我们并不是要去比他们的地址值,我们要比的就是他们的姓名和年龄!

所以说Object中的equals满足不了我们的需求!

所以要复写!

public boolean equals(Object obj){

if(this.name==obj.name && this.age == obj.age){

return true;

}else{

return false;

}

}

报错了.因为obj当中没有nameage字段.这时候要向下强转!

public boolean equals(Object obj){

if(obj instanceof Student){

Student s = (Student)obj;

if(s.name == name && s.age == age){

return true;

}

return false;

}else{

return false;

}

}

现在运行一下,就可以判断两个学生是否相等!

题目:下面的运行结果是?

1.

 

 

 

2.

 

 

 

 

1.报错   2.多此一举

:向下强转,首先得看实体对象的类型,使用多态后,才能强转回原来的类型!

 

三.String== equals

1.String的常量池

 

因为两个都是比的地址值.

String类里面的==也是比的地址值,但是String涉及到一个常量池

String s1 = "hehe";

String s2 = "hehe";

String s3 = new String("hehe");

System.out.println(s1==s2);

System.out.println(s1==s3);

System.out.println(s1.equals(s3));

为什么呢?String有一个常量池:

 

Stringequals比的字符串内容!不管你是不是在常量池!

 

 

通过API可以看到String类也复写了Objectequals方法!

Object--equals:比地址值

String--equals:比字符串内容

很多面试题用这个可以让大多数人懵逼!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值