由一个android的getView方法侦听引出的对final的理解

在android自定义adapter的时候,在getView方法里面设置一个控件的侦听,发现在侦听里面我们使用不了局部变量position
定义一个final变量index,然后在侦听里面使用index发现可以
在形参position前面加上final修饰也可以

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final int index = position;
        ViewHolder holder = null;
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.item1, null);
            holder = new ViewHolder();
            holder.textView = (TextView)convertView.findViewById(R.id.text);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder)convertView.getTag();
        }
        holder.textView.setText(mData.get(position));
        convertView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                System.out.println(this);
                System.out.println("位置:" + index);//我们要访问的位置
            }
        });
        return convertView;
    }

由上面的现象引发我对final的理解,我们设置侦听,new了匿名的对象,实现了OnClickListener接口。
那么我们为什么在内部类访问函数的局部变量的时候要加final修饰呢?

其实是编译器在编译内部类的class文件时,偷偷做了一些工作, 使内部类持有外部类的引用, 并且通过在构造方法上添加参数注入这个引用, 在调用构造方法时默认传入了外部类的引用。

访问局部变量有2种情况:
a、当被访问的局部变量是编译时可确定的字面常量时。
1 在外部类的main方法中有一个局部变量count, 并且在内部类的run方法中访问了这个count变量。 也就是说, 方法中定义的内部类, 可以访问方法中的局部变量(方法的参数也是局部变量);
2 count变量使用final关键字修饰, 如果去掉final, 则编译失败。 也就是说被方法中的内部类访问的局部变量必须是final的。

例如count=0,就是已经确定的
一段演示代码:
     public class Test {  

        public static void main(String[] args) {  
            final int count = 0;  

            new Thread(){  
                public void run() {  
                    int var = count;  
                };  
            }.start();  
        }  
    } 
当内部类中访问的局部变量是int型的字面量时, 编译器直接将对该变量的访问嵌入到内部类的字节码中, 
也就是说, 在运行时, 方法中的内部类和外部类, 和外部类方法中的局部变量就没有任何关系了。 
这也是编译器所做的额外工作。

b、当被访问的局部变量的值在编译时不可确定时。
由于使用getString方法的返回值为localVar赋值, 所以在编译时期, 编译器不可确定localVar的值, 必须在运行时执行了getString方法之后才能确定它的值。 既然编译时不不可确定, 那么像上面那样的处理就行不通了。 那么在这种情况下, 内部类是通过什么机制访问方法中的局部变量的呢?

    public class Outer {  
        void outerMethod(){  
            final  String localVar = getString();  

            /*定义在方法中的内部类*/  
            class Inner{  
                void innerMethod(){  
                    String a = localVar;  
                }  
            }  

            new Inner();  
        }  

        String getString(){  
            return "aa";  
        }  
    }
当方法中定义的内部类访问的方法局部变量的值, 不是在编译时能确定的字面常量时, 编译器会为内部类增加一个成员变量, 
在运行时, 将对外部类方法中局部变量的访问。 转换成对这个内部类成员变量的方法。 
这就要求内部类中的这个新增的成员变量和外部类方法中的局部变量具有相同的值。 
编译器通过为内部类的构造方法增加参数, 并在调用构造器初始化内部类对象时传入这个参数, 来初始化内部类中的这个成员变量的值。 
所以, 虽然在源文件中看起来是访问的外部类方法的局部变量, 其实运行时访问的是内部类对象自己的成员变量。
就类似局部变量的localVar时,实际是通过参数传过去的。

所以为什么要定义final,就是因为需要让他们都不能再指向其他对象(被final修饰), 所以可以保证内部类和外部类数据访问的一致性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值