内部类

Tags : Java,Inner Class


1. 内部类的作用:

  1. 提供了更好的封装,可以把内部类隐藏在外部类里, 不允许同一个包的其他类访问该类。(==更清楚的组织逻辑==)

    • 例如在GUI中, 如果我要给MyFrame里的一个Button添加一个监听器, 那么对于其他类(其他Frame)来说, 完全没有必要访问这个监听器类, 那么我便可以把这个监听器类设成这个Frame的内部类, 更严谨的来说, 可以设成private class, 从语法上就把它限制死了, 其他的类根本没有办法访问这个内部类。这时候疑问来了, 不设成内部类, 以后写代码的时候小心一点不访问不调用不就行了吗? 逻辑上是可以的,但是从设计本身来说, ==不该让别人访问的东西就不应该暴露出来==,这才是良好的设计习惯!
       class MyFrame extends Frame {
    
           public void launchFrame() {
    
               Button b = new Button("ok");
               b.addActionListener(new MyMonitor());
               this.add(b);
    
           }
    
           // Inner class
           private class MyMonitor implements ActionListener {
               public void actionPerformed(ActionEvent e) {
               // ...
               }
           }
    
       } 
    
    
  2. 可以方便的访问外部类的成员(属性、方法)

  3. 何时使用内部类?

    该类不允许或者不需要其他类来访问它

2. 成员内部类

1. 非静态内部类

class Cow {

    private double weight;
    private String name;

    public Cow(double weight, String name) {
        this.weight = weight;
        this.name = name;
    }

    public double getWeight() {
        return this.weight;
    }

    public String getName() {
        return this.name;
    }

    public void getCowLegColor() {
        System.out.println(new CowLeg(15.00, "red").color);
    }

    /**
     * Inner class
     * @author EckoTan
     * @version 1.0
     */
    class CowLeg {

        private double weight;
        private String color;

        public CowLeg() {

        }

        public CowLeg(double weight, String color) {
            this.weight = weight;
            this.color = color;
        }

        public double getWeight() {
            return this.weight;
        }

        public String getColor() {
            return this.color;
        }

        public void info() {
            System.out.println("Name of the cow: " + name);
            System.out.println("Weight of the cow:" + Cow.this.weight);
            System.out.println("Weight of the cow's leg:" + this.weight);
        }
    }

}

public class TestInner {

    public static void main(String[] args) {

        Cow c = new Cow(100.00, "A");
        Cow.CowLeg leg = c.new CowLeg(10.00, "white");
        leg.info();
        c.getCowLegColor();

    }

}
  1. 非静态内部类可以方便的访问外部类的成员(属性、方法)

    这是因为:==在非静态内部类对象里,保存了一个它寄存的外部类对象的引用==

    • 当在非静态内部类的方法内访问某个变量时:
      系统首先在方法内部查找是否存在该名字的局部变量, 若存在就使用该变量;
      若方法不存在, 就去内部类中查找;
      若内部类中不存在, 就会去外部类中查找;
      若外部类中也没有, 报错。

    例如: 内部类CowLeg中的info()方法中访问name,是访问外部类Cow中的name

    • 如果外部类属性、内部类属性与内部类方法里的局部变量同名, 可以通过this外部类类名.this区分

      例如:

        System.out.println("Weight of the cow:" + Cow.this.weight);
    
        System.out.println("Weight of the cow's leg:" + this.weight);
    • 非静态内部类的成员可以访问外部类的private成员, 但反过来就不成立了。 非静态内部类的成员只在非静态内部类范围内是可知的, 并不能被外部类直接调用。如果外部类需要访问非静态内部类成员, 必须==显式创建非静态内部类对象调用、访问其实例成员==

      例如:在Cow中的getCowLegColor()方法想访问CowLeg中的color

      public void getCowLegColor() {
      
         System.out.println(new CowLeg(15.00, "red").color);
      
      }
      
  2. 非静态内部类和外部类对象的关系

    非静态内部类对象必须==寄存==在外部类对象里, 而外部类对象则==不必一定==有非静态内部类对象寄存在里面。 (有点类似寄生的关系, 内部类是寄生物, 外部类是宿主,寄生物必须在宿主里面存在, 因此有非静态内部类对象必然要由外部类对象, 但是宿主里面不必一定要有寄生物, 所以外部类对象里不一定有非静态内部类对象。)

  3. 根据静态成员不能访问非静态成员的规则, 外部类的静态方法、静态代码==不能访问非静态内部类==(包括不能使用非静态内部类定义的变量、 不能创建非静态内部类实例等)。 另外, Java**不允许**在非静态内部类里定义静态成员(==非静态内部类里不能有静态方法, 静态属性, 静态初始化块==)。

    public class TestStatic {
    
       private class In {
       }
    
       // Static method of outer class
       public static void main(String[] args) {
    
           // Wrong!
           new In();
       }
    }

2. 静态内部类

