内部类初探

一、什么是内部类?

  内部类是指在一个外部类的内部再定义一个类。内部类作为外部类的一个成员,并且依附于外部类而存在的。内部类可为静态,可用protected和private修饰(而外部类只能使用public和缺省的包访问权限)。内部类主要有以下几类:成员内部类、局部内部类、静态内部类、匿名内部类

二、内部类的共性

(1)内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号 。

(2)内部类不能用普通的方式访问。

(3)内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量 。

(4)外部类不能直接访问内部类的的成员,但可以通过内部类对象来访问

  内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的。

  因为当某个外围类的对象创建内部类的对象时,此内部类会捕获一个隐式引用,它引用了实例化该内部对象的外围类对象。通过这个指针,可以访问外围类对象的全部状态。

通过反编译内部类的字节码,分析之后主要是通过以下几步做到的:

  1 编译器自动为内部类添加一个成员变量, 这个成员变量的类型和外部类的类型相同, 这个成员变量就是指向外部类对象的引用;

  2 编译器自动为内部类的构造方法添加一个参数, 参数的类型是外部类的类型, 在构造方法内部使用这个参数为1中添加的成员变量赋值;

  3 在调用内部类的构造函数初始化内部类对象时, 会默认传入外部类的引用

二、使用内部类的好处:

静态内部类的作用:

1 只是为了降低包的深度,方便类的使用,静态内部类适用于包含类当中,但又不依赖与外在的类。

2 由于Java规定静态内部类不能用使用外在类的非静态属性和方法,所以只是为了方便管理类结构而定义。于是我们在创建静态内部类的时候,不需要外部类对象的引用。

非静态内部类的作用:

1 内部类继承自某个类或实现某个接口,内部类的代码操作创建其他外围类的对象。所以你可以认为内部类提供了某种进入其外围类的窗口。

2 使用内部类最吸引人的原因是:每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响

3 如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。 从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了”多重继承”。

三、 那静态内部类与普通内部类有什么区别呢?问得好,区别如下:

(1)静态内部类不持有外部类的引用 在普通内部类中,我们可以直接访问外部类的属性、方法,即使是private类型也可以访问,这是因为内部类持有一个外部类的引用,可以自由访问。而静态内部类,则只可以访问外部类的静态方法和静态属性(如果是private权限也能访问,这是由其代码位置所决定的),其他则不能访问。

(2)静态内部类不依赖外部类 普通内部类与外部类之间是相互依赖的关系,内部类实例不能脱离外部类实例,也就是说它们会同生同死,一起声明,一起被垃圾回收器回收。而静态内部类是可以独立存在的,即使外部类消亡了,静态内部类还是可以存在的。

(3)普通内部类不能声明static的方法和变量 普通内部类不能声明static的方法和变量,注意这里说的是变量常量(也就是final static修饰的属性)还是可以的,而静态内部类形似外部类,没有任何限制

==为什么普通内部类不能有静态变量呢?==

1 成员内部类 之所以叫做成员 就是说他是类实例的一部分 而不是类的一部分

2 结构上来说 他和你声明的成员变量是一样的地位 一个特殊的成员变量 而静态的变量是类的一部分和实例无关

3 你若声明一个成员内部类 让他成为主类的实例一部分 然后又想在内部类声明和实例无关的静态的东西 你让JVM情何以堪啊

4 若想在内部类内声明静态字段 就必须将其内部类本身声明为静态

非静态内部类有一个很大的优点:可以自由使用外部类的所有变量和方法

下面的例子大概地介绍了

1 非静态内部类和静态内部类的区别。

2 不同访问权限的内部类的使用。

3 外部类和它的内部类之间的关系

//本节讨论内部类以及不同访问权限的控制
//内部类只有在使用时才会被加载。
//外部类B
public class B{
   int i = 1;
   int j = 1;
   static int s = 1;
   static int ss = 1;
   A a;
   AA aa;
   AAA aaa;
   //内部类A

   public class A {
//       static void go () {
//
//       }
//       static {
//
//       }
//     static int b = 1;//非静态内部类不能有静态成员变量和静态代码块和静态方法,
       // 因为内部类在外部类加载时并不会被加载和初始化。
       //所以不会进行静态代码的调用
       int i = 2;//外部类无法读取内部类的成员,而内部类可以直接访问外部类成员

       public void test() {
           System.out.println(j);
           j = 2;
           System.out.println(j);
           System.out.println(s);//可以访问类的静态成员变量
      }
       public void test2() {
           AA aa = new AA();
           AAA aaa = new AAA();
      }

  }
   //静态内部类S,可以被外部访问
   public static class S {
       int i = 1;//访问不到非静态变量。
       static int s = 0;//可以有静态变量

       public static void main(String[] args) {
           System.out.println(s);
      }
       @Test
       public void test () {
//           System.out.println(j);//报错,静态内部类不能读取外部类的非静态变量
           System.out.println(s);
           System.out.println(ss);
           s = 2;
           ss = 2;
           System.out.println(s);
           System.out.println(ss);
      }
  }

   //内部类AA,其实这里加protected相当于default
   //因为外部类要调用内部类只能通过B。并且无法直接继承AA,所以必须在同包
   //的类中才能调用到(这里不考虑静态内部类),那么就和default一样了。
   protected class AA{
       int i = 2;//内部类之间不共享变量
       public void test (){
           A a = new A();
           AAA aaa = new AAA();
           //内部类之间可以互相访问。
      }
  }
   //包外部依然无法访问,因为包没有继承关系,所以找不到这个类
   protected static class SS{
       int i = 2;//内部类之间不共享变量
       public void

相关文章: