LINUX.ORG.RU

Возможно тупой вопрос по обобщениям в Java

 , ,


0

1

Учу понемногу Java и напоролся на такое:

public class Main {
    public static class MyTestClass<T>{
        private T[] myAr;
        private int curItem=0;
        private int count=10;

        MyTestClass(){
            myAr = (T[]) new Object[count]; //Этот код работает
            for(int i=0; i<myAr.length; i++){
                myAr[i] = (T) new Object(); //Этот код работает
            }
        }

        void set(T value){
            if(curItem<count) {
                myAr[curItem++] = value;
            }
        }

        T get(int index){
            return myAr[index];
        }
    }

    public static void main(String[] args){
        MyTestClass<Integer> myTestClass = new MyTestClass<Integer>();
        myTestClass.set(12);
        System.out.println(myTestClass.get(0));

        String[] str = (String[]) new Object[10]; //Этот код не работает, хотя, как мне кажется, делает тоже самое
    }

}

Внимание, вопрос!

myAr = (T[]) new Object[count];
...
myAr[i] = (T) new Object();

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

 String[] str = (String[]) new Object[10];
возникает Exception in thread «main» java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;

★★★★★

Потому что массив объектов не может быть приведен к массиву строк

subwoofer ★★★★★ ()
Ответ на: комментарий от subwoofer

согласен, но если выполнить

MyTestClass<String> myTestClass = new MyTestClass<String>();
myTestClass.set("MyText");
System.out.println(myTestClass.get(0));

то происходит приведение массива объектов к массиву строк, разве нет?

r0ck3r ★★★★★ ()

Подозреваю, что Object[] целиком никогда и не приводится к T[] (в твоем случае - Integer[]), потому и не падает. В рантайме он всегда остается Object[].

А вот отдельный элемент, Object[0] (Object) легко превращается в Integer[0] (Integer).

И вообще, массивы - сакс. Пользуйся ArrayList, как белый человек.

anonymous ()

Грубо говоря, Object[] не является базовым классом для String[], при этом класс String наследник класса Object, приведение легально.

mono ★★★★★ ()
Ответ на: комментарий от anonymous

про ArrayList знаю, но хочется понять принцип функционирования сабжа

r0ck3r ★★★★★ ()
Ответ на: комментарий от r0ck3r

Нет, происходит приведение конкретных элементов массива.

mono ★★★★★ ()
Ответ на: комментарий от mono

где можно об этом почитать? Что-то никак вникнуть не могу

UPDATE: разобрался, спасибо за помощь

r0ck3r ★★★★★ ()
Последнее исправление: r0ck3r (всего исправлений: 1)
Ответ на: комментарий от r0ck3r

- Не пытайся понять то, чего понять не можешь.

- Не понял?!

- И не пытайся!

Такие вопросы больше для самоутверждения на собеседованиях. В жизни оно не пригодится.

Вот так даже веселее:

"" + myArr.getClass()
сработает изнутри класса, но не сработает снаружи.
public class Main {
    public static class MyTestClass<T>{
        private T[] myAr;
        private int curItem=0;
        private int count=10;

        MyTestClass(){
            myAr = (T[]) new Object[count]; //Этот код работает
            for(int i=0; i<myAr.length; i++){
                myAr[i] = (T) new Object(); //Этот код работает
            }
        }

        void set(T value){
            if(curItem<count) {
                myAr[curItem++] = value;
            }
        }

        T get(int index){
            System.out.println("Class from the inside " + myAr.getClass());
            return myAr[index];
        }
    }

    public static void main(String[] args){
        MyTestClass<Integer> myTestClass = new MyTestClass<Integer>();
        myTestClass.set(12);
        System.out.println(myTestClass.get(0)); // Напечатает Class from the inside
        System.out.println("Class from the outside " + myTestClass.myAr.getClass()); // Упадем уже здесь
        String[] str = (String[]) new Object[10]; //Этот код не работает, хотя, как мне кажется, делает тоже самое
    }
}

Единственное, что нужно знать - массивы очень не ОК для дженериков, коллекции гораздо лучше.

anonymous ()
Ответ на: комментарий от r0ck3r

Повнимательней пройдись по каждой строчке в твоём коде. Убери дженерики, понятнее будет. Возможно ты упускаешь, что никаких дженериков в рантйме нет.

MyTestClass<String> myTestClass = new MyTestClass<String>();

Создаём объект класса MyTestClass. Так как jvm ничего не знает про дженерики, то внутри myAr есть массив Object[].

myTestClass.set("MyText");

В массив myArr кладётся строка «MyText». Так как в рантайме никаких дженериков нет, то при передаче аргумента в функцию String приводится в Object и в массив кладётся обычный Object.

System.out.println(myTestClass.get(0));

Тоже самое. Функция get() возвращает Object, внутри класса MyTestClass никаких приведений не происходит. Приведение типа выполняется во время передачи аргумента в System.out.println.

mono ★★★★★ ()
Ответ на: комментарий от anonymous

Такие вопросы больше для самоутверждения на собеседованиях. В жизни оно не пригодится.

как мне кажется, то как раз наоборот! Именно знание таких тонкостей и дает лучшее понимание того, с чем предстоит работать

Единственное, что нужно знать - массивы очень не ОК для дженериков, коллекции гораздо лучше.

До серьезной работы с коллекциями пока не добрался - знаком только поверхностно. Но за совет спасибо

r0ck3r ★★★★★ ()
Ответ на: комментарий от blan4

Большое спасибо! Интересная статья, да и сайт! Благодарю

r0ck3r ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.