面向对象与面向过程:

面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。

代码混淆:亦称花指令,是将计算机程序的代码,转换成一种功能上等价,但是难于阅读和理解的形式的行为,防止他人可以轻松的反编译出你的代码。

面向对象3特征:封装、继承、多态性。

    作用域      当前类 同一package  子孙类 其他package

public       √              √               √               √

protected √               √               √               ×

default     √               √               ×               ×

private     √               ×               ×               ×

Java与c、c++编码到运行的区别:

Java:.java文件->javac(编译器)->.class(字节码文件)->jvm运行,java运行在虚拟机上,可做到跨平台运行。

c、c++:直接编译成可执行文件,无法跨平台,不同的操作系统的标准不一样。

JAVA方法的形参的传递机制:值传递

值传递时,因为修改的是形参地址的内容,所以不会对实参产生影响,地址(引用)传递时,修改形参的属性,并不是直接就把形参的地址里的内容覆盖(因为形参地址里存的只是个地址,没有什么属性),而是先从形参地址里取出里面的内容,即形参和实参共同指向的地址,然后再对那个地址进行操作,这样,因为实参也指向那个地址,所以实参的属性也会发生改变。对于重新给形参赋值,这时是在形参的地址里重新存入一个新的地址,此时形参与实参不再指向同一个地址,所以形参的任何变化都不会对实参造成影响。这也就是为什么在函数里不能改变实参的指向的原因。

int[] a={1,2,3} 和 int[] a = new int[]{1,2,3}

数组对象一样放在堆里,java的数组变量是一种引用型的变量,数组变量并不是数组本身。他只是指向堆内存中的数组对象。
所有局部变量都是存放在栈内存中,不管其是基本类型的变量还是引用类型的变量,都是存储在各自的方法栈区中;但引用类型变量所引用的对象(包括数组、普通java对象)则总是存储在堆内存中。

从低位类型到高位类型自动转换,从高位类型到低位类型需要强制类型转换:

  • 布尔型和其它基本数据类型之间不能相互转换;
  • byte型可以转换为short、int、、long、float和double;
  • short可转换为int、long、float和double;
  • char可转换为int、long、float和double;
  • int可转换为long、float和double;
  • long可转换为float和double;
  • float可转换为double;

将long值b强制转换为int:int a = (int)b

基本数据类型占字节及位数:

  • 字节byte:用来计量存储容量的一种计量单位;位bit      一个字节等于8位  1byte = 8bit

整型:

  • byte:1个字节 8位 -128~127
  • short :2个字节 16位
  • int :4个字节 32位
  • long:8个字节 64位

浮点型:

  • float:4个字节 32 位
  • double :8个字节 64位

注:默认的是double类型,如3.14是double类型的,加后缀F(3.14F)则为float类型的。

char类型:

  • char:2个字节 16位,所以一个char类型的可以存储一个汉字。

Boolean 类型

  • boolean: true or false

算术运算规则

  1. 基本就是先转换为高位数据类型,再参加运算,结果也是最高位的数据类型;
  2. byte short char运算会转换为Int;

String类是final类

“对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象”。

public class Test{public static void main(String[] args){String a = "aaaa";String b = a.replace('a', 'b');System.out.println(a);System.out.print(b);}
}

当对String类对象进行substring(),replace()等,应该赋值给新的String对象,因为a还是原来的内容。

String str="hello world"和String str=new String("hello world")的区别:

public class Test{public static void main(String[] args){String a = new String("aaaa");String b = new String("aaaa");String c = "aaaa";System.out.println(a==b);System.out.println(a.equals(b));System.out.println(a==c);System.out.println(a.equals(c));}
}

String c = "aaaa";在编译期间生成了字面常量和符号引用,运行期间字面常量"aaaa"被存储在运行时常量池(当然只保存了一份)。通过这种方式来将String对象跟引用绑定的话,JVM执行引擎会先在运行时常量池查找是否存在相同的字面常量,如果存在,则直接将引用指向已经存在的字面常量;否则在运行时常量池开辟一个空间来存储该字面常量,并将引用指向该字面常量。通过new关键字来生成对象是在堆区进行的,而在堆区进行对象生成的过程是不会去检测该对象是否已经存在的。因此通过new来创建对象,创建出的一定是不同的对象,即使字符串的内容是相同的

"=="和eqals区别:

  • equals:String类的equals方法只比较内容,所以上面equals返回true。Object类的equals方法则比较他们在内存中的存放地址
  • ==:基本数据类型,byte,short,char,int,long,float,double,boolean 他们之间的比较,应用双等号(==),比较的是他们的值。当用来比较类对象时,比较的是他们在内存中的存放地址,所以除非是引用自同一个new的对象,否则都为false。

StringBuilder和StringBuffer类区别:

StringBuilder和StringBuffer类拥有的成员属性以及成员方法基本相同,区别是StringBuffer类的成员方法前面多了一个关键字:synchronized,StringBuffer类是线程安全的

序列化和反序列化

