Java学习指南(08) 当前对象

本文是《Java学习指南》原书的网络版,作者邵发,拥有本书的全部权利。相关视频课程在此查看

目录

第8章 当前对象

8.1 当前对象 this

8.2 省略与重名

8.3 类的设计示范

8.4 特殊形式的属性


第8章 当前对象

8.1 当前对象 this

引例:用Screen表示一个屏幕,width, height表示宽和高。要求写一个方法pixel() 计算它的像素数。

( 像素计算公式: p = width * height )

按我们现在的所学,可以新建一个Screen类,

public class Screen
{
    public int width;
    public int height;
    public int pixel ( int w, int h )
    {
        int result = w * h;
        return result;
    }
}

然后再main()方法里按如下的方式调用,

Screen s = new Screen();
s.width = 1366;
s.height = 768;
int p = s.pixel( s.width, s.height );
System.out.println("像素数: " + p );  

这样是可以实现需求的,但是也存在一个显示的问题:前面已经设置了s的属性s.width和s.height,后面在调用s.pixel()方法的时候却又传递的一遍。

这就好比,Screen类当于我们编写的一个工具,明明已经给它设好了宽高,在让它计算像素的时候,却又还要我们传递一遍。显然,这么设计的工具不能算是好用的。

下面,我们可以做一个小改进,

public class Screen

{
    public int width;
    public int height;
    public int pixel ( Screen that ) // 此处改进
    {
        int result = that.width * that.height;
        return result;
    }
}

再按如下方式调用,

Screen s = new Screen();
s.width = 1366;
s.height = 768;

int p = s.pixel( s ); // 此处改进
System.out.println("像素数: " + p );

经此改进之后,在调用s.pixel() 时,只需要对s对象本身传递过去就行了。

虽然如此,但是像s.pixel( s ) 的调用仍然显得有点奇怪:为什么调用调用对象s的方法要传递它自己作为参数呢?

 

8.1.1 this参数

在Java的方法里,默认传递了一个this参数,该参数指向自身对象。例如,

在这里,pixel() 看起来并未带任何参数,但实际上有一个隐含的参数this,指向当前对象。

那么,什么是当前对象呢?

当在外面调用s.pixel() 时,s即为当前对象。在进入pixel()方法,this所指向的对象,就是当前对象。

 

8.1.2 调用自己的方法

使用this不仅可以访问当前对象的属性,也可以调用当前对象的方法。通过下面的例子来演示。

要求输出m,n之间所有的质数,例如,求400~500之间所有的质数。

所谓质数,是指只能被1和自身整除的,如2,3,5,7,11。

观察以下代码,

public class MyMath
{
    // 判断n是否为质数; true,是质数; false, 不是质数
    public boolean isPrime( int n )
    {
        for(int i=2; i<n ; i++)
        {
            if( n % i == 0)
            {
                return false;
            }
        }
        return true;
    }

    // 输出m,n之间所有的质数
    public void showPrimes (int m, int n)
    {
        for(int i=m;  i<=n; i++)
        {
            if( this.isPrime( i )) //
            {
                System.out.println("质数: " + i );
            }
        }
    }
}

在此例中,在showPrimes() 方法里,通过this.isPrime() 调用当前对象的方法。

这说明,通过this可以访问当前对象的属性和方法。

8.2 省略与重名

8.2.1 省略this

使用this可以访问当前对象的属性和方法,一般情况下,this是可以省略的。

例如,

public class Example
{
    public int number = 10;

    public void showNumber()
    {
        System.out.println("当前值: " + this.number);
    }
}

 

在showNumber()方向当前对象的属性,可以用this.number。为了简化书写,此处的this可省略,形如,

初学者应坚持使用this,再熟练使用this之后才开始省略this的写法。

8.2.2 重名

再看看以下的例子,

1

2

3

4

5

6

7

8

9

public class Example

{

public int number = 10;

public void test()

{

int number = 12;

System.out.println("值为:" + number);

}

}

 

在此例中,

第3行,定义了一个属性 number,值为10

第6行,定义了一个变量 number,值为12

第7行,输出number的值。问题是,这个到底是第3行的number还是第6行的number ?

在 Java里,把定义在方法中的变量,称为局部变量。所以,第6行定义的number就是一个局部变量。

当局部变量与类的属性重名时,局部变量的优先显示。所以,第7行中的number指的是局部变量。此例将输出的值为12。

在重名的情况下,如果要访问类的属性,则必须指定this前缀,不能省略。

以后,我们会经常看来类似如下的写法,

1

2

3

4

5

6

7

8

public class Example

{

public int number = 10;

public void setNumber (int number)

{

this.number = number;

}

}

 

第4行,在参数列表里定义的变量也叫局部变量

第6行,左侧的this.number指的是属性,右侧的number指的是参数里的局部变量。

8.3 类的设计示范

下面通过几个例子,来演示讲解如何按面象对象的思路来设计一个类。

8.3.1 示例1

有一个换游戏币的机器。可以投1元、5元、10元的人民币。最后按一下出货按钮,可以吐出游戏币。

(每个游戏币=1元人民币)

首先,创建一个类Machine来表示这种机器,

public class Machine
{
}

然后,这种机器可以投入现金,所以添加一个方法用于投入现金,

public class Machine
{
    // 人民币:1,5,10
    public void insertCash ( int cash )
    {
    }
}

