内部类

来源:互联网 发布:ipad看淘宝不能横屏 编辑:程序博客网 时间:2024/04/26 07:43

1.内部类:把一个类放在另一个类的内部定义,定义在其它类内部的类叫内部类(嵌套类),包含内部类的类叫做外部类(宿主类)。

2.内部类的作用:1.提供了更好地封装,把内部类隐藏在外部类之中,不允许同一包中的其它类访问该类。

                                2.内部类可以直接访问外部类的私有数据,因为内部类被当成外部类成员,同一个类成员之间可以相互访问。但外部类不能访问内部类的实现细节,如内部类属性。

                                3.匿名内部类适合那些仅需要使用一次的类

3.内部类一般被当做成员内部类被定义,而不是局部内部类,成员内部类是一种与属性,方法,构造器,和初始化块相似的类成员。局部内部类和匿名内部类不是类成员

   成员内部类:静态内部类和非静态内部类

                         外部类的上一级程序单元是包,所以有两个作用域:同一个包中/任何位置。因此只需要两种访问权限,包访问权限和公开访问权限。                         

                         内部类的上一级程序单元是外部类,所以有四个作用域:同一个类中,同一个包中,父子类,和任何位置,因此可以使用四种访问权限。

4.非静态内部类里可以直接访问外部类的private 成员,这是因为在非静态内部类里保存了一个它寄存的外部类对象的引用:当调用一个非静态内部类实例方法时,必须有一个非静态内部类的实例,而非静态内部类实录必须寄存在外部类实例里。

   非静态内部类的成员可以访问外部类的private 成员,非静态内部类成员只在非静态内部类范围内是可知的,并不能被外部类直接使用,如果外部类需要访问非静态内部类成员,必须显示创建非静态内部类对象来调用访问其实例成员。

  访问外部类的实例属性通过:OuterClass.this.propName 访问非静态内部类的实例属性通过this。propName形式进行访问

   java不允许非静态内部类里定义静态成员。否则编译引起错误

非静态内部类对象和外部类对象的关系:

非静态内部类对象必须寄存在外部类对象里,而外部类对象不一定有非静态内部类对象寄存,如果存在一个非静态内部类对象,则一定存在被它寄存的外部类对象,但外部类对象存在时,外部对象里不一定寄存了非静态内部类对象,因此外部类对象访问内部类成员时,可能非静态普通内部类对象根本不存在,而非静态内部类对象访问外部类成员时,外部类对象一定是存在的。

静态内部类:

1.Static修饰内部类,使内部类变成是外部类类相关的。属于整个外部类,而不是单独属于外部类的某个对象。因此使用static修饰的内部类被称为类内部类(静态内部类)

  Static 关键字的作用是把类的成员变成类相关,而不是实例相关。外部类的上一级程序单元式包,所以不可使用static 修饰,而内部类上一级程序单元是外部类,使用static 修饰可以将内部类变成外部类相关,因此static 不可以修饰外部类,可以修饰内部类。

2.静态内部类可以包含静态成员,也可以包含非静态成员。

  根据静态成员不能访问非静态成员的规则:

                             静态内部类不能访问外部类的实例成员,只能访问外部类的静态成员。即使内部类的实例方法也不能访问外部类的实例成员。

 

为什么静态内部类实例方法也不能访问外部类的实例属性:

因为静态内部类是外部类的类相关的,而不是外部类的对象相关的。静态内部类的对象不是寄存在外部类对象里,而是寄存在外部类的类本身中,也就是说,当静态内部类的对象存在时,并不存在一个被它寄存的外部类对象,静态内部类的对象里只有外部类的类引用,没有外部类的对象引用,如果允许静态内部类的实例方法访问外部类的实例成员,但找不到被寄存的外部类对象,将引起错误

3.外部类依然不能直接访问静态内部类的成员,但可以使用静态内部类的类名作为调用者来访问静态类的类成员,也可以使用静态内部类的对象作为调用者来访问静态内部类的实例成员。

4.允许在接口里定义内部类,接口里定义的内部类默认使用public static 修饰符,也就是说接口内部类只能是静态内部类。

 

使用内部类:

1.在外部类内部使用内部类:

在外部类的内部使用内部类时,与平常使用普通类没有太大的区别,通过new调用内部类构造器来创建实例,唯一存在区别的是:不要在外部类的静态成员中(静态方法和静态初始化块)中使用非静态内部类,因为静态成员不能访问非静态成员。

2.在外部类以外使用非静态内部类

  

如果希望在外部类以为的地方访问内部类,(包括静态和非静态两种),则内部类不能使用private访问控制权限:在外部类以外的地方定义内部类(包括静态和非静态两种):OUterClass.InnerClass  varName 在外部类以外地方使用内部类时,内部类完整的类名应该是:包名.OuterClass.InnerClass

因为非静态内部类的对象必须寄存在外部类的对象里,因此创建非静态内部类对象之前,必须先创建其外部类的对象,在外部类以外的地方创建非静态内部类实例的语法:

OuterInstance.new  InnerConstructor();

