Является ли массив String подклассом массива Object? - PullRequest
7 голосов
/ 11 января 2012

Я думаю, что мне здесь чего-то не хватает.Любое объяснение или указатели на ранее заданные вопросы будут очень полезны.

import java.util.Arrays;
import java.util.List;

public class St {

    public static void bla(Object[] gaga) {
            gaga[0] = new Date(); // throws ArrayStoreException
        System.out.println(gaga[0]);
    }

    public static void bla(List<Object> gaga) {
        System.out.println(gaga.get(0));
    }

    public static void main(String[] args) {
            String[] nana = { "bla" };
        bla(nana); // Works fine

        List<String> bla1 = Arrays.asList(args);
        bla(bla1); // Wont compile

            System.out.println(new String[0] instanceof Object[]); // prints true
            System.out.println(nana.getClass().getSuperclass().getSimpleName()); // prints Object
    }

}

Так что, похоже, List<String> не является подклассом List<Object>, а String[] является подклассом Object[].

Это правильное предположение?Если так, то почему?Если нет, то почему?

Спасибо

Ответы [ 5 ]

10 голосов
/ 11 января 2012

Массивы Java ковариантны , то есть допускают Object[] foo = new String[2];.Но это не значит, что они подклассы.String[] является подклассом Object (хотя instanceof возвращает true, String[].class.getSuperclass() возвращает Object)

5 голосов
/ 11 января 2012

Да, ваше предположение верно. По словам @Bozho массивы являются ковариантными, тогда как универсальные коллекции (такие как универсальный список) не являются ковариантными.

Ковариация в массивах рискованна:

String[] strings = new String[] { "a", "b" }
Object[] objects = strings;
objects[0] = new Date();  // <-- Runtime error here 
String s = strings[0];
s.substring(5, 3);        // ????!! s is not a String 

Третья строка вызывает исключение времени выполнения. Если бы оно не вызывало это исключение, вы могли бы получить переменную String, s, которая ссылается на значение, которое не является String (ни его подтипом): a Date.

3 голосов
/ 11 января 2012

Вы правы.Типы массивов ковариантны в Java по своей конструкции, но Foo<Sub> is-not-a Foo<Super>.

3 голосов
/ 11 января 2012
(new String[0] instanceof Object[]) // => true
2 голосов
/ 12 января 2012

String [] является подклассом Object []

Правильно, см. 4.10.3 Подтипы среди типов массивов :

Если S и T оба являются ссылочными типами, то S []> 1 T [], если S> 1 T.

С String >1 Object, поэтому String[] >1 Object[]

То есть String[] является прямым подтипом из Object[]

Объект> 1 Объект []

для этого Object > String[]; String[] является (косвенным?) подтипом из Object

Для дженериков такой связи не существует, поэтому List<String> > List<Object> неверно.

Теперь рассмотрим следующий простой пример:

import java.util.*;

class G {
    interface I {
    void f();
    }
    class C implements I {
    public void f() {}
    }

    void allF(List<I> li) {
    for (I i : li) { i.f(); }
    }

    void x(List<C> lc) {
    allF(lc);
    }
}

Он не компилируется, потому что x вызывает allF с List<C>, который не a List<I>. Чтобы использовать List<C> подпись должна слегка измениться:

void allF(List<? extends I> li) {

Теперь он компилируется. Неофициально, li - это List из некоторого типа, который расширяет / реализует I. Поэтому List<C> является , присваиваемым List<? extends I>. То, что вы можете сделать с таким списком, ограничено. По сути, вы можете читать / получать к нему доступ, но не можете write/modify.

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