Использование копирования в/из передачи в Java

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

Мне нужно обновить поплавки (f1, f2 и f3) в основном методе, отрегулировав расстояние с помощью метода AdjustDistance(). Это для викторины с домашним заданием, поэтому то, что я могу/не могу изменить, ограничено. Ищу немного информации о том, что мне нужно сделать и почему.

Это код:

public class Flow {
public static String formatF1F2F3(float f1, float f2, float f3)
{
    return
      "f1 = " + f1 + ", f2 = " + f2 + ", f3 = " + f3;
}

//      The new record type is needed to
//      so that the two results
//      of adjustDistance can be returned together.
//
//      adjustDistance is a method inside this
//      class so that parameter passing is simpler
private static class TwoFlows
{
    public float flow1;
    public float flow2;

    public TwoFlows(float flow1, float flow2)
    {
        this.flow1 = flow1;
        this.flow2 = flow2;
    }

    public void adjustDistance()
    {
        if ( Math.abs(flow1 - flow2) < 10 )
        {
            if (flow1 > flow2)
            {
                flow2 = flow2 / 3;
                flow1 = flow1 + flow2;
                flow1 = flow1 + flow2;
            }
            else
            {
                flow1 = flow1 / 3;
                flow2 = flow2 + flow1;
                flow2 = flow2 + flow1;
            }
        }
    }
}

public static void main(String[] args)
{
    float f1, f2, f3;
    f1 = 3; f2 = 3; f3 = 4;
    
    System.out.println(formatF1F2F3(f1,f2,f3));

    //    TASK:
    //    Write code that it simulates *copy-in copy-out* passing
    //    of formal parameters flow1 and flow2 to method adjustDistance.
    //    only alter code below this comment

    // my attempt:

    TwoFlows twoFa = new TwoFlows(f2, f3);
    twoFa.adjustDistance();
    System.out.println(formatF1F2F3(f1,f2,f3));
    TwoFlows twoFb = new TwoFlows(f1,f2);
    twoFb.adjustDistance();
    System.out.println(formatF1F2F3(f1,f2,f3));
    TwoFlows twoFc = new TwoFlows(f3,f3);
    twoFc.adjustDistance();
    System.out.println(formatF1F2F3(f1,f2,f3));
} }

ВЫХОД:

f1 = 3,0, f2 = 3,0, f3 = 4,0

f1 = 3,0, f2 = 3,0, f3 = 4,0

f1 = 3,0, f2 = 3,0, f3 = 4,0

f1 = 3,0, f2 = 3,0, f3 = 4,0

Если я не инициализирую новый TwoFlows() каждый раз, я получаю сообщение об ошибке. Я не думаю, что поток 1 и поток 2 обновятся, как я ожидаю.

Я считаю, что ожидаемый результат:

f1 = 3,00, f2 = 3,00, f3 = 4,00

f1 = 3,00, f2 = 1,00, f3 = 6,00

f1 = 3,67, f2 = 0,33, f3 = 6,00

f1 = 3,67, f2 = 0,33, f3 = 10,00

Ваш метод «adjustDistance» обновляет переменные-члены объекта TwoFlows. Это не влияет на одноименные локальные переменные функции main(). Это то, что вы ожидали?

undefined symbol 31.01.2023 13:37

Да, кажется, я понимаю это. Метод main() предназначен для изменения значений переменных f1, f2 и f3 с помощью методов TwoFlows() и AdjustDistance(). Я пытаюсь передать их в TwoFlows, а затем настроить расстояние, чтобы обновить значения.

Chelsea 31.01.2023 13:41

Поля TwoFlows остаются в TwoFlows. Чтобы распечатать результаты, сделайте что-то вроде этого: System.out.println(formatF1F2F3(f1,twoFa.flow1,twoFa.flow2))‌​; и т. д.

Maurice Perry 31.01.2023 15:04

Да, кажется, я понимаю это. Позвольте мне перефразировать: вы устанавливаете основные f1,f2,f3 один раз при инициализации, и нет кода для изменения их значений, и поэтому каждый раз, когда вы обрабатываете одни и те же значения с помощью formatf1f2f3, вы должны и будете получать один и тот же результат.

undefined symbol 01.02.2023 00:21
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
4
60
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Я изо всех сил пытаюсь полностью понять передачу копии/копии в Java.

Я не знал терминов «копирование» и «копирование», но я предполагаю, что они относятся к «передаче по значению». В основном это означает, что значение параметра или возвращаемого типа копируется, т.е. если вы позже измените переменную, это не отразится на другой стороне.

Рассмотрим следующее:

int someMethod(int param) { 
  try {
        param++;
        return param;
    } finally {
        param--;
        param--;
    }
}

void test() {
  int a = 2; 
  int b = someMethod(a);
}

Здесь param является копией a, что означает, что приращение влияет только на param, но не на a. Когда вы возвращаете param, значение копируется в b, поэтому уменьшение применяется только к param. Это означает, что b будет иметь значение 3, а a сохранит свое значение 2, хотя param сначала увеличивается до 3, а после определения возвращаемого значения уменьшается до 1. - В вашем примере это означает, что значения f1, f2 и f3 копируются в TwoFlows(...), но сами переменные никогда не изменяются.

Обратите внимание, что если ваши переменные и параметры являются ссылками на объекты, копируемые значения являются ссылками (думайте о них как об адресе объекта), а не сами объекты.

Итак, давайте изменим пример, чтобы использовать AtomicInteger, что позволит нам изменить значение объекта:

AtomicInteger someMethod(AtomicInteger param) {
    try {
        param.incrementAndGet();
        return param;
    } finally {
        //decrement twice after "copying" the return value
        param.decrementAndGet();
        param.decrementAndGet();
    }
}

void test() {
  AtomicInteger a = new AtomicInteger(2);
  AtomicInteger b = someMethod(a);
}

Теперь param будет копией ссылки a, а b будет копией ссылки param. В конце концов, все 3 ссылки «указывают» на один и тот же экземпляр AtomicInteger. Таким образом, операции увеличения и уменьшения влияют на них всех, что означает, что все они возвращают одно и то же значение — 1.

Итак, как мне исправить мой код?

Чтобы исправить код, вам нужно получить значения flow1 и flow2, например. так:

TwoFlows twoFa = new TwoFlows(f2, f3);
twoFa.adjustDistance();
System.out.println(formatF1F2F3(f1,twoFa.flow1,twoFa.flow2));

Переменные с плавающей запятой — это примитивные типы Java, поэтому, когда вы передаете их в метод или конструктор, они передаются по значению, а не по ссылке. Это означает, что какие бы изменения ни происходили с переменными f1, f2, f3 внутри вашего статического класса и метода adjustDistance(), они «видимы» только внутри этого класса. Когда вы пытаетесь напечатать значения в своем основном методе, вы просто печатаете исходные значения с плавающей запятой, которые не были изменены. Если вы хотите распечатать измененные значения, я предлагаю следующее:

System.out.println(formatF1F2F3(f1,f2,f3));
System.out.println(formatF1F2F3(f1,twoFa.flow1,twoFa.flow2));
System.out.println(formatF1F2F3(twoFb.flow1,twoFb.flow2,f3));     
System.out.println(formatF1F2F3(f1,twoFc.flow1,twoFc.flow2));

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