毕向东Java基础教程-内部类

2019-12-17  本文已影响0人  Lois_Huang

内部类

定义:将一个类定义在另一个类的里面,里面那个类就称为内部类(内置类,嵌套类)。

访问特点

用法
一般用于类的设计。分析事物时,发现该事物描述中还有事物,而且这个事物还在访问被描述事物的内容,这时就将里面的事物定义成内部类。

细节

Example 1:为什么内部类能直接访问外部类的成员呢?是因为内部持有了外部类的引用-->外部类.this

class Outer
{
    int num = 3;
    class Inner
    {
        int num = 4;
        void show()
        {
            int num = 5;
            System.out.println(num); //打印5
            System.out.println(this.num); //打印4,或者可写为Inner.this.num
            System.out.println(Outer.this.num); //打印3
        }
    }
    public void method()
    {
        new Inner().show();
    }
}
class Demo
{
    public static void main(String[] args)
    {
        new Outer().method();
    }
}

成员内部类

定义:内部类定义在成员位置上。

特点:

Example 1:内部类和其成员都是非静态的

class Outer
{
    private int num = 3;
    class Inner
    {
        void show()
        {
            System.out.println("show run..."+num);
        }
    }
    public void method()
    {
        Inner in = new Inner();
        in.show();
    }
}
class Demo
{
    public static void main(String[] args)
    {
        //直接访问外部类中的内部类中的成员
        Outer.Inner in = new Outer().new Inner(); //不常用,因为一般都将内部类封装了
        in.show();
    }
}

Example 2:内部类为静态,其成员为非静态的

class Outer
{
    private static int num = 3;
    static class Inner
    {
        void show()
        {
            System.out.println("show run..."+num);
        }
    }
    public void method()
    {
        Inner in = new Inner();
        in.show();
    }
}
class Demo
{
    public static void main(String[] args)
    {
        //如果内部类是静态的,相当于一个外部类
        Outer.Inner in = new Outer.Inner();//不需要再创建Outer对象
        in.show();
    }
}

Example 3:内部类和其成员都为静态

class Outer
{
    private static int num = 3;
    static class Inner
    {
        static void show()
        {
            System.out.println("show run..."+num);
        }
    }
    public void method()
    {
        Inner.show();
    }
}
class Demo
{
    public static void main(String[] args)
    {
        Outer.Inner.show();//不需要再创建Outer和Inner对象
    }
}

如果内部类中定义了静态成员,则该内部类也必须是静态的。
如果类中的静态函数想访问内部类,则该内部类必须是静态的。

局部内部类

定义:内部类定义在局部位置上。

特点:

Example 1:示例

class Outer
{
    int num = 3;
    void method()
    {
        int x = 9;
        final int y = 8;
        class Inner
        {       
            void show()
            {
                System.out.println("show..."+num);//可以直接访问外部类中的成员。
                System.out.println("show..."+x); //编译错误,从内部类中访问所在局部中的局部变量x,需要被声明为最终类型
                System.out.println("show..."+y); //可以访问所在局部中的局部变量,但必须是被final修饰的。
            }
        }
        Inner in = new Inner();
        in.show();
    }
    //method()方法外不能访问Inner
}
class Demo
{
    public static void main(String[] args)
    {
        new Outer().method();
    }
}

Example 2:为什么局部变量需要被final修饰,局部内部类才可访问?

class Outer
{
    int num = 3;
    Object method()//若method函数有参数int y,如果想在内部类Inner中访问,也需要写为final int y
    {
        int x = 9;
        class Inner
        {
            void show()
            {
                System.out.println("show..."+x);
            }         
        }
        Object in = new Inner();
        return in;
    }
}
class Demo
{
    public static void main(String[] args)
    {
        Outer out = new Outer();
        Object obj = out.method();
    }
}

method函数执行完就出栈了,x便不存在了,而obj对象仍然存在,于是访问不了x,因此需把x声明为常量。

实质上是,java把局部内部类对象要访问的final型局部变量,复制过来变成该内部类对象中的一个成员变量,这样即使栈中局部变量(含final)已死亡,但由于它是final的,其值是不会发生改变的,因而内部类对象在局部变量死亡后,照样可以访问自己内部维护的一个值跟局部变量一样的成员变量,从而解决这个问题。

注意:java8中匿名/局部内部类访问局部变量时,局部变量已经可以不用加final了,但其实这个局部变量还是final的(表现为对该值初始化后不能再赋值了),只不过不用显式的加上而已,推测可能是编译机制发生了改变。

匿名内部类

定义:局部内部类的简化写法。

前提:内部类必须继承或实现一个外部类或者接口。

格式new 外部类名或者接口名(){覆盖类或者接口中的代码,也可以自定义内容}

简单理解:就是建立一个带内容的外部类或者接口的子类匿名对象。

Example 1:匿名类中重写一个函数

abstract class Demo
{
    abstract void show();
}
class Outer
{
    int num = 4;
    /*
    class Inner extends Demo
    {
        void show()
        {
            System.out.println("show..."+num);
        }
    }
    */
    public void method()
    {
        //new Inner().show();
        new Demo()//new了Demo类的子类对象
        {
            void show()
            {
                System.out.println("show..."+num);
            }
        }.show();
    }
}
class Demo
{
    public static void main(String[] args)
    {
        new Outer().method();
    }
}

Example 2:匿名类中重写两个函数

interface Demo
{
    void show1();
    void show1();
}
class Outer
{
    int num = 4;
    public void method()
    {     
        Demo demo = new Demo() //类似于多态,父类引用指向了子类对象
        {
            public void show1()
            {
                System.out.println("show1..."+num);
            }
            public void show2()
            {
                System.out.println("show2..."+num);
            }
        }
        demo.show1();
        demo.show2();
    }
}

应用:当函数参数是接口类型时,而且接口中的方法不超过三个,可以用匿名内部类作为实际参数进行传递。

/*---以前的写法----*/
interface Inter
{
    void show1();
    void show2();
}
class InterImpl implements Inter
{
    public void show1(){}
    public void show2(){}
}
class Demo
{
    public static void main(String[] args)
    {
        show(new InterImpl());
    }
    public static void show(Inter in)
    {
        in.show1();
        in.show2();
    }
}
/*---可以改为以下写法----*/
interface Inter
{
    void show1();
    void show2();
}
class Demo
{
    public static void main(String[] args)
    {
        show(new Inter()
             {
                 public void show1(){}
                 public void show2(){}
             });
    }
    public static void show(Inter in)
    {
        in.show1();
        in.show2();
    }
}

细节

class Outer
{
    void method()
    {
        new Object()
        {
            public void show()
            {
                System.out.println("show run");
            }
        }.show();//创建的Object的子类对象,调用的子类对象的方法
        /*
        Object obj = new Object(){
            public void show()
            {
                System.out.println("show run");
            }
        };
        obj.show(); //编译错误,在java.lang.Object里找不到show()方法,因为匿名内部类这个子类对象已经被向上转型为了Object类型,这样就不能使用子类特有的方法了,只能调用父类或接口中存在的方法。
        */
    }
}
class Demo
{
    public static void main(String[] args)
    {
        new Outer().method();
    }    
}
上一篇下一篇

猜你喜欢

热点阅读