欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文搞懂Java中對(duì)象池的實(shí)現(xiàn)

 更新時(shí)間:2022年07月11日 11:30:12   作者:程序猿阿朗  
池化并不是什么新鮮的技術(shù),它更像一種軟件設(shè)計(jì)模式,主要功能是緩存一組已經(jīng)初始化的對(duì)象,以供隨時(shí)可以使用。本文將為大家詳細(xì)講講Java中對(duì)象池的實(shí)現(xiàn),需要的可以參考一下

最近在分析一個(gè)應(yīng)用中的某個(gè)接口的耗時(shí)情況時(shí),發(fā)現(xiàn)一個(gè)看起來極其普通的對(duì)象創(chuàng)建操作,竟然每次需要消耗 8ms 左右時(shí)間,分析后發(fā)現(xiàn)這個(gè)對(duì)象可以通過對(duì)象池模式進(jìn)行優(yōu)化,優(yōu)化后此步耗時(shí)僅有 0.01ms,這篇文章介紹對(duì)象池相關(guān)知識(shí)。

1. 什么是對(duì)象池

池化并不是什么新鮮的技術(shù),它更像一種軟件設(shè)計(jì)模式,主要功能是緩存一組已經(jīng)初始化的對(duì)象,以供隨時(shí)可以使用。對(duì)象池大多數(shù)場(chǎng)景下都是緩存著創(chuàng)建成本過高或者需要重復(fù)創(chuàng)建使用的對(duì)象,從池子中取對(duì)象的時(shí)間是可以預(yù)測(cè)的,但是新建一個(gè)對(duì)象的時(shí)間是不確定的。

當(dāng)需要一個(gè)新對(duì)象時(shí),就向池中借出一個(gè),然后對(duì)象池標(biāo)記當(dāng)前對(duì)象正在使用,使用完畢后歸還到對(duì)象池,以便再次借出。

常見的使用對(duì)象池化場(chǎng)景:

  • 1. 對(duì)象創(chuàng)建成本過高。
  • 2. 需要頻繁的創(chuàng)建大量重復(fù)對(duì)象,會(huì)產(chǎn)生很多內(nèi)存碎片。
  • 3. 同時(shí)使用的對(duì)象不會(huì)太多。
  • 4. 常見的具體場(chǎng)景如數(shù)據(jù)庫(kù)連接池、線程池等。

2. 為什么需要對(duì)象池

如果一個(gè)對(duì)象的創(chuàng)建成本很高,比如建立數(shù)據(jù)庫(kù)的連接時(shí)耗時(shí)過長(zhǎng),在不使用池化技術(shù)的情況下,我們的查詢過程可能是這樣的。

  • 查詢 1:建立數(shù)據(jù)庫(kù)連接 -> 發(fā)起查詢 -> 收到響應(yīng) -> 關(guān)閉連接
  • 查詢 2:建立數(shù)據(jù)庫(kù)連接 -> 發(fā)起查詢 -> 收到響應(yīng) -> 關(guān)閉連接
  • 查詢 3:建立數(shù)據(jù)庫(kù)連接 -> 發(fā)起查詢 -> 收到響應(yīng) -> 關(guān)閉連接

在這種模式下,每次查詢都要重新建立關(guān)閉連接,因?yàn)榻⑦B接是一個(gè)耗時(shí)的操作,所以這種模式會(huì)影響程序的總體性能。

那么使用池化思想是怎么樣的呢?同樣的過程會(huì)轉(zhuǎn)變成下面的步驟。

  • 初始化:建立 N 個(gè)數(shù)據(jù)庫(kù)連接 -> 緩存起來
  • 查詢 1:從緩存借到數(shù)據(jù)庫(kù)連接 -> 發(fā)起查詢 -> 收到響應(yīng) -> 歸還數(shù)據(jù)庫(kù)連接對(duì)象到緩存
  • 查詢 2:從緩存借到數(shù)據(jù)庫(kù)連接 -> 發(fā)起查詢 -> 收到響應(yīng) -> 歸還數(shù)據(jù)庫(kù)連接對(duì)象到緩存
  • 查詢 3:從緩存借到數(shù)據(jù)庫(kù)連接 -> 發(fā)起查詢 -> 收到響應(yīng) -> 歸還數(shù)據(jù)庫(kù)連接對(duì)象到緩存