在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。

  • 把对象转换为字节序列的过程称为对象的序列化。
  • 把字节序列恢复为对象的过程称为对象的反序列化。
  • java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
  • java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。

transient关键字

只能修饰变量,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会被序列化。保证属性不会被传递,安全。

volatile关键字

所有线程的共享变量都存储在主存(既内存)中,每一个线程都有一个独有的工作内存,每个线程不直接操作在主内存中的变量,而是将主内存上变量的副本放进自己的工作内存中,只操作工作内存中的数据。当修改完毕后,再把修改后的结果放回到主内存中。这就导致多线程的环境下可能会出现脏数据,加上volatile关键字修饰的话,它可以保证当线程对变量值做了变动之后,会立即刷回到主内存中,这样在任何时刻,线程总是会看到变量的同一个值。

缺点:保证了可见性和有序性,但是原子性无法保证,无法代替Synchronize关键字。

例如:两个线程的一个共享volatile变量i,都进行i++循环操作,i=0,此时线程A进行i++,i=1了,而B线程已经读取了i=0,所以B再i++,也是i=1,造成数据不准确。

为了保证数据准确性一般使用Synchronize、lock或者AtomicInteger。AtomicInteger采用CAS保证线程安全。

static关键字

  • 不能修饰外部类,只有修饰内部类。
  • 静态的方法不能重写,直接通过类名调用。静态方法里调用外部类的只能是静态变量和静态方法
  • 静态变量在JVM初始化阶段就被赋值
  • 静态代码块在静态变量后执行。

类初始化的顺序:

父类静态变量->父类静态代码块->子类静态变量->子类静态代码块->父类普通变量->父类普通代码块->父类构造函数->子类普通变量->子类普通代码块->子类构造函数

假设类A有静态内部类B和非静态内部类C,创建B和C的区别为:
A a=new A();
A.B b=new A.B();
A.C c=a.new C();

final关键字

  • final修饰类不可以被继承,但是可以继承其他类。
  • final修饰的变量称为常量,这些变量只能赋值一次。
  • final修饰的方法,不可以重写,但可以继承使用。

final、finally、finalize的区别与用法

  • final:java中的关键字,修饰符。
  • finally:java的异常处理机制最后一步。在try catch块里return的时候,finally也会被执行。System.exit(0)是终止Java虚拟机JVM的,finally不会执行。
  • finalize:Java中的一个方法名。finalize是在对象回收前做一些清扫工作,以及可清理栈上的内存。这个方法是由垃圾收集器在确定这个对象没被引用时对这个对象调用的。它是在Object类中定义的,因此所的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。

try - with - resource

jdk1.7引入的try with resources语法糖式写法。try-with-resources 语句确保了每个资源在语句结束时关闭。所有实现了 java.lang.AutoCloseable 接口(其中,它包括实现了 java.io.Closeable 的所有对象),可以使用作为资源。

public class Demo {    public static void main(String[] args) {try(Resource res = new Resource()) {res.doSome();} catch(Exception ex) {ex.printStackTrace();}}
}class Resource implements AutoCloseable {void doSome() {System.out.println("do something");}@Overridepublic void close() throws Exception {System.out.println("resource is closed");}
}执行输出如下:
do something
resource is closed

在 try 语句中,可以创建多个资源,中间用;隔开,越是最后使用的资源,越是最早被关闭。

try(ResourceSome some = new ResourceSome();ResourceOther other = new ResourceOther())

抽象类与接口区别:

  • 抽象类要被子类继承,接口要被类实现。
  • 接口只能做方法声明,抽象类中可以作方法声明,也可以做方法实现。
  • 接口可以extends接口,而不能implement。
  • 非抽象类implement接口,extends抽象类就必须实现所有方法。

匿名类又称匿名内部类:

new 类名/接口名/抽象类名(){定义子类/实现类的内容}

重载(Overload)和重写(Override)的区别?

重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;

重写:

  1. 发生在父类与子类之间
  2. 方法名,参数列表,返回类型(除过子类中方法的返回类型是父类中返回类型的子类)必须相同
  3. 访问修饰符的限制一定要大于或等于被重写方法的访问修饰符(public>protected>default>private)
  4. 重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常

多态存在的三个条件

静态多态:重载

动态多态:

  • 有继承关系  
  • 子类重写父类方法  
  • 父类引用指向子类对象

多态的实现

方法表:在JVM执行Java字节码时,类型信息被存放在方法区中,通常为了优化对象调用方法的速度,方法区的类型信息中增加一个指针,该指针指向一张记录该类方法入口的表(称为方法表),表中的每一项都是指向相应方法的指针。

方法表结构:方法表中最先存放的是Object类的方法,接下来是该类的父类的方法,最后是该类本身的方法。这里关键的地方在于,如果子类改写了父类的方法,那么子类和父类的那些同名方法共享一个方法表项。排列特性(Object——父类——子类),使得方法表的偏移量总是固定的。

多态的实例方法调用实际上有两种指令:

  • invokevirtual指令用于调用声明为类的方法;
  • invokeinterface指令用于调用声明为接口的方法。

静态方法是由虚拟机指令invokestatic调用的,私有方法和构造函数则是由invokespecial指令调用,只有被invokevirtual和invokeinterface指令调用的方法才会在方法表中出现。

invokevirtual :

  1. 先从操作栈中找到对象的实际类型 class;
  2. 找到 class 中与被调用方法签名相同的方法,如果有访问权限就返回这个方法的直接引用,如果没有访问权限就报错 java.lang.IllegalAccessError ;
  3. 如果第 2 步找不到相符的方法,就去搜索 class 的父类,按照继承关系自下而上依次执行第 2 步的操作;
  4. 如果第 3 步找不到相符的方法,就报错 java.lang.AbstractMethodError ;

如果子类覆盖了父类的方法,则在多态调用中,即使将子类对象声明为父类类型,动态绑定过程会首先确定实际类型是子类,从而先搜索到子类中的方法。这个过程便是方法覆盖的本质。

invokeinterface:

  1. 因为 Java 类是可以同时实现多个接口的,而当用接口引用调用某个方法的时候,情况就有所不同了。
  2. Java 对于接口方法的调用是采用搜索方法表的方式,因为每次接口调用都要搜索方法表,所以从效率上来说,接口方法的调用总是慢于类方法的调用的。

动态编译与静态编译

  • 静态编译:一次性编译。在编译的时候把你所有的模块都编译进去。
  • 动态编译:按需编译。程序在运行的时候,用到那个模块就编译哪个模块。

泛型的意义在于

  1. 适用于多种数据类型执行相同的代码(代码复用)
  2. 泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型)
public class GenericClass<T> {private T data;public T getData() {return data;}public void setData(T data) {this.data = data;}public static void main(String[] args) {GenericClass<String> genericClass=new GenericClass<>();genericClass.setData("Generic Class");System.out.println(genericClass.getData());}
}

限定通配符包括两种:

  1. 表示类型的上界,格式为:<? extends T>,即类型必须为T类型或者T子类
  2. 表示类型的下界,格式为:<? super T>,即类型必须为T类型或者T的父类

非限定通配符:类型为<T>,可以用任意类型来替代。

反射

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

要想解剖一个类,必须先要获取到该类的字节码文件对象。既Class clz = Class.forName("包名.类名");

反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。

反射就是把Java类中的各种成分映射成一个个的Java对象。

//获取类的 Class 对象实例
Class clz = Class.forName("包名.类名");
//根据 Class 对象实例获取 Constructor 对象
Constructor phoneConstructor = clz.getConstructor();
//使用 Constructor 对象的 newInstance 方法获取反射类对象
Object phoneObj = phoneConstructor.newInstance();
//获取方法的 Method 对象
Method setPriceMethod = clz.getMethod("setPrice", int.class);
//利用 invoke 方法调用方法
setPriceMethod.invoke(phoneObj, 6000);

new与反射区别

  1. new属于静态编译,而反射属于动态编译,new时所有模块都加载了,而反射是用到的时候才加载。
  2. new出来的对象,无法反问它的私有属性,而反射可以(通过setAccessible()取访问)
  3. new关键字是强类型的,效率相对较高。 反射是弱类型的,效率低。
  4. 反射提供了一种更加灵活的方式创建对象,得到对象的信息。EventBus框架,通过反射获取类中"onEvent"开头的订阅方法。

删除目录下的所有文件及子目录下所有文件

private  boolean deleteDir(String dir) {File file = new File(dir);boolean delete ;if (file.isDirectory()) {String[] children = file.list();if(children.length>0){/**递归删除目录中的子目录下*/for (int i=0; i<children.length; i++) {boolean success = deleteDir(dir+"/"+children[i]);if (!success) {return false;}}}            }   return file.delete();}

单链表逆置

//单链表定义ListNode{int    value;ListNode    next;
};//单链表逆置实现
ListNode ReverseList(ListNode head)
{if (head == null||head.next == null){retrun pHead;}ListNode finalList = null;ListNode originList = head;while(originList != null){ListNode tempList = originList;   // 步骤①originList = originList.next;       // 步骤②tempList.next = finalList;      // 步骤③finalList = tempList;}return finalList;
}

排序算法:

桶排序:

  • 平均时间复杂度:O(n + k)
  • 最佳时间复杂度:O(n + k)
  • 最差时间复杂度:O(n ^ 2)
public void bucketSort(int[] a){List<Integer> bucket[] = new ArrayList[10];for(int i=0; i < a.length ; i++){int temp = a[i]/10000;if(bucket[temp] == null){bucket[temp] = new ArrayList<Integer>();}bucket[temp].add(a[i]);}//对桶内各个元素进行排序for(int j=0;j<10;j++){intsertSort(bucket[j]);printList(bucket[j]);}}private void printList(List<Integer> list) {while(list.size()>0){System.out.print(list.remove(0) +"\t");}}private void intsertSort(List<Integer> list) {Collections.sort(list);}

插入排序:

直接插入排序基本思想是每一步将一个待排序的记录,插入到前面已经排好序的有序序列中去,直到插完所有元素为止。

当数据正序时,执行效率最好,每次插入都不用移动前面的元素,时间复杂度为O(N)。
当数据反序时,执行效率最差,每次插入都要前面的元素后移,时间复杂度为O(N^2)。

希尔排序:

第一趟排序中,通过计算gap1=N/2(即10/2),将10个元素分为5组,即(9,4),(1,8),(2,6),(5,3),(7,5),然后对每组内的元素进行插入排序。
第二趟排序中,把上次的 gap 缩小一半,即 gap2 = gap1 / 2 = 2 (取整数)。这样每相隔距离为 2 的元素组成一组,可以分为 2 组。分组后依旧对每组的元素进行插入排序。
第三趟排序中,再次把 gap 缩小一半,即gap3 = gap2 / 2 = 1。 这样相隔距离为 1 的元素组成一组,即只有一组。再进行一次插入排序。
需要注意的是,图中有两个相等数值的元素 5 和 5 。我们可以清楚的看到,在排序过程中,两个元素位置交换了。所以,希尔排序是不稳定的算法。

时间复杂度为O(N^(1.3—2))

冒泡排序算法:
1.比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素会是最大的数。

其时间复杂度依然为O(N^2)

选择排序:
1.从待排序序列中,找到最小的元素;
2.如果最小元素不是待排序序列的第一个元素,将其和待排序序列的第一个元素互换;

时间复杂度为 O(N*2)

快排O(n*logn):

import java.util.Arrays;public class Solution {public static void main(String[] args) {quickSort(new int[]{39,28,55,87,66,3,17,39});}public static void quickSort(int[] arr){quickSort(arr,0,arr.length-1);System.out.println(Arrays.toString(arr));}public static void quickSort(int[] arr,int left,int right){int middle;if(left < right){middle = partition(arr,left,right);quickSort(arr,left,middle-1);quickSort(arr,middle+1,right);}}public static int partition(int[] arr,int left,int right){int pivot = arr[left];while(left < right){while(left<right && arr[right] >= pivot)right--;arr[left] = arr[right];while(left < right && arr[left]<= pivot)left++;arr[right] = arr[left];}arr[left] = pivot;return left;}
}

递归通常用栈来实现。

守护进程

在linux系统中,我们会发现在系统启动的时候有很多的进程就已经开始跑了,也称为服务,这也是我们所说的守护进程。

守护进程是脱离于终端并且在后台运行的进程,脱离终端是为了避免在执行的过程中 的信息在终端上显示,并且进程也不会被任何终端所产生的终端信息所打断。守护进程一般的生命周期是系统启动到系统停止运行。

异常:

所有的异常都是继承Throwable的,自定义异常不可以继承自Error。

Error

Error及其子类用来描述Java运行系统中的内部错误以及资源耗尽的错误,是程序无法处理的错误,这类错误比较严重。这类的大多数错误与代码编写者执行的操作无关,如,运行代码时,JVM(Java虚拟机)出现的问题,例如,Java虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。

Exception:可以通过捕捉处理使程序继续执行,是程序自身可以处理的异常,也称为非致命性异常类。

异常与错误的区别是:异常可以通过程序自身捕捉处理,而错误是程序自身无法处理的。

throws:通常被用在声明方法时,用来指定方法可能抛出的异常,多个异常可使用逗号分隔。throws关键字将异常抛给上一级,如果不想处理该异常,可以继续向上抛出,但最终要有能够处理该异常的代码。

throw:通常用在方法体中或者用来抛出用户自定义异常,并且抛出一个异常对象。程序在执行到throw语句时立即停止,如果要捕捉throw抛出的异常,则必须使用try-catch语句块或者try-catch-finally语句。

ThreadLocal

ThreadLocal为解决多线程程序的并发问题提供了一种新的思路,每个线程只能获取到自己线程的数据,多线程下也不会产生冲突。

ThreadLocal的接口方法

//设置当前线程的线程局部变量的值。
public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);
}public Object get()
该方法返回当前线程所对应的线程局部变量。public void remove()
将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。
需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,
所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。

在ThreadLocal类中有一个ThreadLocalMap,用于存储每一个线程的变量副本,Map中元素的key为线程对象,而值对应线程的变量副本。

应用:

  1. 在进行对象跨层传递的时候,使用ThreadLocal可以避免多次传递,打破层次间的约束。
  2. 线程间数据隔离
  3. 进行事务操作,用于存储线程事务信息。
  4. 数据库连接,Session会话管理。

URI与URL

URL 比较实体   表示一个具体的

URI 比较抽象 表示一个相对的意思

URL --   比如 http://www.baidu.com/124/123    是一个绝对的路径

URI -- 比如 /124/123 是一个相对的路径

File实现了 Serializable,可以用Intent传递。

四种启动模式:

  1. Standard  :普通activity
  2. SingleTop(实例在栈顶不会新建):展示推送过来的消息
  3. SingleTask(有实例则移到栈顶,并把它上面的activity出栈。):程序入口等启动页面
  4. SingleInstance(创建一个新的任务栈,并且这个任务栈只有他一个Activity):独立于程序的activity·

