首页 文章 精选 留言 我的

精选列表

搜索[递归超智能],共10002篇文章
优秀的个人博客,低调大师

详细 Java 15 新功能介绍

点赞再看,动力无限。微信搜「 程序猿阿朗 」,认认真真写文章。 本文 Github.com/niumoo/JavaNotes 和 未读代码博客 已经收录,有很多知识点和系列文章。 Java 15 在 2020 年 9 月发布,虽然不是长久支持版本,但是也带来了 14 个新功能,这些新功能中有不少是十分实用的。 Java 15 官方下载:https://jdk.java.net/archive/ Java 15 官方文档:https://openjdk.java.net/projects/jdk/15/ <!-- more --> Java 15 新功能: JEP 描述 JEP 339 爱德华曲线算法(EdDSA) JEP 360 Sealed Classes(密封类)预览 JEP 371 Hidden Classes(隐藏类) JEP 372 移除 Nashorn JavaScript 引擎 JEP 373 重新实现 DatagramSocket APII JEP 374 禁用和废弃偏向锁(Biased Locking) JEP 375 instanceof 类型匹配 (二次预览) JEP 377 ZGC: 可扩展低延迟垃圾收集器(正式发布) JEP 378 文本块 JEP 379 Shenandoah: 低停顿时间的垃圾收集器 JEP 381 删除 Solaris 和 SPARC 端口 JEP 383 外部内存访问 API(第二个孵化器)) JEP 384 Records (二次预览) JEP 385 废弃 RMI 激活机制 1. JEP 339 爱德华曲线算法(EdDSA) Java 15 中增加了一个新的密码学算法,爱德华曲线算法(EdDSA)签名算法。它是由 Schnorr 算法发展而来,在 RFC8032 中被定义实现。 package com.wdbyte; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.Signature; import java.security.SignatureException; import java.util.Base64; public class JEP339 { public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519"); KeyPair kp = kpg.generateKeyPair(); byte[] msg = "www.wdbyte.com".getBytes(StandardCharsets.UTF_8); Signature sig = Signature.getInstance("Ed25519"); sig.initSign(kp.getPrivate()); sig.update(msg); byte[] s = sig.sign(); System.out.println(Base64.getEncoder().encodeToString(s)); } } 输出结果: VXlpxapU+LSWjVQ0QNJvdpUh6VI6PjSwOQ2pHu65bCfnLR13OyWKunlc9rc+7SMxCh2Mnqf7TmC/iOG8oimbAw== 2. JEP 360:Sealed Classes(密封类)预览 我们都知道,在 Java 中如果想让一个类不能被继承和修改,这时我们应该使用 final 关键字对类进行修饰。不过这种要么可以继承,要么不能继承的机制不够灵活,有些时候我们可能想让某个类可以被某些类型继承,但是又不能随意继承,是做不到的。Java 15 尝试解决这个问题,引入了 sealed 类,被 sealed 修饰的类可以指定子类。这样这个类就只能被指定的类继承。 而且 sealed 修饰的类的机制具有传递性,它的子类必须使用指定的关键字进行修饰,且只能是 final 、sealed 、non-sealed 三者之一。 示例:犬类(Dog)只能被牧羊犬(Collie)和田园犬(TuGou)继承,使用 sealed 关键字。 package com.wdbyte; public sealed interface Dog permits Collie, TuGou { //... } 牧羊犬(Collie)只能被边境牧羊犬(BorderCollie)继承。 package com.wdbyte; /** * 牧羊犬 * @author www.wdbyte.com */ public sealed class Collie implements Dog permits BorderCollie { } 边境牧羊犬(BorderCollie)不能被继承,使用 final 关键字。 package com.wdbyte; /** * * @author www.wdbyte.com */ public final class BorderCollie extends Collie{ } 田园犬(ToGou)可以被任意继承,使用 non-sealed 关键字。 package com.wdbyte; /** * @author niulang */ public non-sealed class TuGou implements Dog { } 3. JEP 371:Hidden Classes(隐藏类) 这个特性让开发者可以引入一个无法被其他地方发现使用,且类的生命周期有限的类。这对运行时动态生成类的使用方式十分有利,可以减少内存占用,下面是一个使用示例。 package com.wdbyte; public class JEP371Test { public static String lookup() { return "www.wdbyte.com"; } } 把类 JEP371Test 编译后的 Class 转换成 Base64,然后使用 Java 15 新特性加载调用类中的 lookup 方法。 package com.wdbyte; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.Base64; /** * @author www.wdbyte.com */ public class JEP371 { private static String CLASS_INFO = "yv66vgAAADQAFAoAAgADBwAEDAAFAAYBABBqYXZhL2xhbmcvT2JqZWN0AQAGPGluaXQ+AQADKClWCAAIAQAOd3d3LndkYnl0ZS5jb20HAAoBABVjb20vd2RieXRlL0pFUDM3MVRlc3QBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAF0xjb20vd2RieXRlL0pFUDM3MVRlc3Q7AQAGbG9va3VwAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAApTb3VyY2VGaWxlAQAPSkVQMzcxVGVzdC5qYXZhACEACQACAAAAAAACAAEABQAGAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAAAwANAAAADAABAAAABQAOAA8AAAAJABAAEQABAAsAAAAbAAEAAAAAAAMSB7AAAAABAAwAAAAGAAEAAAAEAAEAEgAAAAIAEw=="; public static void main(String[] args) throws Throwable { byte[] classInBytes = Base64.getDecoder().decode(CLASS_INFO); Class<!--?--> proxy = MethodHandles.lookup() .defineHiddenClass(classInBytes, true, MethodHandles.Lookup.ClassOption.NESTMATE) .lookupClass(); System.out.println(proxy.getName()); MethodHandle mh = MethodHandles.lookup().findStatic(proxy, "lookup", MethodType.methodType(String.class)); String result = (String) mh.invokeExact(); System.out.println(result); } } 输出结果: com.wdbyte.JEP371Test/0x0000000800c01800 www.wdbyte.com 4. JEP 372:移除 Nashorn JavaScript 引擎 Nashorn JavaScript 引擎在 Java 8 中被引入,在 Java 11 中被标记为废弃。由于 ECMAScript 语言发展很快,维护 Nashorn JavaScript 的成本过于高昂,在 Java 15 中被彻底删除。 > 扩展阅读:Nashorn JavaScript Engine,Deprecate the Nashorn JavaScript Engine > 5. JEP 373:重新实现 DatagramSocket API Java 13 中重新实现了旧的 Socket API,在介绍 Java 13 时还有一部分做了这方面的介绍。 现在,Java 15 重新实现了遗留的 DatagramSocket。 > 扩展阅读:Java 13 新功能介绍 6. JEP 374:禁用和废弃偏向锁(Biased Locking) 在之前,JVM 在处理同步操作,如使用 synchronized 同步时,有一套锁的升级机制,其中有一个锁机制就是偏向锁。然而通过目前的 Java 开发环境来看,使用这些被 synchronized 同步的类的机会并不多,如开发者更喜欢使用 HashMap 或者 ArrayList 而非 HashTable 和 Vector。 即使换个角度,当初使用偏向锁是为了提高性能,如今看来性能提升的程度和使用次数都不太有用。而偏向锁的引入增加了 JVM 的复杂性。 所以现在偏向锁被默认禁用,在不久的将来将会彻底删除,对于 Java 15,我们仍然可以使用-XX:+UseBiasedLocking 启用偏向锁定,但它会提示 这是一个已弃用的 API。 7. JEP 375:instanceof 类型匹配 (二次预览) instanceof 类型匹配在 Java 14 中已经改进,这次仅仅再次预览,没有任何改动,用于接受更多的使用反馈。这个特性在 Java 16 中成为正式特性。 在之前,使用 instanceof 进行类型判断之后,需要进行对象类型转换后才能使用。 package com.wdbyte; import java.util.ArrayList; import java.util.List; public class Java14BeaforInstanceof { public static void main(String[] args) { Object obj = new ArrayList&lt;&gt;(); if (obj instanceof ArrayList) { ArrayList list = (ArrayList)obj; list.add("www.wdbyte.com"); } System.out.println(obj); } } 而在 Java 14 中,可以在判断类型时指定变量名称进行类型转换,方便了使用。 package com.wdbyte; import java.util.ArrayList; public class Java14Instanceof { public static void main(String[] args) { Object obj = new ArrayList&lt;&gt;(); if (obj instanceof ArrayList list) { list.add("www.wdbyte.com"); } System.out.println(obj); } } 可以看到,在使用 instanceof 判断类型成立后,会自动强制转换类型为指定类型。 输出结果: [www.wdbyte.com] > 扩展阅读:Java 14 新功能介绍 8. JEP 377:ZGC: 可扩展低延迟垃圾收集器(正式发布) ZGC 垃圾收集器在 Java 11 中被引入,但是因为收集器的复杂性,当初决定逐渐引入。然后不断的听取用户的反馈建议修复问题。而现在,已经很久没有收到用户的问题反馈了,ZGC 是时候投入正式使用阶段了。所以在 Java 15 中 ZGC 正式发布,可以使用下面的参数启用 ZGC。 $ java -XX:+UseZGC className 9. JEP 378: 文本块 文本块在 Java 12 JEP 326 原始字符串文字 中引入,在 Java 13 JEP 355:文本块(预览) 中开始预览,在 Java 14 JEP 368:文本块(第二次预览),而现在,在 Java 15 ,文本块是正式的功能特性了。 String content = """ { "upperSummary": null,\ "sensitiveTypeList": null, "gmtModified": "2011-08-05\s10:50:09", } """; System.out.println(content); > 扩展阅读:Java 14 新功能介绍- JEP368 文本块 10. JEP 379:Shenandoah: 低停顿时间的垃圾收集器 Shenandoah 垃圾收集器在 Java 12 中开始引入,Java 15 中成为了正式功能的一部分,可以使用下面的参数启用 Shenandoah 垃圾收集器。 java -XX:+UseShenandoahGC 但是 openJDK 15 中默认是没有 Shenandoah 收集器,想要使用此功能可以下载 AdoptOpenJDK。 > 为什么 openJDK 中没有 Shenandoah 垃圾收集器? > > Shenandoah 是一个高性能、低暂停时间的垃圾收集器,它是 Red Hat 主导的项目。当 Red Hat 第一次提议将 Shenandoah 贡献给 OpenJDK 时,Oracle 明确表示不想支持它,OpenJDK 作为一个免费软件,不想支持 Red Hat 的 Shenandoah 完全没有问题。 > > 最后 Red Hat 选择和 Oracle 合作设计一个真正干净的可插拔垃圾收集器接口,允许任何人轻松选择垃圾收集器以包含在他们的构建中。最终 Shenandoah 进入了 JDK 12,但是没有构建进 OpenJDK。 11. JEP 384:Records(二次预览) 在 Java 14 中引入了 Record 类,Java 15 中对 Record 进行了增强。使它可以支持密封类型、Record 注解以及相关的反射 API 等。 示例:Record 支持密封(sealed)类型。 package com.wdbyte; /** * @author www.wdbyte.com */ public sealed interface DataBase permits DataBaseSelect, DataBaseUpdate { } final record DataBaseSelect(@Deprecated String table, String sql) implements DataBase { } final record DataBaseUpdate() implements DataBase { } 在 java.lang.Class 增加了两个公共方法用于获取 Record 类信息: RecordComponent[] getRecordComponents() boolean isRecord() 其他更新 JEP 381:删除 Solaris 和 SPARC 端口 Java 14 JEP 362弃用了 Solaris/SPARC、Solaris/x64 和 Linux/SPARC 端口,现在它在 Java 15 中被正式删除。 JEP 383:外部内存访问 API(第二个孵化器) JEP 385:废弃 RMI 激活机制 只是废弃 RMI 激活机制,不影响 RMI 其他功能。 参考 https://openjdk.java.net/projects/jdk/15/ https://docs.oracle.com/en/java/javase/14/docs/specs/rmi/activation.html https://mkyong.com/java/what-is-new-in-java-15/ 系列文章 Java 15 新功能介绍 Java 14 新特性介绍 Java 13 新特性介绍 Java 12 新特性介绍 Java 11 新特性介绍 Java 10 新特性介绍 Java 9 新特性介绍 Java 8 函数接口 UnaryOperator Java 8 函数接口 BiPredicate Java 8 函数接口 BiFunction Java 8 函数接口 Supplier Java 8 函数接口 Predicate Java 8 函数接口 Function Java 8 新特性 - forEach 遍历 Java 8 新特性 - LocalDate、LocalDateTime 时间处理介绍 Java 8 新特性 - 使用 Optional优雅的处理空指针 Java 8 新特性 - Lambda 表达式、函数接口了解一下 Java 8 新特性 - 超强的 Stream 流操作姿势还不学习一下 Java 7 新特性 - 和低效 IO 说再见,Files,Paths,Path 文件操作介绍 Java 7 新特性 - 新特性 - 快来补一波 Java 7 语法特性 订阅 Hello world : ) 我是阿朗,一线技术工具人,认认真真写文章。 点赞的个个都是人才,不仅长得帅气好看,说话还好听。 文章持续更新,可以关注公众号「 程序猿阿朗 」或访问「未读代码博客 」。 回复【资料】有我准备的各系列知识点和必看书籍。 本文 Github.com/niumoo/JavaNotes 已经收录,有很多知识点和系列文章,欢迎Star。