使用池化思想后,數(shù)據(jù)庫(kù)連接并不會(huì)頻繁的創(chuàng)建關(guān)閉,而是啟動(dòng)后就初始化了 N 個(gè)連接以供后續(xù)使用,使用完畢后歸還對(duì)象,這樣程序的總體性能得到提升。

3. 對(duì)象池的實(shí)現(xiàn)

通過上面的例子也可以發(fā)現(xiàn)池化思想的幾個(gè)關(guān)鍵步驟:初始化、借出、歸還。上面沒有展示銷毀步驟, 某些場(chǎng)景下還需要對(duì)象的銷毀這一過程,比如釋放連接。

下面我們手動(dòng)實(shí)現(xiàn)一個(gè)簡(jiǎn)陋的對(duì)象池,加深下對(duì)對(duì)象池的理解。主要是定一個(gè)對(duì)象池管理類,然后在里面實(shí)現(xiàn)對(duì)象的初始化、借出、歸還、銷毀等操作。

package?com.wdbyet.tool.objectpool.mypool;

import?java.io.Closeable;
import?java.io.IOException;
import?java.util.HashSet;
import?java.util.Stack;

/**
?*?@author?https://www.wdbyte.com
?*/
public?class?MyObjectPool<T?extends?Closeable>?{

????//?池子大小
????private?Integer?size?=?5;
????//?對(duì)象池棧。后進(jìn)先出
????private?Stack<T>?stackPool?=?new?Stack<>();
????//?借出的對(duì)象的?hashCode?集合
????private?HashSet<Integer>?borrowHashCodeSet?=?new?HashSet<>();

????/**
?????*?增加一個(gè)對(duì)象
?????*
?????*?@param?t
?????*/
????public?synchronized?void?addObj(T?t)?{
????????if?((stackPool.size()?+?borrowHashCodeSet.size())?==?size)?{
????????????throw?new?RuntimeException("池中對(duì)象已經(jīng)達(dá)到最大值");
????????}
????????stackPool.add(t);
????????System.out.println("添加了對(duì)象:"?+?t.hashCode());
????}

????/**
?????*?借出一個(gè)對(duì)象
?????*
?????*?@return
?????*/
????public?synchronized?T?borrowObj()?{
????????if?(stackPool.isEmpty())?{
????????????System.out.println("沒有可以被借出的對(duì)象");
????????????return?null;
????????}
????????T?pop?=?stackPool.pop();
????????borrowHashCodeSet.add(pop.hashCode());
????????System.out.println("借出了對(duì)象:"?+?pop.hashCode());
????????return?pop;
????}

????/**
?????*?歸還一個(gè)對(duì)象
?????*
?????*?@param?t
?????*/
????public?synchronized?void?returnObj(T?t)?{
????????if?(borrowHashCodeSet.contains(t.hashCode()))?{
????????????stackPool.add(t);
????????????borrowHashCodeSet.remove(t.hashCode());
????????????System.out.println("歸還了對(duì)象:"?+?t.hashCode());
????????????return;
????????}
????????throw?new?RuntimeException("只能歸還從池中借出的對(duì)象");
????}

????/**
?????*?銷毀池中對(duì)象
?????*/
????public?synchronized?void?destory()?{
????????if?(!borrowHashCodeSet.isEmpty())?{
????????????throw?new?RuntimeException("尚有未歸還的對(duì)象,不能關(guān)閉所有對(duì)象");
????????}
????????while?(!stackPool.isEmpty())?{
????????????T?pop?=?stackPool.pop();
????????????try?{
????????????????pop.close();
????????????}?catch?(IOException?e)?{
????????????????throw?new?RuntimeException(e);
????????????}
????????}
????????System.out.println("已經(jīng)銷毀了所有對(duì)象");
????}
}

代碼還是比較簡(jiǎn)單的,只是簡(jiǎn)單的示例,下面我們通過池化一個(gè) Redis 連接對(duì)象 Jedis 來演示如何使用。

其實(shí) Jedis 中已經(jīng)有對(duì)應(yīng)的 Jedis 池化管理對(duì)象了 JedisPool 了,不過我們這里為了演示對(duì)象池的實(shí)現(xiàn),就不使用官方提供的 JedisPool 了。

啟動(dòng)一個(gè) Redis 服務(wù)這里不做介紹,假設(shè)你已經(jīng)有了一個(gè) Redis 服務(wù),下面引入 Java 中連接 Redis 需要用到的 Maven 依賴。

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

正常情況下 Jedis 對(duì)象的使用方式:

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

如果使用上面的對(duì)象池,就可以像下面這樣使用。

package?com.wdbyet.tool.objectpool.mypool;

import?redis.clients.jedis.Jedis;

/**
?*?@author?niulang
?*?@date?2022/07/02
?*/
public?class?MyObjectPoolTest?{

????public?static?void?main(String[]?args)?{
????????MyObjectPool<Jedis>?objectPool?=?new?MyObjectPool<>();
????????//?增加一個(gè)?jedis?連接對(duì)象
????????objectPool.addObj(new?Jedis("127.0.0.1",?6379));
????????objectPool.addObj(new?Jedis("127.0.0.1",?6379));
????????//?從對(duì)象池中借出一個(gè)?jedis?對(duì)象
????????Jedis?jedis?=?objectPool.borrowObj();
????????//?一次?redis?查詢
????????String?name?=?jedis.get("name");
????????System.out.println(String.format("redis?get:"?+?name));
????????//?歸還?redis?連接對(duì)象
????????objectPool.returnObj(jedis);
????????//?銷毀對(duì)象池中的所有對(duì)象
????????objectPool.destory();
????????//?再次借用對(duì)象
????????objectPool.borrowObj();
????}
}

輸出日志:

添加了對(duì)象:1556956098
添加了對(duì)象:1252585652
借出了對(duì)象:1252585652
redis get:www.wdbyte.com
歸還了對(duì)象:1252585652
已經(jīng)銷毀了所有對(duì)象
沒有可以被借出的對(duì)象

如果使用 JMH 對(duì)使用對(duì)象池化進(jìn)行 Redis 查詢,和正常創(chuàng)建 Redis 連接然后查詢關(guān)閉連接的方式進(jìn)行性能對(duì)比,會(huì)發(fā)現(xiàn)兩者的性能差異很大。下面是測(cè)試結(jié)果,可以發(fā)現(xiàn)使用對(duì)象池化后的性能是非池化方式的 5 倍左右。

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

4. 開源的對(duì)象池工具

上面自己實(shí)現(xiàn)的對(duì)象池總歸有些簡(jiǎn)陋了,其實(shí)開源工具中已經(jīng)有了非常好用的對(duì)象池的實(shí)現(xiàn),如 Apache 的 commons-pool2 工具,很多開源工具中的對(duì)象池都是基于此工具實(shí)現(xiàn),下面介紹這個(gè)工具的使用方式。

maven 依賴:

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

在 commons-pool2 對(duì)象池工具中有幾個(gè)關(guān)鍵的類。

  • • PooledObjectFactory 類是一個(gè)工廠接口,用于實(shí)現(xiàn)想要池化對(duì)象的創(chuàng)建、驗(yàn)證、銷毀等操作。
  • • GenericObjectPool 類是一個(gè)通用的對(duì)象池管理類,可以進(jìn)行對(duì)象的借出、歸還等操作。
  • • GenericObjectPoolConfig 類是對(duì)象池的配置類,可以進(jìn)行對(duì)象的最大、最小等容量信息進(jìn)行配置。

下面通過一個(gè)具體的示例演示 commons-pool2 工具類的使用,這里依舊選擇 Redis 連接對(duì)象 Jedis 作為演示。

實(shí)現(xiàn) PooledObjectFactory 工廠類,實(shí)現(xiàn)其中的對(duì)象創(chuàng)建和銷毀方法。

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 類,實(shí)現(xiàn)對(duì)對(duì)象的借出、歸還等操作。

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 類的構(gòu)造函數(shù)中的入?yún)⒂?nbsp;GenericObjectPoolConfig 對(duì)象,這是個(gè)對(duì)象池的配置對(duì)象,可以配置對(duì)象池的容量大小等信息,這里就不配置了,使用默認(rèn)配置。

通過 GenericObjectPoolConfig 的源碼可以看到默認(rèn)配置中,對(duì)象池的容量是 8 個(gè)。

public?class?GenericObjectPoolConfig<T>?extends?BaseObjectPoolConfig<T>?{

????/**
?????*?The?default?value?for?the?{@code?maxTotal}?configuration?attribute.
?????*?@see?GenericObjectPool#getMaxTotal()
?????*/
????public?static?final?int?DEFAULT_MAX_TOTAL?=?8;

????/**
?????*?The?default?value?for?the?{@code?maxIdle}?configuration?attribute.
?????*?@see?GenericObjectPool#getMaxIdle()
?????*/
????public?static?final?int?DEFAULT_MAX_IDLE?=?8;

下面編寫一個(gè)對(duì)象池使用測(cè)試類。

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
釋放連接

上面已經(jīng)演示了 commons-pool2 工具中的對(duì)象池的使用方式,從上面的例子中可以發(fā)現(xiàn)這種對(duì)象池中只能存放同一種初始化條件的對(duì)象,如果這里的 Redis 我們需要存儲(chǔ)一個(gè)本地連接和一個(gè)遠(yuǎn)程連接的兩種 Jedis 對(duì)象,就不能滿足了。那么怎么辦呢?

其實(shí) commons-pool2 工具已經(jīng)考慮到了這種情況,通過增加一個(gè) key 值可以在同一個(gè)對(duì)象池管理中進(jìn)行區(qū)分,代碼和上面類似,直接貼出完整的代碼實(shí)現(xiàn)。

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;

/**
?*?@author?https://www.wdbyte.com
?*?@date?2022/07/07
?*/
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 對(duì)象池實(shí)現(xiàn)分析

這篇文章中的演示都使用了 Jedis 連接對(duì)象,其實(shí)在 Jedis SDK 中已經(jīng)實(shí)現(xiàn)了相應(yīng)的對(duì)象池,也就是我們常用的 JedisPool 類。那么這里的 JedisPool 是怎么實(shí)現(xiàn)的呢?我們先看一下 JedisPool 的使用方式。

package?com.wdbyet.tool.objectpool;

import?redis.clients.jedis.Jedis;
import?redis.clients.jedis.JedisPool;

/**
?*?@author?https://www.wdbyte.com
?*/
public?class?JedisPoolTest?{

????public?static?void?main(String[]?args)?{
????????JedisPool?jedisPool?=?new?JedisPool("localhost",?6379);
????????//?從對(duì)象池中借一個(gè)對(duì)象
????????Jedis?jedis?=?jedisPool.getResource();
????????String?name?=?jedis.get("name");
????????System.out.println("redis?get?:"?+?name);
????????jedis.close();
????????//?徹底退出前,關(guān)閉?Redis?連接池
????????jedisPool.close();
????}
}

代碼中添加了注釋,可以看到通過 jedisPool.getResource() 拿到了一個(gè)對(duì)象,這里和上面 commons-pool2 工具中的 borrowObject 十分相似,繼續(xù)追蹤它的代碼實(shí)現(xiàn)可以看到下面的代碼。

//?redis.clients.jedis.JedisPool
//?public?class?JedisPool?extends?Pool<Jedis>?{
public?Jedis?getResource()?{
????Jedis?jedis?=?(Jedis)super.getResource();
????jedis.setDataSource(this);
????return?jedis;
}
//?繼續(xù)追蹤?super.getResource()
//?redis.clients.jedis.util.Pool
public?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() ,多么熟悉的方法,繼續(xù)分析代碼可以發(fā)現(xiàn) Jedis 對(duì)象池也是使用了 commons-pool2 工具作為實(shí)現(xiàn)。既然如此,那么 jedis.close() 方法的邏輯我們應(yīng)該也可以猜到了,應(yīng)該有一個(gè)歸還的操作,查看代碼發(fā)現(xiàn)果然如此。

//?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();
????}
}
//?繼續(xù)追蹤?super.getResource()
//?redis.clients.jedis.util.Pool
public?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 確實(shí)使用了 commons-pool2 工具進(jìn)行對(duì)象池的管理,通過分析 JedisPool 類的繼承關(guān)系圖也可以發(fā)現(xiàn)。

JedisPool 繼承關(guān)系

6. 對(duì)象池總結(jié)

