FrameLayout(帧布局),LinearLayout (线性布局),AbsoluteLayout(绝对布局),RelativeLayout(相对布局),TableLayout(表格布局) FrameLayout 从屏幕的左上角开始布局,叠加显示, 实际应用 播放器的暂停按钮. LinearLayout 线性布局,这个东西,从外框上可以理解为一个div,他首先是一个一个从上往下罗列在屏幕上。每一个LinearLayout里面又可分为垂直布局 (android:orientation="vertical")和水平布局(android:orientation="horizontal" )。当垂直布局时,每一行就只有一个元素,多个元素依次垂直往下;水平布局时,只有一行,每一个元素依次向右排列。 AbsoluteLayout 绝对布局犹如div指定了absolute属性,用X,Y坐标来指定元素的位置android:layout_x="20px" view android:layout_y="12px" fwvga 854*480apk qq斗地主 qq游戏大厅800*480 800*480.apk fwvga 854*480 指定平板机型的游戏开发中经常用到绝对布局 widget 绝对布局 指定机型的平板游戏开发. 2.3 3.0 1. 界面布局 任务管理器 gridview 2. 手机 任务管理 listview lephone lepad RelativeLayout 相对布局可以理解为某一个元素为参照物,来定位的布局方式。主要属性有: 相对于某一个元素 android:layout_below="@id/aaa" 该元素在 id为aaa的下面 android:layout_toLeftOf="@id/bbb" 改元素的左边是bbb 相对于父元素的地方 android:layout_alignParentLeft="true" 在父元素左对齐 android:layout_alignParentRight="true" 在父元素右对齐 Android oa客户端. TableLayout 表格布局类似Html里面的Table。每一个TableLayout里面有表格行TableRow,TableRow里面可以具体定义每一个元素,设定他的对齐方式android:gravity="" 。 每一个布局都有自己适合的方式,另外,这五个布局元素可以相互嵌套应用,做出美观的界面。 oa 自动化 生成报表 ,图标 表示 webview css div webview
17.谈谈UI中,Padding和Margin有什么区别?
Padding 文字对边框, margin是控件对父窗体. Padding 盒子里面的内容距离盒子的距离 , margin 盒子与盒子之间的距离
18.请解释下在单线程模型中Message、Handler、Message Queue、Looper之间的关系。
简单的说,Handler 获取当前线程中的looper对象,looper用来从存放Message的MessageQueue中取出Message,再有Handler进行Message的分发和处理. Message Queue(消息队列) :用来存放通过Handler发布的消息,通常附属于某一个创建它的线程,可以通过Looper.myQueue()得到当前线程的消息队列. Handler: 可以发布或者处理一个消息或者操作一个Runnable,通过Handler发布消息,消息将只会发送到与它关联的消息队列,然也只能处理该消息队列中的消息. Looper: 是Handler和消息队列之间通讯桥梁,程序组件首先通过Handler把消息传递给Looper,Looper把消息放入队列。Looper也把消息队列里的消息广播给所有的Handler:Handler接受到消息后调用handleMessage进行处理. Message: 消息的类型,在Handler类中的handleMessage方法中得到单个的消息进行处理,在单线程模型下,为了线程通信问题,Android设计了一个Message Queue(消息队列),线程间可以通过该Message Queue并结合Handler和Looper组件进行信息交换。下面将对它们进行分别介绍: 1. Message Message消息,理解为线程间交流的信息,处理数据后台线程需要更新UI,则发送Message内含一些数据给UI线程。 2. Handler Handler处理者,是Message的主要处理者,负责Message的发送,Message内容的执行处理。后台线程就是通过传进来的 Handler对象引用来sendMessage(Message)。而使用Handler,需要implement 该类的 handleMessage(Message)方法,它是处理这些Message的操作内容,例如Update UI。通常需要子类化Handler来实现handleMessage方法。 3. Message Queue Message Queue消息队列,用来存放通过Handler发布的消息,按照先进先出执行。 每个message queue都会有一个对应的Handler。Handler会向message queue通过两种方法发送消息:sendMessage或post。这两种消息都会插在message queue队尾并按先进先出执行。但通过这两种方法发送的消息执行的方式略有不同:通过sendMessage发送的是一个message对象,会被 Handler的handleMessage()函数处理;而通过post方法发送的是一个runnable对象,则会自己执行。 4. Looper Looper是每条线程里的Message Queue的管家。Android没有Global的Message Queue,而Android会自动替主线程(UI线程)建立Message Queue,但在子线程里并没有建立Message Queue。所以调用Looper.getMainLooper()得到的主线程的Looper不为NULL,但调用Looper.myLooper() 得到当前线程的Looper就有可能为NULL。对于子线程使用Looper,API Doc提供了正确的使用方法:这个Message机制的大概流程: 1. 在Looper.loop()方法运行开始后,循环地按照接收顺序取出Message Queue里面的非NULL的Message。 2. 一开始Message Queue里面的Message都是NULL的。当Handler.sendMessage(Message)到Message Queue,该函数里面设置了那个Message对象的target属性是当前的Handler对象。随后Looper取出了那个Message,则调用该Message的target指向的Hander的dispatchMessage函数对Message进行处理。在dispatchMessage方法里,如何处理Message则由用户指定,三个判断,优先级从高到低: 1) Message里面的Callback,一个实现了Runnable接口的对象,其中run函数做处理工作; 2) Handler里面的mCallback指向的一个实现了Callback接口的对象,由其handleMessage进行处理; 3) 处理消息Handler对象对应的类继承并实现了其中handleMessage函数,通过这个实现的handleMessage函数处理消息。 由此可见,我们实现的handleMessage方法是优先级最低的! 3. Handler处理完该Message (update UI) 后,Looper则设置该Message为NULL,以便回收! 在网上有很多文章讲述主线程和其他子线程如何交互,传送信息,最终谁来执行处理信息之类的,个人理解是最简单的方法——判断Handler对象里面的Looper对象是属于哪条线程的,则由该线程来执行! 1. 当Handler对象的构造函数的参数为空,则为当前所在线程的Looper; 2. Looper.getMainLooper()得到的是主线程的Looper对象,Looper.myLooper()得到的是当前线程的Looper对象。
19.AIDL的全称是什么?如何工作?
AIDL的英文全称是Android Interface Define Language当A进程要去调用B进程中的service时,并实现通信,我们通常都是通过AIDL来操作的A工程:首先我们在net.blogjava.mobile.aidlservice包中创建一个RemoteService.aidl文件,在里面我们自定义一个接口,含有方法get。ADT插件会在gen目录下自动生成一个RemoteService.java文件,该类中含有一个名为RemoteService.stub的内部类,该内部类中含有aidl文件接口的get方法。说明一:aidl文件的位置不固定,可以任意然后定义自己的MyService类,在MyService类中自定义一个内部类去继承RemoteService.stub这个内部类,实现get方法。在onBind方法中返回这个内部类的对象,系统会自动将这个对象封装成IBinder对象,传递给他的调用者。其次需要在AndroidManifest.xml文件中配置MyService类,代码如下: 为什么要指定调用AIDL服务的ID,就是要告诉外界MyService这个类能够被别的进程访问,只要别的进程知道这个ID,正是有了这个ID,B工程才能找到A工程实现通信。说明:AIDL并不需要权限B工程: 首先我们要将A工程中生成的RemoteService.java文件拷贝到B工程中,在bindService方法中绑定aidl服务 绑定AIDL服务就是将RemoteService的ID作为intent的action参数。 说明:如果我们单独将RemoteService.aidl文件放在一个包里,那个在我们将gen目录下的该包拷贝到B工程中。如果我们将RemoteService.aidl文件和我们的其他类存放在一起,那么我们在B工程中就要建立相应的包,以保证RmoteService.java文件的报名正确,我们不能修改RemoteService.java文件 bindService(new Inten("net.blogjava.mobile.aidlservice.RemoteService"), serviceConnection, Context.BIND_AUTO_CREATE); ServiceConnection的onServiceConnected(ComponentName name, IBinder service)方法中的service参数就是A工程中MyService类中继承了RemoteService.stub类的内部类的对象。
20.请解释下Android程序运行时权限与文件系统权限的区别。
Android程序执行需要读取到安全敏感项必需在androidmanifest.xml中声明相关权限请求, 打电话,访问网络,获取坐标,读写sd卡,读写联系人等..安装的时候会提示用户… 文件系统的权限是linux权限. 比如说sharedpreference里面的Context.Mode.private Context.Mode.world_read_able Context.Mode_world_writeable 777自己 同组 其他
21.系统上安装了多种浏览器,能否指定某浏览器访问指定页面
Intent intent =newIntent(); intent.setAction("android.intent.action.VIEW"); Uri content_url =Uri.parse(" http://www.163.com "); intent.setData(content_url); intent.setClassName("com.android.browser","com.android.browser.BrowserActivity"); startActivity(intent); 只要修改以intent.setClassName("com.android.browser","com.android.browser.BrowserActivity"); 中相应的应用程序packagename 和要启动的activity即可启动其他浏览器来 uc浏览器":"com.uc.browser", "com.uc.browser.ActivityUpdate“ opera浏览器:"com.opera.mini.android", "com.opera.mini.android.Browser" qq浏览器:"com.tencent.mtt", "com.tencent.mtt.MainActivity"
22.对android主线程的运用和理解。
23.对android虚拟机的理解,包括内存管理机制垃圾回收机制。 dalvik和art区别
虚拟机很小,空间很小,谈谈移动设备的虚拟机的大小限制 16M , 谈谈加载图片的时候怎么处理大图片的, outmemoryException BitmapFactory.option 垃圾回收,没有引用的对象,在某个时刻会被系统gc掉 . Dalvik和标准Java 虚拟机 (JVM)首要差别 Dalvik 基于 寄存器 ,而 JVM 基于栈。 基于 寄存器 的 虚拟机 对于编译后变大的程序来说,在它们执行的时候,花费的时间更短。 Dalvik和Java运行环境的区别 1:Dalvik主要是完成对象生命周期管理, 堆栈 管理,线程管理,安全和异常管理,以及 垃圾回收 等等重要功能。 2:Dalvik负责进程隔离和线程管理,每一个Android应用在底层都会对应一个独立的Dalvik 虚拟机 实例,其代码在虚拟机的解释下得以执行。 3:不同于Java 虚拟机 运行java 字节码 ,Dalvik虚拟机运行的是其专有的 文件格式 Dex 4:dex 文件格式 可以减少整体文件尺寸,提高I/o操作的类查找速度。 5:odex是为了在运行过程中进一步提高性能,对dex文件的进一步优化。 6:所有的Android应用的线程都对应一个Linux线程, 虚拟机 因而可以更多的依赖 操作系统 的 线程调度 和管理机制 7:有一个特殊的 虚拟机 进程Zygote,他是虚拟机实例的孵化器。它在系统启动的时候就会产生,它会完成 虚拟机 的初始化,库的加载,预制类库和初始化的操作。如果系统需要一个新的 虚拟机 实例,它会迅速复制自身,以最快的数据提供给系统。对于一些只读的系统库,所有 虚拟机 实例都和Zygote共享一块内存区域。 8:Dalvik是由Dan Bornstein编写的,名字来源于他的祖先曾经居住过名叫Dalvík的小渔村,村子位于冰岛Eyjafjörður 许多GC实现都是在对象开头的地方留一小块空间给GC标记用。Dalvik VM则不同,在进行GC的时候会单独申请一块空间,以位图的形式来保存整个堆上的对象的标记,在GC结束后就释放该空间。 dalvik是执行的时候编译+运行,安装比较快,开启应用比较慢,应用占用空间小ART是安装的时候就编译好了,执行的时候直接就可以运行的,安装慢,开启应用快,占用空间大用个比喻来说就是,骑自行车dalvik 是已经折叠起来的自行车,每次骑都要先组装自行车才能骑ART 是已经组装好的自行车,每次骑直接上车就能走人效率高在开启的时候,运行中的速度是差不多的
24.Framework工作方式及原理,Activity是如何生成一个view的,机制是什么。
主要用到反射和代理的知识。主要用pull解析xml,然后通过反射得到属性,在onDrew画出来 反射 , 配置文件 可以讲下activity的源码,比如说 每个activity里面都有window.callback和keyevent.callback,一些回调的接口或者函数吧. 框架把activity创建出来就会调用里面的这些回调方法,会调用activity生命周期相关的方法. Activity创建一个view是通过ondraw 画出来的, 画这个view之前呢,还会调用onmeasure方法来计算显示的大小.
25.android本身的一些限制,比如apk包大小限制,读取大文件时的时间限
这个问题问的有问题, apk包大小限制不好说, 极品飞车有100M 还是能装到手机上, 世面google market 上大程序 主程序 很小 5~10M 下载sdcard 200~300M 15分钟之内 申请退款 apk包,精简包, 素材存放在服务器. 游戏程序. 读大文件的时间限制应该是main线程里面的时间限制吧.5秒.
26.Android程序与Java程序的区别?
Android程序用android sdk开发,java程序用javasdk开发. Android SDK引用了大部分的Java SDK,少数部分被Android SDK抛弃,比如说界面部分,java.awt swing package除了java.awt.font被引用外,其他都被抛弃,在Android平台开发中不能使用。 android sdk 添加工具jar httpclient , pull opengl 将Java 游戏或者j2me程序移植到Android平台的过程中, Android SDK 与Java SDK的区别是很需要注意的地方。 sampleDataAdpter("YY-MM-DD")
27.Android中Task任务栈的分配
首先我们来看下Task的定义,Google是这样定义Task的:a task is what the user experiences as an "application." It's a group of related activities, arranged in a stack. A task is a stack of activities, not a class or an element in the manifest file. 这意思就是说Task实际上是一个Activity栈,通常用户感受的一个Application就是一个Task。从这个定义来看,Task跟Service或者其他Components是没有任何联系的,它只是针对Activity而言的。 Activity有不同的启动模式, 可以影响到task的分配 Task,简单的说,就是一组以栈的模式聚集在一起的Activity组件集合。它们有潜在的前后驱关联,新加入的Activity组件,位于栈顶,并仅有在栈顶的Activity,才会有机会与用户进行交互。而当栈顶的Activity完成使命退出的时候,Task会将其退栈,并让下一个将跑到栈顶的Activity来于用户面对面,直至栈中再无更多Activity,Task结束。
事件
Task栈(粗体为栈顶组件)
点开Email应用,进入收件箱(Activity A)
A
选中一封邮件,点击查看详情(Activity B)
AB
点击回复,开始写新邮件(Activity C)
ABC
写了几行字,点击选择联系人,进入选择联系人界面(Activity D)
ABCD
选择好了联系人,继续写邮件
ABC
写好邮件,发送完成,回到原始邮件
AB
点击返回,回到收件箱
A
退出Email程序
null
如上表所示,是一个实例。从用户从进入邮箱开始,到回复完成,退出应用整个过程的Task栈变化。这是一个标准的栈模式,对于大部分的状况,这样的Task模型,足以应付,但是,涉及到实际的性能、开销等问题,就会变得残酷许多。 比如,启动一个浏览器,在Android中是一个比较沉重的过程,它需要做很多初始化的工作,并且会有不小的内存开销。但与此同时,用浏览器打开一些内容,又是一般应用都会有的一个需求。设想一下,如果同时有十个运行着的应用(就会对应着是多个Task),都需要启动浏览器,这将是一个多么残酷的场面,十个Task栈都堆积着很雷同的浏览器Activity, 是多么华丽的一种浪费啊。 于是你会有这样一种设想,浏览器Activity,可不可以作为一个单独的Task而存在,不管是来自那个Task的请求,浏览器的Task,都不会归并过去。这样,虽然浏览器Activity本身需要维系的状态更多了,但整体的开销将大大的减少,这种舍小家为大家的行为,还是很值得歌颂的 standard", "singleTop", "singleTask", "singleInstance"。 standard模式, 是默认的也是标准的Task模式,在没有其他因素的影响下,使用此模式的Activity,会构造一个Activity的实例,加入到调用者的Task栈中去,对于使用频度一般开销一般什么都一般的Activity而言,standard模式无疑是最合适的,因为它逻辑简单条理清晰,所以是默认的选择。 而singleTop模式,基本上于standard一致,仅在请求的Activity正好位于栈顶时,有所区别。此时,配置成singleTop的Activity,不再会构造新的实例加入到Task栈中,而是将新来的Intent发送到栈顶Activity中,栈顶的Activity可以通过重载onNewIntent来处理新的Intent(当然,也可以无视...)。这个模式,降低了位于栈顶时的一些重复开销,更避免了一些奇异的行为(想象一下,如果在栈顶连续几个都是同样的Activity,再一级级退出的时候,这是怎么样的用户体验...),很适合一些会有更新的列表Activity展示。一个活生生的实例是,在Android默认提供的应用中,浏览器(Browser)的书签Activity(BrowserBookmarkPage),就用的是singleTop。 singleTask,和singleInstance,则都采取的另辟Task的蹊径。 标志为singleTask的Activity,最多仅有一个实例存在,并且,位于以它为根的Task中。所有对该Activity的请求,都会跳到该Activity的Task中展开进行。singleTask,很象概念中的单件模式,所有的修改都是基于一个实例,这通常用在构造成本很大,但切换成本较小的Activity中。最典型的例子,还是浏览器应用的主Activity(名为Browser...),它是展示当前tab,当前页面内容的窗口。它的构造成本大,但页面的切换还是较快的,于singleTask相配,还是挺天作之合的。 singleInstance显得更为极端一些。在大部分时候singleInstance与singleTask完全一致,唯一的不同在于,singleInstance的Activity,是它所在栈中仅有的一个Activity,如果涉及到的其他Activity,都移交到其他Task中进行。这使得singleInstance的Activity,像一座孤岛,彻底的黑盒,它不关注请求来自何方,也不计较后续由谁执行。在Android默认的各个应用中,很少有这样的Activity,在我个人的工程实践中,曾尝试在有道词典的快速取词Activity中采用过, 是因为我觉得快速取词入口足够方便(从notification中点选进入),并且会在各个场合使用,应该做得完全独立。 大的apk 拆成 很多小的apk ●Activity的android:affinity属性 1.配置后 当启动这个activity时就先去找有没有activity的亲和力属性相同 有就加入这个 activity所在的任务中没有就新开任务 2.affinity起作用需要的条件而者具备一个: 1.intent包含FLAG_ACTIVITY_NEW_TASK标记 2.activity元素启用了allowTaskReparenting属性.
28.在Android中,怎么节省内存的使用,怎么主动回收内存?
回收已经使用的资源, 合理的使用缓存 合理设置变量的作用范围… application 对象 //未来的某一段时间执行 System.gc();
29.不同工程中的方法是否可以相互调用?
30.dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念 是同一概念
Dvm的进程是dalivk虚拟机进程,每个android程序都运行在自己的进程里面, 每个android程序系统都会给他分配一个单独的liunx uid(user id), 每个dvm都是linux里面的一个进程.所以说这两个进程是一个进程 .
31.在Android中是如何实现判断区分电话的状态,去电,来电、未接来电?
Day8 showAddressService.java TelephoneyManger.listen();
32.谈谈Android的优点和不足之处。
1、开放性,开源ophone 阿里云( 完全兼容android) 2、挣脱运营商束缚 3、丰富的硬件选择 mtk android 4、不受任何限制的开发商 5、无缝结合的Google应用 缺点也有5处: 1、安全问题、隐私问题 2、卖手机的不是最大运营商 3、运营商对Android手机仍然有影响 4、山寨化严重 5、过分依赖开发商,缺乏标准配置
33.Android系统中GC什么情况下会出现内存泄露呢?
视频编解码/内存泄露 检测内存泄露 工具 导致内存泄漏主要的原因是,先前申请了内存空间而忘记了释放。如果程序中存在对无用对象的引用,那么这些对象就会驻留内存,消耗内存,因为无法让垃圾回收器GC验证这些对象是否不再需要。如果存在对象的引用,这个对象就被定义为"有效的活动",同时不会被释放。要确定对象所占内存将被回收,我们就要务必确认该对象不再会被使用。典型的做法就是把对象数据成员设为null或者从集合中移除该对象。但当局部变量不需要时,不需明显的设为null,因为一个方法执行完毕时,这些引用会自动被清理。 Java带垃圾回收的机制,为什么还会内存泄露呢? Vector v = new Vector(10); for (int i = 1; i < 100; i++) { Object o = new Object(); v.add(o); o = null; }//此时,所有的Object对象都没有被释放,因为变量v引用这些对象。 Java 内存泄露的根本原因就是 保存了不可能再被访问的变量类型的引用
34.Android UI中的View如何刷新。
在主线程中 拿到view调用Invalide()方法,查看画画板里面更新imageview的方法 在子线程里面可以通过postInvalide()方法;
35. 简单描述下Android 数字签名。
Android 数字签名 在Android系统中,所有安装到系统的应用程序都必有一个数字证书,此数字证书用于标识应用程序的作者和在应用程序之间建立信任关系 Android系统要求每一个安装进系统的应用程序都是经过数字证书签名的,数字证书的私钥则保存在程序开发者的手中。Android将数字证书用来标识应用程序的作者和在应用程序之间建立信任关系,不是用来决定最终用户可以安装哪些应用程序。 这个数字证书并不需要权威的数字证书签名机构认证(CA),它只是用来让应用程序包自我认证的。 同一个开发者的多个程序尽可能使用同一个数字证书,这可以带来以下好处。 (1)有利于程序升级,当新版程序和旧版程序的数字证书相同时,Android系统才会认为这两个程序是同一个程序的不同版本。如果新版程序和旧版程序的数字证书不相同,则Android系统认为他们是不同的程序,并产生冲突,会要求新程序更改包名。 (2)有利于程序的模块化设计和开发。Android系统允许拥有同一个数字签名的程序运行在一个进程中,Android程序会将他们视为同一个程序。所以开发者可以将自己的程序分模块开发,而用户只需要在需要的时候下载适当的模块。 在签名时,需要考虑数字证书的有效期: (1)数字证书的有效期要包含程序的预计生命周期,一旦数字证书失效,持有改数字证书的程序将不能正常升级。 (2)如果多个程序使用同一个数字证书,则该数字证书的有效期要包含所有程序的预计生命周期。 (3)Android Market强制要求所有应用程序数字证书的有效期要持续到2033年10月22日以后。 Android数字证书包含以下几个要点: (1)所有的应用程序都必须有数字证书,Android系统不会安装一个没有数字证书的应用程序 (2)Android程序包使用的数字证书可以是自签名的,不需要一个权威的数字证书机构签名认证 (3)如果要正式发布一个Android ,必须使用一个合适的私钥生成的数字证书来给程序签名,而不能使用adt插件或者ant工具生成的调试证书来发布。 (4)数字证书都是有有效期的,Android只是在应用程序安装的时候才会检查证书的有效期。如果程序已经安装在系统中,即使证书过期也不会影响程序的正常功能。
36.android中的动画有哪几类,它们的特点和区别是什么?
两种,一种是Tween动画、还有一种是Frame动画。 Tween动画,这种实现方式可以使视图组件移动、放大、缩小以及产生透明度的变化; 可以通过布局文件,可以通过代码 1、 控制View的动画 a) alpha(AlphaAnimation) 渐变透明 b) scale(ScaleAnimation) 渐变尺寸伸缩 c) translate(TranslateAnimation) 画面转换、位置移动 d) rotate(RotateAnimation) 画面转移,旋转动画 2、 控制一个Layout里面子View的动画效果 a) layoutAnimation(LayoutAnimationController) b) gridAnimation(GridLayoutAnimationController) 另一种Frame动画,传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影。
37.说说mvc模式的原理,它在android中的运用
Android中没有mvc,只有在j2ee中有,是用于逻辑也界面分离的 MVC英文即Model-View-Controller,即把一个应用的输入、处理、输出流程按照Model、View、Controller的方式进行分离,这样一个应用被分成三个层——模型层、视图层、控制层。 Android中界面部分也采用了当前比较流行的MVC框架,在Android中M就是应用程序中二进制的数据,V就是用户的界面。Android的界面直接采用XML文件保存的,界面开发变的很方便。在Android中C也是很简单的,一个Activity可以有多个界面,只需要将视图的ID传递到setContentView(),就指定了以哪个视图模型显示数据。 在Android SDK中的数据绑定,也都是采用了与MVC框架类似的方法来显示数据。在控制层上将数据按照视图模型的要求(也就是Android SDK中的Adapter)封装就可以直接在视图模型上显示了,从而实现了数据绑定。比如显示Cursor中所有数据的ListActivity,其视图层就是一个ListView,将数据封装为ListAdapter,并传递给ListView,数据就在ListView中显示。
38.通过点击一个网页上的url 就可以完成程序的自动安装,描述下原理
Day11 AddJavascriptInterface new Object{ callphone(); installapk(); } 将js与java相互调用再来一个例子,解决相互调用之间的关系。 首先说明一重要代码的情况: android中的关键代码 : webview.getSettings().setJavaScriptEnabled(true); webview.addJavascriptInterface(object,"name"); //把Name="name" 的对象添加到object中。object如果是this,就是window.name webview.loadUrl("file:///android_asset/index.html"); //注意这个资源的位置放在assets文件夹下。 js或html中调用android中方法代码: js中使用 window.name.java中的方法(); android中调用js的function方法: Callfunction(){ webview.loadUrl("javascript: function ()"); 需要注意的地方,很多数据类型js中不认识,最好是在android那边封装好,提供必要的方法接口。比如传到js中的list,在js中是没办法去得到里面的元素的。 addJavascriptInterface:addJavascriptInterface方法中要绑定的Java对象及方法要运行在另外的线程中,不能运行在构造他的线程中,也就是说不能运行在当前的activity线程中,就是把这个方法绑定到页面中,js也可以调用。 文档中的解释: Use this function to bind an object to Javascript so that the methods can be accessed from Javascript. The Java object that is bound runs in another thread and not in the thread that it was constructed in. 下面给出具体的测试代码: 1、Activity 代码 [java] view plaincopyprint? public class TestWebView extends Activity { private WebView mWebView; private List list; private int mkeyCode; @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main); mWebView = (WebView) findViewById(R.id.htmlview); initData(); WebSettings webSettings = mWebView.getSettings(); // 是否允许在webview中执行javascript webSettings.setJavaScriptEnabled( true ); mWebView.addJavascriptInterface( this , "javatojs" ); //加载网页 mWebView.loadUrl( "file:///android_asset/index.html" ); } @Override public boolean onKeyUp( int keyCode, KeyEvent event) { mkeyCode = keyCode; Log.i( "AA" , "keyCode=" +keyCode); mWebView.loadUrl( "javascript: OnKeyUp()" ); return super .onKeyUp(keyCode, event); } public int getKeyCode(){ return mkeyCode; } void initData() { list = new ArrayList(); for ( int i = 0 ; i < 5 ; i++) { list.add( "我是List中的第" + (i + 1 ) + "行" ); } } /** * 该方法将在js脚本中,通过window.javatojs.....()进行调用 * * @return */ public Object getObject( int index) { Log.i( "A" , "getObject" ); return list.get(index); } public int getSize() { Log.i( "A" , "getSize" ); return list.size(); } public void Callfunction() { Log.i( "A" , "Callfunction" ); mWebView.loadUrl( "javascript: GetList()" ); } public void printStr(String str){ Log.i( "A" , "GetList:" + str); } } 2、js 代码 index.html [javascript] view plaincopyprint? "-//W3C//DTD HTML 4.0 Transitional//EN" > "Content-Type" content= "text/html; charset=UTF-8" > demotitle> "background-color:#000;" > "400" align= "center" >
以上代码主要测试js与java相互调用,而由于按键这种系统事件被webview截获掉,有如下两种方式进行处理 1、把方向键的流程改成:先传给webcore,假如没处理,再在webview里面处理,这个需要修改webview.java代码 2、直接应用搞定,java捕获按键,然后调js函数,上面代码就是使用这种方法。 测试结果如下: 点击buttons按钮: I/A ( 4990): Callfunction I/A ( 4990): getSize I/A ( 4990): getObject I/A ( 4990): GetList:test I/A ( 4990): getObject I/A ( 4990): GetList:test I/A ( 4990): getObject I/A ( 4990): GetList:test I/A ( 4990): getObject I/A ( 4990): GetList:test I/A ( 4990): getObject I/A ( 4990): GetList:test you press KEY_RIGHT I/AA ( 4990): keyCode=22 I/A ( 4990): GetList:22 you press KEY_UP I/AA ( 4990): keyCode=19 I/A ( 4990): GetList:19 you press KEY_DOWN I/AA ( 4990): keyCode=20 I/A ( 4990): GetList:20 you press KEY_LEFT I/AA ( 4990): keyCode=21 I/A ( 4990): GetList:21 这里为何使用这种方式,是因为对于上下左右及确定这种功能键被webview截取掉了,无法传递到webcore中,而只能重载OnKeyDown/OnKeyUp方法,再由js调用java方法来获取得。 对于数字键的处理可以直接在js中进行处理: logcat中会有明显的打印,对于这些键没有截掉,所以可以直接获取得到: D/webcore ( 4990): proc key: code=12 D/webcore ( 4990): proc key: nativeKey return false D/webcore ( 4990): proc key: nativeKey return true js代码可以如此编写: [javascript] view plaincopyprint?
39.Service和Activity在同一个线程吗
40.ViewStub的应用
在开发应用程序的时候,经常会遇到这样的情况,会在运行时动态根据条件来决定显示哪个View或某个布局。那么最通常的想法就是把可能用到的View都写在上面,先把它们的可见性都设为 View . GONE ,然后在代码中动态的更改它的可见性。这样的做法的优点是逻辑简单而且控制起来比较灵活。但是它的缺点就是,耗费资源。虽然把View的初始可见 View . GONE 但是在Inflate布局的时候View仍然会被Inflate,也就是说仍然会创建对象,会被实例化,会被设置属性。也就是说,会耗费内存等资源。 推荐的做法是使用 android.view.ViewStub ,ViewStub是一个轻量级的View,它一个看不见的,不占布局位置,占用资源非常小的控件。可以为ViewStub指定一个布局,在Inflate布局的时候,只有ViewStub会被初始化,然后当ViewStub被设置为可见的时候,或是调用了ViewStub.inflate()的时候,ViewStub所向的布局就会被Inflate和实例化,然后ViewStub的布局属性都会传给它所指向的布局。这样,就可以使用ViewStub来方便的在运行时,要还是不要显示某个布局。 但ViewStub也不是万能的,下面总结下ViewStub能做的事儿和什么时候该用ViewStub,什么时候该用可见性的控制。 首先来说说ViewStub的一些特点: 1. ViewStub只能Inflate一次,之后ViewStub对象会被置为空。按句话说,某个被ViewStub指定的布局被Inflate后,就不会够再通过ViewStub来控制它了。 2. ViewStub只能用来Inflate一个布局文件,而不是某个具体的View,当然也可以把View写在某个布局文件中。 基于以上的特点,那么可以考虑使用ViewStub的情况有: 1. 在程序的运行期间,某个布局在Inflate后,就不会有变化,除非重新启动。 因为ViewStub只能Inflate一次,之后会被置空,所以无法指望后面接着使用ViewStub来控制布局。所以当需要在运行时不止一次的显示和隐藏某个布局,那么ViewStub是做不到的。这时就只能使用View的可见性来控制了。 2. 想要控制显示与隐藏的是一个布局文件,而非某个View。 因为设置给ViewStub的只能是某个布局文件的Id,所以无法让它来控制某个View。 所以,如果想要控制某个View(如Button或TextView)的显示与隐藏,或者想要在运行时不断的显示与隐藏某个布局或View,只能使用View的可见性来控制。 下面来看一个实例 在这个例子中,要显示二种不同的布局,一个是用TextView显示一段文字,另一个则是用ImageView显示一个图片。这二个是在onCreate()时决定是显示哪一个,这里就是应用ViewStub的最佳地点。 先来看看布局,一个是主布局,里面只定义二个ViewStub,一个用来控制TextView一个用来控制ImageView,另外就是一个是为显示文字的做的TextView布局,一个是为ImageView而做的布局: [html] view plaincopyprint? version = "1.0" encoding = "utf-8"?> xmlns:android = " http://schemas.android.com/apk/res/android " android:orientation = "vertical" android:layout_width = "fill_parent" android:layout_height = "fill_parent" android:gravity = "center_horizontal"]] > android:id = "@+id/viewstub_demo_text" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_marginLeft = "5dip" android:layout_marginRight = "5dip" android:layout_marginTop = "10dip" android:layout = "@layout/viewstub_demo_text_layout"/> android:id = "@+id/viewstub_demo_image" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_marginLeft = "5dip" android:layout_marginRight = "5dip" android:layout = "@layout/viewstub_demo_image_layout"/> 为TextView的布局: [html] view plaincopyprint? version = "1.0" encoding = "utf-8"?> xmlns:android = " http://schemas.android.com/apk/res/android " android:orientation = "vertical" android:layout_width = "wrap_content" android:layout_height = "wrap_content"]] > android:id = "@+id/viewstub_demo_textview" android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:background = "#aa664411" android:textSize = "16sp"/> 为ImageView的布局: [html] view plaincopyprint? version = "1.0" encoding = "utf-8"?> xmlns:android = " http://schemas.android.com/apk/res/android " android:orientation = "vertical" android:layout_width = "wrap_content" android:layout_height = "wrap_content"]] > android:id = "@+id/viewstub_demo_imageview" android:layout_width = "wrap_content" android:layout_height = "wrap_content"/> 下面来看代码,决定来显示哪一个,只需要找到相应的ViewStub然后调用其infalte()就可以获得相应想要的布局: [java] view plaincopyprint? package com.effective; import android.app.Activity; import android.os.Bundle; import android.view.ViewStub; import android.widget.ImageView; import android.widget.TextView; public class ViewStubDemoActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.viewstub_demo_activity); if (((( int ) (Math.random() * 100 )) & 0x01 ) == 0 ) { // to show text // all you have to do is inflate the ViewStub for textview ViewStub stub = (ViewStub) findViewById(R.id.viewstub_demo_text); stub.inflate(); TextView text = (TextView) findViewById(R.id.viewstub_demo_textview); text.setText( "The tree of liberty must be refreshed from time to time" + " with the blood of patroits and tyrants! Freedom is nothing but " + "a chance to be better!" ); } else { // to show image // all you have to do is inflate the ViewStub for imageview ViewStub stub = (ViewStub) findViewById(R.id.viewstub_demo_image); stub.inflate(); ImageView image = (ImageView) findViewById(R.id.viewstub_demo_imageview); image.setImageResource(R.drawable.happy_running_dog); } } } 运行结果: 使用的时候的注意事项: 1. 某些布局属性要加在ViewStub而不是实际的布局上面,才会起作用,比如上面用的android:layout_margin*系列属性,如果加在TextView上面,则不会起作用,需要放在它的ViewStub上面才会起作用。而ViewStub的属性在inflate()后会都传给相应的布局。
41.android开发中怎么去调试bug
逻辑错误 1.断点 debug 2. logcat , 界面布局,显示 hierarchyviewer.bat
42.书写出android工程的目录结构以及相关作用
下面是HelloAndroid项目在eclipse中的目录层次结构: 由上图可以看出项目的根目录下共有九个文件(夹),下面就这九个文件(夹)进行详解: 1.1src文件夹和assets文件夹: 每个Android程序都包含资源目录(src)和资产目录(assets),资源和资产听起来感觉没有多大差别,但在存储外部内容时用资源(src)比较多,其中它们的区别在于存放在资源(src)下的内容可以通过应用程序的R类进行访问,而存放在资产(assets)下的内容会保持原始文件的格式,如果需要访问,则必须使用AssetManager以字节流的方式来读取,用起来非常的不方便。为了方便使用,通常文件和数据都会保存在资源(src)目录下 1.2res(Resource)目录:资源目录 可以存放一些图标,界面文件和应用中用到的文字信息,下图为res目录截图: 1.2.1 drawable-*dpi文件夹:将图标按分辨率的高低放入不同的目录,其中draeable-hdpi用来存放高分辨率的图标,drawable-mdpi用来存放中等分辨率的图标,drawable-ldpi用来存放低分辨率的图标 1.2.2 values文件夹:用来存放文字的信息 (1)strings.xml:用来定义字符串和数值 "1.0"encoding="utf-8" ?> "hello">Hello World, Hello 3G "app_name">Android1.1 "test">哥想你了 "startButton">按钮1 "start">按钮1 每个string标签生命了一个字符串,name属性指定它的引用值 (2)为什么要把这些出现的文字单独放在strings.xml文件中? 答案:一是为了国际化,如果需要将文件中的文字换成别的国家的语言,就可以只需要替换掉一个strings.xml文件就可以了 二是为了减少应用的体积,例如,我们要在应用中使用“哥想你了”这句话1000次,如果我们没有将“哥想你了”定义在strings.xml文件中,而是直接在应用中使用时写上这几个字,那么我们就会在应用中写4000个字。4000个字和4个字占用的内存可是有很大差距的啊,况且手机的内存本来就小,所以应该是能省就省 (3)另外还有arrays.xml,color.xml等定义数组,颜色的,都最好用单独的一个xml文档 1.2.3 layout文件:用来存放界面信息 本例中的布局文件是自动生成的“main.xml” "1.0"encoding="utf-8" ?> " http://schemas.android.com/apk/res/android " android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/test" /> 元素:线性布局的意思,在该元素下的所有子元素都会根据他的”orientation”属性来决定是按行还是按列或者按逐个显示进行布局的 元素:是一种显示控件,他的”text”属性指定了在这个元素上显示的内容 1.3 gen目录:gen目录下只有一个自动生成的“R.java”文件 /*AUTO-GENERATED FILE. DO NOT MODIFY. * * This class was automatically generated bythe * aapt tool from the resource data itfound. It * should not be modified by hand. */ package cn.csdn.android.demo; public final class R { public static final class attr { } public static final class drawable { public static final int ic_launcher=0x7f020000; } public static final class id { public static final int button1=0x7f050000; public static final int radioButton1=0x7f050001; public static final int toggleButton1=0x7f050002; } public static final class layout { public static final int main=0x7f030000; } public static final class string { public static final int app_name=0x7f040001; public static final int hello=0x7f040000; public static final int start=0x7f040004; public static final int startButton=0x7f040003; public static final int test=0x7f040002; } } R.java文件:默认有attr,drawable,layout,string这四个静态内部类,每个静态内部类对应一中资源,如layout静态内部类对应layout中的界面文件,string静态内部类对应string内部的string标签。如果在layout中在增加一个界面文件或者在string内增加一个string标签,R.java会自动在其对应的内部类增加所增加的内容。 R.java除了自动标识资源的索引功能外,还有另一个功能,就是当res文件中的某个资源在应用中没有被用到,在这个应用被编译时,系统不会把对应的资源编译到应用中的APR包中。 1.4 AndroidManifest.xml 功能清单文件 每个应用程序都会有一个Android Manifest 在它的根目录里面。这个清单为Android系统提供了这个应用的基本信息,系统在运行之前必须知道这些信息,另外,如果我们使用系统自带的服务,如拨号服务,应用安装服务等,都必须在AndroidManifest.xml文件中声明权限 AndroidManifest.xml的功能: 命名应用程序的Java应用包,这个包名用来唯一标识应用程序; 描述应用程序的组件,对实现每个组件和公布其功能的类进行命名,这些声明使得Android系统了解这些组件以及它们在什么条件下可以被启动 决定哪个组件运行在哪个进程里面 声明应用程序必须具备的权限,用以访问受保护的API,以及和其他进程的交互 声明应用程序其他的必备权限,用以组件之间的交互 列举application所需要链接的库 以HelloAndroid项目的功能清单为例子进行讲解: "1.0"encoding="utf-8" ?> " http://schemas.android.com/apk/res/android " package="cn.csdn.android.demo" android:versionCode="1" android:versionName="1.0" > "8"/> android:icon="@drawable/ic_launcher" android:label="@string/app_name" > android:label="@string/app_name" android:name=".HelloActivity" > "android.intent.action.MAIN" /> "android.intent.category.LAUNCHER" /> 1.4.1 元素 " http://schemas.android.com/apk/res/android " package="cn.csdn.android.demo" android:versionCode="1" android:versionName="1.0" > 元素是AndroidManifest.xml的根元素,”xmlns:android”是指该文件的命名空间,“package”属性是Android应用所在的包,“android:versionCode”指定应用的版本号,如果应用不断升级,则需要修改这个值,”android:versionName”是版本的名称,这个可以根据自己的喜爱改变 1.4.2 元素 android:icon="@drawable/ic_launcher" android:label="@string/app_name" > android:label="@string/app_name" android:name=".HelloActivity" > "android.intent.action.MAIN"/> "android.intent.category.LAUNCHER" /> 元素是一个很重要的元素,开发组件都会在此下定义 元素的”icon”属性是用来设定应用的图标,其中“@drawable/ic_launcher”的意思是:在R.java文件中的drawable静态内部类下的icon,如下图所示 元素的“label”属性用来设定应用的名称,其中“@string/app_name”和上述的一样,也是R.java文件中的string静态内部类下的app_name 1.4.3 元素 android:label="@string/app_name" android:name=".HelloActivity" > "android.intent.action.MAIN" /> "android.intent.category.LAUNCHER" /> 元素的作用是注册一个activity信息,当我们在创建“HelloAndroid”这个项目时,指定了“Created Activity”属性为“HelloActivity”,然后ADT在生成项目时帮我们自动创建了一个Activity,就是“HelloActivity.java”; 元素的“name“属性指定的是Activity的类名,其中“.HelloActivity”中的“.”指的是元素中的“package”属性中指定的当前包,所以“.HelloActivity”就相当于“cn.csdn.android.demo.HelloActivity.java ”,如果Activity在应用的包中可以不写“.”,但是为了避免出错,还是写上这个点把 1.4.4元素 "android.intent.action.MAIN" /> "android.intent.category.LAUNCHER" /> 如果直接翻译的话是“意图过滤器”,组件通过告诉它们所具备的功能,就是能响应意图类型,在intent中设置action, data, categroy之后在对应的intentfilter中设置相同的属性即可通过过滤被activity调用 1.5应用要求运行的最低Android版本 1.6 存放Android自身的jar包
43.ddms 和traceview的区别.
daivilk debug manager system 1.在应用的主activity的onCreate方法中加入Debug.startMethodTracing("要生成的traceview文件的名字"); 2.同样在主activity的onStop方法中加入Debug.stopMethodTracing(); 3.同时要在AndroidManifest.xml文件中配置权限 3.重新编译,安装,启动服务,测试完成取对应的traceview文件(adb pull /sdcard/xxxx.trace)。 4.直接在命令行输入traceview xxxxtrace,弹出traceview窗口,分析对应的应用即可。 traceview 分析程序执行时间和效率 KPI : key performance information : 关键性能指标: splash界面不能超过5秒 从splash 界面加载mainactivity 不能超过0.7秒
44.谈谈NDK
NDK全称:Native Development Kit。 1、NDK是一系列工具的集合。 * NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的。 [1] * NDK集成了 交叉编译器 ,并提供了相应的mk文件隔离平台、CPU、API等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。 * NDK可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。 2、NDK提供了一份稳定、功能有限的API头文件声明。 Google明确声明该API是稳定的,在后续所有版本中都稳定支持当前发布的API。从该版本的NDK中看出,这些API支持的功能非常有限,包含有:C标准库(libc)、标准数学库(libm)、压缩库(libz)、Log库(liblog)。
45.请介绍下Android的数据存储方式。
一.SharedPreferences方式 二sdcard 三内部存储 四SqliteDatabase 五. 网络存储方式
46.谈谈推送,优缺点以及实现原理
本文主旨在于,对目前Android平台上最主流的几种消息推送方案进行分析和对比,比较客观地反映出这些推送方案的优缺点,帮助大家选择最合适的实施方案。 方案1、 使用GCM服务(Google Cloud Messaging) 简介:Google推出的云消息服务,即第二代的C2DM。 优点:Google提供的服务、原生、简单,无需实现和部署服务端。 缺点:Android版本限制(必须大于2.2版本),该服务在国内不够稳定、需要用户绑定Google帐号,受限于Google。 方案2、 使用XMPP协议(Openfire + Spark + Smack) 简介:基于XML协议的通讯协议,前身是Jabber,目前已由IETF国际标准化组织完成了标准化工作。 优点:协议成熟、强大、可扩展性强、目前主要应用于许多聊天系统中,且已有开源的Java版的开发实例androidpn。 缺点:协议较复杂、冗余(基于XML)、费流量、费电,部署硬件成本高。 方案3、 使用MQTT协议(更多信息见:http://mqtt.org/ ) 简介:轻量级的、基于代理的“发布/订阅”模式的消息传输协议。 优点:协议简洁、小巧、可扩展性强、省流量、省电,目前已经应用到企业领域(参考: http://mqtt.org/software ),且已有C++版的服务端组件rsmb。 缺点:不够成熟、实现较复杂、服务端组件rsmb不开源,部署硬件成本较高。 方案4、 使用HTTP轮循方式 简介:定时向HTTP服务端接口(Web Service API)获取最新消息。 优点:实现简单、可控性强,部署硬件成本低。 缺点:实时性差。 对各个方案的优缺点的研究和对比,推荐使用MQTT协议的方案进行实现,主要原因是:MQTT最快速,也最省流量(固定头长度仅为2字节),且极易扩展,适合二次开发 。接下来,我们就来分析使用MQTT方案进行Android消息的原理和方法,并架设自己的推送服务。 1、推送原理分析 实际上,其他推送系统(包括GCM、XMPP方案)的原理都与此类似。 2、推送服务端准备 a> 下载&解压rsmb安装包(下载地址: http://www.alphaworks.ibm.com/tech/rsmb ) b> 进入对应的目录,比如32位的Linux系统则应该进入linux_ia32目录。 c> 编辑配置文件broker_1883.cfg,配置如下: [html] view plaincopy port 1883 max_inflight_messages 10 max_queued_messages 1000 d> 运行./broker broker_1883.cfg,显示如下: 20120823 110454.039 CWNAN9999I Really Small Message Broker 20120823 110454.039 CWNAN9997I Licensed Materials - Property of IBM 20120823 110454.039 CWNAN9996I Copyright IBM Corp. 2007, 2010 All Rights Reserved 20120823 110454.039 CWNAN9995I US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 20120823 110454.039 CWNAN0049I Configuration file name is broker_1883.cfg 20120823 110454.040 CWNAN0053I Version 1.2.0, Aug 18 2010 17:03:35 20120823 110454.040 CWNAN0054I Features included: bridge 20120823 110454.040 CWNAN9993I Author: Ian Craggs ( [email protected] ) 20120823 110454.040 CWNAN0014I MQTT protocol starting, listening on port 1883 ... ... 这样,推送服务的服务端就已经准备好了,监听1883端口。 3、推送客户端准备 a> 下载&解压AndroidPushNotificationsDemo项目(下载地址: https://github.com/tokudu/AndroidPushNotificationsDemo ) b> 将该项目导入Eclipse中(File -> Export -> Existing Projects into Workspace) c> 修改PushService.java中的MQTT_HOST 常量为推送服务端的IP地址。 d> 启动Android模拟器,并安装该项目。 注意: 在新版本的Android SDK中可能会遇到以下错误。 ... ... 08-23 02:28:44.184: W/dalvikvm(282): VFY: unable to find class referenced in signature (Lcom/ibm/mqtt/MqttPersistence;) 08-23 02:28:44.194: I/dalvikvm(282): Failed resolving Lcom/tokudu/demo/PushService$MQTTConnection; interface 35 'Lcom/ibm/mqtt/MqttSimpleCallback;' 08-23 02:28:44.194: W/dalvikvm(282): Link of class 'Lcom/tokudu/demo/PushService$MQTTConnection;' failed 08-23 02:28:44.194: E/dalvikvm(282): Could not find class 'com.tokudu.demo.PushService$MQTTConnection', referenced from method com.tokudu.demo.PushService.connect 08-23 02:28:44.194: W/dalvikvm(282): VFY: unable to resolve new-instance 42 (Lcom/tokudu/demo/PushService$MQTTConnection;) in Lcom/tokudu/demo/PushService; ... ... 08-23 02:28:44.404: E/AndroidRuntime(282): java.lang.VerifyError: com.tokudu.demo.PushService 08-23 02:28:44.404: E/AndroidRuntime(282): at com.tokudu.demo.PushActivity$1.onClick(PushActivity.java:32) 08-23 02:28:44.404: E/AndroidRuntime(282): at android.view.View.performClick(View.java:2408) 08-23 02:28:44.404: E/AndroidRuntime(282): at android.view.View$PerformClick.run(View.java:8816) 08-23 02:28:44.404: E/AndroidRuntime(282): at android.os.Handler.handleCallback(Handler.java:587) 08-23 02:28:44.404: E/AndroidRuntime(282): at android.os.Handler.dispatchMessage(Handler.java:92) 08-23 02:28:44.404: E/AndroidRuntime(282): at android.os.Looper.loop(Looper.java:123) 08-23 02:28:44.404: E/AndroidRuntime(282): at android.app.ActivityThread.main(ActivityThread.java:4627) 08-23 02:28:44.404: E/AndroidRuntime(282): at java.lang.reflect.Method.invokeNative(Native Method) 08-23 02:28:44.404: E/AndroidRuntime(282): at java.lang.reflect.Method.invoke(Method.java:521) 08-23 02:28:44.404: E/AndroidRuntime(282): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868) 08-23 02:28:44.404: E/AndroidRuntime(282): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626) 08-23 02:28:44.404: E/AndroidRuntime(282): at dalvik.system.NativeStart.main(Native Method) ... ... 原因是发布的时候没有加入wmqtt.jar包,解决办法如下: 1> 在项目根目录下创建libs目录,并把wmqtt.jar包移入该目录。 2> 重新配置项目的Java Build Path(右键菜单中的Properties选项中)。 3> 重新打包发布即可。 运行效果如下: 点击“Start Push Service”按钮即可开启推送服务。这时我们可以看到rsmb的服务日志中打出以下提示: 20120823 113742.297 CWNAN0033I Connection attempt to listener 1883 received from client tokudu/9774d56d682e549c on address 192.168.28.39:3345 其中的“9774d56d682e549c”就是对应的客户端ID号。 4、发送服务准备 a> 下载&解压PHP版的发送服务端代码send_mqtt.zip(下载地址: http://download.csdn.net/detail/shagoo/4520102 ) b> 修改etc/config.php中推送服务端的IP地址和端口号,即MQTT_SERVER_HOST 和MQTT_SERVER_POST 常量。 c> 打开对应的URL地址,就可以看到发送服务的界面,实际上就是向对应的推送客户端推送消息。
47.谈谈数据加密
数据加密又称密码学,它是一门历史悠久的技术,指通过 加密算法 和加密 密钥 将明文转变为密文,而解密则是通过解密算法和解密密钥将密文恢复为明文。数据加密目前仍是 计算机系统 对信息进行保护的一种最可靠的办法。它利用 密码技术 对信息进行加密,实现 信息隐蔽 ,从而起到保护信息的安全的作用。 用自己的话来说就是,只有双方才知道的协议。 数据加密 - 密码算法分类 1按发展进程分密码的发展:古典密码,对称密钥 密码公开密钥密码. 2按加密模式分对称算法:序列密码和分组密码. 经典密码 代替密码: 简单代替多名或同音代替多表代替多字母或多码代替 换位密码 : •对称加密算法 DES AES •非对称公钥算法 RSA 背包密码McEliece密码Rabin 椭圆曲线EIGamal D_H
48.解决问题和思考问题的方式
首先查看官方提供的API,通过自己对功能的理解,然后通过网络的途径,下载demo可以选择 github ,查找问题可以选择 stackover flow,然后可以问身边的朋友。
49.列举7到12个设计模式 以及它们的应用场景
设计模式,提供了很多软件工程问题所需处理的解决方案。 根据模式的目的可分为3类: 1.创建型模式:与对象的创建有关。 2.结构性模式:处理类与对象的组合。 3.行为性模式:对类或对象怎样交互和怎样 分配职责进行描述。 面向对象设计的2个基本原则: 1.针对接口编程,而不是针对实现编程。 2.优先使用对象组合,而不是类继承。 面向对象设计的5个设计原则: 1.单一职责原则(SRP) 2.开放封闭原则(OCP) 3.Liskov替换原则(LSP) 4.依赖倒置原则(DIP) 5.接口隔离原则(ISP) 23中设计模式: 1.创建型模式: (1).工厂方法模式 (2).抽象工厂模式 (3).创建者模式 (4).原型模式 (5).单例模式 2.结构型模式: (6).适配器模式 (7).桥模式 (8).组合模式 (9).装饰模式 (10).外观模式 (11).享元模式 (12).代理模式 3.行为型模式 (13).解释器模式 (14).模板方法模式 (15).职责链模式 (16).命令模式 (17).迭代器模式 (18).中介者模式 (19).备忘录模式 (20).观察者模式 (21).状态模式 (22).策略模式 (23).访问者模式 除此之外,后来人发现很多新的模式,如空模式等。 下面列举几个常见的问题导致重新设计,可能需要设计模式来分析解决: 1.通过显示的指定一个类来创建对象 2.对特殊操作的依赖 3.对硬件和软件平台的依赖 4.对对象表示或实现的依赖 5.算法依赖 6.紧耦合 7.通过生产子类来扩展功能 8.不能方便的对类进行修改 软件的设计臭味: 1.僵化性 2.脆弱性 3.顽固性 4.粘滞性 5.不必要的复杂性 6.不必要的重复 7.晦涩性 ... ... 总而言之,一句话,面向对象特性+原则+模式,折腾来折腾去就是这么个回事。 设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。本章系 Java之美[从菜鸟到高手演变]系列 之设计模式,我们会以理论与实践相结合的方式来进行本章的学习,希望广大程序爱好者,学好设计模式,做一个优秀的软件工程师! 在阅读过程中有任何问题,请及时联系:egg。 邮箱:[email protected] 微博: http://weibo.com/xtfggef 如有转载,请说明出处: http://blog.csdn.net/zhangerqing 企业级项目实战(带源码)地址:http://zz563143188.iteye.com/blog/1825168 23种模式java实现源码及收集五年的开发资料下载地址 : http://pan.baidu.com/share/home?uk=4076915866&view=share 一、设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。 其实还有两类:并发型模式和线程池模式。用一个图片来整体描述一下: 二、设计模式的六大原则 1、开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭 。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。 2、里氏代换原则(Liskov Substitution Principle) 里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科 3、依赖倒转原则(Dependence Inversion Principle) 这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。 4、接口隔离原则(Interface Segregation Principle) 这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。 5、迪米特法则(最少知道原则)(Demeter Principle) 为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。 6、合成复用原则(Composite Reuse Principle) 原则是尽量使用合成/聚合的方式,而不是使用继承。 三、Java的23中设计模式 从这一块开始,我们详细介绍Java中23种设计模式的概念,应用场景等情况,并结合他们的特点及设计模式的原则进行分析。 1、工厂方法模式(Factory Method) 工厂方法模式分为三种: 11、普通工厂模式 ,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。首先看下关系图: 举例如下:(我们举一个发送邮件和短信的例子) 首先,创建二者的共同接口: [java] view plaincopy public interface Sender { public void Send(); } 其次,创建实现类: [java] view plaincopy public class MailSender implements Sender { @Override public void Send() { System.out.println( "this is mailsender!" ); } } [java] view plaincopy public class SmsSender implements Sender { @Override public void Send() { System.out.println( "this is sms sender!" ); } } 最后,建工厂类: [java] view plaincopy public class SendFactory { public Sender produce(String type) { if ( "mail" .equals(type)) { return new MailSender(); } else if ( "sms" .equals(type)) { return new SmsSender(); } else { System.out.println( "请输入正确的类型!" ); return null ; } } } 我们来测试下: public class FactoryTest { public static void main(String[] args) { SendFactory factory = new SendFactory(); Sender sender = factory.produce( "sms" ); sender.Send(); } } 输出:this is sms sender! 22、多个工厂方法模式 ,是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。关系图: 将上面的代码做下修改,改动下SendFactory类就行,如下: [java] view plaincopy public class SendFactory { public Sender produceMail(){ return new MailSender(); } public Sender produceSms(){ return new SmsSender(); } } 测试类如下: [java] view plaincopy public class FactoryTest { public static void main(String[] args) { SendFactory factory = new SendFactory(); Sender sender = factory.produceMail(); sender.Send(); } } 输出:this is mailsender! 33、静态工厂方法模式 ,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。 [java] view plaincopy public class SendFactory { public static Sender produceMail(){ return new MailSender(); } public static Sender produceSms(){ return new SmsSender(); } } [java] view plaincopy public class FactoryTest { public static void main(String[] args) { Sender sender = SendFactory.produceMail(); sender.Send(); } } 输出:this is mailsender! 总体来说,工厂模式适合:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。在以上的三种模式中,第一种如果传入的字符串有误,不能正确创建对象,第三种相对于第二种,不需要实例化工厂类,所以,大多数情况下,我们会选用第三种——静态工厂方法模式。 2、抽象工厂模式(Abstract Factory) 工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。因为抽象工厂不太好理解,我们先看看图,然后就和代码,就比较容易理解。 请看例子: [java] view plaincopy public interface Sender { public void Send(); } 两个实现类: [java] view plaincopy public class MailSender implements Sender { @Override public void Send() { System.out.println( "this is mailsender!" ); } } [java] view plaincopy public class SmsSender implements Sender { @Override public void Send() { System.out.println( "this is sms sender!" ); } } 两个工厂类: [java] view plaincopy public class SendMailFactory implements Provider { @Override public Sender produce(){ return new MailSender(); } } [java] view plaincopy public class SendSmsFactory implements Provider{ @Override public Sender produce() { return new SmsSender(); } } 在提供一个接口: [java] view plaincopy public interface Provider { public Sender produce(); } 测试类: [java] view plaincopy public class Test { public static void main(String[] args) { Provider provider = new SendMailFactory(); Sender sender = provider.produce(); sender.Send(); } } 其实这个模式的好处就是,如果你现在想增加一个功能:发及时信息,则只需做一个实现类,实现Sender接口,同时做一个工厂类,实现Provider接口,就OK了,无需去改动现成的代码。这样做,拓展性较好! 3、单例模式(Singleton) 单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处: 1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。 2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。 3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。 首先我们写一个简单的单例类: [java] view plaincopy public class Singleton { /* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */ private static Singleton instance = null ; /* 私有构造方法,防止被实例化 */ private Singleton() { } /* 静态工程方法,创建实例 */ public static Singleton getInstance() { if (instance == null ) { instance = new Singleton(); } return instance; } /* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */ public Object readResolve() { return instance; } } 这个类可以满足基本要求,但是,像这样毫无线程安全保护的类,如果我们把它放入多线程的环境下,肯定就会出现问题了,如何解决?我们首先会想到对getInstance方法加synchronized关键字,如下: [java] view plaincopy public static synchronized Singleton getInstance() { if (instance == null ) { instance = new Singleton(); } return instance; } 但是,synchronized关键字锁住的是这个对象,这样的用法,在性能上会有所下降,因为每次调用getInstance(),都要对对象上锁,事实上,只有在第一次创建对象的时候需要加锁,之后就不需要了,所以,这个地方需要改进。我们改成下面这个: [java] view plaincopy public static Singleton getInstance() { if (instance == null ) { synchronized (instance) { if (instance == null ) { instance = new Singleton(); } } } return instance; } 似乎解决了之前提到的问题,将synchronized关键字加在了内部,也就是说当调用的时候是不需要加锁的,只有在instance为null,并创建对象的时候才需要加锁,性能有一定的提升。但是,这样的情况,还是有可能有问题的,看下面的情况:在Java指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton();语句是分两步执行的。但是JVM并不保证这两个操作的先后顺序,也就是说有可能JVM会为新的Singleton实例分配空间,然后直接赋值给instance成员,然后再去初始化这个Singleton实例。这样就可能出错了,我们以A、B两个线程为例: a>A、B线程同时进入了第一个if判断 b>A首先进入synchronized块,由于instance为null,所以它执行instance = new Singleton(); c>由于JVM内部的优化机制,JVM先画出了一些分配给Singleton实例的空白内存,并赋值给instance成员(注意此时JVM没有开始初始化这个实例),然后A离开了synchronized块。 d>B进入synchronized块,由于instance此时不是null,因此它马上离开了synchronized块并将结果返回给调用该方法的程序。 e>此时B线程打算使用Singleton实例,却发现它没有被初始化,于是错误发生了。 所以程序还是有可能发生错误,其实程序在运行过程是很复杂的,从这点我们就可以看出,尤其是在写多线程环境下的程序更有难度,有挑战性。我们对该程序做进一步优化: [java] view plaincopy private static class SingletonFactory{ private static Singleton instance = new Singleton(); } public static Singleton getInstance(){ return SingletonFactory.instance; } 实际情况是,单例模式使用内部类来维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,这样我们就不用担心上面的问题。同时该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低性能问题。这样我们暂时总结一个完美的单例模式: [java] view plaincopy public class Singleton { /* 私有构造方法,防止被实例化 */ private Singleton() { } /* 此处使用一个内部类来维护单例 */ private static class SingletonFactory { private static Singleton instance = new Singleton(); } /* 获取实例 */ public static Singleton getInstance() { return SingletonFactory.instance; } /* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */ public Object readResolve() { return getInstance(); } } 其实说它完美,也不一定,如果在构造函数中抛出异常,实例将永远得不到创建,也会出错。所以说,十分完美的东西是没有的,我们只能根据实际情况,选择最适合自己应用场景的实现方法。也有人这样实现:因为我们只需要在创建类的时候进行同步,所以只要将创建和getInstance()分开,单独为创建加synchronized关键字,也是可以的: [java] view plaincopy public class SingletonTest { private static SingletonTest instance = null ; private SingletonTest() { } private static synchronized void syncInit() { if (instance == null ) { instance = new SingletonTest(); } } public static SingletonTest getInstance() { if (instance == null ) { syncInit(); } return instance; } } 考虑性能的话,整个程序只需创建一次实例,所以性能也不会有什么影响。 补充: 采用"影子实例"的办法为单例对象的属性同步更新 [java] view plaincopy public class SingletonTest { private static SingletonTest instance = null ; private Vector properties = null ; public Vector getProperties() { return properties; } private SingletonTest() { } private static synchronized void syncInit() { if (instance == null ) { instance = new SingletonTest(); } } public static SingletonTest getInstance() { if (instance == null ) { syncInit(); } return instance; } public void updateProperties() { SingletonTest shadow = new SingletonTest(); properties = shadow.getProperties(); } } 通过单例模式的学习告诉我们: 1、单例模式理解起来简单,但是具体实现起来还是有一定的难度。 2、synchronized关键字锁定的是对象,在用的时候,一定要在恰当的地方使用(注意需要使用锁的对象和过程,可能有的时候并不是整个对象及整个过程都需要锁)。 到这儿,单例模式基本已经讲完了,结尾处,笔者突然想到另一个问题,就是采用类的静态方法,实现单例模式的效果,也是可行的,此处二者有什么不同? 首先,静态类不能实现接口。(从类的角度说是可以的,但是那样就破坏了静态了。因为接口中不允许有static修饰的方法,所以即使实现了也是非静态的) 其次,单例可以被延迟初始化,静态类一般在第一次加载是初始化。之所以延迟加载,是因为有些类比较庞大,所以延迟加载有助于提升性能。 再次,单例类可以被继承,他的方法可以被覆写。但是静态类内部方法都是static,无法被覆写。 最后一点,单例类比较灵活,毕竟从实现上只是一个普通的Java类,只要满足单例的基本需求,你可以在里面随心所欲的实现一些其它功能,但是静态类不行。从上面这些概括中,基本可以看出二者的区别,但是,从另一方面讲,我们上面最后实现的那个单例模式,内部就是用一个静态类来实现的,所以,二者有很大的关联,只是我们考虑问题的层面不同罢了。两种思想的结合,才能造就出完美的解决方案,就像HashMap采用数组+链表来实现一样,其实生活中很多事情都是这样,单用不同的方法来处理问题,总是有优点也有缺点,最完美的方法是,结合各个方法的优点,才能最好的解决问题! 4、建造者模式(Builder) 工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的Test结合起来得到的。我们看一下代码: 还和前面一样,一个Sender接口,两个实现类MailSender和SmsSender。最后,建造者类如下: [java] view plaincopy public class Builder { private List list = new ArrayList(); public void produceMailSender( int count){ for ( int i= 0 ; i list.add( new MailSender()); } } public void produceSmsSender( int count){ for ( int i= 0 ; i list.add( new SmsSender()); } } } 测试类: [java] view plaincopy public class Test { public static void main(String[] args) { Builder builder = new Builder(); builder.produceMailSender( 10 ); } } 从这点看出,建造者模式将很多功能集成到一个类里,这个类可以创造出比较复杂的东西。所以与工程模式的区别就是:工厂模式关注的是创建单个产品,而建造者模式则关注创建符合对象,多个部分。因此,是选择工厂模式还是建造者模式,依实际情况而定。 5、原型模式(Prototype) 原型模式虽然是创建型的模式,但是与工程模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。本小结会通过对象的复制,进行讲解。在Java中,复制对象是通过clone()实现的,先创建一个原型类: [java] view plaincopy public class Prototype implements Cloneable { public Object clone() throws CloneNotSupportedException { Prototype proto = (Prototype) super .clone(); return proto; } } 很简单,一个原型类,只需要实现Cloneable接口,覆写clone方法,此处clone方法可以改成任意的名称,因为Cloneable接口是个空接口,你可以任意定义实现类的方法名,如cloneA或者cloneB,因为此处的重点是super.clone()这句话,super.clone()调用的是Object的clone()方法,而在Object类中,clone()是native的,具体怎么实现,我会在另一篇文章中,关于解读Java中本地方法的调用,此处不再深究。在这儿,我将结合对象的浅复制和深复制来说一下,首先需要了解对象深、浅复制的概念: 浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。 深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。 此处,写一个深浅复制的例子: [java] view plaincopy public class Prototype implements Cloneable, Serializable { private static final long serialVersionUID = 1L; private String string; private SerializableObject obj; /* 浅复制 */ public Object clone() throws CloneNotSupportedException { Prototype proto = (Prototype) super .clone(); return proto; } /* 深复制 */ public Object deepClone() throws IOException, ClassNotFoundException { /* 写入当前对象的二进制流 */ ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject( this ); /* 读出二进制流产生的新对象 */ ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return ois.readObject(); } public String getString() { return string; } public void setString(String string) { this .string = string; } public SerializableObject getObj() { return obj; } public void setObj(SerializableObject obj) { this .obj = obj; } } class SerializableObject implements Serializable { private static final long serialVersionUID = 1L; } 要实现深复制,需要采用流的形式读入当前对象的二进制输入,再写出二进制数据对应的对象。 我们接着讨论设计模式,上篇文章我讲完了5种创建型模式,这章开始,我将讲下7种结构型模式:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。其中对象的适配器模式是各种模式的起源,我们看下面的图: 适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。首先,我们来看看 类的适配器模式 ,先看类图: 核心思想就是:有一个Source类,拥有一个方法,待适配,目标接口时Targetable,通过Adapter类,将Source的功能扩展到Targetable里,看代码: [java] view plaincopy public class Source { public void method1() { System.out.println( "this is original method!" ); } } [java] view plaincopy public interface Targetable { /* 与原类中的方法相同 */ public void method1(); /* 新类的方法 */ public void method2(); } [java] view plaincopy public class Adapter extends Source implements Targetable { @Override public void method2() { System.out.println( "this is the targetable method!" ); } } Adapter类继承Source类,实现Targetable接口,下面是测试类: [java] view plaincopy public class AdapterTest { public static void main(String[] args) { Targetable target = new Adapter(); 接下来我们将要谈谈责任链模式,有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链,请求在这条链上传递,直到某一对象决定处理该请求。但是发出者并不清楚到底最终那个对象会处理该请求,所以,责任链模式可以实现,在隐瞒客户 target.method1(); target.method2(); } } 输出: this is original method! this is the targetable method! 这样Targetable接口的实现类就具有了Source类的功能。 对象的适配器模式 基本思路和类的适配器模式相同,只是将Adapter类作修改,这次不继承Source类,而是持有Source类的实例,以达到解决兼容性的问题。看图: 只需要修改Adapter类的源码即可: [java] view plaincopy public class Wrapper implements Targetable { private Source source; public Wrapper(Source source){ super (); this .source = source; } @Override public void method2() { System.out.println( "this is the targetable method!" ); } @Override public void method1() { source.method1(); } } 测试类: [java] view plaincopy public class AdapterTest { public static void main(String[] args) { Source source = new Source(); Targetable target = new Wrapper(source); target.method1(); target.method2(); } } 输出与第一种一样,只是适配的方法不同而已。 第三种适配器模式是 接口的适配器模式 ,接口的适配器是这样的:有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行。看一下类图: 这个很好理解,在实际开发中,我们也常会遇到这种接口中定义了太多的方法,以致于有时我们在一些实现类中并不是都需要。看代码: [java] view plaincopy public interface Sourceable { public void method1(); public void method2(); } 抽象类Wrapper2: [java] view plaincopy public abstract class Wrapper2 implements Sourceable{ public void method1(){} public void method2(){} } [java] view plaincopy public class SourceSub1 extends Wrapper2 { public void method1(){ System.out.println( "the sourceable interface's first Sub1!" ); } } [java] view plaincopy public class SourceSub2 extends Wrapper2 { public void method2(){ System.out.println( "the sourceable interface's second Sub2!" ); } } [java] view plaincopy public class WrapperTest { public static void main(String[] args) { Sourceable source1 = new SourceSub1(); Sourceable source2 = new SourceSub2(); source1.method1(); source1.method2(); source2.method1(); source2.method2(); } } 测试输出: the sourceable interface's first Sub1! the sourceable interface's second Sub2! 达到了我们的效果! 讲了这么多,总结一下三种适配器模式的应用场景: 类的适配器模式:当希望将 一个类 转换成满足 另一个新接口 的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。 对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。 接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。 7、装饰模式(Decorator) 顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例,关系图如下: Source类是被装饰类,Decorator类是一个装饰类,可以为Source类动态的添加一些功能,代码如下: [java] view plaincopy public interface Sourceable { public void method(); } [java] view plaincopy public class Source implements Sourceable { @Override public void method() { System.out.println( "the original method!" ); } } [java] view plaincopy public class Decorator implements Sourceable { private Sourceable source; public Decorator(Sourceable source){ super (); this .source = source; } @Override public void method() { System.out.println( "before decorator!" ); source.method(); System.out.println( "after decorator!" ); } } 测试类: [java] view plaincopy public class DecoratorTest { public static void main(String[] args) { Sourceable source = new Source(); Sourceable obj = new Decorator(source); obj.method(); } } 输出: before decorator! the original method! after decorator! 装饰器模式的应用场景: 1、需要扩展一个类的功能。 2、动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点,继承的功能是静态的,不能动态增删。) 缺点:产生过多相似的对象,不易排错! 8、代理模式(Proxy) 其实每个模式名称就表明了该模式的作用,代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。再如我们有的时候打官司,我们需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们的想法。先来看看关系图: 根据上文的阐述,代理模式就比较容易的理解了,我们看下代码: [java] view plaincopy public interface Sourceable { public void method(); } [java] view plaincopy public class Source implements Sourceable { @Override public void method() { System.out.println( "the original method!" ); } } [java] view plaincopy public class Proxy implements Sourceable { private Source source; public Proxy(){ super (); this .source = new Source(); } @Override public void method() { before(); source.method(); atfer(); } private void atfer() { System.out.println( "after proxy!" ); } private void before() { System.out.println( "before proxy!" ); } } 测试类: [java] view plaincopy public class ProxyTest { public static void main(String[] args) { Sourceable source = new Proxy(); source.method(); } } 输出: before proxy! the original method! after proxy! 代理模式的应用场景: 如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法: 1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。 2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。 使用代理模式,可以将功能划分的更加清晰,有助于后期维护! 9、外观模式(Facade) 外观模式是为了解决类与类之家的依赖关系的,像spring一样,可以将类和类之间的关系配置到配置文件中,而外观模式就是将他们的关系放在一个Facade类中,降低了类类之间的耦合度,该模式中没有涉及到接口,看下类图:(我们以一个计算机的启动过程为例) 我们先看下实现类: [java] view plaincopy public class CPU { public void startup(){ System.out.println( "cpu startup!" ); } public void shutdown(){ System.out.println( "cpu shutdown!" ); } } [java] view plaincopy public class Memory { public void startup(){ System.out.println( "memory startup!" ); } public void shutdown(){ System.out.println( "memory shutdown!" ); } } [java] view plaincopy public class Disk { public void startup(){ System.out.println( "disk startup!" ); } public void shutdown(){ System.out.println( "disk shutdown!" ); } } [java] view plaincopy public class Computer { private CPU cpu; private Memory memory; private Disk disk; public Computer(){ cpu = new CPU(); memory = new Memory(); disk = new Disk(); } public void startup(){ System.out.println( "start the computer!" ); cpu.startup(); memory.startup(); disk.startup(); System.out.println( "start computer finished!" ); } public void shutdown(){ System.out.println( "begin to close the computer!" ); cpu.shutdown(); memory.shutdown(); disk.shutdown(); System.out.println( "computer closed!" ); } } User类如下: [java] view plaincopy public class User { public static void main(String[] args) { Computer computer = new Computer(); computer.startup(); computer.shutdown(); } } 输出: start the computer! cpu startup! memory startup! disk startup! start computer finished! begin to close the computer! cpu shutdown! memory shutdown! disk shutdown! computer closed! 如果我们没有Computer类,那么,CPU、Memory、Disk他们之间将会相互持有实例,产生关系,这样会造成严重的依赖,修改一个类,可能会带来其他类的修改,这不是我们想要看到的,有了Computer类,他们之间的关系被放在了Computer类里,这样就起到了解耦的作用,这,就是外观模式! 10、桥接模式(Bridge) 桥接模式就是把事物和其具体实现分开,使他们可以各自独立的变化。桥接的用意是: 将抽象化与实现化解耦,使得二者可以独立变化 ,像我们常用的JDBC桥DriverManager一样,JDBC进行连接数据库的时候,在各个数据库之间进行切换,基本不需要动太多的代码,甚至丝毫不用动,原因就是JDBC提供统一接口,每个数据库提供各自的实现,用一个叫做数据库驱动的程序来桥接就行了。我们来看看关系图: 实现代码: 先定义接口: [java] view plaincopy public interface Sourceable { public void method(); } 分别定义两个实现类: [java] view plaincopy public class SourceSub1 implements Sourceable { @Override public void method() { System.out.println( "this is the first sub!" ); } } [java] view plaincopy public class SourceSub2 implements Sourceable { @Override public void method() { System.out.println( "this is the second sub!" ); } } 定义一个桥,持有Sourceable的一个实例: [java] view plaincopy public abstract class Bridge { private Sourceable source; public void method(){ source.method(); } public Sourceable getSource() { return source; } public void setSource(Sourceable source) { this .source = source; } } [java] view plaincopy public class MyBridge extends Bridge { public void method(){ getSource().method(); } } 测试类: [java] view plaincopy public class BridgeTest { public static void main(String[] args) { Bridge bridge = new MyBridge(); /*调用第一个对象*/ Sourceable source1 = new SourceSub1(); bridge.setSource(source1); bridge.method(); /*调用第二个对象*/ Sourceable source2 = new SourceSub2(); bridge.setSource(source2); bridge.method(); } } output: this is the first sub! this is the second sub! 这样,就通过对Bridge类的调用,实现了对接口Sourceable的实现类SourceSub1和SourceSub2的调用。接下来我再画个图,大家就应该明白了,因为这个图是我们JDBC连接的原理,有数据库学习基础的,一结合就都懂了。 11、组合模式(Composite) 组合模式有时又叫部分-整体 模式在处理类似树形结构的问题时比较方便,看看关系图: 直接来看代码: [java] view plaincopy public class TreeNode { private String name; private TreeNode parent; private Vector children = new Vector(); public TreeNode(String name){ this .name = name; } public String getName() { return name; } public void setName(String name) { this .name = name; } public TreeNode getParent() { return parent; } public void setParent(TreeNode parent) { this .parent = parent; } //添加孩子节点 public void add(TreeNode node){ children.add(node); } //删除孩子节点 public void remove(TreeNode node){ children.remove(node); } //取得孩子节点 public Enumeration getChildren(){ return children.elements(); } } [java] view plaincopy public class Tree { TreeNode root = null ; public Tree(String name) { root = new TreeNode(name); } public static void main(String[] args) { Tree tree = new Tree( "A" ); TreeNode nodeB = new TreeNode( "B" ); TreeNode nodeC = new TreeNode( "C" ); nodeB.add(nodeC); tree.root.add(nodeB); System.out.println( "build the tree finished!" ); } } 使用场景:将多个对象组合在一起进行操作,常用于表示树形结构中,例如二叉树,数等。 12、享元模式(Flyweight) 享元模式的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用。 FlyWeightFactory负责创建和管理享元单元,当一个客户端请求时,工厂需要检查当前对象池中是否有符合条件的对象,如果有,就返回已经存在的对象,如果没有,则创建一个新对象,FlyWeight是超类。一提到共享池,我们很容易联想到Java里面的JDBC连接池,想想每个连接的特点,我们不难总结出:适用于作共享的一些个对象,他们有一些共有的属性,就拿数据库连接池来说,url、driverClassName、username、password及dbname,这些属性对于每个连接来说都是一样的,所以就适合用享元模式来处理,建一个工厂类,将上述类似属性作为内部数据,其它的作为外部数据,在方法调用时,当做参数传进来,这样就节省了空间,减少了实例的数量。 看个例子: 看下数据库连接池的代码: [java] view plaincopy public class ConnectionPool { private Vector pool; /*公有属性*/ private String url = "jdbc:mysql://localhost:3306/test" ; private String username = "root" ; private String password = "root" ; private String driverClassName = "com.mysql.jdbc.Driver" ; private int poolSize = 100 ; private static ConnectionPool instance = null ; Connection conn = null ; /*构造方法,做一些初始化工作*/ private ConnectionPool() { pool = new Vector(poolSize); for ( int i = 0 ; i < poolSize; i++) { try { Class.forName(driverClassName); conn = DriverManager.getConnection(url, username, password); pool.add(conn); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } } /* 返回连接到连接池 */ public synchronized void release() { pool.add(conn); } /* 返回连接池中的一个数据库连接 */ public synchronized Connection getConnection() { if (pool.size() > 0 ) { Connection conn = pool.get( 0 ); pool.remove(conn); return conn; } else { return null ; } } } 通过连接池的管理,实现了数据库连接的共享,不需要每一次都重新创建连接,节省了数据库重新创建的开销,提升了系统的性能!本章讲解了7种结构型模式,因为篇幅的问题,剩下的11种行为型模式, 本章是关于设计模式的最后一讲,会讲到第三种设计模式——行为型模式,共11种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。这段时间一直在写关于设计模式的东西,终于写到一半了,写博文是个很费时间的东西,因为我得为读者负责,不论是图还是代码还是表述,都希望能尽量写清楚,以便读者理解,我想不论是我还是读者,都希望看到高质量的博文出来,从我本人出发,我会一直坚持下去,不断更新,源源动力来自于读者朋友们的不断支持,我会尽自己的努力,写好每一篇文章!希望大家能不断给出意见和建议,共同打造完美的博文! 先来张图,看看这11中模式的关系: 第一类:通过父类与子类的关系进行实现。第二类:两个类之间。第三类:类的状态。第四类:通过中间类 13、策略模式(strategy) 策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数,关系图如下: 图中ICalculator提供同意的方法, AbstractCalculator是辅助类,提供辅助方法,接下来,依次实现下每个类: 首先统一接口: [java] view plaincopy public interface ICalculator { public int calculate(String exp); } 辅助类: [java] view plaincopy public abstract class AbstractCalculator { public int [] split(String exp,String opt){ String array[] = exp.split(opt); int arrayInt[] = new int [ 2 ]; arrayInt[ 0 ] = Integer.parseInt(array[ 0 ]); arrayInt[ 1 ] = Integer.parseInt(array[ 1 ]); return arrayInt; } } 三个实现类: [java] view plaincopy public class Plus extends AbstractCalculator implements ICalculator { @Override public int calculate(String exp) { int arrayInt[] = split(exp, "\\+" ); return arrayInt[ 0 ]+arrayInt[ 1 ]; } } [java] view plaincopy public class Minus extends AbstractCalculator implements ICalculator { @Override public int calculate(String exp) { int arrayInt[] = split(exp, "-" ); return arrayInt[ 0 ]-arrayInt[ 1 ]; } } [java] view plaincopy public class Multiply extends AbstractCalculator implements ICalculator { @Override public int calculate(String exp) { int arrayInt[] = split(exp, "\\*" ); return arrayInt[ 0 ]*arrayInt[ 1 ]; } } 简单的测试类: [java] view plaincopy public class StrategyTest { public static void main(String[] args) { String exp = "2+8" ; ICalculator cal = new Plus(); int result = cal.calculate(exp); System.out.println(result); } } 输出:10 策略模式的决定权在用户,系统本身提供不同算法的实现,新增或者删除算法,对各种算法做封装。因此,策略模式多用在算法决策系统中,外部用户只需要决定用哪个算法即可。 14、模板方法模式(Template Method) 解释一下模板方法模式,就是指:一个抽象类中,有一个主方法,再定义1...n个方法,可以是抽象的,也可以是实际的方法,定义一个类,继承该抽象类,重写抽象方法,通过调用抽象类,实现对子类的调用,先看个关系图: 就是在AbstractCalculator类中定义一个主方法calculate,calculate()调用spilt()等,Plus和Minus分别继承AbstractCalculator类,通过对AbstractCalculator的调用实现对子类的调用,看下面的例子: [java] view plaincopy public abstract class AbstractCalculator { /*主方法,实现对本类其它方法的调用*/ public final int calculate(String exp,String opt){ int array[] = split(exp,opt); return calculate(array[ 0 ],array[ 1 ]); } /*被子类重写的方法*/ abstract public int calculate( int num1, int num2); public int [] split(String exp,String opt){ String array[] = exp.split(opt); int arrayInt[] = new int [ 2 ]; arrayInt[ 0 ] = Integer.parseInt(array[ 0 ]); arrayInt[ 1 ] = Integer.parseInt(array[ 1 ]); return arrayInt; } } [java] view plaincopy public class Plus extends AbstractCalculator { @Override public int calculate( int num1, int num2) { return num1 + num2; } } 测试类: [java] view plaincopy public class StrategyTest { public static void main(String[] args) { String exp = "8+8" ; AbstractCalculator cal = new Plus(); int result = cal.calculate(exp, "\\+" ); System.out.println(result); } } 我跟踪下这个小程序的执行过程:首先将exp和"\\+"做参数,调用AbstractCalculator类里的calculate(String,String)方法,在calculate(String,String)里调用同类的split(),之后再调用calculate(int ,int)方法,从这个方法进入到子类中,执行完return num1 + num2后,将值返回到AbstractCalculator类,赋给result,打印出来。正好验证了我们开头的思路。 15、观察者模式(Observer) 包括这个模式在内的接下来的四个模式,都是类和类之间的关系,不涉及到继承,学的时候应该 记得归纳,记得本文最开始的那个图。观察者模式很好理解,类似于邮件订阅和RSS订阅,当我们浏览一些博客或wiki时,经常会看到RSS图标,就这的意思是,当你订阅了该文章,如果后续有更新,会及时通知你。其实,简单来讲就一句话:当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化!对象之间是一种一对多的关系。先来看看关系图: 我解释下这些类的作用:MySubject类就是我们的主对象,Observer1和Observer2是依赖于MySubject的对象,当MySubject变化时,Observer1和Observer2必然变化。AbstractSubject类中定义着需要监控的对象列表,可以对其进行修改:增加或删除被监控对象,且当MySubject变化时,负责通知在列表内存在的对象。我们看实现代码: 一个Observer接口: [java] view plaincopy public interface Observer { public void update(); } 两个实现类: [java] view plaincopy public class Observer1 implements Observer { @Override public void update() { System.out.println( "observer1 has received!" ); } } [java] view plaincopy public class Observer2 implements Observer { @Override public void update() { System.out.println( "observer2 has received!" ); } } Subject接口及实现类: [java] view plaincopy public interface Subject { /*增加观察者*/ public void add(Observer observer); /*删除观察者*/ public void del(Observer observer); /*通知所有的观察者*/ public void notifyObservers(); /*自身的操作*/ public void operation(); } [java] view plaincopy public abstract class AbstractSubject implements Subject { private Vector vector = new Vector(); @Override public void add(Observer observer) { vector.add(observer); } @Override public void del(Observer observer) { vector.remove(observer); } @Override public void notifyObservers() { Enumeration enumo = vector.elements(); while (enumo.hasMoreElements()){ enumo.nextElement().update(); } } } [java] view plaincopy public class MySubject extends AbstractSubject { @Override public void operation() { System.out.println( "update self!" ); notifyObservers(); } } 测试类: [java] view plaincopy public class ObserverTest { public static void main(String[] args) { Subject sub = new MySubject(); sub.add( new Observer1()); sub.add( new Observer2()); sub.operation(); } } 输出: update self! observer1 has received! observer2 has received! 这些东西,其实不难,只是有些抽象,不太容易整体理解,建议读者: 根据关系图,新建项目,自己写代码(或者参考我的代码),按照总体思路走一遍,这样才能体会它的思想,理解起来容易! 16、迭代子模式(Iterator) 顾名思义,迭代器模式就是顺序访问聚集中的对象,一般来说,集合中非常常见,如果对集合类比较熟悉的话,理解本模式会十分轻松。这句话包含两层意思:一是需要遍历的对象,即聚集对象,二是迭代器对象,用于对聚集对象进行遍历访问。我们看下关系图: 这个思路和我们常用的一模一样,MyCollection中定义了集合的一些操作,MyIterator中定义了一系列迭代操作,且持有Collection实例,我们来看看实现代码: 两个接口: [java] view plaincopy public interface Collection { public Iterator iterator(); /*取得集合元素*/ public Object get( int i); /*取得集合大小*/ public int size(); } [java] view plaincopy public interface Iterator { //前移 public Object previous(); //后移 public Object next(); public boolean hasNext(); //取得第一个元素 public Object first(); } 两个实现: [java] view plaincopy public class MyCollection implements Collection { public String string[] = { "A" , "B" , "C" , "D" , "E" }; @Override public Iterator iterator() { return new MyIterator( this ); } @Override public Object get( int i) { return string[i]; } @Override public int size() { return string.length; } } [java] view plaincopy public class MyIterator implements Iterator { private Collection collection; private int pos = - 1 ; public MyIterator(Collection collection){ this .collection = collection; } @Override public Object previous() { if (pos > 0 ){ pos--; } return collection.get(pos); } @Override public Object next() { if (pos1 ){ pos++; } return collection.get(pos); } @Override public boolean hasNext() { if (pos1 ){ return true ; } else { return false ; } } @Override public Object first() { pos = 0 ; return collection.get(pos); } } 测试类: [java] view plaincopy public class Test { public static void main(String[] args) { Collection collection = new MyCollection(); Iterator it = collection.iterator(); while (it.hasNext()){ System.out.println(it.next()); } } } 输出:A B C D E 此处我们貌似模拟了一个集合类的过程,感觉是不是很爽?其实JDK中各个类也都是这些基本的东西,加一些设计模式,再加一些优化放到一起的,只要我们把这些东西学会了,掌握好了,我们也可以写出自己的集合类,甚至框架! 17、责任链模式(Chain of Responsibility) 接下来我们将要谈谈责任链模式,有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链,请求在这条链上传递,直到某一对象决定处理该请求。但是发出者并不清楚到底最终那个对象会处理该请求,所以,责任链模式可以实现,在隐瞒客户端的情况下,对系统进行动态的调整。先看看关系图: Abstracthandler类提供了get和set方法,方便MyHandle类设置和修改引用对象,MyHandle类是核心,实例化后生成一系列相互持有的对象,构成一条链。 [java] view plaincopy public interface Handler { public void operator(); } [java] view plaincopy public abstract class AbstractHandler { private Handler handler; public Handler getHandler() { return handler; } public void setHandler(Handler handler) { this .handler = handler; } } [java] view plaincopy public class MyHandler extends AbstractHandler implements Handler { private String name; public MyHandler(String name) { this .name = name; } @Override public void operator() { System.out.println(name+ "deal!" ); if (getHandler()!= null ){ getHandler().operator(); } } } [java] view plaincopy public class Test { public static void main(String[] args) { MyHandler h1 = new MyHandler( "h1" ); MyHandler h2 = new MyHandler( "h2" ); MyHandler h3 = new MyHandler( "h3" ); h1.setHandler(h2); h2.setHandler(h3); h1.operator(); } } 输出: h1deal! h2deal! h3deal! 此处强调一点就是,链接上的请求可以是一条链,可以是一个树,还可以是一个环,模式本身不约束这个,需要我们自己去实现,同时,在一个时刻,命令只允许由一个对象传给另一个对象,而不允许传给多个对象。 18、命令模式(Command) 命令模式很好理解,举个例子,司令员下令让士兵去干件事情,从整个事情的角度来考虑,司令员的作用是,发出口令,口令经过传递,传到了士兵耳朵里,士兵去执行。这个过程好在,三者相互解耦,任何一方都不用去依赖其他人,只需要做好自己的事儿就行,司令员要的是结果,不会去关注到底士兵是怎么实现的。我们看看关系图: Invoker是调用者(司令员),Receiver是被调用者(士兵),MyCommand是命令,实现了Command接口,持有接收对象,看实现代码: [java] view plaincopy public interface Command { public void exe(); } [java] view plaincopy public class MyCommand implements Command { private Receiver receiver; public MyCommand(Receiver receiver) { this .receiver = receiver; } @Override public void exe() { receiver.action(); } } [java] view plaincopy public class Receiver { public void action(){ System.out.println( "command received!" ); } } [java] view plaincopy public class Invoker { private Command command; public Invoker(Command command) { this .command = command; } public void action(){ command.exe(); } } [java] view plaincopy public class Test { public static void main(String[] args) { Receiver receiver = new Receiver(); Command cmd = new MyCommand(receiver); Invoker invoker = new Invoker(cmd); invoker.action(); } } 输出:command received! 这个很哈理解,命令模式的目的就是达到命令的发出者和执行者之间解耦,实现请求和执行分开,熟悉Struts的同学应该知道,Struts其实就是一种将请求和呈现分离的技术,其中必然涉及命令模式的思想! 其实每个设计模式都是很重要的一种思想,看上去很熟,其实是因为我们在学到的东西中都有涉及,尽管有时我们并不知道,其实在Java本身的设计之中处处都有体现,像AWT、JDBC、集合类、IO管道或者是Web框架,里面设计模式无处不在。因为我们篇幅有限,很难讲每一个设计模式都讲的很详细,不过我会尽我所能,尽量在有限的空间和篇幅内,把意思写清楚了,更好让大家明白。本章不出意外的话,应该是设计模式最后一讲了,首先还是上一下上篇开头的那个图: 本章讲讲第三类和第四类。 19、备忘录模式(Memento) 主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象,个人觉得叫备份模式更形象些,通俗的讲下:假设有原始类A,A中有各种属性,A可以决定需要备份的属性,备忘录类B是用来存储A的一些内部状态,类C呢,就是一个用来存储备忘录的,且只能存储,不能修改等操作。做个图来分析一下: Original类是原始类,里面有需要保存的属性value及创建一个备忘录类,用来保存value值。Memento类是备忘录类,Storage类是存储备忘录的类,持有Memento类的实例,该模式很好理解。直接看源码: [java] view plaincopy public class Original { private String value; public String getValue() { return value; } public void setValue(String value) { this .value = value; } public Original(String value) { this .value = value; } public Memento createMemento(){ return new Memento(value); } public void restoreMemento(Memento memento){ this .value = memento.getValue(); } } [java] view plaincopy public class Memento { private String value; public Memento(String value) { this .value = value; } public String getValue() { return value; } public void setValue(String value) { this .value = value; } } [java] view plaincopy public class Storage { private Memento memento; public Storage(Memento memento) { this .memento = memento; } public Memento getMemento() { return memento; } public void setMemento(Memento memento) { this .memento = memento; } } 测试类: [java] view plaincopy public class Test { public static void main(String[] args) { // 创建原始类 Original origi = new Original( "egg" ); // 创建备忘录 Storage storage = new Storage(origi.createMemento()); // 修改原始类的状态 System.out.println( "初始化状态为:" + origi.getValue()); origi.setValue( "niu" ); System.out.println( "修改后的状态为:" + origi.getValue()); // 回复原始类的状态 origi.restoreMemento(storage.getMemento()); System.out.println( "恢复后的状态为:" + origi.getValue()); } } 输出: 初始化状态为:egg 修改后的状态为:niu 恢复后的状态为:egg 简单描述下:新建原始类时,value被初始化为egg,后经过修改,将value的值置为niu,最后倒数第二行进行恢复状态,结果成功恢复了。其实我觉得这个模式叫“备份-恢复”模式最形象。 20、状态模式(State) 核心思想就是:当对象的状态改变时,同时改变其行为,很好理解!就拿QQ来说,有几种状态,在线、隐身、忙碌等,每个状态对应不同的操作,而且你的好友也能看到你的状态,所以,状态模式就两点:1、可以通过改变状态来获得不同的行为。2、你的好友能同时看到你的变化。看图: State类是个状态类,Context类可以实现切换,我们来看看代码: [java] view plaincopy package com.xtfggef.dp.state; /** * 状态类的核心类 * 2012-12-1 * @author erqing * */ public class State { private String value; public String getValue() { return value; } public void setValue(String value) { this .value = value; } public void method1(){ System.out.println( "execute the first opt!" ); } public void method2(){ System.out.println( "execute the second opt!" ); } } [java] view plaincopy package com.xtfggef.dp.state; /** * 状态模式的切换类 2012-12-1 * @author erqing * */ public class Context { private State state; public Context(State state) { this .state = state; } public State getState() { return state; } public void setState(State state) { this .state = state; } public void method() { if (state.getValue().equals( "state1" )) { state.method1(); } else if (state.getValue().equals( "state2" )) { state.method2(); } } } 测试类: [java] view plaincopy public class Test { public static void main(String[] args) { State state = new State(); Context context = new Context(state); //设置第一种状态 state.setValue( "state1" ); context.method(); //设置第二种状态 state.setValue( "state2" ); context.method(); } } 输出: execute the first opt! execute the second opt! 根据这个特性,状态模式在日常开发中用的挺多的,尤其是做网站的时候,我们有时希望根据对象的某一属性,区别开他们的一些功能,比如说简单的权限控制等。 21、访问者模式(Visitor) 访问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化。访问者模式适用于数据结构相对稳定算法又易变化的系统。因为访问者模式使得算法操作增加变得容易。若系统数据结构对象易于变化,经常有新的数据对象增加进来,则不适合使用访问者模式。访问者模式的优点是增加操作很容易,因为增加操作意味着增加新的访问者。访问者模式将有关行为集中到一个访问者对象中,其改变不影响系统数据结构。其缺点就是增加新的数据结构很困难。—— From 百科 简单来说,访问者模式就是一种分离对象数据结构与行为的方法,通过这种分离,可达到为一个被访问者动态添加新的操作而无需做其它的修改的效果。简单关系图: 来看看原码:一个Visitor类,存放要访问的对象, [java] view plaincopy public interface Visitor { public void visit(Subject sub); } [java] view plaincopy public class MyVisitor implements Visitor { @Override public void visit(Subject sub) { System.out.println( "visit the subject:" +sub.getSubject()); } } Subject类,accept方法,接受将要访问它的对象,getSubject()获取将要被访问的属性, [java] view plaincopy public interface Subject { public void accept(Visitor visitor); public String getSubject(); } [java] view plaincopy public class MySubject implements Subject { @Override public void accept(Visitor visitor) { visitor.visit( this ); } @Override public String getSubject() { return "love" ; } } 测试: [java] view plaincopy public class Test { public static void main(String[] args) { Visitor visitor = new MyVisitor(); Subject sub = new MySubject(); sub.accept(visitor); } } 输出:visit the subject:love 该模式适用场景:如果我们想为一个现有的类增加新功能,不得不考虑几个事情:1、新功能会不会与现有功能出现兼容性问题?2、以后会不会再需要添加?3、如果类不允许修改代码怎么办?面对这些问题,最好的解决方法就是使用访问者模式,访问者模式适用于数据结构相对稳定的系统,把数据结构和算法解耦, 22、中介者模式(Mediator) 中介者模式也是用来降低类类之间的耦合的,因为如果类类之间有依赖关系的话,不利于功能的拓展和维护,因为只要修改一个对象,其它关联的对象都得进行修改。如果使用中介者模式,只需关心和Mediator类的关系,具体类类之间的关系及调度交给Mediator就行,这有点像spring容器的作用。先看看图: User类统一接口,User1和User2分别是不同的对象,二者之间有关联,如果不采用中介者模式,则需要二者相互持有引用,这样二者的耦合度很高,为了解耦,引入了Mediator类,提供统一接口,MyMediator为其实现类,里面持有User1和User2的实例,用来实现对User1和User2的控制。这样User1和User2两个对象相互独立,他们只需要保持好和Mediator之间的关系就行,剩下的全由MyMediator类来维护!基本实现: [java] view plaincopy public interface Mediator { public void createMediator(); public void workAll(); } [java] view plaincopy public class MyMediator implements Mediator { private User user1; private User user2; public User getUser1() { return user1; } public User getUser2() { return user2; } @Override public void createMediator() { user1 = new User1( this ); user2 = new User2( this ); } @Override public void workAll() { user1.work(); user2.work(); } } [java] view plaincopy public abstract class User { private Mediator mediator; public Mediator getMediator(){ return mediator; } public User(Mediator mediator) { this .mediator = mediator; } public abstract void work(); } [java] view plaincopy public class User1 extends User { public User1(Mediator mediator){ super (mediator); } @Override public void work() { System.out.println( "user1 exe!" ); } } [java] view plaincopy public class User2 extends User { public User2(Mediator mediator){ super (mediator); } @Override public void work() { System.out.println( "user2 exe!" ); } } 测试类: [java] view plaincopy public class Test { public static void main(String[] args) { Mediator mediator = new MyMediator(); mediator.createMediator(); mediator.workAll(); } } 输出: user1 exe! user2 exe! 23、解释器模式(Interpreter) 解释器模式是我们暂时的最后一讲,一般主要应用在OOP开发中的编译器的开发中,所以适用面比较窄。 Context类是一个上下文环境类,Plus和Minus分别是用来计算的实现,代码如下: [java] view plaincopy public interface Expression { public int interpret(Context context); } [java] view plaincopy public class Plus implements Expression { @Override public int interpret(Context context) { return context.getNum1()+context.getNum2(); } } [java] view plaincopy public class Minus implements Expression { @Override public int interpret(Context context) { return context.getNum1()-context.getNum2(); } } [java] view plaincopy public class Context { private int num1; private int num2; public Context( int num1, int num2) { this .num1 = num1; this .num2 = num2; } public int getNum1() { return num1; } public void setNum1( int num1) { this .num1 = num1; } public int getNum2() { return num2; } public void setNum2( int num2) { this .num2 = num2; } } [java] view plaincopy public class Test { public static void main(String[] args) { // 计算9+2-8的值 int result = new Minus().interpret(( new Context( new Plus() .interpret( new Context( 9 , 2 )), 8 ))); System.out.println(result); } } 最后输出正确的结果:3。 基本就这样,解释器模式用来做各种各样的解释器,如正则表达式等的解释器等等! 设计模式基本就这么大概讲完了,总体感觉有点简略,的确,这么点儿篇幅,不足以对整个23种设计模式做全面的阐述,此处读者可将它作为一个理论基础去学习,通过这四篇博文,先基本有个概念,虽然我讲的有些简单,但基本都能说明问题及他们的特点,如果对哪一个感兴趣,可以继续深入研究!同时我也会不断更新,尽量补全遗漏、修正不足,欢迎广大读者及时提出好的建议,我们一起学习!项目中涉及到的代码,已经放到了我的资源里:http://download. csdn.net/detail/zhangerqing/4835830(因为我不喜欢不劳而获,所以没有免积分,只设置了5个,如果有人实在没积分又急要,那么联系我吧,我给你发过去)。
50.谈谈你对框架的理解,设计框架的时候你是怎么考虑的,重构项目的时候你都遵循什么原则。
1. 框架不要为应用做过多的假设 关于框架为应用做过多的假设, 一个非常具体的现象就是, 框架越俎代庖, 把本来是应 用要做的事情揽过来自己做。 这是一种典型的吃力不讨好的做法。 框架越俎代庖, 也许会使 得某一个具体应用的开发变得简单, 却会给其它更多想使用该框架的应用增加了本没有必要 的束缚和负担。 2. 使用接口,保证框架提供的所有重要实现都是可以被替换的 框架终究不是应用, 所以框架无法考虑所有应用的具体情况, 保证所有重要的组件的实 现都是可以被替换的, 这一点非常重要, 它使得应用可以根据当前的实际情况来替换掉框架 提供的部分组件的默认实现。 使用接口来定义框架中各个组件及组件间的联系, 将提高框架 的可复用性。 3. 框架应当简洁、一致、且目标集中 框架应当简洁, 不要包含那些对框架目标来说无关紧要的东西, 保证框架中的每个组件 的存在都是为了支持框架目标的实现。包含过多无谓的元素(类、接口、枚举等) ,会使框 架变得难以理解, 尝试将这些对于框架核心目标不太重要的元素转移到类库中, 可以使得框 架更清晰、目标更集中。 4. 提供一个常用的骨架,但是不要固定骨架的结构,使骨架也是可以组装的 比如说, 如果是针对某种业务处理的框架, 那么框架不应该只提供一套不可变更的业务 处理流程,而是应该将处理流程 “ 单步 ” 化,使得各个步骤是可以重新组装的,如此一来,应 用便可以根据实际情况来改变框架默认的处理流程。 这种框架的可定制化能力可以极大地提 高框架的可复用性。 5. 不断地重构框架 如果说设计和实现一个高质量的框架有什么秘诀?答案只有一个,重构、不断地重构。 重构框架的实现代码、 甚至重构框架的设计。 重构的驱动力源于几个方面, 比如对要解决的 本质问题有了更清晰准备的认识,在使用框架的时候发现某些组件职责不明确、难以使用, 框架的层次结构不够清晰等。
51.LRU算法
假设 序列为 4 3 4 2 3 1 4 2 物理块有3个 则 首轮 4调入内存 4 次轮 3调入内存 3 4 之后 4调入内存 4 3 之后 2调入内存 2 4 3 之后 3调入内存 3 2 4 之后 1调入内存 1 3 2(因为最少使用的是4,所以丢弃4) 之后 4调入内存 4 1 3(原理同上) 最后 2调入内存 2 4 1 在指定内存中如果超过内存剔除最近最少用的。
51.自定义控件的生命周期
onFinishInflate() 当View中所有的子控件均被映射成xml后触发 onMeasure( int , int ) 确定所有子元素的大小 onLayout( boolean , int , int , int , int ) 当View分配所有的子元素的大小和位置时触发 onSizeChanged( int , int , int , int ) 当view的大小发生变化时触发 onDraw(Canvas) view渲染内容的细节 onKeyDown( int , KeyEvent) 有按键按下后触发 onKeyUp( int , KeyEvent) 有按键按下后弹起时触发 onTrackballEvent(MotionEvent) 轨迹球事件 onTouchEvent(MotionEvent) 触屏事件 onFocusChanged( boolean , int , Rect) 当View获取或失去焦点时触发 onWindowFocusChanged( boolean ) 当窗口包含的view获取或失去焦点时触发 onAttachedToWindow() 当view被附着到一个窗口时触发 onDetachedFromWindow() 当view离开附着的窗口时触发,Android123提示该方法和 onAttachedToWindow() 是相反的。 onWindowVisibilityChanged( int ) 当窗口中包含的可见的view发生变化时触发
如果你有好的技术文章想和大家分享,欢迎向我的公众号投稿,投稿具体细节请在公众号主页点击 “投稿” 菜单查看。
欢迎长按下图 -> 识别图中二维码或者在微信中输入ysle_0313进行搜索 或者扫一扫 关注我的公众号:
你可能感兴趣的:(Android,Android学习,创意,面试题)
android系统selinux中添加新属性property
辉色投像
1.定位/android/system/sepolicy/private/property_contexts声明属性开头:persist.charge声明属性类型:u:object_r:system_prop:s0图12.定位到android/system/sepolicy/public/domain.te删除neverallow{domain-init}default_prop:property
python八股文面试题分享及解析(1)
Shawn________
python
#1.'''a=1b=2不用中间变量交换a和b'''#1.a=1b=2a,b=b,aprint(a)print(b)结果:21#2.ll=[]foriinrange(3):ll.append({'num':i})print(11)结果:#[{'num':0},{'num':1},{'num':2}]#3.kk=[]a={'num':0}foriinrange(3):#0,12#可变类型,不仅仅改变
每日算法&面试题,大厂特训二十八天——第二十天(树)
肥学
⚡算法题⚡面试题每日精进 java 算法 数据结构
目录标题导读算法特训二十八天面试题点击直接资料领取导读肥友们为了更好的去帮助新同学适应算法和面试题,最近我们开始进行专项突击一步一步来。上一期我们完成了动态规划二十一天现在我们进行下一项对各类算法进行二十八天的一个小总结。还在等什么快来一起肥学进行二十八天挑战吧!!特别介绍小白练手专栏,适合刚入手的新人欢迎订阅编程小白进阶python有趣练手项目里面包括了像《机器人尬聊》《恶搞程序》这样的有趣文章
OPENAIGC开发者大赛企业组AI黑马奖 | AIGC数智传媒解决方案
RPA中国
人工智能 AIGC 传媒
在第二届拯救者杯OPENAIGC开发者大赛中,涌现出一批技术突出、创意卓越的作品。为了让这些优秀项目被更多人看到,我们特意开设了优秀作品报道专栏,旨在展示其独特之处和开发者的精彩故事。无论您是技术专家还是爱好者,希望能带给您不一样的知识和启发。让我们一起探索AIGC的无限可能,见证科技与创意的完美融合!创未来AI应用赛-企业组AI黑马奖作品名称:AIGC数智传媒解决方案参赛团队:深圳市三象智能技术
2.2.6 通知类控件 Toast、Menu
常思行
本文例程下载:WillFlow_Toast、WillFlowMenu一、什么是Toast?Toast也被叫做吐司,是Android系统提供的一种非常好的提醒方式,在程序中可以使用它将一些短小的信息通知给用户,它有如下两个特点:Toast是没有焦点的Toast显示的时间有限过一定的时间就会自动消失所以一般来讲Toast的使用并不会影响我们的正常操作,并且它通常不会占用太大的屏幕空间,有着良好的用户体
Java企业面试题3
马龙强_
java
1.break和continue的作用(智*图)break:用于完全退出一个循环(如for,while)或一个switch语句。当在循环体内遇到break语句时,程序会立即跳出当前循环体,继续执行循环之后的代码。continue:用于跳过当前循环体中剩余的部分,并开始下一次循环。如果是在for循环中使用continue,则会直接进行条件判断以决定是否执行下一轮循环。2.if分支语句和switch分
Java面试题精选:消息队列(二)
芒果不是芒
Java面试题精选 java kafka
一、Kafka的特性1.消息持久化:消息存储在磁盘,所以消息不会丢失2.高吞吐量:可以轻松实现单机百万级别的并发3.扩展性:扩展性强,还是动态扩展4.多客户端支持:支持多种语言(Java、C、C++、GO、)5.KafkaStreams(一个天生的流处理):在双十一或者销售大屏就会用到这种流处理。使用KafkaStreams可以快速的把销售额统计出来6.安全机制:Kafka进行生产或者消费的时候会
mac 备份android 手机通讯录导入iphone,iphone如何导出通讯录(轻松教你iPhone备份通讯录的方法)...
weixin_39762838
mac 备份android 手机通讯录导入iphone
在日新月异的手机更替中,换手机已经成为一个非常稀松平常的事情,但将旧手机上面的通讯录导入到新手机还是让不少小伙伴为难,本篇将给大家详细讲解这方面的知识:“苹果手机通讯录怎么导入到新手机”及“安卓手机通讯录导入到新手机”的方法。一、苹果手机通讯录导入到新手机常用方法(SIM卡导入)在苹果手机主频幕上找到“设置”,单击进入设置菜单,下拉菜单列表,点击“邮件、通讯录、日历”,然后找到“导入SIM卡通讯录
android 更改窗口的层次,浮窗开发之窗口层级
Ms.Bu
android 更改窗口的层次
最近在项目中遇到了这样的需求:需要在特定的其他应用之上悬浮自己的UI交互(拖动、输入等复杂的UI交互),和九游的浮窗类似,不过我们的比九游的体验更好,我们越过了很多授权的限制。浮窗效果很多人都知道如何去实现一个简单的浮窗,但是却很少有人去深入的研究背后的流程机制,由于项目中浮窗交互比较复杂,遇到了些坑查看了很多资料,故总结浮窗涉及到的知识点:窗口层级关系(浮窗是如何“浮”的)?浮窗有哪些限制,如何
Android应用性能优化
轻口味
Android
Android手机由于其本身的后台机制和硬件特点,性能上一直被诟病,所以软件开发者对软件本身的性能优化就显得尤为重要;本文将对Android开发过程中性能优化的各个方面做一个回顾与总结。Cache优化ListView缓存:ListView中有一个回收器,Item滑出界面的时候View会回收到这里,需要显示新的Item的时候,就尽量重用回收器里面的View;每次在getView函数中inflate新
ai绘画工具midjourney怎么下载?附作品管理教程
设计师早上好
Midjourney是一款功能强大的AI绘画工具,它使用机器学习技术和深度神经网络等算法,可以生成各种艺术风格的绘画作品。在创意设计、广告宣传等方面有着广泛的应用前景。那么,ai绘画工具midjourney怎么下载?本文将为您介绍Midjourney的下载以及作品的相关管理。一、Midjourney下载Midjourney的下载非常简单,只需打开Midjourney官网(点击“GetMidjour
Day_11
ROC_bird..
算法
面试题16.15.珠玑妙算-力扣(LeetCode)/***Note:Thereturnedarraymustbemalloced,assumecallercallsfree().*///下标和对应位置的值都一样,answer[0]+1,对应位置的值猜对了,但是下标不对,answer[1]+1int*masterMind(char*solution,char*guess,int*returnSiz
Android实现监听事件的方法
Amy木婉清
1.通过内部类实现2.通过匿名内部类实现3.通过事件源所在类实现4.通过外部类实现5.布局文件中onclick属性(针对点击事件)1.通过内部类实现代码:privateButtonmBtnEvent;//oncreate中mBtnEvent.setOnClickListener(newOnClick());//内部类实现监听classOnClickimplementsView.OnClickLis
高级UI<第二十四篇>:Android中用到的矩阵常识
NoBugException
(1)定义在数学中,矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合。由m×n个数aij排成的m行n列的数表称为m行n列的矩阵,简称m×n矩阵。记作:图片.png这m×n个数称为矩阵A的元素,简称为元,数aij位于矩阵A的第i行第j列,称为矩阵A的(i,j)元,以数aij为(i,j)元的矩阵可记为(aij)或(aij)m×n,m×n矩阵A也记作Amn。元素是实数的矩阵称为实矩阵,元素是复
RK3229_Android9.0_Box 4G模块EC200A调试
suifen_
网络
0、kernel修改这部分完全可以参考Linux的移植:RK3588EC200A-CN【4G模块】调试_rkec200a-cn-CSDN博客1、修改device/rockchip/rk322xdiff--gita/device.mkb/device.mkindexec6bfaa..e7c32d1100755---a/device.mk+++b/device.mk@@-105,6+105,8@@en
【从问题中去学习k8s】k8s中的常见面试题(夯实理论基础)(二十八)
向往风的男子
k8s 学习 kubernetes 容器
本站以分享各种运维经验和运维所需要的技能为主《python零基础入门》:python零基础入门学习《python运维脚本》:python运维脚本实践《shell》:shell学习《terraform》持续更新中:terraform_Aws学习零基础入门到最佳实战《k8》从问题中去学习k8s《docker学习》暂未更新《ceph学习》ceph日常问题解决分享《日志收集》ELK+各种中间件《运维日常》
kt文件和java文件_Java与Kotlin之间怎样进行互操作
铭空间
kt文件和java文件
Java与Kotlin之间怎样进行互操作发布时间:2021-02-0210:50:43来源:亿速云阅读:98作者:小新这篇文章主要介绍了Java与Kotlin之间怎样进行互操作,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。前言目前kotlin是谷歌首推的开发Android的语言,但由于历史原因,我们绝大部分项目依旧还是以Java为主
Android shell 常用 debug 命令
晨春计
Audio debug android linux
目录1、查看版本2、am命令3、pm命令4、dumpsys命令5、sed命令6、log定位查看APK进程号7、log定位使用场景1、查看版本1.1、Android串口终端执行getpropro.build.version.release#获取Android版本uname-a#查看linux内核版本信息uname-r#单独查看内核版本1.2、linux服务器执行lsb_release-a#查看Lin
【Kubernetes】常见面试题汇总(十一)
summer.335
Kubernetes kubernetes 容器 云原生
目录33.简述Kubernetes外部如何访问集群内的服务?34.简述Kubernetesingress?35.简述Kubernetes镜像的下载策略?33.简述Kubernetes外部如何访问集群内的服务?(1)对于Kubernetes,集群外的客户端默认情况,无法通过Pod的IP地址或者Service的虚拟IP地址:虚拟端口号进行访问。(2)通常可以通过以下方式进行访问Kubernetes集群
华雁智科前端面试题
因为奋斗超太帅啦
前端笔试面试问题整理 javascript 开发语言 ecmascript
1.var变量的提升题目:vara=1functionfun(){console.log(b)varb=2}fun()console.log(a)正确输出结果:undefined、1答错了,给一个大嘴巴子,错误答案输出结果为:2,1此题主要考察var定义的变量,作用域提升的问题,相当于varaa=1functionfun(){varbconsole.log(b)b=2}fun()console.l
1.8,69
知行思合一
运气动力学万维钢老师提出的名词,不愧是物理博士出身,good1idea,创意一些新名词。开文引用查理芒格的话:得到你想要的东西,最保险的办法,就是让自己配得上你想要的那个东西。接着举例《绝命毒师》Breakingbad导演文斯·吉里根接受采访说的话,引出成功的经验——运气。我们现在所处的这个社会不管是美国还是中国,大体上都是一个精英社会——人们可以靠天赋和努力去争取财富和地位,而不像历史上那样家庭
2024年最全Flutter如何和Native通信-Android视角,Electron开发Android界面
2401_84544531
程序员 android 面试 学习
总结【Android详细知识点思维脑图(技能树)】其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。虽然Android没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明Android中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪
2019-1-27晨间日记
将军将离
今天是什么日子起床:十点就寝:十二点天气:阴心情:时好时坏纪念日:追番又追不下去的一天任务清单昨日完成的任务,最重要的三件事:和我妈聊天,吃好多肉改进:早睡习惯养成:不能熬夜周目标·完成进度坚持不下来学习·信息·阅读看小说健康·饮食·锻炼吃了好多肉人际·家人·朋友被我妈嫌工作·思考果然是三分钟热度,海贼王看了三十多集看不下去了,好长啊最美好的三件事1.吃饭2.睡觉3.看动漫思考·创意·未来坚持
音视频知识图谱 2022.04
关键帧Keyframe
前些时间,我在知识星球上创建了一个音视频技术社群:关键帧的音视频开发圈,在这里群友们会一起做一些打卡任务。比如:周期性地整理音视频相关的面试题,汇集一份音视频面试题集锦,你可以看看《音视频面试题集锦2022.04》。再比如:循序渐进地归纳总结音视频技术知识,绘制一幅音视频知识图谱。下面是2022.04月知识图谱新增的内容节选:1)图谱路径:**采集/音频采集/声音三要素/响度******主观计量响
世界上最厉害的人:婚庆老板
王家二少2
我有一段做婚礼主持人的生涯。很多人都说,婚礼主持人都是在耍嘴皮子,其实,这是对婚庆人的误解。婚礼要求很严格,一个个环节巧妙勾连,容不得半点马虎。主持人只是负责仪式,相对轻松。婚礼最繁忙的当属婚庆公司老板。我的师哥师弟都是婚庆公司老板,他们一说起业务,就是滔滔不绝,击中要点。最令我赞叹的是师哥师弟们的借的功力。婚庆行业有一句行话,只有婚庆公司老板是自己的,言外之意,所有的婚庆道具,创意都是借来的。道
小米嵌入式面试题目RTOS面试题目 嵌入式面试题目
好家伙VCC
面试 杂谈杂谈 面试 职场和发展
第一章-非RTOSbootloader工作流程MCU启动流程通信协议,SPIIICMCU怎么选型,STM32F1和F4有什么区别外部RAM和内部RAM区别,怎么分配外部总线和内部总线区别MCU上的固件,数据是怎么分配的MCU启动流程IAP是怎么升级的,突然断电怎么办挑了麦轮项目(因为大疆RM也是麦轮,面试官看样子比较感兴趣)为什么用的CAN总线你说一下spi和i2c和UART的各自的工作方式优缺点
分享一个基于python的电子书数据采集与可视化分析 hadoop电子书数据分析与推荐系统 spark大数据毕设项目(源码、调试、LW、开题、PPT)
计算机源码社
Python项目 大数据 大数据 python hadoop 计算机毕业设计选题 计算机毕业设计源码 数据分析 spark毕设
作者:计算机源码社个人简介:本人八年开发经验,擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等,大家有这一块的问题可以一起交流!学习资料、程序开发、技术解答、文档报告如需要源码,可以扫取文章下方二维码联系咨询Java项目微信小程序项目Android项目Python项目PHP项目ASP.NET项目Node.js项目选题推荐项目实战|p
【Java】面试题31:栈的压入,弹出序列
小小核桃
剑指offer java版
~~题目:~~输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列{1,2,3,4,5}是某栈的压栈序列,序列{4,5,3,2,1}是该压栈序列对应的一个弹出序列,但{4,3,5,1,2}就不可能是该栈序列的弹出序列。思路:首先借助一个辅助栈,把输入的第一个序列中的数字依次压入该辅助栈,并按照第二个序列的顺序依次从该栈中弹出数
数据库常见笔试面试题及其解析
yxsr_zxx
数据库 数据库 SqlServer Oracle 笔试 面试
数据库基础(面试常见题)一、数据库基础1.数据抽象:物理抽象、概念抽象、视图级抽象,内模式、模式、外模式2.SQL语言包括数据定义、数据操纵(DataManipulation),数据控制(DataControl)数据定义:CreateTable,AlterTable,DropTable,Craete/DropIndex等数据操纵:Select,insert,update,delete,数据控制:g
奇慧文化华日雁:行走于另类品牌传播策划的激情人生
静雅子
华日雁原名陈浩,新锐品牌策划界代表性人物,厦门奇慧文化传播有限公司创始人,首席导师,曾任知名上市公司总裁。华日雁最常讲的一句话就是:品牌传播要敢于天马行空,要敢于无中生有,要敢于打破规则,同时要传递积极的社会正能量。这也是华日雁给自己的品牌策划生涯制定的最基本的创意底线和道德底线。奇慧文化创始人华日雁说华日雁的发展史就是一部传奇史一点儿也不为过,从一名普通的销售人员到创立自己的公司,到把公司成功于
JAVA基础
灵静志远
位运算 加载 Date 字符串池 覆盖
一、类的初始化顺序
1 (静态变量,静态代码块)-->(变量,初始化块)--> 构造器
同一括号里的,根据它们在程序中的顺序来决定。上面所述是同一类中。如果是继承的情况,那就在父类到子类交替初始化。
二、String
1 String a = "abc";
JAVA虚拟机首先在字符串池中查找是否已经存在了值为"abc"的对象,根
keepalived实现redis主从高可用
bylijinnan
redis
方案说明
两台机器(称为A和B),以统一的VIP对外提供服务
1.正常情况下,A和B都启动,B会把A的数据同步过来(B is slave of A)
2.当A挂了后,VIP漂移到B;B的keepalived 通知redis 执行:slaveof no one,由B提供服务
3.当A起来后,VIP不切换,仍在B上面;而A的keepalived 通知redis 执行slaveof B,开始
java文件操作大全
0624chenhong
java
最近在博客园看到一篇比较全面的文件操作文章,转过来留着。
http://www.cnblogs.com/zhuocheng/archive/2011/12/12/2285290.html
转自http://blog.sina.com.cn/s/blog_4a9f789a0100ik3p.html
一.获得控制台用户输入的信息
&nbs
android学习任务
不懂事的小屁孩
工作
任务
完成情况 搞清楚带箭头的pupupwindows和不带的使用 已完成 熟练使用pupupwindows和alertdialog,并搞清楚两者的区别 已完成 熟练使用android的线程handler,并敲示例代码 进行中 了解游戏2048的流程,并完成其代码工作 进行中-差几个actionbar 研究一下android的动画效果,写一个实例 已完成 复习fragem
zoom.js
换个号韩国红果果
oom
它的基于bootstrap 的
https://raw.github.com/twbs/bootstrap/master/js/transition.js transition.js模块引用顺序
<link rel="stylesheet" href="style/zoom.css">
<script src=&q
详解Oracle云操作系统Solaris 11.2
蓝儿唯美
Solaris
当Oracle发布Solaris 11时,它将自己的操作系统称为第一个面向云的操作系统。Oracle在发布Solaris 11.2时继续它以云为中心的基调。但是,这些说法没有告诉我们为什么Solaris是配得上云的。幸好,我们不需要等太久。Solaris11.2有4个重要的技术可以在一个有效的云实现中发挥重要作用:OpenStack、内核域、统一存档(UA)和弹性虚拟交换(EVS)。
spring学习——springmvc(一)
a-john
springMVC
Spring MVC基于模型-视图-控制器(Model-View-Controller,MVC)实现,能够帮助我们构建像Spring框架那样灵活和松耦合的Web应用程序。
1,跟踪Spring MVC的请求
请求的第一站是Spring的DispatcherServlet。与大多数基于Java的Web框架一样,Spring MVC所有的请求都会通过一个前端控制器Servlet。前
hdu4342 History repeat itself-------多校联合五
aijuans
数论
水题就不多说什么了。
#include<iostream>#include<cstdlib>#include<stdio.h>#define ll __int64using namespace std;int main(){ int t; ll n; scanf("%d",&t); while(t--)
EJB和javabean的区别
asia007
bean ejb
EJB不是一般的JavaBean,EJB是企业级JavaBean,EJB一共分为3种,实体Bean,消息Bean,会话Bean,书写EJB是需要遵循一定的规范的,具体规范你可以参考相关的资料.另外,要运行EJB,你需要相应的EJB容器,比如Weblogic,Jboss等,而JavaBean不需要,只需要安装Tomcat就可以了
1.EJB用于服务端应用开发, 而JavaBeans
Struts的action和Result总结
百合不是茶
struts Action配置 Result配置
一:Action的配置详解:
下面是一个Struts中一个空的Struts.xml的配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
&quo
如何带好自已的团队
bijian1013
项目管理 团队管理 团队
在网上看到博客"
怎么才能让团队成员好好干活"的评论,觉得写的比较好。 原文如下: 我做团队管理有几年了吧,我和你分享一下我认为带好团队的几点:
1.诚信
对团队内成员,无论是技术研究、交流、问题探讨,要尽可能的保持一种诚信的态度,用心去做好,你的团队会感觉得到。 2.努力提
Java代码混淆工具
sunjing
ProGuard
Open Source Obfuscators
ProGuard
http://java-source.net/open-source/obfuscators/proguardProGuard is a free Java class file shrinker and obfuscator. It can detect and remove unused classes, fields, m
【Redis三】基于Redis sentinel的自动failover主从复制
bit1129
redis
在第二篇中使用2.8.17搭建了主从复制,但是它存在Master单点问题,为了解决这个问题,Redis从2.6开始引入sentinel,用于监控和管理Redis的主从复制环境,进行自动failover,即Master挂了后,sentinel自动从从服务器选出一个Master使主从复制集群仍然可以工作,如果Master醒来再次加入集群,只能以从服务器的形式工作。
什么是Sentine
使用代理实现Hibernate Dao层自动事务
白糖_
DAO spring AOP 框架 Hibernate
都说spring利用AOP实现自动事务处理机制非常好,但在只有hibernate这个框架情况下,我们开启session、管理事务就往往很麻烦。
public void save(Object obj){
Session session = this.getSession();
Transaction tran = session.beginTransaction();
try
maven3实战读书笔记
braveCS
maven3
Maven简介
是什么?
Is a software project management and comprehension tool.项目管理工具
是基于POM概念(工程对象模型)
[设计重复、编码重复、文档重复、构建重复,maven最大化消除了构建的重复]
[与XP:简单、交流与反馈;测试驱动开发、十分钟构建、持续集成、富有信息的工作区]
功能:
编程之美-子数组的最大乘积
bylijinnan
编程之美
public class MaxProduct {
/**
* 编程之美 子数组的最大乘积
* 题目: 给定一个长度为N的整数数组,只允许使用乘法,不能用除法,计算任意N-1个数的组合中乘积中最大的一组,并写出算法的时间复杂度。
* 以下程序对应书上两种方法,求得“乘积中最大的一组”的乘积——都是有溢出的可能的。
* 但按题目的意思,是要求得这个子数组,而不
读书笔记-2
chengxuyuancsdn
读书笔记
1、反射
2、oracle年-月-日 时-分-秒
3、oracle创建有参、无参函数
4、oracle行转列
5、Struts2拦截器
6、Filter过滤器(web.xml)
1、反射
(1)检查类的结构
在java.lang.reflect包里有3个类Field,Method,Constructor分别用于描述类的域、方法和构造器。
2、oracle年月日时分秒
s
[求学与房地产]慎重选择IT培训学校
comsci
it
关于培训学校的教学和教师的问题,我们就不讨论了,我主要关心的是这个问题
培训学校的教学楼和宿舍的环境和稳定性问题
我们大家都知道,房子是一个比较昂贵的东西,特别是那种能够当教室的房子...
&nb
RMAN配置中通道(CHANNEL)相关参数 PARALLELISM 、FILESPERSET的关系
daizj
oracle rman filesperset PARALLELISM
RMAN配置中通道(CHANNEL)相关参数 PARALLELISM 、FILESPERSET的关系 转
PARALLELISM ---
我们还可以通过parallelism参数来指定同时"自动"创建多少个通道:
RMAN > configure device type disk parallelism 3 ;
表示启动三个通道,可以加快备份恢复的速度。
简单排序:冒泡排序
dieslrae
冒泡排序
public void bubbleSort(int[] array){
for(int i=1;i<array.length;i++){
for(int k=0;k<array.length-i;k++){
if(array[k] > array[k+1]){
初二上学期难记单词三
dcj3sjt126com
sciet
concert 音乐会
tonight 今晚
famous 有名的;著名的
song 歌曲
thousand 千
accident 事故;灾难
careless 粗心的,大意的
break 折断;断裂;破碎
heart 心(脏)
happen 偶尔发生,碰巧
tourist 旅游者;观光者
science (自然)科学
marry 结婚
subject 题目;
I.安装Memcahce 1. 安装依赖包libevent Memcache需要安装libevent,所以安装前可能需要执行 Shell代码 收藏代码
dcj3sjt126com
redis
wget http://download.redis.io/redis-stable.tar.gz
tar xvzf redis-stable.tar.gz
cd redis-stable
make
前面3步应该没有问题,主要的问题是执行make的时候,出现了异常。
异常一:
make[2]: cc: Command not found
异常原因:没有安装g
并发容器
shuizhaosi888
并发容器
通过并发容器来改善同步容器的性能,同步容器将所有对容器状态的访问都串行化,来实现线程安全,这种方式严重降低并发性,当多个线程访问时,吞吐量严重降低。
并发容器ConcurrentHashMap
替代同步基于散列的Map,通过Lock控制。
&nb
Spring Security(12)——Remember-Me功能
234390216
Spring Security Remember Me 记住我
Remember-Me功能
目录
1.1 概述
1.2 基于简单加密token的方法
1.3 基于持久化token的方法
1.4 Remember-Me相关接口和实现
位运算
焦志广
位运算
一、位运算符C语言提供了六种位运算符:
& 按位与
| 按位或
^ 按位异或
~ 取反
<< 左移
>> 右移
1. 按位与运算 按位与运算符"&"是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1 ,否则为0。参与运算的数以补码方式出现。
例如:9&am
nodejs 数据库连接 mongodb mysql
liguangsong
mongodb mysql node 数据库连接
1.mysql 连接
package.json中dependencies加入
"mysql":"~2.7.0"
执行 npm install
在config 下创建文件 database.js
java动态编译
olive6615
java HotSpot jvm 动态编译
在HotSpot虚拟机中,有两个技术是至关重要的,即动态编译(Dynamic compilation)和Profiling。
HotSpot是如何动态编译Javad的bytecode呢?Java bytecode是以解释方式被load到虚拟机的。HotSpot里有一个运行监视器,即Profile Monitor,专门监视
Storm0.9.5的集群部署配置优化
roadrunners
优化 storm.yaml
nimbus结点配置(storm.yaml)信息:
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional inf
101个MySQL 的调节和优化的提示
tomcat_oracle
mysql
1. 拥有足够的物理内存来把整个InnoDB文件加载到内存中——在内存中访问文件时的速度要比在硬盘中访问时快的多。 2. 不惜一切代价避免使用Swap交换分区 – 交换时是从硬盘读取的,它的速度很慢。 3. 使用电池供电的RAM(注:RAM即随机存储器)。 4. 使用高级的RAID(注:Redundant Arrays of Inexpensive Disks,即磁盘阵列
zoj 3829 Known Notation(贪心)
阿尔萨斯
ZOJ
题目链接:zoj 3829 Known Notation
题目大意:给定一个不完整的后缀表达式,要求有2种不同操作,用尽量少的操作使得表达式完整。
解题思路:贪心,数字的个数要要保证比∗的个数多1,不够的话优先补在开头是最优的。然后遍历一遍字符串,碰到数字+1,碰到∗-1,保证数字的个数大于等1,如果不够减的话,可以和最后面的一个数字交换位置(用栈维护十分方便),因为添加和交换代价都是1