-----------------------------------------------个人初学,如有错误,欢迎指正-----------------------------------------------
Java学习笔记之内部类
一、简介
内部类,简而言之就是在“内部”的类。这个内部包括类内部或者方法内部。因此,内部类可以分为局部内部类和成员内部类。局部内部类就是在方法体中,实例内部类就是在类中。本篇博客的内容主要有:
1、内部类的概念
2、内部类的实例及特点
二、内部类的概念
根据简介的介绍,我们可以画出内部类的分类图
我个人更倾向于这样分类:
三、内部类实例
3.1局部内部类
//外部类
public class Outer {
private int PrivateNum;
public static void main(String[] args) {
Outer outer = new Outer();
outer.PrivateNum = 111;
System.out.println("外部类:PrivateNum = "+outer.PrivateNum);
Object obj = outer.PrintNum();
System.out.println(obj.toString());
}
//成员方法
private Object PrintNum(){
int MothodNum = 222;
System.out.println("成员方法:MothodNum = "+MothodNum);
class Inner{//局部内部类
private int PrivateNum = 333;
Inner(){
System.out.print("内部类:");
}
public String toString(){
return "PrivateNum = "+this.PrivateNum;
}
}
return new Inner();
}
}
运行后:
外部类:PrivateNum = 111
内部类:PrivateNum = 333
内部类:PrivateNum = 333
*那么,内部类Inner可不可以访问外部类Outer的成员变量PrivateNum或者成员方法PrintNum中的局部变量MothodNum呢?答案是否定的。因为类和成员方法或者局部变量的生命周期不同。Java的垃圾回收机制,方法在调用的时候会实例化,在调用结束后,就会销毁。而类实在实例化之后产生引用,当指向类的引用全部释放之后,类才会销毁。因此,方法中的内部类,只能访问方法中的fin al成员变量和成员方法。
我们对代码做修改,将局部变量MothodNum修改为final型,然后在内部类中打印输出:
//外部类
public class Outer {
private int PrivateNum;
public static void main(String[] args) {
Outer outer = new Outer();
outer.PrivateNum = 111;
System.out.println("外部类:PrivateNum = "+outer.PrivateNum);
Object obj = outer.PrintNum();
System.out.println(obj.toString());
}
private void OuterMothod(){
System.out.println("OuterMothod()方法被内部类调用。");
}
//成员方法
private Object PrintNum(){
final int MothodNum = 222;
class Inner{//局部内部类
private int PrivateNum = 333;
Inner(){
System.out.print("内部类:");
}
public String toString(){
OuterMothod();//调用外部类的成员方法
System.out.println("成员方法:MothodNum = "+MothodNum);//打印方法中的局部变量
return "PrivateNum = "+this.PrivateNum;
}
}
return new Inner();
}
}
运行结果:
外部类:PrivateNum = 111
内部类:OuterMothod()方法被内部类调用。
成员方法:MothodNum = 222
PrivateNum = 333
内部类:OuterMothod()方法被内部类调用。
成员方法:MothodNum = 222
PrivateNum = 333
3.2匿名内部类
匿名内部类,字面理解就是作为内部类的一种,它的名字是隐藏的,看不到的。看下面的代码片段
v.setOnClickListener(
new OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
这里的new OnClickLiatener就是一个一个匿名类,需要注意的是,匿名类只是类没有名字,不代表new的这个匿名类不存在,实际上,匿名类是要预先定义的。
public interface OnClickListener {
/**
* Called when a view has been clicked.
*
* @param v The view that was clicked.
*/
void onClick(View v);
}
既然匿名类,它没有名字,那么就没有构造函数,类也无法添加任何修饰符。因为匿名内部类是局部内部类的特殊形式,所以,匿名内部类也只能只能访问方法中的final成员变量和成员方法。
public static void main(String[] args) {
Outer outer = new Outer();
Inner inner = outer.GetInnerName();
System.out.println(inner.getName());
}
private Inner GetInnerName(){
return new Inner(){//匿名内部类
@Override
public String getName() {
return "我是匿名内部类";
}
};
}
运行结果:
我是匿名内部类
3.3实例内部类
private int PrivateNum;
public static void main(String[] args) {
Outer outer = new Outer();
outer.PrivateNum = 5;
System.out.println("Outer:");
System.out.println("PrivateNum = "+outer.PrivateNum);
Outer.Inner inner = outer.new Inner();
//inner = outer.GetInner();
inner.PrintString();
}
class Inner{//实例内部类
Inner(){}
private void PrintString(){
System.out.println("Inner:");
System.out.println("PrivateNum + 3 = "+(PrivateNum+3));
}
}
private Inner GetInner(){
return new Inner();
}
运行结果:
Outer:
PrivateNum = 5
Inner:
PrivateNum + 3 = 8
PrivateNum = 5
Inner:
PrivateNum + 3 = 8
实例内部类就如同类的成员方法一样,只不过实例内部类的结构更复杂而已。实例内部类可以访问外部类的成员和方法。这里就不做详述了。下来介绍它的特例,静态内部类:
//外部类
public class Outer {
private int PrivateNum;
public static void main(String[] args) {
Outer outer = new Outer();
outer.PrivateNum = 5;
System.out.println("Outer:");
System.out.println("PrivateNum = "+outer.PrivateNum);
Outer.Inner inner = new Outer.Inner();//静态内部类可以直接创建对象
inner.PrintString(outer);
}
private static class Inner{//静态内部类
Inner(){ }
private void PrintString(Outer outer){
System.out.println("Inner:");
System.out.println("PrivateNum + 3 = "+(outer.PrivateNum+3));
}
}
}
静态内部类不能直接访问外部类的非静态成员变量和方法。静态内部类智能访问外部类的静态成员和静态方法,或者,通过外部类的引用来访问
,即例子中的outer.PrivateNum这种方式。
从语法上也可以看出,
静态内部类:Outer.Inner inner = new Outer.Inner();
非静态内部类:Outer.Inner inner = outer.new Inner();
在创建非静态内部类之前,都要先在外部类中用new关键字来创建内部类的对象,因此,非静态内部类的对象是依附在外部类对象上的。而静态内部类的创建,是不需要定义绑定在外部类的实例上的。
*关于静态内部类和非静态类的区别
1、静态内部类可以创建静态成员和静态方法,非静态内部类不可以。
2、静态内部类不可以直接访问非静态成员变量和方法,非静态内部类可以。
【疑问】
为什么静态内部类不能直接访问外部类的非静态成员和方法?
我个人的看法是,静态内部类的初始化不依赖于外部类,所以,静态内部类会先于外部类完成初始化,这样的话,当直接访问外部类的非静态成员,此时外部类的成员变量可能还没有初始化,即编译器还不知道所访问的变量到底是整形数还是数组或者其他类型,所以就会报错。当通过外部类的引用调用外部类的成员方法或者成员变量时,那么外部类肯定已经完成初始化了,这样,静态内部类就可以访问非静态成员了(即便成员为空指针,程序会抛出空指针异常)。
个人看法,也不知道对不对,希望明白其中道理的朋友能回复评论,谢谢。