美文网首页
内部类,匿名内部类

内部类,匿名内部类

作者: 云承寒 | 来源:发表于2017-05-07 21:25 被阅读0次

    内部类应用场景

    描述事物A时,发现需要在事物A内部,封装一个能访问A属性等数据的事物B来只服务于事物A。
    即如果一个类附属于另一个类且只应用于这个类,则可以用内部类,比如Android的Adapter里的ViewHolder。

    使用内部类的优势
    • 可以把内部类隐藏在外部类内,不允许同一个包中的其他类访问该类。

    • 内部类定义于外部类的成员变量位置,因此内部类可以使用任意访问控制符,如 public 、 protected 、 private 等,同时也可以访问外部类任意数据。

    • 内部类隐式的持有了一个外部类的引用,所能用外部类全部属性,要想打破引用就要用静态内部类。

    • 可以实现多重继承。

    成员内部类
    public static void main(String[] args) {
            Outer.Inner inner = new Outer().new Inner();
            inner.test();
    }
    
    class Outer {
        public int i = 1;
    
        class Inner {
            public int i = 2;
    
            public void test() {
                System.out.println("避免就近原则,调用外部类同名变量" + Outer.this.i);
            }
        }
    }
    
    静态内部类
    public static void main(String[] args) {
            Outer.Inner inner = new Outer.Inner();//注意调用方式
            inner.test();
    }
    
    class Outer {
        public static int i = 1;
    
        static class Inner {
    
            public void test() {
                System.out.println("静态内部类只能引用外部类的静态成员" + i);
            }
        }
    }
    
    局部内部类
    class Outer {
        
        public void test() {    
        
            class Inner {   
            
                public void innerTest() {
                    System.out.println("InnerTest" );
                }
            }
    
            Inner inner = new Inner();
            inner.innerTest();
        }
    }
    //调用内部类方式
    Outer outer = new Outer();
    outer.test();
    
    局部内部类访问局部变量问题
    class Outer {
    
        int num = 3;
    
        public void test() {
            //JDK低于1.8
            //final int x = 9;
    
           //JDK1.8
                    int x = 9;
    
            class Inner {
                public void show() {
                    System.out.println("Inner...." + x);
                }
            }
            
            Inner inner = new Inner();
            inner.show();
        }
    }
    

    如果你的JDK为1.8以下,想访问就要把局部变量声明成final,而1.8后的JDK不需要(JDK1.8帮你隐藏了,实际还是存在final)。

    至于为什么访问就要把局部变量声明成fianl?
    因为局部变量的生命周期是一旦出作用域就马上被释放,然而这时new Inner这个对象还在等待Java垃圾回收机制来回收并没有马上释放消失,相应的它内部访问局部变量也没有消失。
    如此给人的感觉就是这个局部变量的生命周期延长了,这就违背Java的设计原则了。
    所以Sun想了解决方案,如果一个局部内部类访问一个局部变量的时候,那就让该局部内部类访问该局部变量的复制品。
    如此什么复制品?
    完全一样的才是复制品。
    为了保证值完全一样不能随意变换,所以这个变量要声明成final。


    匿名内部类

    • 没有类名的类就称作匿名内部类,只是没有类名,类的其他成员都具备。

    • 匿名内部类的好处
      简化书写,能尽快的释放空间(作为实参传值,出作用域就释放)。

    继承方式的匿名内部类
    abstract class Demo {
    
        public abstract void read();
    
    }
    
    public class Run {
        public static void main(String[] args) {
    
            //注意这里创建的是继承Demo类的子类对象
            new Demo() {
    
                @Override
                public void read() {
                    System.out.println("Read");
                }
            }.read();
    
        }
    }
    
    如果想通过匿名内部类实现调用多个方法,需要将返回值设为基类
    abstract class Demo {
    
        public abstract Demo read();
    
        public abstract Demo write();
    
    }
    
    public class Run {
        public static void main(String[] args) {
    
            // 注意这里是继承Demo类的对象
            new Demo() {
    
                @Override
                public Demo read() {
                    System.out.println("Read");
                    return this;
                }
    
                @Override
                public Demo write() {
                    System.out.println("Write");
                    return this;
                }
            }.read().write();
    
        }
    }
    

    如果匿名内部类中定义了其特有的方法,想都不要想调用,不明白的去看我写的多态篇找原因。

    实现方式的匿名内部类
    //接口
    interface Demo {
        void read();
    }
    
    //测试类
    class Test {
    
        public void test() {
       //注意:这是匿名的接口实现类对象,不是接口new。
            new Demo() {
    
                @Override
                public void read() {
                    System.out.println("read");
                }
    
            }.read();
        }
    }
    
    public class Run {
        public static void main(String[] args) {
            
            Test test = new Test();
            test.test();
        }
    }
    

    在实际开发中匿名内部类一般用于实参
    • 假设有一个函数的形参需要传一个接口类的实参,这个实参仅在用时调用。

    • 如果专门去写一个实现类是不是太low,那么这时候就可以用上匿名内部类。

    interface Demo {
        void read();
    }
    
    public class Run {
        public static void main(String[] args) {
    
            test(new Demo() {
    
                @Override
                public void read() {
                    System.out.println("Read");
                }
            });
    
        }
    
        public static void test(Demo demo) {
            demo.read();
        }
    }
    

    相关文章

      网友评论

          本文标题:内部类,匿名内部类

          本文链接:https://www.haomeiwen.com/subject/qnoutxtx.html