列表
SoftReference和WeakReference
当try{}中有return时,finally{}中的代码还会不会被执行?
sendMessage和sendToTarget,一个是Handler类的方法, 一个是Message类的方法
Android 更新UI的两种方法——handler和runOnUiThread(runnable)
为什么在方法内创建匿名内部类的对象时, 方法中的局部变量要声明为final的
反射的应用场景
transient关键字
@SuppressWarings注解的作用
什么时候用接口, 什么时候用抽象类.
什么是抽象类和匿名内部类,以及为什么要使用它们
volatile关键字修饰的变量, 对其操作为原子级.
定义static内部类就相当于直接写了一个.java的文件
StringBuffer和StringBuilder的区别
JSONObject optString与getString的区别
=========================================
SoftReference和WeakReference
强引用: 直接的对象引用
软引用 SoftReference : 当一个对象只有软引用存在时,系统内存不足时此对象会被gc回收.
String str=new String("abc");
SoftReference softRef=new SoftReference(str);
String str2 = softRef.get();
if(str2 != null) {
//直接使用
} else {
//已经被gc回收
}
弱引用 WeakReference : 当一个对象只有弱引用存在时,此对象会随时被gc回收.
弱引用是最弱的.
String str=new String("abc");
WeakReference weakRef=new WeakReference(str);
String str2 = weakRef.get();
if(str2 != null) {
//直接使用
} else {
//已经被gc回收
}
当try{}中有return时,finally{}中的代码还会不会被执行?
yes
public static void main() {
int a = f_test();
Log.i("ahking","333, a = " +a);
}
public static int f_test() {
int a = 0;
try {
a = 1;
Log.i("ahking","111");
return a;
} finally {
Log.i("ahking","222");
a = 2;
return a;
}
}
logcat:
10-22 08:02:33.871 19565-19565/com.qihoo.browser I/ahking﹕ 111
10-22 08:02:33.871 19565-19565/com.qihoo.browser I/ahking﹕ 222
10-22 08:02:33.871 19565-19565/com.qihoo.browser I/ahking﹕ 333, a = 2
结论:
try{}中有return; finally{}也会被执行.
finally{}中如果有return;將覆盖try{}中的return,作为函数的出口. 但不是一个好的编程习惯, 这点了解一下即可, 实际开发中不要这么用.
sendMessage和sendToTarget,一个是Handler类的方法, 一个是Message类的方法
Message message = mHandler.obtainMessage();
message.what = MSG_QUERY_MOBILE_BOOKMARK;
message.obj = infos;
message.sendToTarget();//实际上调用的就是创建message时用的handler对象.
就相当于:
Message msg = Message.obtain(null, MSG_HANDLE_LOCATION_FAILED, 0, 0);
mHandler.sendMessage(msg);
源码:
Handler.java
public final Message obtainMessage()
{
return Message.obtain(this);
}
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
Message.java
Handler target;
public void sendToTarget() {
target.sendMessage(this);
}
Android 更新UI的两种方法——handler和runOnUiThread(runnable)
通过handler执行更新UI的任务,是最常用的方法, 这里就不多说了, 除了这个方法, android还为Activity类提供了一个runOnUiThread(runnable)方法, 也可以用来执行更新UI的任务.
创建Activity对象时, 会在它内部创建一个Handler对象, 目的就是不管在UI线程还是非UI线程中, 都能够通过Activity的对象调用runOnUiThread(runnable)去执行一个更新UI的任务. 如果runOnUiThread(runnable)执行在UI线程,那么这个runnable对象立即执行,如果执行在非UI线程, 那么这个runnable对象就被mHandler封装成msg,压入它所关联的消息队列MessageQueue, 等待UI线程空闲时,被UI线程执行.
Activity.java源码:
public class Activity {
final Handler mHandler = new Handler();
...
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
...
}
为什么在方法内创建匿名内部类的对象时, 方法中的局部变量要声明为final的
内部类通常都含有回调,引用那个匿名内部类的函数执行完了就没了,所以内部类中引用外面的局部变量需要是final的,这样在回调的时候才能找到那个变量,而如果是外围类的成员变量就不需要是final的,因为内部类本身都会含有一个外围了的引用(外围类.this),所以回调的时候一定可以访问到。例如下面:
private Animator createAnimatorView(final View view, final int position) {
MyAnimator animator = new MyAnimator();
animator.addListener(new AnimatorListener() {
@Override
public void onAnimationEnd(Animator arg0) {
Log.d(TAG, "position=" + position);
}
});
return animator;
}
内部类回调里访问position的时候createAnimatorView()早就执行完了,position如果不是final的,回调的时候肯定就无法拿到它的值了,因为局部变量在函数执行完了以后就被回收了。
refer:
http://www.zhihu.com/question/21395848
反射的应用场景
使用被隐藏的类和方法.
package com.android.internal.policy;
import android.content.Context;
import android.view.FallbackEventHandler;
import android.view.LayoutInflater;
import android.view.Window;
import android.view.WindowManagerPolicy;
/**
* {@hide}
*/
public final class PolicyManager {
private static final String POLICY_IMPL_CLASS_NAME =
"com.android.internal.policy.impl.Policy";
private static final IPolicy sPolicy;
static {
// Pull in the actual implementation of the policy at run-time
try {
Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
sPolicy = (IPolicy)policyClass.newInstance();
//这里不能直接 sPolicy = new Policy();而必须要用反射的原因是Policy类的声明也是被隐藏的,尽量Policy类在"impl"子包中, 也必须使用反射才能找到, 不能直接import com.android.internal.policy.impl.Policy; 然后new Policy().
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
POLICY_IMPL_CLASS_NAME + " could not be loaded", ex);
}
// Cannot instantiate this class
private PolicyManager() {}
// The static methods to spawn new policy-specific objects
public static Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context);
}
...
}
transient关键字
加transient关键字的属性, 不会被序列化, 比如银行卡密码等不希望在网络中传输, 就需要加上这个关键字.
public class SerializableCookie implements Serializable {
private static final long serialVersionUID = 6374381828722046732L;
private transient final Cookie cookie;
private transient BasicClientCookie clientCookie;
}
public class HashSet extends AbstractSet implements Set, Cloneable, Serializable {
static final long serialVersionUID = -5024744406713321676L;
private transient HashMap map;
}
@SuppressWarings注解的作用
@SuppressWarings注解
作用:用于抑制编译器产生警告信息。
refer to : http://www.cnblogs.com/fsjohnhuang/p/4040785.html
@SuppressWarnings("UnusedDeclaration")
public class StrictANRWatchDog extends Thread {
//这个类中的某个方法如果没有被使用的话, IDE也不会给出警告信息, 免得代码看起来很繁乱.
什么时候用接口, 什么时候用抽象类.
abstract class中,可以有自己的数据成员,
abstract class中,可以有一部分abstarct成员方法, 其他的也可以是一般的成员方法(给出成员方法的实现).
interface中,一般不定义数据成员,如果定义的话, 也是public static final常量,且必须给其初值.
interface中,所有的成员方法都是abstract的,都没有方法的实现, 只是abstract关键字给省略了.
//abstract class
public abstract class Reader implements Readable, Closeable {
protected Object lock;
protected Reader() {
lock = this;
}
public abstract void close() throws IOException;
public void mark(int readLimit) throws IOException {
throw new IOException();
}
...
}
// interface
public interface ResponseDelivery {
public void postResponse(Request> request, Response> response);
public void postResponse(Request> request, Response> response, Runnable runnable);
public void postError(Request> request, VolleyError error);
}
什么是抽象类和匿名内部类,以及为什么要使用它们
什么是抽象函数
只有函数的定义, 没有函数体的函数被成为抽象函数.
abstract void eat();
什么是抽象类
使用abstract定义的类被称之为抽象类.
- 抽象类不能够生成对象, 但是却可以有构造函数, 提供给子类通过super()方法进行调用.
- 如果一个类当中包含有抽象函数, 那么这个类必须被声明为抽象类.
- 如果一个类中没有抽象函数, 那么这个类也可以被声明为抽象类.
为什么使用抽象类
架构设计的时候为什么要有意识的使用抽象类.
定义一个通用的打印机的基类.
方案1:
class Printer {
void open() {
System.out.println("open()");
}
void close() {
System.out.println("close()");
}
//这里给出一个空的方法体, 让具体的子类去override进行实现.
void print() {
}
}
方案2:
abstract class Printer {
void open() {
System.out.println("open()");
}
void close() {
System.out.println("close()");
}
abstract void print(); //把print()定义为抽象方法.
}
2个方案其实都能实现同样的功能.
抽象类中的抽象方法的设计价值是,通过编译器保证了子类确实对抽象方法进行了实现,如果用一个空函数体的方法代替抽象方法就无法通过编译器去保证子类对这个方法进行了实现.
什么是匿名内部类
匿名内部类的使用地方是:用在方法的参数,一般是new一个接口的对象出来使用.
handler.postDelayed(new Runnable() {
@Override
public void run() {
Log.i(TAG, "Sending file " + filename);
sendCrashData(context, filename, finalJavaCrashCountUploader);
}
}, delayTime);
这里的new Runnable() {}就是一个匿名内部类的对象.
开发中要注意的点:
如果子类的构造方法中没有显示的调用父类构造方法,则系统默认调用父类无参数的构造方法.
class Chinese extends Person {
Chinese() {
System.out.println("Chinese的构造方法");
}
void eat() {
System.out.println("用筷子吃饭");
}
}
等同于:
class Chinese extends Person {
Chinese() {
super();
System.out.println("Chinese的构造方法");
}
void eat() {
System.out.println("用筷子吃饭");
}
}
volatile关键字修饰的变量, 对其操作为原子级.
有一个例外是, 如果当前值与该变量以前的值相关,
那么volatile关键字不起作用,也就是说如下的表达式都不是原子操作:
public static volatile int n = 0;
n = n + 1;
n++;
在这种情况下,可使用synchronized关键字实现对其变量操作的原子性.
public static int n = 0;
public static synchronized void inc()
{
n++;
}
详见:
http://developer.51cto.com/art/200906/132344.htm(初学Java多线程:慎重使用volatile关键字)
定义static内部类就相当于直接写了一个.java的文件
主要是防止内存泄露,使用static 相当于直接写了一个.java的文件,
与外部类就没有依赖关系了,详见
http://stackoverflow.com/questions/70324/java-inner-class-and-static-nested-class
普通内部类隐含有个成员变量this$0, 持有对外部类的引用, this$0变量在内部类的默认构造方法中, 用外部类对象对其进行的赋值.
StringBuffer和StringBuilder的区别
1.使用String类的场景:在字符串不经常变化的场景中可以使用String类,例如常量的声明、少量的变量运算。
2.使用StringBuffer类的场景:在频繁进行字符串运算(如拼接、替换、删除等),并且运行在多线程环境中,则可以考虑使用StringBuffer,例如XML解析、HTTP参数解析和封装。
3.使用StringBuilder类的场景:在频繁进行字符串运算(如拼接、替换、和删除等),并且运行在单线程的环境中,则可以考虑使用StringBuilder,如SQL语句的拼装、JSON封装等。
结论:
StringBuffer是线程安全的,有加锁开销,效率略低。StringBuilder非线程安全,不用加锁,效率更高。一般字符串相加不会有多线程操作,所以推荐使用StringBuilder.
很少碰到这种情况, StringBuilder sb = new StringBuilder(); 然后在2个线程中, 同时分别调用sb.append("abc")和sb.append("123"); 在这种情况下, 最终sb的结果就会不符合预期.
但很少使用多线程对一个字符串进行相加操作, 因此大多数情况下, 优先使用StringBuilder > StringBuffer.
JSONObject optString与getString的区别
getString(String name)与optString(String name),功能一样,只是当name key 不存在时,getString(String name)抛出异常错误,optString(String name)返回空值.