• 关于 带包的类编译和运行 的搜索结果

回答

Eclipse自身使用ecj来编译java代码,而不是JDK的java编译器,是为了便于Eclipse对代码解析过程进行处理并且不必须要求JDK(Eclipse通过ecj可在只具有JRE的环境上对代码进行编译运行) 但ecj编译器仍然需要有JRE(不一定是JDK,JRE即可,除非需要JDK提供的Tools开发包)提供相应版本的Java类库。Eclipse自身不带JDK(MyEclipse等商业版本除外,这一类带的JDK版本自查发行网站)。 另外,由于Eclipose本身也是使用Java进行开发的,所以Eclipse的运行需要机器有JRE环境。 引用来自“逝水fox”的评论 Eclipse自身使用ecj来编译java代码,而不是JDK的java编译器,是为了便于Eclipse对代码解析过程进行处理并且不必须要求JDK(Eclipse通过ecj可在只具有JRE的环境上对代码进行编译运行) 但ecj编译器仍然需要有JRE(不一定是JDK,JRE即可,除非需要JDK提供的Tools开发包)提供相应版本的Java类库。Eclipse自身不带JDK(MyEclipse等商业版本除外,这一类带的JDK版本自查发行网站)。 另外,由于Eclipose本身也是使用Java进行开发的,所以Eclipse的运行需要机器有JRE环境。 JDK:JavaDevelopmentToolKit(Java 开发工具包 ) 。 JDK 是整个 JAVA 的核心,包括了 Java 运行环境( JavaRuntimeEnvirnment ),一堆 Java 工具( javac/java/jdb 等)和 Java 基础的类库(即 JavaAPI  包括 rt.jar)。 JRE:Java    Runtime    Enviromental(java 运行时环境 )。 也就是我们说的 JAVA 平台,所有的 Java 程序都要在 JRE 下才能运行。包括 JVM 和 JAVA 核心类库和支持文件。与JDK相比,它不包含开发工具——编译器、调试器和其它工具。 JVM:JavaVirtualMechinal(JAVA 虚拟机 ) 。JVM是 JRE 的一部分,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 JVM 有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。 JVM  的主要工作是解释自己的指令集(即字节码)并映射到本地的  CPU  的指令集或  OS  的系统调用。Java语言是跨平台运行的,其实就是 不同的操作系统,使用不同的 JVM 映射规则,让其与操作系统无关,完成了跨平台性 。 JVM  对上层的  Java  源文件是不关心的,它关注的只是由源文件生成的类文件(  classfile )。

爱吃鱼的程序员 2020-06-09 11:09:21 0 浏览量 回答数 0

回答

1、静态AOP:在编译期,切面直接以字节 码的形式编译到目标字节 码文件中。 AspectJ属于静态AOP,是在编译时进行增强,会在编译的时候将AOP逻辑织入到代码中,需要专有的编译器和织入器。 优点:被织入的类性能不受影响。 缺点:不够灵活 2、动态AOP(JDK动态代理):在运行期,目标类加载后,为接口动态生成代理类,将切面植入到代理类中。 Java从1.3引入动态代理。实现原理是为被代理的业务接口生成代理类,将AOP逻辑写入到代理类中,在运行时动态织入AOP,使用反射执行织入的逻辑。 主要实现方式依赖java.lang.reflect包下的InvocationHandler和Proxy类。 优点:Java标准库原生支持,使用简单,无需引用额外的包。相对于静态AOP更灵活。 缺点:带代理的类必须是接口,灵活性受到一些限制;使用反射会影响一些性能。 3、动态代码字节生成:在运行期,目标类加载后,动态构建字节码文件生成目标类的子类,将切面逻辑加入到子类中。 CGLib是动态代码字节生成的实现,它封装字节码生成工具Asm,原理是在运行期间目标字节码加载后,生成目标类的子类,将切面逻辑加入到子类中,所以使用Cglib实现AOP不需要基于接口。 优点:没有接口也可以织入,灵活性高。 缺点:扩展类的实例方法为final时,则无法进行织入 4、自定义类加载器:在运行前,目标加载前,将切面逻辑加到目标字节码中。 可以考虑javassist来实现。Javassist 是一个编辑字节码的框架,可以让你很简单地操作字节码。它可以在运行期定义或修改Class。使用Javassist实现AOP的原理是在字节码加载前直接修改需要切入的方法。 优点:可以对绝大部分类织入。 缺点:如果用到了其他类加载器,则这些类将不被织入

jianxia 2019-12-02 03:08:17 0 浏览量 回答数 0

回答

如果说有好多个类不在同一个目录下, 布局编译情况如何? 比如有两个类要用到:B.java和C.java,以下布局可做参考. 先在A.java所在的目录下,分别建立两个子目录BB和CC。将B.java放到BB下。将C.java放到CC下。将cmd置于A.java所在的目录下,用 javacA.java 产生A.class再以 javaA  运行。 输出: callingthemethod'abc()'oftheclassBcallingthemethod'abc()'oftheclassC importBB.*;importCC.*;publicclassA{publicstaticvoidmain(Stringargs[]){newB().abc();newC().abc();}}packageBB;publicclassB{publicvoidabc(){System.out.println("callingthemethod'abc()'oftheclassB");}}packageCC;publicclassC{publicvoidabc(){System.out.println("callingthemethod'abc()'oftheclassC");}} 新手小朋友呀?   我们要让他感受到社区的爱,大家快来呀,这里有个萌新 估计,编译器找不到b类的定义。所以,要检查一下: b类的定义是否写在a.java的文档里:classb{...}若没有写在同一个文档里,再检查一下,在这同一个文件夹内,是否有一个文档名叫:"b.java",那里写着b类的定义:publicclassb{...}   补充什么?你自己不是都说了吗?那如果说我好多个类但是不在一个目录下,我该怎么编译?都放到一个目录下么 大量稳定供应国内个人终端代理IP,可对公签合同,价格含税。   寻合作对象:大数据爬虫、自媒体补量、广告联盟。Q3500891807 1、使用IDE进行编译(ide会自动查找不同目录中的源码依赖) 2、使用ant/maven编译,可以指定源码目录,编译脚本会自动递归查找的 3、如果一定要使用javac命令,可以按照如下步骤做:   a、dir/B/S/Xsrc\*.java>filelist.txt     将所有的源码文件生成文件清单存储到filelist.txt中(src是源码的根目录)   b、执行编译命令javac-cp依赖的jar和class -dclass文件输出目录 -g......@filelist.txt   注意最后的@filelist.txt,表示同时编译filelist.txt中的全部源码 最后就可以到输出目录中找到class文件了 PS:你可以按照我上面说的最后一个重新编译jdk源码,因为jdk源码默认是不带-g参数的,所以源码很多时候调试会很不方便,比如方法参数都是arg0、arg1这种,还有就是没有局部变量等。。。。 这种情况下就是不在同一个文件夹下,可以使用包名来标明文件夹的路径

爱吃鱼的程序员 2020-06-08 11:00:23 0 浏览量 回答数 0

爆款特惠

精选爆款产品低至0.95折

回答

从Java 8迁移到Java 11比大多数升级更棘手。以下是这个过程的一些注意事项。模块在Java 9中Java引入了历史上最大的变化之一 是模块,但:不必将你自己的代码模块化以后才能升级到Java 11。在大多数情况下,放在类路径classpath上的代码能继续在Java 9及更高版本上有效被发现和运行,但是如果将模块放置类路径上会被忽略,这对于库包发布者来说非常糟糕,但对于应用程序开发者是个好事情。因此,在升级到Java 11时尽可能地先不用模块化,而将自己的应用程序转换为Java模块应该等待时机,等待大规模开源的依赖库包真正采用模块化后的几年内才开始实施模块化,现在,尝试模块化很痛苦,因为你的依赖包很少是模块化的。(如果将程序模块化的主要原因是由于使用jlink能缩小JDK的大小,也完全不需要模块化来实现这个目标 – 只需使用Maven创建一个 jar- with-dependencies,其中module-info不配置require,不配置export( no-requires和no-exports )。删除了JDK的部分内容JDK的有关Java EE和Corba的一部分被删除,它们不再适合JDK,或者可以在其他地方维护。如果您使用Corba,那么几乎没有人可以帮助你,但是,如果你使用Java EE模块,那么在大多数情况下,对已删除代码的修复应该很简单。只需添加适当的Maven即可。在Java客户端方面,已经删除了Java WebStart ,替代方案会更加棘手,请考虑使用Getdown或Update4J。不安全和朋友多年来, Sun和Oracle一直在告诉开发人员不要使用sun.misc.Unsafe和其他尖端的JDK API。很长一段时间,Java 9将要删除这些,但这实际上从未发生过。但是在Java 11,首次访问受限API时,你可能会收到警告,此警告仅打印一次。这是一个有用的提醒,你的代码或依赖正在做一些“顽皮”的事情,需要在某个时候修复。您还会发现Java 11有许多专门设计的新API,以避免使用Unsafe人需要,如果你使用的是“非法”API,请优先调查这些新API,例如, Base64, MethodHandles.privateLookupIn, MethodHandles.Lookup.defineClass, StackWalker 和Variable Handles。工具和图书馆模块化和新的六个月发布周期这两个机制共同对工具和库开发人员使用产生了真正的影响,一些项目已经能够跟上,有些人在努力,有些人失败了。升级到Java 11时,关键任务是将所有依赖项更新为最新版本,如果自Java 9问世以来这些依赖项还没有发布新版本,那么这些依赖可能需要额外的关注或测试,确保您也更新了IDE。但是,不仅需要更新应用程序的依赖项,Maven也是如此,大多数Maven插件已将主要版本更改为v3.x,将Maven本身升级到v3.5.4也是有益的。可悲的是,核心maven团队规模很小,因此仍有一些问题需要解决,但是,如果你的Maven构建非常合理且简单,那么通常应该没问题。但请注意,将插件从v2.x升级到v3.x可能需要更改配置,而不仅仅是与模块相关联。例如,Maven Javadoc插件已重命名该argLine属性。需要注意的一个关键点是Maven使用模块进行操作的方式,当Maven编译器或surefire插件找到一个模块化的jar文件(即带有module-info.class)时,它可以将该jar放在模块路径而不是类路径上,因此,即使你可能打算只在类路径上运行你的应用程序,Maven可能部分地在类路径上编译和测试代码,而另外一部分会在模块路径上编译代码,在目前,没有什么可以搞定这个问题。有时你的构建需要更大的更改。例如,需要将Findbugs更改为SpotBugs,并将Cobertura改为JaCoCo。这些构建更改可能需要一些时间 。总结当我完成迁移之后,我的结论是痛苦主要在于维护与Java 8的兼容性,将应用程序全部只到Java 11应该更简单,因为不需要与Java 8保持联系。

hiekay 2019-12-02 01:39:22 0 浏览量 回答数 0

回答

<p>楼主所示的JAVA代码没错。用 <img height="189" src="https://oscimg.oschina.net/oscnet/ac2d557124095ac505fbef0174a5719e923.jpg" width="843">编译、运行都在掌控之中,不会报错。</p> <p>default方法是Java8提供的新特性,如果你的Eclipse使用的jdk低于8,或者配置工程Java语法检查低于javase-1.8,那么可能会出现这个错误,一个Java Compile配置界面如下图。</p> default和public不能同时修饰 java8接口写只能用default <p>含有抽象方法的类,必定是冠以关键字 abstract 的抽象类。极端情况,如果在一个类的定义中,包含的全部是抽象方法,那就只有是接口 interface。换言之,接口就是抽象类的极端情况。但是,这种说法,仅在 jdk1.8之前,成立。<br> jdk 1.8 对接口又有了新规定:可以包括 冠以 关键词 default 的 缺省/默认方法。换言之,jdk 1.8 允许 给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法。</p> 楼主的接口 interface interfaceA 里含有 缺省/默认 default 的带方法体的方法 otherprint(),编译报错。那楼主一定用的是 jdk1.8 之前的版本来编译的。 比如下列代码,如果用jdk1.8以前的版本编译,就通不过。我用jdk1.8,就会成功通过编译,并顺利运行。 interface A { default void print(){ System.out.println("顺应天意"); } void print1(); } public class T implements A { public void print1(){ System.out.println("了却凡尘 "); } public static void main(String[] args) { T t = new T(); t.print(); t.print1(); } }   输出: D:\java\test\OS_China>javac T.java D:\java\test\OS_China>java T 顺应天意 了却凡尘 D:\java\test\OS_China>java -version java version "1.8.0_162" Java(TM) SE Runtime Environment (build 1.8.0_162-b12) Java HotSpot(TM) 64-Bit Server VM (build 25.162-b12, mixed mode) D:\java\test\OS_China>   <p>jdk环境问题,检查eclipse的编译环境,工程jdk版本,或者用maven的话pom里的编译插件等等;代码在jdk8+是没有问题的</p>

爱吃鱼的程序员 2020-06-06 09:58:12 0 浏览量 回答数 0

问题

十问泛型,你能答上来吗?【面试必备】

问问小秘 2020-06-23 14:48:15 2 浏览量 回答数 1

回答

http://blog.csdn.net/zdy0_2004/article/details/462881831.概述 在大型软件系统中,为了监测软件运行状况及排查软件故障,一般都会要求软件程序在运行的过程中产生日志文件。在日志文件中存放程序流程中的一些重要信息,包括:变量名称及其值、消息结构定义、函数返回值及其执行情况、脚本执行及调用情况等。通过阅读日志文件,我们能够较快地跟踪程序流程,并发现程序问题。因此,熟练掌握日志系统的编写方法并快速地阅读日志文件,是对一个软件开发工程师的基本要求。 本文详细地介绍了Linux下一个简单的日志系统的设计方法,并给出了其C代码实现。本文为相关开发项目Linux下软件日志系统的编写提供了有益的参考。2.日志系统的框架结构 一个完整的日志系统包括三大部分:配置文件、软件程序和日志文件,它们之间的关系如图1所示。 3.生成日志文件的程序流程 基于日志系统的框架结构,生成日志文件的程序流程如图2所示。 图2 生成日志文件的程序流程 在实际的软件程序中,为了在程序的不同地方打印不同的日志,要将生成日志的代码封装为函数,作为API供程序调用。 如果软件没有成功生成日志,那么就不要让其继续执行后续流程,而是要查找问题的原因,直到日志生成正常为止。4.日志文件命名及日志信息格式 对于日志文件的命名,不同的软件开发项目有不同的规定。一般说来,日志文件都是以log作为后缀,如本文中的日志文件命名为:WriteLog.log。 对于每条日志信息的格式,对于不同的软件来说,也会有所不同。在本文中,日志信息的格式有以下两种(具体使用哪一种通过配置项决定): 第一种:日志生成时间函数名[日志等级]日志具体信息 第二种:日志生成时间日志具体信息5.配置文件说明 本文中使用的配置文件为Config.ini,它包括了两部分信息,如下所示:其中,“EMPLOYEEINFO”段是指员工信息,包含员工姓名和员工年龄两个配置项。程序会将员工姓名和员工年龄读入,并输出到日志文件中。 “LOG”段是指日志信息,包含日志等级、日志代码位置标识和输出日志文件的目录三个配置项。对于“LogLevel”配置项,只有代码中日志等级不低于配置值的日志信息才会被输出到日志文件中(例如,LogLevel=4,那么只有Fatal、Error、Warn、Info和Trace等级的日志会被输出到日志文件中)。“LogPosition”配置项的值用于控制是否在日志文件中显示“文件名/函数名/代码行数”信息,1则显示,0则不显示。“LogDir”配置项的值表示生成的日志文件存放的目录。6.重要程序流程 (1) 从配置文件中读取各个配置项的值 该操作的流程如图3所示,具体请参见《Linux下配置文件读取操作流程及其C代码实现》(http://blog.csdn.net/zhouzhaoxiong1227/article/details/45563263)一文。 图4 向日志文件中写入日志信息程序流程该流程的具体代码请参考本文附录中的完整程序代码中的WriteLogFile函数。7.程序测试设计及文件上传 为了测试本日志系统的功能是否正确,在main函数中设计了以下三类日志信息: 第一类:打印程序的版本号及编译时间。 第二类:打印Fatal、Error、Warn、Info、Trace、Debug、All这七个等级的日志各一条。 第三类:调用GetEmployeeInfo函数打印读取到的员工姓名和年龄。将本程序“WriteLog.c”上传到Linux的“/home/zhou/zhouzx/test”目录下,并在该目录下建立“etc”和“log”目录,将配置文件“Config.ini”上传到“etc”下。文件及目录布局如图5所示。 图5 文件及目录布局8.代码编译及运行 在Linux下使用“gcc -g -o WriteLog WriteLog.c”命令对程序进行编译,生成“WriteLog”文件。 下面来运行程序。 (1) 将配置文件中的各个配置项的值设置如下:对照配置文件和日志文件,我们可以看到,“LogLevel”设置的是为4,因此只有日志等级不低于4的日志被输出到了日志文件中;“LogPosition”设置的是为0,因此在日志文件中不显示“文件名/函数名/代码行数”的信息。为了验证本日志系统功能的正常与否,要对程序进行多组测试,9.总结 本文对Linux下一个简单的日志系统的设计方法进行了详细的介绍(其C代码实现请见附录),代码中的写日志相关函数可作为API供其它需要进行类似操作的程序调用。在使用本日志系统的过程中,有以下注意事项: 第一,配置文件中“LOG”段只包括了日志等级、日志代码位置标识和输出日志文件的目录三个配置项。在实际的软件开发项目中,还会有更多的配置参数,像存放的日志文件的最大个数、每个日志文件的大小阈值、每个已写入完成的日志文件的命名等。可以在本程序的基础上进一步扩展来实现复杂的日志功能。 第二,本文中对日志信息的写入采用的是直接在日志文件后面追加的方式,因此每次测试之前,要在“log”目录下删除上一次产生的“WriteLog.log”文件,否则新的日志信息会写入旧的日志文件中。 第三,由于写日志函数WriteLogFile的入参较多,每次调用的时候编写代码较为繁琐,因此使用一个宏WRITELOGFILE来代替,且只需要带上日志等级和日志消息两个参数即可,其它的如代码文件名、函数名和代码行数直接使用系统自定义的宏即可。附录:完整的程序代码

杨冬芳 2019-12-02 03:06:27 0 浏览量 回答数 0

问题

【教程免费下载】C++程序设计教程(第3版)

玄学酱 2019-12-01 22:07:48 1450 浏览量 回答数 2

回答

Apache Tomcat VersionsApache Tomcat®是java Servlet和JSP技术的一个开放源代码的软件实现。不同版本的Apache Tomcat可用于不同版本的servlet和JSP规范。规格和各自的Apache Tomcat版本之间的映射是:每个版本的tomcat是任何稳定的java版本,满足最后一列的表中的上述要求的支持。Tomcat也应该工作在任何java早期访问构建满足最后一列的表中的上述要求。例如,用户已成功运行Tomcat 8在java 8个多月前的第一个稳定的java 8版本。但是,早期访问构建的用户应该知道以下内容:这是不寻常的初步早期访问构建包含错误,可能会导致问题的Web应用程序运行在Tomcat。如果新的java版本引入了新的语言特征,然后默认的JSP编译器可能不支持他们。JSP编译器javac开关可以使这些新的语言功能可用于在JSPs。如果你发现一个问题,使用java早期Access建立,请寻求帮助。Tomcat的用户的邮件列表可能是最好的开始。下面的详细说明将帮助您确定哪一个适合您。有关每个版本的详细信息可以在相关的发行说明中找到。请注意,虽然我们提供下载和旧版本的文件,如Apache Tomcat 6,x,我们强烈鼓励用户使用最新的稳定版本的Apache Tomcat尽可能。我们认识到,在主要版本的升级可能不是一个简单的任务,一些支持仍然提供的旧版本的用户的邮件列表。但是,由于社区驱动的支持方式,你的版本越老,会有更少的人感兴趣或者能够支持你。Alpha / Beta / Stable当投票为一个版本,评审指定的稳定水平,他们认为释放已经达到。最初版本的一个新的主要版本通常从阿尔法,通过测试,以稳定在几个月的时间内。然而,稳定的水平是唯一的一次java规范发布实施已完成。这意味着在所有其他方面被认为是稳定的版本,如果规格不是最终的,仍然可以被标记为beta。下载页将始终显示最新的稳定版本和任何新的alpha或beta版本,如果存在。alpha和beta版本总是在下载页面上明确标注。稳定性是一个主观判断,你应该仔细阅读发行说明任何版本,你打算利用。如果你是一个释放的早期采用者,我们很想听听你对其作为投一部分稳定的看法:它发生在开发邮件列表。alpha版本可能包含大量未经测试的/缺少的功能所需的规范和/或重大错误,预计不会运行稳定的任何时间长度。Beta版本可能包含一些未经测试的功能和/或一些相对较小的错误。beta版本预计不会稳定运行。稳定版本可能包含少量相对较小的错误。稳定版本的目的是生产使用,预计将稳定运行长时间。Apache Tomcat 9.xApache Tomcat 9是当前开发的重点,它基于Tomcat 8和X实现了Servlet 4规范的当前草案,并且还将实现JSP 2.4?,厄尔尼诺3.1?1.2、WebSocket?1.1、jaspic规格一旦开始更新java EE 8规范。除此之外,还包括以下重大改进:增加支持HTTP / 2(要求APR /本机库)增加支持TLS虚拟主机增加使用TLS支持JSSE连接器支持OpenSSL(NiO和NIO2)Apache Tomcat 8.xApache Tomcat 8。x建立在Tomcat 7。X实现了servlet JSP 2.3,3.1,3和1.1规格的WebSocket EL。除此之外,还包括以下重大改进:一个单一的,共同的资源实现,以取代早期版本中提供的多个资源扩展功能。Apache Tomcat 8.5。X支持同一个servlet,JSP,EL和WebSocket规范版本的Apache Tomcat 8。X。此外,它还实现jaspic 1.1规范。在许多地区的引擎盖下有显着的变化,从而提高性能,稳定性和总拥有成本。请参阅Apache Tomcat 8.5更新详情。Apache Tomcat 7.xApache Tomcat 7。x建立在Tomcat 6做了改进。X实现了JSP Servlet 3,2.2,2.2和1.1规格的WebSocket EL。除此之外,还包括以下改进:Web应用程序内存泄漏检测与防范管理器和主机管理器应用程序的安全性改进通用的CSRF保护支持直接包含外部内容的web应用程序重构(连接器,生命周期)和大量内部代码清理Apache Tomcat 6.xApache Tomcat 6 x基于Tomcat 5.5和X的改进,实现了servlet 2.5和JSP 2.1规范。除此之外,还包括以下改进:内存使用的优化先进的IO能力重构的聚类Tomcat 6的用户应该意识到Tomcat 6已经达到生命的终结。Tomcat 6的用户应该升级到Tomcat 7 x或更高版本。Apache Tomcat 5.xApache Tomcat 5 x可从档案中下载。Apache Tomcat 5.5 x支持与Apache Tomcat 5相同的servlet和JSP规范版本。在引擎盖下的许多区域都有显著的变化,导致性能、稳定性和总拥有成本的提高。请参阅Apache Tomcat 5.5更新详情。Apache Tomcat 5 x在许多方面提高Apache Tomcat 4.1,包括:性能优化和减少垃圾收集重构应用程序的部署,一个可选的独立部署允许Web应用程序的验证和编译之前把它在生产完整的服务器使用JMX和经理的Web应用监控可扩展性和可靠性增强改进的标签库处理,包括先进的共享和标签插件改进的平台集成,与本机的Windows和Unix的包装嵌入使用JMX增强安全管理器支持集成会话聚类扩展的文件Apache Tomcat 4.xApache Tomcat 4 x可从档案中下载。Apache Tomcat 4。X实现了一种新的servlet容器(称为卡特琳娜)是基于全新的架构。4、X发布实现Servlet 2.3和JSP 1.2规范。Apache Tomcat 4.1 x是Apache Tomcat 4 x的重构,并包含显著的增强功能,包括:基于JMX的管理功能基于JSP和Struts的管理Web应用新狼连接器(HTTP/1.1,AJP 1.3和JNI支持)重写JSP页面编译器性能和内存效率改进增强管理器应用程序支持与开发工具集成自定义Ant任务与管理应用程序直接从build.xml脚本互动Apache Tomcat 4。X的Apache Tomcat 4.0.6是旧的生产质量释放。4 Servlet容器(Catalina)已经从地上爬起来的灵活性和性能开发。版本4实现了servlet 2.3和JSP 1.2规范的最终发布版本。按照规格要求,Apache Tomcat 4还支持为servlet 2.2和JSP 1.1规范构建的Web应用程序,没有任何更改。Apache Tomcat 3.xApache Tomcat 3 x可从档案中下载。版本3.3是当前生产质量发布的servlet 2.2和JSP 1.1规格。Apache Tomcat 3.3是Apache Tomcat 3最新的延续。X架构;然后3.2.4更先进,这是'老'生产质量释放。3.2.4版本是'老'生产质量的释放和现在在维护模式。3.1.1版是一个传统的释放。所有Apache Tomcat 3 x释放他们的遗产回到原来的servlet和JSP实现Sun捐赠给Apache软件基金会。3、X版全部实现Servlet 2.2和JSP 1.1规范。Apache Tomcat 3.3。X版本3.3.2是当前生产质量释放。它继续在第3.2版中开始的重构,并把它带到合乎逻辑的结论。版本3.3提供了一个更加模块化的设计,通过添加和移除控制servlet请求处理的模块来实现servlet容器的定制。此版本还包含许多性能改进。3.2版本的版本自3.1起增加了一些新的功能;主要的努力是重构内部以提高性能和稳定性。3.2.1版本的,像3.1.1,是一个安全补丁。3.2.2版本,一大批固定的错误和所有已知的规范合规问题。3.2.3版本是一个安全更新,关闭一个严重的安全漏洞。是一个小bug修复版本3.2.4释放。Apache Tomcat版本3.2.3所有用户之前,应尽快升级。除了关键的安全相关的错误修复,Apache Tomcat 3.2 X分支的发展已经停止。3.1的版本包含了Apache Tomcat 3的几个改进,包括servlet重装、WAR文件支持以及为IIS和Netscape Web服务器添加了连接器。最新的维护版本,3.1.1,包含对安全问题的修复。没有活动的发展进行了Apache Tomcat 3.1。X的用户应该升级到Apache Tomcat 3.1 3.1.1关闭安全漏洞,大力鼓励他们迁移到目前的产能释放,Apache Tomcat 3.3。Apache Tomcat 3初始Apache Tomcat发布。

hiekay 2019-12-02 01:39:27 0 浏览量 回答数 0

问题

我是如何3分钟安装LNMP环境的

bendchen 2019-12-01 21:57:14 9664 浏览量 回答数 6

问题

TypeScript:拥有超能力的 JavaScript

茶什i 2020-01-20 15:15:47 3 浏览量 回答数 0

问题

【精品问答】python百大常见问题与答案详解

祖安文状元 2020-02-24 17:56:41 363 浏览量 回答数 1

回答

public class Server { public static void main(String[] args) throws IOException { Service(); } private static void Service() throws IOException { ServerSocket ss = new ServerSocket(80); while (true) { Socket socket = ss.accept(); InputStream in = socket.getInputStream(); DataInputStream dis = new DataInputStream(in); String command = dis.readUTF(); dealCommond(command,socket.getInetAddress()); ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); News news = null; oos.writeInt(Integer.valueOf(3)); for (int i = 0; i < 3; i++) { news = new News(); news.setId(i); news.setContent("手机新闻" + i); oos.writeObject(news); } System.out.println("新闻对象发送完毕"); oos.close(); socket.close(); } } private static void dealCommond(String command, InetAddress inetAddress) { } } public class Client { public static void main(String[] args) throws Exception { Socket socket = new Socket("localhost",80); OutputStream os = socket.getOutputStream(); DataOutputStream dos = new DataOutputStream(os); dos.writeUTF("get"); ObjectInputStream bis = new ObjectInputStream(socket.getInputStream()); int num = bis.readInt(); System.out.println("收到新闻条数:" + num); for (int i = 0; i < num; i++) { News news = (News) bis.readObject(); // write file System.out.println("新闻:" + news.getId() + " --" + news.getContent()); } bis.close(); socket.close(); } } public class News implements Serializable { private static final long serialVersionUID = 4720377449858029580L; private int id; private String content; /** * @return the id */ public int getId() { return id; } /** * @param id the id to set */ public void setId(int id) { this.id = id; } /** * @return the content */ public String getContent() { return content; } /** * @param content the content to set */ public void setContent(String content) { this.content = content; } /** * @return the serialVersionUID */ public static long getSerialVersionUID() { return serialVersionUID; } } 如果服务端需要非阻塞支持多client那你要加Thread处理。 ######回复 @宇智波带土 : 我在百度知道里看了看有人说是把NewsObject类编译,打包成jar文件,拷到服务端,添加到服务端的类路径里面去,我已经打成jar文件了,但是不知道怎么添加类路径里,求你指点迷津啊大神。。。谢啦哈######回复 @宇智波带土 : 我的NewsOject类就是那个序列化对象类,我本来是在PC端JDBC包里建立的,安卓的工程里也建了一个NewsObject类,但是安卓工程运行出现的异常总是说找不到PC端那个工程里JDBC包里的NewsObject类,我也不知道怎么办了,readObject()不能读的问题应该是出在这里不?######int num = in.read(); 你这读出来的是0吧,循环里面没执行。或者发下异常信息。######谢谢你,用你的方法测试完后确实能够顺利收发流对象。只是我在想为什么我的那段代码不行,思路是一样的。我发现有不同的地方是流对象的定义位置,你的是哪里要用则在哪定义并实例化一个对象,而我是一开始定义了一个空对象,再到用的时候实例化,可能就是这里有问题吧。###### 回复 @宇智波带土 : 安卓那端接收到的数确实是发过来的流对象的个数,只是进入循环就会卡死在readObject()那一句,我以为是线程的问题,后来用Looper循环者机制也没用,问题还是出现在那。 04-27 10:45:10.822: I/Receive(18607): 接收到PC的对象流个数: 10 04-27 10:45:10.832: W/System.err(18607): java.lang.ClassNotFoundException: JDBC.NewsObject 04-27 10:45:10.842: W/System.err(18607): at java.lang.Class.classForName(Native Method) 04-27 10:45:10.842: W/System.err(18607): at java.lang.Class.forName(Class.java:217) 04-27 10:45:10.842: W/System.err(18607): at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:2301) 04-27 10:45:10.842: W/System.err(18607): at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1660) 04-27 10:45:10.842: W/System.err(18607): at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:683) 04-27 10:45:10.842: W/System.err(18607): at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:1803) 04-27 10:45:10.842: W/System.err(18607): at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:787) 04-27 10:45:10.842: W/System.err(18607): at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2003) 04-27 10:45:10.842: W/System.err(18607): at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1960) 04-27 10:45:10.842: W/System.err(18607): at com.example.Internet.UpdataNews.run(UpdataNews.java:53) 04-27 10:45:10.842: W/System.err(18607): Caused by: java.lang.NoClassDefFoundError: JDBC/NewsObject 04-27 10:45:10.842: W/System.err(18607): ... 10 more 04-27 10:45:10.842: W/System.err(18607): Caused by: java.lang.ClassNotFoundException: JDBC.NewsObject 04-27 10:45:10.842: W/System.err(18607): at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:61) 04-27 10:45:10.842: W/System.err(18607): at java.lang.ClassLoader.loadClass(ClassLoader.java:501) 04-27 10:45:10.842: W/System.err(18607): at java.lang.ClassLoader.loadClass(ClassLoader.java:461) 04-27 10:45:10.842: W/System.err(18607): ... 10 more 04-27 10:45:10.842: W/System.err(18607): java.io.OptionalDataException 04-27 10:45:10.842: W/System.err(18607): at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:810) 04-27 10:45:10.842: W/System.err(18607): at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2003) 04-27 10:45:10.842: W/System.err(18607): at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1960) 04-27 10:45:10.842: W/System.err(18607): at com.example.Internet.UpdataNews.run(UpdataNews.java:53) ######回复 @铁龙98 : 不客气,我在我本机器上测试,还原你上边的异常,只不过客户端不是android而已,就是读取了不同包的NewsObject造成的,如果改成服务器端NewsObject一样的包问题解决了,当然要一样的如果你客户端里面NewsObject 那个生成的版本号不一样,一样会抛异常的######回复 @宇智波带土 : 意思是读写都是共享那一个序列化对象的类吗?那要是PC服务器和android客户端分开开发呢?其实我试过从一个包里公用NewsObject类,问题是LogCat视图总是说找不到那个包里的NewsObject类。哎,为这问题头疼了。谢谢你的回复,真的感谢你。还望您多多关照哈。######这个问题应该是你在android端读取对象的时候 NewsObject的包与你服务端的包的位置不一样造成的. 你服务器端 com.xxx.xxx android com.xxx.xxx 要相同。 ==========================

kun坤 2020-06-06 22:19:39 0 浏览量 回答数 0

回答

一 系统介绍 Android 是Google开发的基于Linux平台的、开源的、智能手机操作系统。Android包括操作系统、中间件和应用程序,由于源代码开放,Android可以被移植到不同的硬件平台上。 围绕在Google的Android系统中,形成了移植开发和上层应用程序开发两个不同的开发方面。手机厂商从事移植开发工作,上层的应用程序开发可以由任何单位和个人完成,开发的过程可以基于真实的硬件系统,还可以基于仿真器环境。 作为一个手机平台,Android在技术上的优势主要有以下几点: - 全开放智能手机平台 - 多硬件平台的支持 - 使用众多的标准化技术 - 核心技术完整,统一 - 完善的SDK和文档 - 完善的辅助开发工具 Android的开发者可以在完备的开发环境中进行开发,Android的官方网站也提供了丰富的文档、资料。这样有利于Android系统的开发和运行在一个良好的生态环境中。 https://developer.android.com/about安卓开发者官方网站 从宏观的角度来看,Android是一个开放的软件系统,它包含了众多的源代码。从下至上,Android系统分成4个层次: 第1层次:Linux操作系统及驱动; 第2层次:本地代码(C/C++)框架; 第3层次:Java框架; 第4层次:Java应用程序。 Android系统的架构如图所示: 由于Android系统需要支持Java代码的运行,这部分内容是Android的运行环境(Runtime),由虚拟机和Java基本类组成。 对于Android应用程序的开发,主要关注第3层次和第4层次之间的接口。 二 学习路线 基础学习——JavaSE: 基础学习扩展——JavaEE: 基础学习扩展——Linux基础: Android开发学习——基础理论:系统架构分析: Android系统从底向上一共分了4层,每一层都把底层实现封装,并暴露调用接口给上一层。 Linux内核(Linux Kernel) Android运行在linux kernel 2.6之上,但是把linux内受GNU协议约束的部分做了取代,这样在Android的程序可以用于商业目的。 Linux 内核是硬件和软件层之间的抽象层。 中间件 中间件包括两部分: 核心库和运行时(libraries & Android runtime) 核心库包括,SurfaceManager 显示系统管理库,负责把2D或3D内容显示到屏幕;Media Framework 媒体库,负责支持图像,支持多种视频和音频的录制和回放;SQlite 数据库,一个功能强大的轻量级嵌入式关系数据库;WebKit 浏览器引擎等。 Dalvik虚拟机: 区别于Java虚拟机的是,每一个Android 应用程序都在它自己的进程中运行,都有一个属于自己的Dalvik 虚拟机,这一点可以让系统在运行时可以达到优化,程序间的影响大大降低。Dalvik虚拟机并非运行Java字节码,而是运行自己的字节码。 应用程序框架(Application Framework) 丰富而又可扩展性的视图(Views),可以用来构建应用程序, 它包括列表(lists),网格(grids), 文本框(text boxes),按钮( buttons), 可嵌入的web 浏览器。内容提供者(Content Providers)使得应用程序可以访问另一个应用程序的数据(如联系人数据库), 或者共享它们自己的数据。资源管理器(Resource Manager)提供非代码资源的访问,如本地字符串,图形,和布局文件( layoutfiles )。通知管理器(Notification Manager) 使得应用程序可以在状态栏中显示自定义的提示信息。活动管理器( Activity Manager) 用来管理应用程序生命周期并提供常用的导航回退功能。 三 基础知识 掌握java部分之后,可以使用开发工具进入android世界 您可以使用 Kotlin、Java 和 C++ 语言编写 Android 应用。Android SDK 工具会将您的代码连同任何数据和资源文件编译成一个 APK(Android 软件包),即带有 .apk 后缀的归档文件。一个 APK 文件包含 Android 应用的所有内容,它也是 Android 设备用来安装应用的文件。 每个 Android 应用都处于各自的安全沙盒中,并受以下 Android 安全功能的保护: • Android 操作系统是一种多用户 Linux 系统,其中的每个应用都是一个不同的用户; • 默认情况下,系统会为每个应用分配一个唯一的 Linux 用户 ID(该 ID 仅由系统使用,应用并不知晓)。系统会为应用中的所有文件设置权限,使得只有分配给该应用的用户 ID 才能访问这些文件; • 每个进程都拥有自己的虚拟机 (VM),因此应用代码独立于其他应用而运行。 • 默认情况下,每个应用都在其自己的 Linux 进程内运行。Android 系统会在需要执行任何应用组件时启动该进程,然后当不再需要该进程或系统必须为其他应用恢复内存时,其便会关闭该进程。 Android 系统实现了最小权限原则。换言之,默认情况下,每个应用只能访问执行其工作所需的组件,而不能访问其他组件。这样便能创建非常安全的环境,在此环境中,应用无法访问其未获得权限的系统部分。不过,应用仍可通过一些途径与其他应用共享数据以及访问系统服务: • 可以安排两个应用共享同一 Linux 用户 ID,在此情况下,二者便能访问彼此的文件。为节省系统资源,也可安排拥有相同用户 ID 的应用在同一 Linux 进程中运行,并共享同一 VM。应用还必须使用相同的证书进行签名。 • 应用可以请求访问设备数据(如用户的联系人、短信消息、可装载存储装置(SD 卡)、相机、蓝牙等)的权限。用户必须明确授予这些权限。如需了解详细信息,请参阅使用系统权限。 本文档的其余部分将介绍以下概念: • 用于定义应用的核心框架组件 • 用来声明组件和应用必需设备功能的清单文件。 • 与应用代码分离并允许应用针对各种设备配置适当优化其行为的资源。 应用组件 应用组件是 Android 应用的基本构建块。每个组件都是一个入口点,系统或用户可通过该入口点进入您的应用。有些组件会依赖于其他组件。 共有四种不同的应用组件类型: • Activity • 服务 • 广播接收器 • 内容提供程序 每种类型都有不同的用途和生命周期,后者会定义如何创建和销毁组件。以下部分将介绍应用组件的四种类型。 Activity Activity 是与用户交互的入口点。它表示拥有界面的单个屏幕。例如,电子邮件应用可能有一个显示新电子邮件列表的 Activity、一个用于撰写电子邮件的 Activity 以及一个用于阅读电子邮件的 Activity。尽管这些 Activity 通过协作在电子邮件应用中形成一种紧密结合的用户体验,但每个 Activity 都独立于其他 Activity 而存在。因此,其他应用可以启动其中任何一个 Activity(如果电子邮件应用允许)。例如,相机应用可以启动电子邮件应用内用于撰写新电子邮件的 Activity,以便用户共享图片。Activity 有助于完成系统和应用程序之间的以下重要交互: • 追踪用户当前关心的内容(屏幕上显示的内容),以确保系统继续运行托管 Activity 的进程。 • 了解先前使用的进程包含用户可能返回的内容(已停止的 Activity),从而更优先保留这些进程。 • 帮助应用处理终止其进程的情况,以便用户可以返回已恢复其先前状态的 Activity。 • 提供一种途径,让应用实现彼此之间的用户流,并让系统协调这些用户流。(此处最经典的示例是共享。) 您需将 Activity 作为 Activity 类的子类来实现。如需了解有关 Activity 类的更多信息,请参阅 Activity 开发者指南。 服务 服务是一个通用入口点,用于因各种原因使应用在后台保持运行状态。它是一种在后台运行的组件,用于执行长时间运行的操作或为远程进程执行作业。服务不提供界面。例如,当用户使用其他应用时,服务可能会在后台播放音乐或通过网络获取数据,但这不会阻断用户与 Activity 的交互。诸如 Activity 等其他组件可以启动服务,使该服务运行或绑定到该服务,以便与其进行交互。事实上,有两种截然不同的语义服务可以告知系统如何管理应用:已启动服务会告知系统使其运行至工作完毕。此类工作可以是在后台同步一些数据,或者在用户离开应用后继续播放音乐。在后台同步数据或播放音乐也代表了两种不同类型的已启动服务,而这些服务可以修改系统处理它们的方式: • 音乐播放是用户可直接感知的服务,因此,应用会向用户发送通知,表明其希望成为前台,从而告诉系统此消息;在此情况下,系统明白它应尽全力维持该服务进程运行,因为进程消失会令用户感到不快。 • 通常,用户不会意识到常规后台服务正处于运行状态,因此系统可以更自由地管理其进程。如果系统需要使用 RAM 来处理用户更迫切关注的内容,则其可能允许终止服务(然后在稍后的某个时刻重启服务)。 绑定服务之所以能运行,原因是某些其他应用(或系统)已表示希望使用该服务。从根本上讲,这是为另一个进程提供 API 的服务。因此,系统会知晓这些进程之间存在依赖关系,所以如果进程 A 绑定到进程 B 中的服务,系统便知道自己需使进程 B(及其服务)为进程 A 保持运行状态。此外,如果进程 A 是用户关心的内容,系统随即也知道将进程 B 视为用户关心的内容。由于存在灵活性(无论好坏),服务已成为非常有用的构建块,并且可实现各种高级系统概念。动态壁纸、通知侦听器、屏幕保护程序、输入方法、无障碍功能服务以及众多其他核心系统功能均可构建为在其运行时由应用实现、系统绑定的服务。 您需将服务作为 Service 的子类来实现。如需了解有关 Service 类的更多信息,请参阅服务开发者指南。 注意:如果您的应用面向 Android 5.0(API 级别 21)或更高版本,请使用 JobScheduler 类来调度操作。JobScheduler 的优势在于,它能通过优化作业调度来降低功耗,以及使用 Doze API,从而达到省电目的。如需了解有关使用此类的更多信息,请参阅 JobScheduler 参考文档。 广播接收器 借助广播接收器组件,系统能够在常规用户流之外向应用传递事件,从而允许应用响应系统范围内的广播通知。由于广播接收器是另一个明确定义的应用入口,因此系统甚至可以向当前未运行的应用传递广播。例如,应用可通过调度提醒来发布通知,以告知用户即将发生的事件。而且,通过将该提醒传递给应用的广播接收器,应用在提醒响起之前即无需继续运行。 许多广播均由系统发起,例如,通知屏幕已关闭、电池电量不足或已拍摄照片的广播。应用也可发起广播,例如,通知其他应用某些数据已下载至设备,并且可供其使用。尽管广播接收器不会显示界面,但其可以创建状态栏通知,在发生广播事件时提醒用户。但广播接收器更常见的用途只是作为通向其他组件的通道,旨在执行极少量的工作。例如,它可能会根据带 JobScheduler 的事件调度 JobService 来执行某项工作 广播接收器作为 BroadcastReceiver 的子类实现,并且每条广播都作为 Intent 对象进行传递。如需了解详细信息,请参阅 BroadcastReceiver 类。 内容提供程序 内容提供程序管理一组共享的应用数据,您可以将这些数据存储在文件系统、SQLite 数据库、网络中或者您的应用可访问的任何其他持久化存储位置。其他应用可通过内容提供程序查询或修改数据(如果内容提供程序允许)。例如,Android 系统可提供管理用户联系人信息的内容提供程序。 因此,任何拥有适当权限的应用均可查询内容提供程序(如 ContactsContract.Data),以读取和写入特定人员的相关信息。我们很容易将内容提供程序看作数据库上的抽象,因为其内置的大量 API 和支持时常适用于这一情况。但从系统设计的角度看,二者的核心目的不同。对系统而言,内容提供程序是应用的入口点,用于发布由 URI 架构识别的已命名数据项。因此,应用可以决定如何将其包含的数据映射到 URI 命名空间,进而将这些 URI 分发给其他实体。反之,这些实体也可使用分发的 URI 来访问数据。在管理应用的过程中,系统可以执行以下特殊操作: • 分配 URI 无需应用保持运行状态,因此 URI 可在其所属的应用退出后继续保留。当系统必须从相应的 URI 检索应用数据时,系统只需确保所属应用仍处于运行状态。 • 这些 URI 还会提供重要的细粒度安全模型。例如,应用可将其所拥有图像的 URI 放到剪贴板上,但将其内容提供程序锁定,以便其他应用程序无法随意访问它。当第二个应用尝试访问剪贴板上的 URI 时,系统可允许该应用通过临时的 URI 授权来访问数据,这样便只能访问 URI 后面的数据,而非第二个应用中的其他任何内容。 内容提供程序也适用于读取和写入您的应用不共享的私有数据。 内容提供程序作为 ContentProvider 的子类实现,并且其必须实现一组标准 API,以便其他应用能够执行事务。如需了解详细信息,请参阅内容提供程序开发者指南。 Android 系统设计的独特之处在于,任何应用都可启动其他应用的组件。例如,当您想让用户使用设备相机拍摄照片时,另一个应用可能也可执行该操作,因而您的应用便可使用该应用,而非自行产生一个 Activity 来拍摄照片。您无需加入甚至链接到该相机应用的代码。只需启动拍摄照片的相机应用中的 Activity 即可。完成拍摄时,系统甚至会将照片返回您的应用,以便您使用。对用户而言,这就如同相机是您应用的一部分。 当系统启动某个组件时,它会启动该应用的进程(如果尚未运行),并实例化该组件所需的类。例如,如果您的应用启动相机应用中拍摄照片的 Activity,则该 Activity 会在属于相机应用的进程(而非您的应用进程)中运行。因此,与大多数其他系统上的应用不同,Android 应用并没有单个入口点(即没有 main() 函数)。 由于系统在单独的进程中运行每个应用,且其文件权限会限制对其他应用的访问,因此您的应用无法直接启动其他应用中的组件,但 Android 系统可以。如要启动其他应用中的组件,请向系统传递一条消息,说明启动特定组件的 Intent。系统随后便会为您启动该组件。 启动组件 在四种组件类型中,有三种(Activity、服务和广播接收器)均通过异步消息 Intent 进行启动。Intent 会在运行时对各个组件进行互相绑定。您可以将 Intent 视为从其他组件(无论该组件是属于您的应用还是其他应用)请求操作的信使。 您需使用 Intent 对象创建 Intent,该对象通过定义消息来启动特定组件(显式 Intent)或特定的组件类型(隐式 Intent)。 对于 Activity 和服务,Intent 会定义要执行的操作(例如,查看或发送某内容),并且可指定待操作数据的 URI,以及正在启动的组件可能需要了解的信息。例如,Intent 可能会传达对 Activity 的请求,以便显示图像或打开网页。在某些情况下,您可以通过启动 Activity 来接收结果,这样 Activity 还会返回 Intent 中的结果。例如,您可以发出一个 Intent,让用户选取某位联系人并将其返回给您。返回 Intent 包含指向所选联系人的 URI。 对于广播接收器,Intent 只会定义待广播的通知。例如,指示设备电池电量不足的广播只包含指示“电池电量不足”的已知操作字符串。 与 Activity、服务和广播接收器不同,内容提供程序并非由 Intent 启动。相反,它们会在成为 ContentResolver 的请求目标时启动。内容解析程序会通过内容提供程序处理所有直接事务,因此通过提供程序执行事务的组件便无需执行事务,而是改为在 ContentResolver 对象上调用方法。这会在内容提供程序与请求信息的组件之间留出一个抽象层(以确保安全)。 每种组件都有不同的启动方法: • 如要启动 Activity,您可以向 startActivity() 或 startActivityForResult() 传递 Intent(当您想让 Activity 返回结果时),或者为其安排新任务。 • 在 Android 5.0(API 级别 21)及更高版本中,您可以使用 JobScheduler 类来调度操作。对于早期 Android 版本,您可以通过向 startService() 传递 Intent 来启动服务(或对执行中的服务下达新指令)。您也可通过向将 bindService() 传递 Intent 来绑定到该服务。 • 您可以通过向 sendBroadcast()、sendOrderedBroadcast() 或 sendStickyBroadcast() 等方法传递 Intent 来发起广播。 • 您可以通过在 ContentResolver 上调用 query(),对内容提供程序执行查询。 如需了解有关 Intent 用法的详细信息,请参阅 Intent 和 Intent 过滤器文档。以下文档将为您详细介绍如何启动特定组件:Activity、服务、BroadcastReceiver 和内容提供程序。

问问小秘 2020-03-03 09:47:38 0 浏览量 回答数 0

回答

更实际的情况是,在程序运行开始时,程序已经具有一个初始的程序界面(初始界面可能只包含一个UIView),在程序运行过程中,程序需要根据用户交互来动态添加、删除UI控件。 在这种需求下,我们可以通过Interface Builder来设计程序的初始界面;接下来在程序运行过程中,可以通过代码创建UI控件,再将UI控件添加到相应的父控件中即可。 实例:动态添加、删除标签 首先创建一个iOS的Single View Application应用,创建完成后,该应用将自带一个Main.storyboard界面设计文件,但我们并不打算修改该界面设计文件,而是直接在程序代码中创建整个UI界面,程序只使用该界面文件中的UIView作为容器即可。 接下来修改控制器类,在控制器类的实现部分创建整个程序界面,绑定事件处理方法。下面是控制类的实现部分代码。 程序清单:codes/09/9.5/DynaLabel/DynaLabel/FKViewController.m #import "FKViewController.h" // 定义FKViewController的扩展 @interface FKViewController () // 定义一个属性来记录所有动态添加的UILabel控件 @property (nonatomic, strong) NSMutableArray* labels; @end @implementation FKViewController // 定义一个变量来记录下一个将要添加的UILabel的位置 int nextY = 80; - (void)viewDidLoad { [super viewDidLoad]; // 设置该view的背景色 self.view.backgroundColor = [UIColor grayColor]; // 初始化labels数组 self.labels = [NSMutableArray array]; // 创建UIButtonTypeRoundedRect类型的UIButton对象 UIButton* addBn = [UIButton buttonWithType:UIButtonTypeRoundedRect]; // 设置addBn的大小和位置 addBn.frame = CGRectMake(30, 30, 60, 40); // 为UIButton设置按钮文本 [addBn setTitle:@"添加" forState:UIControlStateNormal]; // 为addBn的Touch Up Inside事件绑定事件处理方法 [addBn addTarget:self action:@selector(add:) forControlEvents:UIControlEventTouchUpInside]; // 创建UIButtonTypeRoundedRect类型的UIButton对象 UIButton* removeBn = [UIButton buttonWithType:UIButtonTypeRoundedRect]; // 设置removeBn的大小和位置 removeBn.frame = CGRectMake(230, 30, 60, 40); // 为UIButton设置按钮文本 [removeBn setTitle:@"删除" forState:UIControlStateNormal]; // 为removeBn的Touch Up Inside事件绑定事件处理方法 [removeBn addTarget:self action:@selector(remove:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:addBn]; [self.view addSubview:removeBn]; } - (void)add:(id)sender { // 创建一个UILabel控件 UILabel* label = [[UILabel alloc] initWithFrame: CGRectMake(80, nextY, 160, 30)]; label.text = @"疯狂iOS讲义"; // 设置该UILabel显示的文本 [self.labels addObject: label]; // 将该UILabel添加到labels数组中 [self.view addSubview:label]; // 将UILabel控件添加到view父控件内 nextY += 50; // 控制nextY的值加50 } - (void)remove:(id)sender { // 如果labels数组中元素个数大于0,表明有UILabel可删除 if([self.labels count] > 0) { // 将最后一个UILabel从界面上删除 [[self.labels lastObject] removeFromSuperview]; [self.labels removeLastObject]; // 从labels数组中删除最后一个元素 nextY -= 50; // 控制nextY的值减50 } } @end 上面的代码中,第一段粗体字代码创建了应用的初始界面,该初始界面只包含两个按钮,并且程序还为这两个按钮绑定了事件处理方法。 提示: 上面程序中多次使用了CGRectMake()函数,该函数专门用于创建一个CGRect对象。当使用代码来创建UI控件时,总需要控制UI控件的大小和位置,通常都会用CGRect结构体,它代表一个矩形区的大小和位置。CGRect结构体包括origin、size两个成员,其中origin又是CGPoint类型的一个结构体,它包括x、y两个成员,代表该矩形区左上角的位置;size又是CGSize类型的一个结构体,它包括width、height两个成员,代表该矩形区的宽度和高度。正如CGRectMake()函数可返回一个CGRect结构体一样,CGPointMake(x,y)可返回一个CGPoint结构体,CGSizeMake(width,height)可返回一个CGSize对结构体。 该应用的关键就是实现add:和remove:两个方法,其中add:方法中粗体字代码负责创建一个UILabel控件(每次创建的UILabel的Y坐标并不相同),并将这个UILabel控件添加到该控制器关联的UIView内。这样即可实现每次用户触碰该按钮,程序界面就会添加一个UILabel控件;而remove:方法中粗体字代码则负责把labels数组的最后一个元素(UILabel控件)从父控件中删除,并从该数组中删除该元素。 通过上面的程序,即可实现通过用户交互来动态添加、删除程序界面控件。编译、运行该程序,并多次触碰添加、删除按钮后,可能看到如图9.37所示的动态界面。 ![Uploading screenshot . . .]()

杨冬芳 2019-12-02 03:01:21 0 浏览量 回答数 0

问题

云效使用指南:持续交付:(待迁移)应用构建与发布

行者武松 2019-12-01 22:00:28 1443 浏览量 回答数 0

回答

浅谈Flutter框架原理及其生态圈 Flutter的锋芒 跨平台高性能的渲染引擎逐渐成为移动端、大前端领域的一个热点,作为其中的明星框架Flutter,经过近几年来的迅速发展,由极大的可能成为下一代跨端终端解决方案。自从2017 年 5 月,谷歌公司发布的了 Alpha 版本的 Flutter; 2018 年底 Flutter Live 发布的 1.0 版本;2019年7月发布1.5版本,截止今日(2020年2月)已经发布了v1.14.6 Beta版本。 在Flutter诞生之前,已经有许多跨平台UI框架的方案如Cordova、ReactNative、weex、uni-app、Hippy等,常见的需要处理兼容的终端平台也包括android、ios、web、Iot等,但是在大前端的浪潮下,对于企业和开发者来说开发效率和使用体验都十分重要,传统的做法莫过于分不同的团队开发不同的终端项目,如果还要继续向其他平台,拓展的话,我们需要付出的成本和时间将成倍增长。正因为如此,在这样的背景下,Flutter等跨端框架的兴起,从本质上讲,帮助开发者增加业务代码的复用率,减少因为要适配多个平台带来的工作量,从而降低开发成本、提高开发效率。 纵观已有的跨端方案,可以分为三类:Web 容器、泛 Web 容器、自绘引擎框架。 基于web容器即基于浏览器的跨平台也做得越来越好,自然管线也越来越短,与native的一些技术手段来实现性能上的相互补充。比如Egret、Cocos、Laya这些游戏引擎,它们在跨平台方面的做法多以Typescript编写,在iOS和安卓平台的各种浏览器中轻松的运行HTML5游戏,并在不同平台浏览器里提供近乎一致的用户体验,比如Egret还会提供高效的 JS-C Binding 编译机制,以满足游戏编译为原生格式的需求,不过大多数HTML游戏引擎也属于web容器这个范畴内。web容器框架也有一个明显的致命(在对体验&性能有较高要求的情况下)的缺点,那就是WebView的渲染效率和JavaScript执行性能太差。再加上Android各个系统版本和设备厂商的定制,很难保证所在所有设备上都能提供一致的体验。 泛 Web 容器框架比如ReactNative和Weex,即上层通过面向前端友好的UI,下层通过native的渲染形式,虽然同样使用类HTML+JS的UI构建逻辑,但是最终会生成对应的自定义原生控件,以充分利用原生控件相对于WebView的较高的绘制效率,同时H5与native相互补充来达到更好的用户体验,这也是一种很好的解决方案。缺陷也很明显,随着系统版本变化和API的变化,开发者可能也需要处理不同平台的差异,甚至有些特性只能在部分平台上实现,这样框架的跨平台特性就会大打折扣。 自绘引擎框架这里专指Flutter框架,从底层就承担跨端的任务和渲染方式,从目前来看,从技术的实现和方案的成熟度、产品的性能方面比较,Flutter有很大可能成为下一代主流跨平台框架。 Flutter与其他跨端框架的不同点之一就是自带渲染引擎,Flutter渲染引擎依靠跨平台的Skia图形库来实现,Skia引擎会将使用Dart语言构建的抽象的视图结构数据加工成GPU数据,交由 OpenGL 最终提供给 GPU 渲染,至此完成渲染闭环,因此可以在最大程度上保证一款应用在不同平台、不同设备上的体验一致性。 而开发语言选用的是同时支持 JIT和 AOT的 Dart语言,Dart本身提供了三种运行方式,应对web环境,用Dart2js编译成JavaScript代码,运行在常规浏览器中;使用DartVM直接在命令行中运行Dart代码;AOT方式编译成机器码,例如Flutter App框架。而且Dart 避免了抢占式调度和共享内存,可以在没有锁的情况下进行对象分配和垃圾回收,在性能方面表现相当不错,不仅保证了开发效率,代码性能和用户体验也更卓越。因此,Flutter在各类跨平台移动开发方案中脱颖而出。同时在去年2019的Google IO大会上,备受关注的Fuchsia系统虽然并没有发布,但是宣布了 Flutter除了支持开发 Android 和 iOS 程序之外,现在还支持开发Web程序了,在 I/O 大会上,谷歌发布了 Web 版 Flutter 的首个技术预览版,宣布 Flutter 将为包括 Google Home Hub 在内的 Google Smart Display 平台提供技术支持,并迈出利用 Chrome 操作系统支持桌面级应用的第一步。 很多JS开发者会思考Google Flutter团队至于为啥选择Dart而不是JS,其实Google 公司给出的原因很简单也很直接:Dart 语言开发组就在隔壁,对于 Flutter 需要的一些语言新特性,能够快速在语法层面落地实现;而如果选择了 JavaScript,就必须经过各种委员会(TC39等)和浏览器提供商漫长的决议。 Flutter绘制原理 在计算机系统中,图像的显示需要 CPU、GPU 和显示器一起配合完成:CPU 负责图像数据计算,GPU 负责图像数据渲染,而显示器则负责最终图像显示。 CPU 把计算好的、需要显示的内容交给 GPU,由 GPU 完成渲染后放入帧缓冲区,随后视频控制器根据垂直同步信号(VSync)以每秒 60 次的速度,从帧缓冲区读取帧数据交由显示器完成图像显示。 操作系统在呈现图像时遵循了这种机制,而 Flutter 作为跨平台开发框架也采用了这种底层方案。下面有一张更为详尽的示意图来解释 Flutter 的绘制原理。可以看到,Flutter 关注如何尽可能快地在两个硬件时钟的 VSync 信号之间计算并合成视图数据,然后通过 Skia 交给 GPU 渲染:UI 线程使用 Dart 来构建视图结构数据,这些数据会在 GPU 线程进行图层合成,随后交给 Skia 引擎加工成 GPU 数据,而这些数据会通过 OpenGL 最终提供给 GPU 渲染。 Skia原理 Skia 是一款用由C++ 开发的2D 图像绘制引擎。在2005 年被 Google 公司收购后被广泛应用在 Android和其他等核心产品上,Skia 目前是Android 官方的图像渲染引擎,因此 Flutter Android SDK 无需内嵌 Skia 引擎就可以获得天然的 Skia 支持;而对于 iOS 平台来说,由于 Skia 是跨平台的,因此它作为 Flutter iOS 渲染引擎被嵌入到 Flutter 的 iOS SDK 中,替代了 iOS 闭源的 Core Graphics/Core Animation/Core Text,这也正是 Flutter iOS SDK 打包的 App 包体积比 Android 要大一些的原因。 底层渲染能力统一了,上层开发接口和功能体验也就随即统一了,开发者再也不用操心平台相关的渲染特性了。也就是说,Skia 保证了同一套代码调用在 Android 和 iOS 平台上的渲染效果是完全一致的。 Flutter架构 Framework底层是Flutter引擎,引擎主要负责图形绘制(Skia)、文字排版(libtxt)和提供Dart运行时,引擎全部使用C++实现,Framework层使我们可以用Dart语言调用引擎的强大能力。Flutter 架构采用分层设计,从下到上分为三层,依次为:Embedder、Engine、Framework。 Embedder 是操作系统适配层,实现了渲染 Surface 设置,线程设置,以及平台插件等平台相关特性的适配。从这里我们可以看到,Flutter 平台相关特性并不多,这就使得从框架层面保持跨端一致性的成本相对较低。 Engine 层主要包含 Skia、Dart 和 Text,实现了 Flutter 的渲染引擎、文字排版、事件处理和 Dart 运行时等功能。Skia 和 Text 为上层接口提供了调用底层渲染和排版的能力,Dart 则为 Flutter 提供了运行时调用 Dart 和渲染引擎的能力。而 Engine 层的作用,则是将它们组合起来,从它们生成的数据中实现视图渲染。 Framework 层则是一个用 Dart 实现的 UI SDK,包含了动画、图形绘制和手势识别等功能。为了在绘制控件等固定样式的图形时提供更直观、更方便的接口,Flutter 还基于这些基础能力,根据 Material 和 Cupertino 两种视觉设计风格封装了一套 UI 组件库,开发者可以直接使用这些组件库。 Flutter运行流程 页面中的各界面元素(Widget)以树的形式组织,即控件树。Flutter 通过控件树中的每个控件创建不同类型的渲染对象,组成渲染对象树。在Flutter界面渲染过程分为三个阶段:布局、绘制、合成,布局和绘制在Flutter框架中完成,合成则交由引擎负责。 Flutter 采用深度优先机制遍历渲染对象树,决定渲染对象树中各渲染对象在屏幕上的位置和尺寸。在布局过程中,渲染对象树中的每个渲染对象都会接收父对象的布局约束参数,决定自己的大小,然后父对象按照控件逻辑决定各个子对象的位置,最终完成布局过程。这里只需要注意一点,无论布局还是绘制,都是父子间的遍历关系:父Widget的布局需要依赖子Widget的布局结果;而绘制则反过来(子Widget需要盖在父Widget上),布局是后续遍历,绘制是前序遍历,他们都是深度优先遍历。 Flutter生命周期 可以看到,Flutter中State 的生命周期可以分为 3 个阶段:创建(插入视图树)、更新(在视图树中存在)、销毁(从视图树中移除)。接下来,我们一起看看每一个阶段的具体流程。 第一步创建 State 初始化时会依次执行 :构造方法 -> initState -> didChangeDependencies -> build,随后完成页面渲染。构造方法是 State 生命周期的起点,Flutter 会通过调用StatefulWidget.createState() 来创建一个 State。我们可以通过构造方法,来接收父 Widget 传递的初始化 UI 配置数据。这些配置数据,决定了 Widget 最初的呈现效果。 initState,会在 State 对象被插入视图树的时候调用。这个函数在 State 的生命周期中只会被调用一次,所以我们可以在这里做一些初始化工作,比如为状态变量设定默认值。 didChangeDependencies 则用来专门处理 State 对象依赖关系变化,会在 initState() 调用结束后,被 Flutter 调用。 build,作用是构建视图。经过以上步骤,Framework 认为 State 已经准备好了,于是调用 build。我们需要在这个函数中,根据父 Widget 传递过来的初始化配置数据,以及 State 的当前状态,创建一个 Widget 然后返回。 第二步更新 Widget 的状态更新,主要由个方法触发:setState、didchangeDependencies、didUpdateWidget。 setState:我们最熟悉的方法之一。当状态数据发生变化时,我们总是通过调用这个方法告诉 Flutter:“我这儿的数据变啦,请使用更新后的数据重建 UI!” didChangeDependencies:State 对象的依赖关系发生变化后,Flutter 会回调这个方法,随后触发组件构建。哪些情况下 State 对象的依赖关系会发生变化呢?典型的场景是,系统语言 Locale 或应用主题改变时,系统会通知 State 执行 didChangeDependencies 回调方法。 didUpdateWidget:当 Widget 的配置发生变化时,比如,父 Widget 触发重建(即父 Widget 的状态发生变化时),热重载时,系统会调用这个函数。一旦这三个方法被调用,Flutter 随后就会销毁老 Widget,并调用 build 方法重建 Widget。 第三步销毁 比如组件被移除,或是页面销毁的时候,系统会调用 deactivate 和 dispose 这两个方法,来移除或销毁组件。 Flutter生态圈及其常用框架 一项技术一个框架是否流行,最直观的体现就是它的生态圈是否活跃,下面列举了一些Flutter开发中常用的库工具。 参考文献 1、[Flutter原理与实践](https://tech.meituan.com/2018/08/09/waimai-flutter-practice.html) 少杰 2、[Flutter框架技术概览](https://flutter.dev/docs/resources/technical-overview) 3、[Flutter中文官网](https://pub.dartlang.org/flutter/) 4、[Flutter插件仓库](https://pub.dev/flutter/packages)

罗思雨 2020-02-27 11:47:50 0 浏览量 回答数 0

回答

首先,我们要清楚的便是每个系统之间的差别,以及在阿里云上的差别: 1. Windows 1.1) 系统内含正版激活。 1.2) 适合于运行Windows下开发的程序,如.net等。 1.3) 支持SQL Server等数据库(需自行安装)。 1.4) 可以使用远程桌面方式登录进行管理。 注:512内存不支持选择Windows系统,1G以上内存才能很好支持该系统。 2. Linux 2.1.1) 最流行的服务器端操作系统,强大的安全性和稳定性。 2.1.2) 免费且开源,轻松建立和编译源代码。 2.1.3) 通过SSH方式远程访问您的云服务器。 2.1.4) 一般用于高性能web等服务器应用,支持常见的PHP/Python等编程语言,支持MySQL等数据库(需自行安装)。 2.2 CentOS (推荐)请使用yum方式在线安装软件。 2.3 Ubuntu请使用aptitude方式在线安装软件。 2.4 Debian请使用apt-get方式在线安装软件。 2.5 Aliyun Linux(兼容 Red Hat)请使用yum方式在线安装软件,yum源需要自行购买redhat的商业支持。 操作系统更换规则: 1.更换操作系统 更换系统之前请先停止云服务器,云服务器更换操作系统会直接重置系统盘【IP不变】,系统盘数据将会丢失! 请您注意: 1.1. 更换操作系统会使云服务器的系统盘更换为新的镜像,原有系统盘的数据都会丢失。 1.2. 云服务器数据盘的数据不会受到影响。 1.3. 建议您将系统盘的个人数据备份到数据盘中,或采用其他方式进行备份。 1.4. 因您没有备份系统盘相关个人数据而造成的数据丢失,阿里云不承担责任。 1.5. 内存为512M云服务器不支持更换Windows操作系统。 2. CPU/内存与操作系统的选择 2.1)如需选择/变更4G以上内存请您选择64位操作系统(32位操作系统存在寻址限制)。 2.2) 如您选择32位操作系统,4G以上内存页面暂不展示,只有云服务器更换为64位操作系统才可展示。 2.3)Windows 32位操作系统支持最高CPU为4核。 2.4)配置:[CPU:1核;内存:512M] 的云服务器不支持选择/更换Windows操作系统。 Windows篇 阿里云提供了6种window系统,涵盖了Server 2003 sp2以及Server 2008 R2这两大类操作系统。 其中又分为了32位和64位 (1)如何选择32位还是64位 32位系统相比64位系统,最主要的限制体现在内存的大小上。因为32位本身的限制,其最大只可支持到4GB内存,如果您的网站要使用高于4GB的内存或者以后有扩充内存寻到4GB以上的打算,请使用64位操作系统。 (2)选择2003还是选择2008 对于windows来说,我个人建议是选择版本越高的越好。相对来说新版本漏洞相对来说更少,而且IIS 7.5相对于IIS6提供了更多的功能以及更方便的控制台。但是考虑到大家的机器配置不同,在此给出一下几种选择: A:配置低于双核 2GB内存:选择server2003 不装数据库配置双核4GB: server 2003 mssql 或者 server 2008 R2 不带数据库 B:配置高于双核 8GB:serever 2008 R2 mssql 建议如果大家要在云服务器上跑数据库,尽量选择大内存配置,或者降低配置去选用RDS (3)中英文、安全加固版如何选择 这个就依据大家各自的喜好来了,在此不多说了至于Windows服务器配置教程,因为网上教程很多而且相对于Linux来说Windows配置难度更低,所以Windows的配置教程会比较晚的放出。 Linux篇 (1)这些linux大类有什么区别 Debian:用的deb包,使用APT包管理系统。 同时Debian提供了大多数软件比较新的版本,并且提供了更多的软件包(相对于原版Red Hat)。Debian的优点在于更新迅速,软件包完善(Ubuntu尤其),操作便利。缺点是部分时候稳定性欠佳,跟进最新软件有可能存在Bug。 Centos:用rpm包,使用yum包管理系统。 相对于Debian来说,Centost的一大特点就是慢。大部分软件停留在稳定版本,而且相距最新版版本也差较多。而且某些新版软件的一些新特性支持也比较慢,比如php-fpm。 因为Centos是面向企业用户提供的操作系统,所以在稳定性上十分突出,一般在新功能或稳定性的选择上更倾向于后者。只有当某个功能完全确定稳定了,才会加入到系统里。优点是系统稳定,技术文档完善,如果付费的话能得到企业级别的技术支持。缺点是软件包比较老旧,而且一些较新功能会欠缺。 总结一下:如果你喜欢尝鲜,喜欢用最新的功能或喜欢折腾系统,那么Debian是个更好的选择。 上手难度 Ubunt<Debian<Redhat=Centos (2)Debian与Ubuntu的选择 Ubuntu是基于Debian所开发,可以简单地认为Ubuntu是Debian的功能加强版。 与Debian相比,Ubuntu提供了更人性化系统配置,更强大的系统操作以及比Debian更激进的软件更新。 Ubuntu与Debian比较,可以认为Debian更趋向于保守一些,Ubuntu对新手友好度更高,上手更容易。 用过Ubuntu的都会体会到它的易用,反之如果用过Ubuntu再换到别的系统,都会觉得不适应,Ubuntu真的很方便。 个人建议,如果你打算选择Debian类的,建议选择Ubuntu。 Ubuntu提供了更好的操作,更激进的软件更新,更方便管理软件以及相差无几的稳定性。 如果你不想放弃稳定,那么请选择Debian。 关于Ubuntu版本选择: 在此解释下Ubuntu的版本支持时间。Ubuntu普通版本只提供18个月的技术支持,过期则不管。 服务器版本提供长达五年的技术支持。所以建议大家选择12.04 版,提供长达5年的技术支持,可以确保在静候相当长的一段时间内你的服务器可以继续收到系统升级补丁以及可用的软件源。 (3) Centos 的选择 对于阿里云Centos的选择,建议选择Centos 6.5版本,带来了更多的新特性以及更多的新功能。 除非你的软件需要php 5.1的环境,那么就选择Centos6.5。如果网站需要支持php5.1,只能选用Centos 5.8。 至于具体版本选择,建议php 5.1用户选择Centos 5.8,其他的用户则为Centos 6.5。 答案来源网络,供您参考

问问小秘 2019-12-02 02:13:05 0 浏览量 回答数 0

回答

1.   【初级】下面属于关键字的是() A. func B. def C. struct D. class 参考答案:AC   2.   【初级】定义一个包内全局字符串变量,下面语法正确的是() A. var str string B. str := "" C. str = "" D. var str = "" 参考答案:AD   3.   【初级】通过指针变量 p 访问其成员变量 name,下面语法正确的是() A. p.name B. (*p).name C. (&p).name D. p->name 参考答案:AB   4.   【初级】关于接口和类的说法,下面说法正确的是() A. 一个类只需要实现了接口要求的所有函数,我们就说这个类实现了该接口 B. 实现类的时候,只需要关心自己应该提供哪些方法,不用再纠结接口需要拆得多细才合理 C. 类实现接口时,需要导入接口所在的包 D. 接口由使用方按自身需求来定义,使用方无需关心是否有其他模块定义过类似的接口 参考答案:ABD   5.   【初级】关于字符串连接,下面语法正确的是() A. str := ‘abc’ + ‘123’ B. str := "abc" + "123" C. str := '123' + "abc" D. fmt.Sprintf("abc%d", 123) 参考答案:BD   6.   【初级】关于协程,下面说法正确是() A. 协程和线程都可以实现程序的并发执行 B. 线程比协程更轻量级 C. 协程不存在死锁问题 D. 通过channel来进行协程间的通信 参考答案:AD   7.   【中级】关于init函数,下面说法正确的是() A. 一个包中,可以包含多个init函数 B. 程序编译时,先执行导入包的init函数,再执行本包内的init函数 C. main包中,不能有init函数 D. init函数可以被其他函数调用 参考答案:AB   8.   【初级】关于循环语句,下面说法正确的有() A. 循环语句既支持for关键字,也支持while和do-while B. 关键字for的基本使用方法与C/C++中没有任何差异 C. for循环支持continue和break来控制循环,但是它提供了一个更高级的break,可以选择中断哪一个循环 D. for循环不支持以逗号为间隔的多个赋值语句,必须使用平行赋值的方式来初始化多个变量  参考答案:CD   9.   【中级】对于函数定义: func add(args ...int) int {  sum :=0  for _,arg := range args {     sum += arg  }  returnsum } 下面对add函数调用正确的是() A. add(1, 2) B. add(1, 3, 7) C. add([]int{1, 2}) D. add([]int{1, 3, 7}...) 参考答案:ABD   【初级】关于类型转化,下面语法正确的是() A. type MyInt int var i int = 1 var jMyInt = i B. type MyIntint var i int= 1 var jMyInt = (MyInt)i C. type MyIntint var i int= 1 var jMyInt = MyInt(i) D. type MyIntint var i int= 1 var jMyInt = i.(MyInt) 参考答案:C   【初级】关于局部变量的初始化,下面正确的使用方式是() A. var i int = 10 B. var i = 10 C. i := 10 D. i = 10 参考答案:ABC   【初级】关于const常量定义,下面正确的使用方式是() A. const Pi float64 = 3.14159265358979323846 const zero= 0.0 B. const ( size int64= 1024 eof = -1 ) C. const ( ERR_ELEM_EXISTerror = errors.New("element already exists") ERR_ELEM_NT_EXISTerror = errors.New("element not exists") ) D. const u, vfloat32 = 0, 3 const a,b, c = 3, 4, "foo" 参考答案:ABD   【初级】关于布尔变量b的赋值,下面错误的用法是() A. b = true B. b = 1 C. b = bool(1) D. b = (1 == 2) 参考答案:BC   【中级】下面的程序的运行结果是() func main() {   if (true) {    defer fmt.Printf("1") } else {    defer fmt.Printf("2") } fmt.Printf("3") } A. 321 B. 32 C. 31 D. 13 参考答案:C   【初级】关于switch语句,下面说法正确的有() A. 条件表达式必须为常量或者整数 B. 单个case中,可以出现多个结果选项 C. 需要用break来明确退出一个case D. 只有在case中明确添加fallthrough关键字,才会继续执行紧跟的下一个case 参考答案:BD   【中级】 golang中没有隐藏的this指针,这句话的含义是() A. 方法施加的对象显式传递,没有被隐藏起来 B. golang沿袭了传统面向对象编程中的诸多概念,比如继承、虚函数和构造函数 C. golang的面向对象表达更直观,对于面向过程只是换了一种语法形式来表达 D. 方法施加的对象不需要非得是指针,也不用非得叫this 参考答案:ACD   【中级】 golang中的引用类型包括() A. 数组切片 B. map C. channel D. interface 参考答案:ABCD   【中级】 golang中的指针运算包括() A. 可以对指针进行自增或自减运算 B. 可以通过“&”取指针的地址 C. 可以通过“*”取指针指向的数据 D. 可以对指针进行下标运算 参考答案:BC   【初级】关于main函数(可执行程序的执行起点),下面说法正确的是() A. main函数不能带参数 B. main函数不能定义返回值 C. main函数所在的包必须为main包 D. main函数中可以使用flag包来获取和解析命令行参数 参考答案:ABCD   【中级】下面赋值正确的是() A. var x = nil B. var x interface{} = nil C. var x string = nil D. var x error = nil 参考答案:BD   【中级】关于整型切片的初始化,下面正确的是() A. s := make([]int) B. s := make([]int, 0) C. s := make([]int, 5, 10) D. s := []int{1, 2, 3, 4, 5} 参考答案:BCD   【中级】从切片中删除一个元素,下面的算法实现正确的是() A. func (s *Slice)Remove(value interface{})error { for i, v := range *s {    if isEqual(value, v) {        if i== len(*s) - 1 {            *s = (*s)[:i]        }else {            *s = append((*s)[:i],(*s)[i + 2:]...)        }        return nil    } } return ERR_ELEM_NT_EXIST } B. func (s*Slice)Remove(value interface{}) error { for i, v:= range *s {     if isEqual(value, v) {         *s =append((*s)[:i],(*s)[i + 1:])         return nil     } } returnERR_ELEM_NT_EXIST } C. func (s*Slice)Remove(value interface{}) error { for i, v:= range *s {     if isEqual(value, v) {         delete(*s, v)         return nil     } } returnERR_ELEM_NT_EXIST } D. func (s*Slice)Remove(value interface{}) error { for i, v:= range *s {     if isEqual(value, v) {         *s =append((*s)[:i],(*s)[i + 1:]...)         return nil     } } returnERR_ELEM_NT_EXIST } 参考答案:D   【初级】对于局部变量整型切片x的赋值,下面定义正确的是() A. x := []int{ 1, 2, 3, 4, 5, 6, } B. x :=[]int{ 1, 2, 3, 4, 5, 6 } C. x :=[]int{ 1, 2, 3, 4, 5, 6} D. x :=[]int{1, 2, 3, 4, 5, 6,} 参考答案:ACD   【初级】关于变量的自增和自减操作,下面语句正确的是() A. i := 1 i++ B. i := 1 j = i++ C. i := 1 ++i D. i := 1 i-- 参考答案:AD   【中级】关于函数声明,下面语法错误的是() A. func f(a, b int) (value int, err error) B. func f(a int, b int) (value int, err error) C. func f(a, b int) (value int, error) D. func f(a int, b int) (int, int, error) 参考答案:C   【中级】如果Add函数的调用代码为: func main() { var a Integer = 1 var b Integer = 2 var i interface{} = &a sum := i.(*Integer).Add(b) fmt.Println(sum) } 则Add函数定义正确的是() A. typeInteger int func (aInteger) Add(b Integer) Integer {  return a + b } B. typeInteger int func (aInteger) Add(b *Integer) Integer {  return a + *b } C. typeInteger int func (a*Integer) Add(b Integer) Integer {  return *a + b } D. typeInteger int func (a*Integer) Add(b *Integer) Integer {  return *a + *b } 参考答案:AC   【中级】如果Add函数的调用代码为: func main() { var a Integer = 1 var b Integer = 2 var i interface{} = a sum := i.(Integer).Add(b) fmt.Println(sum) } 则Add函数定义正确的是() A. typeInteger int func (a Integer)Add(b Integer) Integer {  return a + b } B. typeInteger int func (aInteger) Add(b *Integer) Integer {  return a + *b } C. typeInteger int func (a*Integer) Add(b Integer) Integer {  return *a + b } D. typeInteger int func (a*Integer) Add(b *Integer) Integer {  return *a + *b } 参考答案:A   【中级】关于GetPodAction定义,下面赋值正确的是() type Fragment interface { Exec(transInfo *TransInfo) error } type GetPodAction struct { } func (g GetPodAction) Exec(transInfo*TransInfo) error { ... return nil } A. var fragment Fragment =new(GetPodAction) B. var fragment Fragment = GetPodAction C. var fragment Fragment = &GetPodAction{} D. var fragment Fragment = GetPodAction{} 参考答案:ACD   【中级】关于GoMock,下面说法正确的是() A. GoMock可以对interface打桩 B. GoMock可以对类的成员函数打桩 C. GoMock可以对函数打桩 D. GoMock打桩后的依赖注入可以通过GoStub完成 参考答案:AD   【中级】关于接口,下面说法正确的是() A. 只要两个接口拥有相同的方法列表(次序不同不要紧),那么它们就是等价的,可以相互赋值 B. 如果接口A的方法列表是接口B的方法列表的子集,那么接口B可以赋值给接口A C. 接口查询是否成功,要在运行期才能够确定 D. 接口赋值是否可行,要在运行期才能够确定 参考答案:ABC   【初级】关于channel,下面语法正确的是() A. var ch chan int B. ch := make(chan int) C. <- ch D. ch <- 参考答案:ABC   【初级】关于同步锁,下面说法正确的是() A. 当一个goroutine获得了Mutex后,其他goroutine就只能乖乖的等待,除非该goroutine释放这个Mutex B. RWMutex在读锁占用的情况下,会阻止写,但不阻止读 C. RWMutex在写锁占用情况下,会阻止任何其他goroutine(无论读和写)进来,整个锁相当于由该goroutine独占 D. Lock()操作需要保证有Unlock()或RUnlock()调用与之对应 参考答案:ABC   【中级】 golang中大多数数据类型都可以转化为有效的JSON文本,下面几种类型除外() A. 指针 B. channel C. complex D. 函数 参考答案:BCD   【中级】关于go vendor,下面说法正确的是() A. 基本思路是将引用的外部包的源代码放在当前工程的vendor目录下面 B. 编译go代码会优先从vendor目录先寻找依赖包 C. 可以指定引用某个特定版本的外部包 D. 有了vendor目录后,打包当前的工程代码到其他机器的$GOPATH/src下都可以通过编译 参考答案:ABD   【初级】 flag是bool型变量,下面if表达式符合编码规范的是() A. if flag == 1 B. if flag C. if flag == false D. if !flag 参考答案:BD   【初级】 value是整型变量,下面if表达式符合编码规范的是() A. if value == 0 B. if value C. if value != 0 D. if !value 参考答案:AC   【中级】关于函数返回值的错误设计,下面说法正确的是() A. 如果失败原因只有一个,则返回bool B. 如果失败原因超过一个,则返回error C. 如果没有失败原因,则不返回bool或error D. 如果重试几次可以避免失败,则不要立即返回bool或error 参考答案:ABCD   【中级】关于异常设计,下面说法正确的是() A. 在程序开发阶段,坚持速错,让程序异常崩溃 B. 在程序部署后,应恢复异常避免程序终止 C. 一切皆错误,不用进行异常设计 D. 对于不应该出现的分支,使用异常处理 参考答案:ABD   【中级】关于slice或map操作,下面正确的是() A. var s []int s =append(s,1) B. var mmap[string]int m["one"]= 1 C. var s[]int s =make([]int, 0) s =append(s,1) D. var mmap[string]int m =make(map[string]int) m["one"]= 1 参考答案:ACD   【中级】关于channel的特性,下面说法正确的是() A. 给一个 nil channel 发送数据,造成永远阻塞 B. 从一个 nil channel 接收数据,造成永远阻塞 C. 给一个已经关闭的 channel 发送数据,引起 panic D. 从一个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回一个零值 参考答案:ABCD   【中级】关于无缓冲和有冲突的channel,下面说法正确的是() A. 无缓冲的channel是默认的缓冲为1的channel B. 无缓冲的channel和有缓冲的channel都是同步的 C. 无缓冲的channel和有缓冲的channel都是非同步的 D. 无缓冲的channel是同步的,而有缓冲的channel是非同步的 参考答案:D   【中级】关于异常的触发,下面说法正确的是() A. 空指针解析 B. 下标越界 C. 除数为0 D. 调用panic函数 参考答案:ABCD   【中级】关于cap函数的适用类型,下面说法正确的是() A. array B. slice C. map D. channel 参考答案:ABD   【中级】关于beego框架,下面说法正确的是() A. beego是一个golang实现的轻量级HTTP框架 B. beego可以通过注释路由、正则路由等多种方式完成url路由注入 C. 可以使用bee new工具生成空工程,然后使用bee run命令自动热编译 D. beego框架只提供了对url路由的处理,而对于MVC架构中的数据库部分未提供框架支持 参考答案:ABC   【中级】关于goconvey,下面说法正确的是() A. goconvey是一个支持golang的单元测试框架 B. goconvey能够自动监控文件修改并启动测试,并可以将测试结果实时输出到web界面 C. goconvey提供了丰富的断言简化测试用例的编写 D. goconvey无法与go test集成 参考答案:ABC   【中级】关于go vet,下面说法正确的是() A. go vet是golang自带工具go tool vet的封装 B. 当执行go vet database时,可以对database所在目录下的所有子文件夹进行递归检测 C. go vet可以使用绝对路径、相对路径或相对GOPATH的路径指定待检测的包 D. go vet可以检测出死代码 参考答案:ACD   100.             【中级】关于map,下面说法正确的是() A. map反序列化时json.unmarshal的入参必须为map的地址 B. 在函数调用中传递map,则子函数中对map元素的增加不会导致父函数中map的修改 C. 在函数调用中传递map,则子函数中对map元素的修改不会导致父函数中map的修改 D. 不能使用内置函数delete删除map的元素 参考答案:A 101.             【中级】关于GoStub,下面说法正确的是() A. GoStub可以对全局变量打桩 B. GoStub可以对函数打桩 C. GoStub可以对类的成员方法打桩 D. GoStub可以打动态桩,比如对一个函数打桩后,多次调用该函数会有不同的行为 参考答案:ABD   102.             【初级】关于select机制,下面说法正确的是() A. select机制用来处理异步IO问题 B. select机制最大的一条限制就是每个case语句里必须是一个IO操作 C. golang在语言级别支持select关键字 D. select关键字的用法与switch语句非常类似,后面要带判断条件 参考答案:ABC   103.             【初级】关于内存泄露,下面说法正确的是() A. golang有自动垃圾回收,不存在内存泄露 B. golang中检测内存泄露主要依靠的是pprof包 C. 内存泄露可以在编译阶段发现 D. 应定期使用浏览器来查看系统的实时内存信息,及时发现内存泄露问题 参考答案:BD   ———————————————— 原文链接:https://blog.csdn.net/itcastcpp/article/details/80462619 ————————————————

