【JavaSE】内部类

简介: 本文讲解:内部类

 image.gif编辑

目录

1.内部类

1.1内部类的简单创建

1.2内部类的分类

1.2.1普通内部类

1.2.2静态内部类

1.3匿名内部类

1.4局部内部类

image.gif编辑

1.内部类

内部类就是一是一个类里面装着另外一个类,就像俄罗斯套娃一样。最外层的类我们叫外部类,内层的类我们叫内部类

image.gif编辑


1.1内部类的简单创建

内部类就是一个类中的包含的另外一个类我们称之内部类,内部类外面那个类我们称之为外部类。如以下代码:

//这是一个外部类
class OutClass {
    //这是一个普通内部类
    class NeiBuClass {
    }
}

image.gif

以上代码中OutClass为外部类,NeiBuClass为内部类。这样的一段代码就构成了一个类包含另一个类,当然你也可以在一个类里面定义多个类。以上是对外部类与内部类的一个简单创建,详细讲解请看下方。


1.2内部类的分类

内部类可分为:静态内部类、实例内部类、匿名内部类、局部内部类。其中的局部内部类是在方法里面定义的类,几乎不用。匿名内部类是没有名称的类,也几乎不用。因此我们今天主要掌握前两种内部类,但后两种我们也会讲到。


1.2.1普通内部类

普通内部类是非静态内部类/实例内部类。它是没有任何修饰符修饰的一个内部类。它的语法格式为: class 类名。如以下代码展示:

//外部类
class OutClass { 
    //普通内部类/非静态内部类
    class NeiBuClass {
    }
}

image.gif

以上代码中OutClass为外部类,NeiBuCass为一个普通内部类,下面我就来讲解它的用法。

class OutClass {
    public int num1;
    private int num2;
    protected int num3;
    public void fun() {
        System.out.println("今天过得很开心!");
    }
    class NeiBuClass {
        public void show() {
            //外部类里的任何属性都内被内部类使用
            num1 = 1;
            num2 = 2;
            num3 = 3;
            System.out.println(num1+" "+num2+" "+num3);
            //访问外部类成员方法
            fun();
        }
    }
}
public class Test {
    public static void main(String[] args) {
        //实例化内部类前得先实例化外部类
        OutClass.NeiBuClass neiBuClass = new OutClass().new NeiBuClass();
        neiBuClass.show();
    }
}

image.gif

运行后输出:

image.gif编辑

通过上述代码,我们可以看到外部类中的成员变量和成员方法都能被我们的普通内部类使用。无论外部类是被public还是private或者protected修饰都能使用。此外,我们在实例化内部类时,必须先实例化外部类。这样才能得到一个内部类引用。

因此我们有一个问题,在我们学习封装的时候知道了一个概念。一个类里面被private修饰的属性,不能在其他类中使用,比如:

class Try1 {
    private int num = 10;
}
class Try2 {
    num = 20;
}

image.gif

报错:

image.gif编辑

那为什么在外部类与内部类的关系中,我们能使用呢?大家不必惊慌,这是语法所规定的。我们只需要知道这是一个特例就好了,可以放心使用。


注意,当我们外部类与内部类中有相同的属性时,我们优先访问内部类中的属性,如下代码:

class OutClass {
    //外部类成员变量
    public int num = 10;
    //外部类成员变量
    public void fun() {
        System.out.println("今天过得很开心!");
    }
    class NeiBuClass {
        //内部类成员变量
        public int num = 20;
        //内部类成员方法
        public void fun() {
            System.out.println("今天过得不开心!");
        }
        public void show() {
            //优先访问内部类自己的成员
            System.out.println(num);
            //优先访问内部类自己的方法
            fun();
        }
    }
}
public class Test {
    public static void main(String[] args) {
        //实例化内部类前得先实例化外部类
        OutClass.NeiBuClass neiBuClass = new OutClass().new NeiBuClass();
        neiBuClass.show();
    }
}

image.gif

运行后输出:

image.gif编辑

如果我们非得访问外部类中的属性怎么办呢?我们可以用外部类名.this.属性名来访问外部类的属性。如:

class OutClass {
    public int num = 10;
    public void fun() {
        System.out.println("今天过得很开心!");
    }
    class NeiBuClass {
        public int num = 20;
        public void fun() {
            System.out.println("今天过得不开心!");
        }
        public void show() {
            //访问了外部类成员变量
            System.out.println(OutClass.this.num);
            //访问外部类成员方法
            OutClass.this.fun();
        }
    }
}
public class Test {
    public static void main(String[] args) {
        //实例化内部类前得先实例化外部类
        OutClass.NeiBuClass neiBuClass = new OutClass().new NeiBuClass();
        neiBuClass.show();
    }
}

