Operator Overloading in Java

Why doesn't Java offer operator overloading?

Assuming you wanted to overwrite the previous value of the object referred to by a, then a member function would have to be invoked.

Complex a, b, c;
// ...
a = b.add(c);

In C++, this expression tells the compiler to create three (3) objects on the stack, perform addition, and copy the resultant value from the temporary object into the existing object a.

However, in Java, operator= doesn't perform value copy for reference types, and users can only create new reference types, not value types. So for a user-defined type named Complex, assignment means to copy a reference to an existing value.

Consider instead:

b.set(1, 0); // initialize to real number '1'
a = b;
b.set(2, 0);
assert( !a.equals(b) ); // this assertion will fail

In C++, this copies the value, so the comparison will result not-equal. In Java, operator= performs reference copy, so a and b are now referring to the same value. As a result, the comparison will produce 'equal', since the object will compare equal to itself.

The difference between copies and references only adds to the confusion of operator overloading. As @Sebastian mentioned, Java and C# both have to deal with value and reference equality separately -- operator+ would likely deal with values and objects, but operator= is already implemented to deal with references.

In C++, you should only be dealing with one kind of comparison at a time, so it can be less confusing. For example, on Complex, operator= and operator== are both working on values -- copying values and comparing values respectively.

Operator overloading in Java

No, Java doesn't support user-defined operator overloading. The only aspect of Java which comes close to "custom" operator overloading is the handling of + for strings, which either results in compile-time concatenation of constants or execution-time concatenation using StringBuilder/StringBuffer. You can't define your own operators which act in the same way though.

For a Java-like (and JVM-based) language which does support operator overloading, you could look at Kotlin or Groovy. Alternatively, you might find luck with a Java compiler plugin solution.

Java, operator overloading and + operator for String

This operator is not "overloaded", it is pre-defined operator, called String Concatenation Operator.

15.18.1 String Concatenation Operator +

If only one operand expression is of type String, then string conversion (§5.1.11) is performed on the other operand to produce a string at run time.
The result of string concatenation is a reference to a String object that is the
concatenation of the two operand strings. The characters of the left-hand operand
precede the characters of the right-hand operand in the newly created string.

In other words, when Java sees

String res = stringObj + someObj;

it replaces the expression with code that constructs the resulting string by concatenating an existing string value with someObj.toString().

Java equivalent for C++ operator overloading

There is no operator overloading in Java as in C/C++ world, so the + operator is used, let's say only, for primitive numbers (byte, short, int, long, float and double) incremental operations.

This saying you should not complain or get surprised when you find a special case where the + operator is overloaded when it comes to the String Class.

String s1 = "Hello ";
String s2 = "World";
String helloWorld = s1 + s2;

Look at the last line in above code, it is totally legal and will result on a concatenated String and the compiler will never complain about it. Remember that this is the one and only exception.

So instead of overloading some operators, you can seamlessly implement a method that handles your addition stuff:

public class Complex 
{
private double x;
private double y;

public Complex(double x , double y)
{
this.x = x;
this.y = y;
}

public Complex add (Complex c)
{
Complex sum = new Complex();
sum.x = this.x + c.x;
sum.y = this.y + c.y;
return sum;
}

}

public static void main(String args[])
{
Complex p1 = new Complex(1 , 2);
Complex p2 = new Complex(3 , 4);
Complex p3 = p2.add(p1);
}

Does operator overloading exist in Java?

The compiler converts that phrase ("x = "+x) into a StringBuilder internally and uses .append(int) to "add" the integer to the string.

To go beyond the practical "how does Java do this", I'll take the advice of Stephen and give the theoretical as well. Conceptually, each value in the concatenation is first converted to a String and then concatenated. Nulls are concatenated as the word "null".

From the Java Language Specification:

15.18.1.1 String Conversion

Any type may be converted to type String by string conversion. A value
x of primitive type T is first converted to a reference value as if by
giving it as an argument to an appropriate class instance creation
expression:

If T is boolean, then use new Boolean(x). If T is char, then use new
Character(x). If T is byte, short, or int, then use new Integer(x). If
T is long, then use new Long(x). If T is float, then use new Float(x).
If T is double, then use new Double(x). This reference value is then
converted to type String by string conversion. Now only reference
values need to be considered. If the reference is null, it is
converted to the string "null" (four ASCII characters n, u, l, l).
Otherwise, the conversion is performed as if by an invocation of the
toString method of the referenced object with no arguments; but if the
result of invoking the toString method is null, then the string "null"
is used instead.

The toString method is defined by the primordial class Object; many
classes override it, notably Boolean, Character, Integer, Long, Float,
Double, and String.

15.18.1.2 Optimization of String Concatenation

An implementation may choose to perform conversion and concatenation
in one step to avoid creating and then discarding an intermediate
String object. To increase the performance of repeated string
concatenation, a Java compiler may use the StringBuffer class or a
similar technique to reduce the number of intermediate String objects
that are created by evaluation of an expression. For primitive types,
an implementation may also optimize away the creation of a wrapper
object by converting directly from a primitive type to a string.

The optimized version will not actually do a full wrapped String conversion first.

This is a good illustration of an optimized version used by the compiler, albeit without the conversion of a primitive, where you can see the compiler changing things into a StringBuilder in the background:

http://caprazzi.net/posts/java-bytecode-string-concatenation-and-stringbuilder/

This java code:

public static void main(String[] args) {
String cip = "cip";
String ciop = "ciop";
String plus = cip + ciop;
String build = new StringBuilder(cip).append(ciop).toString();
}

Generates this - see how the two concatenation styles lead to the very same bytecode:

 L0
LINENUMBER 23 L0
LDC "cip"
ASTORE 1
L1
LINENUMBER 24 L1
LDC "ciop"
ASTORE 2
// cip + ciop
L2
LINENUMBER 25 L2

NEW java/lang/StringBuilder
DUP
ALOAD 1
INVOKESTATIC java/lang/String.valueOf(Ljava/lang/Object;)Ljava/lang/String;
INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
ALOAD 2
INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;

ASTORE 3
// new StringBuilder(cip).append(ciop).toString()
L3
LINENUMBER 26 L3

NEW java/lang/StringBuilder
DUP
ALOAD 1
INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
ALOAD 2
INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;

ASTORE 4
L4
LINENUMBER 27 L4
RETURN

The compiler has transformed "cip+ciop" into "new StringBuilder(cip).append(ciop).toString()". In other words, "+" is effectively a shorthand for the more verbose StringBuilder idiom.

Why doesn't Java need Operator Overloading?

Java only allows arithmetic operations on elementary numeric types. It's a mixed blessing, because although it's convenient to define operators on other types (like complex numbers, vectors etc), there are always implementation-dependent idiosyncrasies. So operators don't always do what you expect them to do. By avoiding operator overloading, it's more transparent which function is called when. A wise design move in some people's eyes.

Confusion of Operator Overloading in java

A language is said to support operator overloading when you can overload operators, i.e. make them do something that is not built into the language. Not when the langauge uses the same operator for two different things.

Operator overloading in Java

== for reference types compares the references; == for primitive types compares values. In case of your first example, the two object references turn out to be the same due to a concept known as string pool. Hence two true in the given case. Another code snippet you might want to try out:

String s1 = "abc";
String s2 = new String("abc");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));

As you must have already tried out; it prints out false and then true. The reason for this is that using the new keyword results in the creation of a completely new string even though a string object with the exact same contents already exists in the string pool. In this case, s1 now points to an interned string with the contents "abc" (or to a string in the string pool) whereas s2 now points to a completely new string object (again with the content "abc"). Hence the false in the first print statement.

In the second print statement, what we are doing is comparing the contents of the String object rather than its reference, which as it should prints true.

This is one of the most common mistakes made by beginners of the Java language; they use == for logical comparison when it actually results in a reference comparison. Read the link posted in one of the answers here for more details about string pooling. On a related note, String class "overrides" the equals method of the Object class to provide a logical comparison. Unless the class you write doesn't provide a logical implementation of the equals method, it doesn't matter whether you call equals or use the == operator; the result would be the same i.e. reference comparison.

For a more in-depth view on equality, read Brian's article; an excellent read.



Related Topics



Leave a reply



Submit