Java中是否存在运算符重载?

时间:2011-11-03 23:27:40

标签: java operator-overloading

我只想知道Java中的一个简单的事情。让我们考虑Java中的以下代码段。

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

在Java中完全有效并产生输出,x = 10作为字符串。


虽然变量x的类型为 int ,但它会自动转换为String类型(包装类型)。 Java如何做到这一点?像C ++和C#一样,运算符重载在某种程度上或某处存在于Java中,尽管它已从Java中删除。 此处使用哪个特定概念将x转换为字符串。我唯一想知道的事情


还有一个问题,在Java中,布尔数据类型(不是布尔值,包装类)不能转换为任何其他类型(根据我所知)。为什么会这样,在某些非常特殊的情况下,将它转换为字符串或其他类型可能会有用。

3 个答案:

答案 0 :(得分:9)

编译器在内部将该短语(“x =”+ x)转换为StringBuilder,并使用.append(int)将整数“添加”到字符串中。

为了超越实际的“Java如何做到这一点”,我将接受斯蒂芬的建议并给出理论。从概念上讲,串联中的每个值首先转换为String,然后连接。空值连接为单词“null”。

来自Java Language Specification

  

15.18.1.1字符串转换

     

任何类型都可以通过字符串转换转换为String类型。一个值   原始类型T的x首先被转换为参考值,如同   将它作为适当的类实例创建的参数   表达式:

     

如果T是布尔值,则使用new Boolean(x)。如果T是char,那么使用new   字符(X)。如果T是byte,short或int,则使用new Integer(x)。如果   T很长,然后使用新的Long(x)。如果T是float,则使用new Float(x)。   如果T为double,则使用new Double(x)。那么这个参考值   通过字符串转换转换为String类型。现在只参考   需要考虑价值观。如果引用为null,则为   转换为字符串“null”(四个ASCII字符n,u,l,l)。   否则,转换就像通过调用一样执行   没有参数的引用对象的toString方法;但如果   调用toString方法的结果为null,则字符串为“null”   而是用来代替。

     

toString方法由原始类Object定义;许多   类覆盖它,特别是布尔,字符,整数,长,浮点数,   Double和String。

     

15.18.1.2字符串连接的优化

     

实现可以选择执行转换和连接   在一步中避免创建然后丢弃中间体   字符串对象。增加重复字符串的性能   连接,Java编译器可以使用StringBuffer类或a   类似的技术减少了中间String对象的数量   通过评估表达式创建的。对于原始类型,   实现还可以优化包装器的创建   对象通过直接从基本类型转换为字符串。

优化版本实际上不会首先执行完全包装的String转换。

这是编译器使用的优化版本的一个很好的例证,虽然没有原语的转换,你可以看到编译器在后台将事物更改为StringBuilder:

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

这个java代码:

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

生成这个 - 看看两个连接样式如何导致相同的字节码:

 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

编译器已将“cip + ciop”转换为“new StringBuilder(cip).append(ciop).toString()”。换句话说,“+”实际上是更冗长的StringBuilder习语的简写。

答案 1 :(得分:1)

Java确实支持有限运算符重载...对于具有某些(基本)操作数类型组合的内置运算符。主要案例是:

  • 算术运算符对不同的数字基元类型具有重载。除了字符串连接外,还会重载“+”运算符。

  • '&amp;','|','^'和'!'运算符因(非短路)逻辑和按位积分运算而过载。

但是,Java 不支持支持任何形式的程序员定义的运算符或运算符重载。


说重载是“编译器魔术”或“编译器执行”的答案都缺少重点。 Java语言规范说它是语言的一部分,它意味着什么,并且(几乎)要求如何实现它。


正如另一个答案所指出的,自动装箱/拆箱和其他事情(严格来说)是转换而不是重载。例如:

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

这使用'+'运算符的(int, int)重载,并使用auto-unboxing将第二个操作数转换为int。

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

这使用'+'运算符的(int, int)重载,并使用强制转换将第二个操作数转换为int。

请注意,JLS指定了根据操作数的(初始)类型确定使用哪个运算符重载的规则。因此,在第二个示例中,JLS要求使用'{'的(int, int)重载,而不是(byte, byte)重载。

答案 2 :(得分:0)

这都是编译魔术。你不能用Java做运算符重载。

穿过手指,希望这不是可怕的错误,让我得到20个downvotes