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

Java的Object類九個(gè)方法技巧

 更新時(shí)間:2022年04月13日 17:40:25   作者:???????東風(fēng)玖哥  
這篇文章主要介紹了Java的Object類九個(gè)方法技巧,Java的Object?類的完整路徑是java.lang.Object?,是所有類的父類編譯,下文相關(guān)資料,需要的朋友可以參考一下

前言:

Java的Object 類的完整路徑是java.lang.Object ,是所有類的父類編譯,當(dāng)我們創(chuàng)建一個(gè)類時(shí),如果沒有明確繼承一個(gè)父類,那么它就會(huì)自動(dòng)繼承 Object,成為 Object 的子類(隱式繼承)。Object類有九大常用方法,分別是getClass()、finalize()、toString()、equals()、hashcode()、wait()、notify()、notifyAll()和clone()。

一、getClass()

首先,getClass()方法用于獲取一個(gè)對(duì)象的運(yùn)行時(shí)類(Class),進(jìn)而通過返回的Class對(duì)象獲取Person的相關(guān)信息,比如獲取該類的構(gòu)造方法、該類有哪些方法、該類有哪些成員變量等信息。不同VM針對(duì)Class做了不同的優(yōu)化,所以getClass()的實(shí)現(xiàn)也并不相同:

// Java用native方法實(shí)現(xiàn)getClass()
public final native Class<?> getClass();
// Android特殊的實(shí)現(xiàn)方式
private transient Class<?> shadow$_klass_;
public final Class<?> getClass() {
  return shadow$_klass_;
}

這是因?yàn)槭荍ava默認(rèn)的Hotspot虛擬機(jī)并沒有開辟單獨(dú)的Method Area空間,而是有GC Heap的老生代的Metaspace實(shí)現(xiàn)的。而Android采用ART VM,這才造成了這種差異。想深入了解不同VM的實(shí)現(xiàn)的運(yùn)行時(shí)數(shù)據(jù)分區(qū)、ClassLoader和Class類要讀很多書,本文不做過多討論。

二、finalize()

finalize()是Object的protected方法,在發(fā)生GC時(shí)觸發(fā)該方法,大致流程是當(dāng)對(duì)象變成GC Roots不可達(dá)時(shí),GC判斷該對(duì)象是否覆蓋了finalize()方法,若未覆蓋,則直接將其回收。否則,若對(duì)象未執(zhí)行過finalize()方法,將其放入F-Queue隊(duì)列,由一低優(yōu)先級(jí)線程執(zhí)行該隊(duì)列中對(duì)象的finalize()方法。執(zhí)行finalize()方法完畢后,GC會(huì)再次判斷該對(duì)象是否可達(dá),若不可達(dá),則進(jìn)行回收;否則,對(duì)象“復(fù)活”。

子類可以override方法以實(shí)現(xiàn)(1)防止對(duì)象被回收、(2)防止對(duì)象不被回收。防止對(duì)象被回收只需讓該對(duì)象與GC ROOTS之間存在可達(dá)鏈即可。我們重點(diǎn)看看FileInputStream、FileOutputStream、Connection等類怎么防止用戶忘記釋放資源呢,如下是FileInputStream的部分源碼:

protected void finalize() throws IOException {
    // Android新增CloseGuard確保FlieInputStream回收更安全
    if (guard != null) {
        guard.warnIfOpen();
    }
// Java利用FileDescriptor確保FileInputStream不可達(dá),可以被安全回收
    if ((fd != null) &&  (fd != FileDescriptor.in)) {
        close();
    }
}

三、toString()

toString()方法返回該對(duì)象的String表示,這也是連每個(gè)初級(jí)程序員都很熟悉的一個(gè)方法了。你仔細(xì)讀過Java的源碼,就知道很多類的toString()方法都是精雕細(xì)琢的,就像Integer的toString()方法,就針對(duì)Android做了一定適配:

public String toString() {
    return toString(this.value);
}
//返回指定十進(jìn)制整數(shù)的String
public static String toString(int i) {
    if (i == Integer.MIN_VALUE)
        return "-2147483648";

    // small是Android特有的變量,用二維Array緩存較?。▋晌粩?shù))數(shù)字的String
    boolean negative = i < 0;
    boolean small = negative ? i > -100 : i < 100;
    if (small) {
        final String[] smallValues = negative ? SMALL_NEG_VALUES : SMALL_NONNEG_VALUES;

        if (negative) {
            i = -i;
            if (smallValues[i] == null) {
                smallValues[i] =
                    i < 10 ? new String(new char[]{'-', DigitOnes[i]})
                           : new String(new char[]{'-', DigitTens[i], DigitOnes[i]});
            }
        } else {
            if (smallValues[i] == null) {
                smallValues[i] =
                    i < 10 ? new String(new char[]{DigitOnes[i]})
                           : new String(new char[]{DigitTens[i], DigitOnes[i]});
            }
        }
        return smallValues[i];
    }
    int size = negative ? stringSize(-i) + 1 : stringSize(i);
    // getChars()方法略
    char[] buf = new char[size];
    getChars(i, size, buf);
    return new String(buf);
}

在實(shí)際開發(fā)中,復(fù)雜對(duì)象的toString()方法用Gson生成JSON來實(shí)現(xiàn)。

四、equals()和hashcode()

equals()方法和hashcode()方法,我要放在一起說。

// 其實(shí)Object方法默認(rèn)的equals()也是比較引用是否相同
public boolean equals(Object obj) {
    return (this == obj);
}

一般來說==比較的是引用是否相同,而equals()則是需要重寫來比較值是否相同。重寫equals()要注意以下幾點(diǎn)注意事項(xiàng):

(1)對(duì)任意x,x.equals(x)一定返回true

(2)對(duì)任意x,y,如果x.equals(y)返回true,則y.equals(x)也一定返回true

(3)對(duì)任意x,y,z,如果x.equals(y)返回true,y.equals(z)也返回true,則x.equals(z)也一定返回true

(4)對(duì)任意x,y,如果對(duì)象中用于比較的信息沒有改變,那么無論調(diào)用多少次x.equals(y),返回的結(jié)果應(yīng)該保持一致,要么一直返回true,要么一直返回false

(5)對(duì)任意不是null的x,x.equals(null)一定返回false,如果兩個(gè)對(duì)象equals()方法相等則它們的hashCode返回值一定要相同。我們先看一下String是如何實(shí)現(xiàn)equals()的:

//比較這個(gè)String和另一個(gè)對(duì)象,當(dāng)且僅當(dāng)那個(gè)對(duì)象不為null且與這個(gè)String有相同的字符排列順序時(shí)返回true
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = length();
        if (n == anotherString.length()) {
            int i = 0;
            while (n-- != 0) {
                if (charAt(i) != anotherString.charAt(i))
                        return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

我們?cè)倏匆幌耂tring是如何實(shí)現(xiàn)hashcode()的:

// 緩存String的hashcode()
private int hash; // 默認(rèn)為0
public int hashCode() {
    int h = hash;
    final int len = length();
    if (h == 0 && len > 0) {
        for (int i = 0; i < len; i++) {
            h = 31 * h + charAt(i);
        }
        hash = h;
    }
    return h;
}

反之,如果兩個(gè)對(duì)象的hashCode返回值相同,它們的equals()方法可以不返回true。這種情況叫做hash碰撞。HashMap處理hash碰撞的方法叫鏈地址法,除此以外hash碰撞還可以用ArrayMap采用的開放地址法解決,這些不在今天的話題討論范圍之內(nèi),不做贅述。

五、wait()、notify()和notifyAll()

wait()、notify()和notifyAll()三個(gè)方法實(shí)現(xiàn)了Java的wait-notify機(jī)制。

先看wait()方法,wait()方法用來讓持有此對(duì)象的監(jiān)視器的線程處于阻塞狀態(tài),有參數(shù)不同的三個(gè)同名方法:

// 無參方法的Java與Android實(shí)現(xiàn)方式?jīng)]有區(qū)別
// 如果不在synchronized修飾的方法或代碼塊里調(diào)用,如果沒有獲取鎖,則會(huì)拋出IllegalMonitorStateException 異常
// 如果當(dāng)前線程在等待時(shí)被中斷,則拋出InterruptedException異常
public final void wait() throws InterruptedException {
    wait(0);
}
// timeout是線程等待時(shí)間,時(shí)間結(jié)束則自動(dòng)喚醒,單位ms
// Java默認(rèn)的實(shí)現(xiàn)方式,native實(shí)現(xiàn)
public final native void wait(long timeout) throws InterruptedException;
// Android的特殊處理
public final void wait(long timeout) throws InterruptedException {
    wait(timeout, 0);
}
// nanos是更精確的線程等待時(shí)間,單位ns(1 ms == 1,000,000 ns)
// Java默認(rèn)的實(shí)現(xiàn)方式
public final void wait(long timeout, int nanos) throws InterruptedException {
    if (timeout < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }
    if (nanos < 0 || nanos > 999999) {
        throw new IllegalArgumentException(
                "nanosecond timeout value out of range");
    }
    if (nanos > 0) {
        timeout++;
    }
    wait(timeout);
}
// Android的特殊處理,改為native實(shí)現(xiàn)
@FastNative
public final native void wait(long timeout, int nanos) throws InterruptedException;

ns是納秒的意思,1s == 1,000,000,000ns,光速是世界上最快的速度,光在1ns時(shí)間內(nèi)僅能傳播0.3m。一般PC的CPU計(jì)算一道簡單指令,比如2+3=5的時(shí)間為2~4ns。我們一般只用一個(gè)參數(shù)的wait()方法或者無參方法就足夠了,第二個(gè)參數(shù)在現(xiàn)實(shí)開發(fā)中幾乎用不到。

含參的wait()方法調(diào)用后,線程可以在等待時(shí)間結(jié)束后進(jìn)入就緒狀態(tài)(以下簡稱“喚醒”);無參的wait()方法調(diào)用后,則必須等待持有該對(duì)象監(jiān)視器的線程主動(dòng)調(diào)用notify()或notifyAll()方法后才能被喚醒。區(qū)別在于notify()方法喚醒在此對(duì)象監(jiān)視器上等待的單個(gè)線程,如果所有線程都在此對(duì)象上等待,則會(huì)隨機(jī)喚醒其中一個(gè)線程;而notifyAll()方法則喚醒在此對(duì)象監(jiān)視器上等待的所有線程。

public final native void notify();
public final native void notifyAll();

wait()、notify()和notifyAll()都是final native方法,我們暫時(shí)不需要深入理解內(nèi)部是怎樣實(shí)現(xiàn)的,我們只要知道這就是Java的等待-通知(wait-notify)機(jī)制,學(xué)習(xí)它們的應(yīng)用場景就好了。

打個(gè)比方:

  • (1)用人單位決定錄用程序員的時(shí)間是不確定的,比如可能要面試好多人,需要綜合考慮,不能及時(shí)反饋
  • (2)每個(gè)程序員面試結(jié)束后需要wait()
  • (3)用人單位綜合考慮之后覺得最合適的程序員,讓HR notify()
  • (4)最后被選中程序員高高興興去上班了,其他程序員就等著吧

在開發(fā)中,wait-notify機(jī)制的最廣泛用途就是實(shí)現(xiàn)生產(chǎn)者/消費(fèi)者模型,生產(chǎn)者/消費(fèi)者模型能解決絕大多數(shù)并發(fā)問題,通過平衡生產(chǎn)線程和消費(fèi)線程的工作能力來提高程序的整體處理數(shù)據(jù)的速度。

使用wait-notify機(jī)制的注意事項(xiàng):

  • (1)wait()、notify()和notifyAll()必須在synchronized修飾的方法或代碼塊中使用
  • (2)在while循環(huán)里而不是if語句下使用wait(),確保在線程睡眠前后都檢查wait()觸發(fā)的條件(防止虛假喚醒)
  • (3)wait()方法必須在多線程共享的對(duì)象上調(diào)用

我們先定義注意(1)和(2)的一個(gè)生產(chǎn)者,往隊(duì)列里添加元素:

// 生產(chǎn)者,有詳細(xì)的注釋
public class Producer implements Runnable{
    private Queue<Integer> queue;
    private int maxSize;
    public Producer(Queue<Integer> queue, int maxSize){
        this.queue = queue;
        this.maxSize = maxSize;
    }
    @Override
    public void run() {
        // 這里為了方便演示做了一個(gè)死循環(huán),現(xiàn)實(shí)開發(fā)中不要這樣搞
        while (true){
            //(1)wait()、notify()和notifyAll()必須在synchronized修飾的方法或代碼塊中使用
            synchronized (queue){
//(2)在while循環(huán)里而不是if語句下使用wait(),確保在線程睡眠前后都檢查wait()觸發(fā)的條件(防止虛假喚醒)
                while (queue.size() == maxSize){
                    try{
                        System.out.println("Queue is Full");
// 生產(chǎn)者線程進(jìn)入等待狀態(tài),在此對(duì)象監(jiān)視器上等待的所有線程(其實(shí)只有那個(gè)消費(fèi)者線程)開始爭奪鎖
                        queue.wait();
                    }catch (InterruptedException ie){
                        ie.printStackTrace();
                    }
                }
                Random random = new Random();
                int i = random.nextInt();
                System.out.println("Produce " + i);
                queue.add(i);
// 喚醒這個(gè)Queue對(duì)象的等待池中的所有線程(其實(shí)只有那個(gè)消費(fèi)者線程),等待獲取對(duì)象監(jiān)視器
                queue.notifyAll();
            }
        }
    }
}

再定義一個(gè)一模一樣的消費(fèi)者,除了從隊(duì)列里移除元素之外,其他代碼同上

// 消費(fèi)者,注釋略
public class Consumer implements Runnable{
    private Queue<Integer> queue;
    private int maxSize;
    public Consumer(Queue<Integer> queue, int maxSize){
        this.queue = queue;
        this.maxSize = maxSize;
    }

    @Override
    public void run() {
        while (true){
            synchronized (queue){
                while (queue.isEmpty()){
                    System.out.println("Queue is Empty");
                    try{
                        queue.wait();
                    }catch (InterruptedException ie){
                        ie.printStackTrace();
                    }
                }
                int v = queue.remove();
                System.out.println("Consume " + v);
                queue.notifyAll();
            }
        }
    }
}

最后編寫符合(3)的測試代碼:

public void test(){
    //(3)wait()方法必須在多線程共享的對(duì)象上調(diào)用
    // 這個(gè)隊(duì)列就是給消費(fèi)者、生產(chǎn)者兩個(gè)線程共享的對(duì)象
    Queue<Integer> queue = new LinkedList<>();
    int maxSize = 5;
    Producer p = new Producer(queue, maxSize);
    Consumer c = new Consumer(queue, maxSize);
    Thread pT = new Thread(p);
    Thread pC = new Thread(c);
// 生產(chǎn)者線程啟動(dòng),獲取鎖
    pT.start();
// 消費(fèi)者線程啟動(dòng)
    pC.start();
}

查看運(yùn)行結(jié)果:

Produce 1604006010

Produce 1312202442

Produce -1478853208

Produce 1460408111

Produce 1802825495

Queue is Full

Consume 1604006010

Consume 1312202442

Consume -1478853208

Consume 1460408111

Consume 1802825495

Queue is Empty

除了以上介紹的用synchronized關(guān)鍵字配合Object的wait()/notity()實(shí)現(xiàn),生產(chǎn)者-消費(fèi)者模型還可以用Lock接口配合Condition的await()、signalAll()實(shí)現(xiàn),此外還可以用BlockingQueue實(shí)現(xiàn),但這些都不在本文的話題討論范圍之內(nèi),就不再贅述了。

六、clone()

Java語言的Object類實(shí)現(xiàn)了Cloneable接口,一個(gè)對(duì)象可以通過調(diào)用Clone()方法生成對(duì)象。需要注意的是,clone()方法并不是Cloneable接口里的,而是Object類里的,Cloneable是一個(gè)標(biāo)識(shí)接口,標(biāo)識(shí)這個(gè)類的對(duì)象是可被拷貝的,如果沒有實(shí)現(xiàn)Cloneable接口卻調(diào)用了clone()方法就會(huì)報(bào)錯(cuò)。

// protected native Object clone() throws CloneNotSupportedException;
protected Object clone() throws CloneNotSupportedException {
    if (!(this instanceof Cloneable)) {
        throw new CloneNotSupportedException("Class " + getClass().getName() + " doesn't implement Cloneable");
    }
    return internalClone();
}
// Native helper method for cloning.
private native Object internalClone();

對(duì)象除了new出來和clone()出來,還可以通過反射和反序列化兩種方式產(chǎn)生,但這兩種方式不在我們今天的話題討論范圍之內(nèi)。

所謂原型模式,就是利用clone()生成對(duì)象的設(shè)計(jì)模式。需要提前了解一下深拷貝和淺拷貝的概念。Java中的數(shù)據(jù)類型分為基本類型和引用類型,在一個(gè)方法里的變量如果是基本類型的話,變量就直接存儲(chǔ)在這個(gè)方法的棧幀里,例如int、long等;而引用類型則在棧幀里存儲(chǔ)這個(gè)變量的指針,指向堆中該實(shí)體的地址,例如String、Array等。深拷貝和淺拷貝是只針對(duì)引用數(shù)據(jù)類型的

比如一個(gè)方法有一個(gè)基本類型參數(shù)和一個(gè)引用類型參數(shù),在方法體里對(duì)參數(shù)重新賦值,會(huì)影響傳入的引用類型參數(shù),而不會(huì)影響基本類型參數(shù),因?yàn)榛绢愋蛥?shù)是值傳遞,而引用類型是引用傳遞。需要注意的是,較真來說Java只有值傳遞,因?yàn)镴ava的引用傳遞傳的是引用類型對(duì)象在堆內(nèi)存空間的地址,引用傳遞只是一種習(xí)慣性的說法,這個(gè)涉及到JVM和操作系統(tǒng),不做過多討論。

先定義一個(gè)用戶類:

// 這是一個(gè)非常簡單的用戶類
public class User {
    private String name;
    private int age;
    public User(String name, int age) {
        this.name=name;
        this.age=age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "User{name='" + name + ", age=" + age +'}';
    }
}

編寫測試代碼:

private int x=10;
public void updateValue(int value){
    value = 3 * value;
}
private User user= new User("唐茜靖",18);
public void updateUser(User student){
    student.setName("管晨辰");
    student.setAge(16);
}

public void test(){
    System.out.println("調(diào)用前x的值:"+x);
    updateValue(x);
    System.out.println("調(diào)用后x的值:"+x);
    System.out.println("調(diào)用前user的值:"+user.toString());
    updateUser(user);
    System.out.println("調(diào)用后user的值:"+user.toString());
}

Log打印結(jié)果如下:

調(diào)用前x的值:10

調(diào)用后x的值:10

調(diào)用前user的值:User{name='唐茜靖, age=18}

調(diào)用后user的值:User{name='管晨辰, age=16}

傳遞基本類型的方法(updateValue())流程圖:

Java的Object類九大方法_設(shè)計(jì)模式

傳遞引用類型的方法(updateUser())流程圖:

Java的Object類九大方法_Jav啊_02

但也有例外,比如String類型和<=127的Long類型雖然也是引用類型,卻像基本類型一樣不受影響,這是因?yàn)樗鼈儠?huì)先比較常量池維護(hù)的值,這涉及VM的內(nèi)容,今天不做過多討論。淺拷貝是在按位(bit)拷貝對(duì)象,這個(gè)對(duì)象有著原始對(duì)象屬性值的一份精確拷貝。我們結(jié)合應(yīng)用場景分析一下,還是剛才的User類,我們?cè)黾右粋€(gè)存放地址的內(nèi)部類Address,我們需要用戶信息可以被其他module查詢,但是不允許它們被其他module修改,新增代碼如下:

// 這是一個(gè)稍微復(fù)雜的、支持拷貝的用戶類
public class User implements Cloneable {
// ……省略上文代碼……
    private Address address;

    @NonNull
    @NotNull
    @Override
    public User clone() {
        try{
            return (User)super.clone();
        }catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    public class Address{
        // 地市
        public String city;
        // 區(qū)縣
        public String county;
        // 鄉(xiāng)鎮(zhèn)街道
        public String street;
    } 
}

我們可以注意到Address還是指向以前的引用,淺拷貝會(huì)帶來數(shù)據(jù)安全方面的隱患,這就到了需要深拷貝的時(shí)候了。對(duì)于有多層對(duì)象的,每個(gè)對(duì)象都需要實(shí)現(xiàn) Cloneable 并重寫 clone() 方法,才可以實(shí)現(xiàn)了對(duì)象的串行層層拷貝。就像這樣:

// 這是一個(gè)更復(fù)雜的、支持深拷貝的用戶類
public class User implements Cloneable {
    // ……省略上文代碼……
    @NonNull
    @NotNull
    @Override
    public User clone() {
        try{
            User newUser = (User)super.clone();
            newUser.setName(this.name);
            newUser.setAddress(this.address.clone());
            return newUser;
        }catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }

    public class Address implements Cloneable{
        // ……省略上文代碼……
        @NonNull
        @NotNull
        @Override
        public Address clone() {
            try{
                Address newAddress = (Address)super.clone();
                newAddress.city = this.city;
                newAddress.county = this.county;
                newAddress.street = this.street;
                return newAddress;
            }catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
}

至于徹底深拷貝幾乎是不可能實(shí)現(xiàn)的,不但可能存在引用關(guān)系非常復(fù)雜的情況,也可能存在引用鏈的某一級(jí)上引用了一個(gè)沒有實(shí)現(xiàn)Cloneable接口的第三方對(duì)象的情況。

最后總結(jié)一下,原型模式的用途之一是保護(hù)性拷貝,防止外部對(duì)只讀對(duì)象進(jìn)行修改,剛才我舉的例子就是保護(hù)性拷貝。另一個(gè)重要用途則是解決構(gòu)建復(fù)雜對(duì)象的資源消耗問題,提升創(chuàng)建對(duì)象的效率,這是因?yàn)閏lone()方法的原理是在內(nèi)存中拷貝二進(jìn)制流,比new一個(gè)對(duì)象的性能好很多,非常適用于需要在循環(huán)體內(nèi)產(chǎn)生大量對(duì)象的時(shí)候。絕大多數(shù)設(shè)計(jì)模式都是犧牲性能提升開發(fā)效率的,原型模式是為數(shù)不多的犧牲開發(fā)效率提升性能的。

我們做一下new和clone的對(duì)比:

private User user= new User("唐茜靖",18);
public void testNew(){
    User user1 = new User("管晨辰",16);
}
public void testClone(){
    User user2 = user.clone();
}

通過ASM工具查看bytecode,可以對(duì)比出二者對(duì)棧資源的消耗:

// access flags 0x1

??public testNew()V

???……省略……

????MAXSTACK = 4

????MAXLOCALS = 2



??// access flags 0x1

??public testClone()V

???……省略……

????MAXSTACK = 1

????MAXLOCALS = 2

此外還需要注意一點(diǎn),拷貝不會(huì)執(zhí)行構(gòu)造函數(shù),所以有時(shí)候我們需要注意這個(gè)潛在的問題。幸好這個(gè)問題不是不可避免的,這是Android第五大組件Intent的clone()的實(shí)現(xiàn),沒有用拷貝:

@Override
public Object clone() {
    return new Intent(this);
}

到此這篇關(guān)于Java的Object類九個(gè)方法技巧的文章就介紹到這了,更多相關(guān)Java的Object類方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中文件創(chuàng)建于寫入內(nèi)容的常見方法

    Java中文件創(chuàng)建于寫入內(nèi)容的常見方法

    在日常開發(fā)中,肯定離不開要和文件打交道,今天就簡單羅列一下平時(shí)比較常用的創(chuàng)建文件并向文件中寫入數(shù)據(jù)的幾種方式,希望對(duì)大家有一定的幫助
    2023-10-10
  • 淺談java String不可變的好處

    淺談java String不可變的好處

    這篇文章主要介紹了java String不可變的好處,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • SpringBoot多模塊打包部署Docker的項(xiàng)目實(shí)戰(zhàn)

    SpringBoot多模塊打包部署Docker的項(xiàng)目實(shí)戰(zhàn)

    本文通過介紹最常見的Maven管理的Spring Boot項(xiàng)目多模塊打包部署Docker來介紹一下項(xiàng)目部署過程中操作流程和幾個(gè)需要注意的點(diǎn),具有一定的參加價(jià)值,感興趣的可以了解一下
    2023-08-08
  • 一文搞懂Spring?Security異常處理機(jī)制

    一文搞懂Spring?Security異常處理機(jī)制

    這篇文章主要為大家詳細(xì)介紹一下Spring?Security異常處理機(jī)制,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Spring?Security有一定幫助,感興趣的可以學(xué)習(xí)一下
    2022-07-07
  • Spring Boot 會(huì)員管理系統(tǒng)之處理文件上傳功能

    Spring Boot 會(huì)員管理系統(tǒng)之處理文件上傳功能

    Spring Boot會(huì)員管理系統(tǒng)的中,需要涉及到Spring框架,SpringMVC框架,Hibernate框架,thymeleaf模板引擎。這篇文章主要介紹了Spring Boot會(huì)員管理系統(tǒng)之處理文件上傳功能,需要的朋友可以參考下
    2018-03-03
  • 如何解決freemarker靜態(tài)化生成html頁面亂碼的問題

    如何解決freemarker靜態(tài)化生成html頁面亂碼的問題

    這篇文章主要介紹了如何解決freemarker靜態(tài)化生成html頁面亂碼的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • SpringBoot內(nèi)置tomcat參數(shù)調(diào)優(yōu)的實(shí)現(xiàn)

    SpringBoot內(nèi)置tomcat參數(shù)調(diào)優(yōu)的實(shí)現(xiàn)

    springboot內(nèi)置了tomcat, 并給我們?cè)O(shè)置了默認(rèn)參數(shù), 我們?cè)趺礃有薷膕pringboot內(nèi)置的tomcat參數(shù),本文就詳細(xì)的來介紹一下,感興趣的可以了解一下
    2023-09-09
  • RSA加密的方式和解密方式實(shí)現(xiàn)方法(推薦)

    RSA加密的方式和解密方式實(shí)現(xiàn)方法(推薦)

    下面小編就為大家?guī)硪黄猂SA加密的方式和解密方式實(shí)現(xiàn)方法(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • 關(guān)于idea剛打開時(shí)瘋狂報(bào)錯(cuò)的問題

    關(guān)于idea剛打開時(shí)瘋狂報(bào)錯(cuò)的問題

    這篇文章主要介紹了關(guān)于idea剛打開時(shí)瘋狂報(bào)錯(cuò)的問題,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • @Valid 無法校驗(yàn)List<E>的問題

    @Valid 無法校驗(yàn)List<E>的問題

    這篇文章主要介紹了@Valid 無法校驗(yàn)List<E>的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10

最新評(píng)論