剑曼红尘 2020-03-09 10:46:25 0 浏览量 回答数 0

问题

Git 改变了分布式 Web 开发规则:报错

kun坤 2020-06-08 11:09:24 3 浏览量 回答数 1

回答

先说结论: 不要对接!不要对接!不要对接! 开个玩笑,以上仅代表个人观点,大家也知道这种“三体式警告”根本没有用的,我自己也研究如何对接,说不定做完后就觉得“真香”了。 为什么要对接? 首先讨论一下为什么要把 Flutter 对接到 Web 生态。 Flutter 现在是一个炙手可热的跨平台技术,能够一套代码运行在 Android、iOS、PC、IoT 以及浏览器上,被认为是下一代跨平台技术。相比于 Weex 和 React Native 可以很好地解决多平台一致性问题,原生渲染性能相近,上层没有 JS 那么厚的封装层次,整体性能会略好一些。 但是大部分兴冲冲去学 Flutter 的人疑惑的第一个问题就是:为什么 Flutter 要用 Dart?一个全新的语言意味着新的学习成本,难道 JS 不香吗?JS 不香不是还有 TypeScript 吗!事实上 Flutter 抛弃的岂止是 JS 这门语言,也抛弃了 HTML 和 CSS,设计了一套解耦得更好的 Widget 体系,Flutter 抛弃的是整个 Web,致力于打造一个新的生态,但是这个生态无法复用 Web 生态的代码和解决方案。尤其是之前所有跨平台方案 Hybrid、React Native、Weex 都是对接 Web 生态的,这让 Flutter 显得有些格格不入,也让大部分前端开发者望而却步。 下面是我整理出来的,前端开发者使用 Flutter 的各方面成本: 因为 Flutter 的开发模式和前端框架比较像(可以说就是抄的 React),所以框架的学习成本并不高,稍微高一些的是 Dart 语言的学习成本,另外还要学习如何用 Widget 组装 UI,虽然很多布局 Widget 设计得和 CSS 很像,灵活度还是差了很多。要想在真实项目中用起来,还要改造整个工具链,以“Native First”的视角做开发,开发 Flutter 和开发原生应用的链路是比较像的,和开发前端页面有较大差异。最高的还是生态成本,前端生态的积累无论是代码还是技术方案都很难复用,这是最痛的一点,生态也是 Flutter 最弱的一环。 无论是为了先进的技术理念还是出于商业私心,先不管 Flutter 为什么抛弃 Web 生态,现实问题是最大的 UI 开发者群体是前端,最丰富的生态是 Web 生态,我觉得 Web 技术也是开发 UI 最高效的方式。如果能在上层使用 Web 技术栈开发,在底层使用 Flutter 实现跨平台渲染,不是可以很好的兼顾开发效率、性能和跨平台一致性吗?还能复用 Web 技术栈大量的技术积累。 可能这些理由也不够充分,暂且先照着这个假设继续分析,最后再重新讨论到底该不该对接。 关于 Flutter 和 Web 生态的对接涉及两个方面: 从 Web 到 Flutter。就是使用 Web 技术栈来开发,然后对接到 Flutter 上实现跨平台渲染。对 Web 来说是解决性能和跨平台一致性问题,对 Flutter 来说是解决生态复用问题。从 Flutter 到 Web。就是官方已经实现的 Web support for Flutter,把已经用 Dart 开发好的 App 编译成 HTML/JS/CSS 然后运行在浏览器上,可以用于降级和外投场景。 如何实现“从 Web 到 Flutter”? 首先分析一下 Flutter 的架构图,看看可以从哪里下手。 Flutter 可以分为 Framework 和 Engine 两部分,Engine 部分比较底层也比较稳定了,最好不要动,需要改的是用 Dart 实现的 Framework。要想对接 Web 生态的话,JS 引擎肯定是要引入的,至于是否保留 Dart VM 有待讨论。图中最上面 Material 和 Cupertino 两个 UI 库前端是不需要的,前端有自己的。关键是 Widget 这部分,是替换成 HTML/CSS 的方式写 UI,还是继续保留 Widget 但是把语言换成 JS,不同方案给出的解法也不一样。 有不少方案可以实现对接,业界有挺多尝试的,我总结了下面三种方式: - TS 魔改:用 JS 引擎替换掉 Dart VM,用 JS/TS 重新实现 Flutter Framework(或者直接 dart2js 编译过来)。 - JS 对接:引入 JS 引擎同时保留 Dart VM,用前端框架对接 Flutter Framework。 - C++ 魔改:用 JS 引擎替换掉 Dart VM,用 C++ 重新实现 Flutter Framework。 TS 魔改 TS 魔改就是完全抛弃掉 Dart VM,用 TypeScript 重新实现一遍用 Dart 写的 Flutter Framework。 为啥是 TS 而不是 JS?这不是因为 TS 是个大热门嘛,而且向下兼容 JS,现在几乎所有时髦的框架都要用 TS 重写了。 这种方案的出发点是“如果能把 Flutter 的 Dart 换成 JS 就好了”,最容易想到的路就是把 Dart 翻译成 TS,或者直接用 dart2js 把代码编译成 js,但是编译出来的代码包含很多 dart:ui 之类的库的封装,生成的包也挺大的,也比较难定制需要导出的接口,不如干脆用 TS 重写一遍,工具链更熟悉一些,还可以加一些定制。 理论上讲翻译之后 Flutter 绝大部分功能都依然支持,可以复用各种 npm 包,还可以动态化,但是丧失了 AOT 能力,JS 语言的执行性能应该是不如 Dart 的。而且所有节点的布局运算都发生在 JS,底层只需要提供基础的图形能力就好了,就好像是基于 Canvas API 写了一套 UI 框架,性能未必有现存前端框架的性能高。 此外最大的问题是如何与官方 Flutter 保持一致,假如现在是从 v1.13 版本翻译过来的,以后官方升级到了 v1.15 要不要同步更新?这个过程没啥技术含量,而且需要持续投入,做起来比较恶心。 另外还需要考虑上层是用 Widget 的方式写 UI,还是用前端熟悉的 HTML+CSS。如果依然用 Widget 的话,那大部分前端组件还是用不了的,UI 还是得重写一遍。反正要重写的话,成本也没降下来,那就用 Dart 重写呗…… 直接用官方原版 Flutter 也避免每次更新都要翻译一遍 Dart 代码。所以既然选择了对接前端生态,那就要对接 CSS,不然就没有足够的价值。然而 CSS 和 Widget 的对接也是很繁琐的过程,而且存在完备性问题。 JS 对接 翻译代码的方式不够优雅,那就保留 Dart,把 JS/CSS 对接到 Widget 上面不就好了? 当然可以,这种方式是仅把 Flutter 当做了底层的渲染引擎,上层保持前端框架的写法,仅把渲染部分对接到 Flutter。现存的很多前端框架都把底层渲染能力做了抽象,可以对接到不同渲染引擎上,如 Vue/Rax 同时支持浏览器和 Weex,用同样的方式,可以再支持一个 Flutter。 这种方式对前端框架的兼容性比较好,但是链路太长了,业务代码调用前端框架接口做渲染,一顿操作之后发出了渲染指令,这个渲染指令要基于通信的方式传给 Flutter Framework,这中间涉及一次 JS 到 C++ 再到 Dart 的跨语言转换,然后再接收到渲染指令之后还要转成相应的 Widget 树,从 CSS 到 Widget 的转换依然很繁琐。而且 Widget 本身是可以带有状态的,本身就是响应式更新的,在更新时会重新生成 widget 并 diff,如果在前端更新 UI 的话,前端框架在 js 里 diff 一次 vdom,传到 Flutter 之后又 diff 一次 widget。 如果要绕过 Widget 直接对接图中的 Rendering 这一层,可以绕过 widget diff 但是得改 Flutter Framework 的渲染链路,既然要改 Flutter Framework 那为什么不直接用 TS 魔改呢,还绕过了 JS 到 Dart 的通信,又回到了第一种方案。 总结来说,这个方案的优点是:实现简单、能最大化保留前端开发体验,缺点是:渲染链路长、通信成本高、响应式逻辑冲突、CSS 转 Widget 不完备等。 C++ 魔改 想要干掉 Dart VM,就需要用其他语言重新实现用 Dart 开发的 Framework,用 JS/TS 可以,用 C++ 当然可以,最硬核的方式就是用 C++ 重新实现 Flutter 的 Framework,然后接入 JS 引擎,通过 binding 把 C++ 接口透出到 JS 环境,上层应用还是用 JS 做开发。 把 Framework 层下沉到 C++ 之后,不仅会有更好的性能,也能支持更多语言。原本 Flutter Framework 是在 Dart VM 之上的,必须依赖 Dart VM 才能运行,所以对 Dart 有强依赖;用 C++ 重新实现之后,JS 引擎是在 C++ 版 Framework 之上的,框架本身并不依赖 JS 引擎,还可以对接其他各种语言,如对接了 JVM 之后可以支持 Java 和 Kotlin,对接回 Dart VM 可以继续支持 Dart。 这个方案可以增强性能,也能保持和 Flutter 的一致性,但是改造成本和维护成本都相当高。C++ 的开发效率肯定不如 Dart,当 Flutter 快速迭代之后如何跟进是很大的问题,如果跟进不及时或者实现不一致那很可能就分化了。从 CSS 到 Widget 的转换也是不得不面对的问题。 几种方案对比 把上面几种方案画在同一张图里是这个样子的: 图中实线部分表示了跨语言的通信,太过频繁会影响性能,虚线部分表示了其他对接可能性。 从下到上,Flutter Engine 是不需要动的,这一层是跨平台的关键。Framework 则有三种语言版本,JS/TS、Dart、C++,性能是 C++ 版本最好,成本是 Dart 版本最低。然后还需要向上处理 HTML/CSS 和 Widget 的问题,可以直接对接一个前端框架,也可以直接在 C++ 层实现(不然需要透出的 binding 接口就太多了,用通信的方式也太过频繁了)。 如何实现“从 Flutter 到 Web”? 这个功能官方已经实现了,可以把使用 Dart 开发的 App 编译成 Web App 运行在浏览器上,官方文档以介绍用法和 API 为主,我这里简单分析一下内部具体的实现方案。 实现原理 结合 Flutter 的架构图来看,要实现 Web 到 Flutter 需要改造的是上层 Framework,要实现 Flutter 到 Web 需要改造的则是底层 Engine。 Framework 对 Engine 的核心依赖是 dart:ui,这是库是在 Engine 里实现的,抽象出了绘制 UI 图层的接口,底层对接 skia 的实现,向上透出 Dart 语言的接口。这样来看,对接方式就比较简单了: 使用 dart2js 把 Framework 编译成 JS 代码。基于浏览器的 API 重新实现 dart:ui,即 dart:web_ui。 把 Dart 编译成 JS 没什么问题,性能可能会有一点影响,功能都是可以完全保留的,关键是 dart:web_ui 的实现。在原生 Engine 中,dart:ui 依赖 skia 透出的 SkCanvas 实现绘制,这是一套很底层的图形接口,只定义了画线、画多边形、贴图之类的底层能力,用浏览器接口实现这一套接口还是很有挑战的。上图可以看到 Web 版 Engine 是基于 DOM 和 Canvas 实现的,底层定义了 DomCanvas 和 BitmapCanvas 两种图形接口,会把传来的 layer tree 渲染成浏览器的 Element tree,但是节点上仅包含了 position, transform, opacity 之类的样式,只用到 CSS 很小的一个子集,一些更复杂的绘制直接用 2D canvas 实现。 存在的问题 我编译了一个还算复杂的 demo 试了一下,性能很不理想,滑动不流畅,有时候图片还会闪动。生成出来的 js 代码有 1.1MB (minify 之后,未 gzip),节点层次也比较深,我评估这个页面用前端写不会超过 300KB,节点数可以少一半以上。 另外再看一下 Flutter 仓库的 issue,过滤出 platfrom-web 相关的,可以看到大量:文字编辑失效、找不到光标、ListView 在 ios 上不可滚动、checkbox/button 行为不正常、安卓滚动卡顿图片闪烁、字体失效、某些机型视频无法播放、文字选中后无法复制、无法调试…… 感觉 flutter for web 已经陷入泥潭,让人回想起前端当年处理各种浏览器兼容性的噩梦。 这些性能和兼容性问题,核心原因是浏览器未暴露足够的底层能力,以及浏览器处理手势、用户输入和方式和 Flutter 差异巨大。 实现 Flutter Engine 需要的是底层的图形接口和系统能力,虽然canvas 提供了相似的图形接口,如果全部用 canvas 实现的话很难处理可访问性、文本选择、手势、表单等问题,也会存在很多兼容性问题。所以真实方案里用的是 Canvas + DOM 混合的方式,封装层次太高了,渲染链路太长。就好像 Flutter Framework 里进行了一顿猛如虎的操作之后,节点生成好了、布局算好了、绘制属性也处理好了,就差一个画布画出来了,然后交到浏览器手里,又生成一遍 Element,再算一遍布局,在处理一遍绘制,最终才交给了底层的图形库画出来。 再比如长页面的滚动,浏览器里只要一条 CSS (overflow:scroll) 就可以让元素可滚动,手势的监听以及页面的滚动以及滚动动画都是浏览器原生实现的,不需要与 JS 交互,甚至不需要重新 layout 和 paint,只需要 compositing。如上图所示,在 Flutter 中 Animation 和 Gesture 是用 Dart 实现的,编译过来就是 JS 实现的,浏览器本身并不知道这个元素是否可滚,只是不断派发 touchmove 事件,JS 根据事件属性计算节点偏移,然后运算动画,然后把 transform 或者新的 position 作用到节点上,然后浏览器再来一遍完整的渲染流程…… 优化方案 性能和兼容性的问题还是要解决的,短期内先把 issue 解掉,长线的优化方案,官方有两种尝试: 使用 CSS Painting API 做绘制。 a, 这是还处于提案状态的新标准,可以用 JS 实现一些绘制功能,自定义 CSS 属性。 b. 目前还未实现,需要等浏览器先把 CSS Houdini 支持好。 使用 WebAssembly 版本的 Skia 做绘制 https://skia.org/user/modules/canvaskit a, 这样可以发挥 wasm 的性能优势,并且保持 skia 功能的一致。但是目前 wasm 在浏览器环境里未必有性能优势,这里不展开讨论了。 b. 已经部分实现,参考这里的配置启用功能: https://github.com/flutter/flutter/issues/41062#issuecomment-533952994 这两个方案都是想更多的利用到浏览器的底层能力,只有浏览器暴露了更多底层能力,才能更好的实现 Flutter 的 Web Engine。不过这个要等挺久的时间,我们也参与不了,现阶段想要使用 flutter for web,还是得保持现有架构,一起参与进去把 issue 解决掉,优先保障功能,其次优化性能。 一种适应性更好的架构 如果理想化一点,能不能从架构角度让 Flutter 和 Web 生态融合的更好一些呢? 回顾文章最开始的官方架构图,上面是 Framework(Dart),下面是 Engine(C++),切分在 Foundation 这一层,双方之间的交互是几何图形信息。如果还保持这个架构,把切分层次划分的更靠上一些,如下图所示,划分在 Widgets 和 Rendering 这一层,理论上讲对 Flutter 的开发者来说是无感知的,因为上层的开发语言和 Widget 接口都是不变的。 切分在这一层,Framework 和 Engine 之间的交互就不再是几何图形而是节点信息,Widget 的组合、setState 响应式更新、Widget diff 都还在 Dart 中,展开后的 RenderObject 的布局、绘制、裁剪、动画全都在 C++ 中,不仅有更好的性能,还可以与 Engine 有更好的结合。 或者说,还原本保留 Engine 的设计,把下沉的这部分逻辑上划分成 Renderer,就有了如下三层的结构: 这样划分出来的每一层都有明确的定位: Framework: 开发框架。为开发者提供可编程 API,实现响应式的开发模式,提供细粒度 Widget 供开发者自由封装和组合。Renderer: 渲染引擎。专门实现布局、绘制、动画、手势的的处理,这部分功能相对独立,是可以与开发框架解耦的,也不必与特定语言绑定。Engine: 图形引擎。实现跨平台一致的图形接口,合成输入的层并绘制到屏幕上,处理好平台力的接入和适配。 这样切分除了有性能优势以外,也使得渲染引擎摆脱了对 Dart 的依赖,能够支持多种语言,也能支持多种开发模式。对接到 Dart VM 就可以用 Dart 写代码,对接到 JS 引擎就可以用 JS 写代码,对接到 JVM 还可以写 Java,但是无论怎么写,底层的渲染能力是一样的,一套统一的布局算法,动画和手势的处理行为也是一致的。 在这样的架构下,对接 Web 生态就更容易了。Dart 和 Widget 是前端不想要的,希望能换成 JS 和 CSS,但是又想要底层的跨平台一致渲染引擎,那从 Renderer 层开始对接就好了,绕过了所有不想要的,也保留了所有想要的。 要实现 Flutter for Web 也更简单了一些。在 Engine 层做对接,一直苦于浏览器透出的底层能力不够,如果是在 Renderer 之上做对接就更容易一些,基于 JS/CSS/DOM/Canvas 的能力封装出一套 Rendering 接口,供 Widget 调用就好了,这样可以使渲染链路更短一些,但是依然要处理 Widget 和 DOM/CSS 之间的兼容性问题。 再讨论一遍:为什么要对接? 技术上已经分析完了,要想搞定 Flutter 生态和 Web 生态的对接,需要投入很大的成本,所以真正决定做之前,要先讨论清楚为什么要做对接?到底要不要做对接? 首先 Google 官方对 Flutter 的定位就是个问题。Flutter 设计之初就是不考虑 Web 生态的,甚至在刻意回避,倡导的是更贴近原生的开发方式。我之所以在开头说不要对接,原因也很简单:两种技术设计理念不同,不是朝着一个方向发展的,生态不通,技术方案不通,强行融合很可能让彼此都丧失了优势。但是业界又有很多团队在做这种尝试,说明需求是存在的,如果 Google 抵制这个方向,那就不好做了。不过现在官方已经支持了 Flutter for Web,已经向 Web 生态迈了一步,未来是否进一步与 Web 融合,也是有可能的。 另外就是跨平台技术本身的问题,浏览器发展了二三十年,已经是个很强大的跨平台产品了,几乎是 Web 的代名词了,这一点无人能敌。但是也臃肿不堪,有大量历史包袱,性能和体验不够好,和 Native 的结合度差,尤其在移动和 IoT 平台。虽然硬件性能在不断提升,但这是所有软件共享的,浏览器的性能和体验总会比 Native 差一些,差的这一些很可能就是新业务和新场景的发挥空间。观察一下近几年新诞生的业务场景,很多都是利用到了 Native 新提供的能力才火爆起来的,如 AI/AR/ 视频 / 直播 等,有因为新的 Web API 而孵化生出来的商业模式吗? 原文链接: https://mp.weixin.qq.com/s?__biz=MzAxNDEwNjk5OQ==&mid=2650405725&idx=1&sn=0b7476f7c7c01df7fdafda578f9ceb98&chksm=83953345b4e2ba53917ac30b709c07be15bd1c2fd5ae2a8ecfbb129b3813f771621b8fac95ca&scene=27#wechat_redirect

