黑马程序员技术交流社区

标题: 内部类成员怎么定义? [打印本页]

作者: sanguodouble1    时间: 2014-4-18 09:57
标题: 内部类成员怎么定义?
本帖最后由 sanguodouble1 于 2014-4-19 17:19 编辑

虽然我了解,非静态内部类不能定义静态成员变量(因为非静态内部类要依靠外部类实例存在,这与静态成员变量相矛盾)。
但我不理解,为什么static final 就可以了

代码如下所示:
  1. class Outer {
  2.         public void outMethod() {
  3.                 int outI = 10;
  4.                 class Inner {
  5.                         static int a = 5;  //编译报错
  6.                         static final int b = 10;  //编译不报错
  7.                 }
  8.         }
  9. }
复制代码
网上有人说,static final 在类加载时就被加载了,这句话在内部类中我无法理解,

求高手解释



作者: skill20    时间: 2014-4-18 10:14
本帖最后由 skill20 于 2014-4-18 10:25 编辑
  1. class Outer {
  2.         public void outMethod() {
  3.                 int outI = 10;
  4.                 class Inner {
  5.                         static int a = 5;  //这是一个变量;
  6.                         static final int b = 10;  //这是一个常量;常量是不是只要在其作用域就可以随便放?这里有static或没static都一样。
  7.                 }
  8.         }
  9. }
复制代码

作者: Sniper_qiu    时间: 2014-4-18 10:20
static final用来修饰成员变量和成员方法,可简单理解为“全局常量”!
对于变量,表示一旦给值就不可修改,并且通过类名可以访问。
对于方法,表示不可覆盖,并且可以通过类名直接访问。
作者: sanguodouble1    时间: 2014-4-18 10:38
本帖最后由 sanguodouble1 于 2014-4-18 10:49 编辑
skill20 发表于 2014-4-18 10:14

可是单单final的生命期和普通变量是一样的啊(这个是其他地方查到的),
而static的生命周期在类一被加载就存在了。
所以,static final的生命周期也是类一被加载就存在了,但这与非静态类的生命周期相矛盾,
请问这个怎么解释?

换个问法,你说static final是常量,对,这个没问题。
问题是你把常量放在非静态内部类里,这个根本就是一个矛盾体啊,
就好比你能把一个static final 放在非静态方法里吗?答案当然是不能,因为非静态方法是要依靠类实例来存在的,在他还不存在的时候,里面就有一个已经存在的常量了,这根本就是荒谬。
但现在,你竟然说一个非静态内部类,可以放常量了,凭什么?



作者: sanguodouble1    时间: 2014-4-18 10:39
Sniper_qiu 发表于 2014-4-18 10:20
static final用来修饰成员变量和成员方法,可简单理解为“全局常量”!
对于变量,表示一旦给值就不可修改 ...

问题是final的生命期和普通变量是一样的啊(这个是其他地方查到的),
而static的生命周期在类一被加载就存在了。
所以,static final的生命周期也是类一被加载就存在了,但这与非静态类的生命周期相矛盾,
请问这个怎么解释?
作者: Sniper_qiu    时间: 2014-4-18 11:29
sanguodouble1 发表于 2014-4-18 10:39
问题是final的生命期和普通变量是一样的啊(这个是其他地方查到的),
而static的生命周期在类一被加载就 ...

你这样考虑就行了,static静态,而final是最终,在一起,就表示这是一个静态的最终的变量,用在定义在类加载前就存在的,可以直接用类名访问,而且此方法可以表示在类的外面,也可以定在类内部,静态的可以访问静态的、
作者: sanguodouble1    时间: 2014-4-18 12:03
本帖最后由 sanguodouble1 于 2014-4-18 12:11 编辑
Sniper_qiu 发表于 2014-4-18 11:29
你这样考虑就行了,static静态,而final是最终,在一起,就表示这是一个静态的最终的变量,用在定义在类 ...

兄弟,我不是要记住,我问的是原理

你就直接解释为什么
在非静态方法里 static final int a =0错的
而在非静态内部类 static final int a =0却是对的

因为这两个的生命的出生期都是一样的,都是需要依靠外部类实例被初始化的,你如果能解释就回答
作者: 清风有意    时间: 2014-4-18 12:24
同求权威解答!
作者: Kelvinhu    时间: 2014-4-18 12:36
  1. 参考链接:http://segmentfault.com/q/1010000000304968
复制代码

{:3_50:}这答案我也不会。。百度学习了下,这个答案说的不错:

每一个非静态内部类,必须维持一个对其外部类实例的应用,这就表明了非静态内部类的作用域是实例级别;而static关键字显式指定某个属性、方法或内部类的作用域是属于类级别。既然二者在语言层面要求的作用域不同,自然无法编译通过。
为什么添加final就可以了呢。final关键字的字面语义就是指明不可变,用在属性上,表示属性一旦赋值后即不可改变。与static关键字合用即表示定义一个常量,从这个角度看有点类似c++中的const。一旦作为常量,其作用域自然不再是实例级别了,而是全局级别了,只是java语言里面没有全局级别的作用域这个概念,类级别作用域其实就只是加了一个访问权限修饰的全局作用域而已。所以编译自然OK。
作者: sanguodouble1    时间: 2014-4-18 13:00
本帖最后由 sanguodouble1 于 2014-4-18 13:01 编辑
Kelvinhu 发表于 2014-4-18 12:36
这答案我也不会。。百度学习了下,这个答案说的不错:

