内部类

    xiaoxiao2021-04-13  30

    

    内部类不是很好理解,但说白了其实也就是一个类中还包含着另外一个类

    如同一个人是由大脑、肢体、器官等身体结果组成,而内部类相当于其中的某个器官之一,例如心脏:它也有自己的属性和行为(血液、跳动)

    显然,此处不能单方面用属性或者方法表示一个心脏,而需要一个类

    而心脏又在人体当中,正如同是内部类在外部内当中

     

    实例1:内部类的基本结构

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 //外部类 class  Out {      private  int  age =  12 ;            //内部类      class  In {          public  void  print() {              System.out.println(age);          }      } }   public  class  Demo {      public  static  void  main(String[] args) {          Out.In in =  new  Out(). new  In();          in.print();          //或者采用下种方式访问          /*          Out out = new Out();          Out.In in = out.new In();          in.print();          */      } }

    运行结果:12

    从上面的例子不难看出,内部类其实严重破坏了良好的代码结构,但为什么还要使用内部类呢?

    因为内部类可以随意使用外部类的成员变量(包括私有)而不用生成外部类的对象,这也是内部类的唯一优点

    如同心脏可以直接访问身体的血液,而不是通过医生来抽血

     

    程序编译过后会产生两个.class文件,分别是Out.class和Out$In.class

    其中$代表了上面程序中Out.In中的那个 .

    Out.In in = new Out().new In()可以用来生成内部类的对象,这种方法存在两个小知识点需要注意

      1.开头的Out是为了标明需要生成的内部类对象在哪个外部类当中

      2.必须先有外部类的对象才能生成内部类的对象,因为内部类的作用就是为了访问外部类中的成员变量

     

    实例2:内部类中的变量访问形式

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class  Out {      private  int  age =  12 ;            class  In {          private  int  age =  13 ;          public  void  print() {              int  age =  14 ;              System.out.println( "局部变量:"  + age);              System.out.println( "内部类变量:"  +  this .age);              System.out.println( "外部类变量:"  + Out. this .age);          }      } }   public  class  Demo {      public  static  void  main(String[] args) {          Out.In in =  new  Out(). new  In();          in.print();      } }

    运行结果:

    局部变量:14 内部类变量:13 外部类变量:12

    从实例1中可以发现,内部类在没有同名成员变量和局部变量的情况下,内部类会直接访问外部类的成员变量,而无需指定Out.this.属性名

    否则,内部类中的局部变量会覆盖外部类的成员变量

    而访问内部类本身的成员变量可用this.属性名,访问外部类的成员变量需要使用Out.this.属性名

     

    实例3:静态内部类

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class  Out {      private  static  int  age =  12 ;            static  class  In {          public  void  print() {              System.out.println(age);          }      } }   public  class  Demo {      public  static  void  main(String[] args) {          Out.In in =  new  Out.In();          in.print();      } }

    运行结果:12

    可以看到,如果用static 将内部内静态化,那么内部类就只能访问外部类的静态成员变量,具有局限性

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

     

    实例4:私有内部类

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class  Out {      private  int  age =  12 ;            private  class  In {          public  void  print() {              System.out.println(age);          }      }      public  void  outPrint() {          new  In().print();      } }   public  class  Demo {      public  static  void  main(String[] args) {          //此方法无效          /*          Out.In in = new Out().new In();          in.print();          */          Out out =  new  Out();          out.outPrint();      } }

    运行结果:12

    如果一个内部类只希望被外部类中的方法操作,那么可以使用private声明内部类

    上面的代码中,我们必须在Out类里面生成In类的对象进行操作,而无法再使用Out.In in = new Out().new In() 生成内部类的对象

    也就是说,此时的内部类只有外部类可控制

    如同是,我的心脏只能由我的身体控制,其他人无法直接访问它

     

    实例5:方法内部类

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class  Out {      private  int  age =  12 ;        public  void  Print( final  int  x) {          class  In {              public  void  inPrint() {                  System.out.println(x);                  System.out.println(age);              }          }          new  In().inPrint();      } }   public  class  Demo {      public  static  void  main(String[] args) {          Out out =  new  Out();          out.Print( 3 );      } }

    运行结果:

    3 12

    在上面的代码中,我们将内部类移到了外部类的方法中,然后在外部类的方法中再生成一个内部类对象去调用内部类方法

    如果此时我们需要往外部类的方法中传入参数,那么外部类的方法形参必须使用final定义

    至于final在这里并没有特殊含义,只是一种表示形式而已

     

     

    匿名内部类也就是没有名字的内部类

    正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写

    但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口

     

    实例6.1:不使用匿名内部类来实现抽象方法

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 abstract  class  Person {      public  abstract  void  eat(); }   class  Child  extends  Person {      public  void  eat() {          System.out.println( "eat something" );      } }   public  class  Demo {      public  static  void  main(String[] args) {          Person p =  new  Child();          p.eat();      } }

    运行结果:eat something

    可以看到,我们用Child继承了Person类,然后实现了Child的一个实例,将其向上转型为Person类的引用

    但是,如果此处的Child类只使用一次,那么将其编写为独立的一个类岂不是很麻烦?

    这个时候就引入了匿名内部类

     

    实例6.2:匿名内部类的基本实现

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 abstract  class  Person {      public  abstract  void  eat(); }   public  class  Demo {      public  static  void  main(String[] args) {          Person p =  new  Person() {              public  void  eat() {                  System.out.println( "eat something" );              }          };          p.eat();      } }

    运行结果:eat something

    可以看到,我们直接将抽象类Person中的方法在大括号中实现了

    这样便可以省略一个类的书写

    并且,匿名内部类还能用于接口上

     

    实例6.3:在接口上使用匿名内部类

    interface  Person {      public  void  eat(); }   public  class  Demo {      public  static  void  main(String[] args) {          Person p = new  Person() {              public  void  eat() {                  System.out.println( "eat something" );              }          };          p.eat();      } }

    运行结果:eat something

     

    由上面的例子可以看出,只要一个类是抽象的或是一个接口,那么其子类中的方法都可以使用匿名内部类来实现

    ps:

    匿名内部类中是不能定义构造函数的。

    匿名内部类中不能存在任何的静态成员变量和静态方法

    匿名内部类只能使用一次是指只能有一个对象,可随时声明该类引用该对象

    1       内部类

    1.1  内部类的概述

    将类定义在另一个类的内部则成为内部类。其实就是类定义的位置发生了变化。

    在一个类中,定义在类中的叫成员变量,定义在函数中的叫成员函数,那么根据类定义的位置也可以分为成员内部类和局部内部类。

    备注:内部类生产的class文件为 “外部类$内部类”,为了标明该内部类是属于具体哪个外部类的。

    1.2  成员内部类的访问方式

    内部类可以直接访问外部类的成员属性。(孙悟空相当于内部类飞到牛魔王的肚子里面去)

    外部类需要访问内部类的成员属性时需要创建内部类的对象。

    在外部类的成员函数中创建内部类的对象,通过内部类对象对象直接访问内部类的成员。

    在其他类中直接创建内部类的对象。

    Outer.Innerinner = new Outer().new Inner();

     

    外部类访问内部类的属性

    编译异常分析:外部类需要访问内部类的属性时,需要创建内部类的对象访问。

     

    A类和B类,当A类想要直接访问B类中的成员,而B类又需要建立A类的对象来A类中的成员。这时,就将A类定义成B类的内部类。比喻:孙悟空和铁扇公主。孙悟空到了公主肚子中,就成了内部类(其实是持有外部类的对象引用)。

     

    疑问: 什么时候使用内部类呢?

    当我们分析事物时,发现事物的内部还有具体的事物,这时则应该定义内部类了。

    比如人体是一个类,人体有心脏,心脏的功能在直接访问人体的其他内容。这时就将心脏定义在人体类中,作为内部类存在。

    内部类的优势:成员内部类作为外部类的成员,那么可以访问外部类的任意成员。

     

    1.3  成员内部类访问细节

     

    私有的成员内部类不能在其他类中直接创建内部类对象来访问。

    如果内部类中包含有静态成员,那么java规定内部类必须声明为静态的访问静态内部类的形式:Outer.Inner in = new Outer.Inner(); 

     

    总结:成员内部类(成员属性、成员方法)特点

    私有的成员内部类

                       特点:不能在其他类中直接创建内部类对象来访问

     静态的成员内部类

                       特点:如果内部类中包含有静态成员,那么java规定内部类必须声明为静的

                          访问静态内部类的形式:

                          Outer.Inner in = new Outer.Inner();

    疑问: 目前打印的num20,如果想打印10的话,应该怎么做?

    解答:这时候其实在show方法中已经存在了两个this对象,一个是外部类对象,一个是内部类对象,所以要在this前面加上类名标明对应的this

    1.4  局部内部类

    局部内部类概述:包含在外部类的函数中的内部类称之为局部内部类。

    访问:可以在包含局部内部类的方法中直接创建局部内部类的对象调用局部内部类的成员。

    注意:局部内部类只能访问所在函数的fanal属性。

    1.5  匿名内部类

    匿名内部类:就是没有类名字的内部类。

    匿名内部类作用:简化内部类书写。

    匿名内部类的前提:必须继承一个父类或者是实现一个接口。

    匿名内部类的格式:

           new父类或者接口(){ 执行代码….};

    内部类的写法:

    class Outer{

           class Inner

           {

                  public void show(){

                         System.out.println("内部类的show方法");

                  }

           }

           public void print(){

                  new Inner().show();

           }

    }

    匿名内部类调用show方法:

    案例:在外部类调用show1show2方法。内部类的实现方法/

    使用匿名内部类实现: 

          

    注意细节:

    1.使用匿名内部类时,如果需要调用匿名内部类的两个方法或者两个方法以上。可以使用变量指向该对象。

    转载请注明原文地址: https://ju.6miu.com/read-668766.html

    最新回复(0)