前言
本篇博客主要涉及以下几个内容
- Java中的内部类
- Java中的静态内部类
- 关于内部类常见的一些面试题
Java中的内部类
内部类就是在Java类内部定义的类,主要分为四种类型:
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
使用内部类的原因
- Java拥有单继承的特性,而内部类可以独立继承一个类或实现接口。这一定程度上方便了开发。
- 内部类的信息与其他外围类信息独立,提供了更好的封装
成员内部类
作为外部类的成员变量存在,其性质如下:
- 可以有访问修饰符
- 外部类在类中访问内部类需要通过new的方式
- 外部类加载,成员内部类不加载
- 不能有静态信息【因为如果外部类没有实例化,则内部类不会被加载(不符合类加载的几种条件),因此静态变量不会进内存,这与static的概念矛盾了】
- 内部类的this关键字表示自己的对象,如要访问外部类的对象则使用
外部类名.this
- 在外部类外访问内部类需要使用
外部类的实例引用.new 内部类构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| package memoforward;
public class TestOuterInnerClass{ public static void main(String[] args) { OuterInnerClass outer = new OuterInnerClass(); OuterInnerClass.InnerClass inner = outer.new InnerClass(); inner.print();
} }
class OuterInnerClass /*extends A implements IA*/{ private int val = 10; public OuterInnerClass() { System.out.println("Outer Constructor.."); } private void outerPrint(){ System.out.println("outerPrint.."); } public class InnerClass /*extends B implements IB*/{ private int val = 5; public InnerClass(){ System.out.println("Inner Constructor"); } public void print(){ System.out.println("Outer's val:" + OuterInnerClass.this.val); System.out.println("Inner's val:" + this.val); outerPrint(); } } public InnerClass creatInner() { return new InnerClass(); } }
|
静态内部类
静态内部类的性质如下:
- 可以有访问修饰符
- 静态内部类不依赖于外部类。因此外部类被加载,内部类不会被加载;而内部类被加载,外部类也不会被加载
- 内部类创建:
Outer.Inner inner = new Outer.Inner()
- 访问内部类的静态成员:
Outer.Inner.staticValue
- 静态内部类只可以关联外部类的静态资源(因为内部类被加载时,关联外部类的静态资源会使外部类加载,但是不能拥有外部类的实例)
- 与成员内部类的区别
- 不需要依赖于外部类的实例创建
- 只能关联外部类静态资源
- 不存在this关键字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| package memoforward.test;
public class TestStaticOuterInner { public static void main(String[] args) { Outer.Inner inner = new Outer.Inner(); Outer.Inner.innerStaticMethod(); inner.innerMethod();
} }
class Outer{ static{ System.out.println("Outer static block..."); } private static int a = 10;
public Outer(){ System.out.println("Outer constructor..."); } static class Inner{ static{ System.out.println("inner static block..."); } public static void innerStaticMethod(){ System.out.println("innerStaticMethod..."); System.out.println("Outer static value:" + a); }
public Inner(){ System.out.println("Inner constructor..."); } public void innerMethod(){ System.out.println("innerMethod..."); } }
public static void outStaticMethod(){ Inner inner = new Inner(); inner.innerMethod(); } }
|
- 首先创建静态内部类的实例,先加载内部类执行静态代码块,随后执行构造方法。由静态内部类的性质可知,加载静态内部类,外部类是不加载的。
- 随后执行静态内部类的静态方法,此方法关联了外部类的静态变量,因此外部类被加载,但没有实例化。
- 最后执行了静态内部类实例的方法。可见在整个流程中,外部类只是加载了,并没有实例化。
局部内部类
在一个方法内定义的类,有如下性质:
- 没有访问权限修饰符
- 仅在方法内有效
- 无法创造静态信息,因为这个类是临时的
- 可以访问外部类的所有信息(方法内部本身就是可以访问的)
- 可以访问方法的参数和局部变量(但是这些变量始终不能被改变)
匿名内部类
常用来重写某个或某些方法,这个用的还是比较多的,比较常见的就是Java的动态代理实现,会实现一个匿名内部类并重写invoke()方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| package memoforward.test;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;
public class TestAnonInnerClass { public static void main(String[] args) { IPerson person = PersonProxy.getPerson(); person.eat(); }
}
interface IPerson{ void eat(); } class Person implements IPerson{ @Override public void eat() { System.out.println("吃饭..."); } }
class PersonProxy{ static IPerson person = new Person(); public static IPerson getPerson(){ return (IPerson) Proxy.newProxyInstance(person.getClass().getClassLoader() , person.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object obj = null; try{ System.out.println("做饭..."); obj = method.invoke(person); return obj; }catch(Exception e){ System.out.println("饭馊了..."); throw new RuntimeException("没吃上饭:" + e); }finally{ System.out.println("洗碗..."); } } }); } }
|