手机版
你好,游客 登录 注册
背景:
阅读新闻

Java内部类使用总结

[日期:2017-02-18] 来源:Linux社区  作者:shenjianeng [字体: ]

1.什么是内部类?
  定义在类内部的类,称之为内部类

 public class Out{
   class In{    //此时In就是内部类
   }    
}

2.为什么要使用内部类?
  1),增强封装,把内部类隐藏在外部类中,不允许其他类来访问内部类
  2),内部类能提高代码的可读性和可维护性

3.内部类的分类
  对于内部类的分类,可以对比于成员变量的分类.
  我们可以根据不同的修饰符或者定义的不同位置把成员变量,可以细分为:类成员变量,实例成员变量,局部变量.
  内部类看做是外部类的一个成员,那么内部类可以使用public/缺省/protected/private修饰.还可以是static修饰.
  同理,内部类也根据使用不同的修饰符或者定义的不同位置,将其分成4类:

  1),实例内部类:内部类没有使用static修饰
  2),静态内部类:内部类使用static修饰
  3),局部内部类:在方法中定义的内部类
  4),匿名内部类:只能使用一次,属于内部类的一种特殊情况

3.1实例内部类:
  1)定义:实例内部类,即没有使用static修饰的内部类.这说明,实例内部类属于外部类的对象,不属于外部类本身(类比字段).
  2)创建实例内部类

//外部类
class Outter {
    // 实例内部类:没有使用static修饰
    class Inner {

    }
}

public class InnerDemo1 {
    public static void main(String[] args) {
        // 创建实例内部类,没有使用static修饰,属于外部类的对象,因此,创建实例内部类前,必须存在外部类对象
        Outter out = new Outter();
        // 通过外部类对象创建内部类对象
        Outter.Inner in = out.new Inner();
    }
}

  3)特点:

    a.由创建实例内部类的过程可知,当存在内部类对象时,一定存在外部类对象.

    b.实例内部类的实例自动持有外部类的实例的引用,实例内部类可以无条件访问外部类的所有字段和方法

    注意:当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象

    c.外部类中不能直接访问内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问

//外部类
class Outter {
    private String name = "out";
    private Integer age = 17;

    // 实例内部类:没有使用static修饰
    class Inner {
        private Integer age = 18; // 隐藏现象,隐藏了外部类的age

        Inner() {
            // 特点:1.实例内部类能直接访问外部类成员
            // 2.当实例内部类和外部类有同名的字段或者方法时,会发生隐藏现象
            System.out.println(name + this.age);// 输出out18
            // 此时若需要使用外部类的age,语法:外部类.this.age
            System.out.println(Outter.this.age);// 输出17
        }
    }
}

总结:简单来说,就是看变量的作用域,外部类成员变量的作用域是整个外部类,而内部类在外部类中(可以看做外部类的字段),内部类自然就可以访问外部类.而外部类要去访问内部类的成员,可以这样理解:内部类的成员属于内部类,在内部类中有效,内部类都不存在,其中的成员变量也不会存在,所以,外部类中不能直接访问内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问.

3.2静态内部类

  1)定义:使用static修饰的内部类.所以,该内部类属于外部类本身,而不属于外部类的对象

  2)创建静态内部类

//外部类
class Outter {
    // 静态内部类:使用static修饰
    static class Inner {
    }
}

public class InnerDemo2 {
    public static void main(String[] args) {
        // 因为静态内部类属于外部类本身,可以直接通过外部类类名来访问(类比字段)
        Outter.Inner in = new Outter.Inner();
    }
}

  3)特点:

    a.在创建内部类的实例时,不必创建外部类的实例.

    b.静态内部类可以直接访问外部类的静态成员,如果访问外部类的实例成员,必须通过外部类的实例去访问.

      简单理解:静态成员属于类,非静态成员属于对象,如果要访问外部类的实例成员(非静态成员),当然要先存着外部类对象的.而静态内部类的创建是不需要外部类的对象,因此,如果访问外部类的实例成员,必须通过外部类的实例去访问.

    c.在静态内部类中可以定义静态成员和实例成员.

    d.测试类可以通过完整的类名直接访问静态内部类的静态成员.

//外部类
class Outter {
    static String name = "outter";
    public Integer age = 17;

    // 静态内部类:使用static修饰
    static class Inner {
        Inner() {
            // 静态内部类能直接访问外部类的静态成员
            System.out.println(name);// 输出 outter
            // 访问外部类的实例成员,必须通过外部类的实例去访问.
            System.out.println(new Outter().age);// 输出 17
        }
    }
} 

3.3局部内部类(几乎用不到)

  1)定义:在方法中定义的内部类,其可见范围是当前方法,和局部变量是同一个级别,所以局部内部类只能在方法中使用.

    注意,局部内部类和方法里面的局部变量一样,是不能有public、protected、private以及static修饰符的。

public class InnerDemo3 {
    public static void main(String[] args) {
        // 局部内部类
        class Inner {
        }
    }
}

  2)特点:

    a.局部内部类和实例内部类一样,不能包含静态成员.(局部内部类属于方法,而静态成员属于类)

    b.局部内部类和实例内部类,可以访问外部类的所有成员.

    c.局部内部类访问的局部变量必须使用final修饰,在Java8中是自动隐式加上final(语法糖).

      原因:当方法被调用运行完毕之后,当前方法的栈帧被销毁,方法内部的局部变量的空间全部销毁.但内部类对象可能还在堆内存中,要直到没有被引用时才会消亡.此时就会出现一种情况:内部类要访问一个不存在的局部变量.为了避免该问题,我们使用final修饰局部变量,从而变成常量,永驻内存空间,即使方法销毁之后,该局部变量也在内存中,对象可以继续持有.

public class InnerDemo3 {
    public static void main(String[] args) {
        int age = 17;
        final int num = 15;
        // 局部内部类
        class Inner {
            public void test() {
                // 报错:Cannot refer to a non-final variable age inside an inner class defined in a different method
                System.out.println(age);
                System.out.println(num);// 正确
            }
        }
    }
} 

3.4匿名内部类(使用最频繁)

  1):定义:匿名内部类是一个没有名称的局部内部类,适合于只使用一次的类.

  2)创建匿名内部类:

匿名内部类本身没有构造器,但是会调用父类构造器.一般来说,匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写.

注意:匿名内部类必须继承一个父类或者实现一个接口,但最多只能一个父类或实现一个接口.

//定义一个接口
interface Person {
   
public void eat();
}

public class AnonymousDemo {
   
public static void main(String[] args) {
       
// 使用匿名内部类
        Person p = new Person() {
           
public void eat() {
                System.out.println(
"eat something");
            }
        };
        p.eat();
    }
}

4.总结

5.面试题public class Outer {
   
public void someOuterMethod() {
       
// Line 3
    }

   
public class Inner {
    }

   
public static void main(String[] argv) {
        Outer o
= new Outer();
       
// Line 8
    }
}

/*
* Which instantiates an instance of Inner?
A. new Inner(); // At line 3
B. new Inner(); // At line 8
C. new o.Inner(); // At line 8
D. new Outer.Inner();    // At line 8
*/

答案A.new Inner();等价于this.new Inner();已经存在一个Outer类对象了.

line 8 正确写法,应为: o.new Inner();

本文永久更新链接地址http://www.linuxidc.com/Linux/2017-02/140767.htm

linux
相关资讯       Java内部类 
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数

       

评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款