北京总部

JAVA入门学习:学好Java,这些编程思想很重要

JAVA入门学习:学好Java,这些编程思想很重要

2017-01-31

如今,Java已是业界最流行的软件技术之一,在历年的编程语言排行榜中均稳均前三。论起原因,在于JAVA在各平台独立性、可移植性和厂商独立性方面的出色表现,Java已在世界范围内成为大多数企业、机构和团体的IT基础设施的重要组成部分。想学好JAVA,下面这些编程的思想很重要。 (一)在一个类中,所有成员变量在定义时的初始化在构造函数进行初始化之前完成,就是说,先进行定义时的初始化,然后再是构造方法里的初始化。 (二)为什么要进行方法重载? 1、不同类型的对象可能有相似的操作,在抽象的过程中把“相似”抽象出同一个方法名,因此进行方法的重载可以使得同名方法接受不同类型、不同数量的参数,从而对该操作的行为进行具体的控制; 2、构造方法的存在要求必须支持方法重载。因为构造方法必须与类同名,又可能存在需要对类的成员进行不同程度的初始化(体现在构造方法的参数的类型和数量),因此构造方法必须重载。 (三)如何判断方法重载? 判断方法的重载是根据“方法名”、“方法参数”和“方法参数的顺序”,方法的重载必须满足以下条件: 1、在使用重载时只能通过不同的参数样式。例如:不同的参数类型、不同的参数个数、不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int, float), 但是不能为fun(int, int)); 2、不能通过“访问权限”、“返回类型”、“抛出的异常”进行重载; 3、方法的异常类型和数目不会对重载造成影响; 4、对于继承来说,如果某一方法在父类中是访问权限是priavte,那么就不能在子类对其进行重载,如果定义的话,也只是定义了一个新方法,而不会达到重载的效果。 (四)方法的参数如果有基本类型对重载有什么影响? 因为基本类型会自动从较小类型提升到较大类型,因此如果传入的int,但是类中只有f(long)和f(float),因为没有f(int),因此int自动提升到long,从而调用f(long),提升的顺序是byte-char-short-int-long-float-double。 (五)什么叫重载的二义性? 如果在重载方法时,其他的都相同,仅仅是返回类型不同,则会出现二义性,比如f(){}和int f(){return 1;}。 1、如果调用int i = f();,则编译器能正确找到所调用的方法; 2、如果仅仅调用f();,则编译器没有任何条件来确定到底应该调用哪个方法; 所以,不能根据返回类型来重载。 (六)为什么在方法体内定义的局部变量必须显式初始化? 像java的基本类型,在定义类的成员变量时如果没有显式初始化,则会隐含地初始化为0或false等。但是在方法体内定义时必须进行显示初始化,因为编译器会认为这是程序员的一个“粗心的错误”,有可能他自己并不需要定义或者不是定义这种类型,显式初始化会起到一个提示程序员的作用。 (七)当构建一个类的实例时,编译器依次主要做以下三件事情: 1、为对象分配内存空间; 2、初始化对象中实例变量的值,初始化值可以是缺省值或按指定的方式初始化。“指定的方式”可能是直接赋值、表达式赋值或调用其他任何方法赋值; 3、调用对象的构造方法。 (八)静态变量只有在必要的时候才执行初始化,它只在第一次使用时初始化,然后就一直存在供其他实例使用。“必要的时候”指:创建对象时、用类名直接访问时、在装载类时。 (九)构造方法即使没有显式使用static关键字,它实际上是一个静态方法。 (十)JAVA初始化顺序 JAVA类首次装入时,会对静态成员变量或方法进行一次初始化,但方法不被调用是不会执行的,静态成员变量和静态初始化块级别相同,非静态成员变量和非静态初始化块级别相同。 先初始化父类的静态代码--->初始化子类的静态代码-->(创建实例时,如果不创建实例,则后面的不执行)初始化父类的非静态代码--->初始化父类构造函数--->初始化子类非静态代码--->初始化子类构造函数 其他说明: 1 、类只有在使用New调用创建的时候才会被JAVA类装载器装入; 2、创建类实例时,首先按照父子继承关系进行初始化; 3、类实例创建时候,首先初始化块部分先执行,然后是构造方法;然后从本类继承的子类的初始化块执行,最后是子类的构造方法; 4、类消除时候,首先消除子类部分,再消除父类部分; (十一)静态块的初始化:静态快就像其它的静态初始化一样,只进行一次:第一次创建对象时或第一次调用类的一个静态成员(通常直接用类名访问类的静态成员)。 非静态块的初始化的作用:1、对匿名类的初始化提供直接支持;2、保证了无论调用哪个构造方法都执行特定的初始化操作。 (十二)类的访问级别只有package和public,没有private和protected。 1、对于package级别的类,其方法一般设为package,但是也可以也可以设置成public。 2、实际上,内部类的访问级别可以为private和protected,但只有这一种特殊情况。 (十三)final类型的变量分为编译时初始化(这种类型的常量一定是基本类型的)和运行时初始化两种。 final使基本类型的变量的值为常量,而使对象类型的实例的引用变量为常量,它不能再引用其它实例,但它所引用的实例是可以改变的。 (十四)什么叫blank final?有什么作用? 成员变量在定义为final,但是暂时不显式初始化。但是它在使用前必须被初始化,编译器会检查。注意:定义成final类型的基本类型的变量的隐式初始化并不起作用。 定义成blank final的变量一般在构造方法中初始化,因此在创建类的实例时可以产生一些特殊效果:使得每个类的不同实例的这个实例变量拥有不同的值(要达到这种效果,就不能再加上static关键字了)。 (十五)final类型的参数:对方法的参数加final限制,主要用于想匿名内部类传递数据。 (十六) final类型的方法:一是在父类定义的方法加上final可以防止被子类覆盖。二是早期处于效率的考虑,现在已经没这个可言了。 (十七)类的所有private方法都隐含为final,不需要显式声明为final。但是private成员变量并不是final的,因为private成员变量可以隐式初始化,final的变量是不能通过隐式初始化来初始化的,因此,要是private成员变量是是final的,必须显式地加上final关键字。 (十八)final类型的类不允许继承,final类的成员变量可以是final的,也可以不是final的,由你自己决定。但是final类的所有方法都隐含是final的。 (十九)在一个类中,如果成员变量或方法定义为private,则表明该成员变量或方法并不是类提供给外部的接口。覆盖只会发生在类提供给外部的接口上,因此如果子类定义了与父类private成员变量或方法名字、参数均相同的方法,它不是覆盖,而是子类定义的新的方法。 (二十)方法覆盖和方法重载具有以下相同点: 1、都要求方法同名。 2、都可以用于抽象方法和非抽象方法之间。 3、方法覆盖和方法重载具有以下不同点: 4、方法覆盖要求参数签名必须一致,而方法重载要求参数签名必须不一致。 5、方法覆盖要求返回类型必须一致,而方法重载对此不做限制。 6、方法覆盖只能用于子类覆盖父类的方法,方法重载用于同一个类的所有方法(包括从父类中继承而来的方法)。 7、方法覆盖对方法的访问权限和抛出的异常有特殊的要求,而方法重载在这方面没有任何限制。 8、父类的一个方法只能被子类覆盖一次,而一个方法在所在的类中可以被重载多次。 在覆盖要注意以下的几点: 1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果; 2、覆盖的方法的返回类型必须和被覆盖的方法的返回类型一致;(在jdk1.4及以前的版本有此严格要求,从jdk1.5开始弱化了,只要求覆盖方法的返回类型与被覆盖方法的返回类型相同或者前者是后者的子类就可以了) 3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类; 4、被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。 5、子类方法的访问级别不能低于父类方法的访问级别。 (二十一)只有类的方法才存在多态性;类的成员变量不存在多态性;类的static方法也不存在多态性。 父类和子类如果存在同名的成员变量,则不叫覆盖,而叫遮盖,子类实际上包含了这两个变量,它们的存储空间是不同的但是子类的该变量是默认的,要想访问父类的那个变量就必须显式使用super来访问。 (二十二)抽象类可能并不包含抽象的方法,此时它的作用仅仅是使得无法创建该类的实例而已; (二十三)接口可以包含成员变量,都隐含是static并且final,但是不会是blank final的(static与blank final是冲突的,参考(十四)),接口类如果没有显式设置访问级别,则默认为package;接口里的方法如果没有显式设置访问级别,则默认为public,而不是通常的默认为package。 如果,您对java感兴趣,却不得门而入,那么可以接受中软国际的JAVA培训,我们这边有专业的师资团队,真实的项目经验,真实项目经理,真实的工作环境,真实的工作压力,真实的就业机会,助您成就IT梦。  了解更多JAVA入门精彩内容欢迎登陆中软国际教育集团技术知识库!

更多>
软件开发培训:为什么要进行面向对象设计?

软件开发培训:为什么要进行面向对象设计?

2017-01-30

   前段时间,小卓曾邀请一位工程师前辈与大家详细交流了什么是面向对象,同学们表示很有收获。        那么为什么要面向对象设计呢?它有哪些设计原则?今天,我们就这个问题继续深入探讨: 小卓:在编程时,有个很重要的问题,既然我们能够很快地创建几个类,编写程序并提交,为什么我们还要关注面向对象设计? 同学:是啊,以前我不知道面向对象设计,我也能开发提交项目。有什么关系? 小卓:好的,先让我给你看一个经典的引述: "需求不变的程序开发会同行走在冰上一样简单。" - Edward V. Berard 同学:你是指软件开发说明书会被不断修改 小卓:非常正确!软件开发唯一的真理是“软件必然修改”。为什么? 要知道,你的软件解决的是现实世界中的问题,而现实生活不是一成不变的。 可能你的软件现在运行良好。但它能灵活的支持“变化”吗?如果不能,那它就不是一个敏捷设计的软件。 同学:好,那你就解释一下什么叫做“敏捷设计的软件”! 小卓:“一个敏捷设计的软件能轻松应对变化,能被扩展和复用。” 而应用“面向对象设计”是做到敏捷设计的关键。那么,什么时候你可以说你的程序应用了面向对象设计? 同学:我也正想问呢。 小卓:如果代码符合以下几点,那么你就在“面向对象设计”: · 面向对象 · 复用 · 变化的代价极小 · 无需改代码即可扩展 同学:然后呢? 小卓:不只我们,很多人也花了很多时间和精力思考这个问题上,他们尝试更好的进行“面向对象设计”,并为“面向对象设计”指出几条基本的原则(你可以用在你的“面向对象设计”中)。他们也确实总结出了一些通用的设计模式(基于基本的原则)。 同学:你能说出一些吗?  小卓:没问题。现在有许多设计原则,但是最基本的,就是SOLID(缩写),这五项原则。(感谢鲍勃叔叔,伟大OOD导师)。 S  = 单一责任原则 O = 开闭原则 L  = Liscov替换原则 I  = 接口隔离原则 D = 依赖倒置原则       想了解什么是SOLID?请阅读今天技术知识库的第2至第6篇文章,你将会看到许多生动有趣的举例说明,比如鸵鸟不会飞、买电视机、穿衣服……让你轻松了解面向对象的基本原则! 出处:开源中国 译者:K6F, 凡程子, 叫我蝴蝶吧, 王薇, 人头马没面, 铂金小龟, 风子, nikeff1108, sigai 链接:http://www.oschina.net/translate/how-i-explained-ood-to-my-wife?lang=chs&page=4# 了解更多软件开发知识欢迎访问中软国际教育集团技术知识库!

更多>
JAVA入门:JAVA几个常见错误简析

JAVA入门:JAVA几个常见错误简析

2017-01-25

1、空指针错误 java.lang.NullPointerException 使用基本的JAVA数据类型,变量的值要么已经是默认值,如果没有对其正常赋值,程序便不能通过编译,因此使用基本的JAVA数据类型(double,float,boolean,char,int,long)一般不会引起空指针异常。由此可见,空指针异常主要跟与对象的操作相关。 下面先列出了可能发生空指针异常的几种情况及相应解决方案: 不管对象是否为空就直接开始使用。 (JSP)代码段1: out.println(request.getParameter("username")); 描述: 代码段1的功能十分简单,就是输出用户输入的表域"username"的值。 说明: 看上去,上面的语句找不出什么语法错误,而且在大多数情况下也遇不到什么问题。但是,如果某个用户在输入数据时并没有提供表单域"username"的值,或通过某种途径绕过表单直接输入时,此时request.getParameter("username")的值为空(不是空字符串,是空对象null。),out对象的println方法是无法直接对空对象操作,因此代码段1所在的JSP页面将会抛出"java.lang.NullPointerException"异常。 即使对象可能为空时,也调用java.lang.Object或Object对象本身的一些方法如toString(), equals(Object obj)等操作。 (JSP)代码段2: String userName = request.getParameter("username");  If (userName.equals("root"))  {....} 描述: 代码段2的功能是检测用户提供的用户名,如果是用户名称为"root"的用户时,就执行一些特别的操作。 说明: 在代码段2中,如果有用户没有提供表单域"username"的值时,字符串对象userName为null值,不能够将一个null的对象与另一个对象直接比较,同样,代码段2所在的JSP页面就会抛出(java.lang.NullPointerException)空指针错误。 (JSP)代码段3: String userName = session.getAttribute("session.username").toString(); 描述: 代码段3的功能是将session中session.username的值取出,并将该值赋给字符串对象 userName。 说明: 在一般情况下,如果在用户已经进行某个会话,则不会出现什么问题;但是,如果此时应用服务器重新启动,而用户还没有重新登录,(也可能是用户关闭浏览器,但是仍打开原来的页面。)那么,此时该session的值就会失效,同时导致session中的session.username的值为空。对一个为null的对象的直接执行toString()操作,就会导致系统抛出(java.lang.NullPointerException)空指针异常。 解决方案: 为了确保进行操作或引用的对象非空,假若我们要对某对象进行操作或引用,我们首先去检查该对象是否已经实例化且不为空;并且在系统中加入针对对象为空时情况的处理。 如:采用String对象保存用户提交的结果;在如果涉及对象的操作时,先检测其是否为空后,检查到对象为空后,可再选择进行以下任一种处理方式: 处理方式 1) 检查到对象为空时,设置对象值为空字符串或一个默认值; 处理方式 2) 检测到对象为空时,根本不执行某操作,直接跳转到其他处理中。 处理方式 3) 检查到对象为空时,提示用户操作有错误。 将代码段2按以上方式进行改写,得到: 方式1: String userName = request.getParameter("username"); // 该变量值为空时,转化为默认空字符串 If (userName == null) userName = ""; If (userName.equals("root")) {..........} 方式2: String userName = request.getParameter("username"); // 该变量值为空时,转化为默认空字符串,不执行有关操作。 If (usreName != null) { If (userName.equals("root")) {..........} } 方式3: String userName = request.getParameter("username"); // 该变量值为空时,转化为默认空字符串,不执行有关操作。 If (usreName == null) { // 提示用户输入信息为空 } 实际中,上面提供到三种处理方式也同样适用于其他异常的处理: 异常处理方式 1) 检查到异常出现,设置对象值为空字符串或一个默认值。 异常处理方式 2) 检测到异常出现,根本不执行某操作,直接跳转到其他处理中。 异常处理方式 3) 检查到异常出现,提示用户操作有错误。 2、格式化数字错误 java.lang.NumberFormatException分析 (JSP)代码段3: String s_memberid = request.getParameter("memberid"); int i_memberid = Integer.parseInt(s_memberid); 描述: 以上代码段的作用是将用户提交的表单域memberid的值转化为整数。 说明: 如果用户输入正确的数字如:1082,不会有什么问题。然而,如果用户输入T1082时,由于T1082不是合法的数字格式,JAVA无法将其转化为合适的数字,导致抛出java.lang.NumberFormatException数字格式化异常。 解决方案: 在任何用到字符串转化为数字时,捕捉异常,对异常情况进行处理按异常处理方式1:检查到异常发生,即赋给某变量一个默认值;(可能在某些情况下导致一其他程序错误[比方说其他模块中并未处理您所赋予的默认值情况,可能导致一些异常或错误出现。])按异常处理方式3:检查到异常发生,提示用户使用正确的数字格式输入。(实现稍微麻烦一点,但是将错误阻挡在您的模块前[即您提供给其他模块的值均是安全的]。)按这种方法对程序进行改写,在编程时稍微麻烦一点,但这的确会您的模块更加健壮。将代码段3按以上要求进行改写,得到: String s_memberid = request.getParameter("memberid"); int i_memberid; try { i_memberid = Integer.parseInt(s_memberid); ... } catch(NumberFormatException nfe) { //方式1:(简单,直接给该编号为一个默认值0;) i_memberid = 0; //方式2:(很简陋的做法,建议使用更友好的提示方式) out.println(""); } 3、字符串越界错误 java.lang.StringIndexOutOfBoundsException等字符串类相关错误 代码段4: String s_all_power = "1010011"; String s_access_power = s_all_power.substring(3,4); 描述: 以上代码段功能的功能是获取字符串s_all_power中的第4个字符。 说明: 一般情况下,程序不会有问题,如果由于某种原因,s_all_power长度变短,程序就会抛出字符串错误。 解决方案: 对字符串进行截取(substring, charAt)、转换为字节数组(getBytes),字符数组转换为字符串(valueOf)操作时,先对操作字符串对象的存在性(是否为空)及长度进行检查后,再进行操作。 改写得到: String s_all_power = "1010011"; if (s_all_power.length>4)  String s_access_power = s_all_power.substring(3,4); 4、类定义未找到错误 java.lang.NoClassDefFoundError 原因: 由于该程序调用到的JAVA类文件没有正确上传; 解决方案: 将JAVA类文件重新上传。 JAVA类文件已经上传,但应用服务器并未检测到,建议将JSP页面重新更新。 解决方案: 将JSP页面更新并上传;或将应用程序服务器进行重新启动。 5、JAVA错误 java.lang.Error 原因: 1.对系统所访问外部资源,未执行关闭操作,导致外部资源大量浪费,最终可能导致系统无法正常运行; 2.对系统所访问的外部资源关闭次数太多,外部系统无法正常处理; 3.系统访问的外部资源出现异常情况。 解决方案: 1.访问外部资源前,首先检查该资源(如数据库)是否可正常连接或操作。 2.访问外部资源时,如果进行了连接,一定进行关闭操作,并仅进行一次关闭操作。 3.尽量在同一操作中共享外部资源,以减少该操作对资源的消费,提高程序的执行效率。 了解更多JAVA入门知识欢迎访问中软国际教育集团技术知识库!

更多>
JAVA入门学习:网站的URL重写

JAVA入门学习:网站的URL重写

2017-01-23

