Явное преобразование типов в случае необработанных типов Java - PullRequest
0 голосов
/ 13 декабря 2018

Я читаю книгу о шаблонах ООП с примерами Java. Пример кода класса из книги:

public class Board {

    private int width, height;
    private List tiles;

    ...

    private void initialize() {
        tiles = new ArrayList(width);
        for (int i=0; i<width; i++) {
            tiles.add(i, new ArrayList(height));
            for (int j=0; j<height; j++) {
                ((ArrayList)tiles.get(i)).add(j, new Tile());
            }
        }
    }

    public Tile getTile(int x, int y) {
        return (Tile)((ArrayList)tiles.get(x-1)).get(y-1);
    }

}

Вопрос:

Почему в обоих описанных методах используется Явное преобразование типов?В первом случае ArrayList в строке ((ArrayList)tiles.get(i)).add(j, new Tile());, во втором - Tile в строке return (Tile)((ArrayList)tiles.get(x-1)).get(y-1);.Я имею в виду, это мнение автора сценария или необходимо в случае Java?

Ответы [ 5 ]

0 голосов
/ 14 декабря 2018

Java - строго типизированный язык.Большинство ошибок типа \ all должно быть получено во время компиляции.До Generics вы не можете контролировать, какие типы хранятся в списке.В этом случае (необработанные типы) отложенная проверка типов переходит во время выполнения.Тогда всегда лучше сначала преобразовать любой необработанный тип в конкретный тип, чтобы избежать ошибок во время выполнения.

Но в этом примере мы даже не сможем скомпилировать код, потому что пример показывает, как ненадежные необработанные типы могутбыть, и компилятор понимает это во время компиляции.Я имею в виду эту строку: ((ArrayList)tiles.get(i)).add(j, new Tile()); - это простой случай, который говорит сам за себя.Если мы удалим (ArrayList) и получим (tiles.get(i)).add(j, new Tile()); - , почему компилятор Java должен верить нам , что в (tiles.get(i)) у нас есть List или какой-то объект с add() методом ?!Да, не должен, и он не делает.

Чтобы проверить, мы можем попытаться скомпилировать простой аналогичный пример с использованием Типы необработанных данных в случае с переменными List:

List listOfLists = new ArrayList();
listOfLists.add(0, new ArrayList());
(listOfLists.get(0)).add("something");  // compile error

Но когда мы говорим компилятору о точном типе внутри listOfLists.get(0), и тогда все будет в порядке:

((ArrayList)listOfLists.get(0)).add("something");  // NO compile error

Generics решит эту проблему более точно.Они жестко фиксируют тип для переменных List:

List<List> listOfLists = new ArrayList<List>();   // now List only have List's inside
listOfLists.add(0, new ArrayList());
(listOfLists.get(0)).add("something");  // NO compile error

Компилятор знает, что listOfLists.get(0) - это список, и у него есть метод add().

0 голосов
/ 13 декабря 2018

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

Я думаю,

tiles = new Array(width);

должно было быть

tiles = new ArrayList(width);

Далее

 ((ArrayList)tiles.get(i)).add(j, new Tile());

Здесь tile.get (i) типизирован для ArrayListпотому что плитка - это список с каждым элементом, содержащим свой собственный ArrayList.(Это код создания двумерного динамического массива)

В настоящее время tiles.get(i) возвращает тип объекта.Для использования метода «add» он должен быть приведен к типу ArrayList. Аналогично ниже, объект приведен к типу ArrayList для использования метода «get»

0 голосов
/ 13 декабря 2018

Похоже, что вы читаете древнюю книгу .

Почему в обоих описанных методах используется явное преобразование типов?

Этонеобходимо, потому что вы имеете дело с необработанными типами

Я имею в виду, это мнение автора сценария или необходимо в случае Java?

это не обязательноразыграть, если вы используете дженерики .

0 голосов
/ 13 декабря 2018

Существует два способа объявить ArrayList.

Ради простого примера я создал следующий фиктивный класс

public class Tile {
    int x = 123;
}

Первый более старый способ, как вы описалив вашем вопросе может быть написано следующее:

List tiles = new ArrayList();
tiles.add(new Tile());

Tile tile = ((Tile)tiles.get(0));
System.out.println(tile.x); // prints 123

То же самое можно сделать с помощью Generics.предпочтительный способ использования списка.

0 голосов
/ 13 декабря 2018

Это более старый код Java, до введения обобщений, поэтому интерфейс List возвращает Object, а не требуемый тип.Похоже, что на современном языке они хотят что-то вроде

private List<List<Tile>> tiles;

, и тогда initialize (при условии, что я не сделал опечаток) может выглядеть так:

private void initialize() {
    tiles = new ArrayList<>(width);
    for (int i=0; i<width; i++) {
        tiles.add(i, new ArrayList<>(height));
        for (int j=0; j<height; j++) {
            tiles.get(i)).add(j, new Tile();
        }
    }
}

(Я считаю, что Array в исходном коде является опечаткой для ArrayList)

и

public Tile getTile(int x, int y) {
    return tiles.get(x-1).get(y-1);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...