依据个人实验经历浅谈java新建对象即新建地址以及如何保证成功查询对象

前言:本篇博客依据哈工大软件构造实验二棋牌游戏设计,笔者在文中只会简单提及题目而不做详细阐述,所以观看本篇博客的同学请自行查阅相关资料。

第一版

一开始我自以为耍了一个小聪明,用Map类型的board同时储存position和piece,那么piece就和position通过board联系起来,这样在我们下棋过程中如果需要改变piece的位置,那就直接改变position的位置就好了呀,而不用再涉及position里具体x,y的事了(哭~~,留下了弱鸡的眼泪)。
如果你和我的想法一样苍白,那么我就简单解释一下,为什么明明我们只需要改变piece的位置position,还需要以x,y为输入参数,通过x,y去改变position,而不是直接改变position。
我一开始在客户端调用下棋动作的代码如下:

Position mov_cur_position = new Position(mov_curX,mov_curY);
Position mov_tar_position = new Position(mov_tarX,mov_tarY);
game.do_move(currentplayer,mov_cur_position,mov_tar_position)

在game类中的do_move方法:

public boolean do_move(Player player,Position mov_cur_position,Position mov_tar_position)
action.movechesspiece(mov_cur_position,mov_tar_position)

在下棋动作类中具体实现move代码如下:

public boolean movechesspiece(Position mov_cur_position,Position mov_tar_position)
board.getpieceinboard(position);
board.putpieceinboard(mov_tar_position,piece);
board.removepieceinboard(mov_cur_position,piece);

发现了吗,一个错误导致步步错,使我的目标已经远离我的初心了。。。我每次再用户输入一个x,y值我都new一个position,从来不看新手上路指导的我以为只要依据position属性x,y创建的position那就一定是一个position。不是滴,java中每new一次产生一个新地址,你可以说x,y一样,那这个地址里存的position的相关属性是一样的,但这个position也不再是你之前创建的position,你可认为是克隆体。那么你用新的position去找旧的position,然后想根据map的自带方法去找到相关的piece,完全就是不对的,因为这个新建的position甚至都没有放在board上,(小声bb,这里你对新建的position操作就会出现java程序员经常遇见的死问题,nullpointerror,空指针异常)。
那么接下来我们要解决的问题就很明确了,如何使我一旦new完position后再也不new,代码全程无论操作什么都只用x,y去找到我一开始new的position,这样,就是一直在对我的初心position做操作,而没有第三者插足了。

第二版

在修改代码前,我特意去看了别人的实现,发现大部分人都用二维数组实现,那么就是一定是通过x,y去标识位置,移动piece的位置就一定是改变x,y,找到piece也一定是通过数组下标x,y,也就不存在position新建不新建的问题了。不过我并不打算放弃我的实现,数组太c了,根本没有map高级,更能体现java面向对象编程的特点,同时map提供了很多方法,就相当于帮助我们减去了很多实现的代码量,这难道不香吗,,
在客户端输入参数x,y,我们就用x,y去找那个对应的position。怎么做?就在类里写方法呀(不用担心你的代码量会增加多少,你用map而减少的代码量远远大于你为这点小破事而增加的代码量的),在board类里写如下方法:

public Piece ishaspiece(int x,int y){
    checkRep();
    for (Position temp:board.keySet()){       //x,y一定合要求,可以不验证x,y的范围
        if (temp.getX() == x && temp.getY() == y){
            Piece piececopy = board.get(temp);
            return piececopy;//immutable
        }
    }
    return null;
    }

为什么在board里写这个方法,从逻辑上我们是从position->piece,board可以它们二者的桥梁;从代码实现上,我们想用map的一系列keyset,get方法是不是得在board类里用,在别的类因为board类已经封装好了,我们是不可以访问到board的具体属性map的,只能用board里写好的方法,是调用不到map的方法的。
在操作动作实现类中代码如下:

Piece tar_piece = board.ishaspiece(targetX,targetY);
Piece cur_piece = board.ishaspiece(currentX,currentY);

通过这样的操作我们没有再new一次对象,我们没有新指向一个地址,我们所有的piece,position对象指向的都是我们最初new的那一个,那么你对position,piece的操作就可以保证一致性了。
在客户端我们需要改变position的属性x,y的值也不可以用新的x,y去创建新的一个position,再把新的position和piece联系起来,这简直太门外汉了。我们需要的是直接改变和piece相关position的属性,那就需要用到我们在position类里写到的改变属性的方法。

public void changeXY(int x,int y){
    X = x;
    Y = y;
    checkRep();
}

操作动作实现类中:

cur_piece.getPosition().changeXY(targetX,targetY);//在棋盘上重置初始棋子
tar_piece.getPosition().changeXY(-1,-1);从棋盘上移除目标棋子

这样子才是编程的思想,java面向对象编程的实现,而不是想当然的把现实生活的事情完全映射到代码世界里,那是有bug的。

小结

其实这一切原因归根结底是没有深刻理解java的面向对象编程,在不同类里实现对各种属性的操作方法,然后封装对象,隐藏属性,在其他类调用方法改变属性的值从而改变对象,而不是我们自以为的对象改变了,那么就是一个新的对象了,这太不计算机科学了,我们new的只是一个引用(地址),这个地址指向一个堆空间,这个堆空间就是"对象"。空间里的内容(属性)变了,这个对象就变了,所以改变对象的属性即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值