Class Out{

  Class in{

        Public in(String msg){

               System.out.println(msg);

}

}

 

}

Public class CreateInnerInstance{

 Public static void main(){

   Out.in in = new Out().new in(“aaa”);

}

}

非静态内部类的构造器必须使用外部类对象来调用。

在外部类以外地方创建非静态内部类的子类,注意:非静态内部类的构造器必须使用外部类对象来调用。

当创建一个子类时,子类构造器总会调用父类的构造器,因此创建非静态内部类的子类时,必须保证子类构造器可以调用非静态内部类的构造器,调用非静态内部类的构造器时,必须存在一个外部类对象。

Public class SubClass extends Out.in{

Public SubClass(Out out){

    //通过传入的Out对象显示调用in的构造器

     Out.super(“aaa”);

}

}

非静态内部类in的构造器必须使用外部类对象来调用,代码中super代表in类的构造器,而out则代表了外部类对象

从上面代码可以看出,如果需要创建SubClass对象时,必须先创建一个Out对象,这是合理的,因为SubClass是非静态内部类in类的子类,非静态内部类in对象里必须有一个对out对象的引用,其子类SubClass对象里也应该存在一个out对象的引用,当创建SubClass对象时传递给该构造器的Out对象,就是SubClass对象里Out对象引用所指向的对象。

非静态内部类in对象和SubClass对象都必须保留有指向Outer对象的引用,区别是创建两种对象时传入out对象的方式不同:当创建非静态内部类in类对象时,必须通过Outer对象调用new关键字;当创建SubClass类对象时,必须将Outer对象作为参数传给SubClass构造器。

非静态内部类的子类不一定是内部类,它可以是一个顶层类,但非静态内部类的子类的实例一样需要保留一个引用,该引用指向其父类所在外部类的对象,也就是说,如果有一个内部类子类的对象存在,则一定存在于之对应外部类对象。

3.在外部类以外使用静态内部类:

因为静态内部类是外部类类相关的,因此创建内部类对象时无需创建外部类对象

在外部类以外地方创建静态内部类实例语法如下:

Class Staticout{

 Static class StaticIn{

   Public StaticIn(){

    

}

 

}

}

Public class CreateStaticInnerInsatance{

   Public static void main(String[] args){

       StaticOut.StaticIn in = new StaticOut.StaticIn();               

}

}

不管是静态内部类还是非静态内部类,它们声明变量的语法完全一样,区别只是在创建内部类对象时,前者需要使用外部类来调用构造器,后者必须使用外部类对象来调用构造器

因为调用静态内部类的构造器时无需使用外部类对象,所以创建静态内部类的子类也比较简单:public class StaticSubClass extends StaticOut.Staticin{}

既然内部类是外部类的成员,是否可以为外部类定义子类,在子类中再定义一个内部类来重写其父类中的内部类?

不可以,内部类的类名不再是简单的由内部类的类名组成,它实际上还把外部类作为一个命名空间,作为内部类类名的限制,因此子类中内部类和父类中内部类不可能完全同名,即使二者所包含的内部类的类名相同,但因为它们所处的外部类空间不同,所以它们不可能是同一个类,也就不可能重写

 

4.    局部内部类

  把内部类放在方法里定义,局部内部类仅在该方法里有效,因此局部内部类不能再外部类以外的地方使用,也不能使用访问控制符和Static修饰符修饰。

   对于局部成员而言,不管是局部变量还是局部内部类,它们的上一级程序单元式方法,而不是类,使用static修饰它们没有任何意义,因此所有局部变量都不能使用static修饰,不仅如此,因为局部成员的作用域是所在的方法,其他程序单元永远不可能访问另一个方法中的局部变量,所以所有局部成员都不能使用访问控制修饰符

5.匿名内部类:

1.适合只需要一次使用的类

      不能重复使用,new 父类构造器(实参列表)|实现接口(){

              //匿名内部类的类体部分

}

匿名内部类必须继承一个父类或实现一个接口,但最多只能继承一个父类或实现一个接口。

两条规则:匿名内部类不能是抽象类,因为系统在创建匿名内部类的时候,会立即创建匿名内部类的对象,因此不允许匿名内部类定义成抽象类

 匿名内部类不能定义构造器,因为匿名内部类没有类名,所以无法定义构造器,但匿名内部类可以定义实例化初始块,通过实例化处室块来完成构造器需要完成的事情。定义匿名内部类无需class关键字,而是在定义匿名内部类时直接生成该匿名内部类的对象,由于匿名内部类不能是抽象的,所以匿名内部类必须实现它的抽象父类或者接口里包含的所有抽象方法

当通过实现接口来创建匿名内部类时,匿名内部类也不能显示创建构造器,因为匿名内部类只有一个隐式,所有new接口后括号里不能传入参数值。

但如果通过继承来创建匿名内部类时,匿名内部类将拥有和父类相似的构造器,此处的相似指的是拥有相同的形参列表

如果匿名内部类需要访问外部类的局部变量,则必须使用final修饰符来修饰外部类的变量,否则系统将报错