Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Parasoft Jtest 2022.2

Method and constructor overloading allows declaration of methods or constructors with the same name but with different parameter lists. The compiler inspects each call to an overloaded method or constructor and uses the declared types of the method parameters to decide which method to invoke. In some cases, however, confusion may arise because of the presence of relatively new language features such as autoboxing and generics.

Furthermore, methods or constructors with the same parameter types that differ only in their declaration order are typically not flagged by Java compilers. Errors can result when a developer fails to consult the documentation at each use of a method or constructor. A related pitfall is to associate different semantics with each of the overloaded methods or constructors. Defining different semantics sometimes necessitates different orderings of the same method parameters, creating a vicious circle. Consider, for example, an overloaded getDistance() method in which one overloaded method returns the distance traveled from the source while another (with reordered parameters) returns the remaining distance to the destination. Implementers may fail to realize the difference unless they consult the documentation at each use.

Noncompliant Code Example (Constructor)

Constructors cannot be overridden and can only be overloaded. This noncompliant code example shows the class Con with three overloaded constructors:

Code Block
bgColor#FFCCCC
class Con {
  public Con(int i, String s) { 
    // Initialization Sequence #1
  }
  public Con(String s, int i) {
    // Initialization Sequence #2 
  } 
  public Con(Integer i, String s) {
    // Initialization Sequence #3 
  } 
}

Failure to exercise caution while passing arguments to these constructors can create confusion because calls to these constructors contain the same number of similarly typed actual parameters. Overloading must also be avoided when the overloaded constructors or methods provide distinct semantics for formal parameters of the same types, differing solely in their declaration order.

Compliant Solution (Constructor)

This compliant solution avoids overloading by declaring public static factory methods having distinct names in place of the public class constructors:

Code Block
bgColor#ccccff
public static Con createCon1(int i, String s) { 
  /* Initialization Sequence #1 */
}
public static Con createCon2(String s, int i) { 
  /* Initialization Sequence #2 */
}
public static Con createCon3(Integer i, String s) {
  /* Initialization Sequence #3 */
}

Noncompliant Code Example (Method)

In this noncompliant code example, the OverLoader class holds a HashMap instance and has overloaded getData() methods. One getData() method chooses the record to return on the basis of its key value in the map; the other chooses on the basis of the actual mapped value. 