Activity A跳转到B:

A:onPause()

B: onCreate() onStart() onResume()  或 onRestart() onStart()  onResume()

A:  onStop()

onSaveInstanceState方法

  • onSaveInstanceState() 方法的主要目的是保存和 Activity 的状态有关的数据,当系统在销毁 Activity 时,如果它希望 Activity 下次出现的样子跟之前完全一样,那么它就会调用onSaveInstanceState(),否则就不调用。能够通过 onCreate(Bundle) 或者onRestoreInstanceState(Bundle) 来恢复其界面状态。
  • onSaveInstanceState() 方法并不是永远都会调用。比如,当用户在一个 Activity 点击返回键时,就不会调用,因为用户此时明确知道这个 Activity 是要被销毁的,并不期望下次它的样子跟现在一样,所以就不用调用onSaveInstanceState()。
  • 在onPause()、onStop() 以及 onDestroy() 中需要保存的是那些需要永久化的数据,而不是保存用于恢复状态的数据,状态数据有专门的方法:onSaveInstanceState()。数据保存在一个 Bundle 中,Bundle 被系统永久化。当再调用 Activity 的onCreate()时,原先保存的 Bundle就被传入,以恢复上一次临死时的模样,如果上次被销毁时没有保存 Bundle,则为 null。
  • 如果你没有实现自己的 onSaveInstanceState(),但是 Activity 上控件的样子可能依然能被保存并恢复。原来 Activity 类已实现了onSaveInstanceState(),在 onSaveInstanceState() 的默认实现中,会调用所有控件的相关方法,把控件们的状态都保存下来,比如 EditText 中输入的文字、CheckBox 是否被选中等等。然而不是所有的控件都能被保存,这取决于你是否在 layout 文件中为控件赋了一个名字(android:id)。有名的就存,无名的不管。
  • 既然有现成的可用,那么我们到底还要不要自己实现 onSaveInstanceState() 方法呢?这就得看情况了,如果你自己的派生类中有变量影响到UI,或你程序的行为,当然就要把这个变量也保存了,那么就需要自己实现,否则就不需要,但大多数情况肯定需要自己实现一下下了。对了,别忘了在你的实现中调用父类的 onSaveInstanceState() 方法。

注:由于 onSaveInstanceState() 方法并不是在每次被销毁时都会调用,所以不要在其中保存那些需要永久化的数据,执行保存那些数据的最好地方是在 onPause() 方法中。

Fragment的place方法是先删除其他fragment再添加。

Fragment之间数据传递的三种方式

Fragment的setArguments(Bundle)方法

创建Fragment对象时,如果需要传递参数,不推荐重载带参的构造方法。通过 使用默认的构造函数 加上 Fragment.setArguments(Bundle)来取代。

public class MyFragment extends Fragment {public static MyFragment newInstance(int someInt) {MyFragment myFragment = new MyFragment();Bundle args = new Bundle();args.putInt("someInt", someInt);myFragment.setArguments(args);return myFragment;}
}

根据Android文档说明,当一个fragment重新创建的时候,系统会再次调用 Fragment中的默认构造函数。 注意这里:是默认构造函数

当你创建了一个带有重要参数的Fragment的之后,一旦由于什么原因(横竖屏切换)导致你的Fragment重新创建。你之前传递的参数都不见了。

使用系统推荐的 Fragment.setArguments(Bundle)来传递参数。就可以有效的避免这一个问题,当你的Fragment销毁的时候,其中的Bundle会保存下来,当要重新创建的时候会检查Bundle是否为null,如果不为null,就会使用bundle作为参数来重新创建fragment.

疑问:当fragment重建的时候,怎么获取之前的参数呢?

可以重写 fragment的onCreate()方法。

getArguments().getInt("someInt", 0);

onNewIntent()方法

只对SingleTop(且位于栈顶),SingleTask和SingleInstance(且已经在任务栈中存在实例)的情况下,再次启动它们时才会调用。

SingleTop:

如果ActivityA在栈顶,且现在要再启动ActivityA,这时会调用onNewIntent()方法 ,生命周期顺序为:

onCreate--->onStart--->onResume---onPause--->onNewIntent--->onResume

当ActivityA的LaunchMode为SingleInstance,SingleTask:

如果ActivityA已经在任务栈中,再次启动ActivityA,那么此时会调用onNewIntent()方法,生命周期调用顺序为:

Pause--->B跳转回A--->onNewIntent--->onRestart--->onStart--->onResume

protected void onNewIntent(Intent intent) {super.onNewIntent(intent);setIntent(intent);//must store the new intent unless getIntent() will return the old one
}

activity退出方式

RS优雅式

