Java: разрешение во время компиляции и «самый специфический метод» в применении к переменной arity - PullRequest
4 голосов
/ 17 мая 2011

Может ли кто-нибудь помочь мне понять раздел 15.12.2.5 JLS re: самый специфический метод ?

(следует дубинка и паста из JLS)

Кроме того, один метод члена переменной арности с именем m более специфичен, чем другой метод члена переменной арности с тем же именем, если либо:

  • Один метод-член имеет n параметров, а другой - k параметров, где n> = k. Типы параметров первого метода-члена: T1,. , , , Tn-1, Tn [], типами параметров другого метода являются U1,. , , , Великобритания-1, Великобритания. Если второй метод является универсальным, тогда пусть R1 ... Rp p1, будут его параметрами формального типа, пусть Bl будет объявленной границей Rl, 1lp, пусть A1 ... Ap будет фактическими выведенными аргументами типа (§15.12.2.7) для этого вызова при начальных ограничениях Ti << Ui, 1ik-1, Ti << Uk, kin и пусть Si = Ui [R1 = A1, ..., Rp = Ap] 1ik; в противном случае пусть Si = Ui, 1ik. Затем: для всех j от 1 до k-1, Tj <: Sj, и, для всех j от k до n, Tj <: Sk, и, Если второй метод является общим методом, как описано выше, то Al <: Bl [R1 = A1, ..., Rp = Ap], 1lp. </li>
  • Один метод-член имеет k параметров, а другой - n параметров, где n> = k. Типы параметров первого метода: U1,. , , , Uk-1, Uk [], типами параметров другого метода являются T1,. , ., Tn-1, Tn []. Если второй метод является универсальным, тогда пусть R1 ... Rp p1, будут его параметрами формального типа, пусть Bl будет объявленной границей Rl, 1lp, пусть A1 ... Ap будет фактическими выведенными аргументами типа (§15.12.2.7) для этого вызова при начальных ограничениях Ui << Ti, 1ik-1, Uk << Ti, kin и пусть Si = Ti [R1 = A1, ..., Rp = Ap] 1in; в противном случае пусть Si = Ti, 1in. Затем: для всех j от 1 до k-1, Uj <: Sj, и, для всех j от k до n, Uk <: Sj, и, Если второй метод является общим методом, как описано выше, то Al <: Bl [R1 = A1, ..., Rp = Ap], 1lp. </li>

Игнорируя общие проблемы, означает ли это, что varargs важнее подтипов, или подтип более важен, чем varargs, когда принимается решение, является ли один метод более конкретным, чем другой? Я не могу понять это.

Конкретный пример: какой из следующих compute() методов является «более конкретным» в соответствии с JLS?

package com.example.test.reflect;

class JLS15Test
{
    int compute(Object o1, Object o2, Object... others) { return 1; }
    int compute(String s1, Object... others)            { return 2; }

    public static void main(String[] args) 
    {
        JLS15Test y = new JLS15Test();
        System.out.println(y.compute(y,y,y));
        System.out.println(y.compute("hi",y,y));
    }
}

Я не могу понять, что является "более конкретным"; на выходе печатает

1
2

Я запутался, как интерпретировать результаты. Когда первым аргументом был String, компилятор выбрал метод с более конкретным подтипом. Когда первым аргументом был Object, компилятор выбрал метод с меньшим количеством необязательных переменных.


ПРИМЕЧАНИЕ : Если вы не читаете этот раздел JLS и даете ответ, который зависит от типов аргументов , вы мне не помогаете. Если вы внимательно прочитаете JLS, кроме частей, относящихся к универсальным, определение «более конкретный» зависит от объявленных аргументов, а не от фактических аргументов - это вступает в действие в других частях JLS (не могу найти его в данный момент).

например. для методов фиксированной арности compute(String s) будет более конкретным, чем compute(Object o). Но я пытаюсь понять соответствующий раздел методов JLS re: variable arity.

Ответы [ 3 ]

5 голосов
/ 17 мая 2011
  1. int compute(String s1, Object... others) более конкретно при вызове compute("hi",y,y), поскольку String является подклассом Object.

  2. int compute(Object o1, Object o2, Object... others) является только соответствует compute(y,y,y), поскольку второй метод получает String в качестве первого параметра, а JLS15Test не является подклассом String

EDIT

Мой ответ основан на основах конкретных методов, но ваш код компилируется только из-за способности компилятора различать методы описанным выше способом.

Следующие примерыдаже не компилируется из-за своей неоднозначности:

case 1:

int compute(Object o1, Object o2, Object... others) { return 1; }
int compute(Object s1, Object... others)            { return 2; }

public static void main(String[] args) 
{
    JLS15Test y = new JLS15Test();
    System.out.println(y.compute(y,y,y));
    System.out.println(y.compute("hi",y,y));
}

case 2:

int compute(String o1, Object o2, Object... others) { return 1; }
int compute(Object s1, String... others)            { return 2; }

public static void main(String[] args) 
{
    JLS15Test y = new JLS15Test();
    System.out.println(y.compute("hi","hi","hi"));
}

Подробнее Редактировать

Первые два раза я не очень хорошо понял ваш вопрос (и надеюсь, что на этот раз :)).

Фактический случай, о котором вы говорите, будет выглядеть так:

public class Test {
    public static void main(String[] args)
    {
        Test t = new Test();
        int a = t.compute("t", new Test());
        System.out.println(a);
    }

    int compute(String s, Object... others) { return 1; }
    int compute(Object s1, Object others)   { return 2; }
}

В этом случае compute(Object s1, Object others) действительно более конкретен, чем compute(String s, Object... others) (имеет меньше параметров), поэтому на самом деле будет 2.

1 голос
/ 17 мая 2011

После прочтения JLS несколько раз, я, наконец, думаю, что понимаю этот раздел.

То, что они говорят, это то, что если есть два метода переменной арности, для целей определения, который является «более конкретным», вы можете считать, что метод с более коротким списком аргументов будет расширен, чтобыдлина равна более длинной.например,

int compute(Object o1, Object o2, Object... others)
int compute(String s1, Object... others)

можно считать (только для целей "более конкретной") эквивалентным

int compute(Object o1, Object o2, Object... others)
int compute(String s1, Object,    Object... others)

, а затем типы аргументов сравниваются один за другим споследний метод более конкретен.

(более строго, первый имеет n = 3, k = 2, n> = k, с String <: Object [String является подтипом Object] и JLSдиктует сравнение типов непосредственно каждого параметра для j от 1 до k-1 [на один меньше, чем более короткая длина], сравнение типа vararg более короткой сигнатуры метода с остальными параметрами более длинного метода.) </p>

В следующем случае:

int compute(Object o1, Object o2, String... strings)
int compute(Object o1, String... strings)

они будут эквивалентны (только для целей "более конкретно")

int compute(Object o1, Object o2, String... strings)
int compute(Object o1, String,    String... strings)

, а последний более конкретен.

Таким образом, переменная арность никогда не превосходит подтипы для сравнения «более специфических» методов, которые оба имеют переменную арность.

Однако методы с фиксированной арностью всегда рассматриваются первыми (JLS 15.12.2.2 и 15.12.2.3) перед методами переменной арности.

0 голосов
/ 17 мая 2011

Второй вызов compute выводит 2, потому что литерал hi во время компиляции известен как String, поэтому компилятор выбирает вторую сигнатуру метода, потому что String более специфичен, чем Object.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...