每篇一句
理解一門技術的原理,最好最紮實的方式就是本身嘗試去實現一遍java
一、概述
本篇博文很簡單啊,主要說說我們平時最長看見的null、void和Void等。通常人可能不會留意,但此文經過一些簡單的例子,但願能夠加深同窗們對他哥幾個的瞭解redis
二、栗子
關於null,估計不少人可能恨透它了,由於它是NullPointerException的罪魁禍首。可是用好了它,咱們仍是能成爲好朋友滴。null是全部引用類型的默認值,可是我要澄清一些誤解,null既不是對象也不是一種類型,它僅是一種特殊的值,你能夠將其賦予任何引用類型,你也能夠將null轉化成任何類型(這個估計不少人沒有用過)算法
public final class Main {
public static void main(String[] args) {
Main m = (Main) null; //這樣子是不報錯的 其實編譯器底層會對null這樣作處理
System.out.println(m); //輸出null
m.doSomething(); //居然輸出了doSomething 意不意外
}分佈式
private static void doSomething() {
System.out.println("doSomething");
}
}
1
2
3
4
5
6
7
8
9
10
11
對上述結果進行分析:第一個對null的強轉,實際上是java編譯器底層的實現,看.class文件能夠看出來結果。第二個,咱們想到m的值確定爲null啊,爲何調用doSomething沒有空指針呢?但下面代碼就空指針了:函數
public final class Main {
public static void main(String[] args) {
Main m = (Main) null; //這樣子是不報錯的 其實編譯器底層會對null這樣作處理
System.out.println(m); //輸出null
m.doSomething(); //java.lang.NullPointerException
}.net
private void doSomething() {
System.out.println("doSomething");
}
}
1
2
3
4
5
6
7
8
9
10
11
各位同窗從這兩個例子的對比,應該也能看出來了吧。因此對靜態方法調用這裏奉送兩句話,記住就行:設計
所引用對象是否爲null可有可無,由於訪問靜態方法不須要實例對象。
若是引用不爲null,運行時對象類型也可有可無,由於靜態調用不會致使動態調用分派。而是與類相關。
所以,靜態方法的訪問,不建議用實例調用,反而讓語意變得晦澀了。最後提一點,在java中的自動拆裝箱的過程當中,若是遇到null值,處理的時候須要小心:指針
任何含有null值的包裝類在Java拆箱生成基本數據類型時候都會拋出一個空指針異常對象
在看下面例子,判斷null值的類型blog
public final class Main {
public static void main(String[] args) {
Main m = (Main) null;
System.out.println(m instanceof Main); //返回false哦 返回false哦 返回false哦
System.out.println(m.getClass()); //空指針
}
}
1
2
3
4
5
6
7
咱們會發現:若是使用了帶有null值的引用類型變量,instanceof操做將會返回false。
咱們可使用或者!=操做來比較null值,可是不能使用其餘算法或者邏輯操做,例如小於或者大於。在Java中**nullnull將返回true**。
接下來聊聊void和Void。可能不少人咋一看挺懵逼的,好像沒啥區別啊。
void不是函數,是方法的修飾符,void的意思是該方法沒有返回值,意思就是方法只會運行方法中的語句,可是不返回任何東西。 java.lang.Void是一種類型。例如給Void引用賦值null。經過Void類的源代碼能夠看到,Void類型不能夠繼承與實例化。
public final class Main {
public void do1() {
return; //返回void,return可寫可不寫
}
public Void do2() {
return null; //此處必須返回null 返回其他類型都很差使
}
}
1
2
3
4
5
6
7
8
9
10
public final class Main {
public static void main(String[] args) {
System.out.println(Void.class); //class java.lang.Void
System.out.println(void.class); //void
//相似於下面的
System.out.println(Integer.class); //class java.lang.Integer
System.out.println(int.class); //int
}
}
1
2
3
4
5
6
7
8
9
10
如上,能夠清晰的看到void和Void的一些區別,但有些人可能會問,Void咱們到底有什麼用呢?其實在泛型出現以前,Void通常用於反射之中。例如,下面的代碼打印**返回類型爲void(這裏必須藉助Void類)**的方法名:
public class Test {
public void print(String v) {}
public static void main(String args[]){
for(Method method : Test.class.getMethods()) {
//判斷返回值類型 用到了Void類
if(method.getReturnType().equals(Void.TYPE)) {
System.out.println(method.getName());
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
還有有的時候,並不須要返回值的抽像性設計,好比我設計的分佈式鎖:RedisLock
public static <T> T doInLock(Supplier<T> supplier, RedisTemplate<String, String> redisTemplate, String lockKey) {
//這裏咱們使用函數式變成supplier來提供回調函數而且接收返回值
return supplier.get();
}
1
2
3
4
如上,若是使用者實現supplier方法並不須要返回值怎麼辦呢?這個時候最優雅的處理方式以下:
LockUtil.doInLock(() -> {
..... //處理一系列業務邏輯
return Void.class; //返回這個就很是的優雅了,閱讀起來也十分明白
}, stringRedisTemplate,"aaa");
1
2
3
4
另外,再介紹兩種狀況下Void的使用,雖然使用較少,但技多不壓身嘛。
泛型出現後,某些場景下會用到Void類型。例如Future用來保存結果,但若是操做並無返回值呢?這種狀況下就能夠用Future表示。當調用get後結果計算完畢則返回後將會返回null。(原理同上示例)
另外Void也用於無值的Map中(只須要key不須要值),例如Map<,Void>這樣map將具Set有同樣的功能。
所以當你使用泛型時函數並不須要返回結果或某個對象不須要值時候這是可使用java.lang.Void類型表示。
Void類可能自己做用就只是不起任何做用,可是自己只是一個佔位符類。即Void類自己只是一個佔位符類,不能被實例化,多用於泛型中做佔位符使用。
三、使用場景
驚不驚喜,意不意外,沒想到平時絕不起眼的一個Void,居然仍是有這麼多使用場景的。這裏附上Void.class源碼裏的一句代碼,就更加能輔助小夥伴們理解了
public static final Class<Void> TYPE = (Class<Void>) Class.getPrimitiveClass("void"); 1 四、最後 本文的內容可能平時使用不多,但我建議,這個能夠看成裝逼神器,哈哈。so,這技能你get到了嗎? --------------------- 做者:_YourBatman 來源:CSDN 原文:https://blog.csdn.net/f641385712/article/details/80409211 版權聲明:本文爲博主原創文章,轉載請附上博文連接!