当把现金投进去后,应该有一个属性记录一共投了多少现金,

public class Machine
{
    public int money = 0; // 机器里投入了多少钱

    public void insertCash ( int cash )
    {
    }
}

现在来完成insertCash() 方法,每投入一些现金后,应该把现金数加到余额上,

    public void insertCash ( int cash )
    {
        this.money += cash;
        System.out.println("当前余额: " + this.money);
    }

现在,该完成交易了,添加exchange() 方法,

public class Machine
{
    public int money = 0;

    public void insertCash ( int cash )
    {
        ... 篇幅原因,  省略此处代码 ..
    }

    public int exchange ()
    {
        int numOfCoin = this.money / 1;
        this.money = 0;
        System.out.println("交易完成, 当前余额: "   + this.money);
        return numOfCoin;
    }
}

最后看看怎么调用这个类,

Machine m  = new Machine();
m.insertCash( 5 );
m.insertCash( 10);
m.insertCash( 50);

int coins = m.exchange(); // 按一下按钮
System.out.println("拿到了" + coins + "个游戏币");

这便是一个最简单的面向对象的设计。

可以发现,类的属性是由于存储数据的,而类的方法则是用于计算处理的。类就是属性和方法的综合体。

 

8.3.2 示例2

有两个数组

int[]  a1 = { 123, 38,  103, 89 };

int[]  b1 = { 34, 8,  11, 29 };

求这两个数组中的所有的质数。

首先,设计一个类PrimeFilter。

添加一个put () 方法,将需要处理的数组传给它,内部检出所有的质数,存在属性result里。

添加一个value()方法,用于取出最后的结果。

示例代码如下,

public class PrimeFilter
{
    // 存储
    public int[] result = new int[512];
    public int total= 0;


    // 用户输入: 数组data
    // 把data数组里面,所有的质数都放到result
    public void put ( int[] data)
    {
        for (int i=0; i<data.length; i++)
        {
            if ( this.isPrime( data[i] ))
            {
                this.result[total] = data[i];
                this.total += 1;
            }
        }
    }

    // 取出最终过滤得到 所有的质数
    public int[] values()
    {
        int[] r = new int[total];
        for(int i=0; i< this.total; i++)
        {
            r[i] = this.result[i];
        }
        return r;
    }

    // 判断n是否为质数; true,是质数; false, 不是质数
    public boolean isPrime( int n )
    {
        for(int i=2; i<n ; i++)
        {
            if( n % i == 0)
            {
                return false;
            }
        }
        return true;
    }
}

再来看一下怎么调用,

PrimeFilter filter = new PrimeFilter();
int[]  a1 = { 123, 38,  103, 89 };
int[]  b1 = { 34, 8,  11, 29 };

filter.put (a1);
filter.put (b1);
int[] numbers = filter.values();

 

小结一下,所谓的对象可以视为属性和方法的综合体,即:

对象 = 属性 + 方法

其中,属性就是数据,方法就是算法。创建一个对象、给它所需的数据、让它干活、取出结果,这就是一般的面向对象的设计方法。

8.4 特殊形式的属性

下面,再了解一种相对来说有点奇怪的写法。用Human表示人类,每个人类都应该有名字(name),有一个配偶(mate)。用代码表示如下,

public class Human
{
    public String name; // 名字
    public Human mate; // 配偶 (指向另外一个Human对象)
}

对于初学者来说,这种写法可能会有点奇怪:一个属性的类型可以是它的同类?

如果觉得奇怪的话,我们可以大胆的改一下,改成我们熟悉的形式,

public class Human
{
    public String name;
    public Monkey mate; // Monkey, 猴子
}

如此改动,在字面形式上我们会觉得很熟悉,对吧?但是,从逻辑上理解却是不合常理的,一个人类(Human)的配偶(mate)竟然是一个猴子?

一个Human的mate属性是另一个Human对象,才是符合逻辑的,也是非常自然的。虽然语法形式上大家会觉得有点生疏,但看多了就习惯了。

下面,再添加一个方法merryWith(),表示与某个结婚,示例如下,

public class Human
{
    public String name; // 名字
    public Human mate; // 配偶 (指向另外一个Human对象)

    // 与另一人结婚
    public void merryWith ( Human someone)
    {
        this.mate = someone; // 我的伴侣是Ta
        someone.mate = this; // Ta的伴侣是我
    }

    // 自我介绍
    public void introduce()
    {
        System.out.println("我叫" + this.name + ", 我的爱人叫" + mate.name);
    }
}

在merryWith()的时候,需要指定另一个人类对象someone作为参数。同样的,如果不喜欢的话可以换成一只猴子!

下面再来看一下如何使用这个Human类,示例如下,

public class HelloWorld
{
    public static void main(String[] args)
    {
        Human a = new Human(); // 小张
        a.name = "张";

        Human b = new Human("王"); // 小王
        b.name = "王";

        a.merryWith( b );  // a与b结婚
        a.introduce();  // a自我介绍
        b.introduce();  // b自我介绍
    }
}

显然,要谈婚论嫁,必需得有两个人(a 和 b ),然后再调用a.merryWith(b) 使之结为夫妻。结论之后,再自我介绍(introduce)的时候就得把爱人的名字( mate.name) 也报一下了!

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿发你好

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值