Java-内部类(一)

来源:互联网 发布:淘宝客服辛苦吗 编辑:程序博客网 时间:2024/04/28 03:23

一、什么是内部类

Java中可以把一个类的定义放在另一个类的定义的内部,这就是内部类。他和类的成员方法,成员变量对象的方法一样,可以为外围类的功能实现提供支持,允许编程人员把分散的逻辑组合在一起。内部类与组合以及方法的调用不同:内部类提供了代码的隐藏机制:内部类的可见性可以得到控制;此外内部类可以直接访问外围类的属性和方法,提供了低成本的交流机制,可以简化功能的实现(减少很多代码)。相对于内部方法,内部类可以拥有自己的属性,提供更为完整和丰富的功能。相对于外部类,内部类可以直接访问外部类的属性和方法,这样就可以简化功能的实现了。比如在LinkedHashMap中有多个内部类,包括Entry、LinkedHashIterator、KeyIterator... ,以LinkedHashIterator为例,继承了Iterator接口为外围类提供一些迭代器功能,但是在内部类实现中直接使用了LinkedHashMap外围类中的属性,操作数以及头结点等等。其中操作数modCount是父类hashMap中的成员,如果要使用外部类来实现这个方法的话,这个外部类必须在获得这个参数,同时LinkedHashIterator暴露外外面,尽管你可能使用default的权限,但是其实这个类是仅仅为LinkedHashMap服务的,所以定义为内部类是最佳的选择。

二、内部类的种类

定义在外围类内部的类,根据其作用域和是否静态可以分为以下四种

  • 成员内部类(member inner classes)
  • 局部内部类(local inner classes)
  • 匿名内部类(anonymous inner classes)
  • 静态内部类(static inner classes)
成员内部类,故名思议就是和外围类的成员在相同层级定义的内部类。费静态的成员的内部类,可以直接访问外围类的属性和方法,可以很方便的进行通信。
局部内部类,是定义在方法内部的类,仅在方法作用域内有效,不能访问外围类的非静态变量。
匿名内部类,通常是创建接口的实例,类型的定义和实例化结合在一起,可以很方便的使用一个基于接口的功能。
静态内部类,也就是嵌套类,类用static修饰。如果不需要与外围类对象之间有联系,可以将内部类声明为static,嵌套类不像局部内部类一样隐式的保存了一个外围类对象的引用,嵌套类不能   访问外围类的非静态成员。

内部类可以被 private protected、public以及默认权限修饰。外围只能使用public或者保持默认的权限修饰符。

为了学习内部类的用法,下面是不同种类的内部来的使用演示:
/**
* Created by ryan01.peng on 2017/6/27.
*/
public class LeInnerClass {
 
private int outClassProperty = 1;
private static int outClassStaticProperty = 1;
 
public static void main(String[] args) {
 
/** 成员内部类的实例化和使用 */
InnerClass innerClass = new LeInnerClass().new InnerClass(); //创建内部类实例的方式1
// LeInnerClass leInnerClass = new LeInnerClass(); //创建内部类实例的方式2
// InnerClass innerClass1 = leInnerClass.getInnerInstance();
innerClass.innerClassMethod();
 
 
/** 局部内部类,只能在方法内部使用和实例化 */
class LocalInnerClass {
private String localInnerClassProperty = "localInnerClassMthod-->> 动次打次";
private void localInnerClassMethod() {
// outClassProperty++; //局部内部类不能访问外围类的非静态变量
outClassStaticProperty++; //可以访问外围类的静态变量
System.out.println(localInnerClassProperty);
}
}
LocalInnerClass localInnerClass = new LocalInnerClass();
localInnerClass.localInnerClassMethod();
 
 
/** 匿名内部类的实例化和使用 */
// 类型的定义和实例化结合在一起
new InterfaceToImpl(){ // 在新建线程的时候我们常常用到这种方式 new Thread(new Runnable() { @Override public void run() { } }).start();
@Override
public void talk(String s) {
System.out.println(s);
}
}.talk("---------->>实现接口的匿名内部类talk");
 
 
/** 嵌套类的使用 */
StaticInnerClass.staticInnerClassStaticMethod();
 
}
 
private InnerClass getInnerInstance(){
return new InnerClass();
}
 
/** 外围类的非静态方法 */
private void outClassMethod(){
System.out.println("---------OutClass.outClassMethod");
}
 
/** 定义一个成员内部类 */
private class InnerClass { //成员内部类可以使用private和protected修饰符,这样就可以保证这写功能的可见范围,同时控制对这些类的继承与扩展。
 
private int innerClassProperty ;
 
// private static int cannotContainStaticProperty; //成员内部类不能包含静态属性。
public int innerClassMethod() {
 
innerClassProperty = LeInnerClass.this.outClassProperty + 1; //通过OutClass.this 方位外部类及其属性
System.out.println("----------------->>innerClassMethod "+ ":"+innerClassProperty);
outClassMethod(); //成员内部类可以直接访问外部类的方法
return innerClassProperty;
}
}
 
/** 定义一个嵌套类 */
private static class StaticInnerClass{
private int property =1;
private static int staticProperty = 2; //嵌套类可以包含静态属性
 
void staticInnerClassMethod(){
System.out.println("----------》》嵌套类:"+ property);
}
 
static void staticInnerClassStaticMethod(){
System.out.println("----------》》嵌套类:"+ staticProperty );
}
}
 
}
以上代码中匿名内部类的接口定义
public interface InterfaceToImpl {
void talk(String s);
}
运行输出
----------------->>innerClassMethod :2
---------OutClass.outClassMethod
localInnerClassMthod-->> 动次打次
---------->>实现接口的匿名内部类talk
----------》》嵌套类:2