每一个非静态内部类,必须维持一个对其外 ...

照你这个解释,那同样的问题再问你一下好了

你就直接解释为什么
在非静态方法里 static final int a =0错的
而在非静态内部类 static final int a =0却是对的

因为这两者的作用域都是类实例级别的

作者: sanguodouble1    时间: 2014-4-18 13:02
我觉得这个问题可以完美回答的人,应该给10分
作者: Kelvinhu    时间: 2014-4-18 13:12
sanguodouble1 发表于 2014-4-18 13:00
照你这个解释,那同样的问题再问你一下好了

你就直接解释为什么

static只存在于类中,而不是在方法里
作者: Kelvinhu    时间: 2014-4-18 13:17
静态变量属于类,为这个类所有对象而分享,在程序开始执行前就分配空间
作者: sanguodouble1    时间: 2014-4-18 13:17
Kelvinhu 发表于 2014-4-18 13:12
static只存在于类中,而不是在方法里

就是问的你这个,为什么static只存在于类中,而不是在方法里
作者: Kelvinhu    时间: 2014-4-18 13:27
sanguodouble1 发表于 2014-4-18 13:17
就是问的你这个,为什么static只存在于类中,而不是在方法里

因为static属于类啊,那你说方法里的变量作用域在哪里?不就只是在方法里面吗

那static修饰的又在哪里?任何类的实例对象都能访问,是共享的。

这样说难道不对吗 能反驳吗
作者: sanguodouble1    时间: 2014-4-18 13:34
Kelvinhu 发表于 2014-4-18 13:27
因为static属于类啊,那你说方法里的变量作用域在哪里?不就只是在方法里面吗

那static修饰的又在哪里? ...

对啊,就是问你这个啊,


你说static的作用域是类级别,好,
那么static方法里为什么还是不能有static变量呢?
这逻辑有问题吗?
反正都是不需要实例对象就能使用的,为什么我里面不能有static变量呢?
作者: Kelvinhu    时间: 2014-4-18 13:49
本帖最后由 Kelvinhu 于 2014-4-18 14:01 编辑

。。。。。。
作者: Kelvinhu    时间: 2014-4-18 13:50
完了 我已晕。。。坐等答案{:3_63:}不要告诉我这是规定什么的。。。
作者: Kelvinhu    时间: 2014-4-18 13:53
方法内部变量不能被除了Final以外的其他修饰符修饰。。。其他的我就不管了。。。{:3_47:}LZ有新答案了记得告诉下我。。。。
作者: yanzhendong    时间: 2014-4-18 13:54
这应该是java的编程规范规定的,内部类是被当成外部类的成员来看待的,当一个内部类不是非静态时,这个内部类必须依赖于外部类的实例对象,而如果在在内部类定义静态成员时,这个静态成员就不会依赖于外部类实例对象,这与类的成员变量的定义不符。既然java这样规定,我们只要照做就行了,
作者: sanguodouble1    时间: 2014-4-18 14:01
yanzhendong 发表于 2014-4-18 13:54
这应该是java的编程规范规定的,内部类是被当成外部类的成员来看待的,当一个内部类不是非静态时,这个内部 ...

你都没看清问题,
static final int a = 0;这个也是静态成员,也可以不会依赖于外部类实例对象,你怎么解释
作者: yanzhendong    时间: 2014-4-18 14:14
sanguodouble1 发表于 2014-4-18 14:01
你都没看清问题,
static final int a = 0;这个也是静态成员,也可以不会依赖于外部类实例对象,你怎么 ...

java是这样规定的,就像一个java源文件中只能有一个public类一样。

作者: yanzhendong    时间: 2014-4-18 14:17
sanguodouble1 发表于 2014-4-18 14:01
你都没看清问题,
static final int a = 0;这个也是静态成员,也可以不会依赖于外部类实例对象,你怎么 ...

还有,static final int a主要突出的是a是一个常量,前面加不加static都一样,因为类中的常量本来就只有一份,就相当于静态变量一样,
作者: yanzhendong    时间: 2014-4-18 14:29
sanguodouble1 发表于 2014-4-18 13:34
对啊,就是问你这个啊,

被static修饰的变量都是在堆中分配内存,而函数中的变量都是在栈中分配内存,所以不能在函数中使用static

作者: sanguodouble1    时间: 2014-4-18 15:06
yanzhendong 发表于 2014-4-18 14:17
还有,static final int a主要突出的是a是一个常量,前面加不加static都一样,因为类中的常量本来就只有 ...

