Ссылочный объект в списке массивов

обновленный вопрос

Привет,

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

Я добавляю 4 объекта в ArrayList, затем сохраняю ссылку в "голове", указывающую объекту в первом слоте.

public List<SmakeSegment> smakeParts = new ArrayList<>();

public SmakeSegment head;


public Smake() {
    addInitialSmakeSegment(14, 9, RIGHT);
    addInitialSmakeSegment(14, 8, UP);
    addInitialSmakeSegment(15, 8, LEFT);
    addInitialSmakeSegment(15, 9, DOWN);

    state = ALIVE;
    head = smakeParts.get(0);           // TODO: DEBUG check if reference gets updated automatically upon changing list entity
}

private void addInitialSmakeSegment(int i, int i1, int direction) {
    SmakeSegment segment = new SmakeSegment(i * TILESIZE, i1 * TILESIZE, TILESIZE, TILESIZE);
    segment.addTileStep(direction);
    smakeParts.add(segment);
}

public void addSegment(){

    if ( smakeParts.size() >= 2 ){

        SmakeSegment original    = smakeParts.get( smakeParts.size() - 2 );
        SmakeSegment duplicate   = new SmakeSegment(  original.getPositionLL().x,
                                                            original.getPositionLL().y,
                                                            TILESIZE, TILESIZE);
        SmakeSegment end         = smakeParts.get( smakeParts.size() - 1 );

        duplicate.setDirection( original.getDirection() );

        smakeParts.remove( smakeParts.size() - 1 );
        smakeParts.add( duplicate );
        smakeParts.add( end );
    }else if (smakeParts.size() ==1){
        SmakeSegment original = smakeParts.get(0);
        SmakeSegment duplicate = new SmakeSegment(original.getPositionLL().x,original.getPositionLL().y,TILESIZE,TILESIZE);
        duplicate.setDirection(original.getDirection());
        smakeParts.add(duplicate);
    }
}

позже я визуализирую Объект. Первый объект в списке всегда будет отображаться с другим активом:

public void renderSmake() {
    batcher.beginBatch(Assets.itemsUni);
    TextureRegion segmentRegion;
    SmakeSegment segment ;

    // cycle through the entire smake and draw its parts
    for (int i = world.smake.smakeParts.size()-1; i >= 0; i--) {
        segment = world.smake.smakeParts.get(i);

        // first in array is the head
        if ( i== 0 ){
            segmentRegion = Assets.smakeHeadAnimation.getKeyFrame(segment.stateTime, Animation.ANIMATION_LOOPING);

            // last in array is the tail
        }else if ( i == world.smake.smakeParts.size() - 1 ){
            segmentRegion = Assets.smakeTailAnimation.getKeyFrame(segment.stateTime,Animation.ANIMATION_LOOPING);

            // all other parts are middle parts
        }else{
            segmentRegion = Assets.smakeMiddleAnimation.getKeyFrame(segment.stateTime,Animation.ANIMATION_LOOPING);
        }

        // paint parts according to direction
        if (segment.getDirection() == Smake.UP) {
            batcher.drawSprite(segment.getPositionCenter().x, segment.getPositionCenter().y, segment.bounds.width, segment.bounds.height, 270, segmentRegion);
        } else if (segment.getDirection() == Smake.LEFT) {
            batcher.drawSprite(segment.getPositionCenter().x, segment.getPositionCenter().y, segment.bounds.width, segment.bounds.height, 0,segmentRegion);
        } else if (segment.getDirection() == Smake.RIGHT) {
            batcher.drawSprite(segment.getPositionCenter().x, segment.getPositionCenter().y, segment.bounds.width, segment.bounds.height, 180, segmentRegion);
        } else if (segment.getDirection() == Smake.DOWN) {
            batcher.drawSprite(segment.getPositionCenter().x, segment.getPositionCenter().y, segment.bounds.width, segment.bounds.height, 90, segmentRegion);
        }
    }
    batcher.endBatch();
}

что меня действительно удивляет, так это то, что если я удалю первый объект:

public void removeSegment(int index){
    if (smakeParts.size() > index && smakeParts.size() > 1) {

        if (!smakeParts.get(index).getPixelMoves().isEmpty()) {
            for (int i = 0; i < smakeParts.get(index).getPixelMoves().size(); i++) {

                if (index + 1 != smakeParts.size())
                    smakeParts.get(index + 1).addStep(smakeParts.get(index).getPixelMoves().get(i));
            }
        }
    }
    smakeParts.remove(index);
}

Я ожидал, что при рендеринге произойдет ошибка, так как ссылка «head» по-прежнему указывает на старый объект (SmakePart @ 4206) и, таким образом, все равно будет отображаться, хотя и удалена из списка, поскольку на нее все еще есть ссылка.

