繁体   English   中英

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

[英]Does operator overloading exist in Java?

我只想知道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中,布尔数据类型(不是布尔值,包装类)不能转换为任何其他类型(根据我所知)。 为什么会这样,在某些非常特殊的情况下,将它转换为字符串或其他类型可能会有用。

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

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

Java语言规范

15.18.1.1字符串转换

可以通过字符串转换将任何类型转换为String类型。 首先将基本类型T的值x转换为引用值,就像将其作为参数提供给适当的类实例创建表达式一样:

如果T是布尔值,则使用new Boolean(x)。 如果T是char,则使用new Character(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定义; 许多类都覆盖它,特别是Boolean,Character,Integer,Long,Float,Double和String。

15.18.1.2字符串连接的优化

实现可以选择在一个步骤中执行转换和连接,以避免创建然后丢弃中间String对象。 为了提高重复字符串连接的性能,Java编译器可以使用StringBuffer类或类似技术来减少通过表达式求值创建的中间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习语的简写。

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

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

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

但是,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)重载。

这都是编译器的魔力。 您无法在Java中执行运算符重载。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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