谁告诉你类中的常量只有一份的?
final常量,如果在非静态方法中,那么方法每次被调用,都会在栈内存中分配一个空间的好么
作者: sanguodouble1    时间: 2014-4-18 15:10
yanzhendong 发表于 2014-4-18 14:29
被static修饰的变量都是在堆中分配内存,而函数中的变量都是在栈中分配内存,所以不能在函数中使用static ...

你说来说去也没说明白为什么在非静态内部类中可以用static final,外部类都没实例化,非静态内部类竟然已经有成员了?

这就好比先有爷爷,然后父亲,再儿子
现在你没爷爷,直接就有儿子了,这逻辑合适吗?

你要老整java规范,那就没法说了,而且java规矩都有他制定的道理, 你如果一定要说java规范
,那你倒是说说他为什么要这样规范?
作者: yanzhendong    时间: 2014-4-18 15:38
sanguodouble1 发表于 2014-4-18 15:10
你说来说去也没说明白为什么在非静态内部类中可以用static final,外部类都没实例化,非静态内部类竟然已 ...

静态常量和静态变量还是有区别的,你不要纠结于这里,就像方法中的内部类只能访问方法中的被final修饰的变量一样,这是语法规定,你只要知道这么一回事就行了,我也解释不清楚,求哪位大神帮忙解释一下:Q
作者: yanzhendong    时间: 2014-4-18 15:46
sanguodouble1 发表于 2014-4-18 15:06
谁告诉你类中的常量只有一份的?
final常量,如果在非静态方法中,那么方法每次被调用,都会在栈内存中分 ...

我说的是类中的常量,不是方法中的常量,方法中的常量和类中的常量还是有区别的,类中的常量是在常量区分配空间,方法中的常量是在栈中分配空间,
作者: sanguodouble1    时间: 2014-4-18 16:07
yanzhendong 发表于 2014-4-18 15:38
静态常量和静态变量还是有区别的,你不要纠结于这里,就像方法中的内部类只能访问方法中的被final修饰的 ...

那我帮你解释一下你的问题,之所以方法内部类不能访问方法的局部变量,

这是因为局部变量和内部类的生命期是不一样的,局部方法在方法调用完后就消失了,而内部类只要有引用,就会一直存在。
这样就会出现,一个存在的内部类,去访问一个已经不存在的局部变量,这不是荒谬吗?
所以为了实现这个需求,java公司就规范内部类可以访问final的局部量,
注意,这时不是访问的这个量的本身,而是访问这个final的拷贝值
比如我在方法内定义一个 final int a = 10;
然后内部类就会把这个a 复制一份,作为自己的成员变量。而原来这个a,在方法调用完后,就消失了。
以后内部类访问的都是他自己的成员变量,但看起来就好像在访问局部变量一样,知道了吗?
而之所以需要什么成final ,是因为实际逻辑考虑的,如果不声明成final,那就可以会存在这种情况:你把一个已经消失的变量值改变了,这不是滑天下之大稽?

话说回来,任何规范都有他的初衷和因果,
是你自己理解不够深入,解释不通,却叫别人不要纠结?

作者: Sniper_qiu    时间: 2014-4-18 21:06
sanguodouble1 发表于 2014-4-18 12:03
兄弟,我不是要记住,我问的是原理

你就直接解释为什么

class Outer {
        public void outMethod() {
                int outI = 10;
                class Inner {
                        static int a = 5;  //编译报错
                        static final int b = 10;  //编译不报错
                }
        }
}
你定义了一个Outer类,这个类中的有个outMethod方法,而该方法中定义了一个内部类Inner,这样的结果就是可以通过outer类调用outmethod方法,即可直接调用outmethod方法中的变量或者方法。简单点理解就是,可以只用inner中的变量或者方法,这样的做法就会导致该程序中的static可有可无。但是,要注意了,final的用法:
首先看2个定义:
内部类的对象:脱离了其外围类的对象就不会存在。
静态变量:作用是让该类的所有对象共享一个状态。

原因分析:
因为你的内部类是非静态的,除了要依靠外部类实例外,还要依赖内部类实例。
而静态变量是不需要构建类实例的,两者是相矛盾的。
而final类型修饰的变量(即常量)可以离开类实例存活一段时间的。
所以final修饰过的不错。
你如果把内部类修饰成静态的就不会报错了。

综上所述:出现这种情况的主要原因,是外部类实例与内部类实例依赖问题。

作者: sanguodouble1    时间: 2014-4-19 07:55
Sniper_qiu 发表于 2014-4-18 21:06
class Outer {
        public void outMethod() {
                int outI = 10;

先纠正你两点
1.内部类只要有引用存在,即使脱离了外围类对象也会存在
2.final类型的声明周期和普通变量是一样的,谁告诉你他可以离开实例存活一段时间的?不要网上随便看点就当公理好不好?存在就意味着可使用,你能在一个方法的外面使用它里面的final量?具体去看29楼

回到主题上:这个问题我其实是问的变量生命期的逻辑问题
你自己也说了“内部类是非静态的,除了要依靠外部类实例外,还要依赖内部类实例。而静态变量是不需要构建类实例的,两者是相矛盾的。”
而static final也是不需要构建实例的,为什么就不矛盾了?





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2