Java UrlRewrite 的使用实例  URL重写  现在大部分的网站和商城都会使用到URL重写,接触到这个,也是因为正在做的电子商务商城。URL重写,是将原有的URL采用另一种规则来显示,使得用户方便访问同时也屏蔽一些信息。  在此说下它的好处,在开发过程中,经常会遇到一些带了一大堆参数的URL,这样子,一方面显得烦乱,另一方面,一些信息直接显示在URL上,会有些安全性问题。使用URL重写,可以使带有参数的URL以一种较规则的方式体现,如:  /demoAction?id=1            ==>            /demo1.html  它也将本该在URL上显示出来的传参给隐蔽起来,隐藏了技术实现和敏感信息。另外,URL重写,也有利于搜索引擎的访问。  最近项目接触到的URL重写采用的是UrlRewrite,它主要是采用Filter技术在用户请求的时候对访问的URL进行处理,来实现重写的作用。  以下是UrlRewrite的使用实例(个人认为,UrlRewrite的官方文档写的还是比较全面易懂的)  UrlRewrite的导入:  UrlRewrite的导入非常简单,首先需在项目的lib文件夹中加入urlrewrite-3.2.0.jar包,然后,在web.xml中声明Filter  ? 1  2UrlRewriteFilter3org.tuckey.web.filters.urlrewrite.UrlRewriteFilter456UrlRewriteFilter7/*8REQUEST9FORWARD10   声明完filter后,需要在WEB-INF目录下新建一个urlrewrite.xml文件  ? 12345  1 2  56      7      8   该文件是UrlRewrite的规则制定文件,后续主要通过配置它来进行URL的重写。  至此,UrlRewrite的导入就完成了  UrlRewrite 导入成功后,接下来主要通过在urlrewrite.xml添加规则,就能实现URL的重写了。在此列举一些常用的规则。  ? 1  12^/demo/(w+).html$3/Struts/$14   rule 是urlrewrite下的子节点,是urlrewrite的主要规则节点,在它里面包含from 和to两个子节点,from表示请求的URL,to表示将转到的真实的URL。关于from,UrlRewrite有两种匹配的模式,一种是正则表达式匹配,一种的通配符匹配,如上就是正则表达式匹配。当进行匹配的时候,匹配部分的正则可以被提取为参数进行传递  如上规则设置,当客户端访问的网址是http://127.0.0.1:8080/Struts/demo/hello.html 的时候,因为匹配部分是hello,所以它跳转到的是http://127.0.0.1:8080/Struts/hello 上。当网址规则中有多个正则的时候,匹配的参数也会随之增加。如:  ? 1  12^/demo1/(w+)/(w+).html$3/Struts/$1.action?age=$24   rule 的默认匹配方式是正则表达式,但是,有时候也可以以通配符的形式进行匹配。在编写规则的时候,只需要在rule添加一个match-type="wildcard" 的属性即可。  ? 1  12/demo2/*/*3/Struts/$1.action?age=$24   关于to节点,UrlRewrite提供了多种网址跳转方式,如forward和redirect,这两种方式,和大部分MVC框架提供的功能一样,在此不再赘述。  除了支持指定规则的跳转外,UrlRewrite还支持当匹配规则的时候执行某个对象的某个函数  ? 1  12^/demo3/(w+)/(w+).html$34/Struts/$1.action?age=$25   如上述设置,要实现匹配规则是执行某个函数,需要添加多一个run节点,在节点上面添加对应的类属性和方法属性。同时,对应的类必须继承RewriteRule类,执行的方法必须传入两个参数,分别是HttpServletRequest 和HttpServletResponse  ? 12345678910  1 public class Demo extends RewriteRule{  2   3     public void log(HttpServletRequest request,HttpServletResponse response){  4         System.out.println("haha1");  5     }  6       7     public void log2(HttpServletRequest request,HttpServletResponse response){  8         System.out.println("haha2");  9     } 10 }   这样,当客户端输入的网址第一次匹配到指定规则的时候,UrlRewrite就会执行对应的函数,该函数只在第一次匹配成功的时候执行。  如果想要每次匹配规则都执行某函数,可以在urlrewrite添加class-rule子节点,该节点设置后,每次匹配规则后,指定的函数都会执行一次。  ? 1  1   除了对请求的URL进行处理外,UrlRewrite还提供了对返回页面中的地址进行重写的功能。使用rule是对用户输入的url进行处理,但是开发过程中,经常需要在页面中也添加一些网址请求,UrlRewrite可以通过规则,对页面中的网址也进行重写。如:  ? 1  12/(w+).action?id=(w+)$3/$1.html4   在UrlRewrite中添加该规则后,我们在页面中原本的地址是  可是在页面中显示却成了如下:  这样可以隐藏了许多开发中的技术,较为安全。  以上,就是UrlRewrite的一些常见的用法。关于UrlRewrite,网上也有人说这个会影响性能,因为在每次请求的时候都需要经过换一次过滤,但是这个还是要见仁见智,毕竟,使用URL重写,对网址还是有好处的。 了解更多JAVA入门学习、PHP入门学习等知识欢迎来中软国际教育集团技术知识库!

更多>
JAVA入门学习:Java绘图机制

JAVA入门学习:Java绘图机制

2017-01-22

      JAVA的绘图功能非常丰富,绘图包括字体、颜色、图形,以下我们将把这部分JAVA入门学习知识分技术专题来讲。 一、关于JAVA的绘图机制。 JAVA中的任何一个图形组件,小到文本框、标签,大到一个FRAME,一个DIALOG,都有一个专门负责显示其界面的函数,这个函数名称是固定的:paint,它的原型为: public void paint(Graphics g) { …… } 每当组件大小、位置、组件内容发生变化时,该函数即负责生成新的图形界面显示。由于该函数可以被子类继承,因此,继承的子类有能力修改该函数。如果子类中没有出现该函数,则表示其行为完全继承自父类。则不管是组件中是否添加了新的内容,是否发生了大小的改变,是否发生了位移,父类都要有一个专门的线程,来负责描绘变化以后的组件界面。 paint函数由父类自动维护,并且如果子类一旦重载该函数,必须自己去维护所有的界面显示。 二、设置画笔颜色 1、颜色常识 任何颜色都是三原色组成(RGB),JAVA中支持224位彩色,即红绿蓝色分量可取值介于0..255之间。下面首先学习一个JAVA中的类Color Color中的常量: public final static Color black=new Color(0,0,0); public final static Color blue=new Color(0,0,255); ….. Color的构造函数: public Color(int r,int g,int b); 使用举例:如果想构造一个灰色对象,则用下面的句子: Color gray=new Color(205,205,205); 2、设置画笔颜色语法 g.setColor(color); //color是一个Color对象 每修改一次颜色它影响的就是下面所有的绘图语句,一直影响到再次碰到setColor函数才以新的颜色代替。 3、使用JColorChooser组件选择颜色 JAVA中有一个已经定义好的选色器,通过简单的语法我们就可以将该窗口调出来,从其中选择自己喜欢的颜色。下面的这个例子就是通过颜色选取器选取颜色,并将选择到的颜色做为窗体的背景色。 (1)JColorChooser简介 JColorChooser组件的showDialog()方法让用户从弹出的窗口中选择一个颜色,并传给Color对象。其调用语法如下: color=JColorChooser.showDialog(this,”选色”,color); 第一个参数指定调用选色器的父窗体,第二个参数指定选色器窗口标题,最后一个为接收颜色的颜色对象。 4、如何将一个图形(以文件存在,如JPG或者GIF)画到窗体的画布中 其实放置图形到画板中实际就是调用了画板的drawImage函数。其大致思路如下: 首先获取一个ImageIcon对象,这个对象将会从指定的文件中读取相关图象信息,它支持GIF和JPG、BMP等基本图象格式。语法如下: ImageIcon icon=new ImageIcon(GraExp5.class.getResource("1.gif")); 获取到图象的图标以后,就可以从图标中获取到绘制到画板上的实际需要的图象: Image img=icon.getImage(); 有了这个图象对象,我们就可以用画板的drawImage函数画图了。 g.drawImage(img,0,0,null); 中间两个参数是图象绘制时在画板的起始点坐标。 例如: import java.awt.*; import java.awt.event.*; import javax.swing.*; public class GraExp5 extends JFrame { ImageIcon icon; Image img; public GraExp5() { icon=new ImageIcon(GraExp5.class.getResource("1.gif")); img=icon.getImage(); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); setSize(new Dimension(400,300)); show(); } public void paint(Graphics g) { g.drawImage(img,0,0,null); } public static void main(String[] args) { GraExp5 ge=new GraExp5(); } } 程序分析: 需要注意的是,图象文件所在的位置应该和该类放在同一个目录中,这样不至于出错。 6、系统扩展,综合应用,如何为一个窗体设置背景图片。 要为一个窗体添加背景图片,必须知道绘制JComponent组件的过程。Swing轻量组件的绘制是组件和组件UI代表合作的结果。 JComponent.paint先绘制组件,然后绘制组件的边框,再绘制组件的子组件。调用的顺序确保组件、边框和子组件都是可视的。如果组件有一个UI代表,则JComponent.paintComponent调用该代表的Update方法,该方法为不透明组件擦除背景,然后绘制组件。 CInstead是一个不透明的组件,如果重载paint方法,其背景图是无法被擦除的,因此,即使更新了组件的所有包含组件,在界面上是看不到的。所以必须重载paintComponent方法,在绘制子组件前先擦除背景。对双缓存组件,paint方法负责把组件绘制到屏外缓存中,然后把屏外缓存拷贝到组件的屏上代表中,正因为如此,我们不建议为Swing组件重载paint,如果需要重新定义如何绘制组件,那么就重载paintComponent()。 7、用可获取的字体、样式、字号修饰文字 (1)函数说明: 字形类Font用于规范组件所使用的字形大小、样式和字体等。其构造函数: public Font(String name,int style,int size); name表示本地可获取字体名称 style表示字体样式,包含Font.PLAIN,Font.BOLD,Font.ITALIC三种,分别对应平体、加粗和斜体。 一个有用的方法用来获取本地可用字体 GraphicsEnvironment ge=GraphicsEnvironment.getLocalGraphicsEnvironment(); String[] fa=ge.getAvailableFontFamilyNames(); 通过从绘图环境中获取到本地可用的字体名数组。 了解更多java入门学习知识欢迎访问中软国际教育集团技术知识库!

