www.itlanbao.com 本网站里面分享不少Android特效,更多的面试资料在IT蓝豹资讯部分 ,但愿可以给你帮助,欢迎到IT蓝豹上互相学习。html
|
ArrayListjava |
Vectorandroid |
LinkedList程序员 |
实现原理web |
数组面试 |
数组算法 |
双向链表数据库 |
线程安全编程 |
否设计模式 |
是 |
否 |
优势 |
1.数组实现优于遍历 |
1.数组实现优于遍历 |
1.节点的增删无需对象的重建 |
缺点 |
1.非线程安全 |
1.数组中未使用的元素形成空间的浪费 |
1.遍历效率较低 |
扩容 |
0.5倍增量 |
1倍增量 |
按需增删 |
使用场景 |
1.无线程的要求。 |
1.有线程安全的要求 |
增删场景较多的时候 |
11.int与Integer的区别
|
int |
Integer |
类型 |
基本类型 |
复合类型 |
默认值 |
0 |
null |
存储 |
栈(局部变量) |
堆上(只能经过new建立) |
方法 |
基本类型无方法 |
有 |
速度 |
快(栈上 的操做相对快) |
慢 |
泛型支持 |
否(java中的泛型不支持,C++中的模板支持) |
支持 |
容器类支持 |
否(直接使用一般会进行装箱操做) |
支持 |
存在乎义 |
1.历史缘由(顺延C/C++中存在) |
基本类型int的包装类 |
Checked Exception:在编译时就可以被Java编译器所检测到的。
UncheckedException:则是编译时,java编译器不能检查到。
|
RuntimeException |
普通Exception |
Error |
受控异常 |
否 |
是 |
否 |
产生缘由 |
开发者的编程错误 |
因为外界环境所限, |
Java运行时的系统错误,资源耗尽,是一种严重的, |
例子 |
NullPointerException |
ClassNotFoundException |
VirtualMachineError |
final:关键字,表不变
修饰:
· 方法:方法不可Override
· 类:不可被继承
· 基本类型量:常量,值不可变
· 符合类型量:引用不可变,即引用的值不可变
[java] view plaincopy
1. final Object o1 = new Object();
2. o1 = new Object();
finally:关键字,Java异常处理机制的一部分,在异常发生时,用来提供一个必要的清理的机会。
finalize:Object类的方法(参考自百度百科)
意义:Java技术容许使用finalize()方法在垃圾回收器将对象回收以前,作一些必要的清理操做。
调用前提:这个对象肯定没有被引用到。
工做原理:
· 垃圾收集器准备好释放对象占用的空间。
· 首先调用其finalize方法。
· 下一次垃圾收集过程当中,真正回收内存。
不肯定性:
· finalize的执行时间是不缺定的。
· 一个对象引用另外一个对象,并不能保证finalize的方法按照特定的执行顺序。
|
Override |
Overload |
签名+返回值 |
相同 |
方法名相同,签名不一样 |
关系 |
父子类继承关系 |
一般是同一类层次中 |
识别 |
运行时多态 |
编译时多态 |
修饰符限制 |
非private |
无特别 |
异常关系 |
子类方法不能抛出被父类方法更多的异常 |
无特别 |
可见性关系 |
子类不能比父类访问权限更窄 |
无特别 |
Collection:接口,集合类的接口,一个契约,提供了集合基本的大小,添加,清除,遍历方法等。
Collections:工具类,提供了不少静态方法,给集合提供一些查询,比较,排序,交换,线程安全化等方法。
package com.jue.test;
public class TestMain {
public static void main(String[] args) {
Integer i1 = 1;
Integer i11 = 1;
System.out.println(i1 == i11);
Integer i2 = 200;
Integer i22 = 200;
System.out.println(i2 == i22);
}
}
结果 :True,false
分析:反编译结果为 Integer i1 = Integer.valueOf(1);
能够看出,对于Integer i = 1;编译器作了额外的处理,即Integer.valueof();能够看出Integer对于必定 范围内的数字从Cache中取得,对于额外的,调用new建立。
故能够知道Integer的大小,默认是从-128到127,对于这个范围内的数组作了缓存的处理。 对于额外的,调用new建立
|
wait |
sleep |
所属类 |
Object |
Thread |
意义 |
让线程挂起 |
让线程休眠指定的时间 |
释放锁 |
是 |
否(这个跟锁原本就没有关系) |
恢复 |
1.有参:wait指定时间 |
1.根据参数长度自动恢复。 |
使用限制 |
wait,notify必须持有当前对象锁的状况下调用 |
无特别 |
抛出异常 |
否 |
是 |
静态方法 |
否 |
是 |
HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap容许空(null)键值(key),因为非线程安全,效率上可能高于Hashtable。
HashMap容许将null做为一个entry的key或者value,而Hashtable不容许。
HashMap把Hashtable的contains方法去掉了,改为containsvalue和containsKey。由于contains方法容易让人引发误解。
整体来讲设计模式分为三大类:
建立型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
其实还有两类:并发型模式和线程池模式。用一个图片来总体描述一下:
http://www.cnblogs.com/maowang1991/archive/2013/04/15/3023236.html
首先,建立两者的共同接口:
[java] view plaincopy
1. public interface Sender {
2. public void Send();
3. }
其次,建立实现类:
[java] view plaincopy
1. public class MailSender implements Sender {
2. @Override
3. public void Send() {
4. System.out.println("this is mailsender!");
5. }
6. }
[java] view plaincopy
1. public class SmsSender implements Sender {
2.
3. @Override
4. public void Send() {
5. System.out.println("this is sms sender!");
6. }
7. }
最后,建工厂类:
[java] view plaincopy
1. public class SendFactory {
2.
3. public Sender produce(String type) {
4. if ("mail".equals(type)) {
5. return new MailSender();
6. } else if ("sms".equals(type)) {
7. return new SmsSender();
8. } else {
9. System.out.println("请输入正确的类型!");
10. return null;
11. }
12. }
13. }
咱们来测试下:
1. public class FactoryTest {
2.
3. public static void main(String[] args) {
4. SendFactory factory = new SendFactory();
5. Sender sender = factory.produce("sms");
6. sender.Send();
7. }
8. }
输出:this is sms sender!
a、多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,若是传递的字符串出错,则不能正确建立对象,而多个工厂方法模式是提供多个工厂方法,分别建立对象。关系图:
将上面的代码作下修改,改动下SendFactory类就行,以下:
[java] view plaincopypublic class SendFactory {
public Sender produceMail(){
1. return new MailSender();
2. }
3.
4. public Sender produceSms(){
5. return new SmsSender();
6. }
7. }
测试类以下:
[java] view plaincopy
1. public class FactoryTest {
2.
3. public static void main(String[] args) {
4. SendFactory factory = new SendFactory();
5. Sender sender = factory.produceMail();
6. sender.Send();
7. }
8. }
输出:this is mailsender!
b、静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不须要建立实例,直接调用便可。
[java] view plaincopy
1. public class SendFactory {
2.
3. public static Sender produceMail(){
4. return new MailSender();
5. }
6.
7. public static Sender produceSms(){
8. return new SmsSender();
9. }
10. }
[java] view plaincopy
1. public class FactoryTest {
2.
3. public static void main(String[] args) {
4. Sender sender = SendFactory.produceMail();
5. sender.Send();
6. }
7. }
输出:this is mailsender!
整体来讲,工厂模式适合:凡是出现了大量的产品须要建立,而且具备共同的接口时,能够经过工厂方法模式进行建立。在以上的三种模式中,第一种若是传 入的字符串有误,不能正确建立对象,第三种相对于第二种,不须要实例化工厂类,因此,大多数状况下,咱们会选用第三种——静态工厂方法模式。
能够看出工厂方法的加入,使得对象的数量成倍增加。当产品种类很是多时,会出现大量的与之对应的工厂对象,这不是咱们所但愿的。由于若是不能避免这种情 况,能够考虑使用简单工厂模式与工厂方法模式相结合的方式来减小工厂类:即对于产品树上相似的种类(通常是树的叶子中互为兄弟的)使用简单工厂模式来实 现。
c、简单工厂和工厂方法模式的比较
工厂方法模式和简单工厂模式在定义上的不一样是很明显的。工厂方法模式的核心是一个抽象工厂类,而不像简单工厂模式, 把核心放在一个实类上。工厂方法模式能够容许不少实的工厂类从抽象工厂类继承下来, 从而能够在实际上成为多个简单工厂模式的综合,从而推广了简单工厂模式。
反过来说,简单工厂模式是由工厂方法模式退化而来。设想若是咱们很是肯定一个系统只须要一个实的工厂类, 那么就不妨把抽象工厂类合并到实的工厂类中去。而这样一来,咱们就退化到简单工厂模式了。
d、抽象工厂模式
代码:
//抽象工厂类
public abstract class AbstractFactory {
public abstract Vehicle createVehicle();
public abstract Weapon createWeapon();
public abstract Food createFood();
}
//具体工厂类,其中Food,Vehicle,Weapon是抽象类,
public class DefaultFactory extends AbstractFactory{
@Override
public Food createFood() {
return new Apple();
}
@Override
public Vehicle createVehicle() {
return new Car();
}
@Override
public Weapon createWeapon() {
return new AK47();
}
}
//测试类
public class Test {
public static void main(String[] args) {
AbstractFactory f = new DefaultFactory();
Vehicle v = f.createVehicle();
v.run();
Weapon w = f.createWeapon();
w.shoot();
Food a = f.createFood();
a.printName();
}
}
在抽象工厂模式中,抽象产品 (AbstractProduct) 多是一个或多个,从而构成一个或多个产品族(Product Family)。 在只有一个产品族的状况下,抽象工厂模式实际上退化到工厂方法模式。
6、总结。
(1)简单工厂模式是由一个具体的类去建立其余类的实例,父类是相同的,父类是具体的。
(2)工厂方法模式是有一个抽象的父类定义公共接口,子类负责生成具体的对象,这样作的目的是将类的实例化操做延迟到子类中完成。
(3)抽象工厂模式提供一个建立一系列相关或相互依赖对象的接口,而无须指定他们具体的类。它针对的是有多个产品的等级结构。而工厂方法模式针对的是一个产品的等级结构。
单例对象(Singleton)是一种经常使用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处:
1、某些类建立比较频繁,对于一些大型的对象,这是一笔很大的系统开销。
2、省去了new操做符,下降了系统内存的使用频率,减轻GC压力。
3、有些类如交易所的核心交易引擎,控制着交易流程,若是该类能够建立多个的话,系统彻底乱了。(好比一个军队出现了多个司令员同时指挥,确定会乱成一团),因此只有使用单例模式,才能保证核心交易服务器独立控制整个流程。
首先咱们写一个简单的单例类:
[java] view plaincopy
1. public class Singleton {
2.
3. /* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */
4. private static Singleton instance = null;
5.
6. /* 私有构造方法,防止被实例化 */
7. private Singleton() {
8. }
9.
10. /* 静态工程方法,建立实例 */
11. public static Singleton getInstance() {
12. if (instance == null) {
13. instance = new Singleton();
14. }
15. return instance;
16. }
17.
18. /* 若是该对象被用于序列化,能够保证对象在序列化先后保持一致 */
19. public Object readResolve() {
20. return instance;
21. }
22. }
这个类能够知足基本要求,可是,像这样毫无线程安全保护的类,若是咱们把它放入多线程的环境下,确定就会出现问题了,如何解决?咱们首先会想到对getInstance方法加synchronized关键字,以下:
[java] view plaincopy
1. public static synchronized Singleton getInstance() {
2. if (instance == null) {
3. instance = new Singleton();
4. }
5. return instance;
6. }
可是,synchronized关键字锁住的是这个对象,这样的用法,在性能上会有所降低,由于每次调用getInstance(),都要对对象上锁,事实上,只有在第一次建立对象的时候须要加锁,以后就不须要了,因此,这个地方须要改进。咱们改为下面这个:
[java] view plaincopy
1. public static Singleton getInstance() {
2. if (instance == null) {
3. synchronized (instance) {
4. if (instance == null) {
5. instance = new Singleton();
6. }
7. }
8. }
9. return instance;
10. }
1、最简单的实现
首先,能想到的最简单的实现是,把类的构造函数写成private的,从而保证别的类不能实例化此类。而后在类中返回一个静态示例并返回给调用者。这样,调用者就能够经过这个引用使用这个实例了。
public class Singleton{ private static final Singleton singleton = new Singleton(); public static Singleton getInstance(){ return singleton; } private Singleton(){ }}
如上例,外部使用者若是须要使用SingletonClass的实例,只能经过getInstance()方法,而且它的构造方法是private的,这样就保证了只能有一个对象存在。
2、性能优化--lazy loaded
上面的代码虽然简单,可是有一个问题----不管这个类是否被使用,都会建立一个instance对象。若是这个建立很耗时,好比说连接10000次数据库(夸张一点啦....),而且这个类还不必定会被使用,那么这个建立过程就是无用的,怎么办呢?
为了解决这个问题,咱们想到的新的解决方案:
public class SingletonClass { private static SingletonClass instance = null; public static SingletonClass getInstance() { if(instance == null) { instance = new SingletonClass(); } return instance; } private SingletonClass() { } }
代码的变化有俩处----首先,把 instance 设置为 null ,知道第一次使用的时候判是否为 null 来建立对象。由于建立对象不在声明处,因此那个 final 的修饰必须去掉。
咱们来想象一下这个过程。要使用 SingletonClass ,调用 getInstance()方法,第一次的时候发现instance时null,而后就建立一个对象,返回出去;第二次再使用的时候,由于这个 instance事static的,共享一个对象变量的,因此instance的值已经不是null了,所以不会再建立对象,直接将其返回。
这个过程就称为lazy loaded ,也就是迟加载-----直到使用的时候才经行加载。
这样写法也比较完美:可是还能够优化
public class SingletonClass{ private static SingletonClass instance = null; public static SingletonClass getInstance(){ if(instance == null){ synchronized(SingletonClass.class){ if(instance == null){ instance = new SingletonClass(); } } } return instance; } private SingletonClass(){ } }
经过单例模式的学习告诉咱们:
1、单例模式理解起来简单,可是具体实现起来仍是有必定的难度。
2、synchronized关键字锁定的是对象,在用的时候,必定要在恰当的地方使用(注意须要使用锁的对象和过程,可能有的时候并非整个对象及整个过程都须要锁)。
到这儿,单例模式基本已经讲完了,结尾处,笔者忽然想到另外一个问题,就是采用类的静态方法,实现单例模式的效果,也是可行的,此处两者有什么不一样?
首先,静态类不能实现接口。(从类的角度说是能够的,可是那样就破坏了静态了。由于接口中不容许有static修饰的方法,因此即便实现了也是非静态的)
其次,单例能够被延迟初始化,静态类通常在第一次加载是初始化。之因此延迟加载,是由于有些类比较庞大,因此延迟加载有助于提高性能。
再次,单例类能够被继承,他的方法能够被覆写。可是静态类内部方法都是static,没法被覆写。
最后一点,单例类比较灵活,毕竟从实现上只是一个普通的Java类,只要知足单例的基本需求,你能够在里面为所欲为的实现一些其它功能,可是静态类 不行。从上面这些归纳中,基本能够看出两者的区别,可是,从另外一方面讲,咱们上面最后实现的那个单例模式,内部就是用一个静态类来实现的,因此,两者有很 大的关联,只是咱们考虑问题的层面不一样罢了。两种思想的结合,才能造就出完美的解决方案,就像HashMap采用数组+链表来实现同样,其实生活中不少事 情都是这样,单用不一样的方法来处理问题,老是有优势也有缺点,最完美的方法是,结合各个方法的优势,才能最好的解决问题!
工厂类模式提供的是建立单个类的模式,而建造者模式则是将各类产品集中起来进行管理,用来建立复合对象,所谓复合对象就是指某个类具备不一样的属性,其实建造者模式就是前面抽象工厂模式和最后的Test结合起来获得的。咱们看一下代码:
还和前面同样,一个Sender接口,两个实现类MailSender和SmsSender。最后,建造者类以下:
[java] view plaincopy
1. public class Builder {
2.
3. private List<Sender> list = new ArrayList<Sender>();
4.
5. public void produceMailSender(int count){
6. for(int i=0; i<count; i++){
7. list.add(new MailSender());
8. }
9. }
10.
11. public void produceSmsSender(int count){
12. for(int i=0; i<count; i++){
13. list.add(new SmsSender());
14. }
15. }
16. }
测试类:
[java] view plaincopy
1. public class Test {
2.
3. public static void main(String[] args) {
4. Builder builder = new Builder();
5. builder.produceMailSender(10);
6. }
7. }
从这点看出,建造者模式将不少功能集成到一个类里,这个类能够创造出比较复杂的东西。因此与工程模式的区别就是:工厂模式关注的是建立单个产品,而建造者模式则关注建立符合对象,多个部分。所以,是选择工厂模式仍是建造者模式,依实际状况而定。
原型模式虽然是建立型的模式,可是与工程模式没有关系,从名字便可看出,该模式的思想就是将一个对象做为原型,对其进行复制、克隆,产生一个和原对象相似的新对象。本小结会经过对象的复制,进行讲解。在Java中,复制对象是经过clone()实现的,先建立一个原型类:
[java] view plaincopy
1. public class Prototype implements Cloneable {
2.
3. public Object clone() throws CloneNotSupportedException {
4. Prototype proto = (Prototype) super.clone();
5. return proto;
6. }
7. }
很简单,一个原型类,只须要实现Cloneable接口,覆写clone方法,此处clone方法能够改为任意的名称,由于Cloneable接口 是个空接口,你能够任意定义实现类的方法名,如cloneA或者cloneB,由于此处的重点是super.clone()这句 话,super.clone()调用的是Object的clone()方法,而在Object类中,clone()是native的,具体怎么实现,我会 在另外一篇文章中,关于解读Java中本地方法的调用,此处再也不深究。在这儿,我将结合对象的浅复制和深复制来讲一下,首先须要了解对象深、浅复制的概念:
浅复制:将一个对象复制后,基本数据类型的变量都会从新建立,而引用类型,指向的仍是原对象所指向的。
深复制:将一个对象复制后,不管是基本数据类型还有引用类型,都是从新建立的。简单来讲,就是深复制进行了彻底完全的复制,而浅复制不完全。
此处,写一个深浅复制的例子:
[java] view plaincopy
1. public class Prototype implements Cloneable, Serializable {
2.
3. private static final long serialVersionUID = 1L;
4. private String string;
5.
6. private SerializableObject obj;
7.
8. /* 浅复制 */
9. public Object clone() throws CloneNotSupportedException {
10. Prototype proto = (Prototype) super.clone();
11. return proto;
12. }
13.
14. /* 深复制 */
15. public Object deepClone() throws IOException, ClassNotFoundException {
16.
17. /* 写入当前对象的二进制流 */
18. ByteArrayOutputStream bos = new ByteArrayOutputStream();
19. ObjectOutputStream oos = new ObjectOutputStream(bos);
20. oos.writeObject(this);
21.
22. /* 读出二进制流产生的新对象 */
23. ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
24. ObjectInputStream ois = new ObjectInputStream(bis);
25. return ois.readObject();
26. }
27.
28. public String getString() {
29. return string;
30. }
31.
32. public void setString(String string) {
33. this.string = string;
34. }
35.
36. public SerializableObject getObj() {
37. return obj;
38. }
39.
40. public void setObj(SerializableObject obj) {
41. this.obj = obj;
42. }
43.
44. }
45.
46. class SerializableObject implements Serializable {
47. private static final long serialVersionUID = 1L;
48. }
要实现深复制,须要采用流的形式读入当前对象的二进制输入,再写出二进制数据对应的对象。
咱们接着讨论设计模式,上篇文章我讲完了5种建立型模式,这章开始,我将讲下7种结构型模式:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。其中对象的适配器模式是各类模式的起源,咱们看下面的图:
适配器模式将某个类的接口转换成客户端指望的另外一个接口表示,目的是消除因为接口不匹配所形成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。首先,咱们来看看类的适配器模式,先看类图:
核心思想就是:有一个Source类,拥有一个方法,待适配,目标接口时Targetable,经过Adapter类,将Source的功能扩展到Targetable里,看代码:
[java] view plaincopy
1. public class Source {
2.
3. public void method1() {
4. System.out.println("this is original method!");
5. }
6. }
[java] view plaincopy
1. public interface Targetable {
2.
3. /* 与原类中的方法相同 */
4. public void method1();
5.
6. /* 新类的方法 */
7. public void method2();
8. }
[java] view plaincopy
1. public class Adapter extends Source implements Targetable {
2.
3. @Override
4. public void method2() {
5. System.out.println("this is the targetable method!");
6. }
7. }
Adapter类继承Source类,实现Targetable接口,下面是测试类:
[java] view plaincopy
1. public class AdapterTest {
2.
3. public static void main(String[] args) {
4. Targetable target = new Adapter();
5. target.method1();
6. target.method2();
7. }
8. }
输出:
this is original method!
this is the targetable method!
这样Targetable接口的实现类就具备了Source类的功能
将以前介绍的全部排序算法整理成NumberSort类,代码
NumberSort
Java语言引入了Java虚拟机,具备跨平台运行的功能,可以很好地适应各类Web应用。同时,为了提升Java语言的性能和健壮性,还引入了如垃圾回收机制等新功能,经过这些改进让Java具备其独特的工做原理。
1.Java虚拟机
Java源程序经过编译器编译成.Class文件,而后java虚拟机中的java 解释器负责将字节码文件解释成为特定的机器码进行运行。
java是一种半编译半解释型语言。半编译是指:java源代码,会通过javac命令变成 .class文件。半解释是指: .class文件被jvm解释的过程。也就是由于jvm的半解释才有了java的动态语言特性:反射和annotation。
和android区别
alvik有本身的libdex库负责对.class进行处理。libdex主要对.class进行处理生成本身的dex文件。主要作的工做是,对虚拟机指令进行转换(dalvik是基于寄存器的,sun虚拟机是基于栈的),对类的静态数据进行归类、压缩。
dalvik基于寄存器,而JVM基于stack ,Dalvik执行的是特有的DEX文件格式,而JVM运行的是*.class文件格式。
优点:1、在编译时提早优化代码而不是等到运行时
2、 虚拟机很小,使用的空间也小;被设计来知足可高效运行多种虚拟机实例。
Java虚拟机的创建须要针对不一样的软硬件平台来实现,既要考虑处理器的型号,也要考虑操做系统的种类。由此在SPARC结构、X86结构、MIPS和PPC等嵌入式处理芯片上,在UNIX、Linux、Windows和部分实时操做系统上均可实现Java虚拟机。
2.无用内存自动回收机制
而在Java运行环境中,始终存在着一个系统级的线程,专门跟踪内存的使用状况, 按期检测出再也不使用的内存,并自动进行回收,避免了内存的泄露,也减轻了程序员的工做量。
1.JVM
JVM是Java平台的核心,为了让编译产生的字节码能更好地解释与执行,所以把JVM分红了6个部分:JVM解释器、指令系统、寄存器、栈、存储区和碎片回收区。
能够很明显看出,Android系统架构由5部分组成,分别是:Linux Kernel、Android Runtime、Libraries、Application Framework、Applications。第二部分将详细介绍这5个部分。
如今咱们拿起手术刀来剖析各个部分。其实这部分SDK文档已经帮咱们作得很好了,咱们要作的就是拿来主义,而后再加上本身理解。下面自底向上分析各层。
Android基于Linux 2.6提供核心系统服务,例如:安全、内存管理、进程管理、网络堆栈、驱动模型。Linux Kernel也做为硬件和软件之间的抽象层,它隐藏具体硬件细节而为上层提供统一的服务。
Android 包含一个核心库的集合,提供大部分在Java编程语言核心类库中可用的功能。每个Android应用程序是Dalvik虚拟机中的实例,运行在他们本身 的进程中。Dalvik虚拟机设计成,在一个设备能够高效地运行多个虚拟机。Dalvik虚拟机可执行文件格式是.dex,dex格式是专为Dalvik 设计的一种压缩格式,适合内存和处理器速度有限的系统。
大多数虚拟机包括JVM都是基于栈的,而Dalvik虚拟机则是基于寄存器的。 两种架构各有优劣,通常而言,基于栈的机器须要更多指令,而基于寄存器的机器指令更大。dx 是一套工具,能够將 Java .class 转换成 .dex 格式。一个dex文件一般会有多个.class。因为dex有時必须进行最佳化,会使文件大小增长1-4倍,以ODEX结尾。
Dalvik虚拟机依赖于Linux 内核提供基本功能,如线程和底层内存管理。
Android包含一个C/C++库的集合,供Android系统的各个组件使用。这些功能经过Android的应用程序框架(application framework)暴露给开发者。下面列出一些核心库:
· 系统C库——标准C系统库(libc)的BSD衍生,调整为基于嵌入式Linux设备
· 媒体库——基于PacketVideo的OpenCORE。这些库支持播放和录制许多流行的音频和视频格式,以及静态图像文件,包括MPEG4、 H.264、 MP3、 AAC、 AMR、JPG、 PNG
· 界面管理——管理访问显示子系统和无缝组合多个应用程序的二维和三维图形层
· LibWebCore——新式的Web浏览器引擎,驱动Android 浏览器和内嵌的web视图
· SGL——基本的2D图形引擎
· 3D库——基于OpenGL ES 1.0 APIs的实现。库使用硬件3D加速或包含高度优化的3D软件光栅
· FreeType ——位图和矢量字体渲染
· SQLite ——全部应用程序均可以使用的强大而轻量级的关系数据库引擎
经过提供开放的开发平台,Android使开发者可以编制极其丰富和新颖的应用程序。开发者能够自由地利用设备硬件优点、访问位置信息、运行后台服务、设置闹钟、向状态栏添加通知等等,不少不少。
开发者能够彻底使用核心应用程序所使用的框架APIs。应用程序的体系结构旨在简化组件的重用,任何应用程序都能发布他的功能且任何其余应用程序能够使用这些功能(须要服从框架执行的安全限制)。这一机制容许用户替换组件。
全部的应用程序实际上是一组服务和系统,包括:
· 视图(View)——丰富的、可扩展的视图集合,可用于构建一个应用程序。包括包括列表、网格、文本框、按钮,甚至是内嵌的网页浏览器
· 内容提供者(Content Providers)——使应用程序能访问其余应用程序(如通信录)的数据,或共享本身的数据
· 资源管理器(Resource Manager)——提供访问非代码资源,如本地化字符串、图形和布局文件
· 通知管理器(Notification Manager)——使全部的应用程序可以在状态栏显示自定义警告
· 活动管理器(Activity Manager)——管理应用程序生命周期,提供通用的导航回退功能
Android装配一个核心应用程序集合,包括电子邮件客户端、SMS程序、日历、地图、浏览器、联系人和其余设置。全部应用程序都是用Java编程语言写的。更加丰富的应用程序有待咱们去开发!
1、Socket通讯简介
Android 与服务器的通讯方式主要有两种,一是Http通讯,一是Socket通讯。二者的最大差别在于,http链接使用的是“请求—响应方式”,即在请求时创建 链接通道,当客户端向服务器发送请求后,服务器端才能向客户端返回数据。而Socket通讯则是在双方创建起链接后就能够直接进行数据的传输,在链接时可 实现信息的主动推送,而不须要每次由客户端想服务器发送请求。 那么,什么是socket?Socket又称套接字,在程序内部提供了与外界通讯的端口,即端口通讯。经过创建socket链接,可为通讯双方的数据传输 传提供通道。socket的主要特色有数据丢失率低,使用简单且易于移植。
1.2Socket的分类
根据不一样的的底层协议,Socket的实现是多样化的。本指南中只介绍TCP/IP协议族的内容,在这个协议族当中主要的Socket类型为流套接字 (streamsocket)和数据报套接字(datagramsocket)。流套接字将TCP做为其端对端协议,提供了一个可信赖的字节流服务。数据 报套接字使用UDP协议,提供数据打包发送服务。
2、Socket 基本通讯模型
3、Socket基本实现原理
3.1基于TCP协议的Socket
服务器端首先声明一个ServerSocket对象而且指定端口号,而后调 用Serversocket的accept()方法接收客户端的数据。accept()方法在没有数据进行接收的处于堵塞状态。 (Socketsocket=serversocket.accept()),一旦接收到数据,经过inputstream读取接收的数据。
客户端建立一个Socket对象,指定服务器端的ip地址和端口号 (Socketsocket=newSocket("172.168.10.108",8080);),经过inputstream读取数据,获取服务器 发出的数据(OutputStreamoutputstream=socket.getOutputStream()),最后将要发送的数据写入到 outputstream便可进行TCP协议的socket数据传输。
3.2基于UDP协议的数据传输
服务器端首先建立一个DatagramSocket对象,而且指点监听的端 口。接下来建立一个空的DatagramSocket对象用于接收数据 (bytedata[]=newbyte[1024;]DatagramSocketpacket=newDatagramSocket(data,data.length)), 使用DatagramSocket的receive方法接收客户端发送的数据,receive()与serversocket的accepet()相似, 在没有数据进行接收的处于堵塞状态。
客户端也建立个DatagramSocket对象,而且指点监听的端口。接 下来建立一个InetAddress对象,这个对象相似与一个网络的发送地址 (InetAddressserveraddress=InetAddress.getByName("172.168.1.120")).定义要发送的 一个字符串,建立一个DatagramPacket对象,并制定要讲这个数据报包发送到网络的那个地址以及端口号,最后使用DatagramSocket 的对象的send()发送数据。*(Stringstr="hello";bytedata[]=str.getByte(); DatagramPacketpacket=new DatagramPacket(data,data.length,serveraddress,4567);socket.send(packet);)
4、android 实现socket简单通讯
4.1使用TCP协议通讯
android端实现:
[java] view plaincopy
1. protected void connectServerWithTCPSocket() {
2.
3. Socket socket;
4. try {// 建立一个Socket对象,并指定服务端的IP及端口号
5. socket = new Socket("192.168.1.32", 1989);
6. // 建立一个InputStream用户读取要发送的文件。
7. InputStream inputStream = new FileInputStream("e://a.txt");
8. // 获取Socket的OutputStream对象用于发送数据。
9. OutputStream outputStream = socket.getOutputStream();
10. // 建立一个byte类型的buffer字节数组,用于存放读取的本地文件
11. byte buffer[] = new byte[4 * 1024];
12. int temp = 0;
13. // 循环读取文件
14. while ((temp = inputStream.read(buffer)) != -1) {
15. // 把数据写入到OuputStream对象中
16. outputStream.write(buffer, 0, temp);
17. }
18. // 发送读取的数据到服务端
19. outputStream.flush();
20.
21. /** 或建立一个报文,使用BufferedWriter写入,看你的需求 **/
22. // String socketData = "[2143213;21343fjks;213]";
23. // BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
24. // socket.getOutputStream()));
25. // writer.write(socketData.replace("\n", " ") + "\n");
26. // writer.flush();
27. /************************************************/
28. } catch (UnknownHostException e) {
29. e.printStackTrace();
30. } catch (IOException e) {
31. e.printStackTrace();
32. }
33.
34. }
服务器端简单实现:
[java] view plaincopy
1. public void ServerReceviedByTcp() {
2. // 声明一个ServerSocket对象
3. ServerSocket serverSocket = null;
4. try {
5. // 建立一个ServerSocket对象,并让这个Socket在1989端口监听
6. serverSocket = new ServerSocket(1989);
7. // 调用ServerSocket的accept()方法,接受客户端所发送的请求,
8. // 若是客户端没有发送数据,那么该线程就停滞不继续
9. Socket socket = serverSocket.accept();
10. // 从Socket当中获得InputStream对象
11. InputStream inputStream = socket.getInputStream();
12. byte buffer[] = new byte[1024 * 4];
13. int temp = 0;
14. // 从InputStream当中读取客户端所发送的数据
15. while ((temp = inputStream.read(buffer)) != -1) {
16. System.out.println(new String(buffer, 0, temp));
17. }
18. serverSocket.close();
19. } catch (IOException e) {
20. e.printStackTrace();
21. }
22. }
4.2使用UDP协议通讯
客户端发送数据实现:
[java] view plaincopy
1. protected void connectServerWithUDPSocket() {
2.
3. DatagramSocket socket;
4. try {
5. //建立DatagramSocket对象并指定一个端口号,注意,若是客户端须要接收服务器的返回数据,
6. //还须要使用这个端口号来receive,因此必定要记住
7. socket = new DatagramSocket(1985);
8. //使用InetAddress(Inet4Address).getByName把IP地址转换为网络地址
9. InetAddress serverAddress = InetAddress.getByName("192.168.1.32");
10. //Inet4Address serverAddress = (Inet4Address) Inet4Address.getByName("192.168.1.32");
11. String str = "[2143213;21343fjks;213]";//设置要发送的报文
12. byte data[] = str.getBytes();//把字符串str字符串转换为字节数组
13. //建立一个DatagramPacket对象,用于发送数据。
14. //参数一:要发送的数据 参数二:数据的长度 参数三:服务端的网络地址 参数四:服务器端端口号
15. DatagramPacket packet = new DatagramPacket(data, data.length ,serverAddress ,10025);
16. socket.send(packet);//把数据发送到服务端。
17. } catch (SocketException e) {
18. e.printStackTrace();
19. } catch (UnknownHostException e) {
20. e.printStackTrace();
21. } catch (IOException e) {
22. e.printStackTrace();
23. }
24. }
客户端接收服务器返回的数据:
[java] view plaincopy
1. public void ReceiveServerSocketData() {
2. DatagramSocket socket;
3. try {
4. //实例化的端口号要和发送时的socket一致,不然收不到data
5. socket = new DatagramSocket(1985);
6. byte data[] = new byte[4 * 1024];
7. //参数一:要接受的data 参数二:data的长度
8. DatagramPacket packet = new DatagramPacket(data, data.length);
9. socket.receive(packet);
10. //把接收到的data转换为String字符串
11. String result = new String(packet.getData(), packet.getOffset(),
12. packet.getLength());
13. socket.close();//不使用了记得要关闭
14. System.out.println("the number of reveived Socket is :" + flag
15. + "udpData:" + result);
16. } catch (SocketException e) {
17. e.printStackTrace();
18. } catch (IOException e) {
19. e.printStackTrace();
20. }
21. }
服务器接收客户端实现:
[java] view plaincopy
1. public void ServerReceviedByUdp(){
2. //建立一个DatagramSocket对象,并指定监听端口。(UDP使用DatagramSocket)
3. DatagramSocket socket;
4. try {
5. socket = new DatagramSocket(10025);
6. //建立一个byte类型的数组,用于存放接收到得数据
7. byte data[] = new byte[4*1024];
8. //建立一个DatagramPacket对象,并指定DatagramPacket对象的大小
9. DatagramPacket packet = new DatagramPacket(data,data.length);
10. //读取接收到得数据
11. socket.receive(packet);
12. //把客户端发送的数据转换为字符串。
13. //使用三个参数的String方法。参数一:数据包 参数二:起始位置 参数三:数据包长
14. String result = new String(packet.getData(),packet.getOffset() ,packet.getLength());
15. } catch (SocketException e) {
16. e.printStackTrace();
17. } catch (IOException e) {
18. e.printStackTrace();
19. }
20. }
5、总结:
使用UDP方式android端和服务器端接收能够看出,其实android端和服务器端的发送和接收大庭相径,只要端口号正确了,相互通讯就没有问题,TCP使用的是流的方式发送,UDP是以包的形式发送。
本示例以Servlet为例,演示Android与Servlet的通讯。
众所周知,Android与服务器通讯一般采用HTTP通讯方式和Socket通讯方式,而HTTP通讯方式又分get和post两种方式。至于Socket通讯会在之后的博文中介绍。
HTTP协议简介:
HTTP (Hypertext Transfer Protocol ),是Web联网的基础,也是手机联网经常使用的协议之一,HTTP协议是创建在TCP协议之上的一种协议。
HTTP链接最显 著的特色是客户端发送的每次请求都须要服务器回送响应,在请求结束后,会主动释放链接。从创建链接到关闭链接的过程称为“一次链接”。 在HTTP 1.0中,客户端的每次请求都要求创建一次单独的链接,在处理完本次请求后,就自动释放链接。 在HTTP 1.1中则能够在一次链接中处理多个请求,而且多个请求能够重叠进行,不须要等待一个请求结束后再发送下一个请求。
由 于HTTP在每次请求结束后都会主动释放链接,所以HTTP链接是一种“短链接”、“无状态”,要保持客户端程序的在线状态,须要不断地向服务器发起链接 请求。一般的作法是即便不须要得到任何数据,客户端也保持每隔一段固定的时间向服务器发送一次“保持链接”的请求,服务器在收到该请求后对客户端进行回 复,代表知道客户端“在线”。若服务器长时间没法收到客户端的请求,则认为客户端“下线”,若客户端长时间没法收到服务器的回复,则认为网络已经断开。
基于HTTP1.0协议的客户端在每次向服务器发出请求后,服务器就会向客户端返回响应消息,在确认客户端已经收到响应消息后,服务端就会关闭网络链接。在这个数据传输过程当中,并不保存任何历史信息和状态信息,所以,HTTP协议也被认为是无状态的协议。
HTTP1.1 和HTTP1.0相比较而言,最大的区别就是增长了持久链接支持。当客户端使用HTTP1.1协议链接到服务器后,服务器就将关闭客户端链接的主动权交还 给客户端;也就是说,只要不调用Socket类的close方法关闭网络链接,就能够继续向服务器发送HTTP请求。
HTTP链接使用的是“请求—响应”的方式(2次握手),不只在请求时须要先创建链接,并且须要客户端向服务器发出请求后,服务器端才能回复数据。而Socket链接在双方创建起链接后就能够直接进行数据的传输
HTTP协议的特色:
支持B/S及C/S模式;
简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法经常使用的有GET、HEAD、POST。
灵活:HTTP 容许传输任意类型的数据对象。正在传输的类型由Content-Type 加以标记;
无状态:HTTP 协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺乏状态意味着若是后续处理须要前面的信息,则它必须重传,这样可能致使每次链接传送的数据量增大。
HTTP协议请求方法:
请求行中包括了请求方法,解释以下:
GET 请求获取Request-URI 所标识的资源;
POST 在Request-URI 所标识的资源后附加新的数据;
HEAD 请求获取由Request-URI 所标识的资源的响应消息报头
PUT 请求服务器存储一个资源,并用Request-URI 做为其标识
DELETE 请求服务器删除Request-URI 所标识的资源;
TRACE 请求服务器回送收到的请求信息,主要用于测试或诊断
CONNECT 保留未来使用
OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求
Get与Post请求区别:
Post 请求能够向服务器传送数据,并且数据放在HTML HEADER内一块儿传送到服务端URL地址,数据对用户不可见。而get是把参数数据队列加到提交的URL中,值和表单内各个字段一一对应, 例如(http://www.baidu.com/s?w=%C4&inputT=2710)
get 传送的数据量较小,不能大于2KB。post传送的数据量较大,通常被默认为不受限制。但理论上,IIS4中最大量为80KB,IIS5中为100KB。
get安全性很是低,post安全性较高。
在Android开发中咱们常常会用到网络链接功能与服务器进行数据的交互,为此Android的SDK提供了Apache的HttpClient来方便咱们使用各类Http服务
///
Get() 先建立一个HttpClient 而后再建立一个HttpGet,经过HttpClient的execute方法来发送一个HttpGet而且返回String内容。
try {
// 建立一个默认的HttpClient
HttpClient httpclient =new DefaultHttpClient();
// 建立一个GET请求
HttpGet request =new HttpGet("www.google.com");
// 发送GET请求,并将响应内容转换成字符串
String response = httpclient.execute(request, new BasicResponseHandler());
Log.v("response text", response);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
///////////////////////////////
Post()
publicstatic String post(String url, NameValuePair... params) {
try {
// 编码参数
List<NameValuePair> formparams =new ArrayList<NameValuePair>(); // 请求参数
for (NameValuePair p : params) {
formparams.add(p);
}
UrlEncodedFormEntity entity =new UrlEncodedFormEntity(formparams,
CHARSET);
// 建立POST请求
HttpPost request =new HttpPost(url);
request.setEntity(entity);
// 发送请求
HttpClient client = getHttpClient();
HttpResponse response = client.execute(request);
if(response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
thrownew RuntimeException("请求失败");
}
HttpEntity resEntity = response.getEntity();
return (resEntity ==null) ?null : EntityUtils.toString(resEntity, CHARSET);
} catch (UnsupportedEncodingException e) {
Log.w(TAG, e.getMessage());
returnnull;
} catch (ClientProtocolException e) {
Log.w(TAG, e.getMessage());
returnnull;
} catch (IOException e) {
thrownew RuntimeException("链接失败", e);
}
}
整理:杨光福&王飞龙
时间仓促,不免有不周之处,请见谅。
http://www.cnblogs.com/pepcod/archive/2013/02/11/2937403.html
能够用咱们上课讲的说
也能够参照
http://blog.saymagic.cn/2015/01/30/android-pic-three-cache.html
http://www.cnblogs.com/elliotta/p/3633752.html
http://blog.csdn.net/yudajun/article/details/9323941
技术方面说明
http://blog.csdn.net/lwyygydx/article/details/41870377
功能改进方面说明
http://digi.tech.qq.com/a/20150121/012030.htm
能够参照李延磊老师的
也能够参照连接
http://blog.csdn.net/fancylovejava/article/details/39927539
xUtils,Gson 极光推送 都讲过,忽略
友盟第三方登陆
http://blog.umeng.com/uncategorized/4160.html
第三方登陆案例
http://blog.csdn.net/yueqinglkong/article/details/15028041
http://blog.csdn.net/lyf_007217/article/details/8542238
http://www.cnblogs.com/devinzhang/p/3856200.html
http://www.360doc.com/content/14/0402/09/10504424_365635496.shtml
http://blog.csdn.net/androidzhaoxiaogang/article/details/7910364
http://www.2cto.com/kf/201409/335964.html
http://blog.csdn.net/u200814499/article/details/40391443
http://blog.csdn.net/jiangliloveyou/article/details/9849775
http://blog.csdn.net/lnb333666/article/details/7471292
http://skywen.iteye.com/blog/1811310
已经讲了,请看视频
已经讲了,请看视频
已经讲了,请看视频
http://blog.csdn.net/wuqiong_524itcast/article/details/25378685
http://blog.csdn.net/wangshione/article/details/8490245
http://blog.csdn.net/lnb333666/article/details/8031770
1.垃圾收集算法的核心思想
Java语言创建了垃圾收集机制,用以跟踪正在使用的对象和发现并回收再也不使用(引用)的对象。该机制能够有效防范动态内存分配中因内存垃圾过多而引起的内存耗尽,以及不恰当的内存释放所形成的内存非法引用。
垃圾收集算法的核心思想是:对虚拟机可用内存空间,即堆空间中的对象进行识别,若是对象正在被引用,那么称其为存活对象,反之,若是对象再也不被引用,则 为垃圾对象,能够回收其占据的空间,用于再分配。垃圾收集算法的选择和垃圾收集系统参数的合理调节直接影响着系统性能,所以须要开发人员作比较深刻的了解。
2.触发主GC(Garbage Collector)的条件
JVM进行次GC的频率很高,但由于这种GC占用时间极短,因此对系统产生的影响不大。更值得关注的是主GC的触发条件,由于它对系统影响很明显。总的来讲,有两个条件会触发主GC:
①当应用程序空闲时,即没有应用线程在运行时,GC会被调用。由于GC在优先级最低的线程中进行,因此当应用忙时,GC线程就不会被调用,但如下条件除外。
②Java堆内存不足时,GC会被调用。当应用线程在运行,并在运行过程当中建立新对象,若这时内存空间不足,JVM就会强制地调用GC线程,以 便回收内存用于新的分配。若GC一次以后仍不能知足内存分配的要求,JVM会再进行两次GC做进一步的尝试,若仍没法知足要求,则 JVM将报“out of memory”的错误,Java应用将中止。
3.减小GC开销的措施
根据上述GC的机制,程序的运行会直接影响系统环境的变化,从而影响GC的触发。若不针对GC的特色进行设计和编码,就会出现内存驻留等一系列负面影响。为了不这些影响,基本的原则就是尽量地减小垃圾和减小GC过程当中的开销。具体措施包括如下几个方面:
(1)不要显式调用System.gc()
此函数建议JVM进行主GC,虽然只是建议而非必定,但不少状况下它会触发主GC,从而增长主GC的频率,也即增长了间歇性停顿的次数。
(2)尽可能减小临时对象的使用
临时对象在跳出函数调用后,会成为垃圾,少用临时变量就至关于减小了垃圾的产生,从而延长了出现上述第二个触发条件出现的时间,减小了主GC的机会。
(3)对象不用时最好显式置为Null
通常而言,为Null的对象都会被做为垃圾处理,因此将不用的对象显式地设为Null,有利于GC收集器断定垃圾,从而提升了GC的效率。
(4)尽可能使用StringBuffer,而不用String来累加字符串(详见blog另外一篇文章JAVA中String与StringBuffer)
因为String是固定长的字符串对象,累加String对象时,并不是在一个String对象中扩增,而是从新建立新的String对象,如 Str5=Str1+Str2+Str3+Str4,这条语句执行过程当中会产生多个垃圾对象,由于对次做“+”操做时都必须建立新的String对象,但 这些过渡对象对系统来讲是没有实际意义的,只会增长更多的垃圾。避免这种状况能够改用StringBuffer来累加字符串,因StringBuffer 是可变长的,它在原有基础上进行扩增,不会产生中间对象。
(5)能用基本类型如Int,Long,就不用Integer,Long对象
基本类型变量占用的内存资源比相应对象占用的少得多,若是没有必要,最好使用基本变量。
(6)尽可能少用静态对象变量
静态变量属于全局变量,不会被GC回收,它们会一直占用内存。
(7)分散对象建立或删除的时间
集中在短期内大量建立新对象,特别是大对象,会致使忽然须要大量内存,JVM在面临这种状况时,只能进行主GC,以回收内存或整合内存碎片, 从而增长主GC的频率。集中删除对象,道理也是同样的。它使得忽然出现了大量的垃圾对象,空闲空间必然减小,从而大大增长了下一次建立新对象时强制主GC 的机会。
gc()函数的做用只是提醒虚拟机:程序员但愿进行一次垃圾回收。可是它不能保证垃圾回收必定会进行,并且具体何时进行是取决于具体的虚拟机的,不一样的虚拟机有不一样的对策。在Davilk中,给程序分配的内存是根据机型厂商的不一样而不一样(如今大部分为32MB),在VM内部会将内存分为:java使用的内存,Native使用的内存,他们之间不能共享,当某一方面不足
的时候必须向VM申请,而不能直接使用另一个的内存。
出现内存泄漏的可能性:
出现状况:
1. 数据库的cursor没有关闭
2.构造adapter时,没有使用缓存contentview
衍生listview的优化问题-----减小建立view的对象,充分使用contentview,能够使用一静态类来优化处理getview的过程
3.Bitmap对象不使用时采用recycle()释放内存
4.activity中的对象的生命周期大于activity
调试方法: DDMS==> HEAPSZIE==>dataobject==>[Total Size]
1、 Android的内存机制
Android的程序由Java语言编写,因此Android的内存管理与Java的内存管理类似。程序员经过new为对象分配内存,全部对象在java 堆内分配空间;然而对象的释放是由垃圾回收器来完成的。C/C++中的内存机制是“谁污染,谁治理”,java的就比较人性化了,给咱们请了一个专门的清 洁工(GC)
2、GC是什么? 为何要有GC?
GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会致使程序或系统的不稳定甚至崩溃,Java提供的GC功能能够 自动监测对象是否超过做用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操做方法。
4、垃圾回收器的基本原理是什么?垃圾回收器能够立刻回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?
对于GC来讲,当程序员建立对象时,GC就开始监控这个对象的地址、大小以及使用状况。一般,GC采用有向图的方式记录和管理堆(heap)中的全部对 象。经过这种方式肯定哪些对象是"可达的",哪些对象是"不可达的"。当GC肯定一些对象为"不可达"时,GC就有责任回收这些内存空间。能够。程序员可 以手动执行System.gc(),通知GC运行,可是Java语言规范并不保证GC必定会执行。
间而忘记了释放。若是程序中存在对无用对象的引用,那么这些对象就会驻留内存,消耗内存,由于没法让垃圾回收器GC验证这些对象是否再也不须要。若是存在对 象的引用,这个对象就被定义为"有效的活动",同时不会被释放。要肯定对象所占内存将被回收,咱们就要务必确认该对象再也不会被使用。典型的作法就是把对象 数据成员设为null或者从集合中移除该对象。但当局部变量不须要时,不需明显的设为null,由于一个方法执行完毕时,这些引用会自动被清理。
Java带垃圾回收的机制,为何还会内存泄露呢?举例:
[java] view plaincopyprint?
1. Vector v = new Vector(10);
2. for (int i = 1; i < 100; i++) {
3. Object o = new Object();
4. v.add(o);
5. o = null;
6. }// 此时,全部的Object对象都没有被释放,由于变量v引用这些对象。
Java 内存泄露的根本缘由就是 保存了不可能再被访问的变量类型的引用
6、Android的内存溢出
Android的内存溢出是如何发生的?
Android的虚拟机是基于寄存器的Dalvik,它的最大堆大小通常是16M,有的机器为24M。也就是说咱们所能利用的内存空间是有限的。若是咱们的内存占用超过了必定的水平就会出现OutOfMemory的错误。
为何会出现内存不够用的状况呢?我想缘由主要有两个:
因为咱们程序的失误,长期保持某些资源(如Context)的引用,形成内存泄露,资源形成得不到释放。保存了多个耗用内存过大的对象(如Bitmap),形成内存超出限制。
(一)、(二)中,咱们了解了一些基本概念。
600dp的含义是:表明这个设备的最短的那一边。
获取设备的最短边的代码是:Configuration config = getResources().getConfiguration();
int smallestScreenWidth = config.smallestScreenWidthDp;
这个时候拿smallestScreenWidth 与600想比较就能够知道该设备可否读取里面的资源了。
)
除此以外,为了方便适配,在编码时咱们还应该注意什么呢,主要有如下几点:
(1)多使用权重(android:layout_weight)
尤为是在tab切换布局,listview title及Item布局等状况下;
(2)设置宽度和高度时,尽可能使用match_parent和wrap_content,避免把控件宽高设死;
(3)父容器布局选用
多使用RelativeLayout,FrameLayout,GridLayout等,减小布局层次。固然,在使用
权重时,得采用LinearLayout;
(4) 在xml里,设置高度、宽度采用dp(dip),设置字体采用sp。
(应该注意,在代码里面,咱们写的setHeight(...)单位是px)
(二)
那么在具体开发中,咱们应该注意什么呢。
首先,咱们必需要知道,其实适配的关键在于两点:
(1)不一样分辨率设备的适配,这点在单位的使用上用dp、sp以及图片资源存放于不一样的drawable文件夹就能够解决问题;
(2)不一样尺寸的适配,这点主要靠将相关值以及布局文件放置于不一样的文件夹中来解决。
2.1 values文件夹
能够在工程下建立不一样的values文件夹:values-sw480dp, values-sw600dp,
values-sw720dp-land等。好比一个控件的宽度,在10寸pad上是10dp,在8寸pad
上是5dp。这时,你能够定义一个变量,button_width,而后在values-sw600dp
下写5dp,在values-sw720-land下写
10dp。这样就达到了在不一样尺寸pad上,
相应控件大小不同的效果。
2.1 layout文件夹
若是在不一样尺寸设备上展现的布局有明显差异,仅仅用values不一样已经难以控制,
那么就能够考虑写不一样的布局文件置于不一样的layout文件夹下,android会根据设备
尺寸去加载相应文件夹下的布局文件。如:layout-sw480dp,layout-sw600dp,
layout-sw700dp等。
值得注意的是,若是不是颇有必要,尽可能采用2.1方案,方便维护。若是尺寸和分辨率都不一样,
那么就要结合(1)、(2)考虑了。
(补充:其实values文件夹和layout文件夹不只仅是根据尺寸判断,也和分辨率有关,不过在一般状况下,
综合计算考虑,仅根据尺寸判断就能够了:
www.itlanbao.com 本网站里面分享不少android特效,更多的面试资料在IT蓝豹资讯部分 ,但愿可以给你帮助,欢迎到IT蓝豹上互相学习。
|
ArrayList |
Vector |
LinkedList |
实现原理 |
数组 |
数组 |
双向链表 |
线程安全 |
否 |
是 |
否 |
优势 |
1.数组实现优于遍历 |
1.数组实现优于遍历 |
1.节点的增删无需对象的重建 |
缺点 |
1.非线程安全 |
1.数组中未使用的元素形成空间的浪费 |
1.遍历效率较低 |
扩容 |
0.5倍增量 |
1倍增量 |
按需增删 |
使用场景 |
1.无线程的要求。 |
1.有线程安全的要求 |
增删场景较多的时候 |
11.int与Integer的区别
|
int |
Integer |
类型 |
基本类型 |
复合类型 |
默认值 |
0 |
null |
存储 |
栈(局部变量) |
堆上(只能经过new建立) |
方法 |
基本类型无方法 |
有 |
速度 |
快(栈上 的操做相对快) |
慢 |
泛型支持 |
否(java中的泛型不支持,C++中的模板支持) |
支持 |
容器类支持 |
否(直接使用一般会进行装箱操做) |
支持 |
存在乎义 |
1.历史缘由(顺延C/C++中存在) |
基本类型int的包装类 |
Checked Exception:在编译时就可以被Java编译器所检测到的。
UncheckedException:则是编译时,java编译器不能检查到。
|
RuntimeException |
普通Exception |
Error |
受控异常 |
否 |
是 |
否 |
产生缘由 |
开发者的编程错误 |
因为外界环境所限, |
Java运行时的系统错误,资源耗尽,是一种严重的, |
例子 |
NullPointerException |
ClassNotFoundException |
VirtualMachineError |
final:关键字,表不变
修饰:
· 方法:方法不可Override
· 类:不可被继承
· 基本类型量:常量,值不可变
· 符合类型量:引用不可变,即引用的值不可变
[java] view plaincopy
1. final Object o1 = new Object();
2. o1 = new Object();
finally:关键字,Java异常处理机制的一部分,在异常发生时,用来提供一个必要的清理的机会。
finalize:Object类的方法(参考自百度百科)
意义:Java技术容许使用finalize()方法在垃圾回收器将对象回收以前,作一些必要的清理操做。
调用前提:这个对象肯定没有被引用到。
工做原理:
· 垃圾收集器准备好释放对象占用的空间。
· 首先调用其finalize方法。
· 下一次垃圾收集过程当中,真正回收内存。
不肯定性:
· finalize的执行时间是不缺定的。
· 一个对象引用另外一个对象,并不能保证finalize的方法按照特定的执行顺序。
|
Override |
Overload |
签名+返回值 |
相同 |
方法名相同,签名不一样 |
关系 |
父子类继承关系 |
一般是同一类层次中 |
识别 |
运行时多态 |
编译时多态 |
修饰符限制 |
非private |
无特别 |
异常关系 |
子类方法不能抛出被父类方法更多的异常 |
无特别 |
可见性关系 |
子类不能比父类访问权限更窄 |
无特别 |
Collection:接口,集合类的接口,一个契约,提供了集合基本的大小,添加,清除,遍历方法等。
Collections:工具类,提供了不少静态方法,给集合提供一些查询,比较,排序,交换,线程安全化等方法。
package com.jue.test;
public class TestMain {
public static void main(String[] args) {
Integer i1 = 1;
Integer i11 = 1;
System.out.println(i1 == i11);
Integer i2 = 200;
Integer i22 = 200;
System.out.println(i2 == i22);
}
}
结果 :True,false
分析:反编译结果为 Integer i1 = Integer.valueOf(1);
能够看出,对于Integer i = 1;编译器作了额外的处理,即Integer.valueof();能够看出Integer对于必定 范围内的数字从Cache中取得,对于额外的,调用new建立。
故能够知道Integer的大小,默认是从-128到127,对于这个范围内的数组作了缓存的处理。 对于额外的,调用new建立
|
wait |
sleep |
所属类 |
Object |
Thread |
意义 |
让线程挂起 |
让线程休眠指定的时间 |
释放锁 |
是 |
否(这个跟锁原本就没有关系) |
恢复 |
1.有参:wait指定时间 |
1.根据参数长度自动恢复。 |
使用限制 |
wait,notify必须持有当前对象锁的状况下调用 |
无特别 |
抛出异常 |
否 |
是 |
静态方法 |
否 |
是 |
HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap容许空(null)键值(key),因为非线程安全,效率上可能高于Hashtable。
HashMap容许将null做为一个entry的key或者value,而Hashtable不容许。
HashMap把Hashtable的contains方法去掉了,改为containsvalue和containsKey。由于contains方法容易让人引发误解。
整体来讲设计模式分为三大类:
建立型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
其实还有两类:并发型模式和线程池模式。用一个图片来总体描述一下:
http://www.cnblogs.com/maowang1991/archive/2013/04/15/3023236.html
首先,建立两者的共同接口:
[java] view plaincopy
1. public interface Sender {
2. public void Send();
3. }
其次,建立实现类:
[java] view plaincopy
1. public class MailSender implements Sender {
2. @Override
3. public void Send() {
4. System.out.println("this is mailsender!");
5. }
6. }
[java] view plaincopy
1. public class SmsSender implements Sender {
2.
3. @Override
4. public void Send() {
5. System.out.println("this is sms sender!");
6. }
7. }
最后,建工厂类:
[java] view plaincopy
1. public class SendFactory {
2.
3. public Sender produce(String type) {
4. if ("mail".equals(type)) {
5. return new MailSender();
6. } else if ("sms".equals(type)) {
7. return new SmsSender();
8. } else {
9. System.out.println("请输入正确的类型!");
10. return null;
11. }
12. }
13. }
咱们来测试下:
1. public class FactoryTest {
2.
3. public static void main(String[] args) {
4. SendFactory factory = new SendFactory();
5. Sender sender = factory.produce("sms");
6. sender.Send();
7. }
8. }
输出:this is sms sender!
a、多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,若是传递的字符串出错,则不能正确建立对象,而多个工厂方法模式是提供多个工厂方法,分别建立对象。关系图:
将上面的代码作下修改,改动下SendFactory类就行,以下:
[java] view plaincopypublic class SendFactory {
public Sender produceMail(){
1. return new MailSender();
2. }
3.
4. public Sender produceSms(){
5. return new SmsSender();
6. }
7. }
测试类以下:
[java] view plaincopy
1. public class FactoryTest {
2.
3. public static void main(String[] args) {
4. SendFactory factory = new SendFactory();
5. Sender sender = factory.produceMail();
6. sender.Send();
7. }
8. }
输出:this is mailsender!
b、静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不须要建立实例,直接调用便可。
[java] view plaincopy
1. public class SendFactory {
2.
3. public static Sender produceMail(){
4. return new MailSender();
5. }
6.
7. public static Sender produceSms(){
8. return new SmsSender();
9. }
10. }
[java] view plaincopy
1. public class FactoryTest {
2.
3. public static void main(String[] args) {
4. Sender sender = SendFactory.produceMail();
5. sender.Send();
6. }
7. }
输出:this is mailsender!
整体来讲,工厂模式适合:凡是出现了大量的产品须要建立,而且具备共同的接口时,能够经过工厂方法模式进行建立。在以上的三种模式中,第一种若是传 入的字符串有误,不能正确建立对象,第三种相对于第二种,不须要实例化工厂类,因此,大多数状况下,咱们会选用第三种——静态工厂方法模式。
能够看出工厂方法的加入,使得对象的数量成倍增加。当产品种类很是多时,会出现大量的与之对应的工厂对象,这不是咱们所但愿的。由于若是不能避免这种情 况,能够考虑使用简单工厂模式与工厂方法模式相结合的方式来减小工厂类:即对于产品树上相似的种类(通常是树的叶子中互为兄弟的)使用简单工厂模式来实 现。
c、简单工厂和工厂方法模式的比较
工厂方法模式和简单工厂模式在定义上的不一样是很明显的。工厂方法模式的核心是一个抽象工厂类,而不像简单工厂模式, 把核心放在一个实类上。工厂方法模式能够容许不少实的工厂类从抽象工厂类继承下来, 从而能够在实际上成为多个简单工厂模式的综合,从而推广了简单工厂模式。
反过来说,简单工厂模式是由工厂方法模式退化而来。设想若是咱们很是肯定一个系统只须要一个实的工厂类, 那么就不妨把抽象工厂类合并到实的工厂类中去。而这样一来,咱们就退化到简单工厂模式了。
d、抽象工厂模式
代码:
//抽象工厂类
public abstract class AbstractFactory {
public abstract Vehicle createVehicle();
public abstract Weapon createWeapon();
public abstract Food createFood();
}
//具体工厂类,其中Food,Vehicle,Weapon是抽象类,
public class DefaultFactory extends AbstractFactory{
@Override
public Food createFood() {
return new Apple();
}
@Override
public Vehicle createVehicle() {
return new Car();
}
@Override
public Weapon createWeapon() {
return new AK47();
}
}
//测试类
public class Test {
public static void main(String[] args) {
AbstractFactory f = new DefaultFactory();
Vehicle v = f.createVehicle();
v.run();
Weapon w = f.createWeapon();
w.shoot();
Food a = f.createFood();
a.printName();
}
}
在抽象工厂模式中,抽象产品 (AbstractProduct) 多是一个或多个,从而构成一个或多个产品族(Product Family)。 在只有一个产品族的状况下,抽象工厂模式实际上退化到工厂方法模式。
6、总结。
(1)简单工厂模式是由一个具体的类去建立其余类的实例,父类是相同的,父类是具体的。
(2)工厂方法模式是有一个抽象的父类定义公共接口,子类负责生成具体的对象,这样作的目的是将类的实例化操做延迟到子类中完成。
(3)抽象工厂模式提供一个建立一系列相关或相互依赖对象的接口,而无须指定他们具体的类。它针对的是有多个产品的等级结构。而工厂方法模式针对的是一个产品的等级结构。
单例对象(Singleton)是一种经常使用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处:
1、某些类建立比较频繁,对于一些大型的对象,这是一笔很大的系统开销。
2、省去了new操做符,下降了系统内存的使用频率,减轻GC压力。
3、有些类如交易所的核心交易引擎,控制着交易流程,若是该类能够建立多个的话,系统彻底乱了。(好比一个军队出现了多个司令员同时指挥,确定会乱成一团),因此只有使用单例模式,才能保证核心交易服务器独立控制整个流程。
首先咱们写一个简单的单例类:
[java] view plaincopy
1. public class Singleton {
2.
3. /* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */
4. private static Singleton instance = null;
5.
6. /* 私有构造方法,防止被实例化 */
7. private Singleton() {
8. }
9.
10. /* 静态工程方法,建立实例 */
11. public static Singleton getInstance() {
12. if (instance == null) {
13. instance = new Singleton();
14. }
15. return instance;
16. }
17.
18. /* 若是该对象被用于序列化,能够保证对象在序列化先后保持一致 */
19. public Object readResolve() {
20. return instance;
21. }
22. }
这个类能够知足基本要求,可是,像这样毫无线程安全保护的类,若是咱们把它放入多线程的环境下,确定就会出现问题了,如何解决?咱们首先会想到对getInstance方法加synchronized关键字,以下:
[java] view plaincopy
1. public static synchronized Singleton getInstance() {
2. if (instance == null) {
3. instance = new Singleton();
4. }
5. return instance;
6. }
可是,synchronized关键字锁住的是这个对象,这样的用法,在性能上会有所降低,由于每次调用getInstance(),都要对对象上锁,事实上,只有在第一次建立对象的时候须要加锁,以后就不须要了,因此,这个地方须要改进。咱们改为下面这个:
[java] view plaincopy
1. public static Singleton getInstance() {
2. if (instance == null) {
3. synchronized (instance) {
4. if (instance == null) {
5. instance = new Singleton();
6. }
7. }
8. }
9. return instance;
10. }
1、最简单的实现
首先,能想到的最简单的实现是,把类的构造函数写成private的,从而保证别的类不能实例化此类。而后在类中返回一个静态示例并返回给调用者。这样,调用者就能够经过这个引用使用这个实例了。
public class Singleton{ private static final Singleton singleton = new Singleton(); public static Singleton getInstance(){ return singleton; } private Singleton(){ }}
如上例,外部使用者若是须要使用SingletonClass的实例,只能经过getInstance()方法,而且它的构造方法是private的,这样就保证了只能有一个对象存在。
2、性能优化--lazy loaded
上面的代码虽然简单,可是有一个问题----不管这个类是否被使用,都会建立一个instance对象。若是这个建立很耗时,好比说连接10000次数据库(夸张一点啦....),而且这个类还不必定会被使用,那么这个建立过程就是无用的,怎么办呢?
为了解决这个问题,咱们想到的新的解决方案:
public class SingletonClass { private static SingletonClass instance = null; public static SingletonClass getInstance() { if(instance == null) { instance = new SingletonClass(); } return instance; } private SingletonClass() { } }
代码的变化有俩处----首先,把 instance 设置为 null ,知道第一次使用的时候判是否为 null 来建立对象。由于建立对象不在声明处,因此那个 final 的修饰必须去掉。
咱们来想象一下这个过程。要使用 SingletonClass ,调用 getInstance()方法,第一次的时候发现instance时null,而后就建立一个对象,返回出去;第二次再使用的时候,由于这个 instance事static的,共享一个对象变量的,因此instance的值已经不是null了,所以不会再建立对象,直接将其返回。
这个过程就称为lazy loaded ,也就是迟加载-----直到使用的时候才经行加载。
这样写法也比较完美:可是还能够优化
public class SingletonClass{ private static SingletonClass instance = null; public static SingletonClass getInstance(){ if(instance == null){ synchronized(SingletonClass.class){ if(instance == null){ instance = new SingletonClass(); } } } return instance; } private SingletonClass(){ } }
经过单例模式的学习告诉咱们:
1、单例模式理解起来简单,可是具体实现起来仍是有必定的难度。
2、synchronized关键字锁定的是对象,在用的时候,必定要在恰当的地方使用(注意须要使用锁的对象和过程,可能有的时候并非整个对象及整个过程都须要锁)。
到这儿,单例模式基本已经讲完了,结尾处,笔者忽然想到另外一个问题,就是采用类的静态方法,实现单例模式的效果,也是可行的,此处两者有什么不一样?
首先,静态类不能实现接口。(从类的角度说是能够的,可是那样就破坏了静态了。由于接口中不容许有static修饰的方法,因此即便实现了也是非静态的)
其次,单例能够被延迟初始化,静态类通常在第一次加载是初始化。之因此延迟加载,是由于有些类比较庞大,因此延迟加载有助于提高性能。
再次,单例类能够被继承,他的方法能够被覆写。可是静态类内部方法都是static,没法被覆写。
最后一点,单例类比较灵活,毕竟从实现上只是一个普通的Java类,只要知足单例的基本需求,你能够在里面为所欲为的实现一些其它功能,可是静态类 不行。从上面这些归纳中,基本能够看出两者的区别,可是,从另外一方面讲,咱们上面最后实现的那个单例模式,内部就是用一个静态类来实现的,因此,两者有很 大的关联,只是咱们考虑问题的层面不一样罢了。两种思想的结合,才能造就出完美的解决方案,就像HashMap采用数组+链表来实现同样,其实生活中不少事 情都是这样,单用不一样的方法来处理问题,老是有优势也有缺点,最完美的方法是,结合各个方法的优势,才能最好的解决问题!
工厂类模式提供的是建立单个类的模式,而建造者模式则是将各类产品集中起来进行管理,用来建立复合对象,所谓复合对象就是指某个类具备不一样的属性,其实建造者模式就是前面抽象工厂模式和最后的Test结合起来获得的。咱们看一下代码:
还和前面同样,一个Sender接口,两个实现类MailSender和SmsSender。最后,建造者类以下:
[java] view plaincopy
1. public class Builder {
2.
3. private List<Sender> list = new ArrayList<Sender>();
4.
5. public void produceMailSender(int count){
6. for(int i=0; i<count; i++){
7. list.add(new MailSender());
8. }
9. }
10.
11. public void produceSmsSender(int count){
12. for(int i=0; i<count; i++){
13. list.add(new SmsSender());
14. }
15. }
16. }
测试类:
[java] view plaincopy
1. public class Test {
2.
3. public static void main(String[] args) {
4. Builder builder = new Builder();
5. builder.produceMailSender(10);
6. }
7. }
从这点看出,建造者模式将不少功能集成到一个类里,这个类能够创造出比较复杂的东西。因此与工程模式的区别就是:工厂模式关注的是建立单个产品,而建造者模式则关注建立符合对象,多个部分。所以,是选择工厂模式仍是建造者模式,依实际状况而定。
原型模式虽然是建立型的模式,可是与工程模式没有关系,从名字便可看出,该模式的思想就是将一个对象做为原型,对其进行复制、克隆,产生一个和原对象相似的新对象。本小结会经过对象的复制,进行讲解。在Java中,复制对象是经过clone()实现的,先建立一个原型类:
[java] view plaincopy
1. public class Prototype implements Cloneable {
2.
3. public Object clone() throws CloneNotSupportedException {
4. Prototype proto = (Prototype) super.clone();
5. return proto;
6. }
7. }
很简单,一个原型类,只须要实现Cloneable接口,覆写clone方法,此处clone方法能够改为任意的名称,由于Cloneable接口 是个空接口,你能够任意定义实现类的方法名,如cloneA或者cloneB,由于此处的重点是super.clone()这句 话,super.clone()调用的是Object的clone()方法,而在Object类中,clone()是native的,具体怎么实现,我会 在另外一篇文章中,关于解读Java中本地方法的调用,此处再也不深究。在这儿,我将结合对象的浅复制和深复制来讲一下,首先须要了解对象深、浅复制的概念:
浅复制:将一个对象复制后,基本数据类型的变量都会从新建立,而引用类型,指向的仍是原对象所指向的。
深复制:将一个对象复制后,不管是基本数据类型还有引用类型,都是从新建立的。简单来讲,就是深复制进行了彻底完全的复制,而浅复制不完全。
此处,写一个深浅复制的例子:
[java] view plaincopy
1. public class Prototype implements Cloneable, Serializable {
2.
3. private static final long serialVersionUID = 1L;
4. private String string;
5.
6. private SerializableObject obj;
7.
8. /* 浅复制 */
9. public Object clone() throws CloneNotSupportedException {
10. Prototype proto = (Prototype) super.clone();
11. return proto;
12. }
13.
14. /* 深复制 */
15. public Object deepClone() throws IOException, ClassNotFoundException {
16.
17. /* 写入当前对象的二进制流 */
18. ByteArrayOutputStream bos = new ByteArrayOutputStream();
19. ObjectOutputStream oos = new ObjectOutputStream(bos);
20. oos.writeObject(this);
21.
22. /* 读出二进制流产生的新对象 */
23. ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
24. ObjectInputStream ois = new ObjectInputStream(bis);
25. return ois.readObject();
26. }
27.
28. public String getString() {
29. return string;
30. }
31.
32. public void setString(String string) {
33. this.string = string;
34. }
35.
36. public SerializableObject getObj() {
37. return obj;
38. }
39.
40. public void setObj(SerializableObject obj) {
41. this.obj = obj;
42. }
43.
44. }
45.
46. class SerializableObject implements Serializable {
47. private static final long serialVersionUID = 1L;
48. }
要实现深复制,须要采用流的形式读入当前对象的二进制输入,再写出二进制数据对应的对象。
咱们接着讨论设计模式,上篇文章我讲完了5种建立型模式,这章开始,我将讲下7种结构型模式:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。其中对象的适配器模式是各类模式的起源,咱们看下面的图:
适配器模式将某个类的接口转换成客户端指望的另外一个接口表示,目的是消除因为接口不匹配所形成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。首先,咱们来看看类的适配器模式,先看类图:
核心思想就是:有一个Source类,拥有一个方法,待适配,目标接口时Targetable,经过Adapter类,将Source的功能扩展到Targetable里,看代码:
[java] view plaincopy
1. public class Source {
2.
3. public void method1() {
4. System.out.println("this is original method!");
5. }
6. }
[java] view plaincopy
1. public interface Targetable {
2.
3. /* 与原类中的方法相同 */
4. public void method1();
5.
6. /* 新类的方法 */
7. public void method2();
8. }
[java] view plaincopy
1. public class Adapter extends Source implements Targetable {
2.
3. @Override
4. public void method2() {
5. System.out.println("this is the targetable method!");
6. }
7. }
Adapter类继承Source类,实现Targetable接口,下面是测试类:
[java] view plaincopy
1. public class AdapterTest {
2.
3. public static void main(String[] args) {
4. Targetable target = new Adapter();
5. target.method1();
6. target.method2();
7. }
8. }
输出:
this is original method!
this is the targetable method!
这样Targetable接口的实现类就具备了Source类的功能
将以前介绍的全部排序算法整理成NumberSort类,代码
NumberSort
Java语言引入了Java虚拟机,具备跨平台运行的功能,可以很好地适应各类Web应用。同时,为了提升Java语言的性能和健壮性,还引入了如垃圾回收机制等新功能,经过这些改进让Java具备其独特的工做原理。
1.Java虚拟机
Java源程序经过编译器编译成.Class文件,而后java虚拟机中的java 解释器负责将字节码文件解释成为特定的机器码进行运行。
java是一种半编译半解释型语言。半编译是指:java源代码,会通过javac命令变成 .class文件。半解释是指: .class文件被jvm解释的过程。也就是由于jvm的半解释才有了java的动态语言特性:反射和annotation。
和android区别
alvik有本身的libdex库负责对.class进行处理。libdex主要对.class进行处理生成本身的dex文件。主要作的工做是,对虚拟机指令进行转换(dalvik是基于寄存器的,sun虚拟机是基于栈的),对类的静态数据进行归类、压缩。
dalvik基于寄存器,而JVM基于stack ,Dalvik执行的是特有的DEX文件格式,而JVM运行的是*.class文件格式。
优点:1、在编译时提早优化代码而不是等到运行时
2、 虚拟机很小,使用的空间也小;被设计来知足可高效运行多种虚拟机实例。
Java虚拟机的创建须要针对不一样的软硬件平台来实现,既要考虑处理器的型号,也要考虑操做系统的种类。由此在SPARC结构、X86结构、MIPS和PPC等嵌入式处理芯片上,在UNIX、Linux、Windows和部分实时操做系统上均可实现Java虚拟机。
2.无用内存自动回收机制
而在Java运行环境中,始终存在着一个系统级的线程,专门跟踪内存的使用状况, 按期检测出再也不使用的内存,并自动进行回收,避免了内存的泄露,也减轻了程序员的工做量。
1.JVM
JVM是Java平台的核心,为了让编译产生的字节码能更好地解释与执行,所以把JVM分红了6个部分:JVM解释器、指令系统、寄存器、栈、存储区和碎片回收区。
能够很明显看出,Android系统架构由5部分组成,分别是:Linux Kernel、Android Runtime、Libraries、Application Framework、Applications。第二部分将详细介绍这5个部分。
如今咱们拿起手术刀来剖析各个部分。其实这部分SDK文档已经帮咱们作得很好了,咱们要作的就是拿来主义,而后再加上本身理解。下面自底向上分析各层。
Android基于Linux 2.6提供核心系统服务,例如:安全、内存管理、进程管理、网络堆栈、驱动模型。Linux Kernel也做为硬件和软件之间的抽象层,它隐藏具体硬件细节而为上层提供统一的服务。
Android 包含一个核心库的集合,提供大部分在Java编程语言核心类库中可用的功能。每个Android应用程序是Dalvik虚拟机中的实例,运行在他们本身 的进程中。Dalvik虚拟机设计成,在一个设备能够高效地运行多个虚拟机。Dalvik虚拟机可执行文件格式是.dex,dex格式是专为Dalvik 设计的一种压缩格式,适合内存和处理器速度有限的系统。
大多数虚拟机包括JVM都是基于栈的,而Dalvik虚拟机则是基于寄存器的。 两种架构各有优劣,通常而言,基于栈的机器须要更多指令,而基于寄存器的机器指令更大。dx 是一套工具,能够將 Java .class 转换成 .dex 格式。一个dex文件一般会有多个.class。因为dex有時必须进行最佳化,会使文件大小增长1-4倍,以ODEX结尾。
Dalvik虚拟机依赖于Linux 内核提供基本功能,如线程和底层内存管理。
Android包含一个C/C++库的集合,供Android系统的各个组件使用。这些功能经过Android的应用程序框架(application framework)暴露给开发者。下面列出一些核心库:
· 系统C库——标准C系统库(libc)的BSD衍生,调整为基于嵌入式Linux设备
· 媒体库——基于PacketVideo的OpenCORE。这些库支持播放和录制许多流行的音频和视频格式,以及静态图像文件,包括MPEG4、 H.264、 MP3、 AAC、 AMR、JPG、 PNG
· 界面管理——管理访问显示子系统和无缝组合多个应用程序的二维和三维图形层
· LibWebCore——新式的Web浏览器引擎,驱动Android 浏览器和内嵌的web视图
· SGL——基本的2D图形引擎
· 3D库——基于OpenGL ES 1.0 APIs的实现。库使用硬件3D加速或包含高度优化的3D软件光栅
· FreeType ——位图和矢量字体渲染
· SQLite ——全部应用程序均可以使用的强大而轻量级的关系数据库引擎
经过提供开放的开发平台,Android使开发者可以编制极其丰富和新颖的应用程序。开发者能够自由地利用设备硬件优点、访问位置信息、运行后台服务、设置闹钟、向状态栏添加通知等等,不少不少。
开发者能够彻底使用核心应用程序所使用的框架APIs。应用程序的体系结构旨在简化组件的重用,任何应用程序都能发布他的功能且任何其余应用程序能够使用这些功能(须要服从框架执行的安全限制)。这一机制容许用户替换组件。
全部的应用程序实际上是一组服务和系统,包括:
· 视图(View)——丰富的、可扩展的视图集合,可用于构建一个应用程序。包括包括列表、网格、文本框、按钮,甚至是内嵌的网页浏览器
· 内容提供者(Content Providers)——使应用程序能访问其余应用程序(如通信录)的数据,或共享本身的数据
· 资源管理器(Resource Manager)——提供访问非代码资源,如本地化字符串、图形和布局文件
· 通知管理器(Notification Manager)——使全部的应用程序可以在状态栏显示自定义警告
· 活动管理器(Activity Manager)——管理应用程序生命周期,提供通用的导航回退功能
Android装配一个核心应用程序集合,包括电子邮件客户端、SMS程序、日历、地图、浏览器、联系人和其余设置。全部应用程序都是用Java编程语言写的。更加丰富的应用程序有待咱们去开发!
1、Socket通讯简介
Android 与服务器的通讯方式主要有两种,一是Http通讯,一是Socket通讯。二者的最大差别在于,http链接使用的是“请求—响应方式”,即在请求时创建 链接通道,当客户端向服务器发送请求后,服务器端才能向客户端返回数据。而Socket通讯则是在双方创建起链接后就能够直接进行数据的传输,在链接时可 实现信息的主动推送,而不须要每次由客户端想服务器发送请求。 那么,什么是socket?Socket又称套接字,在程序内部提供了与外界通讯的端口,即端口通讯。经过创建socket链接,可为通讯双方的数据传输 传提供通道。socket的主要特色有数据丢失率低,使用简单且易于移植。
1.2Socket的分类
根据不一样的的底层协议,Socket的实现是多样化的。本指南中只介绍TCP/IP协议族的内容,在这个协议族当中主要的Socket类型为流套接字 (streamsocket)和数据报套接字(datagramsocket)。流套接字将TCP做为其端对端协议,提供了一个可信赖的字节流服务。数据 报套接字使用UDP协议,提供数据打包发送服务。
2、Socket 基本通讯模型
3、Socket基本实现原理
3.1基于TCP协议的Socket
服务器端首先声明一个ServerSocket对象而且指定端口号,而后调 用Serversocket的accept()方法接收客户端的数据。accept()方法在没有数据进行接收的处于堵塞状态。 (Socketsocket=serversocket.accept()),一旦接收到数据,经过inputstream读取接收的数据。
客户端建立一个Socket对象,指定服务器端的ip地址和端口号 (Socketsocket=newSocket("172.168.10.108",8080);),经过inputstream读取数据,获取服务器 发出的数据(OutputStreamoutputstream=socket.getOutputStream()),最后将要发送的数据写入到 outputstream便可进行TCP协议的socket数据传输。
3.2基于UDP协议的数据传输
服务器端首先建立一个DatagramSocket对象,而且指点监听的端 口。接下来建立一个空的DatagramSocket对象用于接收数据 (bytedata[]=newbyte[1024;]DatagramSocketpacket=newDatagramSocket(data,data.length)), 使用DatagramSocket的receive方法接收客户端发送的数据,receive()与serversocket的accepet()相似, 在没有数据进行接收的处于堵塞状态。
客户端也建立个DatagramSocket对象,而且指点监听的端口。接 下来建立一个InetAddress对象,这个对象相似与一个网络的发送地址 (InetAddressserveraddress=InetAddress.getByName("172.168.1.120")).定义要发送的 一个字符串,建立一个DatagramPacket对象,并制定要讲这个数据报包发送到网络的那个地址以及端口号,最后使用DatagramSocket 的对象的send()发送数据。*(Stringstr="hello";bytedata[]=str.getByte(); DatagramPacketpacket=new DatagramPacket(data,data.length,serveraddress,4567);socket.send(packet);)
4、android 实现socket简单通讯
4.1使用TCP协议通讯
android端实现:
[java] view plaincopy
1. protected void connectServerWithTCPSocket() {
2.
3. Socket socket;
4. try {// 建立一个Socket对象,并指定服务端的IP及端口号
5. socket = new Socket("192.168.1.32", 1989);
6. // 建立一个InputStream用户读取要发送的文件。
7. InputStream inputStream = new FileInputStream("e://a.txt");
8. // 获取Socket的OutputStream对象用于发送数据。
9. OutputStream outputStream = socket.getOutputStream();
10. // 建立一个byte类型的buffer字节数组,用于存放读取的本地文件
11. byte buffer[] = new byte[4 * 1024];
12. int temp = 0;
13. // 循环读取文件
14. while ((temp = inputStream.read(buffer)) != -1) {
15. // 把数据写入到OuputStream对象中
16. outputStream.write(buffer, 0, temp);
17. }
18. // 发送读取的数据到服务端
19. outputStream.flush();
20.
21. /** 或建立一个报文,使用BufferedWriter写入,看你的需求 **/
22. // String socketData = "[2143213;21343fjks;213]";
23. // BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
24. // socket.getOutputStream()));
25. // writer.write(socketData.replace("\n", " ") + "\n");
26. // writer.flush();
27. /************************************************/
28. } catch (UnknownHostException e) {
29. e.printStackTrace();
30. } catch (IOException e) {
31. e.printStackTrace();
32. }
33.
34. }
服务器端简单实现:
[java] view plaincopy
1. public void ServerReceviedByTcp() {
2. // 声明一个ServerSocket对象
3. ServerSocket serverSocket = null;
4. try {
5. // 建立一个ServerSocket对象,并让这个Socket在1989端口监听
6. serverSocket = new ServerSocket(1989);
7. // 调用ServerSocket的accept()方法,接受客户端所发送的请求,
8. // 若是客户端没有发送数据,那么该线程就停滞不继续
9. Socket socket = serverSocket.accept();
10. // 从Socket当中获得InputStream对象
11. InputStream inputStream = socket.getInputStream();
12. byte buffer[] = new byte[1024 * 4];
13. int temp = 0;
14. // 从InputStream当中读取客户端所发送的数据
15. while ((temp = inputStream.read(buffer)) != -1) {
16. System.out.println(new String(buffer, 0, temp));
17. }
18. serverSocket.close();
19. } catch (IOException e) {
20. e.printStackTrace();
21. }
22. }
4.2使用UDP协议通讯
客户端发送数据实现:
[java] view plaincopy
1. protected void connectServerWithUDPSocket() {
2.
3. DatagramSocket socket;
4. try {
5. //建立DatagramSocket对象并指定一个端口号,注意,若是客户端须要接收服务器的返回数据,
6. //还须要使用这个端口号来receive,因此必定要记住
7. socket = new DatagramSocket(1985);
8. //使用InetAddress(Inet4Address).getByName把IP地址转换为网络地址
9. InetAddress serverAddress = InetAddress.getByName("192.168.1.32");
10. //Inet4Address serverAddress = (Inet4Address) Inet4Address.getByName("192.168.1.32");
11. String str = "[2143213;21343fjks;213]";//设置要发送的报文
12. byte data[] = str.getBytes();//把字符串str字符串转换为字节数组
13. //建立一个DatagramPacket对象,用于发送数据。
14. //参数一:要发送的数据 参数二:数据的长度 参数三:服务端的网络地址 参数四:服务器端端口号
15. DatagramPacket packet = new DatagramPacket(data, data.length ,serverAddress ,10025);
16. socket.send(packet);//把数据发送到服务端。
17. } catch (SocketException e) {
18. e.printStackTrace();
19. } catch (UnknownHostException e) {
20. e.printStackTrace();
21. } catch (IOException e) {
22. e.printStackTrace();
23. }
24. }
客户端接收服务器返回的数据:
[java] view plaincopy
1. public void ReceiveServerSocketData() {
2. DatagramSocket socket;
3. try {
4. //实例化的端口号要和发送时的socket一致,不然收不到data
5. socket = new DatagramSocket(1985);
6. byte data[] = new byte[4 * 1024];
7. //参数一:要接受的data 参数二:data的长度
8. DatagramPacket packet = new DatagramPacket(data, data.length);
9. socket.receive(packet);
10. //把接收到的data转换为String字符串
11. String result = new String(packet.getData(), packet.getOffset(),
12. packet.getLength());
13. socket.close();//不使用了记得要关闭
14. System.out.println("the number of reveived Socket is :" + flag
15. + "udpData:" + result);
16. } catch (SocketException e) {
17. e.printStackTrace();
18. } catch (IOException e) {
19. e.printStackTrace();
20. }
21. }
服务器接收客户端实现:
[java] view plaincopy
1. public void ServerReceviedByUdp(){
2. //建立一个DatagramSocket对象,并指定监听端口。(UDP使用DatagramSocket)
3. DatagramSocket socket;
4. try {
5. socket = new DatagramSocket(10025);
6. //建立一个byte类型的数组,用于存放接收到得数据
7. byte data[] = new byte[4*1024];
8. //建立一个DatagramPacket对象,并指定DatagramPacket对象的大小
9. DatagramPacket packet = new DatagramPacket(data,data.length);
10. //读取接收到得数据
11. socket.receive(packet);
12. //把客户端发送的数据转换为字符串。
13. //使用三个参数的String方法。参数一:数据包 参数二:起始位置 参数三:数据包长
14. String result = new String(packet.getData(),packet.getOffset() ,packet.getLength());
15. } catch (SocketException e) {
16. e.printStackTrace();
17. } catch (IOException e) {
18. e.printStackTrace();
19. }
20. }
5、总结:
使用UDP方式android端和服务器端接收能够看出,其实android端和服务器端的发送和接收大庭相径,只要端口号正确了,相互通讯就没有问题,TCP使用的是流的方式发送,UDP是以包的形式发送。
本示例以Servlet为例,演示Android与Servlet的通讯。
众所周知,Android与服务器通讯一般采用HTTP通讯方式和Socket通讯方式,而HTTP通讯方式又分get和post两种方式。至于Socket通讯会在之后的博文中介绍。
HTTP协议简介:
HTTP (Hypertext Transfer Protocol ),是Web联网的基础,也是手机联网经常使用的协议之一,HTTP协议是创建在TCP协议之上的一种协议。
HTTP链接最显 著的特色是客户端发送的每次请求都须要服务器回送响应,在请求结束后,会主动释放链接。从创建链接到关闭链接的过程称为“一次链接”。 在HTTP 1.0中,客户端的每次请求都要求创建一次单独的链接,在处理完本次请求后,就自动释放链接。 在HTTP 1.1中则能够在一次链接中处理多个请求,而且多个请求能够重叠进行,不须要等待一个请求结束后再发送下一个请求。
由 于HTTP在每次请求结束后都会主动释放链接,所以HTTP链接是一种“短链接”、“无状态”,要保持客户端程序的在线状态,须要不断地向服务器发起链接 请求。一般的作法是即便不须要得到任何数据,客户端也保持每隔一段固定的时间向服务器发送一次“保持链接”的请求,服务器在收到该请求后对客户端进行回 复,代表知道客户端“在线”。若服务器长时间没法收到客户端的请求,则认为客户端“下线”,若客户端长时间没法收到服务器的回复,则认为网络已经断开。
基于HTTP1.0协议的客户端在每次向服务器发出请求后,服务器就会向客户端返回响应消息,在确认客户端已经收到响应消息后,服务端就会关闭网络链接。在这个数据传输过程当中,并不保存任何历史信息和状态信息,所以,HTTP协议也被认为是无状态的协议。
HTTP1.1 和HTTP1.0相比较而言,最大的区别就是增长了持久链接支持。当客户端使用HTTP1.1协议链接到服务器后,服务器就将关闭客户端链接的主动权交还 给客户端;也就是说,只要不调用Socket类的close方法关闭网络链接,就能够继续向服务器发送HTTP请求。
HTTP链接使用的是“请求—响应”的方式(2次握手),不只在请求时须要先创建链接,并且须要客户端向服务器发出请求后,服务器端才能回复数据。而Socket链接在双方创建起链接后就能够直接进行数据的传输
HTTP协议的特色:
支持B/S及C/S模式;
简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法经常使用的有GET、HEAD、POST。
灵活:HTTP 容许传输任意类型的数据对象。正在传输的类型由Content-Type 加以标记;
无状态:HTTP 协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺乏状态意味着若是后续处理须要前面的信息,则它必须重传,这样可能致使每次链接传送的数据量增大。
HTTP协议请求方法:
请求行中包括了请求方法,解释以下:
GET 请求获取Request-URI 所标识的资源;
POST 在Request-URI 所标识的资源后附加新的数据;
HEAD 请求获取由Request-URI 所标识的资源的响应消息报头
PUT 请求服务器存储一个资源,并用Request-URI 做为其标识
DELETE 请求服务器删除Request-URI 所标识的资源;
TRACE 请求服务器回送收到的请求信息,主要用于测试或诊断
CONNECT 保留未来使用
OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求
Get与Post请求区别:
Post 请求能够向服务器传送数据,并且数据放在HTML HEADER内一块儿传送到服务端URL地址,数据对用户不可见。而get是把参数数据队列加到提交的URL中,值和表单内各个字段一一对应, 例如(http://www.baidu.com/s?w=%C4&inputT=2710)
get 传送的数据量较小,不能大于2KB。post传送的数据量较大,通常被默认为不受限制。但理论上,IIS4中最大量为80KB,IIS5中为100KB。
get安全性很是低,post安全性较高。
在Android开发中咱们常常会用到网络链接功能与服务器进行数据的交互,为此Android的SDK提供了Apache的HttpClient来方便咱们使用各类Http服务
///
Get() 先建立一个HttpClient 而后再建立一个HttpGet,经过HttpClient的execute方法来发送一个HttpGet而且返回String内容。
try {
// 建立一个默认的HttpClient
HttpClient httpclient =new DefaultHttpClient();
// 建立一个GET请求
HttpGet request =new HttpGet("www.google.com");
// 发送GET请求,并将响应内容转换成字符串
String response = httpclient.execute(request, new BasicResponseHandler());
Log.v("response text", response);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
///////////////////////////////
Post()
publicstatic String post(String url, NameValuePair... params) {
try {
// 编码参数
List<NameValuePair> formparams =new ArrayList<NameValuePair>(); // 请求参数
for (NameValuePair p : params) {
formparams.add(p);
}
UrlEncodedFormEntity entity =new UrlEncodedFormEntity(formparams,
CHARSET);
// 建立POST请求
HttpPost request =new HttpPost(url);
request.setEntity(entity);
// 发送请求
HttpClient client = getHttpClient();
HttpResponse response = client.execute(request);
if(response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
thrownew RuntimeException("请求失败");
}
HttpEntity resEntity = response.getEntity();
return (resEntity ==null) ?null : EntityUtils.toString(resEntity, CHARSET);
} catch (UnsupportedEncodingException e) {
Log.w(TAG, e.getMessage());
returnnull;
} catch (ClientProtocolException e) {
Log.w(TAG, e.getMessage());
returnnull;
} catch (IOException e) {
thrownew RuntimeException("链接失败", e);
}
}
整理:杨光福&王飞龙
时间仓促,不免有不周之处,请见谅。
http://www.cnblogs.com/pepcod/archive/2013/02/11/2937403.html
能够用咱们上课讲的说
也能够参照
http://blog.saymagic.cn/2015/01/30/android-pic-three-cache.html
http://www.cnblogs.com/elliotta/p/3633752.html
http://blog.csdn.net/yudajun/article/details/9323941
技术方面说明
http://blog.csdn.net/lwyygydx/article/details/41870377
功能改进方面说明
http://digi.tech.qq.com/a/20150121/012030.htm
能够参照李延磊老师的
也能够参照连接
http://blog.csdn.net/fancylovejava/article/details/39927539
xUtils,Gson 极光推送 都讲过,忽略
友盟第三方登陆
http://blog.umeng.com/uncategorized/4160.html
第三方登陆案例
http://blog.csdn.net/yueqinglkong/article/details/15028041
http://blog.csdn.net/lyf_007217/article/details/8542238
http://www.cnblogs.com/devinzhang/p/3856200.html
http://www.360doc.com/content/14/0402/09/10504424_365635496.shtml
http://blog.csdn.net/androidzhaoxiaogang/article/details/7910364
http://www.2cto.com/kf/201409/335964.html
http://blog.csdn.net/u200814499/article/details/40391443
http://blog.csdn.net/jiangliloveyou/article/details/9849775
http://blog.csdn.net/lnb333666/article/details/7471292
http://skywen.iteye.com/blog/1811310
已经讲了,请看视频
已经讲了,请看视频
已经讲了,请看视频
http://blog.csdn.net/wuqiong_524itcast/article/details/25378685
http://blog.csdn.net/wangshione/article/details/8490245
http://blog.csdn.net/lnb333666/article/details/8031770
1.垃圾收集算法的核心思想
Java语言创建了垃圾收集机制,用以跟踪正在使用的对象和发现并回收再也不使用(引用)的对象。该机制能够有效防范动态内存分配中因内存垃圾过多而引起的内存耗尽,以及不恰当的内存释放所形成的内存非法引用。
垃圾收集算法的核心思想是:对虚拟机可用内存空间,即堆空间中的对象进行识别,若是对象正在被引用,那么称其为存活对象,反之,若是对象再也不被引用,则 为垃圾对象,能够回收其占据的空间,用于再分配。垃圾收集算法的选择和垃圾收集系统参数的合理调节直接影响着系统性能,所以须要开发人员作比较深刻的了解。
2.触发主GC(Garbage Collector)的条件
JVM进行次GC的频率很高,但由于这种GC占用时间极短,因此对系统产生的影响不大。更值得关注的是主GC的触发条件,由于它对系统影响很明显。总的来讲,有两个条件会触发主GC:
①当应用程序空闲时,即没有应用线程在运行时,GC会被调用。由于GC在优先级最低的线程中进行,因此当应用忙时,GC线程就不会被调用,但如下条件除外。
②Java堆内存不足时,GC会被调用。当应用线程在运行,并在运行过程当中建立新对象,若这时内存空间不足,JVM就会强制地调用GC线程,以 便回收内存用于新的分配。若GC一次以后仍不能知足内存分配的要求,JVM会再进行两次GC做进一步的尝试,若仍没法知足要求,则 JVM将报“out of memory”的错误,Java应用将中止。
3.减小GC开销的措施
根据上述GC的机制,程序的运行会直接影响系统环境的变化,从而影响GC的触发。若不针对GC的特色进行设计和编码,就会出现内存驻留等一系列负面影响。为了不这些影响,基本的原则就是尽量地减小垃圾和减小GC过程当中的开销。具体措施包括如下几个方面:
(1)不要显式调用System.gc()
此函数建议JVM进行主GC,虽然只是建议而非必定,但不少状况下它会触发主GC,从而增长主GC的频率,也即增长了间歇性停顿的次数。
(2)尽可能减小临时对象的使用
临时对象在跳出函数调用后,会成为垃圾,少用临时变量就至关于减小了垃圾的产生,从而延长了出现上述第二个触发条件出现的时间,减小了主GC的机会。
(3)对象不用时最好显式置为Null
通常而言,为Null的对象都会被做为垃圾处理,因此将不用的对象显式地设为Null,有利于GC收集器断定垃圾,从而提升了GC的效率。
(4)尽可能使用StringBuffer,而不用String来累加字符串(详见blog另外一篇文章JAVA中String与StringBuffer)
因为String是固定长的字符串对象,累加String对象时,并不是在一个String对象中扩增,而是从新建立新的String对象,如 Str5=Str1+Str2+Str3+Str4,这条语句执行过程当中会产生多个垃圾对象,由于对次做“+”操做时都必须建立新的String对象,但 这些过渡对象对系统来讲是没有实际意义的,只会增长更多的垃圾。避免这种状况能够改用StringBuffer来累加字符串,因StringBuffer 是可变长的,它在原有基础上进行扩增,不会产生中间对象。
(5)能用基本类型如Int,Long,就不用Integer,Long对象
基本类型变量占用的内存资源比相应对象占用的少得多,若是没有必要,最好使用基本变量。
(6)尽可能少用静态对象变量
静态变量属于全局变量,不会被GC回收,它们会一直占用内存。
(7)分散对象建立或删除的时间
集中在短期内大量建立新对象,特别是大对象,会致使忽然须要大量内存,JVM在面临这种状况时,只能进行主GC,以回收内存或整合内存碎片, 从而增长主GC的频率。集中删除对象,道理也是同样的。它使得忽然出现了大量的垃圾对象,空闲空间必然减小,从而大大增长了下一次建立新对象时强制主GC 的机会。
gc()函数的做用只是提醒虚拟机:程序员但愿进行一次垃圾回收。可是它不能保证垃圾回收必定会进行,并且具体何时进行是取决于具体的虚拟机的,不一样的虚拟机有不一样的对策。在Davilk中,给程序分配的内存是根据机型厂商的不一样而不一样(如今大部分为32MB),在VM内部会将内存分为:java使用的内存,Native使用的内存,他们之间不能共享,当某一方面不足
的时候必须向VM申请,而不能直接使用另一个的内存。
出现内存泄漏的可能性:
出现状况:
1. 数据库的cursor没有关闭
2.构造adapter时,没有使用缓存contentview
衍生listview的优化问题-----减小建立view的对象,充分使用contentview,能够使用一静态类来优化处理getview的过程
3.Bitmap对象不使用时采用recycle()释放内存
4.activity中的对象的生命周期大于activity
调试方法: DDMS==> HEAPSZIE==>dataobject==>[Total Size]
1、 Android的内存机制
Android的程序由Java语言编写,因此Android的内存管理与Java的内存管理类似。程序员经过new为对象分配内存,全部对象在java 堆内分配空间;然而对象的释放是由垃圾回收器来完成的。C/C++中的内存机制是“谁污染,谁治理”,java的就比较人性化了,给咱们请了一个专门的清 洁工(GC)
2、GC是什么? 为何要有GC?
GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会致使程序或系统的不稳定甚至崩溃,Java提供的GC功能能够 自动监测对象是否超过做用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操做方法。
4、垃圾回收器的基本原理是什么?垃圾回收器能够立刻回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?
对于GC来讲,当程序员建立对象时,GC就开始监控这个对象的地址、大小以及使用状况。一般,GC采用有向图的方式记录和管理堆(heap)中的全部对 象。经过这种方式肯定哪些对象是"可达的",哪些对象是"不可达的"。当GC肯定一些对象为"不可达"时,GC就有责任回收这些内存空间。能够。程序员可 以手动执行System.gc(),通知GC运行,可是Java语言规范并不保证GC必定会执行。
间而忘记了释放。若是程序中存在对无用对象的引用,那么这些对象就会驻留内存,消耗内存,由于没法让垃圾回收器GC验证这些对象是否再也不须要。若是存在对 象的引用,这个对象就被定义为"有效的活动",同时不会被释放。要肯定对象所占内存将被回收,咱们就要务必确认该对象再也不会被使用。典型的作法就是把对象 数据成员设为null或者从集合中移除该对象。但当局部变量不须要时,不需明显的设为null,由于一个方法执行完毕时,这些引用会自动被清理。
Java带垃圾回收的机制,为何还会内存泄露呢?举例:
[java] view plaincopyprint?
1. Vector v = new Vector(10);
2. for (int i = 1; i < 100; i++) {
3. Object o = new Object();
4. v.add(o);
5. o = null;
6. }// 此时,全部的Object对象都没有被释放,由于变量v引用这些对象。
Java 内存泄露的根本缘由就是 保存了不可能再被访问的变量类型的引用
6、Android的内存溢出
Android的内存溢出是如何发生的?
Android的虚拟机是基于寄存器的Dalvik,它的最大堆大小通常是16M,有的机器为24M。也就是说咱们所能利用的内存空间是有限的。若是咱们的内存占用超过了必定的水平就会出现OutOfMemory的错误。
为何会出现内存不够用的状况呢?我想缘由主要有两个:
因为咱们程序的失误,长期保持某些资源(如Context)的引用,形成内存泄露,资源形成得不到释放。保存了多个耗用内存过大的对象(如Bitmap),形成内存超出限制。
(一)、(二)中,咱们了解了一些基本概念。
600dp的含义是:表明这个设备的最短的那一边。
获取设备的最短边的代码是:Configuration config = getResources().getConfiguration();
int smallestScreenWidth = config.smallestScreenWidthDp;
这个时候拿smallestScreenWidth 与600想比较就能够知道该设备可否读取里面的资源了。
)
除此以外,为了方便适配,在编码时咱们还应该注意什么呢,主要有如下几点:
(1)多使用权重(android:layout_weight)
尤为是在tab切换布局,listview title及Item布局等状况下;
(2)设置宽度和高度时,尽可能使用match_parent和wrap_content,避免把控件宽高设死;
(3)父容器布局选用
多使用RelativeLayout,FrameLayout,GridLayout等,减小布局层次。固然,在使用
权重时,得采用LinearLayout;
(4) 在xml里,设置高度、宽度采用dp(dip),设置字体采用sp。
(应该注意,在代码里面,咱们写的setHeight(...)单位是px)
(二)
那么在具体开发中,咱们应该注意什么呢。
首先,咱们必需要知道,其实适配的关键在于两点:
(1)不一样分辨率设备的适配,这点在单位的使用上用dp、sp以及图片资源存放于不一样的drawable文件夹就能够解决问题;
(2)不一样尺寸的适配,这点主要靠将相关值以及布局文件放置于不一样的文件夹中来解决。
2.1 values文件夹
能够在工程下建立不一样的values文件夹:values-sw480dp, values-sw600dp,
values-sw720dp-land等。好比一个控件的宽度,在10寸pad上是10dp,在8寸pad
上是5dp。这时,你能够定义一个变量,button_width,而后在values-sw600dp
下写5dp,在values-sw720-land下写
10dp。这样就达到了在不一样尺寸pad上,
相应控件大小不同的效果。
2.1 layout文件夹
若是在不一样尺寸设备上展现的布局有明显差异,仅仅用values不一样已经难以控制,
那么就能够考虑写不一样的布局文件置于不一样的layout文件夹下,android会根据设备
尺寸去加载相应文件夹下的布局文件。如:layout-sw480dp,layout-sw600dp,
layout-sw700dp等。
值得注意的是,若是不是颇有必要,尽可能采用2.1方案,方便维护。若是尺寸和分辨率都不一样,
那么就要结合(1)、(2)考虑了。
(补充:其实values文件夹和layout文件夹不只仅是根据尺寸判断,也和分辨率有关,不过在一般状况下,
综合计算考虑,仅根据尺寸判断就能够了: