方法重载和原始类型如何工作?

How method-overloading and primitive types works?

我正在做 Java class 练习。我有这段代码,其中包含一个重载方法:

class A {

    // Overloaded method
    public void f(int n, float x) {
        System.out.println("f(int n, float x) n = " + n + " x = " + x);
    }

    private void f(long q, double y) {
        System.out.println("f(long q, double y) q = " + q + " y = " + y);
    }

    public void f(double y1, double y2) {
        System.out.println("f(double y1, double y2) y1 = " + y1 + " y2 = " + y2);
    }

    public void g() {
        int n = 1;
        long q = 12;
        float x = 1.5f;
        double y = 2.5;
        System.out.println("--- dans g ");
        f(n, q);
        f(q, n);
        f(n, x);
        f(n, y);
    }
}

主要:

public static void main(String[] args){ 
    A a = new A() ;
    a.g() ;
    System.out.println ("--- dans main") ;
    int n=1 ; 
    long q=12 ; 
    float x=1.5f ; 
    double y = 2.5 ;

    a.f(n, q) ; // my problem is here
    a.f(q, n) ; 
    a.f(n, x) ; 
    a.f(n, y) ;  
}

当我在 main 中调用方法 a.f(n,q) 时,我预计会出现错误,但它会调用方法 f(int n, float x) 而我的 q 是一个 long 数字,它的大小大于 float 的大小(8 字节/4 字节)所以我想知道这些基本类型是如何工作的?

longs 可以转换为 float 而不会引发错误。但是你可能会失去精度。

详情见the specs

Method invocations 占据了规范的很大一部分。总而言之,编译器按如下方式进行:

  1. 确定可能调用该方法的 classes。
  2. 确定那些 class 可能被调用的方法。
  3. 如果确定了不止一种方法,请选择最具体的一种。

第 2 步是这里最有趣的一步:它分为多个步骤。总结:

  1. 如果 class 上有一个具有完全相同参数类型(严格调用)的非可变参数方法,请选择该方法。
  2. 如果 class 上有一个非可变参数方法,其参数类型可以从实际参数自动转换(松散调用),请选择该方法。
  3. 如果 class 上有可变参数方法,其参数类型与自动转换相匹配,请选择它。

您提供的参数与重载的任何参数类型都不完全匹配,因此您需要检查是否可以转换该参数以允许严格调用。严格调用中的转换 are:

  • an identity conversion (§5.1.1)
  • a widening primitive conversion (§5.1.2)
  • a widening reference conversion (§5.1.5)

一个int可以通过身份转换转换为intlong 可以通过 widening primitive conversion 转换为 float.

因此f(int, float)适用。

f(long, double)f(double, double)也适用,因为int可以扩大到longdoublelong 可以扩大到 double.

但是,这些没有 f(int, float) 具体,因为 int 可以扩大到 longdouble,并且 float 可以扩大到double。因此,根据 informal intuition laid out in JLS Sec 15.12.2.5,这些方法不如 f(int, float) 具体。因此,f(int, float) 是被调用的。

以下 19 种原始类型的特定转换称为扩展原始类型转换:

byte 到 short、int、long、float 或 double

short 到 int、long、float 或 double

char 到 int、long、float 或 double

int 到 long、float 或 double

长到浮动或加倍

浮动到两倍

扩大基元转换不会丢失有关数值总体大小的信息。

...

将 int 或 long 值转换为 float,或将 long 值转换为 double,可能会导致精度损失 - 也就是说,结果可能会丢失该值的一些最低有效位。在这种情况下,生成的浮点值将是 long 值的正确舍入版本。