我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java中对象池怎么实现

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java中对象池怎么实现

这篇“Java中对象池怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java中对象池怎么实现”文章吧。

1. 什么是对象池

池化并不是什么新鲜的技术,它更像一种软件设计模式,主要功能是缓存一组已经初始化的对象,以供随时可以使用。对象池大多数场景下都是缓存着创建成本过高或者需要重复创建使用的对象,从池子中取对象的时间是可以预测的,但是新建一个对象的时间是不确定的。

当需要一个新对象时,就向池中借出一个,然后对象池标记当前对象正在使用,使用完毕后归还到对象池,以便再次借出。

常见的使用对象池化场景:

  • 对象创建成本过高。

  • 需要频繁的创建大量重复对象,会产生很多内存碎片。

  • 同时使用的对象不会太多。

  • 常见的具体场景如数据库连接池、线程池等。

2. 为什么需要对象池

如果一个对象的创建成本很高,比如建立数据库的连接时耗时过长,在不使用池化技术的情况下,我们的查询过程可能是这样的。

  • 查询 1:建立数据库连接 -> 发起查询 -> 收到响应 -> 关闭连接

  • 查询 2:建立数据库连接 -> 发起查询 -> 收到响应 -> 关闭连接

  • 查询 3:建立数据库连接 -> 发起查询 -> 收到响应 -> 关闭连接

在这种模式下,每次查询都要重新建立关闭连接,因为建立连接是一个耗时的操作,所以这种模式会影响程序的总体性能。

那么使用池化思想是怎么样的呢?同样的过程会转变成下面的步骤。

  • 初始化:建立 N 个数据库连接 -> 缓存起来

  • 查询 1:从缓存借到数据库连接 -> 发起查询 -> 收到响应 -> 归还数据库连接对象到缓存

  • 查询 2:从缓存借到数据库连接 -> 发起查询 -> 收到响应 -> 归还数据库连接对象到缓存

  • 查询 3:从缓存借到数据库连接 -> 发起查询 -> 收到响应 -> 归还数据库连接对象到缓存

使用池化思想后,数据库连接并不会频繁的创建关闭,而是启动后就初始化了 N 个连接以供后续使用,使用完毕后归还对象,这样程序的总体性能得到提升。

3. 对象池的实现

通过上面的例子也可以发现池化思想的几个关键步骤:初始化、借出、归还。上面没有展示销毁步骤, 某些场景下还需要对象的销毁这一过程,比如释放连接。

下面我们手动实现一个简陋的对象池,加深下对对象池的理解。主要是定一个对象池管理类,然后在里面实现对象的初始化、借出、归还、销毁等操作。

