Java中内部类到底有什么用?

java中内部类种类较多,语法比较复杂,用法也不尽相同。
归纳下来,能够分类为如下五种内部类。java

  1. 内部类
  2. 嵌套内部类
  3. 局部内部类
  4. 接口内部类
  5. 匿名内部类

本篇文章只对实际项目开发中用的较多的,普通内部类与匿名内部类作必定介绍。其余三种如有兴趣请自行经过谷歌或书籍进行了解。python

内部类

首先经过一个简单的小示例,来看看内部类的语法吧。程序员

import java.util.HashMap;

public class Parcell {

    private HashMap<String, String> testMap = new HashMap<String, String>();

    class Contents {
        // 返回一个外部类的引用.
        public Parcell ParcellRef = Parcell.this;
    }

    class Destination {
        public void putSomethingInMap() {
            testMap.put("hello", "world");
            System.out.println(testMap.get("hello"));
        }
        
    }

    public Destination to() {
        return new Destination();
    }

    public Contents contents() {
        return new Contents();
    }

    public void ship(String dest) {
        Contents c = new Contents();
        Destination d = new Destination();
    }

    public static void main(String[] args) {
        Parcell p = new Parcell();
        Parcell.Contents c = p.contents();
        Parcell.Destination d = p.to();
        d.putSomethingInMap();
        Parcell.Contents c1 = p.new Contents();
    }

}

复制代码

内部类的语法和相信你们都很熟悉。
在这里我再自做主张的为你们归纳一下编程

  1. 普通内部类持有一个指向外部类的引用。要建立普通内部类,必定要先建立外部类。
  2. 普通内部类就像人体的心脏同样,可以随意访问外部类的任意成员变量。
  3. 在内部类中能够经过“外部类类名.this”的方式返回一个指向外部类实例的引用.如Parcell.this
  4. 在外部类的static方法中若要建立内部类对象,则须要经过“外部类类名.new XXX()”的方式来建立。
  5. 普通内部类中不能拥有静态成员变量。静态内部类中能够拥有静态成员变量。也能够拥有非静态成员变量。可是静态内部类不能访问外部类中非静态的成员变量。而普通内部类能够访问外部类的静态成员变量。

为何static方法中须要p.new XXX()的方式而非static方法中咱们直接new 内部类名 就能够建立一个对象了呢?
若是你有这样的疑问请再看看第一条,必定能够想明白的。设计模式

普通内部类的语法大体就是这样了。
那么,回到咱们主题。闭包

内部类到底有什么用?咱们在实际项目中,应该如何使用内部类呢?
内部类的用处或者说用法,归根结底,主要就是一点:
: “内部类,主要是设计出来用来解决java中所‘缺乏’的,多重继承的概念的。”ide

什么?难道java不是靠接口来实现多重继承的吗?我认为,这种说法对,也不对。下面咱们来看这样一个例子。函数

你正在参与一项代号X的星际飞船项目。
宇航局的人但愿飞船上的综合机器人可以完成两个工做。一是做为向导,可以供人们查阅信息。二是做为修理机器人,完成一些简单的飞船平常维护工做。
做为软件工程师,你被要求编写一段代码来实现这两个功能。
ui

好消息是,向导部分的功能与飞船修理维护的功能,已经由你的同事们完成了!太好了,我只须要调用他们提供给咱们的接口就大功告成了!
坏消息是,同事们编写的向导功能与飞船修理功能的接口,居然都叫作work!
这可伤脑筋了,应该怎么办呢?
this

public class Guider {

    public void work(String name) {
        System.out.println("欢迎光临" + name + ",请查阅飞船信息");
    }

}

-------------------------------------------------------------------

public class Repairer {
    
    public void work (String name) {
        System.out.println("你好" + name + ",开始准备对飞船进行维护.");
    }

}

-------------------------------------------------------------------

public class SpacecraftRobot extends Guider {
    
    
    public void doGuidWork(String name) { 
        // 调用guider的work方法
        work(name);
    }
    
    public void doRepairWork(String name) {
        // 返回内部类引用,调用内部类实例的work方法。
        new repairerRobot().doRepairWork(name);
    }
    
    public class repairerRobot extends Repairer {
        
        public void doRepairWork(String name) {
            work(name);
        }
    }
}

复制代码

太棒了。经过使用内部类与“多重继承”,咱们实现了这个功能。如今这个综合机器人可以正常工做了!

对于用户来讲,只须要走到机器人面前,告诉机器人你想要doGuidWork仍是doRepairWork,它就可以帮你干活儿了。内部类的代码对用户,对外界完全隐藏了起来,用户惟一可以得到的信息就是这两个方法而已。

匿名内部类

综合机器人原型机试作成功后,新的工做来了!
咱们须要对原型机进行量产。以知足每艘星际飞船的须要。
如今咱们要编写一间生产综合机器人的工厂。每当咱们访问一次工厂,就可以从工厂中提取出一台崭新的综合机器人。聪明的你想到了用工厂设计模式来解决这个问题!可是因为有了内部类,因此咱们的工厂,稍稍显得有点不一样