image.gif

运行后输出:

image.gif编辑通过以上代码,很好的展示了通过外部类名.this.外部属性名就能访问到外部类中的属性。


那么我们的外部类能不能访问内部类中的成员变量或方法呢?我们来看一组代码:

class OutClass {
    //外部类成员变量
    public int num1 = 10;
    //外部类成员方法
    public void show() {
        fun();
        System.out.println(num2);
    }
    class NeiBuClass {
        //内部类成员变量
        public int num2 = 20;
        //内部类成员方法
        public void fun() {
            System.out.println("今天过得很开心!");
    }
}

image.gif

报错:

image.gif编辑因此,外部类不能直接访问内部类中的属性,如果我们要访问的化,可以创建一个内部类对象。通过引用这个对象就可以访问内部类中的属性,如下代码:

class OutClass {
    //实例化了内部类的一个对象
    NeiBuClass neiBuClass = new NeiBuClass();
    //外部类成员变量
    public int num1 = 10;
    //外部类成员方法
    public void show() {
        neiBuClass.fun();
        System.out.println(neiBuClass.num2);
    }
    class NeiBuClass {
        //内部类成员变量
        public int num2 = 20;
        //内部类成员方法
        public void fun() {
            System.out.println("今天过得很开心!");
        }
    }
}
public class Test {
    public static void main(String[] args) {
        OutClass outClass = new OutClass();
        outClass.show();
    }
}

image.gif

运行后输出:

image.gif编辑以上代码展示了,在外部类访问内部类的方法就是实例化内部类出一个对象即可访问内部类属性。

总结

    • 外部类的属性可以在内部类中使用(实例内部类所处的位置与外部类成员位置相同,因此也受public、private等访问限定符的约束)
    • 当外部类的属性与内部类中的属性同名时,在内部类中使用该属性时会优先访问内部类中该属性
    • 在内部类中访问同名属性时,可以使用外部类名.this.属性名来访问外部类属性
    • 实例化内部类时,必须先实例化外部类(借助外部类来访问内部类)
    • 外部类不能直接访问内部类中的属性,必须得实例化一个内部类对象才可访问

    1.2.2静态内部类

    静态内部类是由static修饰的类,它的语法格式为:static class 类名。下面我们来看代码:

    //外部类
    class OutClass {
        //静态内部类
        static class NeiBuClass {
        }
    }

    image.gif

    以上代码就是一个静态内部类的创建方式,下面我们来看它的用法。当我们直接在静态内部类访问外部类中的非静态属性时是访问不到的,我们只能访问静态的成员属性。因为静态不依赖于类。

    //外部类
    class OutClass {
        //外部类成员
        public int num1 = 10;
        private int num2 = 10;
        protected int num3 = 20;
        public static int num4 = 30;
        //静态内部类
        static class NeiBuClass {
            public void show() {
                //num1-num3不能直接访问
                System.out.println(num1);
                System.out.println(num2);
                System.out.println(num3);
                System.out.println(num4);
            }
        }
    }

    image.gif

    报错:

    image.gif编辑

    因此,如果我们要在静态内部类中访问外部类中的非静态属性的话,我们要先实例化一个外部类对象。通过引用来访问外部类中的非静态属性,如以下代码:

    //外部类
    class OutClass {
        //外部类成员
        public int num1 = 10;
        private int num2 = 20;
        protected int num3 = 30;
        public static int num4 = 40;
        //静态内部类
        static class NeiBuClass {
            public void show() {
                //实例化一个外部类对象
                OutClass outClass = new OutClass();
                //通过外部类对象来引用外部类属性
                System.out.println(outClass.num1);
                System.out.println(outClass.num2);
                System.out.println(outClass.num3);
                System.out.println(num4);
            }
        }
    }
    public class Test {
        public static void main(String[] args) {
            //创造一个静态内部类对象
            OutClass.NeiBuClass neiBuClass = new OutClass.NeiBuClass();
            neiBuClass.show();
        }
    }

    image.gif

    运行后输出:

    image.gif编辑

    以上代码展示了静态内部类如何访问外部类中的非静态成员。我们在类和对象中学到了,一个类中的静态成员我们可以直接使用类名来访问该成员。因此在上述实例化静态内部类时,我们不用像普通内部类那样得先实例化外部类在实例化内部类。我们直接通过外部类引用静态内部类来创建一个静态内部类对象。


    外部类访问静态内部类:

    //外部类
    class OutClass {
        //实例化一个惊天内部类对象
        NeiBuClass neiBuClass = new NeiBuClass();
        //外部类方法
        public void show() {
            System.out.println(neiBuClass.num1);
            System.out.println(neiBuClass.num2);
            System.out.println(neiBuClass.num3);
            neiBuClass.fun();
        }
        //静态内部类
        static class NeiBuClass {
            //静态内部类中的成员变量
            int num1 = 1;
            int num2 = 2;
            int num3 = 3;
            //静态内部类中的方法
            public void fun() {
                System.out.println("今天天气很糟糕!");
            }
        }
    }
    public class Test {
        public static void main(String[] args) {
            //实例化一个外部类对象
            OutClass outClass = new OutClass();
            //引用外部类中的show方法
            outClass.show();
        }
    }

    image.gif

    运行后输出:

    image.gif编辑

    以上代码展示了外部类访问静态内部类属性的方法,就是实例化一个静态内部类对象即可访问。

    总结:

      • 静态内部类无法访问外部类中的非静态成员变量或成员方法
      • 静态内部类要访问外部类中非静态属性时可创建一个外部类对象来访问
      • 静态属性不依赖于类,因此可以使用类名来引用静态属性
      • 外部类想访问静态内部类属性时,可以实例化一个静态内部类对象即可访问
      • 静态内部类不能直接实例化,要通过外部类名的引用来实例化

      1.3匿名内部类

      匿名内部类,简单的来说就是没有类名的内部类。一般在是在接口对象中定义的内部类。

      //定义一个名为IUSB的接口
      interface IUSB {
          void show();
      }
      //Try类使用了这个接口
      class Try implements IUSB{
          //重写了接口中的show方法
          @Override
          public void show() {
              System.out.println("今天你开心吗?");
          }
      }
      public class Test {
          public static void main(String[] args) {
              //new一个接口
              new IUSB() {
                  @Override
                  public void show() {
                      System.out.println("这就是一个匿名内部类");
                  }
              }.show();
          }
      }

      image.gif

      运行后输出:

      image.gif编辑

      以上代码展示了,匿名类内部类的用法。这种内部类我们几乎不用,大家可以看到我们必须在一个接口中定义一个方法,并且要有一个类使用这个接口并实现重载接口中的方法才能达到这个方法的可用性,然后我们再才能new一个接口对象这个对象没有类名没有修饰,这就是匿名内部类。可见这种内部类我们使用的非常之少。


      1.4局部内部类

      局部内部类是在方法里面的定义的类,例如:

      public class Test {
          //一个名为show的方法
          public void show() {
              //这是一个局部内部类
              class Dog {
                  //局部内部类的成员变量
                  public int num = 10;
                  //局部内部类中的成员方法
                  public void fun() {
                      System.out.println("这是局部内部类中的fun()方法");
                  }
              }
              //实例化一个局部内部类对象
              Dog dog = new Dog();
              //通过dog引用来方法这两个属性
              System.out.println(dog.num);
              dog.fun();
          }
          public static void main(String[] args) {
              //再通过实例化一个主类才能调用show方法
              Test test = new Test();
              test.show();
          }
      }

      image.gif

      运行后输出:

      image.gif编辑我们发现,在一个方法里面定义一个类然后去创建一些属性我们还得在这个方法中实例化对象和main方法中实例化对象才能访问到这些属性,真是脱裤子放弃多费手续。因此,这种内部类我们也是不怎么常用的。


      好了,今天的博文到这里就结束了,感谢你的阅读。

      image.gif编辑

      下期预告:图书管理系统的实现、通讯录的实现

      相关文章
      |
      11月前
      |
      Java
      【JavaSE】详解final关键字
      【JavaSE】详解final关键字
      |
      Java 编译器
      【JAVASE】继承 中
      【JAVASE】继承
      |
      Java 编译器
      【JavaSE】抽象类
      【JavaSE】抽象类
      【JavaSE】抽象类
      |
      Java 程序员 编译器
      【JavaSE】一起学继承
      【JavaSE】一起学继承
      |
      6月前
      |
      存储 Java 编译器
      JavaSE学习之--抽象类,接口,内部类(三)
      JavaSE学习之--抽象类,接口,内部类(三)
      39 0
      |
      6月前
      |
      存储 Java 机器人
      JavaSE学习之--抽象类,接口,内部类(二)
      JavaSE学习之--抽象类,接口,内部类(二)
      54 0
      |
      11月前
      |
      Java
      【JavaSE】内部类
      【JavaSE】内部类
      |
      Java 编译器
      【javaSE】 抽象类
      【javaSE】 抽象类
      |
      Java 程序员
      【JAVASE】继承 上
      【JAVASE】继承