Java内部类

* 内部类(inner class)是定义在另一个类中的类。
* 为什么要使用内部类?
    1. 内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据。
    2. 内部类可以对同一个包中的其他类隐藏起来。
    3. 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。




* 使用内部类访问对象的状态
public class Out {
    private String string="nothing";
    private void sys(){
         System.out.println("This is out !");
    }

    public class Inner{
         public void print(){
             sys();
             System.out.println(string);
         }
    }
    public static void main(String[] args) {
         Out.Inner inner=new Out().new Inner();
         inner.print();
    }
}
* 需要注意:虽然Inner类位于Out类的内部,但是并不意味着每个Out都有Inner实例。
* 虽然Inner中没有定义string,但是可以访问外部类的string变量。这是因为:内部类既可以访问自身的数据域,也可以访问外部类的数据域(包括私有变量)。
* 成员内部类也是最普通的内部类,它是外部类的一个成员,所以他是可以无限制的访问外部类的所有 成员属性和方法,尽管是private的,但是外部类要访问内部类的成员属性和方法则需要通过内部类实例来访问。
* 内部类对象总有一个隐式引用(称为outer,注意outer不是关键字,只是为了方便说明),它指向了创建它的外部类对象。所以成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类。
* 外部类的引用在构造器中设置。编译器修改了所有的内部类的构造器,添加个外部类引用的参数。因为在Inner类中没有构造器,所以编译器生成了一个默认的构造器,如下:
public Inner(Out out){
         outer=out;
     }
* 内部类的修饰符可以是public ,protected,private,默认的。

内部类的特殊语法
* 上面我们说内部类有个外部类的引用outer,事实上,使用外部类的引用的表达式如下:
*
* OuterClass.this //表示外部类引用
* 所以上面的代码可以为:
public void print(){
Out.this.sys();
System.out.println(Out.this.string);
}

* 注意,this关键字在哪个类中使用,就表示该类的隐式参数。
public class Outer {
    private String string="Outer";

    private class Inner{
         private String string="Inner";
         public void print(){
             System.out.println(string);//输出内部类实例域,将外部类的string覆盖了
             System.out.println(Outer.this.string);//输出外部类实例域
             System.out.println(this.string);//输出内部类实例域
         }

    }
    public static void main(String[] args) {
         Outer.Inner inner=new Outer().new Inner();
         inner.print();
    }
}
输出结果为:
Inner
Outer
Inner
* 
    * 内部类在没有同名成员变量和局部变量的情况下,内部类会直接访问外部类的成员变量,而无需指定OutClass.this.属性名 ,否则,内部类中的局部变量会覆盖外部类的成员变量 ;而访问内部类本身的成员变量可用this.属性名,访问外部类的成员变量需要使用OutClass.this.属性名
    * 在外部类的作用域之外,可以这样引用内部类:
    * 
        * OuterClass.InnerClass    //表示内部类变量    如:Outer.Inner inner

    * 当在外部类定义中引用内部类时,可以直接使用内部类,如:

Inner inner=new Inner();

    * 调用内部对象构造器进行内部对象实例化时,使用如下:
    * 
        * outerObject.new InnerClass(parameters...)

    * 如:Outer.Inner inner=new Outer().new Inner();//所以成员内部类依赖外部对象
    * 成员内部类中不能存在任何static的变量和方法,所有的静态域都必须是fianl的。
    * 
    * 内部类是一种编译器现象,与虚拟机无关。编译器会把内部类翻译成:外部类名$内部类名的常规文件。如Outer$Inner.class





*  局部内部类
* 
    * 局部类不能用public /private/protected访问修饰符进行声明,它的作用域被限制在声明这个局部类的块中。

public class Outer1 {
private String string=”Outer”;
public void print(){
class Inner{
String string=”Inner”;
public void sys(){
System.out.println(string);
System.out.println(Outer1.this.string);
}
}
Inner inner=new Inner();
inner.sys();
}
public static void main(String[] args) {
Outer1 outer1=new Outer1();
outer1.print();
}
}

