Java 使用新类向现有类添加功能,同时仍然公开先前类的所有方法

标签 java class this subclass extends

我想做类似 super() 的事情但没有将任何内容传递给构造函数。
就像复制当前状态的所有变量一样,这些变量被设置为该类内的方法。
我想避免做像 getPlayer() 这样的事情在包装类中,当包装类是带有额外方法的 Player 时。
我不想将这些额外的方法移至 Player 类中,因为它不是 Player 类的一部分,它是 Player 类可能会进入的东西,但并非总是如此。

我仍然希望能够使用它必须设置的自己的变量来运行 SpecialPlayer 的构造函数,同时仍将其作为我传递给它的任何实例的 Player 来维护。

Player类变量在转换为 SpecialPlayer 时可能随时更改。类和 SpecialPlayer类应该具有与 Player 相同的最新变量是的,从外观上看,它始终具有完全相同的引用。



这是我编写的一些伪代码,试图说明问题

public class Player {
    private int money;
    private boolean bar;

    public Player(int money) {
        this.money = money;
        bar = true;
    }

    public void toggleBar() {
        bar != bar;
    }
}

public class SpecialPlayer extends Player {
    private Player player;
    private long foo;

    public SpecialPlayer(Player player) {
    this.player = player; //wrapper way not good...
    //this = player; ??? doesn't compile...
    foo = System.currentTimeMillis();
    }

    public long getFoo() {
        return foo;
    }

    public Player getPlayer() { //<-- this is stupid.
        return player;
    }
}


Player player = new Player(12345);
player.toggleBar(); //it's now false, also it's not a constructor variable.

SpecialPlayer specialPlayer = new SpecialPlayer(player);
specialPlayer.getFoo(); //some long number value.
specialPlayer.toggleBar(); //now it should be true!.
player.toggleBar(); //should be false.
specialPlayer.toggleBar(); //should be true.

最佳答案

我认为您对继承的工作原理有点困惑

例如,下面代码的版本稍作修改

class Player {
    private int     money;
    private boolean bar;

    public Player() {} // I've added this guy, so your subclass is not forced to implement a similar constructor as Player(int money)

    public Player(int money) {
        this.money = money;
        bar = true;
    }

    public void setBar() {
    }
}

class SpecialPlayer extends Player {
    private long    foo;

    public long getFoo() {
        return foo;
    }
}

使用这种结构,例如执行以下操作是合法的

SpecialPlayer sp = new SpecialPlayer();
sp.getFoo(); //method specific to special player
sp.setBar(); //method inherited from Player

如果您希望 SpecialPlayer 成为 Player,则将 Player 包装在 SpecialPlayer 中是没有意义的。

更新:如何将现有播放器中的数据分配给特殊播放器

将类视为内存空间。例如

Object SpecialPlayer

[X] money
[X] bar
[X] foo

Object Player

[X] money
[X] bar
[ ] foo

所以很容易看出你可以做类似的事情

Player p = new SpecialPlayer()

因为 p 必须只知道“money”和“bar”的数据,尽管“foo”仍然存在,但从 p 的角度来看,它是无关紧要的,因为 p 只知道“money”和“bar”

当然,相反的情况是不正确的,因为

SpecialPlayer sp = p

将强制解释器解决为p分配字段“foo”的问题。这里有两种情况

  1. p 实际上是一个 SpecialPlayer,因此您可以像 sp = (SpecialPlayer)p 一样对其进行类型转换。解释器只会意识到 p 最初是作为 SpecialPlayer 创建的,然后某处有一个“foo”。
  2. p 不是一个 SpecialPlayer,而是一个纯粹的 Player。在这种情况下,解释器无法猜测“foo”必须具有什么值。在java中,没有办法让SpecialPlayer使用与Player相同的字段进行初始化,并假设“foo”为空。在这种情况下,您必须手动执行此分配,创建一个方法,例如

    public void valueOf(Player p){
        this.money = p.money;
        this.bar = p.bar;           
    }
    

当然,这可能是一个返回 SpecialPlayer 的静态方法,或者是您计划的构造函数。但问题是一样的。如何将“foo”分配给 SpecialPlayer。 java 解释器只是“更喜欢”不将其假定为 null(或任何其他默认值)并让开发人员实现它。

更新 #2 - 这里有一个很好的问题

为什么我不能(或不应该)将父类(super class)分配给子类,这样我就可以复制我需要的属性并假设其余属性为空?

例如

 Player p = new Player()
 p.setMoney(1)
 p.setBar(bar)

 SpecialPlayer sp = p

含义

 sp.setMoney(1)
 sp.setBar(bar)
 sb.setFoo(null)

嗯,在java中,当你将一个对象分配给另一个对象时,你实际上并没有将值从一个对象复制到另一个对象中。您只是创建一个链接。这就是为什么你可以分配

 SpecialPlayer sp = new SpecialPlayer()
 //set SpecialPlayer attributes
 Player p = sp
 SpecialPlayer sp2 = (SpecialPlayer)p;

不丢失任何信息。

如果我们复制这些值,上面的代码只会删除最后一行中“foo”的值,因为 Player 没有地方放置“foo”

这样好吗?或许。想象一下,如果将一个对象分配给另一个对象,我们执行类似所有值属性的“深层复制”之类的操作,会发生什么。

想象一下典型的持久实体,它们是许多倍复杂的对象图,有时非常深,有时带有循环。你会遇到很多内存问题。

关于Java 使用新类向现有类添加功能,同时仍然公开先前类的所有方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21948738/

相关文章:

java - JAVA-如何从for循环外部访问FOR循环内部的变量

class - 在Dart中,了解类是否已定义的最佳方法是什么?

带有 $(this) 的 jQuery 多重选择器

Javascript call() & apply() vs bind()?

c++ - 宏和函数中的“this”指针

java - 解码使用文件系统 API 创建的文件

java - 如何将状态添加到我的游戏中?

java - 如何验证struts2 Action 中表单的输入

ruby - ruby 类中的可继承属性

ruby-on-rails - 'has_one :through' association using namespaced classes