返回列表 发新帖

【Android入坑系列教程】35.类与对象(一)---面向对象

[复制链接]

62

主题

722

回帖

2756

积分

大学生

Rank: 5Rank: 5

金币
2029
好评
12
信誉
100

考神

发表于 2019-3-25 16:17:18 | 显示全部楼层 | 阅读模式  来自 四川
本帖最后由 pansong291 于 2019-3-21 15:44 编辑

上篇:34.面向对象的概念---面向对象
下篇:36.类与对象(二)---面向对象

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


面向对象的编程思想力图使在计算机语言中对事物的描述与现实世界中该事物的本来
面目尽可能的一致,类(class)和对象(object)就是面向对象方法的核心概念。类是对某一
类事物的描述,是抽象的、概念上的定义;对象是实际存在的该类事物的个体,因而也称实
例(instance)。
如图 3.1 所示就是一个典型的说明:

其中,汽车设计图就是“类”,由这个图纸设计出来的若干的汽车就是按照该类产生的
“对象”。可见,类描述了对象的属性和对象的行为,类是对象的模板、图纸。对象(Object)
是类(Class)的一个实例(Instance),是一个实实在在的个体,一个类可以对应多个对象。
如果将对象比作汽车,那么类就是汽车的设计图纸。所以面向对象程序设计的重点是类的设
计,而不是对象的设计。
同一个类按同种方法产生出来多个对象,刚开始的状态都应该是一样的,好比按照“奔
驰 s600”型设计图纸生产出来的汽车刚开始都是一样的,其中一辆“奔驰 s600”汽车被改
装后,是不会影响到同型号的其他“奔驰 s600”汽车的。但如果修改了“奔驰 s600”型的
设计图纸,就会影响到以后所有出厂的“奔驰 s600”汽车。

类的定义
类可以将数据和函数封装在一起,其中数据表示类的属性,函数表示类的行为。定义类
就是要定义类的属性与行为(方法)。请看这段代码:
class Person
{
    int age;
    void shout()
    {
        System.out.println("oh,my god! my age is " + age);
    }
}
其中,定义了一个 Person 类,该类有一个属性 age,一个方法 shout。类的属性也叫类
成员变量,类的方法也叫类的成员函数。一个类中的方法可以直接访问同类中的任何成员(包
括成员变量和成员函数),如 shout 方法可以直接访问同一个类中的 age 变量。
脚下留心:如果一个方法中有与成员变量同名的局部变量,该方法中对这个变量名的
访问是局部变量,而不再是成员变量。如:
class Person
{
    int age; //这是一个成员变量
    void shout()
    {
        int age=60; //这是函数内部又重新定义的一个局部变量
        System.out.println("oh,my god! my age is " + age);
    }
}
在这里,shout 方法的 System.out.println("oh,my god! my age is " + age); 语句
所访问的 age 就不再是成员变量 age,而是在 shout 方法中定义的局部变量 age。

对象的产生与使用
光有设计图是无法实现汽车的功能的,只有产生了实际的汽车才行,同样的,要想实现
类的属性和行为,必须创建具体的对象。
要创建新的对象,需要使用 new 关键字和想要创建对象的类名,如:
Person p1 = new Person();
等号左边以类名 Person 做为变量类型定义了一个变量 p1,来指向等号右边通过 new
键字创建的一个 Person 类的实例对象,变量 p1 就是对象的引用句柄,对象的引用句柄是在
栈中分配的一个变量,对象本身是在堆中分配的,原理同上一章讲过的数组是一样的。注意:
new 语句的类名后一定要跟着一对圆括号(),在本章的稍后部分,读者就会明白这个括
号的意义的。这条语句执行完后的内存状态如图 3.2 所示:

变量在被初始化之前是不能使用的,我们肯定还记得在一个方法内部的变量必须进行初
始化赋值,否则编译无法通过的情况。当一个对象被创建时,会对其中各种类型的成员变量
按表 3.1 自动进行初始化赋值。除了基本数据类型之外的变量类型都是引用类型,如上面的
Person 及前面讲过的数组。

所以,我们看到对象内存状态图中的 age 成员变量的初始值为 0
创建新的对象之后,我们就可以使用“对象名.对象成员”的格式,来访问对象的成员(包
括属性和方法),下面的程序代码演示了 Person 类对象的产生和使用方式。
class TestPerson
{
    public static void main(String[] args)
    {
        Person p1 = new Person();
        Person p2 =new Person();
        p1.age = -30;
        p1.shout();
        p2.shout();
    }
}
程序运行结果如下:
oh,my god! my age is -30
oh,my god! my age is 0

上面的程序代码,在 TestPerson.main 方法中创建了两个 Person 类的对象,并定义了
两个 Person 类的对象引用句柄 p1、p2,分别指向这两个对象。接着,程序调用了 p1 和 p2
的方法和属性,p1、p2 是两个完全独立的对象,类中定义的成员变量,在每个对象都被单
独实例化,不会被所有的对象共享,改变了 p1 的 age 属性,不会影响 p2 的 age 属性。调用
某个对象的方法时,该方法内部所访问的成员变量,是这个对象自身的成员变量。上面程序
运行的内存布局如图 3.3 所示:

每个创建的对象都是有自己的生命周期的,对象只能在其有效的生命周期内被使用,当
没有引用变量指向某个对象时,这个对象就会变成垃圾,不能再被使用。我们通过分析下面
的几种程序代码,来了解对象何时会变成垃圾的情况。
第一种情况的程序代码:
{
    Person p1 = new Person();
    ……
}
程序执行完这个代码块后,也就是执行完这对大括号中的所有代码后,产生的 Person
对象就会变成垃圾,因为引用这个对象的句柄 p1 已超过其作用域,p1 已经无效, Person
对象就不再被任何句柄引用了。如图 3.4 所示:

第二种情况的程序代码:
{
    Person p1 = new Person();
    p1 = null;
    ……
}
在执行完 p1 = null;后,即使句柄 p1 还没有超出其作用域,仍然有效,但它已经被赋
值为空,也就是说 p1 不再指向任何对象,这个 Person 对象也就成了孤儿,不再被任何句柄
引用,变成了垃圾。如图 3.5 所示:

第三种情况的程序代码:
{
    Person p1 = new Person();
    Person p2 = p1;
    p1 = null;
    ……
}
执行完 p1 = null;后,产生的 Person 对象不会变成垃圾,因为这个对象仍被 p2 所引
用,直到 p2 超出其作用域而无效,产生的 Person 对象才会变成垃圾。如图 3.6 所示:


对象的比较
有两种方式可用于对象间的比较,它们是“==”运算符与 equals()方法,“==”操作符
用于比较两个变量的值是否相等,equals()方法用于比较两个对象的内容是否一致。我们在
前面讲过“==”操作符用于基本数据类型的变量比较的情况,非常简单和容易理解。如果一
个变量是用作指向一个数组或一个对象的句柄,那么这个变量的类型就是引用数据类型 ,
==”操作符用于比较两个引用数据类型变量的情况,对初学者来说,很容易造成一些混淆,
我们来看看下面的程序代码:
class Compare
{
    public static void main(String[] args)
    {
        String str1 = new String("abc");
        String str2 = new String("abc");
        String str3 = str1;
        if(str1==str2)
            System.out.println("str1==str2");
        else
            System.out.println("str1!=str2");
        if(str1==str3)
            System.out.println("str1==str3");
        else
            System.out.println("str1!=str3");
    }
}
程序运行结果是:
str1!=str2
str1==str3

str1 和 str2 分别指向了两个新创建的 String 类对象,尽管创建的两个 String 实例对
象看上去是一模一样,但他们是两个彼此独立的对象,是两个占据不同内存空间地址的不同
对象。str1 和 str2 分别是这两个对象的句柄,也就是 str1 和 str2 的值分别是这两个对象
的内存地址,显然他们的值是不相等的。将 str1 中的值直接赋给了 str3,str1 和 str3 的
值当然是相等的。str1 和 str2 就好比是一对双胞胎兄弟的名称,尽管这对双胞胎兄弟长相
完全一模一样,但他们不是同一个人,所以,是不能等同的,str3 就好比是为 str1 取的一
个别名,str3 和 str1 代表的是同一个人,所以,它们是相等的。这个过程如图 3.7 所示。

只要在脑子里想的是各个变量所对应的内存状态,就非常容易理解上面的结果了。
我们下面再来看看使用 equals()方法的情况。
class Compare
{
    public static void main(String[] args)
    {
        String str1 = new String("abc");
        String str2 = new String("abc");
        String str3 = str1;
        if(str1.equals(str2))
            System.out.println("str1 equal str2");
        else
            System.out.println("str1 not equal str2");
        if(str1.equals(str3))
            System.out.println("str1 equal str3");
        else
            System.out.println("str1 not equal str3");
    }
}
程序运行结果是:
str1 equal str2
str1 equal str3

equals()方法是 String 类的一个成员方法,用于比较两个引用变量所指向的对象的内
容是否相等,就像比较两个人的长相是否一样。关于 equals 更详细的信息,我们将在后面讲解。
多学两招:同我们刚才讲的普通对象的比较方式一样,我们是不能用“==”运算符来比较两个数组
对象的内容是否相等,但数组对象本身又没有 equals 方法,那我们怎样比较两个数组对象
的内容是否相等呢?如果你还记得,在上一章中,我们曾经用过 Arrays.sort 方法对数组进
行排序,我们为什么不去大胆设想 Arrays 里面可能提供了另外的方法,来帮助我们解决比
较两个数组对象的内容是否相等的问题,查看 Arrays 类的信息,我们果然发现该类提供了
用于比较数组内容的 equals()方法。或者你也可以搜索Java的API。


上篇:34.面向对象的概念---面向对象
下篇:36.类与对象(二)---面向对象

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

1

主题

2283

回帖

4494

积分

大学生

Rank: 5Rank: 5

金币
2610
好评
1
信誉
100
发表于 2019-3-25 19:00:54 | 显示全部楼层  来自 河北
只会说感谢分享
回复

使用道具 举报

发表回复

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

本版积分规则

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