zoukankan      html  css  js  c++  java
  • 内部类的概念和分类——Java

    /*
    如果一个事物的内部包含另一个事物,那么这就是一个类内部包含另一个类。
    例如:身体和心脏的关系。又如:汽车和发动机的关系。
    
    分类:
    1. 成员内部类
    2. 局部内部类(包含匿名内部类)
    
    成员内部类的定义格式:
    修饰符 class 外部类名称 {
        修饰符 class 内部类名称 {
            // ...
        }
        // ...
    }
    
    注意:内用外,随意访问;外用内,需要内部类对象。
    
    ==========================
    如何使用成员内部类?有两种方式:
    1. 间接方式:在外部类的方法当中,使用内部类;然后main只是调用外部类的方法。
    2. 直接方式,公式:
    类名称 对象名 = new 类名称();
    外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();】
     */

    一:成员内部类的使用

    public class Demo01InnerClass {
    
        public static void main(String[] args) {
            Body body = new Body(); // 外部类的对象
            // 通过外部类的对象,调用外部类的方法,里面间接在使用内部类Heart
            body.methodBody();
            System.out.println("=====================");
    
            // 按照公式写:
            Body.Heart heart = new Body().new Heart();
            heart.beat();
        }
    
    }
    public class Body { // 外部类
    
        public class Heart { // 成员内部类
    
            // 内部类的方法
            public void beat() {
                System.out.println("心脏跳动:蹦蹦蹦!");
                System.out.println("我叫:" + name); // 正确写法!
            }
    
        }
    
        // 外部类的成员变量
        private String name;
    
        // 外部类的方法
        public void methodBody() {
            System.out.println("外部类的方法");
            new Heart().beat();
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }

    内部类的同名变量访问

    // 如果出现了重名现象,那么格式是:外部类名称.this.外部类成员变量名
    public class Outer {
    
        int num = 10; // 外部类的成员变量
    
        public class Inner /*extends Object*/ {
    
            int num = 20; // 内部类的成员变量
    
            public void methodInner() {
                int num = 30; // 内部类方法的局部变量
                System.out.println(num); // 局部变量,就近原则
                System.out.println(this.num); // 内部类的成员变量
                System.out.println(Outer.this.num); // 外部类的成员变量
            }
    
        }
    
    }
    public class Demo02InnerClass {
    
        public static void main(String[] args) {
            // 外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
            Outer.Inner obj = new Outer().new Inner();
            obj.methodInner();
        }
    
    }

    二:局部内部类

    /*
    如果一个类是定义在一个方法内部的,那么这就是一个局部内部类。
    “局部”:只有当前所属的方法才能使用它,出了这个方法外面就不能用了。
    
    定义格式:
    修饰符 class 外部类名称 {
        修饰符 返回值类型 外部类方法名称(参数列表) {
            class 局部内部类名称 {
                // ...
            }
        }
    }
    
    小节一下类的权限修饰符:
    public > protected > (default) > private
    定义一个类的时候,权限修饰符规则:
    1. 外部类:public / (default)
    2. 成员内部类:public / protected / (default) / private
    3. 局部内部类:什么都不能写
     */
    public class Outer {
    
        public void methodOuter() {
            class Inner { // 局部内部类
                int num = 10;
                public void methodInner() {
                    System.out.println(num); // 10
                }
            }
    
            Inner inner = new Inner();
            inner.methodInner();
        }
    
    }
    public class DemoMain {
    
        public static void main(String[] args) {
            Outer obj = new Outer();
            obj.methodOuter();
        }
    
    }
    /*
    局部内部类,如果希望访问所在方法的局部变量,那么这个局部变量必须是【有效final的】。
    
    备注:从Java 8+开始,只要局部变量事实不变,那final关键字可以省略。
    
    原因:
    1. new出来的对象在堆内存当中。
    2. 局部变量是跟着方法走的,在栈内存当中。
    3. 方法运行结束之后,立刻出栈,局部变量就会立刻消失。
    4. 但是new出来的对象会在堆当中持续存在,直到垃圾回收消失。
     */
    public class MyOuter {
    
        public void methodOuter() {
            final int num = 10; // 所在方法的局部变量
    
            class MyInner {
                public void methodInner() {
                    System.out.println(num);
                }
            }
        }
    
    }

    三:匿名内部类

    /*
    如果接口的实现类(或者是父类的子类)只需要使用唯一的一次,
    那么这种情况下就可以省略掉该类的定义,而改为使用【匿名内部类】。
    
    匿名内部类的定义格式:
    接口名称 对象名 = new 接口名称() {
        // 覆盖重写所有抽象方法
    };
    
    对格式“new 接口名称() {...}”进行解析:
    1. new代表创建对象的动作
    2. 接口名称就是匿名内部类需要实现哪个接口
    3. {...}这才是匿名内部类的内容
    
    另外还要注意几点问题:
    1. 匿名内部类,在【创建对象】的时候,只能使用唯一一次。
    如果希望多次创建对象,而且类的内容一样的话,那么就需要使用单独定义的实现类了。
    2. 匿名对象,在【调用方法】的时候,只能调用唯一一次。 如果希望同一个对象,调用多次方法,那么必须给对象起个名字。
    3. 匿名内部类是省略了【实现类/子类名称】,但是匿名对象是省略了【对象名称】 强调:匿名内部类和匿名对象不是一回事!!!
    */
     1 public class DemoMain {
     2 
     3     public static void main(String[] args) {
     4 //        MyInterface obj = new MyInterfaceImpl();
     5 //        obj.method();
     6 
     7 //        MyInterface some = new MyInterface(); // 错误写法!
     8 
     9         // 使用匿名内部类,但不是匿名对象,对象名称就叫objA
    10         MyInterface objA = new MyInterface() {
    11             @Override
    12             public void method1() {
    13                 System.out.println("匿名内部类实现了方法!111-A");
    14             }
    15 
    16             @Override
    17             public void method2() {
    18                 System.out.println("匿名内部类实现了方法!222-A");
    19             }
    20         };
    21         objA.method1();
    22         objA.method2();
    23         System.out.println("=================");
    24 
    25         // 使用了匿名内部类,而且省略了对象名称,也是匿名对象
    26         new MyInterface() {
    27             @Override
    28             public void method1() {
    29                 System.out.println("匿名内部类实现了方法!111-B");
    30             }
    31 
    32             @Override
    33             public void method2() {
    34                 System.out.println("匿名内部类实现了方法!222-B");
    35             }
    36         }.method1();
    37         // 因为匿名对象无法调用第二次方法,所以需要再创建一个匿名内部类的匿名对象
    38         new MyInterface() {
    39             @Override
    40             public void method1() {
    41                 System.out.println("匿名内部类实现了方法!111-B");
    42             }
    43 
    44             @Override
    45             public void method2() {
    46                 System.out.println("匿名内部类实现了方法!222-B");
    47             }
    48         }.method2();
    49     }
    50 
    51 }
    public interface MyInterface {
    
        void method1(); // 抽象方法
    
        void method2();
    
    }
    public class MyInterfaceImpl implements MyInterface {
        @Override
        public void method1() {
            System.out.println("实现类覆盖重写了方法!111");
        }
    
        @Override
        public void method2() {
            System.out.println("实现类覆盖重写了方法!222");
        }
    }
  • 相关阅读:
    数据类型装换
    变量及数据类型
    27 网络通信协议 udp tcp
    26 socket简单操作
    26 socket简单操作
    14 内置函数 递归 二分法查找
    15 装饰器 开闭原则 代参装饰器 多个装饰器同一函数应用
    12 生成器和生成器函数以及各种推导式
    13 内置函数 匿名函数 eval,exec,compile
    10 函数进阶 动态传参 作用域和名称空间 函数的嵌套 全局变量
  • 原文地址:https://www.cnblogs.com/zeon/p/13521779.html
Copyright © 2011-2022 走看看