平常都很少用到位運算,這裡介紹一種jdk
使用位運算的小案例。它是用位運算來優化一個類所佔的大小。下面介紹:
- 什麼情況下,符合這種優化條件;
- 用具體的例子來介紹;
優化情況
假設一個類需要有很多boolean
型別得屬性,如果直接用boolean
型別,那麼這個類會在記憶體中佔用很大空間。通常情況下,一個boolean
型別屬性會佔4個位元組。但這不是一定得,JAVA得boolean屬性佔用位元組不一定。這時候,使用多個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
屬性得值,作為儲存這三個屬性得屬性值
public class Cat {
// 儲存三個boolean屬性得值
private int properties = 0;
}
2、設定三個int
屬性作為三個屬性都為true;這是為了後期方便設定值
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
屬性的最後一位的值,需要注意的是獲取最後一位值得時候,不能影響其他位得值!!!
/**
* 這隻貓萌嗎?請在此處使用位運算讀取properties,得到貓是否萌的結果
*
* @return 萌則返回true,否則返回false
*/
public boolean isCute() {
return (properties & Cat.CUTE) != 0;
}
使用與運算得時候,其他位不受影響;最後一位也是取決於
properties
最後一位得值
(2)設定值的時候
在設定properties
屬性得最後一位得值,需要注意得是設定最後一位的值的時候,不能影響其他位得值!!!
/**
* 使用位運算設定貓咪萌的屬性
*
* @param cute true為萌,false為不萌
*/
public void setCute(boolean cute) {
if (cute == true){
properties = properties | Cat.CUTE;
} else {
properties = properties & (~Cat.CUTE);
}
}
4、設定其他屬性
/**
* 使用位運算設定貓咪胖的屬性
*
* @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 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());
}
}
位運算的一些坑
交換倆個值得功能可以用位運算這種騷操作完成。比如:
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]
}
但這裡有個坑,如果你傳得倆個地址是一樣得話,就會出錯:
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]
}