Не может относиться к непоследней переменной во внутреннем классе, определенном в другом методе

Или создайте массив параметров вручную:

SqlParameter[] parameter = {
new SqlParameter(...), 
new SqlParameter(...), 
new SqlParameter(...)
};

, Но я не вижу то, что должно быть неправильным с Вашим подходом. Это простой, читаемый и понятный.

244
задан Josh Lee 5 October 2010 в 08:01
поделиться

9 ответов

Java не поддерживает истинные замыкания , хотя использование анонимного класса, подобного используемому вами здесь ( new TimerTask () {...} ), выглядит как своего рода закрытие.

редактировать - См. комментарии ниже - следующее не является правильным объяснением, как указывает KeeperOfTheSoul.

Вот почему это не работает:

Переменные lastPrice и price являются локальными переменными в методе main (). Объект, который вы создаете с помощью анонимного класса, может существовать до тех пор, пока метод main () не вернется.

Когда метод main () вернет результат, локальные переменные (например, ] lastPrice и price ) будут удалены из стека, поэтому они больше не будут существовать после возврата main () .

Но анонимный объект класса ссылается на эти переменные. Все будет ужасно неправильно, если объект анонимного класса попытается получить доступ к переменным после того, как они были очищены.

Сделав lastPrice и price final , они не являются действительно переменных больше, но констант. Затем компилятор может просто заменить использование lastPrice и price в анонимном классе значениями констант (конечно, во время компиляции), и у вас не будет проблема с доступом к несуществующим переменным больше.

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

@Ankur: Ты мог бы сделать это:

public static void main(String args[]) {
    int period = 2000;
    int delay = 2000;

    Timer timer = new Timer();

    timer.scheduleAtFixedRate(new TimerTask() {
        // Variables as member variables instead of local variables in main()
        private double lastPrice = 0;
        private Price priceObject = new Price();
        private double price = 0;

        public void run() {
            price = priceObject.getNextPrice(lastPrice);
            System.out.println();
            lastPrice = price;
        }
    }, delay, period);      
}
196
ответ дан 23 November 2019 в 03:09
поделиться

Потому что это сбивает с толку, если переменная не является окончательной, поскольку ее изменения не будут учтены в анонимном классе.

Просто сделайте переменные 'price' и 'lastPrice 'final.

- Edit

К сожалению, вам также не нужно назначать их, очевидно, в вашей функции. Вам понадобятся новые локальные переменные. В любом случае, я подозреваю, что кто-то уже дал вам лучший ответ.

-2
ответ дан 23 November 2019 в 03:09
поделиться

Вы можете получить доступ только к конечным переменным из содержащего класса при использовании анонимного класса.

0
ответ дан 23 November 2019 в 03:09
поделиться

Если переменная должна быть окончательной, не может быть, тогда вы можете присвоить значение переменной другой переменной и сделать ТОЛЬКО окончательным, чтобы вы могли использовать его вместо этого.

1
ответ дан 23 November 2019 в 03:09
поделиться

Вы не можете ссылаться на незавершенные переменные, потому что так сказано в спецификации языка Java. Начиная с версии 8.1.3:
«Любая локальная переменная, параметр формального метода или параметр обработчика исключений, используемые, но не объявленные во внутреннем классе, должны быть объявлены окончательными». Целый абзац.
Я вижу только часть вашего кода - на мой взгляд, изменение расписания локальных переменных - странная идея. Локальные переменные перестают существовать, когда вы выходите из функции. Может быть, статические поля класса лучше?

2
ответ дан 23 November 2019 в 03:09
поделиться

Когда я натыкаюсь на эту проблему, я просто передаю объекты внутреннему классу через конструктор. Если мне нужно передать примитивы или неизменяемые объекты (как в этом случае), необходим класс-оболочка.

Изменить: На самом деле я вообще не использую анонимный класс, а использую соответствующий подкласс:

public class PriceData {
        private double lastPrice = 0;
        private double price = 0;

        public void setlastPrice(double lastPrice) {
            this.lastPrice = lastPrice;
        }

        public double getLastPrice() {
            return lastPrice;
        }

        public void setPrice(double price) {
            this.price = price;
        }

        public double getPrice() {
            return price;
        }
    }

    public class PriceTimerTask extends TimerTask {
        private PriceData priceData;
        private Price priceObject;

        public PriceTimerTask(PriceData priceData, Price priceObject) {
            this.priceData = priceData;
            this.priceObject = priceObject;
        }

        public void run() {
            priceData.setPrice(priceObject.getNextPrice(lastPrice));
            System.out.println();
            priceData.setLastPrice(priceData.getPrice());

        }
    }

    public static void main(String args[]) {

        int period = 2000;
        int delay = 2000;

        PriceData priceData = new PriceData();
        Price priceObject = new Price();

        Timer timer = new Timer();

        timer.scheduleAtFixedRate(new PriceTimerTask(priceData, priceObject), delay, period);
    }
7
ответ дан 23 November 2019 в 03:09
поделиться

Чтобы избежать странных побочных эффектов с замыканиями в java-переменных, на которые ссылается анонимный делегат, они должны быть помечены как окончательные, чтобы ссылаться на lastPrice и цену в пределах задача таймера, они должны быть помечены как окончательные.

Очевидно, это не сработает для вас, потому что вы хотите их изменить, в этом случае вам следует взглянуть на их инкапсуляцию в класс.

public class Foo {
    private PriceObject priceObject;
    private double lastPrice;
    private double price;

    public Foo(PriceObject priceObject) {
        this.priceObject = priceObject;
    }

    public void tick() {
        price = priceObject.getNextPrice(lastPrice);
        lastPrice = price;
    }
}

теперь просто создайте новый Foo как final и вызовите .tick из таймера.

public static void main(String args[]){
    int period = 2000;
    int delay = 2000;

    Price priceObject = new Price();
    final Foo foo = new Foo(priceObject);

    Timer timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask() {
        public void run() {
            foo.tick();
        }
    }, delay, period);
}
31
ответ дан 23 November 2019 в 03:09
поделиться

Хорошие объяснения того, почему вы не можете делать то, что пытаетесь сделать, уже предоставлены. В качестве решения, возможно, рассмотрите:

public class foo
{
    static class priceInfo
    {
        public double lastPrice = 0;
        public double price = 0;
        public Price priceObject = new Price ();
    }

    public static void main ( String args[] )
    {

        int period = 2000;
        int delay = 2000;

        final priceInfo pi = new priceInfo ();
        Timer timer = new Timer ();

        timer.scheduleAtFixedRate ( new TimerTask ()
        {
            public void run ()
            {
                pi.price = pi.priceObject.getNextPrice ( pi.lastPrice );
                System.out.println ();
                pi.lastPrice = pi.price;

            }
        }, delay, period );
    }
}

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

13
ответ дан 23 November 2019 в 03:09
поделиться

Вы можете получить доступ только к final переменные из содержащего класса при использовании анонимного класса. Поэтому вам необходимо объявить используемые переменные final (это не вариант для вас, поскольку вы меняете lastPrice и price ) или не используйте анонимный класс.

Итак, вы можете создать реальный внутренний класс, в который вы можете передавать переменные и использовать их обычным образом

или:

Существует быстрый (и, на мой взгляд, уродливый) способ взлома вашего lastPrice и price переменная, которая должна объявить это так

final double lastPrice[1];
final double price[1];

, и в вашем анонимном классе вы можете установить значение, подобное этому

price[0] = priceObject.getNextPrice(lastPrice[0]);
System.out.println();
lastPrice[0] = price[0];
18
ответ дан 23 November 2019 в 03:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: