今天来说说一个非常特殊的类——内部类。
在实际的开发中,比较常用到的,一方面是Java图形开发的事件处理中,另一方面,在Spring应用开发中,会大量用到,在Spring框架本身,就大量使用了匿名内部类,通过回调方法实现了一些模板应用。
下面来具体看看内部类的内容。
所谓内部类,就是定义在一个类内部的类。
内部类的概念是在JDK1.1中被引入的。引入内部类,主要有以下一些考虑:
内部类对象能访问它所处类的私有数据;
内部类能够隐藏起来不为同一个包中的其他类访问;
匿名内部类可以方便的用在回调方法(callback method)中,典型应用是图形编程中的事件处理。
1 内部类定义
内部类有时也称为“嵌套类(nested class)”,是定义在一个类内部的类。
这里所谓的“类的内部”,指的是在类定义的两个大括号之间,如下:
public class OuterClass{
//可以在这个类的内部的任何地方定义内部类
}
在这个“类的内部”,包括类中的任何位置,甚至方法体中也可以定义内部类。注意,下面的放在同一个程序文件A.java中的类B不是类A的内部类,这是刚开始接触内部类的程序员比较容易引起混乱的地方:
public class A{
//statements
}
class B{
//statements
}
这两个类虽然写在用一个文件中,但它们之间是两个独立的类,它们之间并没有什么联系。将这个类文件编译之后,会产生两个class文件:A.class和B.class。
可以将一个内部类定义成一个静态的内部类,只需要在内部类定义前面加上static关键字。
为方便表述,我们将封装类相对于“内部类”称为“外部类”。
public class Outer1 {
private int size;
// 定义一个内部类,名为 "Inner"
public class Inner {
public void doStuff() {
// 内部类可以访问外部类的私有属性
size++;
}
}
public void testTheInner() {
Inner i = new Inner();
i.doStuff();
}
}
在这个Outer1类中,定义了一个内部类,这个内部类可以访问外部类的私有属性。
编译这个Outer1.java,将会产生两个class文件:Outer1.clas和Outer1$Inner1.class,前面一个类文件是Outer1类文件,后面一个是内部类类文件,它用“$”来分割开内部类和外部类。
在Outer类范围以外的其他应用中,实例化内部类必须首先有一个外部类实例存在,然后通过外部类实例来实例化内部类,实例化内部类的两种方法:
法一:
Outer.Inner in=new Outer().new Inner();
法二:
Outer o=new Outer();
Outer.Inner I= o.new Inner();
当然,如果内部类是static的,也可以用下面方法:
Outer.Inner in=new Outer.Inner();
我们来看一下,假设我们现在需要在另一个应用程序中使用刚才定义的类Outer1的内部类Inner,我们该如何来实现。为了更好的演示它,我们对上面的Outer类稍作修改,加入了一个用于获得Outer1类的私有属性size的方法getOuterSize():
public class Outer1 {
private int size;
// 定义一个内部类,名为 "Inner"
public class Inner {
public void doStuff() {
// 内部类可以访问外部类的私有属性
size++;
}
public int getOuterSize() {
return size;
}
}
public void testTheInner() {
Inner i = new Inner();
i.doStuff();
}
}
然后我们再来看如何在另外一个类中使用Outer1的内部类:
public class TestInner {
public static void main(String[] args) {
Outer1.Inner oi = new Outer1().new Inner();
oi.doStuff();
System.out.println(oi.getOuterSize());
}
}
编译
并运行这个程序,将在控制台上打印出size的值:1。
和一般的类不同,内部类可以使用protected和private来修饰,以限制在它的外部类以外的地方对它的访问,比如,上面的Outer1中的Inner内部类就可以定义成如下的样子:
public class Outer1 {
private int size;
/* 定义一个内部类,名为 "Inner" */
private class Inner {
public void doStuff() {
// 内部类可以访问外部类的私有属性
size++;
}
public int getOuterSize()
{
return size;
}
}
public void testTheInner() {
Inner i = new Inner();
i.doStuff();
}
}
此时,就不能在Outer1的范围之外使用Inner类了。
2 局部内部类
类的名字只能在定义的范围内使用,除非使用有效的全名。
Inner类也可以定义在方法的内部,或者类的一个自由块中,此时,内部类是一个局部的内部类,只能在方法体或者自由块中使用。
如果内部类被定义在方法中,那么方法中final类型的局部变量,都可以被Inner类的方法访问。定义在方法中的内部类只能在方法内被使用。
例如:
public class Outer {
public void test(int i) {
class LocalClass {
public void localTest() {
System.out.println("局部内部类的方法被调用");
// System.out.println("i="+i); //错
// 如果需要使用局部变量i,必须将它声明为final
}
}
LocalClass lc = new LocalClass();
lc.localTest();
}
public static void main(String[] args) {
Outer o = new Outer();
o.test(1);
}
}
在这个类Outer中,定义了一个方法test(),在它的方法体内定义了一个局部内部类,这个内部类只能在这个方法体内使用。
如果在内部类中需要使用方法的局部变量(如方法的参数i),那么,需要将这个局部变量定义final的,否则,将会出现类似下面的错误(将i++前的注释去掉后的错误):
Outer.java:10: local variable i is accessed from within inner class; needs to be declared final
System.out.println("i="+i);;
^
1 error
如果将方法test()的参数i加上final就可以了。
3 匿名内部类
内部类的另外一个奇特的地方就是,可以不用给它指定一个类名,就可以直接拿来使用,这个用法经常用在图形界面的事件处理中。
4 内部类特性
内部类是一个复杂的应用,除了上面提到的一些特点外,它还有以下一些特点:
Inner class可以声明为抽象类 ,因此可以被其它的内部类继承。也可以声明为final的。
和外层类不同,Inner class可以声明为private或protected。
Inner class 可以声明为static的,但此时就不能再使用外层封装类的非static的成员变量。
非static的内部类中的成员不能声明为static的,只有在顶层类或static的内部类中才可声明static成员。
分享到:
相关推荐
由于没有提供更多的详细信息,我们无法深入了解这个库的内部运作,但可以推测它可能包含了一些用于数据抓取、清洗、转换或分析的工具,也可能包含了一些与DCI相关的特定功能,比如日志记录、数据上传等。 总的来说...
中颖电子推出的SH79F083是一款功能强大、性价比高的8位微控制器,适用于各种工业和消费类电子产品。本篇文章将深入探讨SH79F083的特性、应用以及一个基于该芯片的实例程序,帮助开发者更好地理解和利用这款微控制器...
【内部审计实务标准】是内部审计领域的重要指导文件,它为内部审计师提供了职业道德和实践操作的准则。这篇文档详细阐述了内部审计师在执行职责时应遵循的四大基本原则:正直、客观、保密和能力,并对应每个原则设定...
ArrayList和LinkedList都是List接口的实现,但它们在内部实现和性能上有显著差异: - **ArrayList**:基于动态数组实现,访问元素速度快,随机访问的时间复杂度为O(1),但插入和删除元素时需要移动元素,时间复杂度...
《内部审计实务标准》是内部审计领域的核心准则,旨在指导内部审计师的专业行为,确保其工作的道德性和专业性。该标准由国际内部审计师协会(IIA)制定,对于内部审计师的个人行为和职业操守有着明确的规定,旨在...
1. 目录 1. 2. 目录 .........................................................................................................................................................1 JVM .........................
8. **影响看法与品德学习的内部条件**:认知失调、看法定向(看法定势)和道德认知是内部条件,社会风气则是外部因素。 9. **训练的文化属性**:训练是一种文化现象,它反映并塑造社会文化。 10. **中学阶段的发展...
大连城建集团在进行权限表调整时,需要综合考虑多方面因素,包括集团战略、内部员工的需求、市场竞争状况以及外部标杆企业的经验。 首先,集团管控模式的选择直接影响到权限的划分。大连城建集团根据其业务特性,将...
1. 目录 1. 2. 目录 .........................................................................................................................................................1 JVM ........................
- **动态类型**:引入了`@SafeVarargs`注解,用于消除潜在的泛型警告,以及`钻石操作符<>`,简化了匿名内部类的实例化。 - **Fork/Join框架**:这是一个并行计算框架,用于分解大型任务并将其分配到多个子任务上,...
第1章 Windows应用程序开发入门..........................................................................................16 1.1 第一个实例程序...............................................................
9. **内部类**:包括匿名内部类、成员内部类、局部内部类和静态内部类,以及它们的使用方式和作用。 10. **多线程**:Java提供了Thread类和Runnable接口来实现并发。了解synchronized关键字、线程同步机制、wait/...
- **类型推断(Type Inference)**:通过`钻石操作符<>`简化了匿名内部类和泛型的创建。 - **try-with-resources语句**:自动关闭资源,减少了代码中的异常处理。 - **字符串开关(Switch for Strings)**:允许...
其他类语句和错误语句处理................................................................................................4 第十一节 过程和函数..............................................................
8. `MultiThreadedHttpConnectionManager$ConnectionPool.class` 和 `MultiThreadedHttpConnectionManager$HttpConnectionAdapter.class`: 这些是HttpClient的内部类,分别用于管理和适配HTTP连接池中的连接。...
4. **钻石操作符**:在创建匿名内部类或者Lambda表达式时,编译器可以根据上下文推断出泛型的类型,避免了显式指定类型。 5. **Strings in Switch**:Java 7允许在switch语句中直接使用字符串作为条件,方便处理...