简体   繁体   English

将实例传递给方法Vs。 转发参数

[英]Passing an instance to a method Vs. forwarding parameters

I often encounter situations where I pass instances as parameters to functions. 我经常遇到将实例作为参数传递给函数的情况。 It occurred to me that it is equally possible to forward the parameters of the object instead, and initialize within the method. 在我看来,同样可以转发对象的参数,然后在方法中进行初始化。

Example: 例:

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);
    }

}

Passing four integers, in this case, reduces the variability. 在这种情况下,传递四个整数会减少可变性。 Theoretically speaking, the error surface area should be reduced along with the potential for vulnerabilities. 从理论上讲,应减少错误的表面积以及潜在的漏洞。

How does the JVM handle these two examples differently? JVM如何不同地处理这两个示例?

Is one truly less error/vulnerability prone? 难道没有那么多的错误/漏洞吗?

Will one be more efficient than the other in terms of performance? 就性能而言,一个会比另一个更高效吗?

Note: This is not a question about design preference. 注意:这不是有关设计偏好的问题。 There are multiple ways wrap or bind parameters in such a way that either example would be flexible and efficient. 有多种方式包装或绑定参数,以使任一示例都灵活高效。 All I want to know is what the difference is on the byte code level, and whether or not one is distinctly more efficient/secure at the bytecode level. 我只想知道字节码级别有什么区别,以及在字节码级别上是否明显更有效/更安全。

Be alert to the distinction between architectural security and linguistic security. 注意架构安全性和语言安全性之间的区别。 Most computer science professors are not, in fact, aware thereof. 实际上,大多数计算机科学教授都不知道这一点。

If you want to "securely" pass an object, you could prompt at the keyboard for an encryption key; 如果要“安全地”传递对象,可以在键盘上提示输入加密密钥; collect the key; 收集钥匙; encrypt the object; 加密对象; and pass it. 并通过它。 The receiving function could then re-prompt and reverse the encryption! 然后,接收功能可以重新提示并逆转加密! It all depends what you're trying to accomplish. 这完全取决于您要完成的工作。

The lifetime of the object is the biggest concern. 对象的寿命是最大的问题。 Once it has been passed, the parameter value sits on the stack; 一旦传递,参数值就位于堆栈上; if we postulate an observer that can view memory locations belonging to the JVM, then we're hosed. 如果我们假设一个可以查看属于JVM的内存位置的观察者,那么我们就被束之高阁。 So, once the value has been retrieved, overwrite it in situ with garbage. 因此,一旦检索到值,就用垃圾原位覆盖它。 We call this an "object reuse" consideration, although we typically bear it in mind when freeing objects back to the system: we don't implicitly assume some guy sharing our address space and continually peeking here and poking there. 尽管通常在将对象释放回系统时会牢记这一点,但我们仍将其称为“对象重用”考虑:我们不暗中假设有人共享我们的地址空间并不断在这里偷看并戳戳。

From an API design perspective, passing a Rectangle (or a Shape ) is better. 从API设计的角度来看,传递Rectangle (或Shape )更好。 It supports coding to an interface, not an implementation. 它支持编码到接口,而不是实现。 In one sense, specifying a corner and dimensions is an implementation; 从某种意义上说,指定拐角和尺寸是一种实现。 a different implementation would specify opposite corners. 不同的实现将指定相反的角。 By passing a shape, you make your code more adaptable. 通过传递形状,可以使代码更具适应性。

The main problem here is due to the mutability of Rectangle . 这里的主要问题是由于Rectangle的可变性。 There are efficiency arguments for this, but I wonder if Shape would be mutable if it were designed today. 有效率方面的争论,但是我想知道,如果今天设计Shape话,它是否会变得可变。 For many applications, immutable data types provide many benefits, and safer sharing of data is one of them. 对于许多应用程序而言,不可变的数据类型提供了许多好处,其中更安全的数据共享就是其中之一。

Since you are implementing MyCanvas , you can satisfy yourself that the Rectangle instance is not modified, and is therefore "secure." 由于您正在实现MyCanvas ,因此您可以确信Rectangle实例没有被修改,因此是“安全的”。 However, if someone else is writing the caller, and MyCanvas is a black box they can't fully trust, there are two things that can help. 但是,如果其他人正在编写呼叫者,而MyCanvas是他们无法完全信任的黑匣子,则有两点可以帮助您。

First, you can document the MyCanvas methods that accept a shape, specifying that the shapes are not modified. 首先,您可以记录接受形状的MyCanvas方法,并指定不修改形状。 In Java, this specification should be placed in Javadoc comments on methods and classes. 在Java中,此规范应放在方法和类的Javadoc注释中 This is a common practice; 这是一种惯例。 unless you are writing a plugin system that might execute agents that are written by untrustworthy authors, programmers typically rely on this commitment, or contract, in an API. 除非您编写的插件系统可能执行由不可信作者编写的代理,否则程序员通常会依赖API中的此承诺或合同

Second, if the caller doesn't have that assurance, they can copy "their" Rectangle instance to a temporary copy, and pass you the copy. 其次,如果调用者没有保证,则可以将“其” Rectangle实例复制到临时副本,然后将副本传递给您。 Because they never read the state of the Rectangle after the method returns, it doesn't matter what you do to it. 因为在方法返回后,他们从不读取Rectangle的状态,所以对它执行什么操作都没有关系。 Because Rectangle is mutable, this can be done fairly efficiently. 由于Rectangle是可变的,因此可以相当有效地完成此操作。


From a byte code perspective, passing the Rectangle is faster. 从字节码的角度来看,通过Rectangle更快。 An separate instruction is executed for each parameter that is passed. 对于每个传递的参数,将执行单独的指令。 More parameters, more instructions. 更多参数,更多说明。 Also, passing the Rectangle allows the caller's instance to be re-used, while passing primitive elements requires allocation of a new Rectangle that might be unnecessary. 同样,传递Rectangle允许重新使用调用方的实例,而传递基本元素则需要分配可能不必要的新Rectangle

I don't know what you talking about when you say, "Passing four integers, in this case, reduces the variability. Theoretically speaking, the error surface area should be reduced along with the potential for vulnerabilities." 我不知道您在说什么:“在这种情况下,传递四个整数会减少可变性。从理论上讲,应减小错误表面积并减少潜在的漏洞。”

I do know that in the real, practical world, methods with multiple arguments of the same type, like four int parameters, are extremely error-prone. 我确实知道,在现实世界中,具有相同类型的多个参数(例如四个int参数)的方法极易出错。 Naming them nonsense like q and z makes that problem even worse. qz这样无意义地命名它们会使这个问题更加严重。 Taking advantage of strong typing for parameters makes your program safer by eliminating bugs at compile-time. 利用强大的参数类型输入功能,可以消除编译时的错误,从而使程序更安全。

In the beginning you have 4 ints and in the end a Rectangle is required. 开始时有4个整数,最后需要一个Rectangle。 It all boils down to whose responsibility it is to validate the input and make the conversion. 归结为验证输入并进行转换的责任。

While this particular example is very simple, you could make it more interesting by adding: 尽管这个特定示例非常简单,但是您可以通过添加以下内容使其更加有趣:

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...

in which case it can be argued that the caller should not care how the rectangles are constructed and that is the business of the MyCanvas class 在这种情况下,可以说调用者不应该在乎矩形的构造方式,这是MyCanvas类的MyCanvas

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM