zoukankan      html  css  js  c++  java
  • Java基础之内部类介绍

    内部类

    在一个Java源文件中,只能定义一个与类名完全一致的公开的类,这个类,我们称为外部类。在一个外部类中,我们可以在内部定义一个或者多个类,我们把在内部定义出来的类称为内部类。内部类的定义形式,和普通类的定义方式是一致的:

    1 [访问权限控制符] [类型] [类名] {
    2 
    3 }  

    ①访问权限控制符:取值可以是private、无、protected、public。注意“无”表示不用任何控制符来修饰,也不能用default来修饰。

    ②类型:取值可以是class、enum、interface。但是实际运用中,往往不用interface。因为内部接口不允许被其他外部类所继承。

    ③类名:这个内部类的类名称,这个名称不能和外部类的类名称相同,同时也不能和该外部类中的其他内部类同名称。

    内部类可以是静态或者是非静态,也可以出现在属性的定义、方法体和表达式中,或者是匿名出现。因此我们把内部类分为四种。

    • 静态内部类
    • 成员内部类
    • 局部内部类
    • 匿名内部类

    静态内部类

    使用static修饰的一个内部类,就叫作静态内部类。

     1 public class MyOuter {
     2 
     3     private static int a = 10;
     4     private int b = 20;
     5 
     6     private static void say () {
     7 
     8         System.out.println("hello world!");
     9 
    10     }
    11 
    12     static class MyStaticInner {
    13 
    14         private void test1() {
    15             System.out.println("a = " + a);
    16             //System.out.println("b = " + b);
    17             say();
    18         }
    19 
    20         private static void test2() {
    21 
    22         }
    23     }
    24 }

    1.在一个静态内部类中,可以有静态方法,也可以存在非静态方法。

    2.在一个静态内部类中,只能够访问外部类的静态成员属性和静态成员方法。如上代码中在静态类的方法中访问 外部非静态的成员属性b,编译不通过。

    3.如果要访问静态内部类的静态方法,不需要拿到外部类和内部类的实例,通过 外部类.内部类.内部静态方法的方式访问。如上代码中需要访问内部类的静态方法test2。可以表示为MyOuter.MyStaticInner.test2();

    4.如果要方位静态内部类的非静态方法,不需要拿到外部类的实例,但是需要拿到内部类的实例,通过内部类的实例.非静态内部方法的方式来访问。如上代码中可以表示为MyOuter.MyStaticInner oi = new MyOuter.MyStaticInner();  oi.test1();

    总结一下,静态内部类的实例获取方式:外部类.静态内部类   实例的名称 = new 外部类.静态内部类();我们再来看一个问题。实例代码如下所示:

    public class MyOuter {
    
        private static int a = 10;
        private static int b = 20;
        private static int c = 30;
    
        private static void say () {
    
            System.out.println("hello world!");
        }
    
        public static class MyInner {
    
            private int b = 200;
            private int c = 300;
    
            public void test1() {
                int c = 3000;
                System.out.println("a = " + a);
                System.out.println("b = " + b);
                System.out.println("c = " + c);
            }
    
            public static void test2() {
    
            }
        }
        public static void main(String[] args) {
            MyOuter.MyInner m = new MyOuter.MyInner();
            m.test1();
        }
    }

     当外部类和内部类拥有相同的成员属性,同时内部类的方法中也拥有相同的局部变量,内部类在访问时,优先访问的是内部局部变量,内部成员变量还是外部成员变量?我们来看一下运行结果

    a = 10
    b = 200
    c = 3000 

    于是我们得出结论:在一个静态内部类的内部方法,内部成员属性,外部成员属性中变量相同,优先访问局部变量,再访问内部成员变量,最后是外部静态成员变量。

    成员内部类

    成员内部类定义的位置和静态内部类有点相似,但是成员内部类没有static关键字修饰。

     1 public class MyOuter {
     2 
     3     private  int a = 10;
     4     private static int b = 20;
     5     private static int c = 30;
     6 
     7     private static void say () {
     8 
     9         System.out.println("hello world!");
    10     }
    11 
    12     public class MyInner {
    13 
    14         private int b = 200;
    15         private int c = 300;
    16         //private static int param = 111; 
    17         public void test1() {
    18             int c = 3000;
    19             System.out.println("a = " + a);
    20             System.out.println("b = " + b);
    21             System.out.println("c = " + c);
    22         }
    23 
    24         //public static void test2() {
    25         //成员内部类中不允许存在静态方法
    26         //}
    27     }
    28     public static void main(String[] args) {
    29         MyOuter myOuter = new MyOuter();
    30         MyInner myInner = myOuter.new MyInner();
    31 
    32         myInner.test1();
    33 
    34     }
    35 }

    1.成员内部类中不允许存在静态成员属性,和静态成员方法。第16行和第24行编译不通过。

    2.成员内部类是外部类的实例的一个成员,因此想要访问成员内部类,必须先要拥有外部类的实例。

    3.成员内部类无论是声明为public或者private还是内部类成员属性或者方法声明为public和private。都可以通过外部类的实例,再产生内部类的实例,最后访问内部类的成员属性或者方法。

    4.和静态内部类一样,如果在成员内部类方法中局部变量,内部成员属性,外部成员属性相同时,优先访问局部变量,内部类成员属性,外部成员属性。

    局部内部类

    局部内部类是存在方法体之中的,实例代码如下图所示:

     1 public class MyOuter {
     2 
     3     private  int a = 10;
     4     private  int b = 20;
     5     private  int c = 30;
     6     private  int d = 40;
     7 
     8     private static void say () {
     9 
    10         System.out.println("hello world!");
    11     }
    12 
    13 
    14     public  void abc () {
    15         final int b = 100;
    16 
    17         class MyInner {
    18             private int c = 300;
    19 
    20             private void test () {
    21                 int d = 4000;
    22                 System.out.println("a = " + a);
    23                 System.out.println("b = " + b);
    24                 System.out.println("c = " + c);
    25                 System.out.println("d = " + d);
    26                 say();
    27             }
    28         }
    29 
    30 
    31         MyInner inner = new MyInner();
    32         inner.test();
    33     }
    34 
    35     public static void main(String[] args) {
    36         MyOuter myOuter = new MyOuter();
    37         myOuter.abc();
    38 
    39     }
    40 }

    1.局部内部类只存在方法体中,也只能在该方法中通过获取这个类的实例类访问成员属性和方法。

    2.局部内部类的使用必须要在局部内部类的声明之后。

    3.局部内部类只能访问方法体中的final修饰的变量或者对象。也可以访问外部类的成员属性和方法。

    4.和成员内部类一样,如果在局部内部类方法中局部变量,内部成员属性,外部成员属性相同时,优先访问局部变量,内部类成员属性,外部成员属性。

    匿名内部类

     匿名内部类用的比较常见,比如在线程中,

    1 public static void main(String[] args) {
    2        (new Thread(){}).start();
    3 
    4 }

     匿名内部存在于方法体中,是一个唯一没有构造函数的内部类。

    编译后的内部类

    我们首先来看一段代码:

    public class MyOuter {
    
        //成员内部类
        private class Inner1 {
    
        }
    
    
        //静态内部类
        private static class Inner2 {
    
        }
    
        public static void main(String[] args) {
            //匿名内部类
            (new Thread(){}).start();
            (new Thread(){}).start();
    
            //局部内部类
            class Inner3{}
            class Inner4{}
    
        }
    }

    我们将这一段代码保存为MyOuter.java并另存到D: est目录下。打开cmd;执行javac MyOuter.java。

    由上图可知改文件的编码问题,因此需要更改文件的编码方式为ANSI。

     

    继续执行javac MyOuter.java。在相同目录下出现编译好的class文件。如下图所示;

    编译好的class文件,简单总结一下:

    1.外部类命名为[外部类.class]

    2.内部类的命名,采用外部类与内部类之间使用$分隔。

    3.成员内部类的命名,采用[外部类]$[内部类].class命名。如上图MyOuter$Inner1.class。

    4.静态内部类的命名和成员内部类一样。如上图MyOuter$Inner2.class。

    5.局部内部类的命名,采用[外部类]$[编号][内部类].class命名。这里的编号是为了是为了区分是哪个方法。这也说明了,为什么同一个外部类,的多个方法中,存在的局部内部类的类名可以相同。如上图的MyOuter$1Inner3.class和MyOuter$1Inner4.class

    6.匿名内部类的命名,采用[外部类]$[编号].class命名。这里的编号是为了区分多个匿名类。如上图的MyOuter$1.class和MyOuter$2.class

    为什么要使用内部类

    1.使用内部类,能够使代码程序变得更简单。比如有一段业务逻辑可能有且只有一处会使用,那可以考虑在业务类上增加以下内部类。

    2.普通类只能继承一个超类,当我们想要做到多继承时,可以考虑使用成员内部类来继承某一个原有的类,使用原有来非私有成员属性和方法。这就到达了多继承的效果。

    3.使得代码更加简单,使用匿名内部类,能够使用少量的代码去做更多的事情,比如Thead。当然这里只是说明匿名内部类的好处,线程的使用推荐线程池。

  • 相关阅读:
    web.xml模板
    log4j.properties模板
    springmvc-config.xml模板
    applicationContext.xml配置druid连接池
    mybatis-config.xml模板
    mapper.xml模板
    Servlet基础认识
    单例模式的懒汉饿汉
    霜降小悟
    忙闲有致
  • 原文地址:https://www.cnblogs.com/sunshine798798/p/9786423.html
Copyright © 2011-2022 走看看