zoukankan      html  css  js  c++  java
  • 内部类(成员内部类、局部内部类(包括匿名内部类))

    一个事物的内部包含另一个事物。一个类里面包含另一个类,这个类叫内部类,包含它的叫它外部类。

    例如:身体和心脏的关系;汽车和引擎的关系。

    心脏、引擎只有在身体和汽车中才有用。内部类也一样。

    分类:

      1.成员内部类;

      2.局部内部类(包括匿名内部类);

    1.成员内部类

    /*
    修饰符 class 外部类名称{
    修饰符 class 内部类名称{
    ......
    }
    ......
    }
    */
    public class Outer {
    private String name;

    public class Inter{
    public void InterMethod(){
    System.out.println("内部方法");
    System.out.println("姓名:" + name); // 成员内部类可以访问外部类属性
    }
    }

    public void fun1(){
    Inter in = new Inter();
    in.InterMethod();
    }
    }

    编译后,这个类的class文件保存在磁盘里

     内部类的使用方式

      在外部类中可以直接通过 new 对象的方式使用。

      在其他类中访问:

        1.间接方式:在外部类的方法中使用内部类,而在其他类中使用就 new 外部类调用这个方法; 

    /**
     * 其他类使用内部类
     */
    public class OuterDemo1 {
        public static void main(String[] args) {
            Outer out = new Outer();
            out.fun1();
        }
    }

        2.直接方式,直接创建出内部类

        公式: 外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();

    public class OuterDemo2 {
        public static void main(String[] args) {
            Outer.Inter in = new Outer().new Inter();
    
            in.InterMethod();
        }
    }

    问题:在外部类、内部类、内部类方法体出现相同名称属性,如何输出相应的值呢?

    解决:

    public class OuterDemo3 {

    private String name ="外";

    class Inter{
    private String name = "内";
    public void interMethod(){
    String name = "方法";
    System.out.println(name); // 输出: 方法,就近原则
    System.out.println(this.name); // 输出: 内
    System.out.println(OuterDemo3.this.name); // 输出: 外
    }
    }
    }

    2.局部内部类

      在方法体内定义一个类,出了这个方法,就无法使用这个类(所以其他类无法使用【局部内部类】)

      普及:

      权限修饰符的使用规则:

      public  >  protected  >  (default)  >  private 

      1.外部类:能使用 public  / (defautl)  修饰

      2.成员内部类: publi / protected / (default) / private

      3.局部内部类:什么都不写

    public class Test {

    public void fun(){
    final int num = 100;
    class Fun{
    private void fun2(){
    System.out.println(num);
    }
    }
    Fun fun = new Fun();
    fun.fun2();
    }
    }

    问题:为什么访问所在方法的局部变量,必须要有final修饰?

    原因(本质是生命周期问题):

      1.内部类 new 出来的对象在堆内存中;

      2.局部变量跟着方法,在栈内存中;

      3.方法运行完,立刻出栈,局部变量隔着消失;

      4.但 new 出来的对象,会在堆内存持续存在,知道垃圾回收;

      5.所以,要将该内存复制到常量池才能保存继续使用。

    3.匿名内部类(重要)

      往常,我们要使用接口方法,得先定义该接口的实现类 -> 重写该接口的所有抽象方法 -> new 实现类使用。

      而如果接口的实现类只是用唯一的一次,那么这种情况就可以省略该实现类的定义,而改为使用 【匿名内部类】

    接口

    public interface MyInteface {
        void method();
    }

    使用【匿名内部类】

    /**
     * 格式:
     *      接口名称  对象名 = new 接口名称(){
     *          // 覆盖重写所有抽象方法
     *      };
     */
    public class AnonymityTest2 {
        public static void main(String[] args) {
            MyInteface my = new MyInteface(){
                @Override
                public void method() {
                    System.out.println("匿名内部类方法");
                }
            };
            my.method();
        }
    }
    

      很多人一开始可能会有误解:不是【匿名内部类】吗? MyInteface my = new MyInteface(){...} 这不是有名字么?

      先看,对于"new MyInteface(){...};" 的解析:

        1)new  代表对象创建的动作;

        2)接口名称   【匿名内部类】要实现的接口;

        3){...}   这才是【匿名内部类】的内容,里面重写着接口的所有抽象方法

      它光秃秃的,的确没名没姓的。

      而 MyInteface my = new MyInteface(){...} 中的 my 是对象名,它是供你调用匿名类方法的对象。

    ps:匿名内部类、匿名对象

      1、【匿名内部类】表示,在创建对象是,只能使用唯一一次。

        如果希望多次创建对象,而且类的内容一样的话,那还是单独定义实现类更方便。

    public class AnonymityTest2 {
        public static void main(String[] args) {
            MyInteface my1 = new MyInteface(){
                @Override
                public void method() {
                    System.out.println("匿名内部类方法");
                }
            };
            my1.method();
            
            MyInteface my2 = new MyInteface(){
                @Override
                public void method() {
                    System.out.println("匿名内部类方法");
                }
            };
            my2.method();
        }
    }
    

      2.【匿名对象】表示,在调用方法时,只能调用唯一一次。

        如果希望同一对象,调用多次方,那么还是给对象起个名把。

            new MyInteface(){
                @Override
                public void method1() {
                    System.out.println("匿名内部类方法1");
                }
    
                @Override
                public void method2() {
                    System.out.println("匿名内部类方法2");
                }
            }.method1();
            
            new MyInteface(){
                @Override
                public void method1() {
                    System.out.println("匿名内部类方法1");
                }
                @Override
                public void method2() {
                    System.out.println("匿名内部类方法2");
                }
            }.method2();
    

      3.   【匿名内部类】是省略了 <实现类 / 子类>

        【匿名对象】是省略了 <对象名称>

        两者不是一回事。

    public class AnonymityTest {
        public static void main(String[] args) {
            fun1();
        }
    
        private static void fun1() {
            // 对于 Thread 来说,这就是【匿名对象】
            // 对于 Runnable 来说,这就是【匿名内部类】
            new Thread( new Runnable(){
                @Override
                public void run() {
    
                }
            }).start();
        }
    }
    

      

  • 相关阅读:
    Linux设置静态IP
    jenkins+findbugs
    CentOS 6.6 安装 Node.js
    未来物联网、人工智能无法迈过的技术是什么
    未来物联网、人工智能无法迈过的技术是什么
    spss-数据清洗-处理重复数据
    spss-数据清洗-处理重复数据
    大数据时代数据管理方式研究
    大数据时代数据管理方式研究
    Excel表格文本格式的数字和数字格式如何批量转换
  • 原文地址:https://www.cnblogs.com/jr-xiaojian/p/12197986.html
Copyright © 2011-2022 走看看