更多>
IOS开发入门:超全!iOS 面试题汇总

IOS开发入门:超全!iOS 面试题汇总

2017-01-20

之前看了很多面试题,感觉要不是不够就是过于冗余,于是我将网上的一些面试题进行了删减和重排,现在分享给大家。(题目来源于网络,侵删) 1. Object-c的类可以多重继承么?可以实现多个接口么?Category是什么?重写一个类的方式用继承好还是分类好?为什么?   答: Object-c的类不可以多重继承;可以实现多个接口,通过实现多个接口可以完成C++的多重继承;Category是类别,一般情况用分类好,用Category去重写类的方法,仅对本Category有效,不会影响到其他类与原有类的关系。   2. #import 跟#include 又什么区别,@class呢, #import<> 跟 #import””又什么区别?   答:#import是Objective-C导入头文件的关键字,#include是C/C++导入头文件的关键字,使用#import头文件会自动只导入一次,不会重复导入,相当于#include和#pragma once;@class告诉编译器某个类的声明,当执行时,才去查看类的实现文件,可以解决头文件的相互包含;#import<>用来包含系统的头文件,#import””用来包含用户头文件。   3. 属性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作用,在那种情况下用?   答: 1). readwrite 是可读可写特性;需要生成getter方法和setter方法时 2). readonly 是只读特性 只会生成getter方法不会生成setter方法 ;不希望属性在类外改变 3). assign 是赋值特性,setter方法将传入参数赋值给实例变量;仅设置变量时; 4). retain 表示持有特性,setter方法将传入参数先保留,再赋值,传入参数的retaincount会+1; 5). copy 表示赋值特性,setter方法将传入对象复制一份;需要完全一份新的变量时。 6).nonatomic 非原子操作,决定编译器生成的settergetter是否是原子操作,atomic表示多线程安全,一般使用nonatomic   4.写一个setter方法用于完成@property (nonatomic,retain)NSString *name,写一个setter方法用于完成@property(nonatomic,copy)NSString *name   答: - (void)setName:(NSString*) str { [str retain]; [name release]; name = str; } -(void)setName:(NSString *)str { id t = [str copy]; [name release]; name = t; }   5.对于语句NSString*obj= [[NSData alloc] init]; obj在编译时和运行时分别时什么类型的对象?   答: 编译时是NSString的类型;运行时是NSData类型的对象   6.常见的object-c的数据类型有那些,和C的基本数据类型有什么区别?如:NSInteger和int   答:object-c的数据类型有NSString,NSNumber,NSArray,NSMutableArray,NSData等等,这些都是class,创建后便是对象,而C语言的基本数据类型int,只是一定字节的内存空间,用于存放数值;NSInteger是基本数据类型,并不是NSNumber的子类,当然也不是NSObject的子类。NSInteger是基本数据类型Int或者Long的别名(NSInteger的定义typedef long NSInteger),它的区别在于,NSInteger会根据系统是32位还是64位来决定是本身是int还是Long。   7.id 声明的对象有什么特性?   答:Id 声明的对象具有运行时的特性,即可以指向任意类型的objcetive-c的对象;   8.Objective-C如何对内存管理的,说说你的看法和解决方法?   答: Objective-C的内存管理主要有三种方式ARC(自动内存计数)、手动内存计数、内存池。 1). (Garbage Collection)自动内存计数:这种方式和java类似,在你的程序的执行过程中。始终有一个高人在背后准确地帮你收拾垃圾,你不用考虑它什么时候开始工作,怎样工作。你只需要明白,我申请了一段内存空间,当我不再使用从而这段内存成为垃圾的时候,我就彻底的把它忘记掉,反正那个高人会帮我收拾垃圾。遗憾的是,那个高人需要消耗一定的资源,在携带设备里面,资源是紧俏商品所以iPhone不支持这个功能。所以“Garbage Collection”不是本入门指南的范围,对“Garbage Collection”内部机制感兴趣的同学可以参考一些其他的资料,不过说老实话“Garbage Collection”不大适合适初学者研究。   解决: 通过alloc –initial方式创建的, 创建后引用计数+1, 此后每retain一次引用计数+1, 那么在程序中做相应次数的release就好了.   2). (Reference Counted)手动内存计数:就是说,从一段内存被申请之后,就存在一个变量用于保存这段内存被使用的次数,我们暂时把它称为计数器,当计数器变为0的时候,那么就是释放这段内存的时候。比如说,当在程序A里面一段内存被成功申请完成之后,那么这个计数器就从0变成1(我们把这个过程叫做alloc),然后程序B也需要使用这个内存,那么计数器就从1变成了2(我们把这个过程叫做retain)。紧接着程序A不再需要这段内存了,那么程序A就把这个计数器减1(我们把这个过程叫做release);程序B也不再需要这段内存的时候,那么也把计数器减1(这个过程还是release)。当系统(也就是Foundation)发现这个计数器变成员了0,那么就会调用内存回收程序把这段内存回收(我们把这个过程叫做dealloc)。顺便提一句,如果没有Foundation,那么维护计数器,释放内存等等工作需要你手工来完成。   解决:一般是由类的静态方法创建的,函数名中不会出现alloc或init字样, 如[NSString string]和[NSArray arrayWithObject:], 创建后引用计数+0, 在函数出栈后释放, 即相当于一个栈上的局部变量. 当然也可以通过retain延长对象的生存期.   3). (NSAutoRealeasePool)内存池:可以通过创建和释放内存池控制内存申请和回收的时机.   解决:是由autorelease加入系统内存池, 内存池是可以嵌套的, 每个内存池都需要有一个创建释放对, 就像main函数中写的一样. 使用也很简单, 比如[[[NSStringalloc]initialWithFormat:@”Hey you!”] autorelease], 即将一个NSString对象加入到最内层的系统内存池, 当我们释放这个内存池时, 其中的对象都会被释放. 9. 原子(atomic)跟非原子(non-atomic)属性有什么区别?   答: 1). atomic提供多线程安全。是防止在写未完成的时候被另外一个线程读取,造成数据错误 2). non-atomic:在自己管理内存的环境中,解析的访问器保留并自动释放返回的值,如果指定了 nonatomic ,那么访问器只是简单地返回这个值。   10. 看下面的程序,第一个NSLog会输出什么?这时str的retainCount是多少?第二个和第三个呢? 为什么?   NSMutableArray* ary= [[NSMutableArray array] retain]; NSString *str =[NSString stringWithFormat:@"test"]; [str retain]; [aryaddObject:str]; NSLog(@”%@%d”,str,[str retainCount]); [str retain]; [str release]; [str release]; NSLog(@”%@%d”,str,[str retainCount]); [aryremoveAllObjects]; NSLog(@”%@%d”,str,[str retainCount]);   str的retainCount创建+1,retain+1,加入数组自动+13   retain+1,release-1,release-1 2   数组删除所有对象,所有数组内的对象自动-1 1   11. 内存管理的几条原则时什么?按照默认法则.那些关键字生成的对象需要手动释放?在和property结合的时候怎样有效的避免内存泄露?   答:谁申请,谁释放 遵循Cocoa Touch的使用原则;   内存管理主要要避免“过早释放”和“内存泄漏”,对于“过早释放”需要注意@property设置特性时,一定要用对特性关键字,对于“内存泄漏”,一定要申请了要负责释放,要细心。   关键字alloc 或new 生成的对象需要手动释放;   设置正确的property属性,对于retain需要在合适的地方释放,   12.如何对iOS设备进行性能测试?   答: Profile-> Instruments ->TimeProfiler   13. Object C中创建线程的方法是什么?如果在主线程中执行代码,方法是什么?如果想延时执行代码、方法又是什么?   答:线程创建有三种方法:使用NSThread创建、使用GCD的dispatch、使用子类化的NSOperation,然后将其加入NSOperationQueue;在主线程执行代码,方法是performSelectorOnMainThread,如果想延时执行代码可以用performSelector:onThread:withObject:waitUntilDone:   14. MVC设计模式是什么? 你还熟悉什么设计模式?   答: 设计模式:并不是一种新技术,而是一种编码经验,使用比如java中的接口,iphone中的协议,继承关系等基本手段,用比较成熟的逻辑去处理某一种类型的事情,总结为所谓设计模式。面向对象编程中,java已经归纳了23种设计模式。   mvc设计模式 :模型,视图,控制器,可以将整个应用程序在思想上分成三大块,对应是的数据的存储或处理,前台的显示,业务逻辑的控制。 Iphone本身的设计思想就是遵循mvc设计模式。其不属于23种设计模式范畴。   代理模式:代理模式给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用.比如一个工厂生产了产品,并不想直接卖给用户,而是搞了很多代理商,用户可以直接找代理商买东西,代理商从工厂进货.常见的如QQ的自动回复就属于代理拦截,代理模式在iphone中得到广泛应用.   单例模式:说白了就是一个类不通过alloc方式创建对象,而是用一个静态方法返回这个类的对象。系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为,比如想获得[UIApplication sharedApplication];任何地方调用都可以得到 UIApplication的对象,这个对象是全局唯一的。   观察者模式: 当一个物体发生变化时,会通知所有观察这个物体的观察者让其做出反应。实现起来无非就是把所有观察者的对象给这个物体,当这个物体的发生改变,就会调用遍历所有观察者的对象调用观察者的方法从而达到通知观察者的目的。   工厂模式: public classFactory{ public staticSample creator(int which){ if (which==1) return new SampleA(); else if (which==2) return new SampleB(); } }   15 浅复制和深复制的区别?   答: 浅层复制:只复制指向对象的指针,而不复制引用对象本身。 深层复制:复制引用对象本身。          意思就是说我有个A对象,复制一份后得到A_copy对象后,对于浅复制来说,A和A_copy指向的是同一个内存资源,复制的只不过是是一个指针,对象本身资源还是只有一份,那如果我们对A_copy执行了修改操作,那么发现A引用的对象同样被修改,这其实违背了我们复制拷贝的一个思想。深复制就好理解了,内存中存在了两份独立对象本身。   用网上一哥们通俗的话将就是:   浅复制好比你和你的影子,你完蛋,你的影子也完蛋   深复制好比你和你的克隆人,你完蛋,你的克隆人还活着。 16. 类别的作用?继承和类别在实现中有何区别?   答:category 可以在不获悉,不改变原来代码的情况下往里面添加新的方法,只能添加,不能删除修改,并且如果类别和原来类中的方法产生名称冲突,则类别将覆盖原来的方法,因为类别具有更高的优先级。   类别主要有3个作用: 1).将类的实现分散到多个不同文件或多个不同框架中。 2).创建对私有方法的前向引用。 3).向对象添加非正式协议。 继承可以增加,修改或者删除方法,并且可以增加属性。   17. 类别和类扩展的区别。   答:category和extensions的不同在于后者可以添加属性。另外后者添加的方法是必须要实现的。   extensions可以认为是一个私有的Category。   18. oc中的协议和java中的接口概念有何不同?   答:OC中的代理有2层含义,官方定义为 formal和informal protocol。前者和Java接口一样。   informal protocol中的方法属于设计模式考虑范畴,不是必须实现的,但是如果有实现,就会改变类的属性。   其实关于正式协议,类别和非正式协议我很早前学习的时候大致看过,也写在了学习教程里   “非正式协议概念其实就是类别的另一种表达方式“这里有一些你可能希望实现的方法,你可以使用他们更好的完成工作”。   这个意思是,这些是可选的。比如我门要一个更好的方法,我们就会申明一个这样的类别去实现。然后你在后期可以直接使用这些更好的方法。   这么看,总觉得类别这玩意儿有点像协议的可选协议。”   现在来看,其实protocal已经开始对两者都统一和规范起来操作,因为资料中说“非正式协议使用interface修饰“, 现在我们看到协议中两个修饰词:“必须实现(@requied)”和“可选实现(@optional)”。   19. 什么是KVO和KVC?   答:KVC:键 – 值编码是一种间接访问对象的属性使用字符串来标识属性,而不是通过调用存取方法,直接或通过实例变量访问的机制。   很多情况下可以简化程序代码。apple文档其实给了一个很好的例子。   KVO:键值观察机制,他提供了观察某一属性变化的方法,极大的简化了代码。   具体用看到嗯哼用到过的一个地方是对于按钮点击变化状态的的监控。   比如我自定义的一个button   [selfaddObserver:self forKeyPath:@"highlighted" options:0context:nil]; #pragma mark KVO -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)objectchange:(NSDictionary *)change context:(void *)context

更多>
Android开发入门应用系列:值得收藏的ViewHolder工具类实现

Android开发入门应用系列:值得收藏的ViewHolder工具类实现

2017-01-19

前言        在开发APP的过程中,攻城狮少不了要跟ListView、GridView这些组件眉来眼去,暗送几波秋波。自然原生态美人BaseAdapter更是程序员的最爱,有了它,我们想怎么干就能怎么干,嘿嘿,你懂的哈哈~        但是,每次写一个BaseAdapter,我们都很自觉的给他写一个ViewHolder,一两个还好,万一应用程序中有数不清的ListView,呵呵~你妹!千篇一律,看得都审美疲劳。作为最伟大的第二十二世纪的程序员们,脱掉、搞上永远是我们最真挚的追求,所以我们要怎么将ViewHolder从BaseAdapter中脱掉呢?绝非不是不用,而是要将其搞成一个华丽丽的工具类实现,收入角落那个寂寞得tools类中。 ViewHolder的实现        我觉得应该简略的介绍下ViewHolder的实现,谷歌很聪明的在Adapter中运用了复用View的思想,自然让我们的屌丝机也能泡上一些白富美应用多了一点点可能。ViewHolder的具体实现基本体现在BaseAdapter的 getView(int position, View convertView, ViewGroup parent) 这个方法里面,参见下面的代码: 1. @Override  2. public View getView(int position, View convertView, ViewGroup parent) {  3.     ViewHolder holder;  4.     if (convertView == null) {  5.         convertView = inflater.inflate(R.layout.listview_item_layout, parent, false);  6.         holder = new ViewHolder();  7.         holder.studentName = (TextView) convertView.findViewById(R.id.student_name);  8.         holder.studentAge = (TextView) convertView.findViewById(R.id.student_age);  9.         convertView.setTag(holder);  10.     }  11.     else {  12.         holder = (ViewHolder) convertView.getTag();  13.     }  14.     Student data = (Student) getItem(position);  15.     holder.studentName.setText(data.getName());  16.     holder.studentAge.setText(data.getAge());  17.     return convertView;  18. }  19.   20. class ViewHolder {  21.     public TextView studentName;  22.     public TextView studentAge;  23. }          很明显,大家不要问我ViewHolder在哪里,稍微把目光往上扶一扶就看到那个大大的 class ViewHolder 。这里的ViewHolder用法主要有两个地方,一是 convertView 的复用,二是 ViewHolder 也就是 convertView 里面的索引的复用。具体的用法不熟悉的话可以百度一下,再往下说就对不起我今天这篇博文了,因为在这里写这个代码的目的,肯定不是介绍你怎么用ViewHolder,只是想告诉你:传统的ViewHolder的写法,是多么的臃肿!而且对于每一个新的BaseAdapter,你都得无聊的实现一次又一次,OH~ ViewHolder的工具类实现        自然,脱光要从小,行动要趁早。既然我们烦了,就把它写成一个工具类咯。参见下面的代码 1. static class ViewHolder {  2.     public static  T get(View view, int id) {  3.         SparseArray viewHolder = (SparseArray) view.getTag();  4.         if (viewHolder == null) {  5.             viewHolder = new SparseArray();  6.             view.setTag(viewHolder);  7.         }  8.         View childView = viewHolder.get(id);  9.         if (childView == null) {  10.             childView = view.findViewById(id);  11.             viewHolder.put(id, childView);  12.         }  13.         return (T) childView;  14.     }  15. }         这是工具类的实现,稍微说下实现的原理: 1、ViewHolder既然是依赖View的Tag存放,但是以一个 SparseArray 集合存放。 2、判断View里的Tag是否存在viewHolder,不存在,赶紧叫她生一个。 3、然后在viewholder(也就是SparseArray)寻找View的索引,如果没有,赶紧findViewById一个put进去顺便return出来,如果已经存在,皆大欢喜,直接用呗。        贴个BaseAdapter里面使用的代码: 1. @Override  2. public View getView(int position, View convertView, ViewGroup parent) {  3.     if (convertView == null) {  4.         convertView = inflater.inflate(R.layout.listview_item_layout, parent, false);  5.     }  6.     TextView name = Tools.ViewHolder.get(convertView, R.id.student_name);  7.     TextView age = Tools.ViewHolder.get(convertView, R.id.student_age);  8.       9.     Student data = (Student) getItem(position);  10.     name.setText(data.getName());  11.     age.setText(data.getAge());  12.       13.     return convertView;  14. }          简洁明了,不用多说~~~嘿嘿,后面如果要写ViewHolder,直接Tools工具类调用,省心不废脑。。 分析可行性        既然要作为工具类使用,我们有必要先评估这个工具值不值得我们使用。        一般来说,我们可以从以下几个方面进行评估:易用性? 内存泄露? 性能提升? 健壮性?等等等。。。。。。       易用性:工具类的最大特性就是易用简约,这个ViewHolder的写法就是典型的拿来就用的主义,根本不用我们操心写些适配的代码,直接传入View和id,高内聚松耦合。并且采用了 T的泛型模板的方法,自动与外部的View子类适配,不用我们手动去强制装换。       内存泄露:有些初学者,看到static方法就回固执的认为 SparseArray viewHolder 这个变量会存在内存泄露,但是java告诉我们,这个变量的小命仅仅在方法执行之中,方法完毕,GC回收;存在ViewHolder一如既往放在View的Tag中,一旦View被回收,ViewHolder自然消失。不信,打开DDMS,用你28青年的手速不停刷listView试试,保证对象基本稳定在一个值。       性能提升:在这里我们发现用了 SparseArray 这个集合而不是 HashMap ,我们知道 SparseArray 是Android的一个工具类,是官方推荐用来代替 HashMap 的一个类,它的内部采用了二分查找的实现提高了查找效率,而且不是一点两点的哦,谁用谁知道;具体内容想要了解,可以度娘谷哥或者左转源码。       所以,作为一个工具类,它是完全合格的,赶紧把它拷贝到你的tools、util里面,然后我们就可以开心加愉悦的优雅用起ViewHolder了。 了解更多Android开发入门知识、工具应用、编码规则等等欢迎访问中软国际教育集团技术知识库!

更多>
Android开发入门:Android编码规范与常用技巧

Android开发入门:Android编码规范与常用技巧

2017-01-18

Android编码规则和常用技巧的掌握程度决定了一个Android开发入门程序员的成长效率。下面的内容至少需要花费5分钟时间阅读。 一、Android编码规范 1.java代码中不出现中文,最多注释中可以出现中文 2.局部变量命名、静态成员变量命名 只能包含字母,单词首字母出第一个外,都为大写,其他字母都为小写。 3.常量命名 只能包含字母和_,字母全部大写,单词之间用_隔开。 4.layout中的id命名 命名模式为: view缩写_模块名称_view的逻辑名称 view的缩写详情如下: · LayoutView:lv · RelativeView:rv · TextView:tv · ImageView:iv · ImageButton:im · Button:btn 5.activity中的view变量命名 命名模式为:逻辑名称+view缩写 建议:如果layout文件很复杂,建议将layout分成多个模块,每个模块定义一个moduleViewHolder,其成员变量包含所属view 6.strings.xml中的id命名 命名模式:activity名称_功能模块名称_逻辑名称/activity名称_逻辑名称/common_逻辑名称 strings.xml中,使用activity名称注释,将文件内容区分开来。 7.drawable中的图片命名 命名模式:activity名称_逻辑名称/common_逻辑名称 8.styles.xml:将layout中不断重现的style提炼出通用的style通用组件,放到styles.xml中; 9.使用layer-list和selector 10.图片尽量分拆成多个可重用的图片 11.服务端可以实现的,就不要放在客户端 12.引用第三方库要慎重,避免应用大容量的第三方库,导致客户端包非常大 13.处理应用全局异常和错误,将错误以邮件的形式发送给服务端 14.图片的.9处理 15.使用静态变量方式实现界面间共享要慎重 16.Log(系统名称 模块名称 接口名称,详细描述) 17.单元测试(逻辑测试、界面测试) 18.不要重用父类的handler,对应一个类的handler也不应该让其子类用到,否则会导致message.what冲突 19.activity中在一个View.OnClickListener中处理所有的逻辑 20.strings.xml中使用%1$s实现字符串的通配 21.如果多个Activity中包含共同的UI处理,那么可以提炼一个CommonActivity,把通用部分叫由它来处理,其他activity只要继承它即可 22.使用button+activitgroup实现tab效果时,使用Button.setSelected(true),确保按钮处于选择状态,并使activitygroup的当前activity与该button对应 23.如果所开发的为通用组件,为避免冲突,将drawable/layout/menu/values目录下的文件名增加前缀 24.数据一定要效验,例如字符型转数字型,如果转换失败一定要有缺省值;服务端响应数据是否有效判断; 25.同一个客户端如果要放在不同的市场,而且要统计各个市场下载及使用数据时针对不同的客户端打不同的包,唯一的区别是versionName,apk文件名为versionName.apk。在升级时,要将自己的versionCode和versionName一并传给服务端,如果需要升级,则下载versionName相对应的apk 关于是否要强制升级: · 1).不管何种情况都强制升级 · 2).判断用户的版本和当前最新版本,如果兼容则强制升级,否则可选; 26.有的按钮要避免重复点击 二、Android性能优化 1.http用gzip压缩,设置连接超时时间和响应超时时间   http请求按照业务需求,分为是否可以缓存和不可缓存,那么在无网络的环境中,仍然通过缓存的httpresponse浏览部分数据,实现离线阅读。 2.listview 性能优化 · 1)复用convertView 在getItemView中,判断convertView是否为空,如果不为空,可复用。如果couvertview中的view需要添加listerner,代码一定要在if(convertView==null){}之外。 · 2)异步加载图片 item中如果包含有webimage,那么最好异步加载 · 3)快速滑动时不显示图片     当快速滑动列表时(SCROLL_STATE_FLING),item中的图片或获取需要消耗资源的view,可以不显示出来;而处于其他两种状态(SCROLL_STATE_IDLE 和SCROLL_STATE_TOUCH_SCROLL),则将那些view显示出来 · 4)list中异步加载的图片,当不在可视范围内,按照一定的算法及时回收(如在当前可视范围的上下10条item以外的图片进行回收,或者将图片进行缓存,设置一个大小,按照最近最少使用原则超过部分进行回收) · 5)BaseAdapter避免内存溢出 如果BaseAdapter的实体类有属性非常消耗内存,可以将保存到文件;为提高性能,可以进行缓存,并限制缓存大小。 3.使用线程池,分为核心线程池和普通线程池,下载图片等耗时任务放置在普通线程池,避免耗时任务阻塞线程池后,导致所有异步任务都必须等待 4.异步任务,分为核心任务和普通任务,只有核心任务中出现的系统级错误才会报错,异步任务的ui操作需要判断原activity是否处于激活状态 · 1)主线程不要进行网络处理; · 2)主线程不要进行数据库处理; · 3)主线程不要进行文件处理; 5.尽量避免static成员变量引用资源耗费过多的实例,比如Context 6.使用WeakReference代替强引用,弱引用可以让您保持对对象的引用,同时允许GC在必要时释放对象,回收内存。对于那些创建便宜但耗费大量内存的对象,即希望保持该对象,又要在应用程序需要时使用,同时希望GC必要时回收时,可以考虑使用弱引用。 7.超级大胖子Bitmap 及时的销毁(Activity的onDestroy时将bitmap回收,在被UI组件使用后马上进行回收会抛RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap) 设置一定的采样率(有开发者提供的图片无需进行采样,对于有用户上传或第三方的大小不可控图片,可进行采样减少图片所占的内存),从服务端返回图片,建议同时反馈图片的size 巧妙的运用软引用 drawable对应resid的资源,bitmap对应其他资源 任何类型的图片,如果获取不到(例如文件不存在,或者读取文件时跑OutOfMemory异常),应该有对应的默认图片(默认图片放在在apk中,通过resid获取); 8.保证Cursor 占用的内存被及时的释放掉,而不是等待GC来处理。并且 Android明显是倾向于编 程者手动的将Cursor close掉 9.线程也是造成内存泄露的一个重要的源头。线程产生内存泄露的主要原因在于线程生命周期的不可控 10.如果ImageView的图片是来自网络,进行异步加载 11.应用开发中自定义View的时候,交互部分,千万不要写成线程不断刷新界面显示,而是根据TouchListener事件主动触发界面的更新 12.Drawable ui组件需要用到的图片是apk包自带的,那么一律用setImageResource或者setBackgroundResource,而不要根据resourceid 注意:get(getResources(), R.drawable.btn_achievement_normal)该方法通过resid转换为drawable,需要考虑回收的问题,如果drawable是对象私有对象,在对象销毁前是肯定不会释放内存的。 13.复用、回收Activity对象 临时的activity及时finish · 主界面设置为singleTask · 一般界面设置为singleTop 14.位置信息 获取用户的地理位置信息时,在需要获取数据的时候打开GPS,之后及时关闭掉 15.在onResume时设置该界面的电源管理,在onPause时取消设置 三、AndroidUI优化 1.layout组件化,尽量使用merge及include复用 2.使用styles,复用样式定义 3.软键盘的弹出控制,不要让其覆盖输入框 4.数字、字母和汉字混排占位问题:将数字和字母全角化。由于现在大多数情况下我们的输入都是半角,所以 字母和数字的占位无法确定,但是一旦全角化之后,数字、字母的占位就和一个汉字的占位相同了,这样就可以避免由于占位导致的排版问题。 5.英文文档排版:textview自动换行时要保持单词的完整性,解决方案是计算字符串长度,然后手动设定每一行显示多少个字母并加上‘ ‘ 6.复杂布局使用RelativeLayout 7.自适应屏幕,使用dp替代pix 8.使用android:layout_weight或者TableLayout制作等分布局 9.使用animation-list制作动画效果

更多>

推荐阅读

更多

中软卓越java培训地址:北京市海淀区科学院南路2号融科资讯中心C座北楼12层 联系电话:400-666-3775 邮箱账号:etc-marketing@chinasofti.com

©2008-2016 北京中软国际教育科技股份有限公司 京ICP备14058756号-2