什么是RS式呢?即Receiver+singleTask 。我们知道Activity有四种加载模式,而singleTask就是其中的一种,使用这个模式之后,当startActivity时,它先会在当前栈中查询是否存在Activity的实例,如果存在,则将其至于栈顶,并将其之上的所有Activity移除栈。我们打开一个app,在主页进行N次的跳转,期间会产生数量不定的Activity,有的被销毁,有的驻留在栈中,但是栈底永远是我们的HomeActivity。这样就让问题变得简单很多了。我们只需两步操作即可优雅的实现app的退出。

1、在HomeActivity注册一个退出广播,只需要在HomeActivity一个页面注册即可。 
2、设置HomeActivity的启动模式为singleTask。 
当我们需要退出的时候只需要startActivity(this,HomeActivity,class), 再发送一个退出广播。上面代码首先会把栈中HomeActivity之上的所有Activity移除出栈,然后接到广播finish自己。一切OK ! 没有弹框,不用考虑机型Rom适配。不会有内存问题。

SingleTask改版式

注册广播略显麻烦

  1. 设置MainActivity的加载模式为singleTask
  2. 重写MainActivity中的onNewIntent方法
  3. 需要退出时在Intent中添加退出的tag

第一步设置MainActivity的加载模式为singleTask

 android:launchMode="singleTask"

第二步重写onNewIntent()方法

private static final String TAG_EXIT = "exit";@Override
protected void onNewIntent(Intent intent) {super.onNewIntent(intent);if (intent != null) {boolean isExit = intent.getBooleanExtra(TAG_EXIT, false);if (isExit) {this.finish();}}
}

第三步 退出

Intent intent = new Intent(this,MainActivity.class);intent.putExtra(MainActivity.TAG_EXIT, true);startActivity(intent);

懒人式

这种方式更加简单,只需要如下两步操作

  1. 将MainActivity设置为singleTask
  2. 将退出出口放置在MainActivity

双击两次返回键退出应用,就是基于这样的方式来实现的,这里在贴一下如何处理连续两次点击退出的源码

private long firstTime=0;@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_BACK) {if (System.currentTimeMillis()-firstTime>2000){Toast.makeText(MainActivity.this,"再按一次退出程序",Toast.LENGTH_SHORT).show();firstTime=System.currentTimeMillis();}else{finish();System.exit(0);}return true;}return super.onKeyDown(keyCode, event);}

android:screenOrientation属性:

  • unspecified——默认值,由系统选择显示方向,在不同的设备可能会有所不同。
  • landscape——横向
  • portrait——纵向
  • user——用户当前的首选方向
  • behind——与在活动堆栈下的活动相同方向
  • sensor——根据物理方向传感器确定方向,取决于用户手持的方向,当用户转动设备,他能随意改变。
  • nosensor——不经物理方向传感器确定方向,该传感器被忽略,所以当用户转动设备,显示不会跟随改变,除了这个却别,系统选择相同的政策取向对于“未指定”设置,系统根据“未指定”(unspecified)设定选择相同显示方向。

从 Android 3.2 (API级别 13)以后

  1. 不设置Activity的android:configChanges时,或 设置Activity的android:configChanges="orientation"时,或设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行一次方法。
  2. 配置 android:configChanges="orientation|screenSize",才不会销毁 activity,且只调用 onConfigurationChanged方法。

RecyclerView嵌套

图片加载库对比

Picasso:120K

Glide:475K

Fresco:3.4M

Android-Universal-Image-Loader:162K

图片函数库的选择需要根据APP的具体情况而定,对于严重依赖图片缓存的APP,例如壁纸类,图片社交类APP来说,可以选择最专业的Fresco。对于一般的APP,选择Fresco会显得比较重,毕竟Fresco3.4M的体量摆在这。根据APP对图片的显示和缓存的需求从低到高,我们可以对以上函数库做一个排序。

Picasso < Android-Universal-Image-Loader < Glide < Fresco

Picasso所能实现的功能,Glide都能做,无非是所需的设置不同。但是Picasso体积比起Glide小太多如果项目中网络请求本身用的就是okhttp或者retrofit(本质还是okhttp),那么建议用Picasso,体积会小很多(Square全家桶的干活)。Glide的好处是大型的图片流,比如gif、Video,如果你们是做美拍、爱拍这种视频类应用,建议使用。

ANR(Application Not Responding):

应用程序无响应:在一定的时间内没有做完相应的处理。

应用程序的响应性是由Activity Manager和WindowManager系统服务监视的 。

响应输入input的事件时间超过5S,broadcastReceiver超过10S,前台service处理超过20S,后台service超过200S

判断分析:发生ANR后,可以结合Logcat日志和位于收集内部存储的/data/anr/trace.txt文件进行分析和定位。

线程中start()和run()的区别

start():启动相应的线程,让一个线程进入就绪队列等待分配cpu,分到cpu后才调用实现的run()方法。

run():线程体,包含了线程要执行的内容。直接调用run只是一个普通的函数调用,并没有新建线程的作用。

普通内部类如何访问外部类:

  1. 编译器自动为内部类生成一个带参构造方法, 参数只有一个,类型是外部类。
  2. 编译器自动为内部类添加一个成员变量,通过第一步的构造函数赋值, 这个成员变量就是指向外部类对象的引用;
  3. 内部类通过该引用访问外部类属性。

