返回列表 发新帖

【Android入坑系列教程】45.对象的多态性(一)---面向对象

[复制链接]

62

主题

722

回帖

2756

积分

大学生

Rank: 5Rank: 5

金币
2029
好评
12
信誉
100

考神

发表于 2019-4-3 12:26:52 | 显示全部楼层 | 阅读模式  来自 四川
本帖最后由 pansong291 于 2019-4-1 13:18 编辑

上篇:44.抽象类与接口---面向对象
下篇:46.对象的多态性(二)---面向对象

注意:如果你的回复只是“感谢分享”、“辛苦了”之类的与教程内容无关的字眼,还请不要回复本帖,谢谢合作!!!
注意:如果你的回复只是“感谢分享”、“辛苦了”之类的与教程内容无关的字眼,还请不要回复本帖,谢谢合作!!!
注意:如果你的回复只是“感谢分享”、“辛苦了”之类的与教程内容无关的字眼,还请不要回复本帖,谢谢合作!!!


对象的类型转换
前面第二章我们讲到了基本数据类型变量的类型转换问题,其实对象类型转换也差不多
是一个道理。
1).子类转换成父类
我们来看看下面的程序代码:
程序清单:C.java
class A
{
    public void func1()
    {
        System.out.println("A func1 is calling");
    }
    public void func2()
    {
        func1();
    }
}
class B extends A
{
    public void func1()
    {
        System.out.println("B func1 is calling");
    }
    public void func3()
    {
        System.out.println("B func3 is calling");
    }
}
class C
{
    public static void main(String [] args)
    {
        B b=new B();
        A a = b;
        callA(a);
        callA(new B());
    }
    public static void callA(A a)
    {
        a.func1();
        a.func2();
    }
}
编译没有错误,我们发现,编译器能够自动将类 B 的实例对象 b 直接赋值给 A 类的引用
类型变量,也就是子类能够自动转换成父类类型。另外,我们也看到了,程序可以直接创建
一个类 B 的实例对象,传递给需要类 A 的实例对象作参数的 callA 方法,在参数传递的过程
中发生了隐式自动类型转换。子类能够自动转换成父类的道理非常容易理解,“男人”是“人”
的子类,要把一个“男人”对象当作“人”去用,天经地义!
2).父类转换成子类
如果我们在编程时,知道 callA 方法中传递的形式参数 a 实际上就是子类 B 的一个引用
对象,我们想在 callA 方法中调用子类的特有方法,该如何做呢?
public static void callA(A a)
{
    a.func1();
    a.func2();
    a.func3();
}
编译有问题,因为对编译器来说,它只分析程序语法,它只知道变量 a 的引用类型是类
A,而类 A 又没有 func3 这个方法,所以,编译无法通过。
我们将程序代码作如下修改:
public static void callA(A a)
{
    B b=a;
    b.func1();
    b.func2();
    b.func3();
}
编译还是有问题,因为编译器是不能将父类对象自动转换成子类的。父类对象不能自动
转换成子类的道理也很容易理解,要把一个“人”直接当作“男人”去用,是有点说不过去
的。
最后更改如下:
public static void callA(A a)
{
    B b=(B)a;
    b.func1();
    b.func2();
    b.func3();
}
编译就通过了。读者看到了,我们把对象 a 强制转换成了 B 类的引用类型,编译器对该
对象进行了强制转换。我们通过下面的讲解来帮助读者了解强制类型转换。
比如有个函数为“去叫一个人来”,定义该函数时,其返回值只能是“人”,但实际来的
“人”,不是“男人”,就是“女人”。即使叫来的是一个“女人”,但编译器只能根据函数定
义的语法去确定来的是“人”,没法确定运行时返回的是“男人”,还是“女人”,如果将该
函数的返回值直接赋给一个“女人”类型的变量,编译时将不会通过。程序员是很清楚运行
时返回的是“男人”,还是“女人”的,他可以告诉严格执行语法检查的编译器:“我知道来
的这个人确实是一个女人,你把他当作女人去处理吧,出了问题,我负责!”。这个过程就是
强制类型转换,目的是让编译器进行语法检查时开点后门,放你过关,强制类型转换并不是
要对内存中的对象大动手术,不是要将“男人”变成“女人”。
在类型转换时,程序员要对转换完的后果负责,要确保在内存中存在的对象本身确实可
以被看成那种要转换成的类型,如果来的“人”是男人,我们将其转换成“女人”后,编译
能够通过,但程序运行时将会出错,虽然骗过了编译器,但你没法调用“女人”独有的方法
(比如怀孕),所以运行时就会产生类型转换异常。强制类型转换的前提是程序员提前就知
道要转换的父类引用类型对象的本来面目确实是子类类型的。
作者在编码和调试时,总是用意境的方式,仿佛看到变量或对象在内存中的真实布局和
状态,以及是如何进行转换的,这样编码时比较容易一气呵成,极少犯错。
有些时候,我们不能提前就知道这个“人”是不是“女人”,能不能事先判断一下呢?
也就是这个父类的引用变量是否真的指向了要转换成的那个子类对象呢?我们 用
instanceof 操作符就可以解决这个问题。
3).instanceof 操作符
可以用 instanceof 判断是否一个类实现了某个接口,也可以用它来判断一个实例对象
是否属于一个类。还是用上面的代码来举例:
public static void callA(A a)
{
    if(a instanceof B)
    {
        B b=(B)a;
        b.func1();
        b.func2();
        b.func3();
    }
    else
    {
        a.func1();
        a.func2();
    }
}
这样改的目的是要判断一下传入的“人”,是不是属于“女人”这个类的。如果是,则
强制类型转换,如果不是就不转换。
instanceof 的用法:
对象 instanceof 类(或接口)
它的返回值是布尔型的,或真(true),或假(false)。
大家只要记住:一个“男人”肯定也是“人”,一个“人”却不一定是“男人”的道理,
就非常容易理解父类和子类之间的转换关系了。

