• Java之内部类


    上一篇博客中我们聊了一些关于接口的知识,接口不管是在学习还是工作中都是经常要用的,所以常用的知识一定要清楚,接下来我们学习一下内部类,内部类主要用在这种情况下:我们创建类的对象的时候并不需要使用很多次,每次只是用一次,这个时候我们就可以使用内部类了。

    1、内部类概述

    内部类就是在一个类的内部在定义一个类,比如,A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部类了。

    内部类不是在一个java源文件中编写俩个平行的俩个类,而是在一个类的内部再定义另外一个类。 我们可以把外边的类称为外部类,在其内部编写的类称为内部类。

    内部类分为四种:

      1. 成员内部类

      2. 静态内部类

      3. 局部内部类

      4. 匿名内部类

    2、成员内部类(实例内部类、非静态内部类)

    注:成员内部类中不能写静态属性和方法

    【定义一个内部类】

     1 //在A类中申明了一个B类,此B类就在A的内部,并且在成员变量的位置上,所以就称为成员内部类
     2 public class Outer {
     3     private int id;
     4     public void out(){
     5         System.out.println("这是外部类方法");
     6     }
     7 
     8     class Inner{
     9         public void in(){
    10             System.out.println("这是内部类方法");
    11         }
    12     }
    13 }

    【实例化内部类】

    实例化内部类,首先需要实例化外部类,通过外部类去调用内部类

     1 public class Outer {
     2     private int id;
     3     public void out(){
     4         System.out.println("这是外部类方法");
     5     }
     6     class Inner{
     7         public void in(){
     8             System.out.println("这是内部类方法");
     9         }
    10     }
    11 }
    12 public class Test{
    13     public static void main(String[] args) {
    14         //实例化成员内部类分两步
    15         //1、实例化外部类
    16         Outer outObject = new Outer();
    17         //2、通过外部类调用内部类
    18         Outer.Inner inObject = outObject.new Inner();
    19         //测试,调用内部类中的方法
    20         inObject.in();//打印:这是内部类方法
    21     }
    22 }

    分析:想想如果你要使用一个类中方法或者属性,你就必须要先有该类的一个对象,同理,一个类在另 一个类的内部,那么想要使用这个内部类,就必须先要有外部类的一个实例对象,然后在通过该对象去 使用内部类。

    【成员内部类能干什么?】

      1. 访问外部类的所有属性(这里的属性包括私有的成员变量,方法)

     1 public class Outer {
     2     private int id;
     3     public void out(){
     4         System.out.println("这是外部类方法");
     5     }
     6     class Inner{
     7         public void in(){
     8             System.out.println("这是内部类方法");
     9         }
    10         //内部类访问外部类私有的成员变量
    11         public void useId(){
    12             System.out.println(id+3);。
    13         }
    14         //内部类访问外部类的方法
    15         public void useOut(){
    16             out();
    17         }
    18     }
    19 }
    20 public class Test{
    21     public static void main(String[] args) {
    22 //实例化成员内部类分两步
    23 //1、实例化外部类
    24         Outer outObject = new Outer();
    25 //2、通过外部类调用内部类
    26         Outer.Inner inObject = outObject.new Inner();
    27 //测试
    28         inObject.useId();//打印3,因为id初始化值为0,0+3就为3,其中在内部类就使用了外部类的私有成员变量id。
    29         inObject.useOut();//打印:这是外部类方法
    30     }
    31 }

    如果内部类中的变量名和外部类的成员变量名一样,要通过创建外部类对象 "."属性来访问外部类 属性,通过this.属性访问内部类成员属性

     1 public class Outer {
     2     private int id;//默认初始化0
     3     public void out(){
     4         System.out.println("这是外部类方法");
     5     }
     6     class Inner{
     7         private int id=8; //这个id跟外部类的属性id名称一样。
     8         public void in(){
     9             System.out.println("这是内部类方法");
    10         }
    11         public void test(){
    12             System.out.println(id);//输出8,内部类中的变量会暂时将外部类的成员变量给隐藏
    13 //如何调用外部类的成员变量呢?通过Outer.this,想要知道为什么能通过这个来调用,就得明白下面这个原理
    14 //想实例化内部类对象,就必须通过外部类对象,当外部类对象来new出内部类对象时,会
    15 //把自己(外部类对象)的引用传到了内部类中,所以内部类就可以通过Outer.this来访问外部类的属性和方法,到这里,你也就可以知道为什么内部类可以访问外部类的属性和方法,这里由于有两个相同的
    16 //属性名称,所以需要显示的用Outer.this来调用外部类的属性,平常如果属性名
    17 //不重复,那么我们在内部类中调用外部类的属性和方法时,前面就隐式的调用了Outer.this。
    18             System.out.println(Outer.this.id);//输出外部类的属性id。也就是输出0
    19         }
    20     }
    21 }

    【写的一个小例子】

     1 public class MemberInnerClassTest {
     2     private String name;
     3     private static int age;
     4     public void run(){}
     5     public static void go(){}
     6     public class MemberInnerClass{
     7         private String name;
     8         //内部类访问外部类
     9         public void test(String name){
    10             System.out.println(name);
    11             System.out.println(this.name);
    12             System.out.println(MemberInnerClassTest.this.name);
    13             System.out.println(MemberInnerClassTest.age);
    14             MemberInnerClassTest.this.run();
    15             MemberInnerClassTest.go();
    16         }
    17     }
    18     //外部类访问成员内部类
    19 //成员内部类的对象要 依赖于外部类的对象的存在
    20     public void test(){
    21 //MemberInnerClass mic = MemberInnerClassTest.this.newMemberInnerClass();
    22 //MemberInnerClass mic = this.new MemberInnerClass();
    23         MemberInnerClass mic = new MemberInnerClass();
    24         mic.name = "tom";
    25         mic.test("hua");
    26     }
    27     public static void main(String[] args) {
    28 //MemberInnerClass mic = new MemberInnerClass();这个是不行的,this是动态的。
    29 //所以要使用要先创建外部类对象,才能使用
    30         MemberInnerClassTest out = new MemberInnerClassTest();
    31         MemberInnerClass mic = out.new MemberInnerClass();
    32 //如果内部类是private,则不能访问,只能铜鼓内部方法来调用内部类
    33         mic.name="jik";
    34         mic.test("kkk");
    35     }
    36 }

    3、静态内部类

     看到名字就知道,使用你static修饰的内部类就叫静态内部类。

    既然提到了static,那我们就来复习一下它的用法:一般只修饰变量和方法,平常不可以修饰类,但是内部类却可以被static修饰。

      1)static修饰成员变量:整个类的实例共享静态变量

      2)static修饰方法:静态方法,只能够访问用static修饰的属性或方法,而非静态方法可以访问static修饰的方法或属性

      3)被static修饰了的成员变量和方法能直接被类名调用。

      4)static不能修饰局部变量,切记,不要搞混淆了,static平常就用来修饰成员变量和方法。

    【举例】

     1 public class StaticInnerClassTest {
     2     private String name;
     3     private static int age;
     4     public void run(){}
     5     public static void go(){}
     6     //外部类访问静态内部类
     7     public void test(){
     8         StaticInnerClass sic = new StaticInnerClass(); //静态的内部类不需要依赖外部类,所以不用this
     9         sic.name = "tom";
    10         sic.test1("jack");
    11         StaticInnerClass.age=10;
    12         StaticInnerClass.test2("xixi");
    13     }
    14     private static class StaticInnerClass{
    15         private String name;
    16         private static int age;
    17         public void test1(String name){
    18             System.out.println(name);
    19             System.out.println(this.name);
    20             System.out.println(StaticInnerClass.age);
    21             System.out.println(StaticInnerClassTest.age);
    22 //System.out.println(StaticInnerClassTest.this.name);静态类不能访问非静态属性
    23             StaticInnerClassTest.go();
    24 //StaticInnerClassTest.this.run();静态类不能访问非静态方法
    25         }
    26         public static void test2(String name){
    27 //只能访问自己和外部类的静态属性和方法
    28             System.out.println(name);
    29 //System.out.println(this.name);静态方法里面连自己类的非静态属性都不能访问
    30             System.out.println(StaticInnerClass.age);
    31             System.out.println(StaticInnerClassTest.age);
    32 //System.out.println(StaticInnerClassTest.this.name);静态方法不能访问非静态属性
    33             StaticInnerClassTest.go();
    34 //StaticInnerClassTest.this.run();静态方法不能访问非静态方法
    35         }
    36     }
    37 }

    注意:

      1、我们上面说的内部类能够调用外部类的方法和属性,在静态内部类中就不行了,因为静态内部类没有了指向外部类对象的引用。除非外部类中的方法或者属性也是静态的。这就回归到了static关键字的用法。

     1 public class InnerClassTest {
     2     int a = 1;
     3     static int b = 2;
     4     private int c = 3;
     5     private static int d = 4;
     6     //非静态内部类
     7     class Inner1{
     8         void test(){
     9             System.out.println(a);   //外部类属性
    10             System.out.println(b);   //外部类静态属性
    11             System.out.println(c);   //外部私有类属性
    12             System.out.println(d);   //外部静态私有类属性
    13         }
    14     }
    15 
    16     //静态内部类
    17     static class Inner2{
    18         void test(){
    19             System.out.println(a);  //外部类属性  有错误    
    20             System.out.println(b);  //外部类静态属性
    21             System.out.println(c);  //外部私有类属性  有错误
    22             System.out.println(d);  //外部静态私有类属性
    23         }
    24     }
    25 
    26 
    27 }

      2、静态内部类能够直接被外部类给实例化,不需要使用外部类对象

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

      3、静态内部类中可以声明静态方法和静态变量,但是非静态内部类中就不可以声明静态方法和静态变量

    4、局部内部类

    局部内部类是在一个方法内部声明的一个类

    局部内部类中可以访问外部类的成员变量及方法

    局部内部类中如果要访问该内部类所在方法中的局部变量,那么这个局部变量就必须是final修饰的(有点小绕,多理解理解)

     1 public class Outer {
     2     private int id;
     3     //在method01方法中有一个Inner内部类,这个内部类就称为局部内部类
     4     public void method01(){class Inner{
     5         public void in(){
     6             System.out.println("这是局部内部类");
     7         }
     8     }
     9     }
    10 }

    局部内部类一般的作用跟在成员内部类中总结的差不多,但是有两个要注意的地方:

      在局部内部类中,如果要访问局部变量,那么该局部变量要用final修饰

      局部内部类不能通过外部类对象直接实例化,而是在方法中实例化出自己来,然后通过内部类对象调用自己类中的方法。看下面例子就知道如何用了。

     1 public class Outer {
     2     private int id;
     3     public void out(){
     4         System.out.println("外部类方法");
     5     }
     6     public void method01(){
     7         class Inner{
     8             public void in(){
     9                 System.out.println("这是局部内部类");
    10             }
    11         }
    12 //关键在这里,如需要在method01方法中自己创建内部类实例,然后调用内部类中的方法,等待外部类调用method01方法,就可以执行到内部类中的方法了。
    13         Inner In = new Inner();
    14         In.in();
    15     }
    16 }

    使用局部内部类需要注意的地方就刚才上面说的:

      1、在局部内部类中,如果要访问局部变量,那么该局部变量要用final修饰

      2、如何调用局部内部类方法。

     1 public class LocalInnerClassTest {
     2     private String name;
     3     private static int age;
     4     public void run(){}
     5     public static void go(){}
     6     //局部内部类要定义在方法中
     7     public void test(){
     8         final String myname="";
     9         class LocalInnerClass{
    10             private String name;
    11             // private static int age;不能定义静态属性
    12             public void test(String name){
    13                 System.out.println(name);
    14                 System.out.println(this.name);
    15                 System.out.println(myname);
    16                 System.out.println(LocalInnerClassTest.this.name);
    17                 LocalInnerClassTest.this.run();
    18                 LocalInnerClassTest.go();
    19             }
    20         }
    21 //局部内部类只能在自己的方法中用,因为局部内部类相当于一个局部变量,除了方法就找不到了。
    22         LocalInnerClass lic = new LocalInnerClass();
    23         lic.name="tom";
    24         lic.test("test");
    25     }
    26 }

    5、匿名内部类

    在这四种内部类中,以后的工作可能遇到最多的是匿名内部类,所以说匿名内部类是最常用的一种内部类。

    什么是匿名对象?如果一个对象只要使用一次,那么我们就是需要new Object().method()。 就可以了,而不需要给这个实例保存到该类型变量中去。这就是匿名对象。

     1 public class Test {
     2     public static void main(String[] args) {
     3 //讲new出来的Apple实例赋给apple变量保存起来,但是我们只需要用一次,就可以这样写
     4         Apple apple = new Apple();
     5         apple.eat();
     6 //这种就叫做匿名对象的使用,不把实例保存到变量中。
     7         new Apple().eat();
     8     }
     9 }
    10 class Apple{
    11     public void eat(){
    12         System.out.println("我要被吃了");
    13     }
    14 }

      1. 匿名内部类除了依托的类或接口之外,不能指定继承或者实现其他类或接口,同时也不能被其他类所继承,因为没有名字。

      2. 匿名内部中,我们不能写出其构造器,因为没有名字。

      3. 匿名内部中,除了重写上面的方法外,一般不会再写其他独有的方法,因为从外部不能直接调用到。(间 接是调用到的)

  • 相关阅读:
    SGU 106 The equation 扩展欧几里德
    poj 2478 Farey Sequence 欧拉函数前缀和
    uva 11752 The Super Powers 素数+大数判断大小
    Lightoj 1370 素数打表 +二分
    vijos 1250 最勇敢的机器人 分组背包+并查集
    Codeforces Round #366 (Div. 2) A , B , C 模拟 , 思路 ,queue
    BZOJ 4034: [HAOI2015]T2 树链剖分
    BZOJ 1057: [ZJOI2007]棋盘制作 悬线法求最大子矩阵+dp
    BZOJ 1260: [CQOI2007]涂色paint 区间DP
    BZOJ 1264: [AHOI2006]基因匹配Match 树状数组+DP
  • 原文地址:https://www.cnblogs.com/koss/p/14483152.html
Copyright © 2020-2023  润新知