Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does operator overloading exist in Java?

I just want to know one simple thing in Java. Let's consider the following segment of code In Java.

int x=10;
String temp="x = "+x;
System.out.println(temp);

is perfectly valid in Java and produces the output, x = 10 as a string.


Although, the variable x is of type int, it is automatically converted to a String type (a wrapper type). How does Java do this? Does operator overloading somewhat or somewhere exist in Java like the one above as with C++ and C#?, though it was removed from Java. Which specific concept is used here to convert x into a string. The only thing I want to know


and also, one more question, in Java a boolean data type (not Boolean, a wrapper class), can not be converted to any other type (as per I'm knowing). Why is it so, in some very specific situations , it may useful to convert it to a string or some other types.

like image 472
Bhavesh Avatar asked Dec 27 '22 11:12

Bhavesh


2 Answers

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.

like image 178
Scott A Avatar answered Dec 29 '22 23:12

Scott A


Java does support limited operator overloading ... for built-in operators with certain combinations of (primitive) operand types. The main cases are:

  • The arithmetic operators have overloads for different numeric primitive types. The '+' operator is additionally overloaded for string concatenation.

  • The '&', '|', '^' and '!' operators are overloaded for (non-short-circuit) logical and bitwise integral operations.

However, Java does not support any form of programmer-defined operators or operator overloading.


Answers that say overloading is "compiler magic" or that "the compiler does it" are missing the point. The Java language specification says that it is part of the language, what it means, and (pretty much) mandates how it should be implemented.


As another answer points out, auto-boxing / unboxing and other things are (strictly speaking) conversions and not overloading. So for example:

int j = ...
Integer i = ...
j = j + i;

This uses the (int, int) overload of the '+' operator, and uses auto-unboxing to convert the 2nd operand to an int.

byte b = ...
j = j + b;

This uses the (int, int) overload of the '+' operator, and uses an cast to convert the 2nd operand to an int.

Note that the JLS specifies the rules that determine which operator overload is used based on the (initial) types of the operands. So, in the 2nd example, the JLS mandates that the (int, int) overload of '+' is used, not the (byte, byte) overload.

like image 45
Stephen C Avatar answered Dec 29 '22 23:12

Stephen C