简介:
近日,偶然学习到一个知识点,就是用“与”运算 算出来的结果来传值,Android framework中 通过包管理器来获得 应用程序信息,如下:
PackageManager pm = this.getPackageManager(); List<PackageInfo> appinfos = pm.getInstalledPackages(0); for(PackageInfo p:appinfos){ String packageName = p.packageName ; Drawable icon = p.applicationInfo.loadIcon(pm); String lableName = p.applicationInfo.loadLabel(pm).toString(); int flags = p.applicationInfo.flags; //应用程序的 属性(比如是系统应用还是用户的应用,是不是游戏,安装在哪里了等等)标记 if((flags & ApplicationInfo.FLAG_SYSTEM )==0){ // & 运算只要有一个为0,就是0,只有都是1才为1. 因此如果这个&运算 为0 ,则说明 flags的最后一位 //等于0 表示false ,就是不是system 应用 } else{ //不是系统应用当然是 用户安装的应用 } if((flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE )==0){ //表示没有装在 外存储设备上,就是 安装在了内存中 }else{ //表示装在 外存储设备上 } }
由此上面代码可以看到 ,一个对象的属性如果是多种状态的时候 ,(比如flags 来标记 应用程序状态属性等),且这个状态是可以用bool类型描述,(比如 不是系统应用就是自己安装应用,是不是游戏 ,是不是安装在外存储设备 等等), 就可以用定义 二进制类型的整数来表示。再通过& 运算 计算可以得出 一个对象属性的状态。 我自己总结为:
一、一个对象的某个属性有多种状态
二、这个对象的属性的状态 可以用bool类型描述
三、这个对象的属性的状态 是不能认为改变的,比如 不能将一个系统应用改变一个用户普通应 用 (这样显然是不合理的)。
那么就可以用这种 像ApplicationInfo.FLAG_XXX的形式来设计 ,尤其是当这个对象的属性的状态多的时候,这种设计显得更方便,简洁。
利用这种形式设计 代替枚举类型的传值:(例子形式描述)
如何来实现这种设计呢,我总结为下面几个点:
一、用位移形式 定义对象属性状态的值。感觉像定义协议差不多。
一个对象属性选项如下:
public static final int A = 1<<0;
public static final int B = 1<<1;
public static final int C = 1<<2;
................. 都和 1 来 做“与” 运算。如果想给这个对象传递A和C ,那么传递( 1<<0) + (1<<2) 就可以了,拿到值后 经过计算 可以得到 是(1<<0) 和(1<<2)两个值
,并且只能是(1<<0) 和(1<<2)两个值,其他的都是非法的,这是由这种算法方式决定的。
我们来假设一种场景,客户端 和服务器端交互时,客户端有个对象的属性有多种状态,例如一个视频的某个属性 是:是否免费,是否适合18+看 等等。这时如何设计呢,可以设计为用json 字段来描述 每个状态,
例如:{isFree:true,isAllowedAdult:true},。
如果用上述 方式来传递的话,需要事先和客户端定义好协议,
比如:
public static final int isFree = 1<<0 ; //是否免费
public static final int isAllowedAdult = 1<<1 ; //是否适合18岁以上人看
只需要传递 (1<<0)一个整数就 可以了,这样 节省了很多传输量。效率不言而喻。
二、对象属性的状态 在程序间传递(一个数字)
三、对象属性的状态 的获得
其实 二、三 步骤都是 已经固定了。下面是例子:
package com.example.administrator.applicationname; import android.util.ArrayMap; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Random; import java.util.Set; /** * Created by Administrator on 2015/8/26. */ public class Test { //都和1来做 “与”运算 public static final int A = 1<<0; public static final int B = 1<<1; public static final int C = 1<<2; public static final int D = 1<<3; public static final int E = 1<<4; public static final int F = 1<<5; /** *用来当做协议表,产生选项的时候可以用 */ static HashMap<String,Integer> map = null; /** * 用来当做协议表,拿到传递的值后解析用。 */ static HashMap<Integer,String> map2 = null; static Random r = new Random(); public static void main(String[] a){ //初始化协议 表 map = new HashMap<String,Integer>(); map2 = new HashMap<Integer,String>(); map.put("A",A); map.put("B",B); map.put("C",C); map.put("D",D); map.put("E",E); map.put("F",F); map2.put(A,"A"); map2.put(B,"B"); map2.put(C,"C"); map2.put(D,"D"); map2.put(E, "E"); map2.put(F, "F"); //测试 : HashSet<String> set = new HashSet<String>(); set.add("A"); set.add("B"); set.add("B"); set.add("C"); System.out.println("测试:选择的选项是" + set.toString()); decode(encode(set)); } /** * 测试 随机选择的项 * @param whichToChoose * @return */ private static int encode(HashSet<String> whichToChoose){ if(whichToChoose!=null && whichToChoose.size()>6){ throw new IllegalArgumentException("最多只能限制6个选项或者参数不合法"); } int sum = 0; for(String s : whichToChoose){ Integer i = map.get(s); sum += i; } System.out.println("计算后产生的数为:" + sum); return sum; } /** * * @param param */ private static void decode(int param){ ArrayList<Integer> list = new ArrayList<Integer>(); int tmp = 1; for(int i = 0 ; i < param; i++){ //32 if((tmp¶m) != 0){ System.out.println("选项为:" + i); list.add((1<<i)); } tmp = tmp << 1; } if(list.size()>0){ for (Integer integer : list) { String selected =map2.get(integer); System.out.println("选择的:"+selected); } } } }
运行结果:
再来看下& 运算:
int c = 2 << 3;
int d = 2 << 4;
int e = 2 << 5;
int f = 2 << 6;
int temp = 2 << 5;
System.out.println((temp & c)!=0?"选中了":"没选中");
System.out.println((temp & d)!=0?"选中了":"没选中");
System.out.println((temp & e)!=0?"选中了":"没选中");
System.out.println((temp & f)!=0?"选中了":"没选中");
执行结果:
没选中
没选中
选中了
没选中
由此 ,我们可以做这么一个应用场景,假如传递过来一个值 param, 需要判断是否 是 c ,d e, f 中的 一个。简单的是 方法是
一个一个的判断:
if(c==param){
}else if(d==param){
}else if(e==param){
}else if(f==param){}else{....}
或者 switch(param){
case c:
break;
...................
}
如果是用& 这个运算符来 做,那么在特定的业务场景下,比如单选,只需要考虑正确的判断逻辑即可, 于是就可以写成:(加入判断是否选中某个选项--单选c)
if(param & c != 0){
// 表示 选中了c
}
而不必再一个一个判断。