Я изо всех сил пытаюсь полностью понять передачу копии/копии в 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
Да, кажется, я понимаю это. Метод main() предназначен для изменения значений переменных f1, f2 и f3 с помощью методов TwoFlows() и AdjustDistance(). Я пытаюсь передать их в TwoFlows, а затем настроить расстояние, чтобы обновить значения.
Поля TwoFlows
остаются в TwoFlows
. Чтобы распечатать результаты, сделайте что-то вроде этого: System.out.println(formatF1F2F3(f1,twoFa.flow1,twoFa.flow2));
и т. д.
Да, кажется, я понимаю это. Позвольте мне перефразировать: вы устанавливаете основные f1,f2,f3 один раз при инициализации, и нет кода для изменения их значений, и поэтому каждый раз, когда вы обрабатываете одни и те же значения с помощью formatf1f2f3, вы должны и будете получать один и тот же результат.
Я изо всех сил пытаюсь полностью понять передачу копии/копии в 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));
Ваш метод «adjustDistance» обновляет переменные-члены объекта TwoFlows. Это не влияет на одноименные локальные переменные функции main(). Это то, что вы ожидали?