如果用static来修饰一个内部类, 那么这个内部类就变成了是外部类类相关的, 属于整个外部类, 而不再是单独属于外部类的某个对象。

  1. 静态内部类可以包含静态成员, 也可以包含非静态成员。 根据静态成员不能访问非静态成员的规则,静态内部类不能访问外部类的实例成员, 只能访问外部类的类成员(有static修饰的),即使是静态内部类的非static方法也不能访问外部类的实例成员。(因为静态内部类是外部类的类相关, 而非外部类的对象相关。也就是说, 静态内部类的对象不是寄存在外部类的对象里, 而是寄存在外部类的类本身中。换而言之, 当静态内部类的对象存在时, 并不存在一个被它寄存的外部类对象。==静态内部类的对象里只有外部类的类引用,而没有外部类对象的引用。==)
    public class TestStaticInnerClass {

        private int num1 = 5;
        private static int num2 = 0;

        private static StaticInnerClass {

            // Wrong!
            System.out.println(num1);

            // Correct!
            System.out.println(num2);
        }
    }
  1. 静态内部类与外部类的关系

    外部类依然不能直接访问静态内部类的成员, 但可以:
    (1) 使用静态内部类的类名作为调用者来访问静态内部类的类成员(有static修饰的)

    “`
    内部类类名.类成员

    ``
    (2) 使用静态内部类的对象作为调用者来访问静态内部类的实例成员(无
    static`修饰的)

         内部类对象.实例成员  
    

    例如:

    public class Outer {

        private static class StaticInnerClass {
            private static int num1 = 5;
            private int num2 = 6;
        }

        public void accessInner() {

           // num1 is static.
           System.out.println(StaticInnerClass.num1);

           // num2 is not staitc.
           System.out.println(new StaticInnerClass().num2);

        }
    }

3.使用内部类

  1. 在外部类内部使用内部类

    与平常使用普通的类没有大的区别, 唯一需要注意的是:不要再外部类的静态成员(静态方法, 静态初始化块)中使用非静态内部类静态成员不能访问非静态成员

  2. 在外部类以外使用非静态内部类

    • 如果希望在外部类以外的地方访问内部类, ==则内部类的modifier不能使用private==, private修饰的内部类只能在其外部类里使用

    • 因为非静态内部类的对象必须寄存在外部类的对象里, 因此创建非静态内部类对象之前, ==必须先创建外部类对象(非静态内部类的构造方法必须通过其外部类对象来调用)==

      syntax:

      OuterInstance.new InnerConstructor()
      

      例如:第一段代码中在TestInner这个类中创建leg这个非静态内部类CowLeg的对象

      Cow c = new Cow(100.00, "A");
      Cow.CowLeg leg = c.new CowLeg(10.00, "white");
      

      以上代码也可以写成:

      Cow.CowLeg leg = new Cow(100.00, "A").new CowLeg(10.00, "white");
      
  3. 在外部类以外使用静态内部类

    因为静态内部类是外部类类相关的, 所以创建静态内部类对象时无需创建外部类对象。

    syntax:

       new OuterClass.InnerConstructor();
    

    例 :

    class StaticOut {
    
       static class StaticIn {
    
       }
    }
    
    public class TestStatic {
    
       public static void main(String[] args) {
    
           StaticOut.StaticIn in = new StaticOut.StaticIn();
       }
    }

    ==从以上代码可以看出:静态内部类和非静态内部类声明变量的语法完全相同, 唯一区别是在创建内部类对象时, 静态内部类只需使用外部类来调用构造方法, 非静态内部类必须使用外部类对象来调用构造方法。==

局部内部类

如果把一个内部类放在方法里面定义, 则这个内部类就是一个局部内部类, 仅仅在该方法内有效。

局部内部类不能使用访问控制符和static修饰

例 :

    public class TestLocalInner {
        public static void main(String[] args) {

            class LocalInner {
                private int a;
            }

            LocalInner in = new LocalInner();
            in.a = 6;
            System.out.println("a = " + in.a);
        }    
    }

匿名内部类

前面提到过, 在GUI中, 如果要给某一个Component或者给window添加一个监听器, 可以使用内部类。

例:

class MyFrame extends Frame {

    public MyFrame(String name) {
           super(name);
        this.setBounds(300, 300, 400, 400);
        this.setVisible(true);
        this.addWindowListener(new MyMonitor());
    }

    class MyMonitor extends WindowAdapter {

        public void windowClosing(WindowEvent e) {
            setVisible(false);
            System.exit(0);
        }

    }
}

上面的内部类也可以写成匿名类 :

class MyFrame extends Frame {

    public MyFrame(String name) {
        super(name);
        this.setBounds(300, 300, 400, 400);
        this.setVisible(true);
        this.addWindowListener(new WindowAdapter {
            public void windowClosing(WindowEvent e) {
                setVisible(false);
                System.exit(0);
            }
        });

    }

}

上面这个匿名类本质的意义是 : 它从WindowAdapter继承, new了这个类的对象出来把它当成WindowAdapter传进addWindowListener这个方法里, 出了这个括号就再也没有人认识它了。

  1. 何时使用匿名内部类?

    • 这个方法内逻辑比较简单, 语句比较少, 而且不需要经常变动
    • 创建那些只需要一次使用的类
  2. 匿名内部类的规则:

    • 不能是抽象类(因为创建匿名内部类的时候会立刻创建其对象, 而抽象类无法创建对象)
    • 不能定义构造器, 因为它没有类名, 但可以定义实例初始化块, 通过初始化快来完成构造器需要完成的事情
  3. 如果匿名内部类需要访问外部类的局部变量, 必须使用final修饰符来修饰外部类的局部变量。

第一次写博客, 如有错漏, 请斧正!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值