天天看点

Java 内部类详解(成员内部类、静态内部类、局部内部类、匿名内部类)

内部类概念:

一个类定义在另外一个类内部,就称它为内部类。
           

内部类的应用场景

我们在描述A事物的时候,发现描述的A事物内部还存在另外一个比较复杂的B事物时候,而且这个比较复杂B事物还需要访问A事物的属性等数据,那么这时候我们就可以使用内部类描述B事物。

比如: 人--->心脏
class 人{
    血
    氧气
    等....
    class 心脏{
    }       
}
           

内部类的好处:

内部类可以直接访问外部类的所有成员。
           

内部类还有一些更细的区分:

1、成员内部类

一个类定义在另外一个类成员变量的位置,就称它为成员内部类。

成员内部类的访问方式

方式一:在外部类提供一个方法创建内部类的对象进行访问。

方式二:在其他类直接创建内部类的对象。 
格式:外部类.内部类 变量名 = new 外部类().new 内部类();

注意: 如果是一个静态内部类,那么在其他类创建 的格式:
             外部类.内部类  变量名 = new 外部类.内部类()。
           

内部类要注意的细节

1. 如果外部类与内部类存在同名的成员变量时,在内部类中默认情况下是访问内部类的成员变量。可以通过"外部类.this.成员变量名" 指定访问外部类的 成员。

2. 私有的成员内部类只能在外部类提供一个方法创建内部类的对象进行访问,不能在其他类创建对象了。

3. 成员内部类一旦出现了静态的成员,那么该类也必须 使用static修饰。
原因:静态成员变量访问不需要对象,如果内部类不是静态的,不能通过类名直接访问内部类中的静态变量。
           

代码示例:

//外部类
class Outer{
    //成员变量
    int x = ;

    //成员内部类
    static  class Inner{
        //静态成员在class被加载到内存的时候就存在内存中了   
        static  int i = ;
        int x = ;

        public void print(){
            System.out.println("这个是成员内部类的print方法!"+i);
            //非静态内部类时,内外部成员变量重名时,使用外部类.this.外部类成员,访问重名的外部类成员
            //System.out.println("这个是成员内部类的print方法!" + Outer.this.x);
        }
    }

    //在外部的方法中创建了内部类的对象,然后调用内部方法。
    public void instance(){
        Inner inner = new Inner();
        inner.print();
    }
}

//其他类
class Demo 
{
    public static void main(String[] args) 
    {
        /*
        System.out.println(Outer.Inner.i);

        Outer outer = new Outer();
        outer.instance();

        //非静态成员内部类时,内部类对象的创建
        Outer.Inner inner = new Outer().new Inner();
        inner.print();
        */

        //静态成员内部类时,内部类对象创建
        Outer.Inner inner = new Outer.Inner();
        inner.print();
    }
}
           

2、静态内部类

静态类就是静态内部类。
如果一个类要被声明为static的,那么只有一种情况,就是静态内部类。
           

静态类创建格式:

外部类.内部类  变量名 = new 外部类.内部类()
           

3、局部内部类

一个类定义在另外一个类方法内的局部变量的位置,就称它为局部内部类。
如果局部内部类访问了一个局部变量,那么该局部变量必须使用final修饰!
           

原因:

当方法执行完毕后,局部变量就从内存中消失了,而局部内部类对象还没有消失,但是假若具体内部类中方法还访问着这个局部变量的话,就会存在问题!
所以java虚拟机的做法是让这个局部内部类方法访问这个局部变量的复制变量,但是这个复制变量是在访问时就已经确认了,且不会变化,所以被访问的局部变量也要是不能变化的!
           
class  Outer{
    String name= "外部类的name";
    public void test(){
        //局部变量
        int y =;  // y 什么时候从内存中消失? 方法执行完毕之后y消失。

        //局部内部类
        class Inner{     
            int x = ;
            public void print(){
                System.out.println("这个是局部内部类的print方法.."+y);
            }   
        }   
        Inner inner = new Inner();  //这个inner对象什么时候消失?  Inner对象是要在释放的时候,才会消失。
        inner.print();
    }
}

class Demo
{
    public static void main(String[] args) 
    {
        Outer outer = new Outer();
        outer.test();
    }
}
           

4、匿名内部类

匿名内部类:

没有类名的类就称作为匿名内部类,
虽然没有类名,但是类的其他成员都是存在的。
           

匿名内部类的使用前提:

必须存在抽象类继承或者接口实现关系才能使用。
           

匿名内部类一般是用于实参:

只是用一次,不需要具体的类对象。
           

代码示例:

abstract class Animal{
    int i = ;
    public abstract Animal run();
    public abstract void sleep();
}

class Outer{
    public void print(){
        // 匿名内部类与Animal是继承的关系
        //创建Animal子类的对象,这里使用的是多态,父类的引用变量指向子类的对象
        Animal a = new Animal(){ 
            //匿名内部的成员 
            public Animal run(){
                System.out.println("狗在跑.." + i);
            }

            public void sleep(){
                System.out.println("狗趴在睁开眼睛睡..");
            }

            //特有的方法
            public void bite(){
                System.out.println("狗在咬人..");
            }

        };

        //无法访问特有方法,因为这里使用的是父类的引用变量,只能使用父类的方法
        //a.bite();
        a.run();
        a.sleep();
    }
}

class Demo
{
    public static void main(String[] args) 
    {
        Outer outer = new Outer();
        outer.print();
    }
}