美文网首页
Java-面向对象-内部类(内置类、嵌套类)

Java-面向对象-内部类(内置类、嵌套类)

作者: 码农随想录 | 来源:发表于2018-07-16 16:00 被阅读6次

    什么是内部类

    当A类中的内容要被B类直接访问,而A类还需要创建B的对象,访问B的内容时,
    这时,可以将B类定义到A类的内部。这样访问更为便捷。

    将B称之为内部类(内置类,嵌套类)。

    访问方式
    内部类可以直接访问外部类中的所有成员,包含私有的。
    而外部类要想访问内部类中的成员,必须创建内部类的对象。

    当描述事物时,事物的内部还有事物,这个内部的事物还在访问外部事物中的内容。
    这时就将这个事物通过内部类来描述。

    class Outer//外部类。
    {
        private int num = 4;
        class Inner//内部类。
        {
            void show()
            {
                System.out.println("num="+num);
            }
        }
    
        void method()
        {  
            //因为在Outer中访问可以省略Outer.
            /*Outer.*/Inner in = new /*Outer.*/Inner();
            in.show();
        }
    }
    class InnerClassDemo
    {
        public static void main(String[] args)
        {
            Outer out = new Outer();
            out.method();
        }
    }
    

    内部类被访问的方式

    情况一:内部类在成员位置上的被访问方式。
    成员是可以被指定的修饰符所修饰的。
    public:不多见:因为更多的时候,内部类已经被封装到了外部类中,不直接对外提供。

    class Outer//外部类。
    {
        private int num = 4;
        public class Inner//内部类。
        {
            void show()
            {
                System.out.println("num="+num);
            }
        }
    }
    class InnerClassDemo
    {
        public static void main(String[] args)
        {
            //测试情况一:直接访问Outer中的Inner内部类的非静态成员。
            //创建内部类的对象就哦了。内部类作为成员,应该先有外部类对象,再有内部类对象。
            Outer.Inner in = new Outer().new Inner();
            in.show();
    
        }
    }
    

    private:只能内部用

    class Outer//外部类。
    {
        private int num = 4;
        private class Inner//内部类。
        {
            void show()
            {
                System.out.println("num="+num);
            }
        }
        void method()
        {  
            //因为在Outer中访问可以省略Outer.
            /*Outer.*/Inner in = new /*Outer.*/Inner();
            in.show();
        }
    }
    class InnerClassDemo
    {
        public static void main(String[] args)
        {
            Outer out = new Outer();
            out.method();
        }
    }
    

    static:

    class Outer//外部类。
    {
        private static int num = 4;
        public class Inner//内部类。
        {
            void show()
            {
                System.out.println("num="+num);
            }
    //      static void show1(){}//非静态内部类中不允许定义静态成员。仅允许在非静态内部类中定义 静态常量 static final。
    //      如果想要在内部类中定义静态成员,必须内部类也要被静态修饰。
        }
    
        /*
        内部类被静态修饰后,随着Outer的加载而加载。可以把一个静态内部类理解为就是一个外部类。
    
        */
        static class Inner2
        {
            void show2()
            {
                System.out.println("Inner2 show2 run..."+num);
            }
            static void staticShow()
            {
                System.out.println("Inner2 staticShow run");
            }
        }
        void method()
        {
            /*Outer.*/Inner in = new /*Outer.*/Inner();
            in.show();
        }
    }
    class InnerClassDemo
    {
        public static void main(String[] args)
        {
            //对静态内部类中的非静态成员进行调用。
            //因为内部类是静态,所以不需要创建Outer的对象。直接创建内部类对象就哦了。
            Outer.Inner2 in = new Outer.Inner2();
            in.show2();
    //      如果静态内部类有静态成员,该如何访问呢?既然静态内部类已随外部类加载,而且静态成员随着类的加载而加载,
    //      就不需要对象,直接用类名调用即可。
            Outer.Inner2.staticShow();
        }
    }
    

    为什么内部类就能直接访问外部类中的成员

    那是因为内部类其实持有了外部类的引用 外部类.this (Outer.this)
    对于静态内部类不持有 外部类.this 而是直接使用 外部类名(Outer)。

    class Outer
    {
        int num = 3;
        class Inner
        {
            int num = 4;
    
            void show()
            {
                int num = 5;
                System.out.println("num="+num);// 3
                System.out.println("num="+this.num);//4
                System.out.println("num="+Outer.this.num);//5
            }
        }
        
        void method()
        {
    //      System.out.println(num);
            new Inner().show();
        }
    }
    
    
    class InnerClassDemo2 
    {
        public static void main(String[] args) 
        {
            Outer out = new Outer();
            out.method();
        }
    }
    

    内部类其实也可以定义在外部类的局部位置上。

    内部类定义在局部时,只能访问被final修饰的局部变量。
    为啥呢?因为编译生产的class中直接操作那个最终数值了。

    为什么不能访问非最终的局部变量呢?
    生命周期太短,比如例子中的y

    class Outer
    {
        int  num = 3;
        void method()
        {
            final int  x = 10;
    //      final int x = 5;//局部变量。
            int y = 2;
            class Inner//局部内部类。不能被成员修饰符修饰。
            {
                void show()
                {
    //              System.out.println("y="+y);//访问失败。y的生命周期太短了。
                    System.out.println("x="+x);
                    System.out.println("inner show run........"+num);
                }
            }
            new Inner().show();
        }
    }
    class InnerClassDemo3 
    {
        public static void main(String[] args) 
        {
            Outer out = new Outer();
            out.method();
        }
    }
    

    内部类对象对外提供功能的访问方式

    看API,发现类名或者接口名称中有 . 说明是内部类,或者内部接口。

    内部类的延伸。
    内部类是可以继承或者实现外部其他的类或者接口的。

    好处:通过内部类的方式对类进行继承重写,或者接口进行实现。
    通过公共的方式对其内部类对象进行访问。因为通常内部类很有可能被外部类封装其中。
    我们就可以通过父类或者接口的方式访问到内部类对象。

    abstract class AbsDemo
    {
        abstract void show();
    }
    
    class Outer
    {
        int num = 3;
        private class Inner extends AbsDemo
        {
            //重写抽象方法show。
            void show()
            {
                System.out.println("num="+num);
            }
        }
        //获取内部类的对象。 
        public AbsDemo getObject()
        {
            return new Inner();
        }
    
        public void method()
        {
            new Inner().show();
        }
    }
    
    class InnerClassDemo4 
    {
        public static void main(String[] args) 
        {
            Outer out = new Outer();
    //      out.method();
            //如果Inner对外提供,可以如此获取。
    //      Outer.Inner in = out.getObject();
    //      in.show();
            //如果Inner被private 。可以通过父类型获取。
            AbsDemo a = out.getObject();//多态。
            a.show();
        }
    }
    

    匿名内部类

    匿名内部类:其实就是一个带有内容的子类对象。
    格式:new 父类or接口(){子类的内容}
    匿名内部类就是内部类的简化形式。
    别忘了:匿名内部类有前提,内部类必须要继承父类或者实现接口。

    abstract class AbsDemo
    {
        abstract void show();
    }
    
    
    class Outer
    {
        int num = 3;
        /*
        class Inner extends AbsDemo
        {
            void show()
            {
                System.out.println("num="+num);
            }
        }
        */
        public void method()
        {
            
    //      new Inner().show();
            /*
            不想创建具体的子类型。还想创建AbsDemo的子类对象。
            怎么实现呢?没有子类型干脆,直接使用父类型就哦了。
            可是在该例子中是抽象类,怎么可以new对象呢?
            抽象类之所以不能new对象是因为抽象方法没重写。直接重写不就哦了吗?
            */
            new AbsDemo()//这就是传说中的一个AbsDemo的子类对象。只不过这个对象有点胖!这是一个带着内容的子类对象。
                        //这种写法一个称呼:匿名内部类。
            {
                //重写抽象的show方法。
                void show()
                {
                    System.out.println("num===="+num);
                }
            }.show();
    
        }
    }
    class InnerClassDemo5 
    {
        public static void main(String[] args) 
        {
            Outer out = new Outer();
            out.method();
        }
    }
    

    匿名内部类使用

    interface Inter
    {
        void show1();
        void show2();
    }
    class Outer
    {
        int num = 4;
        //在一个类使用一个接口的对象。可以通过内部类来实现。
        /*
        class Inner implements Inter
        {
            public void show1()
            {}
            public void show2()
            {}
        }
        */
        public void method()
        {
            /*
            Inner in = new Inner();
            in.show1();
            in.show2();
            */
            //对其简化,写成匿名内部类的方式。
            Inter in = new Inter()//记住:内部类中一般方法不要过多。阅读性会很差。
            {
                public void show1()
                {}
                public void show2()
                {}
            };
            in.show1();
            in.show2();
            
        }
    }
    class InnerClassDemo6 
    {
        public static void main(String[] args) 
        {
            System.out.println("Hello World!");
        }
    }
    
    interface Inter
    {
        public void show();
    }
    class Outer
    {
        //代码补足。要求使用匿名内部类。
        public static Inter method()
        {
            //既然在Oute类中使用到了Inter的对象。可以使用内部类来完成。
            //需要子类型,只要简化格式即可,因为接口中就只有一个方法。
            return new Inter()
            {
                public void show()
                {
                    //code..;
                }
            };
    //      return new Inner();
        } 
        
        /*
    //  还原成内部类。  当静态方法访问内部类时,内部类必须是静态的。
        static class Inner implements Inter
        {
            public void show(){}
        }
        */
    }
    class InnerClassDemo7 
    {
        public static void main(String[] args) 
        {
            Outer.method().show();
            /*
            Outer.method() //Outer类中有一个method的方法。这个方式静态的。
            Outer.method.show() //能调用show()的必然是对象,说明method方法运算完应该返回一个对象。而且能调用Inter中的show方法,说明这个对象的类型是Inter。
            */
    }
    
    

    匿名内部类和内部类的一个面试题

    class Outer2
    {
        public void method()
        {
            //以下两个对象有区别吗?
            new Object()
            {
                public void show(){}
            }.show();//这个可以编译通过。
    
            Object obj = new Object()
            {
                public void show(){}
            };
    //      obj.show();//编译失败。为啥呢?因为匿名内部类是子类对象,当Object obj指向时,就被提升了Object。而Object类中没有定义show方法,编译失败。
        }
    //  class Inner extends Object
    //  {
    //      public void show(){}
    //  }
    }
    

    相关文章

      网友评论

          本文标题:Java-面向对象-内部类(内置类、嵌套类)

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