Android 查看内存使用情况

ADB命令

查看应用程序的命令:adb shell procrank

查看单个应用程序内存占用量的命令:adb shell dumpsys meminfo $包名 或者 $进程号

PID     Vss        Rss        Pss        Uss         cmdline

190  79560K  74736K  49624K  43604K  system_server

  • VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
  • RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存)
  • PSS - Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
  • USS - Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)

DDMS工具

sdk文件夹->tools->monitor.bat

Android为什么要设计出Bundle而不是直接使用HashMap来进行数据传递?

Bundle内部是由ArrayMap实现的,ArrayMap的内部实现是两个数组,一个int数组是存储对象数据对应下标,一个对象数组保存key和value,内部使用二分法对key进行排序,所以在添加、删除、查找数据的时候,都会使用二分法查找,只适合于小数据量操作,如果在数据量比较大的情况下,那么它的性能将退化。

HashMap内部则是数组+链表结构,所以在数据量较少的时候,数组占用内存少,HashMap的Entry Array比ArrayMap占用更多的内存。因为使用Bundle的场景大多数为小数据量,我没见过在两个Activity之间传递10个以上数据的场景,所以相比之下,在这种情况下使用ArrayMap保存数据,在操作速度和内存占用上都具有优势,因此使用Bundle来传递数据,可以保证更快的速度和更少的内存占用。

另外一个原因,则是在Android中如果使用Intent来携带数据的话,需要数据是基本类型或者是可序列化类型,HashMap使用Serializable进行序列化,而Bundle则是使用Parcelable进行序列化。而在Android平台中,更推荐使用Parcelable实现序列化,虽然写法复杂,但是开销更小,所以为了更加快速的进行数据的序列化和反序列化,系统封装了Bundle类,方便我们进行数据的传输。

ScrollView嵌套ListView

只显示一个item:

动态计算ListView高度并赋值。

重写onMeasure()。

滑动冲突:

listVIew中调用getParent().requestDisallowInterceptTouchEvent(true);禁止父View拦截事件。

    @Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {switch (ev.getAction()){case MotionEvent.ACTION_DOWN:getParent().requestDisallowInterceptTouchEvent(true);break;case MotionEvent.ACTION_MOVE:boolean a = !canScrollVertically(-1);boolean b = ev.getY()-firstY>0;boolean c = !canScrollVertically(1);boolean d = ev.getY()-firstY<0;if ( (b&&a)|| (c&& d))getParent().requestDisallowInterceptTouchEvent(false);break;}
三级缓存

网络缓存,不优先加载,速度慢,浪费流量。

本地缓存,次优先加载,速度快。

内存缓存,优先加载,速度最快。

首次加载Android App时,肯定要通过网络交互来获取图片,之后我们可以将图片保存至本地SD卡和内存中,之后运行APP时,优先访问内存中的图片缓存,若内存中没有,则加载本地SD卡中图片,最后选择访问网络

Context

Context类本身是一个纯abstract类,它有两个具体的实现子类:ContextImpl和ContextWrapper。

ContextWrapper类,如其名所言,这只是一个包装而已,ContextWrapper构造函数中必须包含一个真正的Context引用,同时ContextWrapper中提供了attachBaseContext()用于给ContextWrapper对象中指定真正的Context对象,调用ContextWrapper的方法都会被转向其所包含的真正的Context对象。ContextThemeWrapper类,如其名所言,其内部包含了与主题(Theme)相关的接口,这里所说的主题就是指在AndroidManifest.xml中通过android:theme为Application元素或者Activity元素指定的主题。当然,只有Activity才需要主题,Service是不需要主题的,因为Service是没有界面的后台场景,所以Service直接继承于ContextWrapper,Application同理。而ContextImpl类则真正实现了Context中的所以函数,应用程序中所调用的各种Context类的方法,其实现均来自于该类。一句话总结:Context的两个子类分工明确,其中ContextImpl是Context的具体实现类,ContextWrapper是Context的包装类。Activity,Application,Service虽都继承自ContextWrapper(Activity继承自ContextWrapper的子类ContextThemeWrapper),但它们初始化的过程中都会创建ContextImpl对象,由ContextImpl实现Context中的方法。

Context数量=Activity数量+Service数量+1

WebView 优化

  • 另开WebView进程
<activityandroid:name=".activity.WebActivity"//设置android:process属性来使其运行在指定的进程中android:process=":webActivity"><intent-filter><action android:name="com.activity.Webactivity"/><category android:name="android.intent.category.DEFAULT"/></intent-filter>
</activity>
  • 使用WebView内置缓存
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
webSettings.setDatabaseEnabled(true);
webSettings.setDomStorageEnabled(true);
webSettings.setAppCacheEnabled(true);
  • 资源文件预置在 app 中
  • 实现WebView复用
  • 实现请求拦截,如果存在缓存资源则拦截请求返回资源
  • 图片资源懒加载,先加载其他资源
//在 WebView 加载页面之前先设置
webView.getSettings().setBlockNetworkImage(true); //将图片下载阻塞
//在浏览器 OnPageFinished事件中设置
webView.getSettings().setBlockNetworkImage(false);
  • 使用VasSonic:

    • 提供预加载接口,预加载 html 内容至内存
    • 仅提升 html 文件加载,js、css、图片等资源走正常浏览器流程
    • 预加载不支持重定向
  • 后台 Service 预加载 WebView

Java、Android—零碎难记笔试考点(持续更新)相关推荐

  1. Android开发样式问题总结【持续更新】

    目录 Android控件/框架开源库收集 配置国内仓库 1. Java中设置控件的大小需要把dp先转换为像素(转换如下) 2. Java中设置GridLayout布局的layout_columnWei ...

  2. Android常用热门开源库汇总(持续更新)

    原文转载:https://www.yundashi168.com/344.html 请及时关注原文网站,因为后续持续更新都在原网站更新.请多多点赞和关注. 前言 收集了一些比较常见的开源库,特此记录( ...

  3. 2019最新Android常用开源库总结(持续更新,建议收藏)

    热文导读|   点击标题阅读 如何才能成为优秀的架构师? 23种设计模式及案例整理分享(建议收藏) 程序员的35个坏习惯,你有几条? 作者:欢子-3824 来源:https://blog.csdn.n ...

  4. android标题栏添加按钮_2019最新Android常用开源库总结(持续更新,建议收藏)

    热文导读|   点击标题阅读 如何才能成为优秀的架构师? 23种设计模式及案例整理分享(建议收藏) 程序员的35个坏习惯,你有几条? 作者:欢子-3824 来源:https://blog.csdn.n ...

  5. Java日常错误及需要注意细节,持续更新......

    记录日常工作中一些容易被忽视的错误及细节,持续更新...... 一.问题:HashMap<Long, String>中,用get(Integer key)取不到值 Map<Long, ...

  6. android 开发工具类,Android中常用开发工具类—持续更新...

    一.自定义ActionBar public class ActionBarTool { public static void setActionBarLayout(Activity act,Conte ...

  7. java基础(适合零基础)持续更新

    目录 java语言的概述 1.概述 2.Java语言特点 3.java的加载与执行 开始第一个java程序 1.安装JDK(这里安装JDK1.8) 2.安装文本编辑器Editplus 3.JDK目录介 ...

  8. 欢迎关注公众号:Android系统攻城狮 原创持续更新中!!!

    公众号:Android系统攻城狮 简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案.音视频.编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列[原创干 ...

  9. Android学习相关文章汇总(持续更新,文章均来自网络,转侵删)

    本文主要是记录在使用Android踩坑时的一些有用的文章.以及Android进阶文章等相关链接的记录,并且附带一些简单的备注等.主要用来备忘.方便日后查看.会持续更新 1. AS相关问题 项目第一次g ...

最新文章

  1. mysql 删除 修改密码_Mysql数据库root密码忘记了,如何在不删除Mysql的情况下修改密码...
  2. activity切换效果
  3. Jscript中window.setInterval和window.setTimeout的区别
  4. Notepad++ 6.0 发布,优化了大文件加载性能
  5. c语言打不开h文件,说那个“mem.h”头文件打不开 怎么改啊 高手们帮帮忙
  6. 数据库发展研究报告(2021年)
  7. php软件开发--php基础
  8. Shell 工作原理
  9. RIP简易配置第二篇
  10. 虚拟串口软件VSPM使用手册
  11. vm8.0下安装mac
  12. autoucad2014激活就未响应_CAD2014激活错误怎么办,autocad2014激活错误的解决办法
  13. 中国人霸屏奥运会乒乓球赛这事 外国人怎么看?
  14. 菜鸟的AI安全乱谈(2)—通过模型再训练留后门
  15. beyond compare下载安装及使用教程
  16. f16_Automated Trading strategy_Kelly Criterion投资比_Vectorized Backtest_drawndown_value-at-risk_socket
  17. 微信小程序开发之——个人中心-个人资料修改(7)
  18. 人脸定点:关键点检测方法汇总
  19. 0-1整数规划的LINGO求解
  20. docker-compose基本命令使用

热门文章

  1. 计算机二级c语言填空题怎么算分,计算机二级C语言题型和评分标准
  2. python手机号码正确编程_python 小练习之生成手机号码
  3. 随机森林 python_如何轻松使用python的随机森林
  4. php内置函数数组函数,PHP 数组排序内置函数
  5. biginteger 原理_Java Bigdecimal使用原理详解
  6. 测试下微信公众号新功能
  7. 要不要出去找一份实习?
  8. 在STM32价格疯长下,哪些国产32可以替代?
  9. matlab 2010 工具箱,Matlab2010下使用FULLBNT工具箱實現簡單的靜態貝葉斯網絡及推理...
  10. linux下用u盘安装xp系统安装教程,全新Linux笔记本电脑用U盘装Win7/XP系统教程