Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this Java code working? compiler doesn't complain about closure

My DialogFragment contains an -initially invisible- OK button and a ListView of clickable items. When any of the ListView items is clicked I set button's visibility to VISIBLE.

This is done through an anonymous OnItemClickListener. The code below works but I don't get why. Since Java does not support closures, I would expect the compiler to complain about button not being final.

Isn't this a typical case of a closure? How come the code below doesn't produce a compiler error?

Thank you

public class AlternativeRoomsDialog extends DialogFragment {

private Button okButton;

static AlternativeRoomsDialog newInstance(String name) {
    AlternativeRoomsDialog f = new AlternativeRoomsDialog();
    return f;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_alternative_rooms, container);
    getDialog().setTitle("Change Room");

    ListView lv = (ListView) view.findViewById(R.id.alternative_rooms_list);
    final adapter = /*some initialization*/;
    lv.setAdapter(adapter);
    lv.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> arg0, View linlay, int position, long id) {
            okButton.setVisibility(View.VISIBLE);
            ListView lv = (ListView) linlay.getParent();
            int total = lv.getChildCount();
            for (int i=0; i< total; i++){
                lv.getChildAt(i).setBackgroundColor(Color.BLUE);
            }
            linlay.setBackgroundColor(Color.GREEN);
        }
    }); 

    // setup OK button
    okButton = (Button) view.findViewById(R.id.btn_ok);
    okButton.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(AlternativeRoomsDialog.this.getActivity(), "ok button clicked", Toast.LENGTH_SHORT).show();
        }
    });
    return view;
}

}

like image 491
kouretinho Avatar asked Mar 21 '23 16:03

kouretinho


2 Answers

The requirement of variables being declared final only applies to local variables, because they are the ones that go out of scope when the method returns. Your button is referenced by a member variable, and there's no need for it to be final: the member won't go anywhere as long as the object exists.

like image 151
Joni Avatar answered Apr 14 '23 14:04

Joni


You don't need to make the instance variable final, that is only the case with local variables. The local variables needs to be final, they are copied to the anonymous class you use inside the method, as instance variables of that class. This is done because the anonymous inner class instance might stay in heap memory, after the method returns. So, it may require to access the variable even after the method stack frame is de-allocated.

Now, since there are 2 copies of the local variables, they can go out of sync, if the local variable is changed outside the anonymous inner class. That would really go weird, that is why it is required to make the local variable final.

As with instance variables, they are instead shared between enclosing class instance, and anonymous inner class instance. So, you don't need to make them final.

like image 21
Rohit Jain Avatar answered Apr 14 '23 15:04

Rohit Jain