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

        final int receiverUserId = sendMessageRequest.getReceiverUserId();
        final int senderUserId = sendMessageRequest.getSenderUserId();
        final int replyTo = sendMessageRequest.getReplyTo();
        final int subsiteId = sendMessageRequest.getRelatedSubsiteId();
        final String message = sendMessageRequest.getMessage();


        KeyHolder keyHolder = new GeneratedKeyHolder();
        jdbcTemplateObject.update(
                new PreparedStatementCreator() {

                    public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
                        PreparedStatement ps =
                                connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
                        ps.setInt(1, senderUserId);
                        ps.setInt(2, receiverUserId);
                        ps.setInt(3, replyTo);
                        ps.setInt(4, subsiteId);
                        ps.setString(5, message);
                        return ps;
                    }
                },
                keyHolder
        );
        return true;

В приведенном выше коде, если я удаляю final из одной из переменных, которые я использую для установки PreparedStatement, он говорит "" is accessed from within inner class, needs to be declared final.

Я понимаю, что java предупреждает меня объявить final, поэтому я не могу изменить переменную позже и сломать PreparedStatementCreater, экземпляр которого я только что сделал. Я читал похожие темы в stackoverflow, но до сих пор не могу понять. Я проверил функцию ps.setInt, ее аргументы имеют тип int. Поэтому они передаются по значению. Я просто не могу изменить их значение в любом случае. Я действительно не понимаю, почему меня предупреждают здесь. Можете ли вы помочь мне понять?


person Ozum Safa    schedule 30.11.2014    source источник
comment
Это не имеет ничего общего с PreparedStatement. Вы используете эту переменную в анонимном классе, поэтому она должна быть окончательной. Прочтите этот ответ для получения дополнительной информации.   -  person Tom    schedule 30.11.2014


Ответы (1)


Здесь вообще ничего не передается (с точки зрения переменных, на которые жалуется компилятор) — и в любом случае в Java все передается по значению, будь то ссылка или примитивное значение.

Проблема в том, что вы пытаетесь использовать локальную переменную из внешней области внутри анонимного внутреннего класса - и вы просто не можете этого сделать, если переменная не final, по крайней мере, до Java 7. Начиная с Java 8 , вы обнаружите, что это сработает, потому что переменная будет фактически final — вы просто не сможете изменить значение переменной ни во внешней, ни во внутренней области.

Что касается почему локальные переменные, используемые в теле анонимного внутреннего класса, должны быть окончательными — насколько я могу судить, это нужно для того, чтобы избежать путаницы — и, возможно, для упрощения реализации. Вполне возможно разработать язык, в котором переменные в замыканиях могут быть изменяемыми (например, C#), но модель Java создает экземпляр анонимного внутреннего класса с копией все переменные, используемые в теле анонимного внутреннего класса. Это просто понять (вы не можете наблюдать какие-либо изменения, потому что вам не разрешено их вносить), и это означает, что вы не сгенерируете дополнительные классы только для хранения переменных, которые используются во внешней области.

person Jon Skeet    schedule 30.11.2014
comment
Так это в основном, чтобы помешать мне думать, что я могу изменить значение переменных внутреннего класса внутри внешней области? - person Ozum Safa; 30.11.2014
comment
@Ozum: Или наоборот. - person Jon Skeet; 30.11.2014