1. 程式人生 > >位運算的應用

位運算的應用

平常都很少用到位運算,這裡介紹一種`jdk`使用位運算的小案例。它是用位運算來優化一個類所佔的大小。下面介紹: - 什麼情況下,符合這種優化條件; - 用具體的例子來介紹; #### 優化情況 假設一個類需要有很多`boolean`型別得屬性,如果直接用`boolean`型別,那麼這個類會在記憶體中佔用很大空間。通常情況下,一個`boolean`型別屬性會佔4個位元組。[但這不是一定得,JAVA得boolean屬性佔用位元組不一定](https://www.cnblogs.com/wangtianze/p/6690665.html?utm_source=itdadao&utm_medium=referral)。這時候,使用多個`boolean`型別的屬性就佔用很多記憶體。 在這種情況下,可以使用位元組得0、1來代表true、false。使用位運算來獲取、設定boolean屬性得值。比如說:我們可以使用`int`來儲存32個boolean屬性,這樣就會節省大量的記憶體。 > `JDK`中有具體得例子,如`java.lang.reflect.Modifier` #### 具體例子 假設一個貓有三個屬性:`cute`、`fat`、`white`,其取值只有倆種true、false。現在用int的後面三個位來儲存這三個型別的值。 即:在`int`最後一個位作為`cute`屬性得值;倒數第二位作為`fat`屬性得值;倒數第三位作為`white`屬性得值。 1、建立`int`屬性得值,作為儲存這三個屬性得屬性值 ```java public class Cat { // 儲存三個boolean屬性得值 private int properties = 0; } ``` ![](https://img2020.cnblogs.com/blog/1227210/202009/1227210-20200920021225424-1522172882.png) 2、設定三個`int`屬性作為三個屬性都為true;這是為了後期方便設定值 ```java public class Cat { private static int CUTE = 0x1; private static int FAT = 0x2; private static int WHITE = 0x4; private int properties = 0; } ``` 3、以`cute`屬性的獲取、設定 (1)獲取值的時候 指獲取`properties`屬性的最後一位的值,需要注意的是獲取最後一位值得時候,不能影響其他位得值!!! ```java /** * 這隻貓萌嗎?請在此處使用位運算讀取properties,得到貓是否萌的結果 * * @return 萌則返回true,否則返回false */ public boolean isCute() { return (properties & Cat.CUTE) != 0; } ``` > 使用與運算得時候,其他位不受影響;最後一位也是取決於`properties`最後一位得值 >![](https://img2020.cnblogs.com/blog/1227210/202009/1227210-20200920021308050-130461180.png) (2)設定值的時候 在設定`properties`屬性得最後一位得值,需要注意得是設定最後一位的值的時候,不能影響其他位得值!!! ```java /** * 使用位運算設定貓咪萌的屬性 * * @param cute true為萌,false為不萌 */ public void setCute(boolean cute) { if (cute == true){ properties = properties | Cat.CUTE; } else { properties = properties & (~Cat.CUTE); } } ``` ![](https://img2020.cnblogs.com/blog/1227210/202009/1227210-20200920021329084-929330893.png) 4、設定其他屬性 ```java /** * 使用位運算設定貓咪胖的屬性 * * @param fat true為胖,false為不胖 */ public void setFat(boolean fat) { if (fat){ properties = properties | Cat.FAT; } else { properties = properties & (~Cat.FAT); } } /** * 這隻貓胖嗎?請在此處使用位運算讀取properties,得到貓是否胖的結果 * * @return 胖則返回true,否則返回false */ public boolean isFat() { return (properties & Cat.FAT) != 0; } /** * 使用位運算設定貓咪白的屬性 * * @param white true為白,false為不白 */ public void setWhite(boolean white) { if (white){ properties = properties | Cat.WHITE; } else { properties = properties & (~Cat.WHITE); } } /** * 這隻貓白嗎?請在此處使用位運算讀取properties,得到貓是否白的結果 * * @return 白則返回true,否則返回false */ public boolean isWhite() { return (properties & Cat.WHITE) != 0; } ``` #### 總結 一般情況下,獲取值使用`&`;設定值使用`|`、`~`和`&`。關鍵就是在使用位運算的時候,隻影響指定位置的值,其他位置的值不能改變。完整程式碼如下: ```java public class Cat { private static int CUTE = 0x1; private static int FAT = 0x2; private static int WHITE = 0x4; private int properties = 0; /** * 使用位運算設定貓咪萌的屬性 * * @param cute true為萌,false為不萌 */ public void setCute(boolean cute) { if (cute == true){ properties = properties | Cat.CUTE; } else { properties = properties & (~Cat.CUTE); } } /** * 這隻貓萌嗎?請在此處使用位運算讀取properties,得到貓是否萌的結果 * * @return 萌則返回true,否則返回false */ public boolean isCute() { return (properties & Cat.CUTE) != 0; } /** * 使用位運算設定貓咪胖的屬性 * * @param fat true為胖,false為不胖 */ public void setFat(boolean fat) { if (fat){ properties = properties | Cat.FAT; } else { properties = properties & (~Cat.FAT); } } /** * 這隻貓胖嗎?請在此處使用位運算讀取properties,得到貓是否胖的結果 * * @return 胖則返回true,否則返回false */ public boolean isFat() { return (properties & Cat.FAT) != 0; } /** * 使用位運算設定貓咪白的屬性 * * @param white true為白,false為不白 */ public void setWhite(boolean white) { if (white){ properties = properties | Cat.WHITE; } else { properties = properties & (~Cat.WHITE); } } /** * 這隻貓白嗎?請在此處使用位運算讀取properties,得到貓是否白的結果 * * @return 白則返回true,否則返回false */ public boolean isWhite() { return (properties & Cat.WHITE) != 0; } public static void main(String[] args) { Cat cat = new Cat(); cat.setCute(true); cat.setFat(true); cat.setWhite(false); System.out.println("這隻貓萌嗎:" + cat.isCute()); System.out.println("這隻貓胖嗎:" + cat.isFat()); System.out.println("這隻貓白嗎:" + cat.isWhite()); } } ``` --- ## 位運算的一些坑 交換倆個值得功能可以用位運算這種騷操作完成。比如: ```java public static void main(String[] args) { Main main = new Main(); int[] arr = {1,2}; main.test(0,1,arr); } public void test(int a, int b, int[] arr){ arr[a] = arr[a] ^ arr[b]; arr[b] = arr[a] ^ arr[b]; arr[a] = arr[a] ^ arr[b]; System.out.println(Arrays.toString(arr));//[2,1] } ``` 但這裡有個坑,如果你傳得倆個地址是一樣得話,就會出錯: ```java public static void main(String[] args) { Main main = new Main(); int[] arr = {1,2}; main.test(0,0,arr); } public void test(int a, int b, int[] arr){ arr[a] = arr[a] ^ arr[b]; arr[b] = arr[a] ^ arr[b]; arr[a] = arr[a] ^ arr[b]; System.out.println(Arrays.toString(arr));//[0,1]