简体   繁体   中英

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?

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. 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. 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 . There are efficiency arguments for this, but I wonder if Shape would be mutable if it were designed today. 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." 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.

First, you can document the MyCanvas methods that accept a shape, specifying that the shapes are not modified. In Java, this specification should be placed in Javadoc comments on methods and classes. 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.

Second, if the caller doesn't have that assurance, they can copy "their" Rectangle instance to a temporary copy, and pass you the copy. Because they never read the state of the Rectangle after the method returns, it doesn't matter what you do to it. Because Rectangle is mutable, this can be done fairly efficiently.


From a byte code perspective, passing the Rectangle is faster. 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.

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. Naming them nonsense like q and z makes that problem even worse. 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. 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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