A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 王红潮 中级黑马   /  2012-9-7 16:36  /  1573 人查看  /  6 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

import java.util.Arrays;
interface IntArrayProductor{
int product();
}
public class CommandTest {
public int[] process(IntArrayProductor cmd , int length){
  int[] result = new int[length];
  for(int i=0;i<length;i++){
   result[i] = cmd.product();
  }
  return result;
}
/**
  * @param args
  */
public static void main(String[] args) {
  CommandTest ct = new CommandTest();
  final int s = 5; //为什么内部类能访问局部变量必须用final修饰
  int[] result = ct.process(new IntArrayProductor(){
   public int product(){
    return (int)Math.round(Math.random() * s);
   }
   
  }, 6);
  
  System.out.println(Arrays.toString(result));
}
}

视频里当时讲了内部类访问局部变量必须用final修饰,只是记住了,但写的时候不知道原理总出问题,为什么必须用final修饰,最好举个简单的例子,谢谢。

6 个回复

倒序浏览
本帖最后由 应广驰 于 2012-9-7 17:00 编辑

不是内部类只能访问final修饰的变量,内部类定义在成员位置时是可以使用所有成员变量的

只有当内部类定义在成员内部时才可以只调用final修饰的变量,因为局部内部类定义在方法中,方法调用结束,局部变量的生命周期就结束了,而局部内部类可能还存在,局部内部类如果可以调用非final修饰 局部变量,那没这些变量就有可能根本不存在
回复 使用道具 举报
当利用final修饰一个属性(变量)的时候,此时的属性成为常量。(即题当中)
常量的地址不可改变,但在地址中保存的值(即对象的属性)是可以改变的。
这样写了就相当于实例变量,局部变量要先赋值,再进行运算,而实例变量均已经赋初值。这是局部变量和实例变量的一大区别。
尤其在内部类当中,如果没有加final,jvm运行后变量不存在的,当运行内部类时,一旦用到变量,就会抛异常。
所以,就可以按照局部变量和实例变量来理解,主要是在未调用变量之前内存中就保存地址。最浅显的列子我暂时还没有想到
回复 使用道具 举报
应广驰 发表于 2012-9-7 16:50
不是内部类只能访问final修饰的变量,内部类定义在成员位置时是可以使用所有成员变量的

只有当内部类定义 ...

加了final的作用只是局部变量不能改变,但如果局部变量的生命周期结束了,它在内存中就应该消失了,如果局部内部类还存在,他就不能继续访问这个局部变量啊?还是说在底层,局部内部类中也有了一个局部变量与生命周期结束的那个局部变量相同,但没有关系了?
回复 使用道具 举报
本帖最后由 杨习平 于 2012-9-7 18:35 编辑

1:内部类
        (1)把一个类定义在某个类中的,这个类就被称为内部类,内置类,嵌套类。
        (2)访问形式:
                A:内部类可以直接访问外部类中的成员。
                B:外部类要想访问内部类的成员,必须创建对象访问。
        (3)什么使用时候内部类呢?
                假如有A类和B类,A类想直接访问B类的成员,B类访问A类成员的时候,
                需要创建对象访问,这个时候,就可以把A类定义为B类的内部类。
        (4)内部类的位置
                A:成员位置
                        **可以被private修饰(Body,Heart)
                        **可以被static修饰。(它访问的外部类的成员必须是静态的)
=========例子:
                class Outer
                {
                        int num = 10;

                        class Inner
                        {
                                public void show()
                                {
                                        sop(num);
                                }
                        }        

                        public void method()
                        {
                                Inner i = new Inner();
                                i.show();
                        }
                }

                注意:
                        如果测试类中想直接访问内部类,格式如下
                        外部类名.内部类名 对象名 = 外部类对象.内部类对象;
                        Outer.Inner oi = new Outer().new Inner();

                        假如内部类使用static修饰的,在测试类中使用,格式如下
                        外部类名.内部类名 对象名 = new 外部类.内部类();
                        Outer.Inner oi = new Outer.Inner();
               
                B:局部位置(匿名类的标准位置)
                        **可以直接访问外部类中的成员,也可以直接访问局部成员,但是
                          局部成员要用final修饰。
==============例子:               
                class Outer
                {
                        int num = 10;

                        public void method()
                        {
                                int num2 = 20;
                                final int num3 = 30;

                                class Inner
                                {
                                        public void show()
                                        {
                                                sop(num3);
                                        }
                                }

                                Inner i = new Inner();
                                i.show();
                        }
                }

                注意:
                  局部内部类不能用private和static修饰。
     
                A:成员位置
                        **可以被private修饰(Body,Heart)
                        **可以被static修饰。(它访问的外部类的成员必须是静态的)
              B:局部位置(匿名类的标准位置)
                        **可以直接访问外部类中的成员,也可以直接访问局部成员,但是
                          局部成员要用final修饰。
回复 使用道具 举报
局部内部类(包括匿名内部类和普通内部类)使用局部变量,被局部类访问的局部变量都是用final修饰,对于普通局部变量他的作用域就是该方法内,当方法结束该局部变量就随之结束:
   public class Test{
        pubic static void main(){
       final String str="abc";
       new Thread(new Runnable(){
               public void run(){
          for(int i=0;i<100;i++){
              System.out.printlln("str"+str+"-----"+i);
}
}

}).start():
   

}


}
回复 使用道具 举报
局部变量是定义在局部函数里面的,当该函数出栈后,局部变量就释放了,但是你这的类里面还用到了这个变量,这就出问题了。
你把局部变量用final修饰后,它会存在在方法区的常量池中,随着类的加载而加载,就不会在局部函数出栈后就释放掉了。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马