优秀的个人博客,低调大师

Hive解析Json数组全讲解

2 --> 在Hive中会有很多数据是用Json格式来存储的,如开发人员对APP上的页面进行埋点时,会将多个字段存放在一个json数组中,因此数据平台调用数据时,要对埋点数据进行解析。接下来就聊聊Hive中是如何解析json数据的。 本文首发于公众号【五分钟学大数据】 Hive自带的json解析函数 1. get_json_object 语法:get_json_object(json_string, '$.key') 说明:解析json的字符串json_string,返回path指定的内容。如果输入的json字符串无效,那么返回NULL。这个函数每次只能返回一个数据项。 示例: selectget_json_object('{"name":"zhangsan","age":18}','$.name'); 结果: name zhangsan 如果既要解析name字段,也解析age字段,则可以这样写: selectget_json_object('{"name":"zhangsan","age":18}','$.name'),get_json_object('{"name":"zhangsan","age":18}','$.age'); 但是如果要解析的字段有很多,再这样写就太麻烦了,所以就有了 json_tuple 这个函数。 2. json_tuple 语法: json_tuple(json_string, k1, k2 ...) 说明:解析json的字符串json_string,可指定多个json数据中的key,返回对应的value。如果输入的json字符串无效,那么返回NULL。 示例: selectb.name,b.agefromtableNamealateralviewjson_tuple('{"name":"zhangsan","age":18}','name','age')basname,age; 结果: name age zhangsan 18 注意:上面的json_tuple函数中没有$. 如果在使用json_tuple函数时加上$.就会解析失败: selectb.name,b.agefromtableNamealateralviewjson_tuple('{"name":"zhangsan","age":18}','$.name','$.age')basname,age; 结果: name age NULL NULL 字段全是NULL,所以json_tuple函数不需要加$.了,否则会解析不到。 总结:json_tuple相当于get_json_object的优势就是一次可以解析多个json字段。但是如果我们有个json数组,这两个函数都无法处理。 Hive解析json数组 一、嵌套子查询解析json数组 如果有一个hive表,表中 json_str 字段的内容如下: json_str [{"website":"baidu.com","name":"百度"},{"website":"google.com","name":"谷歌"}] 我们想把这个字段解析出来,形成如下的结构: website name baidu.com 百度 google.com 谷歌 要解析这个json数组,仅用上面介绍的两个函数就解析不出来了,还需用到如下介绍的几个函数: explode函数 语法: explode(Array OR Map) 说明:explode()函数接收一个array或者map类型的数据作为输入,然后将array或map里面的元素按照每行的形式输出,即将hive一列中复杂的array或者map结构拆分成多行显示,也被称为列转行函数。 示例: --解析arrayhive>selectexplode(array('A','B','C'));OKABC--解析maphive>selectexplode(map('A',10,'B',20,'C',30));OKA10B20C30 regexp_replace函数 语法: regexp_replace(string A, string B, string C) 说明:将字符串A中的符合java正则表达式B的部分替换为C。注意,在有些情况下要使用转义字符,类似oracle中的regexp_replace函数。 示例: hive>selectregexp_replace('foobar','oo|ar','');OKfb 上述示例将字符串中的 oo 或 ar 替换为''。 有了上述几个函数,接下来我们来解析json_str字段的内容: 先将json数组中的元素解析出来,转化为每行显示: hive>SELECTexplode(split(regexp_replace(regexp_replace('[{"website":"baidu.com","name":"百度"},{"website":"google.com","name":"谷歌"}]','\\[|\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;'));OK{"website":"baidu.com","name":"百度"}{"website":"google.com","name":"谷歌"} 对上述sql进行简要说明: SELECTexplode(split(regexp_replace(regexp_replace('[{"website":"baidu.com","name":"百度"},{"website":"google.com","name":"谷歌"}]','\\[|\\]',''),将json数组两边的中括号去掉'\\}\\,\\{','\\}\\;\\{'),将json数组元素之间的逗号换成分号'\\;')以分号作为分隔符(split函数以分号作为分隔)); 为什么要将json数组元素之间的逗号换成分号?因为元素内的分隔也是逗号,如果不将元素之间的逗号换掉的话,后面用split函数分隔时也会把元素内的数据给分隔,这不是我们想要的结果。 上步已经把一个json数组转化为多个json字符串了,接下来结合son_tuple函数来解析json里面的字段: selectjson_tuple(explode(split(regexp_replace(regexp_replace('[{"website":"baidu.com","name":"百度"},{"website":"google.com","name":"谷歌"}]','\\[|\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;')),'website','name'); 执行上述语句,结果报错了:FAILED: SemanticException [Error 10081]: UDTF's are not supported outside the SELECT clause, nor nested in expressions 意思是UDTF函数不能写在别的函数内,也就是这里的explode函数不能写在json_tuple里面。 既然explode函数不能写在别的json_tuple里面,那我们可以用子查询方式,如下所示: selectjson_tuple(json,'website','name')from(selectexplode(split(regexp_replace(regexp_replace('[{"website":"baidu.com","name":"百度"},{"website":"google.com","name":"谷歌"}]','\\[|\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;'))asjson)t; 执行上述语句,没有报错,执行结果如下: www.baidu.com百度google.com谷歌 二 使用 lateral view 解析json数组 hive表中 goods_id 和 json_str 字段的内容如下: goods_id json_str 1,2,3 [{"source":"7fresh","monthSales":4900,"userCount":1900,"score":"9.9"},{"source":"jd","monthSales":2090,"userCount":78981,"score":"9.8"},{"source":"jdmart","monthSales":6987,"userCount":1600,"score":"9.0"}] 目的:把 goods_id 字段和 json_str 字段中的monthSales解析出来。 下面我们就开始解析: 拆分goods_id字段及将json数组转化成多个json字符串: selectexplode(split(goods_id,','))asgood_id,explode(split(regexp_replace(regexp_replace(json_str,'\\[|\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;'))assale_infofromtableName; 执行上述语句,结果报错:FAILED: SemanticException 3:0 Only a single expression in the SELECT clause is supported with UDTF's. Error encountered near token 'sale_info' 意思是用UDTF的时候,SELECT 只支持一个字段。而上述语句select中有两个字段,所以报错了。 那怎么办呢,要解决这个问题,还得再介绍一个hive语法: lateral view lateral view用于和split、explode等UDTF一起使用的,能将一行数据拆分成多行数据,在此基础上可以对拆分的数据进行聚合,lateral view首先为原始表的每行调用UDTF,UDTF会把一行拆分成一行或者多行,lateral view在把结果组合,产生一个支持别名表的虚拟表。 示例: 假设我们有一张用户兴趣爱好表 hobbies_table,它有两列数据,第一列是name,第二列是用户兴趣爱好的id_list,是一个数组,存储兴趣爱好的id值: name id_list zhangsan [1,2,3] lisi [3,4,5] 我们要统计所有兴趣id在所有用户中出现的次数: 对兴趣id进行解析: SELECTname,hobby_idFROMhobbies_tableLATERALVIEWexplode(id_list)tmp_tableAShobby_id; 上述sql执行结果: name hobby_id zhangsan 1 zhangsan 2 zhangsan 3 lisi 3 lisi 4 lisi 5 将id_list拆分完之后统计在用户中出现的次数就简单了,按照hobby_id进行分组聚合即可: SELECThobby_id,count(name)client_numFROMhobbies_tableLATERALVIEWexplode(id_list)tmp_tableAShobby_idgroupbyhobby_id; 结果: hobby_id client_num 1 1 2 1 3 2 4 1 5 1 介绍完 lateral view 之后,我们再来解决上面遇到的用UDTF的时候,SELECT 只支持一个字段的问题: selectgood_id,get_json_object(sale_json,'$.monthSales')asmonthSalesfromtableNameLATERALVIEWexplode(split(goods_id,','))goodsasgood_idLATERALVIEWexplode(split(regexp_replace(regexp_replace(json_str,'\\[|\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;'))salesassale_json; 注意:上述语句是三个表笛卡尔积的结果,所以此方式适用于数据量不是很大的情况。 上述语句执行结果如下: goods_id monthSales 1 4900 1 2090 1 6987 2 4900 2 2090 2 6987 3 4900 3 2090 3 6987 如果表中还有其他字段,我们可以根据其他字段筛选出符合结果的数据。 总结:lateral view通常和UDTF一起出现,为了解决UDTF不允许在select存在多个字段的问题。 公众号【五分钟学大数据】,大数据领域原创技术号,专注于大数据技术研究

优秀的个人博客,低调大师

了解HashMap数据结构,详细!

点击蓝色“程序员的时光”关注我,标注“星标”,及时阅读最新技术文章 写在前面: 小伙伴儿们,大家好!今天来学习HashMap相关内容,作为面试必问的知识点,来深入了解一波! 思维导图: 学习框架图 1,HashMap集合简介 HashMap基于哈希表的Map接口实现,是以key-value存储形式存在,即主要用来存放键值对。HashMap的实现不是同步的,这意味着它不是线程安全的。它的key、value都可以为null。此外,HashMap中的映射不是有序的。 JDK1.8之前的HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了节解决哈希碰撞(两个对象调用的hashCode方法计算的哈希码值一致导致计算的数组索引值相同)而存在的(“拉链法”解决冲突)。 JDK1.8之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(或者红黑树的边界值,默认为8)并且当前数组的长度大于64时,此时此索引位置上的所有数据改为使用红黑树存储。 数组里面都是key-value的实例,在JDK1.8之前叫做Entry,在JDK1.8之后叫做Node。 key-value实例 由于它的key、value都为null,所以在插入的时候会根据key的hash去计算一个index索引的值。计算索引的方法如下: /***根据key求index的过程*1,先用key求出hash值*/staticfinalinthash(Objectkey){inth;return(key==null)?0:(h=key.hashCode())^(h>>>16);}//2,再用公式index=(n-1)&hash(n是数组长度)inthash=hash(key);index=(n-1)&hash; 这里的Hash算法本质上就是三步:取key的hashCode值、高位运算、取模运算。 这样的话比如说put("A",王炸),插入了key为"A"的元素,这时候通过上述公式计算出插入的位置index,若index为3则结果如下(即hash("A")=3): 插入索引为3的结点 那么,HashMap中的链表又是干什么用的呢? 大家都知道数组的长度是有限的,在有限的长度里面使用哈希函数计算index的值时,很有可能插入的k值不同,但所产生的hash是相同的(也叫做哈希碰撞),这也就是哈希函数存在一定的概率性。就像上面的K值为A的元素,如果再次插入一个K值为a的元素,很有可能所产生的index值也为3,也就是即hash("a")=3;那这就形成了链表,这种解决哈希碰撞的方法也叫做拉链法。 同一个位置插入不同元素 当这个链表长度大于阈值8并且数组长度大于64则进行将链表变为红黑树。 补充: 将链表转换成红黑树前会判断,如果阈值大于8,但是数组长度小64,此时并不会将链表变为红黑树。而是选择进行数组扩容。 这样做的目的是因为数组比较小,尽量避开红黑树结构,这种情况下变为红黑树结构,反而会降低效率,因为红黑树需要进行左旋,右旋,变色这些操作来保持平衡。同事数组长度小于64时,搜索时间相对快一些。所以综上所述为了提高性能和减少搜索时间,底层在阈值大于8并且数组长度大于64时,链表才转换为红黑树。具体可以参考treeifyBin方法。 当然虽然增了红黑树作为底层数据结构,结构变得复杂了,但是阈值大于8并且数组长度大于64时,链表转换为红黑树时,效率也变得更高效。 特点: 存取无序的 键和值位置都可以是null,但是键位置只能是一个null 键位置是唯一的,底层的数据结构控制键的 jdk1.8前数据结构是:链表 + 数组 jdk1.8之后是 :链表 + 数组 + 红黑树 阈值(边界值) > 8 并且数组长度大于64,才将链表转换为红黑树,变为红黑树的目的是为了高效的查询。 2,HsahMap底层数据结构 2.1,HashMap存储数据的过程 每一个Node结点都包含键值对的key,value还有计算出来的hash值,还保存着下一个 Node 的引用 next(如果没有下一个 Node,next = null),来看看Node的源码: staticclassNode<K,V>implementsMap.Entry<K,V>{finalinthash;finalKkey;Vvalue;Node<K,V>next;...} HashMap存储数据需要用到put()方法,关于这些方法的详解,我们下节再说,这里简要说一下; publicstaticvoidmain(String[]args){HashMap<String,Integer>hmap=newHashMap<>();hmap.put("斑",55);hmap.put("镜",63);hmap.put("带土",25);hmap.put("鼬",9);hmap.put("佐助",43);hmap.put("斑",88);System.out.println(hmap);} 当创建HashMap集合对象的时候,在jdk1.8之前,构造方法中会创建很多长度是16的Entry[] table用来存储键值对数据的。在jdk1.8之后不是在HashMap的构造方法底层创建数组了,是在第一次调用put方法时创建的数组,Node[] table用来存储键值对数据的。 比方说我们向哈希表中存储"斑"-55的数据,根据K值("斑")调用String类中重写之后的hashCode()方法计算出值(数量级很大),然后结合数组长度采用取余((n-1)&hash)操作或者其他操作方法来计算出向Node数组中存储数据的空间的索引值。如果计算出来的索引空间没有数据,则直接将"斑"-55数据存储到数组中。跟上面的"A-王炸"数据差不多。 我们回到上方的数组图,如果此时再插入"A-蘑菇"元素,那么首先根据Key值("A")调用hashCode()方法结合数组长度计算出索引肯定也是3,此时比较后存储的"A-蘑菇"和已经存在的数据"A-王炸"的hash值是否相等,如果hash相等,此时发生hash碰撞。 那么底层会调用"A"所属类String中的equals方法比较两个key内容是否相等,若相等,则后添加的数据直接覆盖已经存在的Value,也就是"蘑菇"直接覆盖"王炸";若不相等,继续向下和其他数据的key进行比较,如果都不相等,则规划出一个节点存储数据。 两个结点key值比较,是否覆盖 2.2,哈希碰撞相关的问题 哈希表底层采用何种算法计算hash值?还有哪些算法可以计算出hash值? 底层是采用key的hashCode方法的值结合数组长度进行无符号右移(>>>)、按位异或(^)、按位与(&)计算出索引的 还可以采用:平方取中法,取余数,伪随机数法。这三种效率都比较低。而无符号右移16位异或运算效率是最高的。 当两个对象的hashCode相等时会怎么样? 会产生哈希碰撞,若key值内容相同则替换旧的value.否则连接到链表后面,链表长度超过阈值8就转换为红黑树存储。 何时发生哈希碰撞和什么是哈希碰撞,如何解决哈希碰撞? 只要两个元素的key计算的哈希值相同就会发生哈希碰撞。jdk8前使用链表解决哈希碰撞。jdk8之后使用链表+红黑树解决哈希碰撞。 如果两个键的hashcode相同,如何存储键值对? hashcode相同,通过equals比较内容是否相同。相同:则新的value覆盖之前的value 不相同:则将新的键值对添加到哈希表中 2.3,红黑树结构 当位于一个链表中的元素较多,即hash值相等但是内容不相等的元素较多时,通过key值依次查找的效率较低。而jdk1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度(阀值)超过 8 时且当前数组的长度 > 64时,将链表转换为红黑树,这样大大减少了查找时间。jdk8在哈希表中引入红黑树的原因只是为了查找效率更高。 红黑树结构 JDK 1.8 以前 HashMap 的实现是 数组+链表,即使哈希函数取得再好,也很难达到元素百分百均匀分布。当 HashMap 中有大量的元素都存放到同一个桶中时,这个桶下有一条长长的链表,这个时候 HashMap 就相当于一个单链表,假如单链表有 n 个元素,遍历的时间复杂度就是 O(n),完全失去了它的优势。针对这种情况,JDK 1.8 中引入了 红黑树(查找时间复杂度为 O(logn))来优化这个问题。当链表长度很小的时候,即使遍历,速度也非常快,但是当链表长度不断变长,肯定会对查询性能有一定的影响,所以才需要转成树。 2.4,存储流程图 HashMap存放数据是用的put方法,put 方法内部调用的是 putVal() 方法,所以对 put 方法的分析也是对 putVal 方法的分析,整个过程比较复杂,流程图如下: 来看看put()源码: publicVput(Kkey,Vvalue){//对key的hashCode()做hash,调用的是putVal方法returnputVal(hash(key),key,value,false,true);}finalVputVal(inthash,Kkey,Vvalue,booleanonlyIfAbsent,booleanevict){Node<K,V>[]tab;Node<K,V>p;intn,i;/*1,tab为空则开始创建,2,(tab=table)==null表示将空的table赋值给tab,然后判断tab是否等于null,第一次肯定是null3,(n=tab.length)==0表示没有为table分配内存 4,tab为空,执行代码 n =(tab = resize()).length;进行扩容。并将初始化好的数组长度赋值给n.5,执行完n=(tab=resize()).length,数组tab每个空间都是null*/if((tab=table)==null||(n=tab.length)==0)//调用resize()方法进行扩容n=(tab=resize()).length;/*1,i=(n-1)&hash表示计算数组的索引赋值给i,即确定元素存放在哪个桶中2,p=tab[i=(n-1)&hash]表示获取计算出的位置的数据赋值给节点p3,(p=tab[i=(n-1)&hash])==null判断节点位置是否等于null,如果为null,则执行代码:tab[i]= newNode(hash, key, value, null);根据键值对创建新的节点放入该位置的桶中小结:如果当前桶没有哈希碰撞冲突,则直接把键值对插入空间位置*/if((p=tab[i=(n-1)&hash])==null)//节点位置为null,则直接进行插入操作tab[i]=newNode(hash,key,value,null);//节点位置不为null,表示这个位置已经有值了,于是需要进行比较hash值是否相等else{Node<K,V>e;Kk;/*比较桶中第一个元素(数组中的结点)的hash值和key是否相等1,p.hash==hash中的p.hash表示原来存在数据的hash值hash表示后添加数据的hash值比较两个hash值是否相等 2,(k = p.key)== key :p.key获取原来数据的key赋值给k key表示后添加数据的key 比较两个key的地址值是否相等 3,key != null && key.equals(k):能够执行到这里说明两个key的地址值不相等,那么先判断后添加的key是否等于null,如果不等于null再调用equals方法判断两个key的内容是否相等*/if(p.hash==hash&&((k=p.key)==key||(key!=null&&key.equals(k))))/*说明:两个元素哈希值相等(哈希碰撞),并且key的值也相等将旧的元素整体对象赋值给e,用e来记录*/e=p;// hash值不相等或者key不相等;判断p是否为红黑树结点elseif(pinstanceofTreeNode)//是红黑树,调用树的插入方法e=((TreeNode<K,V>)p).putTreeVal(this,tab,hash,key,value);//说明是链表节点,这时进行插入操作else{/*1,如果是链表的话需要遍历到最后节点然后插入2,采用循环遍历的方式,判断链表中是否有重复的key*/for(intbinCount=0;;++binCount){/*1)e=p.next获取p的下一个元素赋值给e2)(e=p.next)==null判断p.next是否等于null,等于null,说明p没有下一个元素,那么此时到达了链表的尾部,还没有找到重复的key,则说明HashMap没有包含该键将该键值对插入链表中*/if((e=p.next)==null){p.next=newNode(hash,key,value,null);//插入后发现链表长度大于8,转换成红黑树结构if(binCount>=TREEIFY_THRESHOLD-1)//转换为红黑树treeifyBin(tab,hash);break;}//key值以及存在直接覆盖valueif(e.hash==hash&&((k=e.key)==key||(key!=null&&key.equals(k))))break;p=e;}}//若结点为null,则不进行插入操作if(e!=null){VoldValue=e.value;if(!onlyIfAbsent||oldValue==null)e.value=value;afterNodeAccess(e);returnoldValue;}}//修改记录次数++modCount;//判断实际大小是否大于threshold阈值,如果超过则扩容if(++size>threshold)resize();//插入后回调afterNodeInsertion(evict);returnnull;} 小结: 根据哈希表中元素个数确定是 扩容还是树形化 如果是树形化遍历桶中的元素,创建相同个数的树形节点,复制内容,建立起联系 然后让桶中的第一个元素指向新创建的树根节点,替换桶的链表内容为树形化内容 3,HashMap的扩容机制 我们知道,数组的容量是有限的,多次插入数据的话,到达一定数量就会进行扩容;先来看两个问题 什么时候需要扩容? 当HashMap中的元素个数超过数组长度loadFactor(负载因子)时,就会进行数组扩容,loadFactor的默认值是0.75,这是一个折中的取值。也就是说,默认情况下,数组大小为16,那么当HashMap中的元素个数超过16×0.75=12(这个值就是阈值)的时候,就把数组的大小扩展为2×16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常耗性能的操作,所以如果我们已经预知HashMap中元素的个数,那么预知元素的个数能够有效的提高HashMap的性能。 怎么进行扩容的? HashMap在进行扩容时使用 resize() 方法,计算 table 数组的新容量和 Node 在新数组中的新位置,将旧数组中的值复制到新数组中,从而实现自动扩容。因为每次扩容都是翻倍,与原来计算的 (n-1)&hash的结果相比,只是多了一个bit位,所以节点要么就在原来的位置,要么就被分配到"原位置+旧容量"这个位置。 因此,我们在扩充HashMap的时候,不需要重新计算hash,只需要看看原来hash值新增的那个bit是1还是0就可以了,是0的话索引没变,是1的话索引变成“原索引+oldCap(原位置+旧容量)”。这里不再详细赘述,可以看看下图为16扩充为32的resize示意图: hashmap扩容 4,HashMap数组长度为什么是2的次幂 我们先看看它的成员变量: 序列化版本号 privatestaticfinallongserialVersionUID=362498820763181265L; 集合的初始化容量initCapacity //默认的初始容量是16--1<<4相当于1*2的4次方---1*16staticfinalintDEFAULT_INITIAL_CAPACITY=1<<4; 初始化容量默认是16,容量过大,遍历时会减慢速度,效率低;容量过小,那么扩容的次数变多,非常耗费性能。 负载因子 /***Theloadfactorusedwhennonespecifiedinconstructor.*/staticfinalfloatDEFAULT_LOAD_FACTOR=0.75f; 初始默认值为0.75,若过大,会导致哈希冲突的可能性更大;若过小,扩容的次数也会提高。 为什么必须是2的n次幂? 当向HashMap中添加一个元素的时候,需要根据key的hash值,去确定其在数组中的具体位置。HashMap为了提高存取效率,要尽量较少碰撞,就是要尽量把数据分配均匀,每个链表长度大致相同,这个实现就在把数据存到哪个链表中的算法。 这个算法实际就是取模,hash%length,计算机中直接求余效率不如位移运算。所以源码中做了优化,使用 hash&(length-1),而实际上hash%length等于hash&(length-1)的前提是length是2的n次幂。 如果输入值不是2的幂会怎么样? 如果数组长度不是2的n次幂,计算出的索引特别容易相同,及其容易发生hash碰撞,导致其余数组空间很大程度上并没有存储数据,链表或者红黑树过长,效率降低。 小结: 1,当根据key的hash确定其在数组的位置时,如果n为2的幂次方,可以保证数据的均匀插入,如果n不是2的幂次方,可能数组的一些位置永远不会插入数据,浪费数组的空间,加大hash冲突。 2,一般可能会想通过 % 求余来确定位置,这样也可以,只不过性能不如 & 运算。而且当n是2的幂次方时:hash & (length - 1) == hash % length 3,因此,HashMap 容量为2次幂的原因,就是为了数据的的均匀分布,减少hash冲突,毕竟hash冲突越大,代表数组中一个链的长度越大,这样的话会降低hashmap的性能 好了,今天就先分享到这里了,下期继续给大家带来HashMap面试内容!更多干货、优质文章,欢迎关注我的原创技术公众号~ 文章好看点这里 本文分享自微信公众号 - 程序员的时光(gh_9211ec727426)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

android简单短信接收——中级编

短信 short message service,简称SMS 是用户通过手机或其他电信终端直接发送或接收的文字或数字信息,用户每次能接收和发送短信的字符数,是160个英文或数字字符,或者70个中文字符。现在我通过Emulator Control向5554发送短信,如果5554收到短信将会提示,下面我们先看一下发来的短信提示图: 我们看一下方法类: packagecom.smart.sms; importandroid.content.BroadcastReceiver; importandroid.content.Context; importandroid.content.Intent; importandroid.os.Bundle; importandroid.telephony.SmsMessage; importandroid.widget.Toast; publicclassSmsReceiverextendsBroadcastReceiver{ @Override publicvoidonReceive(Contextcontext,Intentintent){ if("android.provider.Telephony.SMS_RECEIVED".equals(intent.getAction())){ StringBuildersb=newStringBuilder(); //接收由SMS传过来的数据 Bundlebundle=intent.getExtras(); //判断是否有数据 if(bundle!=null){ //通过pdus可以获得接收到的所有短信消息 Object[]objArray=(Object[])bundle.get("pdus"); //构建短信对象array,并依据收到的对象长度来创建array的大小 SmsMessage[]message=newSmsMessage[objArray.length]; for(inti=0;i<objArray.length;i++){ message[i]=SmsMessage.createFromPdu((byte[])objArray[i]); } //将送来的短信合并自定义信息于StringBuilder当中 for(SmsMessagecurrentMessage:message){ sb.append("短信来源"); //获得接收短信的电话号码 sb.append(currentMessage.getDisplayMessageBody()); sb.append("\n------短信内容------\n"); //获得短信的内容 sb.append(currentMessage.getDisplayMessageBody()); } IntentmainIntent=newIntent(context,SmsActivity.class); mainIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(mainIntent); Toast.makeText(context,sb.toString(),Toast.LENGTH_LONG).show(); } } } } main.xml文件编写代码: <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/textview" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textSize="15dp" android:text="SMART收短信提示" /> </LinearLayout> 附件:http://down.51cto.com/data/2357601 本文转自 llb988 51CTO博客,原文链接:http://blog.51cto.com/llb988/498644,如需转载请自行联系原作者

优秀的个人博客,低调大师

全!iOS 面试题汇总

2015-10-20CocoaChina 作者:Job_Yang 之前看了很多面试题,感觉要不是不够就是过于冗余,于是我将网上的一些面试题进行了删减和重排,现在分享给大家。(题目来源于网络,侵删) 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 非原子操作,决定编译器生成的setter getter是否是原子操作,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函数中写的一样. 使用也很简单, 比如[[[NSString alloc]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,加入数组自动+1 3 retain+1,release-1,release-1 2 数组删除所有对象,所有数组内的对象自动-1 1 11. 内存管理的几条原则时什么?按照默认法则.那些关键字生成的对象需要手动释放?在和property结合的时候怎样有效的避免内存泄露? 答:谁申请,谁释放 遵循Cocoa Touch的使用原则; 内存管理主要要避免“过早释放”和“内存泄漏”,对于“过早释放”需要注意@property设置特性时,一定要用对特性关键字,对于“内存泄漏”,一定要申请了要负责释放,要细心。 关键字alloc 或new 生成的对象需要手动释放; 设置正确的property属性,对于retain需要在合适的地方释放, 12.如何对iOS设备进行性能测试? 答: Profile-> Instruments ->Time Profiler 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 class Factory{ public static Sample creator(int which){ if(which==1) returnnewSampleA(); elseif(which==2) returnnewSampleB(); } } 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 [self addObserver:self forKeyPath:@"highlighted"options:0 context:nil]; #pragma mark KVO - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if([keyPath isEqualToString:@"highlighted"] ) { [self setNeedsDisplay]; } } 对于系统是根据keypath去取的到相应的值发生改变,理论上来说是和kvc机制的道理是一样的。 对于kvc机制如何通过key寻找到value: “当通过KVC调用对象时,比如:[self valueForKey:@”someKey”]时,程序会自动试图通过几种不同的方式解析这个调用。首先查找对象是否带有 someKey 这个方法,如果没找到,会继续查找对象是否带有someKey这个实例变量(iVar),如果还没有找到,程序会继续试图调用 -(id) valueForUndefinedKey:这个方法。如果这个方法还是没有被实现的话,程序会抛出一个NSUndefinedKeyException异常错误。 (cocoachina.com注:Key-Value Coding查找方法的时候,不仅仅会查找someKey这个方法,还会查找getsomeKey这个方法,前面加一个get,或者_someKey以及_getsomeKey这几种形式。同时,查找实例变量的时候也会不仅仅查找someKey这个变量,也会查找_someKey这个变量是否存在。) 设计valueForUndefinedKey:方法的主要目的是当你使用-(id)valueForKey方法从对象中请求值时,对象能够在错误发生前,有最后的机会响应这个请求。这样做有很多好处,下面的两个例子说明了这样做的好处。“ 来至cocoa,这个说法应该挺有道理。 因为我们知道button却是存在一个highlighted实例变量.因此为何上面我们只是add一个相关的keypath就行了,可以按照kvc查找的逻辑理解,就说的过去了。 20. 代理的作用? 答:代理的目的是改变或传递控制链。允许一个类在某些特定时刻通知到其他类,而不需要获取到那些类的指针。可以减少框架复杂度。另外一点,代理可以理解为java中的回调监听机制的一种类似。 21. oc中可修改和不可以修改类型。 答:可修改不可修改的集合类。这个我个人简单理解就是可动态添加修改和不可动态添加修改一样。比如NSArray和NSMutableArray。前者在初始化后的内存控件就是固定不可变的,后者可以添加等,可以动态申请新的内存空间。 22. 我们说的oc是动态运行时语言是什么意思? 答:多态。 主要是将数据类型的确定由编译时,推迟到了运行时。 这个问题其实浅涉及到两个概念,运行时和多态。简单来说,运行时机制使我们直到运行时才去决定一个对象的类别,以及调用该类别对象指定方法。 多态:不同对象以自己的方式响应相同的消息的能力叫做多态。意思就是假设生物类(life)都用有一个相同的方法-eat; 那人类属于生物,猪也属于生物,都继承了life后,实现各自的eat,但是调用是我们只需调用各自的eat方法。 也就是不同的对象以自己的方式响应了相同的消息(响应了eat这个选择器)。因此也可以说,运行时机制是多态的基础?~~~ 23. 通知和协议的不同之处? 答:协议有控制链(has-a)的关系,通知没有。首先我一开始也不太明白,什么叫控制链(专业术语了~)。但是简单分析下通知和代理的行为模式,我们大致可以有自己的理解。简单来说,通知的话,它可以一对多,一条消息可以发送给多个消息接受者。代理按我们的理解,到不是直接说不能一对多,比如我们知道的明星经济代理人,很多时候一个经济人负责好几个明星的事务。只是对于不同明星间,代理的事物对象都是不一样的,一一对应,不可能说明天要处理A明星要一个发布会,代理人发出处理发布会的消息后,别称B的发布会了。但是通知就不一样,他只关心发出通知,而不关心多少接收到感兴趣要处理。因此控制链(has-a从英语单词大致可以看出,单一拥有和可控制的对应关系。 24. 什么是推送消息? 答:推送通知更是一种技术。简单点就是客户端获取资源的一种手段。普通情况下,都是客户端主动的pull。 推送则是服务器端主动push。 测试push的实现可以查看该博文。 25. 关于多态性 答:多态,子类指针可以赋值给父类。这个题目其实可以出到一切面向对象语言中,因此关于多态,继承和封装基本最好都有个自我意识的理解,也并非一定要把书上资料上写的能背出来 26. 对于单例的理解 答:在objective-c中要实现一个单例类,至少需要做以下四个步骤: 1).为单例对象实现一个静态实例,并初始化,然后设置成nil, 2).实现一个实例构造方法检查上面声明的静态实例是否为nil,如果是则新建并返回一个本类的实例, 3).重写allocWithZone方法,用来保证其他人直接使用alloc和init试图获得一个新实力的时候不产生一个新实例, 4).适当实现allocWitheZone,copyWithZone,release和autorelease。 27. 说说响应链 答: 事件响应链。包括点击事件,画面刷新事件等。在视图栈内从上至下,或者从下之上传播。 可以说点事件的分发,传递以及处理。具体可以去看下touch事件这块。因为问的太抽象化了,严重怀疑题目出到越后面就越笼统。可以从责任链模式,来讲通过事件响应链处理,其拥有的扩展性 28. frame和bounds有什么不同? 答:frame指的是:该view在父view坐标系统中的位置和大小。(参照点是父亲的坐标系统) bounds指的是:该view在本身坐标系统中 的位置和大小。(参照点是本身坐标系统) 29. 方法和选择器有何不同? 答:selector是一个方法的名字,method是一个组合体,包含了名字和实现. 详情可以看apple文档。 30. OC的垃圾回收机制? 答: OC2.0有Garbage collection,但是iOS平台不提供。 一般我们了解的objective-c对于内存管理都是手动操作的,但是也有自动释放池。 但是差了大部分资料,貌似不要和arc机制搞混就好了。 31. NSOperation queue? 答:存放NSOperation的集合类。操作和操作队列,基本可以看成java中的线程和线程池的概念。用于处理ios多线程开发的问题。网上部分资料提到一点是,虽然是queue,但是却并不是带有队列的概念,放入的操作并非是按照严格的先进现出。这边又有个疑点是,对于队列来说,先进先出的概念是Afunc添加进队列,Bfunc紧跟着也进入队列,Afunc先执行这个是必然的,但是Bfunc是等Afunc完全操作完以后,B才开始启动并且执行,因此队列的概念离乱上有点违背了多线程处理这个概念。但是转念一想其实可以参考银行的取票和叫号系统。因此对于A比B先排队取票但是B率先执行完操作,我们亦然可以感性认为这还是一个队列。 但是后来看到一票关于这操作队列话题的文章,其中有一句提到“因为两个操作提交的时间间隔很近,线程池中的线程,谁先启动是不定的。”瞬间觉得这个queue名字有点忽悠人了,还不如pool~。综合一点,我们知道他可以比较大的用处在于可以帮组多线程编程就好了。 32. 什么是延迟加载? 答:懒汉模式,只在用到的时候才去初始化。也可以理解成延时加载。我觉得最好也最简单的一个列子就是tableView中图片的加载显示了。一个延时载,避免内存过高,一个异步加载,避免线程堵塞。 33. 是否在一个视图控制器中嵌入两个tableview控制器? 答:一个视图控制只提供了一个View视图,理论上一个tableViewController也不能放吧,只能说可以嵌入一个tableview视图。当然,题目本身也有歧义,如果不是我们定性思维认为的UIViewController,而是宏观的表示视图控制者,那我们倒是可以把其看成一个视图控制者,它可以控制多个视图控制器,比如TabbarController那样的感觉。 34. 一个tableView是否可以关联两个不同的数据源?你会怎么处理? 答:首先我们从代码来看,数据源如何关联上的,其实是在数据源关联的代理方法里实现的。因此我们并不关心如何去关联他,他怎么关联上,方法只是让我返回根据自己的需要去设置如相关的数据源。因此,我觉得可以设置多个数据源啊,但是有个问题是,你这是想干嘛呢?想让列表如何显示,不同的数据源分区块显示? 35. 什么时候使用NSMutableArray,什么时候使用NSArray? 答:当数组在程序运行时,需要不断变化的,使用NSMutableArray,当数组在初始化后,便不再改变的,使用NSArray。需要指出的是,使用NSArray只表明的是该数组在运行时不发生改变,即不能往NSAarry的数组里新增和删除元素,但不表明其数组內的元素的内容不能发生改变。NSArray是线程安全的,NSMutableArray不是线程安全的,多线程使用到NSMutableArray需要注意。 36. 给出委托方法的实例,并且说出UITableVIew的Data Source方法 答:CocoaTouch框架中用到了大量委托,其中UITableViewDelegate就是委托机制的典型应用,是一个典型的使用委托来实现适配器模式,其中UITableViewDelegate协议是目标,tableview是适配器,实现UITableViewDelegate协议,并将自身设置为talbeview的delegate的对象,是被适配器,一般情况下该对象是UITableViewController。 UITableVIew的Data Source方法有- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; 37. 在应用中可以创建多少autorelease对象,是否有限制? 答案:无 38. 如果我们不创建内存池,是否有内存池提供给我们? 答:界面线程维护着自己的内存池,用户自己创建的数据线程,则需要创建该线程的内存池 39. 什么时候需要在程序中创建内存池? 答:用户自己创建的数据线程,则需要创建该线程的内存池 40. 类NSObject的那些方法经常被使用? 答:NSObject是Objetive-C的基类,其由NSObject类及一系列协议构成。 其中类方法alloc、class、 description 对象方法init、dealloc、– performSelector:withObject:afterDelay:等经常被使用 41. 什么是简便构造方法? 答:简便构造方法一般由CocoaTouch框架提供,如NSNumber的 + numberWithBool: + numberWithChar: + numberWithDouble: + numberWithFloat: + numberWithInt:。Foundation下大部分类均有简便构造方法,我们可以通过简便构造方法,获得系统给我们创建好的对象,并且不需要手动释放。 42. 如何使用Xcode设计通用应用? 答:使用MVC模式设计应用,其中Model层完成脱离界面,即在Model层,其是可运行在任何设备上,在controller层,根据iPhone与iPad(独有UISplitViewController)的不同特点选择不同的viewController对象。在View层,可根据现实要求,来设计,其中以xib文件设计时,其设置其为universal。 43. UIView的动画效果有那些? 答:有很多,如 UIViewAnimationOptionCurveEaseInOut UIViewAnimationOptionCurveEaseIn UIViewAnimationOptionCurveEaseOut UIViewAnimationOptionTransitionFlipFromLeft UIViewAnimationOptionTransitionFlipFromRight UIViewAnimationOptionTransitionCurlUpUIViewAnimationOptionTransitionCurlDown 44. 在iPhone应用中如何保存数据? 答:有以下几种保存机制: 1).通过web服务,保存在服务器上 2).通过NSCoder固化机制,将对象保存在文件中 3).通过SQlite或CoreData保存在文件数据库中 45. 什么是coredata? 答:coredata是苹果提供一套数据保存框架,其基于SQlite 46. 什么是NSManagedObject模型? 答:NSManagedObject是NSObject的子类 ,也是coredata的重要组成部分,它是一个通用的类,实现了core data 模型层所需的基本功能,用户可通过子类化NSManagedObject,建立自己的数据模型。 47. 什么是NSManagedobjectContext? 答:NSManagedobjectContext对象负责应用和数据库之间的交互。 48. 什么是谓词? 答:谓词是通过NSPredicate,是通过给定的逻辑条件作为约束条件,完成对数据的筛选。 predicate = [NSPredicate predicateWithFormat:@"customerID == %d",n]; a = [customers filteredArrayUsingPredicate:predicate]; 49. 和coredata一起有哪几种持久化存储机制? 答:存入到文件、 存入到NSUserDefaults(系统plist文件中)、存入到Sqlite文件数据库 50. 谈谈对Block 的理解?并写出一个使用Block执行UIVew动画? 答:Block是可以获取其他函数局部变量的匿名函数,其不但方便开发,并且可以大幅提高应用的执行效率(多核心CPU可直接处理Block指令 [UIView transitionWithView:self.view duration:0.2 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{ [[blueViewController view] removeFromSuperview]; [[self view] insertSubview:yellowViewController.view atIndex:0]; } completion:NULL]; 51. 写出上面代码的Block的定义。 答: typedef void(^animations) (void); typedef void(^completion) (BOOL finished); 52. 试着使用+ beginAnimations:context:以及上述Block的定义,写出一个可以完成 + (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion NS_AVAILABLE_IOS(4_0); 操作的函数执行部分 答案:无 53. 做过的项目是否涉及网络访问功能,使用什么对象完成网络功能? 答:ASIHTTPRequest与NSURLConnection 54. 简单介绍下NSURLConnection类及+ sendSynchronousRequest:returningResponse:error:与– initWithRequest:delegate:两个方法的区别? 答: NSURLConnection主要用于网络访问,其中+ sendSynchronousRequest:returningResponse:error:是同步访问数据,即当前线程会阻塞,并等待request的返回的response,而– initWithRequest:delegate:使用的是异步加载,当其完成网络访问后,会通过delegate回到主线程,并其委托的对象。 55. 多线程是什么 答: 多线程是个复杂的概念,按字面意思是同步完成多项任务,提高了资源的使用效率,从硬件、操作系统、应用软件不同的角度去看,多线程被赋予不同的内涵,对于硬件,现在市面上多数的CPU都是多核的,多核的CPU运算多线程更为出色;从操作系统角度,是多任务,现在用的主流操作系统都是多任务的,可以一边听歌、一边写博客;对于应用来说,多线程可以让应用有更快的回应,可以在网络下载时,同时响应用户的触摸操作。在iOS应用中,对多线程最初的理解,就是并发,它的含义是原来先做烧水,再摘菜,再炒菜的工作,会变成烧水的同时去摘菜,最后去炒菜。 56. iOS 中的多线程 答: iOS中的多线程,是Cocoa框架下的多线程,通过Cocoa的封装,可以让我们更为方便的使用线程,做过C++的同学可能会对线程有更多的理解,比如线程的创立,信号量、共享变量有认识,Cocoa框架下会方便很多,它对线程做了封装,有些封装,可以让我们创建的对象,本身便拥有线程,也就是线程的对象化抽象,从而减少我们的工程,提供程序的健壮性。 GCD是(Grand Central Dispatch)的缩写 ,从系统级别提供的一个易用地多线程类库,具有运行时的特点,能充分利用多核心硬件。GCD的API接口为C语言的函数,函数参数中多数有Block,关于Block的使用参看这里,为我们提供强大的“接口”,对于GCD的使用参见本文 NSOperation与Queue NSOperation是一个抽象类,它封装了线程的细节实现,我们可以通过子类化该对象,加上NSQueue来同面向对象的思维,管理多线程程序。具体可参看这里:一个基于NSOperation的多线程网络访问的项目。 NSThread NSThread是一个控制线程执行的对象,它不如NSOperation抽象,通过它我们可以方便的得到一个线程,并控制它。但NSThread的线程之间的并发控制,是需要我们自己来控制的,可以通过NSCondition实现。 参看 iOS多线程编程之NSThread的使用 其他多线程 在Cocoa的框架下,通知、Timer和异步函数等都有使用多线程,(待补充). 57. 在项目什么时候选择使用GCD,什么时候选择NSOperation? 答: 项目中使用NSOperation的优点是NSOperation是对线程的高度抽象,在项目中使用它,会使项目的程序结构更好,子类化NSOperation的设计思路,是具有面向对象的优点(复用、封装),使得实现是多线程支持,而接口简单,建议在复杂项目中使用。 项目中使用GCD的优点是GCD本身非常简单、易用,对于不复杂的多线程操作,会节省代码量,而Block参数的使用,会是代码更为易读,建议在简单项目中使用。 58. 什么是block 答: 对于闭包(block),有很多定义,其中闭包就是能够读取其它函数内部变量的函数,这个定义即接近本质又较好理解。对于刚接触Block的同学,会觉得有些绕,因为我们习惯写这样的程序main(){ funA();} funA(){funB();} funB(){…..}; 就是函数main调用函数A,函数A调用函数B… 函数们依次顺序执行,但现实中不全是这样的,例如项目经理M,手下有3个程序员A、B、C,当他给程序员A安排实现功能F1时,他并不等着A完成之后,再去安排B去实现F2,而是安排给A功能F1,B功能F2,C功能F3,然后可能去写技术文档,而当A遇到问题时,他会来找项目经理M,当B做完时,会通知M,这就是一个异步执行的例子。在这种情形下,Block便可大显身手,因为在项目经理M,给A安排工作时,同时会告诉A若果遇到困难,如何能找到他报告问题(例如打他手机号),这就是项目经理M给A的一个回调接口,要回掉的操作,比如接到电话,百度查询后,返回网页内容给A,这就是一个Block,在M交待工作时,已经定义好,并且取得了F1的任务号(局部变量),却是在当A遇到问题时,才调用执行,跨函数在项目经理M查询百度,获得结果后回调该block。 59. block 实现原理 答: Objective-C是对C语言的扩展,block的实现是基于指针和函数指针。 从计算语言的发展,最早的goto,高级语言的指针,到面向对象语言的block,从机器的思维,一步步接近人的思维,以方便开发人员更为高效、直接的描述出现实的逻辑(需求)。 使用实例 cocoaTouch框架下动画效果的Block的调用 使用typed声明block typedef void(^didFinishBlock) (NSObject *ob); 这就声明了一个didFinishBlock类型的block, 然后便可用 @property (nonatomic,copy) didFinishBlock finishBlock; 声明一个blokc对象,注意对象属性设置为copy,接到block 参数时,便会自动复制一份。 __block是一种特殊类型, 使用该关键字声明的局部变量,可以被block所改变,并且其在原函数中的值会被改变。 60.关于block 答: 面试时,面试官会先问一些,是否了解block,是否使用过block,这些问题相当于开场白,往往是下面一系列问题的开始,所以一定要如实根据自己的情况回答。 1). 使用block和使用delegate完成委托模式有什么优点? 首先要了解什么是委托模式,委托模式在iOS中大量应用,其在设计模式中是适配器模式中的对象适配器,Objective-C中使用id类型指向一切对象,使委托模式更为简洁。了解委托模式的细节: iOS设计模式—-委托模式 使用block实现委托模式,其优点是回调的block代码块定义在委托对象函数内部,使代码更为紧凑; 适配对象不再需要实现具体某个protocol,代码更为简洁。 2). 多线程与block GCD与Block 使用 dispatch_async 系列方法,可以以指定的方式执行block GCD编程实例 dispatch_async的完整定义 void dispatch_async( dispatch_queue_t queue, dispatch_block_t block); 功能:在指定的队列里提交一个异步执行的block,不阻塞当前线程 通过queue来控制block执行的线程。主线程执行前文定义的 finishBlock对象 dispatch_async(dispatch_get_main_queue(),^(void){finishBlock();}); 62.谈谈Object-C的内存管理方式及过程? 答: 1).当你使用new,alloc和copy方法创建一个对象时,该对象的保留计数器值为1.当你不再使用该对象时,你要负责向该对象发送一条release或autorelease消息.这样,该对象将在使用寿命结束时被销毁. 2).当你通过任何其他方法获得一个对象时,则假设该对象的保留计数器值为1,而且已经被设置为自动释放,你不需要执行任何操作来确保该对象被清理.如果你打算在一段时间内拥有该对象,则需要保留它并确保在操作完成时释放它. 3).如果你保留了某个对象,你需要(最终)释放或自动释放该对象.必须保持retain方法和release方法的使用次数相等. 63.Object-C有私有方法吗?私有变量呢? 答: objective-c – 类里面的方法只有两种, 静态方法和实例方法. 这似乎就不是完整的面向对象了,按照OO的原则就是一个对象只暴露有用的东西. 如果没有了私有方法的话, 对于一些小范围的代码重用就不那么顺手了. 在类里面声名一个私有方法 @interface Controller : NSObject { NSString *something; } + (void)thisIsAStaticMethod; – (void)thisIsAnInstanceMethod; @end @interface Controller (private) - (void)thisIsAPrivateMethod; @end @private可以用来修饰私有变量 在Objective‐C中,所有实例变量默认都是私有的,所有实例方法默认都是公有的 本文未完,余下部分见:http://www.cocoachina.com/programmer/20151019/13746.html 程序猿神奇的手,每时每刻,这双手都在改变着世界的交互方式! 本文转自当天真遇到现实博客园博客,原文链接:http://www.cnblogs.com/XYQ-208910/p/4896814.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

中国物联网产业规模已9000亿元 年复合增长率25%

中国工信部副部长罗文表示,中国物联网(IoT)产业在2016年的产值已超过9300亿元人民币(合1420亿美元),高于2009年的1700亿元。 IoT是通过传感器和数据交换,将更多的日常用品和电器、可穿戴设备和车辆以及工业设备实现互联网平台上相互连接的概念。 罗文在无锡世界物联网博览会上表示,中国的物联网业务正迅速增长,平均年复合增长率超过25%。他认为,庞大的国内市场,全国完整的产业链和全球最大的移动通信网络,不难看出中国在物联网技术的某些子行业处于领先地位;特别是考虑到政府的支持计划。 罗文表示,政府将支持建立一批科技中心和实验室,共同开发技术,还将进一步推广到农业、医疗、环保、物流等领域。 科技部副部长王志刚则表示,中国正在努力制定设备通信的国际标准,这种参与能获得相应的回报。 近年来,物联网嵌入了越来越多的设备,应用也在飞速发展。波士顿咨询集团今年早些时候发布的研究报告估计,到2020年,对物联网技术、应用和解决方案的B2B支出将达到2670亿美元。IHS报告称,2015年物联网设备约为1 54亿台,这一数字到2020年将增长到307亿美元,2025年增长到754亿美元。英特尔对这个市场的预测更大胆,它预测2020年对于物联网来说是一个真正的爆发年,全球将有2000亿个物联网设备——平均每个人几乎有三台设备。 作为物联网领域的重要板块,移动支付在中国发展迅猛,目前已领先全球。近日,国外调研机构Ipsos公布了一项移动支付的调查报告,报告显示中国移动支付普及率全球第一,普及率为77%,印度为76%、印尼为67%、韩国为64%,而日本在亚洲地区普及率最低,仅为27%。 本文转自d1net(转载)

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册