0

我经常遇到将实例作为参数传递给函数的情况。我突然想到,同样可以转发对象的参数,并在方法内进行初始化。

例子:

class MyCanvas extends JComponent {

    private static final long serialVersionUID = 1L;

    private static ArrayList<String>    textData;
    private static ArrayList<Rectangle> rectData;

    @Override

    public void paintComponent(Graphics g) {

        if(g instanceof Graphics2D){

            //Draw the rectangles and text
        }
    }

    public void addText(int x, int y, String text){
        textData.add(text);
    }

    //Do this:
    public void addRect(Rectangle rect){
        rectData.add(rect);
    }

    //Or do this?
    public void addRect(int x, int y, int z,  int q){
        rectData.add(new Rectangle(x, y, z, q);
    }

}

在这种情况下,传递四个整数可以减少可变性。从理论上讲,应该减少错误表面积以及潜在的漏洞。

JVM 如何以不同的方式处理这两个示例?

是否真的不容易出错/易受攻击?

一个在性能方面会比另一个更有效吗?

注意:这不是关于设计偏好的问题。有多种方法可以包装或绑定参数,以使任一示例都灵活高效。我只想知道字节码级别的区别是什么,以及字节码级别是否明显更有效/更安全。

4

3 回答 3

1

请注意架构安全和语言安全之间的区别。事实上,大多数计算机科学教授都没有意识到这一点。

如果你想“安全地”传递一个对象,你可以在键盘上提示输入一个加密密钥;收集钥匙;加密对象;并通过它。然后接收函数可以重新提示并反转加密!这一切都取决于你想要完成什么。

对象的生命周期是最大的问题。一旦它被传递,参数值就位于堆栈上;如果我们假设一个观察者可以查看属于 JVM 的内存位置,那么我们就完蛋了。因此,一旦检索到该值,就用垃圾就地覆盖它。我们将此称为“对象重用”考虑,尽管我们通常在将对象释放回系统时牢记这一点:我们不会隐含地假设有人共享我们的地址空间并不断地在这里偷看和戳那里。

于 2016-07-13T15:52:43.110 回答
1

一开始你有 4 个整数,最后需要一个 Rectangle。这一切都归结为验证输入并进行转换的责任。

虽然这个特定示例非常简单,但您可以通过添加以下内容使其更有趣:

public void addRect(String rect){
  // e.g. rect = "4 2 3 7"
}  

public void addRect(int[] rect){
  // e.g. rect = [4 2 3 7]
}      

// etc...

在这种情况下,可以说调用者不应该关心矩形是如何构造的,这就是MyCanvas类 的事情

于 2016-07-13T17:40:35.923 回答
1

从 API 设计的角度来看,传递 a Rectangle(或 a Shape)更好。它支持对接口进行编码,而不是对实现进行编码。从某种意义上说,指定角点和尺寸是一种实现;不同的实现将指定对角。通过传递一个形状,您可以使您的代码更具适应性。

这里的主要问题是由于Rectangle. 对此有效率论据,但我想知道Shape如果它是今天设计的,是否会是可变的。对于许多应用程序,不可变数据类型提供了许多好处,更安全的数据共享就是其中之一。

由于您正在实施MyCanvas,因此您可以让自己确信该Rectangle实例没有被修改,因此是“安全的”。但是,如果其他人正在编写调用者,并且MyCanvas是他们无法完全信任的黑匣子,则有两件事可以提供帮助。

首先,您可以记录MyCanvas接受形状的方法,指定不修改形状。在 Java 中,这个规范应该放在方法和类的Javadoc 注释中。这是一种常见的做法;除非您正在编写一个可能执行由不值得信任的作者编写的代理的插件系统,否则程序员通常会在 API 中依赖此承诺或合同。

其次,如果调用者没有这种保证,他们可以将“他们的”Rectangle实例复制到临时副本,然后将副本传递给您。因为他们Rectangle在方法返回后从不读取状态,所以你对它做什么并不重要。因为Rectangle是可变的,所以这可以相当有效地完成。


从字节码的角度来看,传递Rectangle速度更快。为每个传递的参数执行单独的指令。更多参数,更多指令。此外,传递Rectangle允许调用者的实例被重用,而传递原始元素需要分配一个Rectangle可能不必要的新元素。

我不知道你在说什么,“在这种情况下,传递四个整数会减少可变性。从理论上讲,应该减少错误表面积以及潜在的漏洞。”

我确实知道,在现实世界中,具有多个相同类型参数(如四个int参数)的方法非常容易出错。将它们命名为无稽之谈qz会使这个问题变得更糟。通过在编译时消除错误,利用参数的强类型使您的程序更安全。

于 2016-07-13T16:15:45.993 回答