剑曼红尘 2020-03-10 09:54:40 0 浏览量 回答数 0

问题

Android目录结构(详解):报错

kun坤 2020-06-07 21:39:11 0 浏览量 回答数 1

问题

阿里云LINUX主机安装从初始环境到完成配置全过程

liming837 2019-12-01 20:21:42 39447 浏览量 回答数 19

回答

说明: 1、测试版本无需登录,运行后直接进入主界面,但是首次运行会提示用户配置参数; 2、根据提示,点击左上角菜单“设置——系统设置”,按照界面要求,逐项完成本地监测路径的设置,远程OSS节点选择、AccessKey设置,获取对应的Bucket列表,设置路径(此处路径可以为空)等,完成本地文件夹和远程OSS的绑定; 3、根据提示,点击左上角菜单“设置——加载配置”,以使刚做的配置生效; 4、然后点击菜单下面的toolBar(不好意思,这里未做图片,大家先凑合用吧),第一个按钮是启动文件监测,第二个按钮是暂停文件监测; ——到这里,你就可以实现本地文件夹到远程OSS的文件同步了; 其它的功能,比如同步策略、设置线程数、同步成功后是否删除本地等等,同时Sync4oss附带了几个方便用户在服务器端做批量操作的小功能,比如“批量上传本地文件夹”、“批量修改HTTP头参数”、“批量复制或移动Object”等,请您体验也帮测试; ------------------------- 回 4楼(eblis) 的帖子 你好,FTP云工具经大量用户测试挺稳定的,日均上传数万都没问题的; 您遇到的问题能否联系我们详细描述?帮您解决问题! http://www.ftp4oss.com/ 首页右下角有联系方式; 或者您提供您的联系方式,我们会安排人员协助你排查问题的。 ------------------------- 回 5楼(eblis) 的帖子 你好,获取Bucket列表的时候失败,请查一下是否被360拦截了?? 360对各种软件连接OSS的连接基本都会拦截,需要你设置为白名单即可; ------------------------- 回 8楼(荆楚小霸王) 的帖子 你好,请问您这里的异常是指什么呢?能否联系我们详细描述一下,我们会努力解决的! Sync4oss灵活性比较高,相关说明近期会编制出来,供大家参考! ------------------------- 回 10楼(荆楚小霸王) 的帖子 您好,您提到的主界面的正常运行是需要您先完成系统配置,具体的就是完成本地目录和远端OSS的绑定,之后才能正常工作的; 另外,您提到的上传10G的图片是没有问题的,和你的服务器带宽关系不是很大,因为除了公网上传外,您还可以设置为内网上传,10G图片小菜一碟! ------------------------- 这个得顶上去~~~ ------------------------- 回 15楼(冲你的风) 的帖子 你好,该问题已经解决,请你重新下载程序测试,有问题联系我们客服继续反馈。 ------------------------- 回 16楼(sheyingtg) 的帖子 该问题需要你正确输入OSS的AccessKey的ID和Secret,以获取Bucket列表~~~ 使用上有问题的,请多测试几次或者联系我们的技术客服,谢谢支持! ------------------------- 回 17楼(ijijni) 的帖子 理论上,Sync4oss这个同步或镜像工具是可以满足你的要求; 但是,还需要根据你的实际情况分析; 同步你的网站到OSS这个没问题; 而你的网站直接从OSS读取相关文件,只要你的网站支持即可~~~ ------------------------- 回 18楼(sheyingtg) 的帖子 用户您好,我们的技术客服反馈过来,和您配合查找过问题,你每次批量上传图片,我们的Sync4oss同步工具都能准确的监测到,并且也确实实时同步工作了,但是您的网站编辑器每次总会占用若干图片,导致我们程序读取失败; 本次我们改进这块的逻辑,您再试试能否解决你的这个问题,你可以随时和我们客服保持联系~~~  多谢支持! ------------------------- 回 23楼(有事请留言) 的帖子 嗯嗯,我们抓紧进度,感谢支持! ------------------------- 目前正在小范围进行核心同步功能的内测,内测结束后将尽快发布正式版本,敬请期待,谢谢大家支持! ------------------------- 11月29日,Linux版本的Sync4oss程序内测版本发布(标准C的程序,理论上兼容所有的Linux操作系统);Linux系统需要安装Curl; ------------------------- 回 28楼(碧血微剑) 的帖子 目前是测试版,我们会在过期之前,提前发布正式版本,我们还会维持很长一段时间免费的;即使以后可能收费的话也都是几十块钱的价位; ------------------------- 回 29楼(脑门王) 的帖子 文件过滤的功能在当前测试版未实现,计划在正式版本里面会提供,敬请期待; ------------------------- 回 33楼(兜里有糖哦) 的帖子 关闭putty之类的远程控制软件的时候,发现Sync4oss工具就停止了    这个时候,您需要把当前运行的Sync4oss工具的程序挂起,并转为后台运行即可;    方法一、简要方法挂起程序转后台运行: 通过以下4个步骤 1、ctrl+z    //挂起当前任务 2、jobs -l    //查看当前任务的编号 3、bg  %n   //将编号为n的任务转后台运行 4、disown -h %1   这样就可以后台运行,可以关闭putty工具了 方法二、利用功能强大的Linux远程工具Screen的虚拟终端(可以支持后台运行,还可以再次调用查看程序运行情况): 方法三、Linux系统的远程桌面; ------------------------- 回 35楼(兜里有糖哦) 的帖子 Windows和Linux两类操作系统都能支持~~~ ------------------------- 回 38楼(遨游美食) 的帖子 你好,可以联系我们的技术客服详细了解一下你的问题,看看是哪里出现了不兼容,以便解决; 目前对于Linux和Windows两个版本的软件,都在若干个正式运行的网站中运行,稳定性没问题; ------------------------- 回 39楼(碧血微剑) 的帖子 sync4oss 的程序正常,请你检查一下是不是论坛帖子的最新版本 也可以联系我们的技术客服配合你检查一下问题所在,以便解决; ------------------------- 回 42楼(秦皇) 的帖子 你好,请确认你的配置是否正确,查看的OSS路径是否正确; 如果还有问题,请联系我们的技术客服协助你配置; 多谢支持! ------------------------- 回 43楼(abua) 的帖子 你好,是误报不是病毒,只要是从我们发布在阿里云的帖子下载或者由我们工作人员发送的软件,即请放心使用! 对于我们现已发布的几款Windows平台下的软件,目前采用的保护手段就是用“Sixxpack24”做了加壳处理(因为C#的程序不加壳的话太容易被反编译了),我们在2014年1月份登陆云市场的时候也已经对杀毒软件误报的事做了论坛发帖说明、在软件包里面也有杀软误报说明,希望广大用户的理解,当然随着我们经验的积累,我们也正计划采用其它方法来取代备受诟病的“ Sixxpack24 ”加壳。 这个是2014年1月4日发布在阿里云论坛的一个安全提示说明: http://bbs.aliyun.com/read/150244.html 这个是2014年1月6日发布在阿里云论坛的一个安全处理说明: http://bbs.aliyun.com/read/150306.html Sixxpack的说明:百度或Google搜索Sixxpack可以看到该软件是一种加壳保护程序,而非病毒;由于加壳后部分杀毒软件无法脱壳而直接把采用类似加壳技术的软件全部判断为潜在威胁并拦截; 感谢理解与支持! ------------------------- 回 48楼(秦皇) 的帖子 你好,该版本已过试用期了,请你用最新版本的可执行程序覆盖即可(配置文件不覆盖,免去重新配置); 相关解决方案在用户内测群里都提供了~~ 多谢支持!