三、为什么需要内部类

学习内部类的时候,困扰我最多的问题并不是怎样创建和使用这些种类的内部类,而是我们为什么需要内部类?因为看起来,内部类可以实现的功能,我们都可以同过成员方法,持有外部类的实例,调用外部类的静态方法等方式来实现,那么我们为什么还是需要内部类呢?

最强理由:可见性控制,将不同的逻辑组合在一起,又可以把专用的逻辑只对这个类使用,对外是隐藏的。这个类除了外围类,其他的类不会也不能用到。比如上文中提到LinkedHashIterator
次强理由:简化实现,节省很多代码。
常见理由:
    1.  多继承机制的完善,通过内外部类继承不同的父类和接口的方式可以实现Java语言中的多继承。
    2.  内部类可以访问外围类的成员。
    3. 匿名内部类可以方便的定义回调。
    4. 使用内部类可以方便的编写时间驱动程序。

增加一段别人描述为什么需要内部类的文字,虽然有点,但是仍然有帮助于我们理解我们为什么需要内部类:来源(http://blog.csdn.net/nnmmbb/article/details/7832498
/**
* 一个实例讲明为什么要使用内部类内部类
* 例:
* 人休是一个类,人体内部又有一些器官,如心、肝,脾、胃、肾
* 描述心脏的时候,可以把它当成是人体的一个功能,直接用函数来描述吗?这个可以,但你觉得
* 一个函数足以描述心脏这个事物吗?心脏里边有属性,有行为,它是一个比较复杂的个体。它里
* 边包含着跳动,血压,等很多属性行为。属性行为多了,就要用对象封装。所以用类描述心脏。
* 好了,现在接受了一点:就是要把心脏也封装成类。那么可以像下面这样把心脏定义成外部类吗?
* public class Body{
*
* }
* //把心脏定义成外部类
* class Heart{
*
* }
*
* 如果把心脏定义在人体外面的话,心脏如果想访问人体里面的其他东西,如神经系统、血管等等,
* 是不是要先建立人体的对象才能访问里边的东西啊?那不是等于说,要先建立一个没有心脏的人
* 吗?有那样的人吗?那死人吧!?心脏类里面调用人体类,什么意思呢?难道说心脏里面有个人
* 体?显然这样不合适。心脏要能直接访问人体内部的其他属性(器官),所以这时候把心脏定义成
* 为人体的内部类是最合适不过的了,最合理的,也是最优的。
*
*/
public class Body {
 
 
//心脏
private class Heart{
 
}
 
//肝
private class Liver{
 
}
//...
private class OtherOrgan{
 
}
}


参考资料:
1. Java编程思想 第十章:内部类
2. http://blog.csdn.net/nnmmbb/article/details/7832498
3. http://www.cnblogs.com/latter/p/5665015.html
4. http://www.cnblogs.com/nliao/p/3308690.html


原创粉丝点击