通過這篇文章的介紹,可以發(fā)現(xiàn)池化思想有幾個(gè)明顯的優(yōu)勢(shì)。

  • 1. 可以顯著的提高應(yīng)用程序的性能。
  • 2. 如果一個(gè)對(duì)象創(chuàng)建成本過高,那么使用池化非常有效。
  • 3. 池化提供了一種對(duì)象的管理以及重復(fù)使用的方式,減少內(nèi)存碎片。
  • 4. 可以為對(duì)象的創(chuàng)建數(shù)量提供限制,對(duì)某些對(duì)象不能創(chuàng)建過多的場(chǎng)景提供保護(hù)。

但是使用對(duì)象池化也有一些需要注意的地方,比如歸還對(duì)象時(shí)應(yīng)確保對(duì)象已經(jīng)被重置為可以重復(fù)使用的狀態(tài)。同時(shí)也要注意,使用池化時(shí)要根據(jù)具體的場(chǎng)景合理的設(shè)置池子的大小,過小達(dá)不到想要的效果,過大會(huì)造成內(nèi)存浪費(fèi)。

以上就是一文搞懂Java中對(duì)象池的實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于Java對(duì)象池的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java中的異步回調(diào)問題

    Java中的異步回調(diào)問題

    這篇文章主要介紹了Java中的異步回調(diào)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • JAVA動(dòng)態(tài)維度笛卡爾積輸出的實(shí)現(xiàn)

    JAVA動(dòng)態(tài)維度笛卡爾積輸出的實(shí)現(xiàn)

    本文主要介紹了JAVA動(dòng)態(tài)維度笛卡爾積輸出的實(shí)現(xiàn),通過動(dòng)態(tài)生成笛卡爾積,可以方便地處理多維數(shù)據(jù)集,提高數(shù)據(jù)處理效率,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-02-02
  • java可以作為第一門編程語(yǔ)言學(xué)習(xí)嗎

    java可以作為第一門編程語(yǔ)言學(xué)習(xí)嗎

    在本篇內(nèi)容里小編給JAVA零基礎(chǔ)的網(wǎng)友分享一篇關(guān)于java可以作為第一門編程語(yǔ)言學(xué)習(xí)嗎的文章,有興趣的朋友們可以參考下。
    2020-11-11
  • 五個(gè)很實(shí)用的IDEA使用技巧分享

    五個(gè)很實(shí)用的IDEA使用技巧分享

    IntelliJ IDEA 是一款優(yōu)秀的 Java 集成開發(fā)環(huán)境,它提供了許多強(qiáng)大的功能和快捷鍵,可以幫助開發(fā)者提高編碼效率和質(zhì)量,本文就在為你介紹博主常用的五個(gè)IntelliJ IDEA使用技巧,希望能夠給你帶來一些工作效率上的提升
    2023-10-10
  • Java內(nèi)部類詳解

    Java內(nèi)部類詳解

    內(nèi)部類在 Java 里面算是非常常見的一個(gè)功能了,在日常開發(fā)中我們肯定多多少少都用過,這里總結(jié)一下關(guān)于 Java 中內(nèi)部類的相關(guān)知識(shí)點(diǎn)和一些使用內(nèi)部類時(shí)需要注意的點(diǎn)。
    2020-02-02
  • java頁(yè)面中文亂碼的解決辦法

    java頁(yè)面中文亂碼的解決辦法

    做java開發(fā)的朋友碰到最多的就是中文亂碼這個(gè)問題了,下面介紹頁(yè)面提交時(shí)與url中文亂碼的一些解決辦法
    2013-11-11
  • Eclipse添加servlet模板過程代碼詳解

    Eclipse添加servlet模板過程代碼詳解

    這篇文章主要介紹了Eclipse添加servlet模板過程代碼詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • 淺談web項(xiàng)目讀取classpath路徑下面的文件

    淺談web項(xiàng)目讀取classpath路徑下面的文件

    這篇文章主要介紹了淺談web項(xiàng)目讀取classpath路徑下面的文件,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • 詳解Java的Spring框架中的事務(wù)管理方式

    詳解Java的Spring框架中的事務(wù)管理方式

    這篇文章主要介紹了Java的Spring框架中的事務(wù)管理方式,Spring框架是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下
    2015-12-12
  • SpringBoot里使用Servlet進(jìn)行請(qǐng)求的實(shí)現(xiàn)示例

    SpringBoot里使用Servlet進(jìn)行請(qǐng)求的實(shí)現(xiàn)示例

    這篇文章主要介紹了SpringBoot里使用Servlet進(jìn)行請(qǐng)求的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01

最新評(píng)論