// 机器人工厂接口。经过getSpaceCraftRobot方法对外提供机器人
public interface SpaceCraftRobotFactory {
    SpacecraftRobot getSpaceCraftRobot();
}

-------------------------------------------------------------------


public class ProduceSpaceCraftRobot {
    // 不再用显示的建立工厂类的对象了!
    private ProduceSpaceCraftRobot() {

    }
    // 经过匿名内部类,建立工厂对象!将工厂封装到了内部。不对外界暴露
    public static SpaceCraftRobotFactory produceRobot = new SpaceCraftRobotFactory () {
        public SpacecraftRobot getSpaceCraftRobot() {
            return new SpacecraftRobot();
        }
    };
    
}

-------------------------------------------------------------------

// 客户
public class Consumer {

    public static void main(String[] args) {
        // 客户来提取机器人了.
        SpacecraftRobot x1 = ProduceSpaceCraftRobot.produceRobot.getSpaceCraftRobot();
        x1.doGuidWork("lch");
        x1.doRepairWork("lch");
    }

}

复制代码

经过建立匿名内部类,咱们使传统的工厂设计模式优雅了许多!不再用在外部编写new xxxFactory()这样丑陋,多余的代码了。
如今的工厂被匿名内部类隐藏了起来。客户只须要关心有没有拿到趁心如意的机器人。不该该,不须要关心工厂的名字,也不须要知道工厂是干吗的。

真棒,你顺利完成了宇航局交给你的任务。
恭喜你,你是这个星球的英雄。

Java中的闭包,闭包与内部类的关系

做为一个程序员,即便你历来没有使用过,你也应该据说过闭包与回调。
要从java,特别是j2ee的方向入手去讲解闭包与回调,会比较困难。
因此咱们首先从python来入手,来了解闭包与回调究竟是什么。

python是一门优秀的解释性语言。你应该掌握他。

下面咱们来看一看,标准的回调,在Python中是什么样子的。

#定义一个返回sum函数的名叫base_sum函数的函数
def base_sum(a,b):
    #在base_sum中定义一个sum()函数用来计算base_sum(a,b)的形参之合
    def sum():
        #返回a+b的值
        return a + b
    #返回定义的sum函数
    return sum
#调用base_sum返回函数sum(),能够理解为返回了一个函数指针
return_method = base_sum(1,2)
#打印出返回的函数对象
print(return_method)
#经过指针回调函数对象,返回a与b的合
print(return_method())

----------
<function base_sum.<locals>.sum at 0x1018f3c80>
3
复制代码

对于java程序员来讲,在一个函数中定义另一个函数也许会比较烧脑。
你能够试着这样去理解他:
“首先你须要了解的是,函数也须要占据内存空间,因此函数在内存中也是有地址的。在c语言中,函数名就表明这个函数的地址。
若是你有过c语言的编程经验,你就应该知道在一个函数中,返回一个指针是一件很容易的事情。
因此,对于以上这段python代码,你能够尝试把它理解为:
base_sum()函数中定义了一个指向sum()函数的指针,而且这个指针做为base_sum()的返回值。”

好了,如今咱们根据上面的例子,来“定义一下闭包”。
: 调用外部函数,返回一个持有外部函数变量,参数引用的内部函数对象的程序结构,咱们就称它为“闭包”。

遗憾的是,java中没有为咱们显示的提供指针供咱们操做,也没有提供相似python,javascrpit中的函数定义的语法,那么咱们应该如何实现闭包呢?
不妨仍是经过综合机器人来解答这个疑问吧。这一次,让咱们稍稍修改一下综合机器人的代码以下:

public class SpacecraftRobot extends Guider {
    // 外部类的成员变量
    private String name;
    
    public SpacecraftRobot(String name) {
        this.name = name;
    }
    
    public class repairerRobot extends Repairer {
        
        public void doRepairWork() {
            // 内部类持有外部类的引用,访问外部类的成员变量name。
            work(name);
        }
    }
    
    public void doGuidWork() { 
        // 调用guider的work方法
        work(name);
    }
    
    public void doRepairWork() {
        // 返回一个持有外部类变量引用的内部类的对象,而后调用这个对象,实现具体的业务逻辑.
        new repairerRobot().doRepairWork();
    }
}

复制代码

经过对java内部类的合理利用,咱们“模拟”出了一个闭包的程序结构。
该程序经过调用外部类对象,从而返回了一个持有外部类对象变量引用的内部类对象。当咱们再次调用内部类对象的某个方法时,咱们实现了具体的业务逻辑。

总结

  1. 内部类一般用来解决“多重继承”的问题。
  2. 当你但愿隐藏一个类的实现,减小工程中.java文件数量,或者这个类不想被扩展时,你能够经过匿名内部类来建立一个类的对象。
  3. java虽然没法直接在语法层面上支持闭包,可是能够经过内部类来模拟一个闭包的程序结构。
相关文章
相关标签/搜索