Но происходит то, что автоматически будет отображен новый первый объект в списке. Отладка показывает мне, что моя «головная» ссылка, используемая в рендерере, по-прежнему содержит тот же объект (SmakePart @ 4206), как это может быть? Является ли этот SmakePart @ 4206 указателем, ссылающимся на мой объект, или он ссылается на первый слот в ArrayList, который я вижу здесь, но затем мне интересно, как ссылаться на объект и почему отладка показывает все еще старый объект, но рисует в позиции нового (второй перед удалением первого), а также мой список стал меньше и рисуется на один сегмент меньше. Так что на самом деле он работает так, как должен, хотя я никогда не обновляю свою "головную" ссылку при удалении первого объекта.

Любая помощь приветствуется!

Переменные не являются объектами. Ни testling1, ни testling2 никогда не являются «оригинальными объектами»; они обе переменные. Объект - это что-то другое.

user2357112 supports Monica 19.11.2018 23:32

что значит объект что-то другое?

railwanderer 19.11.2018 23:36

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

user85421 19.11.2018 23:37

теперь лучше ... testling2 НЕ является ссылкой на testling1; он получает одно и то же значение, которое является ссылкой на экземпляр, поэтому оба являются указывая для одного и того же экземпляра

user85421 19.11.2018 23:40

хорошо, и почему он меняет testling1, когда я меняю testling2. и почему это поведение исчезло в конце концов?

railwanderer 19.11.2018 23:41

У вас есть два оператора new, поэтому вы создаете два объекта. Переменные - это просто ссылки на эти два объекта. Назовем первый объект A и второй объект B. В первой части кода как testline1, так и testling2 ссылаются на объект A, поэтому каждый раз, когда вы меняете A, значение A изменяется (дох!), Независимо от того, видно ли это по разыменованию testline1 или по разыменованию testling2. Позже вы создадите и назначите объект B для testline1. В настоящее время testline2 все еще относится к A, поэтому теперь они относятся к двум различным объектам.

Andreas 19.11.2018 23:41

он не меняет testling1, он меняет экземпляр, на который сначала указывал testling1 (тот же экземпляр, на который указывает testling2). И в конце ничего не пропало, просто testling1 указывает на другой новый экземпляр

user85421 19.11.2018 23:43

@Andreas в порядке, но я никогда не звонил testling2 = new ... Значит, объект A будет уничтожен / удален, когда я установлю testling2 = null? где хранится объект A B и где хранятся его переменные?

railwanderer 19.11.2018 23:44

@CarlosHeuberger хорошо, я подумал, что как только диапазон testling1 выйдет из диапазона, и когда он будет установлен на null, не должно быть ничего, на что testling2 все еще мог бы ссылаться. Я не понимал, что testling1 - это тоже всего лишь ссылка. Итак, когда будет уничтожен исходный экземпляр? и как мне скопировать values ​​/ obj без ссылки на них.

railwanderer 19.11.2018 23:47
«Значит, объект A будет уничтожен / удален, когда я установлю testling2 = null?» Это будет имеющий право для сборки мусора. если, если вы установите для него значение null (чего вы никогда не делаете). --- "Где сохранен Объект A B?" В памяти, в куче. --- "где хранятся их переменные?" В памяти, в стеке.
Andreas 19.11.2018 23:47

точно нет; в противном случае ни один объект не выжил бы, если бы блок закончился ... очень сложно для многопоточности ... просто testling1, поскольку переменная перестает существовать, но не экземпляр, на который она указывает. Экземпляр в конечном итоге удаляется, если на него нет (живой) ссылки

user85421 19.11.2018 23:49

@andreas, если объект уничтожается только тогда, когда не осталось ссылок (и, таким образом, его выкидывают из кучи), когда и как переменные объекта, такие как в моем примере «имя», удаляются из стека?

railwanderer 19.11.2018 23:52

@railwanderer name - это поле, а не локальная переменная. Ключевое слово, используемое для уничтожения объектов, - недоступен. Может какой-нибудь код достигать у объекта (как-нибудь)? В противном случае его можно уничтожить. Если объект Testling становится недоступен, он может быть уничтожен. После уничтожения строковый объект, на который ссылается name, скорее всего, станет недоступен и может быть уничтожен. Промыть и повторить. Конечно, сборщик мусора умнее этого и может уничтожать и то, и другое одновременно, но это детализация производительности.

Andreas 20.11.2018 00:00

@Andreas и эта переменная класса "name" или поле правильно хранится в куче?

railwanderer 20.11.2018 00:04

@railwanderer Он является членом объекта и хранится как часть объекта, а объект находится в куче, поэтому: Да.

Andreas 20.11.2018 00:05

@Andreas Спасибо! теперь имеет смысл :)

railwanderer 20.11.2018 13:53
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
16
73
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот несколько важных концепций:

  1. объекты создаются с помощью new
  2. testling1 и testling2 - это ссылки, указывающие на объекты.
  3. testling2 = testling1; означает, что testling2 теперь указывает на тот же объект, на который указывает testling1, но это все еще две разные ссылки.
  4. testling1 = null; означает, что testling1 не указывает на какой-либо объект, testling2 не затронут, все еще указывая на тот же объект, что и раньше.
  5. объекты автоматически уничтожаются сборщиком мусора, когда на них нет ссылок

Я думаю, этого должно быть достаточно, чтобы понять, что происходит с вашим кодом.

Другие вопросы по теме