安卓面试题
横竖屏切换时候Activity的生命周期
他切换时具体的生命周期是怎么样的:
1、新建一个Activity,并把各个生命周期打印出来
2、运行Activity,得到如下信息
onCreate-->
onStart-->
onResume-->
3、按crtl+f12切换成横屏时
onSaveInstanceState-->
onPause-->
onStop-->
onDestroy-->
onCreate-->
onStart-->
onRestoreInstanceState-->
onResume-->
4、再按crtl+f12切换成竖屏时,发现打印了两次相同的log
onSaveInstanceState-->
onPause-->
onStop-->
onDestroy-->
onCreate-->
onStart-->
onRestoreInstanceState-->
onResume-->
onSaveInstanceState-->
onPause-->
onStop-->
onDestroy-->
onCreate-->
onStart-->
onRestoreInstanceState-->
onResume-->
不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
当前Activity产生事件弹出Toast和AlertDialog的时候Activity的生命周期不会有改变
Activity运行时按下HOME键(跟被完全覆盖是一样的):onSaveInstanceState --> onPause --> onStop,再次进入激活状态时: onRestart -->onStart--->onResume
(1) final:修饰符(关键字),如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载
(2) finally:在异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally块(如果有的话)。
(3) finalize:方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。
如果两个对象equals,Java运行时环境会认为他们的hashcode一定相等。
如果两个对象不equals,他们的hashcode有可能相等。
如果两个对象hashcode相等,他们不一定equals。
如果两个对象hashcode不相等,他们一定不equals。
sleep()和wait()的区别
sleep()使当前线程进入停滞状态(阻塞当前线程),让出CUP的使用、目的是不让当前线程独自霸占该进程所获的CPU资源,以留一定时间给其他线程执行的机会;
sleep()是Thread类的Static(静态)的方法;因此他不能改变对象的机锁,所以当在一个Synchronized块中调用Sleep()方法是,线程虽然休眠了,但是对象的机锁并木有被释放,其他线程无法访问这个对象(即使睡着也持有对象锁)。
在sleep()休眠时间期满后,该线程不一定会立即执行,这是因为其它线程可能正在运行而且没有被调度为放弃执行,除非此线程具有更高的优先级。
wait()方法是Object类里的方法;当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时失去(释放)了对象的机锁(暂时失去机锁,wait(long timeout)超时时间到后还需要返还对象锁);其他线程可以访问;
wait()使用notify或者notifyAlll或者指定睡眠时间来唤醒当前等待池中的线程。
wiat()必须放在synchronized block中,否则会在program runtime时扔出”java.lang.IllegalMonitorStateException“异常。
所以sleep()和wait()方法的最大区别是:
sleep()睡眠时,保持对象锁,仍然占有该锁;
wait()睡眠时,释放对象锁。
但是wait()和sleep()都可以通过interrupt()方法打断线程的暂停状态,从而使线程立刻抛出InterruptedException(但不建议使用该方法)。
Java GC机制主要完成3件事:
确定哪些内存需要回收
确定什么时候需要执行GC
如何执行GC
Java内存分配和回收的机制概括的说,就是:分代分配,分代回收。对象将根据存活的时间被分为:年轻代(Young Generation)、年老代(Old Generation)、永久代(Permanent Generation,也就是方法区)
Java内存泄露与溢出的区别:
内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出
而Java内存泄漏就是没有及时清理内存垃圾,导致系统无法再给你提供内存资源
如何避免内存溢出:
从代码层面进行优化完善,尽量避免该情况发生
调整优化服务器配置:
设置-Xms、-Xmx相等
设置NewSize、MaxNewSize相等
设置Heap size, PermGen space:
Tomcat 的配置示例:修改 %TOMCAT_HOME%/bin/catalina.bat or catalina.sh
在“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行:
set JAVA_OPTS=-Xms800m -Xmx800m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m
如何避免内存泄露:
尽早释放无用对象的引用
程序进行字符串处理时,尽量避免使用String,而应使用StringBuffer
尽量少用静态变量
避免集中创建对象尤其是大对象,如果可以的话尽量使用流操作
尽量运用对象池技术以提高系统性能
不要在经常调用的方法中创建对象,尤其是忌讳在循环中创建对象
优化配置
单例模式
public class Singleton{}
懒汉模式
private static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
//懒汉模式(线程不安全)
return instance == null ? new Singleton() : instance;
}
线程安全懒汉模式
private static Singleton instance = null;
private Singleton() {
}
public static synchronized Singleton getInstance() {
//懒汉模式(加锁,线程安全)
return instance == null ? new Singleton() : instance;
}
饿汉模式
//饿汉模式
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
变种饿汉模式
饿汉变种模式
private static Singleton instance = null;
private Singleton() {
}
static {
instance = new Singleton();
}
public static Singleton getInstance(){
return instance;
}
静态内部类
//静态内部类
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
双重校验锁
//双重校验锁
//volatile是一个类型[修饰符]
//(type specifier)。
// 它是被设计用来修饰被不同线程访问和修改的变量。
// 如果不加入 volatile,基本上会导致这样的结果:
// 要么无法编写多线程 程序,要么[编译器] 失去大量优化的机会
private volatile static Singleton instance;
private Singleton() {
}
public static Singleton getSingleton() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
观察者模式
eg:
OnCLickListener
EventBus
冒泡排序
public void bubbleSort(int[] a) {
int temp = 0;
for (int i = 0; i < a.length - 1; i++) {
for (int j = 0; j < a.length - i - 1; j++) {
if (a[j] > a[j + 1]) {
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
}
查找排序
public void selectorSort(int[] a) {
for (int i = 0; i < a.length; i++) {
int min = i;
for (int j = i + 1; j < a.length; j++) {
if (a[j] < a[min]) {
min = j;
}
}
if (i != min) {
int tmp = a[i];
a[i] = a[min];
a[min] = tmp;
}
}
}
快速排序
public void quickSort(int[] data, int start, int end) {
// 设置关键数据key为要排序数组的第一个元素,
// 即第一趟排序后,key右边的数全部比key大,key左边的数全部比key小
int key = data[start];
// 设置数组左边的索引,往右移动比key大的数
int i = start;
// 设置数组右边的索引,往左移动比key小的数
int j = end;
// 如果左边索引比右边索引小,则还有数据没有排序
while (i < j) {
while (data[j] >= key && j > i) {
j--;
}
data[i] = data[j];
while (data[i] < key && i < j) {
i++;
}
data[j] = data[i];
}
// 此时 i==j
data[i] = key;
// 递归调用
if (i - 1 > start) {
// 递归调用,把key前面的完成排序
quickSort(data, start, i - 1);
}
if (i + 1 < end) {
// 递归调用,把key后面的完成排序
quickSort(data, i + 1, end);
}
}