• Java面向对象进阶篇(内部类)


    一. 概念

      大部分时候,类被定义成一个独立的程序单元。有时候把一个类放在另一个类内部定义,这个类被称为内部类,包含内部类的类也被称为外部类。

    内部类的主要作用:

    • 内部类提供良好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类。
    • 内部类成员可以直接访问外部类的私有数据,因为内部类被当成外部类成员,通一个类的成员之间可以互相访问。但是外部类不能访问内部类的实现细节,例如内部类的成员变量。
    • 匿名内部类适合用于创建哪些仅需要一次使用的类。

    内部类与普通外部类的区别

    • 内部类比外部类可以多使用三个修饰符:private、protected、static,外部类不可以使用这三个修饰符
    • 非静态内部类不能拥有静态成员

       定义内部类非常简单,只要把一个类放在另一个类内部定义即可。这里的类内部包括类中的任何位置,甚至方法中也可以定义内部类(方法中定义的内部类被称为局部内部类)。

      内部类作为外部类的成员,可以使用任意访问权限修饰符,如private,protected,public。外部类只有包访问权限和公开访问权限。

      编译有n个内部类的Java源文件时,文件所在的路径会生成多个 (.class)文件,分别是一个OuterClassName.class和n个OuterClassName$InnerClassName.calss文件

    1.1 非静态内部类

    成员内部类分为两种,静态内部类和非静态内部类,静态内部类使用static修饰 。

    非静态内部类里不能有静态方法,静态成员变量,静态初始化块,静态声明会引发错误

    当在非静态内部类的方法内访问某个变量时,系统优先在方法的局部变量,所在内部类的全局变量,再到外部类的查找。如果都找不到则会编译出错

    如果外部类的成员变量与内部类的成员变量重名,则使用this和OuterClassName.this作为限定来区分

    非静态内部类的成员可以访问外部类的private成员,但反过来就不成立了。非静态内部类的成员只在非静态内部类范围是可知的。并不能被外部类直接使用。如果外部类需要访问非静态内部类

    的成员包括private修饰的成员,则必须显式创建非静态内部类对象来调用访问其实例变量 。

    根据静态成员不能访问非静态成员的规则,外部类的静态方法,静态代码块不能访问非静态内部类。包括不能使用静态内部类定义变量、创建实例等。

    /**
     * 
     */
    package com.gdut.innerclass.test;
    
    /**
     * @author 12539
     *
     */
    public class Outer {
        
        private int outProp = 9;
        
        class Inner
        {
            private int intProp = 5;
            public void accessOutProp() {
                //非静态内部类可以直接访问外部类的private成员变量
                System.out.println("外部类的Prop的值:"+outProp);
            }    
        }
        
        private void accessInnerProp() {
            //System.out.println("内部类的Prop的值:"+intProp);
            Inner inner = new Inner();//需要访问内部类的实例变量必须显式创建内部类对象才能访问
            System.out.println("内部类的Prop的值:"+inner.intProp);
        }
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            Outer outer = new Outer();
            outer.accessInnerProp();
    
        }
    
    }

    输出:内部类的Prop的值:5

    1.2 静态内部类

     静态内部类使用static修饰属于外部类本身,不属于外部类对象。

    静态内部类可以包含静态成员也可以包含非静态成员。根据静态成员不能访问非静态成员的原则,静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。

    外部类依然不能直接访问静态内部类的成员,可以使用静态内部类的类名作为调用者访问内部静态成员,可以使用静态内部类的对象作为调用者访问内部非静态成员。

    Java允许在接口里定义内部类,接口定义的内部类默认使用public static修饰,接口内部类只能是静态内部类。

     

    1.3 使用内部类

    1.3.1 在外部类内部使用内部类

    从前面程序可以看出,在外部类内部使用内部类跟平时使用没有太大的区别。唯一区别就是外部类的静态成员不能使用非静态内部类

    1.3.2 在外部类以外使用非静态内部类

    private修饰的内部类只能在外部类内部使用。

    在外部类以外的地方定义内部类变量的语法格式

     

    OuterClass.InnerClass varName

     

    在外部类以外的地方创建非静态内部类的实例语法如下:

    OuterInstance.new InnerConstrutor()

    如果需要在外部类以外的地方创建非静态内部类的子类。尤其要注意非静态内部类的构造器必须通过外部类对象调用

    public class SubClass extends Outer.Inner{
        
        public SubClass(Outer outer) {
            outer.super();//通过outer对象显式调用Inner构造器
        }
    
    }

    1.3.3 在外部类以外使用静态内部类

    因为静态外部类是类相关的,因此创建静态内部类对象无需创建外部类对象。语法格式如下:

    new OuterClass.InnerConStrutor()

     下面程序示范了实例

    package com.gdut.innerclass.test;
    
    class StaticOut{
        static class StaticIn{
            public StaticIn() {
                System.out.println("静态内部类的构造器");
            }
        }
    }
    public class CreateStaticInnerInstance {
    
        public static void main(String[] args) {
            
        StaticOut.StaticIn in = new StaticOut.StaticIn();
        }
    
    }

    1.4 局部内部类

    在方法里定义内部类,这个内部类就是局部内部类,局部内部类只在该方法里有效,不能使用访问控制修饰符和static修饰

    如果需要用局部内部类定义变量、创建实例或派生子类,那都只能在局部内部类所在的方法内进行

    package com.gdut.innerclass.test;
    
    public class LocalInnerClass {
    
        public static void main(String[] args) {
            class InnerBase{
                int a;
            }
            class SubClass extends InnerBase{
                int b;
            }
            
            SubClass subClass = new SubClass();
            subClass.a = 5;
            subClass.b = 3;
            System.out.println("SubClass对象的a和b实例变量是"+subClass.a+","+subClass.b);
    
        }
    
    }

    1.5 Java8改进的匿名内部类

    匿名内部类适合那种只需要一次使用的类,创建匿名内部类时会立即创建一个该类的实例,这个类定义立即消失。匿名内部类不能重复使用,语法格式

    new 实现接口()|父类构造器(实参列表){
    
    //匿名内部类类体部份
    
    }
    • 匿名内部类必须且只能继承一个父类或实现一个接口。
    • 匿名内部类不能是抽象类,因为系统在创建匿名内部类时,会立即创建匿名内部类的对象。匿名内部类不能定义构造器。因为它没有类名,但是它可以定义初始化块,可以通过初始化块完成构造器完成的事情
    • package com.gdut.innerclass.test;
      interface Product{
          public double getPrice();
          public String getName();
      }
      
      public class Anonymous {
      public void test(Product p) {
          System.out.println("买了一个"+p.getName()+",花掉了"+p.getPrice()+"元。");
      }
          
          public static void main(String[] args) {
              Anonymous an = new Anonymous();
              an.test(new Product() {
                  
                  @Override
                  public double getPrice() {
                      return 5.78;
                  }
                  
                  @Override
                  public String getName() {
                      return "牙膏";
                  }
              });
      
          }
      
      }

      输出:买了一个牙膏,花掉了5.78元。

      通过实现接口来创建匿名内部类时,匿名内部类不能显式创建构造器,他只有一个隐式的无参数构造器。故new接口名后的括号里不能传入参数值。

    如果通过继承父类创建匿名内部类时,匿名内部类将拥有和父类相似的构造器,此处的相似指拥有相同的形参列表。

    当创建匿名内部类时,必须实现接口或抽象父类里的所有抽象方法。如果有需要也可以重写父类的普通方法。

    JDK8以前,Java要求被局部内部类,匿名内部类访问的局部变量必须使用final修饰,从Java8开始,这个限制被取消了,Java8更加智能:如果局部变量被匿名内部类访问,那么该局部变量相当于自动使用了final修饰

     

  • 相关阅读:
    javascript弹出窗口代码
    DOM的核心: Node
    AjaxControlToolkit学习系列(1) DragPanelExtender
    nodeName、nodeValue 以及 nodeType 简单解析
    AjaxControlToolkit学习系列(3) AnimationExtender
    childNodes
    javascript面向对象技术基础(四)
    自定义控件实现无刷新上传图片,立即显示缩略图,保存图片缩略图<原创>
    ADO.NET朝花夕拾(一)
    javascript面向对象技术基础(三)
  • 原文地址:https://www.cnblogs.com/yumiaoxia/p/9020753.html
Copyright © 2020-2023  润新知