内部类
- 内部类作为外部类的成员,可以使用人已访问控制符修饰。
- 外部类的上一级程序单元是包,所以只有两个作用域:同一个包内、任意位置。因此需要两种权限:包访问权限、公开访问权限,对应省略访问修饰控制符和public访问控制符。因此如果一个外部类不使用任何访问控制符修饰,则只能被同一个包中其他类访问。
- 内部类的上一程序单元是外部类,所以具有4个作用域:同一个类、同一个包、父子类、和任意位置,可以有4种访问权限控制。
- 成员内部类的class文件格式为:OuterClass$InnerClass.class
- 外部类成员变量、内部类成员变量与内部类里方法的局部变量同名,则可以通过使用this、外部类类名.this作为限定区分。
非静态内部类
定义:一个类放在另一个类的内部定义。
大部分时候都被作为成员内部类定义,而不是局部内部类。
可以直接访问外部类的private成员,反过来不成立
-
因为在非静态内部类对象里,保存了一个它寄存的外部类对象的引用。
-
非静态内部类的方法内访问某个变量时:
1.系统优先在方法内查找是否存在该名字的局部变量,如果存在即使用;
2.到该方法所在的内部类中查找是否存在改名字的成员变量,如果存在即使用;
3.到内部类所在的外部类中查找,如不存在出现编译错误:提示找不到该变量。 -
非静态内部类成员只有在非静态内部类范围内是可知的,并不能被外部类直接使用。如果外部类需要访问非静态内部类成员,必须显示创建非静态内部类对象来进行访问。
-
非静态内部类里不能有静态方法、静态Field、静态初始化块。
静态内部类
包括静态成员、非静态成员。
- 静态成员不能访问非静态成员。
- 静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。
- 静态内部类的实例方法也不能访问外部类的实例成员,只能访问外部类的静态成员。(静态内部类是外部类的类相关,不是外部类的对象相关。静态内部类对象不是寄存在外部类对象里的,而是寄存在外部类的类本身中。当静态内部类对象存在时,并不存在一个被他寄存的外部类,静态内部类对象里只有对外部类的类引用,没有对外部类的对象应用。)
- 外部类不能直接访问静态内部类成员,可以使用静态内部类的雷鸣作为调用者来访问静态内部类的类成员。
public class A{
static class B{
private static int pro1 = 5;
private int pro2 = 9;
}
public void accessInnerB(){
System.out.println(B.pro1);
System.out.println(new B().pro2);
}
}
内部类的使用
(1)外部类内部使用内部类
不要再外部类的静态成员中使用非静态内部类,静态成员不能访问非静态成员。
(2)外部类以外使用非静态内部类
- 内部类不能使用private访问控制权限,private修饰的内部类只能在外部类的内部使用。
- 省略访问控制符的内部类,只能被与外部类处于同一个包中的其他类所访问。
- 使用protected修饰的内部类,可悲与外部类处于同一个包中的其他类和外部类的子类所访问。
- 使用public修饰的内部类,可以在任何地方被访问。
(3)在外部类以外使用静态内部类
语法:new OuterClass.InnerConstructor()
局部内部类
定义:把一个内部类放在方法中定义
- 上一级程序单元都为方法,不是类,所以,所有的局部成员都不能使用static修饰。
- 局部成员的作用域实在所在的方法,其他程序单元永远也不可能访问另一个方法中的局部成员,所以所有局部成员都不能使用访问控制符修饰。
生成的class文件命名格式为:
OuterClass$NInnerClass.class.
public class LocalInnerClass
{
public static void main(String[] args)
{
// 定义局部内部类
class InnerBase
{
int a;
}
// 定义局部内部类的子类
class InnerSub extends InnerBase
{
int b;
}
// 创建局部内部类的对象
InnerSub is = new InnerSub();
is.a = 5;
is.b = 8;
System.out.println("InnerSub对象的a和b实例变量是:"
+ is.a + "," + is.b);
}
}
匿名内部类
定义:只需要使用一次的类,必须继承一个父类
内部不能是抽象类
系统在创建匿名内部类时,会创建匿名内部类的对象,因此,不允许将匿名内部类定义成抽象类。
不能定义构造器
- 匿名内部类没有类名,无法定义构造器,但匿名内部类可以定义实例初始化块,利用实例初始化块来完成构造器需要完成的事情。
- 通过接口创建匿名内部类时,也不能显示创建构造函数,因此只有一个隐式的无参数构造器,所以new接口名后的括号不能传入参数值。
- 通过继承父类创建匿名内部类时,将拥有和父类相似的构造器,既拥有相同形参列表。
- 如果匿名内部类需要访问外部类的局部变量,必须用final修饰符来修饰外部类的局部变量。
- 通过接口创建匿名内部类
interface Product
{
public double getPrice();
public String getName();
}
public class AnonymousTest
{
public void test(Product p)
{
System.out.println("购买了一个" + p.getName()
+ ",花掉了" + p.getPrice());
}
public static void main(String[] args)
{
AnonymousTest ta = new AnonymousTest();
// 调用test()方法时,需要传入一个Product参数,
// 此处传入其匿名实现类的实例
ta.test(new Product()
{
public double getPrice()
{
return 567.8;
}
public String getName()
{
return "AGP显卡";
}
});
}
}
- 继承父类创建匿名内部类
abstract class Device
{
private String name;
public abstract double getPrice();
public Device(){}
public Device(String name)
{
this.name = name;
}
// 此处省略了name的setter和getter方法
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return this.name;
}
}
public class AnonymousInner
{
public void test(Device d)
{
System.out.println("购买了一个" + d.getName()
+ ",花掉了" + d.getPrice());
}
public static void main(String[] args)
{
AnonymousInner ai = new AnonymousInner();
// 调用有参数的构造器创建Device匿名实现类的对象
ai.test(new Device("电子示波器")
{
public double getPrice()
{
return 67.8;
}
});
// 调用无参数的构造器创建Device匿名实现类的对象
Device d = new Device()
{
// 初始化块
{
System.out.println("匿名内部类的初始化块...");
}
// 实现抽象方法
public double getPrice()
{
return 56.2;
}
// 重写父类的实例方法
public String getName()
{
return "键盘";
}
};
ai.test(d);
}
}
闭包&回掉
闭包:能被调用的对象,保存了它的作用域信息。
回掉:某个方法一旦获得了内部类对象的引用后,就可以再合适的时候反过来去调用外部类实例的方法。(允许客户类通过内部类引用来调用其外部类的方法)
- 接口
interface Teachable
{
void work();
}
- 程序员
public class Programmer
{
private String name;
//Programmer类的两个构造器
public Programmer(){}
public Programmer(String name)
{
this.name = name;
}
//此处省略了name的setter和getter方法
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return this.name;
}
public void work()
{
System.out.println(name + "在灯下认真敲键盘...");
}
}
public class TeachableProgrammer extends Programmer
{
public TeachableProgrammer(){}
public TeachableProgrammer(String name)
{
super(name);
}
//教学工作依然由TeachableProgrammer类定义
private void teach()
{
System.out.println(getName() + "教师在讲台上讲解...");
}
private class Closure implements Teachable
{
/*
非静态内部类回调外部类实现work方法,非静态内部类引用的作用仅仅是
向客户类提供一个回调外部类的途径
*/
public void work()
{
teach();
}
}
//返回一个非静态内部类引用,允许外部类通过该非静态内部类引用来回调外部类的方法
public Teachable getCallbackReference()
{
return new Closure();
}
}
public class TeachableProgrammerTest
{
public static void main(String[] args)
{
TeachableProgrammer tp = new TeachableProgrammer("李刚");
//直接调用TeachableProgrammer类从Programmer类继承到的work方法
tp.work();
//表面上调用的是Closure的work方法,
//实际上是回调TeachableProgrammer的teach方法
tp.getCallbackReference().work();
}
}
<h6 align = "right"> ——整理自疯狂Java</h6>
网友评论