2015-06-15 2 views
13
public class test { 
    test(double[] a) 
    { 
     System.out.println("in double"); 
    } 
    test(Object a) 
    { 
     System.out.println("in object"); 
    } 
    public static void main(String args[]) 
    { 
     new test(null); 
    } 
} 

В приведенном выше коде я передаю null в качестве аргумента конструктора. Поскольку null может быть любым, приведенный выше код компилируется отлично. Когда я запускаю код, я ожидал, что он напечатает в объекте, но он печатает в двойном В чем причина этого?Почему Java предпочитает называть двойной конструктор?

Примечание связанный вопрос не может быть дубликатом, потому что этот вопрос связан с примитивным типом данных против Object

+0

Похоже, что используется 'double', потому что это первый определенный конструктор. Вы пробовали сначала определить конструктор с параметром «Объект»? –

+1

@KErlandsson извините, я не думаю, что это дубликат связанного вопроса. – rocking

+4

@rocking double [] не является примитивным. Массивы - это объекты. 'double [] instanceof Object == true'. –

ответ

21

Причина в том, что Java интерпретирует null как любой тип, и при выборе метода для вызова он выберет наиболее специфический метод, который сначала вводит типы аргументов. Поскольку null может быть типа double[] и double[] является Object, компилятор выберет метод, который принимает double[]. Если выбор включает одинаково возможные, но несвязанные типы, например. double[] и String, тогда компилятор не сможет выбрать метод, и это приведет к ошибке неоднозначного вызова метода.

JLS, Section 4.1, гласит:

Нулевая ссылка всегда может быть назначен или приведение к любой ссылочного типа (§5.2, §5.3, §5.5).

На практике программист может игнорировать нулевой тип и просто притворяться, что null - это просто специальный литерал, который может быть любого ссылочного типа.

+0

Если я создаю другой конструктор, который принимает double [] и Number, то он не компилируется. Почему есть причина? Должен ли я изменить свой вопрос? – rocking

+0

@rocking Причина в том, что ни 'double []', ни 'Number' более специфичны друг для друга. 'double []' не является подклассом 'Number', а' Number' не является подклассом 'double []'. Не существует «особого метода», хотя оба метода применимы. Вот где возникает двусмысленность; компилятор не знает, какой из них выбрать, поэтому он генерирует ошибку. – rgettman

+0

double [] также не относится к объекту i, означает его не подкласс объекта, потому что double является примитивным типом. так как в вашем ответе есть 'Double' vs' Object ', тогда он выберет для большинства конкретных типов, разве нет? – rocking

9

Оба Конструкторы применимы, поскольку null конвертируется в обоих Object и double[] - так что компилятор должен использовать перегрузку разрешение, чтобы определить, какой конструктор вызвать.

JLS 15.9.3 использует JLS 15.12.2, чтобы определить «наиболее специфичную» подпись конструктора для использования на основе того, какой конструктор имеет наиболее конкретные типы параметров, в соответствии с JLS 15.12.2.5. Точные детали немного неясны (IMO), но в этом случае основное эмпирическое правило «если вы можете конвертировать из T1 в T2, но не от T2 до T1, то T1 более конкретный», это достаточно хорошо.

double[] является более конкретным типом, чем Object, потому что есть неявное преобразование из double[] в Object, а не наоборот.

+0

. Можете ли вы рассказать мне, как определить, какой из них наиболее специфичен? – rocking

+2

@rocking: Я дал вам эмпирическое правило и ссылки на спецификации ... Я не уверен, что еще вам нужно. –

+0

Этот же сценарий работает и для методов? –