ftp4oss 2019-12-02 00:18:20 0 浏览量 回答数 0

问题

如何选择适合自己网站的操作系统

随歌 2019-12-01 22:02:48 18238 浏览量 回答数 6

回答

不良的编程习惯TOP1:粘贴复制 在学生时代,我们都知道抄袭是不对的。但在工作中,这方面的规则还很模糊。虽然有些代码块是不能盗用的——不要把专有代码拷贝到你的堆栈中,尤其是这些代码有标记版权信息。这种时候你应该编写自己的版本,老板付你薪水就是要做正事的。 但是当原始创作者想要共享代码时,问题就变得复杂了。这些共享代码也许放到了某个在线编程论坛上,也许它们是带有许可证(BSD,MIT)的开放源代码,允许使用一到三个函数。你使用这些共享代码是没有问题的,而且你上班是为了解决问题,而不是重新发明轮子。 大多数情况下,复制代码的优势非常明显,小心对待的话问题也不大。至少那些从靠谱的来源获得的代码已经被大致“检查“过了。 问题的复杂之处在于,这些共享代码是否存在一些未发现的错误,代码的用途或底层数据是否存在一些特别的假设。也许你的代码混入了空指针,而原始代码从未检查过。如果你能解决这些问题,那么就可以理解为你的老板得到了两位程序员共同努力的成果。这就是某种形式的结对编程,而且用不着什么高大上的办公桌。 不良的编程习惯TOP2:非函数式代码 在过去十年间,函数范式愈加流行。喜欢用嵌套函数调用来构建程序的人们引用了很多研究成果。这些研究表明,与旧式的变量和循环相比,函数式编程代码更安全,错误更少,而且可以随程序员的喜好任意组合在一起。粉丝们十分追捧函数式编程,还会在代码审查和拉取请求中诋毁非函数式方法。关于这种方法的优势,他们的观点其实并没有错。 但有时你需要的仅仅是一卷胶带而已。精心设计并细心计划的代码需要花费很多时间,不仅需要花费时间想象,还需要构建和之后导航的时间。这些都增加了复杂性,并且会花费很多的时间与精力。开发漂亮的函数式代码需要提前做计划,还要确保所有数据都通过正确的途径传递。有时找出并更改变量会简单得多,可能再加个注释说明一下就够了。就算要在注释中为之后的程序员致以冗长而难懂的歉意,也比重新设计整个系统,把它扳回正轨上要省事得多。 不良的编程习惯第 3 位:非标准间距 软件中的大多数空格都不会影响程序的性能。除少数使用间距指示代码块的语言(如 Python)外,大多数空格对程序行为的影响为零。尽管如此,仍然有一些得了强迫症的程序员会数空格,并坚持认为它们很重要。曾有这样一位程序员以最严肃的口吻告诉我的老板,说我正在写“非标准代码”,还说他一眼就看出来了。我的错咯?因为我没在等号的两侧放置空格,违反了 ESLint space-infix-ops 规则[1]。 有时候你只要操心那些更深层的内容就行了,谁管什么空格的位置。也许你担心数据库过载,也许你担心空指针可能会让你的代码崩溃。一套代码中,几乎所有的部分都比空格更重要,就算那些喜欢走形式的标准委员会写出来一大堆规则来限制这些空格或制表符的位置,那又如何呢。 令人欣喜的是,网上可以找到一些很好用的工具来自动重新格式化你的代码,让你的代码遵守所有精心定义的 linting 规则。人类不应该在这种事情上浪费时间和脑细胞。如果这些规则这么重要,我们就应该用工具来解决这些问题。 不良的编程习惯第 4 位:使用 goto 禁止使用 goto 的规则可以追溯到许多结构化编程工具还没有出现的时代。如果程序员想创建一个循环或跳转到另一个例程,则需要键入 goto,后跟一个行号。多年之后,编译器团队开始允许程序员使用字符串标签来代替行号。这在当时被认为是一项热门的新特性。 有的人把这样做法的结果称为“意大利面条式代码”。因为以后没人能读懂你的代码,没人搞得清楚执行路径。成为一团混乱的线程,缠结在一起。Edsger Dijkstra 写过一篇题为“我们认为 goto 声明是有害的”的一篇文章[2],号召大家拒绝使用这个命令。 但是绝对分支并不是问题所在,问题在于它产生的那堆纠缠的结果。一般来说,精心设计的 break 或 return 能提供有关该位置的代码执行情况的非常清晰的陈述。有时,将 goto 添加到一个 case 语句中所生成的东西与联 if-then-else 块的相比,结构更正确的列表理解起来更容易。 也有反例。苹果 SSL 堆栈中的“goto fail”安全漏洞[3]就是一个很好的例子。但是,如果我们谨慎地避免 case 语句和循环中出现的一些问题,我们就可以插入很好用的绝对跳转,使代码读者更容易理解正在发生的事情。有时我们可以放一个 break 或 return,不仅更简洁,而且大家读起来更愉快,除了那些讨厌 goto 的人们。 不良的编程习惯第 5 位:不声明类型 热爱类型化语言的人们有他们的理由。当我们为每个变量的数据类型添加清晰的声明时,我们会编写更好,错误更少的代码。花点时间来阐明类型,就可以帮助编译器在代码开始运行之前标记出愚蠢的错误。这可能会很痛苦,但也会有回报。这是一种编程的笨办法,就是为了避免错误。 时代变了。许多较新的编译器已经足够聪明了,它们可以在查看代码时推断出类型。它们可以在代码中前后移动,最后确认变量应该是 string 或 int,抑或是其他类型。而且,如果推断出来的这些类型没法对齐,则编译器会给出错误标志。它们不需要我们再类型化变量了。 换句话说,我们可以省略一些最简单的声明,然后就能轻松节省一些时间了。代码变得更简洁,代码读者也往往能猜出 for 循环中名为 i 的变量是一个整数。 不良的编程习惯第 6 位:溜溜球代码 程序员喜欢将其称为“yo-yo 代码”。首先,这些值将存储为字符串,然后将它们解析为整数,接下来将它们转换回字符串。这种方法效率极低。你几乎能感受到一大堆额外负载让 CPU 不堪重负的样子。能快速编写代码的聪明程序员会调整自己的代码架构,以最大程度地减少转换。因为他们安排好了计划,他们的代码也能跑得更快。 但不管你信不信,有时溜溜球代码也是有意义的。有的时候,你需要用一个可以在自己的黑匣子里搞定一大堆智能操作的库。有的老板花了很多钱,请好多天才做出来这么一个库。如果这个库需要字符串形式的数据,那么你就得给它字符串,就算你最近刚把数据转换为整数也得再转回去。 当然,你可以重写所有代码以最大程度地减少转换,但这会花费一些时间。有时,代码多运行一分钟、一小时、一天甚至一周也是可以接受的,因为重写代码会花费更多时间。有时候,增加技术债务要比重新建立一笔技术债的成本更低些。 有时这种库里面不是专有代码,而是你很久以前编写的代码。有时,转换一次数据要比重写该库中的所有内容更省事。这种时候你就可以编写悠悠球代码了,不要怕,我们都遇到过这种事情。 不良的编程习惯第7位:编写自己的数据结构 有一条标准规则是,程序员在大二学完数据结构课程后,再也不要编写用于存储数据的代码了。已经有人编写过了我们所需要的所有数据结构,并且他们的代码经过了多年的测试和重新测试。这些结构与语言打包在一起,还可能是免费的。你自己写的代码只会是一堆错误。 但有的时候数据结构库的速度有点缓慢。有时候我们被迫使用的标准结构并不适合我们自己的代码。有时,库会要求我们在使用它的结构之前重新配置数据。有时,这些库带有笨重的保护,还有一些诸如线程锁定之类的特性,而我们的代码并不需要它们。 发生这种情况时就该编写我们自己的数据结构了。有时我们自己的结构会快很多,还可能让我们的代码更整洁,因为我们不需要一大堆额外的代码来重新精确地格式化数据。 不良的编程习惯第 8 位:老式循环 很久以前,创建 C 语言的某人想将所有抽象可能性封装在一个简单的构造中。这个构造开始时要做一些事情,每次循环都要做一些事情,所有事情都完成时还有一些方法来提示我们。当时,这似乎是一种拥有无限可能性的完美语法。 此一时彼一时,如今一些现代评论者只看到了其中的麻烦,发生的事情太多了,所有这些可能性既可能向善也可能作恶。这种构造让阅读和理解代码变得非常困难。他们喜欢更加函数式的的范式,其中没有循环,只有应用到列表的函数,还有映射到某些数据的计算模板。 有时无循环方法更简洁,尤其是当我们只有一个简单的函数和一个数组的时候。但还有些时候,老式的循环要简单得多,因为它可以做更多事情。例如,当你找到第一个匹配项后就立刻停止搜索,这样的代码就简单得多。 此外,要对数据执行多项操作时,映射函数会要求更严格的编码。假设你要对每个数字取绝对值,然后取平方根,最快的方案是先映射第一个函数,然后映射第二个函数,将数据循环两次。 不良的编程习惯第 9 位:在中间打破循环 从有一天开始,一个规则制定小组宣布每个循环都应该有一个“不变项”,就是一个在整个循环中都为真的逻辑语句。当不变量不再为真时,循环就结束了。这是处理复杂循环的好方法,但会带来一些令人抓狂的约束,例如禁止我们在循环中间使用 return 或 break。这条规则是禁止 goto 语句规则的子集。 这个理论很不错,但它通常会导致代码变得更复杂。考虑以下这种简单的情况,其中会扫描一个数组,找出通过测试的一个条目: while (i<a.length){ ... if (test(a[i]) then return a[i]; ... } 喜欢循环不变项的人们宁愿我们添加另一个布尔变量,将其称为 notFound,然后这样用它: while ((notFound) && (i<a.length){ ... if (test(a[i])) then notFound=false; ... } 如果这个布尔名称取得很合适,那就会是一段自我注释得很好的代码。它可以让大家理解起来更容易。但这也增加了复杂性。这还意味着要分配另一个局部变量并阻塞一个寄存器,编译器可能没那么聪明,没法修复这个错误。 有时使用 goto 或 jump 会更简洁。 不良的编程习惯第10位:重载运算符和函数 一些有趣的语言会让你绕一些大弯子,比如说重新定义看起来应该是常量的元素值。拿 Python 来说,至少在 2.7 版及更低版本中,它允许你键入 TRUE=FALSE。这不会引发某种逻辑崩溃,也不会导致宇宙的终结;它只是交换了 TRUE 和 FALSE 的含义。你还可以使用 C 预处理器和其他一些语言来玩这种危险的游戏。还有一些语言允许你重新定义加号之类的运算符。 有时候,在一大段代码中重新定义一个或一些所谓常量,结果效率会更高。有时,老板会希望代码执行完全不同的操作。当然,你可以检查代码,逐一更改对应的部分,也可以干脆重新定义现实来节省时间。别人会觉得你是天才。用不着重写庞大的库,只需翻转一下即可。 这里也许应该划一条底线。无论这种做法多有意思,看起来多聪明,你都不应该在家里做实验。这太危险了——我是认真的。

茶什i 2019-12-30 11:01:01 0 浏览量 回答数 0

问题

用JavaScript编写一个Java虚拟机?谈谈哗众取宠的BicaVM 400 请求报错 

kun坤 2020-05-29 09:57:19 2 浏览量 回答数 1

问题

阿里聚安全攻防挑战赛第三题Android PwnMe解题思路

移动安全 2019-12-01 21:52:44 2439 浏览量 回答数 0

问题

阿里聚安全攻防挑战赛第三题Android PwnMe解题思路

移动安全 2019-12-01 21:52:46 3267 浏览量 回答数 0

问题

Nginx性能为什么如此吊

小柒2012 2019-12-01 21:20:47 15038 浏览量 回答数 3
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 企业信息查询 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 2020阿里巴巴研发效能峰会 企业建站模板 云效成长地图 高端建站 云栖号弹性计算 阿里云云栖号 云栖号案例 云栖号直播