android日记(二)

11.多线程中的空指针问题

  • 导致问题的发法如下,在判空后,却得到model对象NullPointerException。
    private void work() {
        Log.d("zouhecan", getThreadId() + "start work()");
        if (model != null) {
            Log.d("zouhecan", getThreadId() + "id=" + model.getId());
            Log.d("zouhecan", getThreadId() + "name=" + model.getName());//model throw NullPointerException
            Log.d("zouhecan", getThreadId() + "flag=" + model.getFlag()); } }
  • 首先定位问题为:多线程操作model对象,使得其中一个线程判model不为空后,另一个线程又置model=null,这时线程操作work方法还未结束,仍然读操作了model对象。
    private Runnable workRunnable = new Runnable() {
        @Override
        public void run() {
            try {
                work();
                Thread.sleep(1000);
            } catch (Exception e) {
                Log.e("zouhecan", e.getMessage()); } } }; private Runnable resetRunnable = new Runnable() { @Override public void run() { Log.d("zouhecan", getThreadId() + "model=null"); model = null; } };
  • 【误解】有人说对用关键字synchornized声明work()为同步方法。这样只是保持所有操作work()方法的线程同步,不
    private synchronized void work() {
        ...
    }

12.使用反射

  • 反射是在运行时,能够动态获取和调用一个类的所有属性、方法,的一种机制。
  • 反射获取类信息,使用Class.forName()方法,需要捕获ClassNotFoundException。Throwable家族有Error【StackOverFlow、OutOfMemory】和Exception两大分支,Exception又氛围RunTimeException【NullPointer、IIegalArgument、ArrayIndexOutOfBound等】和非运行时异常(在编译检查时)【ClassNotFound,Interrupter,IOException等】。
    try {
        Class clazz = Class.forName("com.example.fragmenttest.TestClass");
        testReflection(clazz);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
  • 反射获取构造函数,其中getConstructors()只获取public构造函数,getDeclaredConstructors()则获取所有的构造函数。
    //获取public构造函数
    Constructor[] constructors = clazz.getConstructors();
    
    
    //获取所有构造函数(public,private,protected)
    Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
  • 反射创建对象,先通过getConstructor()根据参数表类型选择对应构造函数,执行constructor.newInstance()传入参数参数表value,并创建对象
    @SuppressWarnings("unchecked")
    Constructor constructor = clazz.getDeclaredConstructor(String.class, int.class);
    constructor.setAccessible(true);
    TestClass testClass = (TestClass) constructor.newInstance("反射调用构造函数", 1);//创建对象
    
    public class TestClass {
        private TestClass(String message, int mode) {
            Log.d("zouhecan", message); } ... }
  • 反射获取Field,getFields()获取public成员,getDeclaredFields()获取全部成员。通过clazz.getField(fieldName)可以获取指定域名的成员(public),非public成员只能通过clazz.getDecalredField(fieldName)获取,否则会抛NoSuchFieldException。如果要操作某个成员,需要先获得对象实例intance【可通过getConstructor().getInstance()得到】,设置field值:field.set(instance, value)给field设置实参value;获取filed值:field.get(instance)将结果强转成对应类型。注意:如果操作的field是private修饰的,需要执行field.setAccessible(true),解除私有限制,否则会抛IlegalAccessException,更进一步地,就算不是操作的不是private成员,也有必要设置accessible=true,这样可以绕过私有检查,操作速度将提升20倍。
    private void testFields(Class clazz){
            //获取public字段
            Field[] fields = clazz.getFields();
    
            //获取所有字段
            Field[] declaredFields = clazz.getDeclaredFields();
    
            for (Field field : fields) {
                Log.d("zouhecan", field.getName());
            }
            
            for (Field field : declaredFields) { Log.d("zouhecan", field.getName()); } }
    try {
                TestClass instance = (TestClass) clazz.getConstructor().newInstance();
    
                //反射设置filed值
                Field numberField = clazz.getField("number");//number是public field
                numberField.set(instance, 1);
    
                //反射获取filed值
                Field nameField = clazz.getDecarledField("name");//name是private field
                nameField.setAccessible(true);//解除私有限制 String nameValue = (String) nameField.get(instance); } catch (Exception e) { e.printStackTrace(); } 
  • 反射调用method,与操作field类似,getMethods()获取public方法(包含父类public方法),getDeclaredMethods()获取全部方法(自己申明的,不包括继承的)。通过getMethod("methodName")获取指定方法名的方法(public),通过getDeclaredMethod("methodName")获取指定的非public方法。再创建类实例instance后,就可以通过method.invoke(instance)调用方法。如果方法是含参的,则在反射获取方法时,需要指明方法参数,method.getDeclaredMethod("method", Object.class),并在调用时指明实参method.invoke(instance, 'params')。

     @SuppressWarnings("unchecked")
        private void testMethod(Class clazz) {
            //获取public方法
            Method[] methods = clazz.getMethods();
            //获取全部方法
            Method[] declaredMethods = clazz.getDeclaredMethods();
            try {
                //创建实例
                TestClass instance = (TestClass) clazz.getConstructor().newInstance();
                //获取public方法
                Method mTestReflect = clazz.getMethod("testReflect");
                //获取非public方法
                Method mInit = clazz.getDeclaredMethod("init");
                //获取一个名为test,参数为string类型的方法
                Method mTest = clazz.getDeclaredMethod("test", String.class);
                //调用方法
                mTestReflect.invoke(instance);
                mInit.invoke(instance);
                mTest.invoke(instance, "test invoke method by reflect");//调用方法,并传入方法实参
            } catch (InstantiationException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }

13.范型

  • 范型类
  • 范型方法
  • Class<T>与Class<?>区别

14.注解自动生成器

  • AbstractAnnotationProcess

15.坚持记录吧

  • 未来的你会感激现在的自己

猜你喜欢

转载自www.cnblogs.com/zhc-android-blogger/p/12939332.html