java中的内部类又分为三类:普通内部类和普通匿名类、嵌套类(静态内部类)、局部类(局部作用域、方法中的内部类与匿名类)。
1.普通内部类和普通匿名类
</pre><pre name="code" class="java">下面的demo_1展示普通的内部类的使用,它对外部变量(基本类型int i 和对象String s)的访问和修改是不受限制的,
另外普通内部类的创建必须依赖于外部类的某个实例对象:
public class InnnerClassAccessOuterFields {
public static void main(String[] args) {
//声明和使用普通内部类:
InnnerClassAccessOuterFields innnerClassAccessOuterFields = new InnnerClassAccessOuterFields();
Interface interface1 = innnerClassAccessOuterFields.new InnerClass();
interface1.doSomething();
}
int i = 0;
String s = "aaa";
//定义一个普通内部类:
class InnerClass implements Interface{
@Override
public void doSomething() {
//访问和修改外部类的变量
i = i+1;
s = s + "bbb";
System.out.println(i);
System.out.println(s);
}
}
}
输出:
2
aaabbb
下面的demo_2展示普通的匿名类的使用,它对外部变量(基本类型int i 和对象String s)的访问和修改是不受限制的:
<pre name="code" class="java">public class NoNameAsFieldAccessOuterFields {
public static void main(String[] args) {
NoNameAsFieldAccessOuterFields noNameAccessOuterFields = new NoNameAsFieldAccessOuterFields();
noNameAccessOuterFields.test();
}
int i = 0;
String s = new String("abc");
/*
* 测试匿名类作为内部成员对象对外部的访问
*/
Interface interface1 = new Interface() {
@Override
public void doSomething() {
i++;
s = s+"def";
System.out.println(i);
System.out.println(s);
}
};
public void test() {
interface1.doSomething();
System.out.println(i);
System.out.println(s);
}
}
输出:
2
abcdef
2
abcdef
2. 嵌套类(静态内部类)
下面的demo_3展示了静态内部类的使用,静态内部类不能访问外部类的非静态成员,因为非静态成员需要对象实例化后才可访问,而静态内部类可以不依赖外部类的实例而存在(它只依赖外部类对应的Class对象的存在)。
public class StaicInnerClassTest {
public static void main(String[] args) {
//声明和使用普通内部类:
Interface staticInnerClass = new StaicInnerClassTest.StaticInnerClass();
staticInnerClass.doSomething();
}
static int i = 1;
int j = 1;
//定义一个静态内部类:
static class StaticInnerClass implements Interface{
@Override
//静态内部类不可以访问外部类的非静态成员
public void doSomething() {
i++;
System.out.println(i);
}
}
}
3. 局部类(局部内部类,局部匿名类)
注:这里的局部是指位于外部类的某个非静态作用域(即:{})或非静态方法中。
局部类(包括局部内部内和局部匿名类)访问和修改外部类的变量同样是不受限制的。
局部类只能读到其所在作用域和方法中是局部变量,并且一旦编译器发现局部类有这种操作就会阻止任何地方对这个局部变量做修改操作,即:
局部类访问局部变量会迫使该变量变成语义上final的(不要求必须用final修饰,只是编译器不允许修改)。下面解释原因:
由于局部作用域和方法在编译时直接编译为一串java字节码作为在外部类的一部分,而类在使用前必须先加载(局部类也不例外,只不过可见性被限制在了局部作用域和方法中),因此编译器将局部类同普通类一样编译,这样就出现了一个问题:一个类访问了另一个类的方法中的某个局部变量,臣妾做不到哇~~。但是,为了体现java的强大, 不能因此就要放弃局部类的支持。于是,工程师们脑洞大开,偷偷的给局部类装了一个类似于构造方法的东西,将其要访问的局部变量传给局部类的对象实例,这样似乎就解决了问题。但是的但是,不要忘了,java只支持值传递,即他们传给局部类对象的只是局部变量的一个拷贝,这使得局部作用域内和内部类对象里对局部变量的修改不能相互感知到(我擦,好绕~ 。意思大概就是:你玩你的我玩我的,我们互不理睬)。这下工程师们彻底没招了,只好用最笨的方法:规定这种变量必须是语义上final的!
下面的demo_4展示了位于作用域中、方法中的内部类的使用方法,及其访问外部类变量时受到的限制:
public class LocalInnerClassAcessOuterFileds {
public static void main(String[] args) {
new LocalInnerClassAcessOuterFileds().test(100,"xxx");
}
int i = 0;
String s = "aaa";
public void test(int iP, String sP) {
int iP2 = 200;
String sP2 = "yyy";
class Inner{
{
i++;
s = s+"bbb";
System.out.println(i);
System.out.println(s);
//Local variable iP defined in an enclosing scope must be final or effectively final
//iP++;
System.out.println(iP);
//Local variable sP defined in an enclosing scope must be final or effectively final
//sP = sP;
System.out.println(sP);
//Local variable iP2 defined in an enclosing scope must be final or effectively final
//iP2++;
System.out.println(iP2);
//Local variable sP2 defined in an enclosing scope must be final or effectively final
//sP2=sP2;
System.out.println(sP2);
}
}
new Inner();//迫使Inner类被加载
System.out.println(i);
System.out.println(s);
//在局部作用于内部类或匿名类中访问的变量不可以再被修改:
//iP2++;
//在局部作用于内部类或匿名类中访问的对象引用不可以再被修改:
//sP2 = sP2;
}
{
int iL = 1000;
String sL = "qqq";
class Inner{
{
//Local variable iL defined in an enclosing scope must be final or effectively final
//iL++;
System.out.println(iL);
}
}
new Inner();//迫使Inner类加载,并执行初始化
//局部作用域的内部类使用的变量不可再改变
//iL++;
System.out.println(iL);
}
}
输出:
1000
1000
1
aaabbb
100
xxx
200
yyy
1
aaabbb
局部匿名类的情况同上,我不贴代码,也不说话。。。