Code Block
bgColor#FFCCCC
class OverLoader extends HashMap<Integer,Integer> {
  HashMap<Integer,Integer> hm;
  public OverLoader(

Unlike method overriding, in method overloading the choice of which method to invoke is determined at compile time. Even if the runtime type differs for each invocation, in overloading, the method invocations depend on the type of the object at compile time.

Noncompliant Code Example

Wiki Markup
This noncompliant example shows how the programmer can confuse overloading with overriding. At compile time, the type of the object array is {{Collection}}. The messages that one would typically expect are {{Set invoked}}, {{ArrayList invoked}} and {{Collection is not recognized}}. However, in all three instances {{Collection is not recognized}} gets displayed. This is because in overloading, the method invocations are not affected by the runtime types but only the compile time type ({{Collection}}). It is dangerous to implement overloading to tally with overriding, more so, because the latter is characterized by inheritance unlike the former. \[[Bloch 08|AA. Java References#Bloch 08]\]

Code Block
bgColor#FFCCCC

public class Overloader {
  private static String display(Set<Integer> s) {
    returnhm "Set invoked";
  }
= new HashMap<Integer, Integer>();
  private static String display(ArrayList<String> l) {// SSN records
    return "ArrayList invoked" hm.put(1, 111990000);
  }

  private static String display(Collection<?> c) {hm.put(2, 222990000);
    return "Collection is not recognized";hm.put(3, 333990000);	  
  }

  public staticString void main(String[] argsgetData(Integer i) { // Overloading sequence #1
    Collection<?>[] invokeAll = new Collection<?>[] {new HashSet<Integer>(), String s = get(i).toString(); // Get a particular record
    new ArrayList<String>(), new TreeSet<Integer>()};

    for(Collection<?> i : invokeAll) {
return (s.substring(0, 3) + "-" + s.substring(3, 5) + "-" + 
            Systems.out.println(display(isubstring(5, 9));
	    }
  }
}

Compliant Solution

...

 

...

 

...

public 

...

Integer 

...

Code Block
bgColor#ccccff

class Overloader {
  private static String display(Collection<?> cgetData(int i) { // Overloading sequence #2
    return hm.get(i); // Get record at position 'i'
  }
  // Checks whether the ssn exists
  @Override public Integer get(Object data) {
    // SecurityManagerCheck()

    for (Map.Entry<Integer, Integer> entry : hm.entrySet()) {
      if(entry.getValue().equals(data)) {
        return entry.getValue(c); instanceof Set// ?Exists "Set
 invoked" : (c instanceof ArrayList ? "ArrayList invoked"
 }
    }
 : "Collection is not recognized"))return null;
  }

  public static void main(String[] args) {
    Collection<?>[] invokeAllOverLoader bo = new Collection<?>[] {new HashSet<Integer>(), new ArrayList<String>(), new TreeSet<Integer>OverLoader()};

     for(Collection<?> i : invokeAll) {
    // Get record at index '3'
    System.out.println(displaybo.getData(i3));
    }//Get record containing data '111990000'
    System.out.println(bo.getData((Integer)111990000));
  }
}

Notably, constructors cannot be overridden and can only be overloaded. Exercise caution while passing arguments to them.

Risk Assessment

For purposes of overload resolution, the signatures of the getData() methods differ only in the static type of their formal parameters. The OverLoader class inherits from java.util.HashMap and overrides its get() method to provide the checking functionality. This implementation can be extremely confusing to the client who expects both getData() methods to behave in a similar fashion and not depend on whether an index of the record or the value to be retrieved is specified.

Although the client programmer might eventually deduce such behavior, other cases, such as with the List interface, may go unnoticed, as Joshua Bloch [Bloch 2008] describes:

The List<E> interface has two overloadings of the remove method: remove(E) and remove(int). Prior to release 1.5 when it was "generified," the List interface had a remove(Object) method in place of remove(E), and the corresponding parameter types, Object and int, were radically different. But in the presence of generics and autoboxing, the two parameter types are no longer radically different.

Consequently, a client programmer may fail to realize that the wrong element has been removed from the list.

A further problem is that in the presence of autoboxing, adding a new overloaded method definition can break previously working client code. This can happen when a new overloaded method with a more specific type is added to an API whose methods used less specific types in earlier versions. For example, if an earlier version of the OverLoader class provided only the getData(Integer) method, the client could correctly invoke this method by passing a parameter of type int; the result would be selected on the basis of its value because the int parameter would be autoboxed to Integer. Subsequently, when the getData(int) method is added, the compiler resolves all calls whose parameter is of type int to invoke the new getData(int) method, thereby changing their semantics and potentially breaking previously correct code. The compiler is entirely correct in such cases; the actual problem is an incompatible change to the API.

Compliant Solution (Method)

Naming the two related methods differently eliminates both the overloading and the confusion.

Code Block
bgColor#ccccff
public Integer getDataByIndex(int i) { 
  // No longer overloaded
}

public String getDataByValue(Integer i) {
  // No longer overloaded 
}

Applicability

Ambiguous or confusing Ambiguous uses of overloading can lead to unexpected results.

...

Automated Detection

Severity Tool Likelihood Version Remediation Cost Checker Priority Description

Level

MET02-J

low

unlikely

high

P1

L3

Automated Detection

TODO

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

Wiki Markup
\[[API 06|AA. Java References#API 06]\] [Interface Collection|http://java.sun.com/j2se/1.4.2/docs/api/java/util/Collection.html]
\[[Bloch 08|AA. Java References#Bloch 08]\] Item 41: Use overloading judiciously

Parasoft Jtest
Include Page
Parasoft_V
Parasoft_V
CERT.MET50.OVERLOADUse overloading judiciously

Bibliography

[API 2013]Interface Collection<E>
[Bloch 2008]Item 41, "Use Overloading Judiciously"


...

Image Added Image Added Image AddedMET01-J. Follow good design principles while defining methods      09. Methods (MET)      MET03-J. For methods that return an array or collection prefer returning an empty array or collection over a null value