package com.wdbyet.tool.objectpool.mypool;import java.io.Closeable;import java.io.IOException;import java.util.HashSet;import java.util.Stack;public class MyObjectPool<T extends Closeable> {    // 池子大小    private Integer size = 5;    // 对象池栈。后进先出    private Stack<T> stackPool = new Stack<>();    // 借出的对象的 hashCode 集合    private HashSet<Integer> borrowHashCodeSet = new HashSet<>();        public synchronized void addObj(T t) {        if ((stackPool.size() + borrowHashCodeSet.size()) == size) {            throw new RuntimeException("池中对象已经达到最大值");        }        stackPool.add(t);        System.out.println("添加了对象:" + t.hashCode());    }        public synchronized T borrowObj() {        if (stackPool.isEmpty()) {            System.out.println("没有可以被借出的对象");            return null;        }        T pop = stackPool.pop();        borrowHashCodeSet.add(pop.hashCode());        System.out.println("借出了对象:" + pop.hashCode());        return pop;    }        public synchronized void returnObj(T t) {        if (borrowHashCodeSet.contains(t.hashCode())) {            stackPool.add(t);            borrowHashCodeSet.remove(t.hashCode());            System.out.println("归还了对象:" + t.hashCode());            return;        }        throw new RuntimeException("只能归还从池中借出的对象");    }        public synchronized void destory() {        if (!borrowHashCodeSet.isEmpty()) {            throw new RuntimeException("尚有未归还的对象,不能关闭所有对象");        }        while (!stackPool.isEmpty()) {            T pop = stackPool.pop();            try {                pop.close();            } catch (IOException e) {                throw new RuntimeException(e);            }        }        System.out.println("已经销毁了所有对象");    }}

代码还是比较简单的,只是简单的示例,下面我们通过池化一个 Redis 连接对象 Jedis 来演示如何使用。

其实 Jedis 中已经有对应的 Jedis 池化管理对象了 JedisPool 了,不过我们这里为了演示对象池的实现,就不使用官方提供的 JedisPool 了。

启动一个 Redis 服务这里不做介绍,假设你已经有了一个 Redis 服务,下面引入 Java 中连接 Redis 需要用到的 Maven 依赖。

<dependency>    <groupId>redis.clients</groupId>    <artifactId>jedis</artifactId>    <version>4.2.0</version></dependency>

正常情况下 Jedis 对象的使用方式:

Jedis jedis = new Jedis("localhost", 6379);String name = jedis.get("name");System.out.println(name);jedis.close();

如果使用上面的对象池,就可以像下面这样使用。

package com.wdbyet.tool.objectpool.mypool;import redis.clients.jedis.Jedis;public class MyObjectPoolTest {    public static void main(String[] args) {        MyObjectPool<Jedis> objectPool = new MyObjectPool<>();        // 增加一个 jedis 连接对象        objectPool.addObj(new Jedis("127.0.0.1", 6379));        objectPool.addObj(new Jedis("127.0.0.1", 6379));        // 从对象池中借出一个 jedis 对象        Jedis jedis = objectPool.borrowObj();        // 一次 redis 查询        String name = jedis.get("name");        System.out.println(String.format("redis get:" + name));        // 归还 redis 连接对象        objectPool.returnObj(jedis);        // 销毁对象池中的所有对象        objectPool.destory();        // 再次借用对象        objectPool.borrowObj();    }}

输出日志:

添加了对象:1556956098
添加了对象:1252585652
借出了对象:1252585652
redis get:www.wdbyte.com
归还了对象:1252585652
已经销毁了所有对象
没有可以被借出的对象

如果使用 JMH 对使用对象池化进行 Redis 查询,和正常创建 Redis 连接然后查询关闭连接的方式进行性能对比,会发现两者的性能差异很大。下面是测试结果,可以发现使用对象池化后的性能是非池化方式的 5 倍左右。

Benchmark                   Mode  Cnt      Score       Error  Units
MyObjectPoolTest.test      thrpt   15   2612.689 &plusmn;   358.767  ops/s
MyObjectPoolTest.testPool  thrpt    9  12414.228 &plusmn; 11669.484  ops/s

4. 开源的对象池工具

上面自己实现的对象池总归有些简陋了,其实开源工具中已经有了非常好用的对象池的实现,如 Apache 的 commons-pool2 工具,很多开源工具中的对象池都是基于此工具实现,下面介绍这个工具的使用方式。

maven 依赖:

<dependency>    <groupId>org.apache.commons</groupId>    <artifactId>commons-pool2</artifactId>    <version>2.11.1</version></dependency>

在 commons-pool2 对象池工具中有几个关键的类。

  • &bull; PooledObjectFactory 类是一个工厂接口,用于实现想要池化对象的创建、验证、销毁等操作。

  • &bull; GenericObjectPool 类是一个通用的对象池管理类,可以进行对象的借出、归还等操作。

  • &bull; GenericObjectPoolConfig 类是对象池的配置类,可以进行对象的最大、最小等容量信息进行配置。

下面通过一个具体的示例演示 commons-pool2 工具类的使用,这里依旧选择 Redis 连接对象 Jedis 作为演示。

实现 PooledObjectFactory 工厂类,实现其中的对象创建和销毁方法。

public class MyPooledObjectFactory implements PooledObjectFactory<Jedis> {    @Override    public void activateObject(PooledObject<Jedis> pooledObject) throws Exception {    }    @Override    public void destroyObject(PooledObject<Jedis> pooledObject) throws Exception {        Jedis jedis = pooledObject.getObject();        jedis.close();          System.out.println("释放连接");    }    @Override    public PooledObject<Jedis> makeObject() throws Exception {        return new DefaultPooledObject(new Jedis("localhost", 6379));    }    @Override    public void passivateObject(PooledObject<Jedis> pooledObject) throws Exception {    }    @Override    public boolean validateObject(PooledObject<Jedis> pooledObject) {        return false;    }}

继承 GenericObjectPool 类,实现对对象的借出、归还等操作。

public class MyGenericObjectPool extends GenericObjectPool<Jedis> {    public MyGenericObjectPool(PooledObjectFactory factory) {        super(factory);    }    public MyGenericObjectPool(PooledObjectFactory factory, GenericObjectPoolConfig config) {        super(factory, config);    }    public MyGenericObjectPool(PooledObjectFactory factory, GenericObjectPoolConfig config,        AbandonedConfig abandonedConfig) {        super(factory, config, abandonedConfig);    }}

可以看到 MyGenericObjectPool 类的构造函数中的入参有 GenericObjectPoolConfig 对象,这是个对象池的配置对象,可以配置对象池的容量大小等信息,这里就不配置了,使用默认配置。

通过 GenericObjectPoolConfig 的源码可以看到默认配置中,对象池的容量是 8 个

public class GenericObjectPoolConfig<T> extends BaseObjectPoolConfig<T> {        public static final int DEFAULT_MAX_TOTAL = 8;        public static final int DEFAULT_MAX_IDLE = 8;

下面编写一个对象池使用测试类。

public class ApachePool {    public static void main(String[] args) throws Exception {        MyGenericObjectPool objectMyObjectPool = new MyGenericObjectPool(new MyPooledObjectFactory());        Jedis jedis = objectMyObjectPool.borrowObject();        String name = jedis.get("name");        System.out.println(name);        objectMyObjectPool.returnObject(jedis);        objectMyObjectPool.close();    }}

输出日志:

redis get:www.wdbyte.com
释放连接

上面已经演示了 commons-pool2 工具中的对象池的使用方式,从上面的例子中可以发现这种对象池中只能存放同一种初始化条件的对象,如果这里的 Redis 我们需要存储一个本地连接和一个远程连接的两种 Jedis 对象,就不能满足了。那么怎么办呢?

其实 commons-pool2 工具已经考虑到了这种情况,通过增加一个 key 值可以在同一个对象池管理中进行区分,代码和上面类似,直接贴出完整的代码实现。

package com.wdbyet.tool.objectpool.apachekeyedpool;import org.apache.commons.pool2.BaseKeyedPooledObjectFactory;import org.apache.commons.pool2.KeyedPooledObjectFactory;import org.apache.commons.pool2.PooledObject;import org.apache.commons.pool2.impl.AbandonedConfig;import org.apache.commons.pool2.impl.DefaultPooledObject;import org.apache.commons.pool2.impl.GenericKeyedObjectPool;import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;import redis.clients.jedis.Jedis;public class ApacheKeyedPool {    public static void main(String[] args) throws Exception {        String key = "local";        MyGenericKeyedObjectPool objectMyObjectPool = new MyGenericKeyedObjectPool(new MyKeyedPooledObjectFactory());        Jedis jedis = objectMyObjectPool.borrowObject(key);        String name = jedis.get("name");        System.out.println("redis get :" + name);        objectMyObjectPool.returnObject(key, jedis);    }}class MyKeyedPooledObjectFactory extends BaseKeyedPooledObjectFactory<String, Jedis> {    @Override    public Jedis create(String key) throws Exception {        if ("local".equals(key)) {            return new Jedis("localhost", 6379);        }        if ("remote".equals(key)) {            return new Jedis("192.168.0.105", 6379);        }        return null;    }    @Override    public PooledObject<Jedis> wrap(Jedis value) {        return new DefaultPooledObject<>(value);    }}class MyGenericKeyedObjectPool extends GenericKeyedObjectPool<String, Jedis> {    public MyGenericKeyedObjectPool(KeyedPooledObjectFactory<String, Jedis> factory) {        super(factory);    }    public MyGenericKeyedObjectPool(KeyedPooledObjectFactory<String, Jedis> factory,        GenericKeyedObjectPoolConfig<Jedis> config) {        super(factory, config);    }    public MyGenericKeyedObjectPool(KeyedPooledObjectFactory<String, Jedis> factory,        GenericKeyedObjectPoolConfig<Jedis> config, AbandonedConfig abandonedConfig) {        super(factory, config, abandonedConfig);    }}

输出日志:

redis get :www.wdbyte.com

5. JedisPool 对象池实现分析

这篇文章中的演示都使用了 Jedis 连接对象,其实在 Jedis SDK 中已经实现了相应的对象池,也就是我们常用的 JedisPool 类。那么这里的 JedisPool 是怎么实现的呢?我们先看一下 JedisPool 的使用方式。

package com.wdbyet.tool.objectpool;import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;public class JedisPoolTest {    public static void main(String[] args) {        JedisPool jedisPool = new JedisPool("localhost", 6379);        // 从对象池中借一个对象        Jedis jedis = jedisPool.getResource();        String name = jedis.get("name");        System.out.println("redis get :" + name);        jedis.close();        // 彻底退出前,关闭 Redis 连接池        jedisPool.close();    }}

代码中添加了注释,可以看到通过 jedisPool.getResource() 拿到了一个对象,这里和上面 commons-pool2 工具中的 borrowObject 十分相似,继续追踪它的代码实现可以看到下面的代码。

// redis.clients.jedis.JedisPool// public class JedisPool extends Pool<Jedis> {public Jedis getResource() {    Jedis jedis = (Jedis)super.getResource();    jedis.setDataSource(this);    return jedis;}// 继续追踪 super.getResource()// redis.clients.jedis.util.Poolpublic T getResource() {    try {        return super.borrowObject();    } catch (JedisException var2) {        throw var2;    } catch (Exception var3) {        throw new JedisException("Could not get a resource from the pool", var3);    }}

竟然看到了 super.borrowObject() ,多么熟悉的方法,继续分析代码可以发现 Jedis 对象池也是使用了 commons-pool2 工具作为实现。既然如此,那么 jedis.close() 方法的逻辑我们应该也可以猜到了,应该有一个归还的操作,查看代码发现果然如此。

// redis.clients.jedis.JedisPool// public class JedisPool extends Pool<Jedis> {public void close() {    if (this.dataSource != null) {        Pool<Jedis> pool = this.dataSource;        this.dataSource = null;        if (this.isBroken()) {            pool.returnBrokenResource(this);        } else {            pool.returnResource(this);        }    } else {        this.connection.close();    }}// 继续追踪 super.getResource()// redis.clients.jedis.util.Poolpublic void returnResource(T resource) {    if (resource != null) {        try {            super.returnObject(resource);        } catch (RuntimeException var3) {            throw new JedisException("Could not return the resource to the pool", var3);        }    }}

通过上面的分析,可见 Jedis 确实使用了 commons-pool2 工具进行对象池的管理,通过分析 JedisPool 类的继承关系图也可以发现。

Java中对象池怎么实现

以上就是关于“Java中对象池怎么实现”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java中对象池怎么实现

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java中对象池怎么实现

这篇“Java中对象池怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java中对象池怎么实现”文章吧。1. 什么是对
2023-07-02

Java中的对象池怎么使用

本文小编为大家详细介绍“Java中的对象池怎么使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java中的对象池怎么使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1. 什么是对象池对象池,顾名思义就是一定
2023-07-05

Java 中如何实现对象的复制?(java怎么复制对象)

在Java编程中,有时我们需要复制一个对象,以便在不同的地方使用相同的数据或者进行一些操作。那么,Java怎么复制对象呢?下面将为大家介绍两种常见的方法。一、浅拷贝(ShallowCopy)浅拷贝是创建一个新对象,其值与
Java 中如何实现对象的复制?(java怎么复制对象)
Java2024-12-16

C++如何实现对象池

这篇“C++如何实现对象池”文章,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要参考一下,对于“C++如何实现对象池”,小编整理了以下知识点,请大家跟着小编的步伐一步一步的慢慢理解,接下来就让我们进入主题吧。前言需求
2023-06-26

Java对象克隆怎么实现

本篇内容主要讲解“Java对象克隆怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java对象克隆怎么实现”吧!1. Overiew在实际编程中,我们经常会遇到这样一个情景:有一个对象A,
2023-06-17

java中怎么实现面向对象编程

这篇文章给大家介绍java中怎么实现面向对象编程,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。1:允许将子类的引用付给父类的对象,但子类中的那些不是从父类继承来的成员将不再可见。例:Bus bus=new Bus();
2023-06-17

java怎么实现对象克隆

在Java中,可以通过两种方式来实现对象克隆:浅拷贝和深拷贝。1. 浅拷贝:使用Object类的clone()方法进行对象的浅拷贝。浅拷贝会创建一个新的对象,将原始对象的非静态字段的值复制到新对象中,对于引用类型的字段,复制的是引用而不是对
2023-08-18

Java GenericObjectPool对象池化技术怎么使用

这篇文章主要介绍了Java GenericObjectPool对象池化技术怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java GenericObjectPool对象池化技术怎么使用文章都会有所收获,
2023-07-05

golang对象池的实现原理是什么

Golang对象池是一种用于重复利用对象的机制,以避免频繁的创建和销毁对象的开销。它通过预先创建一定数量的对象,并在需要时从池中获取对象,使用完毕后再将对象放回池中,以供后续的使用。Golang对象池的实现原理主要包括以下几个步骤:初始化
2023-10-27

Java对象序列化怎么实现

本篇内容介绍了“Java对象序列化怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!从 Java 类产生 XML 把 Ajax 响应作为
2023-06-03

如何在java中使用对象池

这篇文章将为大家详细讲解有关如何在java中使用对象池,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。1、说明(1)创建工厂类:通过继承BaseGenericObjectPool或者实现基础接
2023-06-15

java string转map对象怎么实现

要将Java中的String转换为Map对象,可以通过以下步骤实现:为了将String转换为Map,首先需要将String解析为键值对的形式。可以使用split()方法将String按照特定的分隔符分割成多个字符串。然后,遍历分割后的字符串
java string转map对象怎么实现
2023-10-28

如何实现 Java 深度克隆对象?(java深度克隆对象怎么实现)

在Java编程中,深度克隆对象是一个常见且重要的操作。深度克隆意味着创建一个新的对象,该对象与原始对象具有相同的状态,但在内存中是独立的,对新对象的修改不会影响原始对象。以下是实现Java深度克隆对象的两种常见方法:一、实现Cloneable接口并重
如何实现 Java 深度克隆对象?(java深度克隆对象怎么实现)
Java2024-12-22

如何实现 Java 对象的深拷贝?(java对象的深拷贝怎么实现)

在Java编程中,对象的拷贝是一个常见的操作。深拷贝和浅拷贝是两种不同的拷贝方式,深拷贝会创建一个新的对象,该对象包含原始对象的所有属性值的副本,而浅拷贝只是创建了原始对象的引用的副本。本文将介绍如何在Java中实现对象的深拷贝。一、为什么需要对象的深拷
如何实现 Java 对象的深拷贝?(java对象的深拷贝怎么实现)
Java2024-12-16

在 Java 中怎样实现对象的深拷贝?(Java中如何实现对象的深拷贝)

在Java编程中,对象的拷贝是一个常见的操作。其中,深拷贝和浅拷贝是两种不同的拷贝方式。浅拷贝只是复制了对象的引用,而深拷贝则会创建一个新的对象,并复制原对象的所有属性。本文将介绍在Java中如何实现对象的深拷贝。一、为什么需要对象的深拷贝?
在 Java 中怎样实现对象的深拷贝?(Java中如何实现对象的深拷贝)
Java2024-12-19

怎么使用CocosCreator对象池

本篇文章给大家分享的是有关怎么使用CocosCreator对象池,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。具体操作第一步:准备好 Prefab把你想要创建的节点事先设置好并
2023-06-14

Java对象池技术的原理及其实现方法

这篇文章主要讲解了“Java对象池技术的原理及其实现方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java对象池技术的原理及其实现方法”吧!摘 要 :本文在分析对象池技术基本原理的基础上
2023-06-03

java object对象转数组怎么实现

在Java中,可以使用反射来实现将对象转换为数组。首先,通过使用 getClass() 方法获取对象的类信息,然后使用 getDeclaredFields() 方法获取对象的所有字段。接下来,创建一个与字段数量相同的数组,并通过遍历字段来获
2023-10-18

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录