обновленный вопрос
Привет,
В настоящее время у меня есть проблема с пониманием того, как на объекты ссылаются в списках массивов, или, чтобы быть более точным, как на самом деле работает использование метода 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, который я вижу здесь, но затем мне интересно, как ссылаться на объект и почему отладка показывает все еще старый объект, но рисует в позиции нового (второй перед удалением первого), а также мой список стал меньше и рисуется на один сегмент меньше. Так что на самом деле он работает так, как должен, хотя я никогда не обновляю свою "головную" ссылку при удалении первого объекта.
Любая помощь приветствуется!
что значит объект что-то другое?
извините, я ничего не вижу, изображения не могут быть скомпилированы .... но ... не намного ли проще просто скопировать и вставить код в виде текста вместо того, чтобы делать снимок экрана? по крайней мере, было бы намного лучше прочитать!
теперь лучше ... testling2 НЕ является ссылкой на testling1; он получает одно и то же значение, которое является ссылкой на экземпляр, поэтому оба являются указывая для одного и того же экземпляра
хорошо, и почему он меняет testling1, когда я меняю testling2. и почему это поведение исчезло в конце концов?
У вас есть два оператора new, поэтому вы создаете два объекта. Переменные - это просто ссылки на эти два объекта. Назовем первый объект A и второй объект B. В первой части кода как testline1, так и testling2 ссылаются на объект A, поэтому каждый раз, когда вы меняете A, значение A изменяется (дох!), Независимо от того, видно ли это по разыменованию testline1 или по разыменованию testling2. Позже вы создадите и назначите объект B для testline1. В настоящее время testline2 все еще относится к A, поэтому теперь они относятся к двум различным объектам.
он не меняет testling1, он меняет экземпляр, на который сначала указывал testling1 (тот же экземпляр, на который указывает testling2). И в конце ничего не пропало, просто testling1 указывает на другой новый экземпляр
@Andreas в порядке, но я никогда не звонил testling2 = new ... Значит, объект A будет уничтожен / удален, когда я установлю testling2 = null? где хранится объект A B и где хранятся его переменные?
@CarlosHeuberger хорошо, я подумал, что как только диапазон testling1 выйдет из диапазона, и когда он будет установлен на null, не должно быть ничего, на что testling2 все еще мог бы ссылаться. Я не понимал, что testling1 - это тоже всего лишь ссылка. Итак, когда будет уничтожен исходный экземпляр? и как мне скопировать values / obj без ссылки на них.
точно нет; в противном случае ни один объект не выжил бы, если бы блок закончился ... очень сложно для многопоточности ... просто testling1, поскольку переменная перестает существовать, но не экземпляр, на который она указывает. Экземпляр в конечном итоге удаляется, если на него нет (живой) ссылки
@andreas, если объект уничтожается только тогда, когда не осталось ссылок (и, таким образом, его выкидывают из кучи), когда и как переменные объекта, такие как в моем примере «имя», удаляются из стека?
@railwanderer name - это поле, а не локальная переменная. Ключевое слово, используемое для уничтожения объектов, - недоступен. Может какой-нибудь код достигать у объекта (как-нибудь)? В противном случае его можно уничтожить. Если объект Testling становится недоступен, он может быть уничтожен. После уничтожения строковый объект, на который ссылается name, скорее всего, станет недоступен и может быть уничтожен. Промыть и повторить. Конечно, сборщик мусора умнее этого и может уничтожать и то, и другое одновременно, но это детализация производительности.
@Andreas и эта переменная класса "name" или поле правильно хранится в куче?
@railwanderer Он является членом объекта и хранится как часть объекта, а объект находится в куче, поэтому: Да.
@Andreas Спасибо! теперь имеет смысл :)




Вот несколько важных концепций:
newtestling1 и testling2 - это ссылки, указывающие на объекты.testling2 = testling1; означает, что testling2 теперь указывает на тот же объект, на который указывает testling1, но это все еще две разные ссылки.testling1 = null; означает, что testling1 не указывает на какой-либо объект, testling2 не затронут, все еще указывая на тот же объект, что и раньше.Я думаю, этого должно быть достаточно, чтобы понять, что происходит с вашим кодом.
Переменные не являются объектами. Ни
testling1, ниtestling2никогда не являются «оригинальными объектами»; они обе переменные. Объект - это что-то другое.