Object 类
Java 中有一个比较特殊的类,就是 Object 类,它是所有类的父类,如果一个类没有
使用 extends 关键字明确标识继承另外一个类,那么这个类就默认继承 Object 类,因此,
Object 类是 Java 类层中的最高层类,是所有类的超类。换句话说,Java 中任何一个类都是
它的子类。由于所有的类都是由 Object 衍生出来的,所以 Object 的方法适用于所有类。
public class Person
{
    ...
}
等价于:
public class Person extends Object
{
    ...
}
Object 中有一个 equals 方法,用于比较两个对象是否相等,默认值为 false。由于上
面的继承特性,我们就可以在我们的类中使用这个 equals 方法,但如果我们要比较的是我
们自己类中的对象,结果就不一定准确了。因此,就必须覆盖掉 Object 类的 equals 方法。
请看下面的例子,在本类中,我们认为姓名和年龄都相同的两个学生是同一个人。所以,
我们用自己的 equals 覆盖掉了 Object 类中的 equals 方法,这样才达到了我们的编程的目
的。
程序清单:Student.java
class Student
{
    String name;
    int age;
    boolean equals(Object obj)
    {
        Student st=null;
        if(obj instanceof Student)
            st = (Student)obj;
        else
            return false;
        if(st.name==this.name && st.age==this.age)
            return true;
        else
            return false;
    }
    public static void main(String[] args)
    {
        Student p=new Student();
        Student q=new Student();
        p.name="xyz";
        p.age=13;
        q.name="xyz";
        q.age=13;
        if(p.equals(q))
            System.out.println("p 与 q 相等");
        else
            System.out.println("p 与 q 不等");
    }
}

上篇:44.抽象类与接口---面向对象
下篇:46.对象的多态性(二)---面向对象
回复

使用道具 举报

0

主题

137

回帖

580

积分

初中生

Rank: 3Rank: 3

金币
172
好评
0
信誉
96

考神

发表于 2022-1-4 16:21:26 来自手机  | 显示全部楼层  来自 重庆
这代码写的太绕了哥我前面44篇都看明白了,这一篇脑袋嗡嗡的
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表