* 
    * 局部类有个优势,即对外面的世界完全隐藏起来,即使Outer类中还有其他方法也不能访问局部类。
    * 局部类不仅能访问包含它的外部类数据,还可以访问方法中的局部变量(不只是方法的参数,还包括方法中定义的变量),不过所访问的局部变量必须事实上为final(不管有没有final关键字)。说明一旦赋值便不可改变。
    * 编译器必须检测对局部变量的访问,为每一个变量建立相应的数据域,并将局部变量拷贝到构造器中,以便将这些数据初始化为局部变量的副本。局部类的方法只能引用定义为final的局部变量。
    * 在jdk1.8之前,必须将从局部类访问的局部变量声明为final。

public void print(int a){
class Inner{
String string=”Inner”;
public void sys(){
System.out.println(a);
System.out.println(string);
System.out.println(Outer1.this.string);
}
}
Inner inner=new Inner();
inner.sys();
}

* 
    * 虽然jdk1.8可以不用显式声明所访问的局部变量为final,但是所访问的局部变量默认为final类型的,仍然不可以对其进行改变。

public void print(int a){
class Inner{
String string=”Inner”;
public void sys(){
System.out.println(a++);
System.out.println(string);
System.out.println(Outer1.this.string);
}
}
Inner inner=new Inner();
inner.sys();
}

* 匿名内部类
* 
    * 将局部内部类的使用再深入下,如果只创建这个类的一个对象,就不必对这个类进行命名,这种类称为匿名内部类。
    * 语法格式为:

new SuperType( construction parameters…){
inner class methods and data
}
SuperType可以是ActionListener这样的接口,于是匿名内部类就要实现这个接口;
SuperType也可以是一个类,于是匿名内部类就需要扩展它。

* 
    * 由于构造器的名字必须与类名相同,而匿名类没有类名,所以匿名类不能有构造器。取而代之的是,将构造器的参数传递给父类的构造器。尤其是匿名类在实现接口的时候,不能有任何构造参数,还要像下面一样提供一组括号。

new InterfaceType(){
methods and data
}
class Inner{
private String string=null;
public Inner(String string){
this.string=string;
}
public void sys(){
System.out.println(“This is outer”);
}
}
public class Outer3 {

public void print(){
     Inner inner=new Inner("Inner"){
         public void sys(){
             System.out.println("This is inner");
         }
     };
     inner.sys();
}
public static void main(String[] args) {
     new Outer3().print();
}

}
输出为:
This is inner

* 静态内部类
* 
    * 使用static修饰的内部类我们称之为静态内部类,不过我们更喜欢称之为嵌套内部类。静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外部类,但是静态内部类却没有。没有这个引用就意味着:
    * 
        * 1、 它的创建是不需要依赖于外围类的。
        * 2、 它不能使用任何外围类的非static成员变量和方法。

    * 与常规内部类不同,静态内部类可以有静态域与静态方法。
    * 声明在接口中的内部类会自动成为static和public类。

public class Outer4 {
private String string=”Outer”;
static class Inner{
static int a=10;
public static void print(){
System.out.println(“This is inner !”);
}
}
public static void main(String[] args) {
Inner inner=new Outer4.Inner();
inner.print();
}
}

* 
    * 因为内部类被静态化,因此Outer.Inner可以当做一个整体看,可以直接new 出内部类的对象(通过类名访问static,生不生成外部类对象都没关系)





* 内部类的优点是:内部类可以访问外部类的私有成员变量,而不需要new外部类的对象。
* 内部类又分为:静态内部类、匿名内部类、局部内部类、成员内部类。

 静态内部类的应用场景是:只可以访问外部类的静态成员变量和静态成员方法。
 成员内部类的应用场景是:它可以访问它的外部类的所有成员变量和方法,不管是静态的还是非静态的 都可以。
 局部内部类:像局部变量一样,不能被public, protected, private和static修饰。只能访问方法中定义的 

final类型的局部变量。
匿名内部类:匿名内部类就是没有名字的局部内部类,不使用关键字class, extends, implements, 没有 构造方法。匿名内部类隐式地继承了一个父类或者实现了一个接口。匿名内部类使用得比较多,通常是作为一个方法参数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值