首页 文章 精选 留言 我的

精选列表

搜索[网站开发],共10000篇文章
优秀的个人博客,低调大师

Android JNI开发系列(十一) JNI 访问父类的构造方法和父类实例方法

JNI 访问父类的构造方法和父类实例方法 构造方法和父类实例方法 先看一段Java代码, Java package org.professor.jni.animal; import android.util.Log; public class Animal { protected String name; public Animal(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void eat() { Log.i("ANIMAL", "ANIMAL EAT FOOD"); } } package org.professor.jni.animal; import android.util.Log; public class Bird extends Animal { public Bird(String name) { super(name); Log.i("ANIMAL", "BIRD Constructor"); } @Override public String getName() { Log.i("ANIMAL", "BIRD Get Name Method"); return name; } @Override public void eat() { Log.i("ANIMAL", "BIRD EAT MI"); } } 简单看下上面代码,很简单的两个类,父类 Animal ,子类 Bird , Animal 类中定义了 eat() 和 getName() 两个方法,Bird 继承自 Animal ,并重写了父类的两个方法。如果调用的话可以用 Animal bird = new Bird("Professor"); , bird.eat() 。在执行 new Bird("Professor")这段代码时, 会先为 Bird 类分配内存空间(所分配的内存空间大小由 Bird 类的成员变量数量决定),然后调用 Bird 的带参构造方法初始化对象。 Bird 是 Animal 类型,但它指向的是 Bird 实例对象的引用,而且 Bird 重写了父类的 eat 方法,因为调用 eat 方法时有多态存在,所以访问的是 Bird 的 eat 而非 Animal 的 eat,运行后打印的结果为: BIRD EAT MI ; 如果要调用父类的 eat() 方法,只需在 Cat 的 eat() 方法中调用 super.eat() 即可。 在C / C++ 中,栈空间和堆空间,栈空间的内存大小受操作系统限制,由操作系统自动来管理,速度较快,所以在函数中定义的局部变量、函数形参变量都存储在栈空间。操作系统没有限制堆空间的内存大小,只受物理内存的限制,内存需要程序员自己管理。在 C 语言中用 malloc 关键字动态分配的内存和在 C++ 中用 new 创建的对象所分配内存都存储在堆空间,内存使用完之后分别用 free 或 delete/delete[] 释放。 Native层发访问父类构造方法和父类实例方法 头文件 // // Created by Peng Cai on 2018/10/16. // # include # ifndef ANDROIDJNIDEMO_CALL_SUPER_H # define ANDROIDJNIDEMO_CALL_SUPER_H # ifdef __cplusplus extern "C" { # endif /* - Class: org_professor_jni_MainActivity - Method: callNativeSuperInstanceMethod - Signature: ()V */ JNIEXPORT void JNICALL Java_org_professor_jni_MainActivity_callNativeSuperInstanceMethod (JNIEnv *, jobject); # ifdef __cplusplus } # endif # endif //ANDROIDJNIDEMO_CALL_SUPER_H 实现文件 // // Created by Peng Cai on 2018/10/16. // # include "include/call_super.h" # include # include # include JNIEXPORT void JNICALL Java_org_professor_jni_MainActivity_callNativeSuperInstanceMethod(JNIEnv *env, jobject instance) { //1. 获取类类型 jclass birdClazz = (*env)->FindClass(env, "org/professor/jni/animal/Bird"); if (NULL == birdClazz) { __android_log_print(ANDROID_LOG_WARN, "ANIMAL", "Create Bird Class Failed"); return; } //2.获取构造函数ID 构造方法的名统一为:<init> jmethodID birdInstanceMethodId = (*env)->GetMethodID(env, birdClazz, "<init>", "(Ljava/long/String;)V"); if (NULL == birdInstanceMethodId) { __android_log_print(ANDROID_LOG_WARN, "ANIMAL", "Create Bird Instance Method Id Failed"); return; } //3. 创建一个对象实例 jstring name = (*env)->NewStringUTF(env, "YIMI"); if (NULL == name) { //有可能内存不够 __android_log_print(ANDROID_LOG_WARN, "ANIMAL", "Create Bird Name Failed"); return; } jobject birdObj = (*env)->NewObject(env, birdClazz, birdInstanceMethodId, name); if (NULL == birdObj) { __android_log_print(ANDROID_LOG_WARN, "ANIMAL", "Create Bird Instance Obj Failed"); return; } // 4.获取调用方法ID jmethodID birdGetNameMethodID = (*env)->GetMethodID(env, birdClazz, "getName", "()Ljava/long/String;"); if (NULL == birdGetNameMethodID) { __android_log_print(ANDROID_LOG_WARN, "ANIMAL", "Create Bird Get Name Method Id Failed"); return; } //5. 调用自己getName方法 jstring birdName = (*env)->CallObjectMethod(env, birdObj, birdGetNameMethodID); if (NULL != birdName) { const char *c_bird_name = (*env)->GetStringUTFChars(env, birdName, JNI_FALSE); //转换编码格式 在C里面用 JNI_FALSE代表不拷贝到缓冲区 if (NULL != c_bird_name) { __android_log_print(ANDROID_LOG_WARN, "ANIMAL bird name = %s", c_bird_name); //释放从java层获取到的字符串所分配的内存 (*env)->ReleaseStringUTFChars(env, birdName, c_bird_name); } } //-------华丽分割线-------------- //6. 获取父类的Clazz jclass animalClazz = (*env)->FindClass(env, "org/professor/jni/Animal"); if (NULL == animalClazz) { __android_log_print(ANDROID_LOG_WARN, "ANIMAL", "Create Animal Class Failed"); return; } //7.获取父类方法ID eat方法 jmethodID animalEatMethodID = (*env)->GetMethodID(env, animalClazz, "eat", "()V"); if (NULL == animalEatMethodID) { __android_log_print(ANDROID_LOG_WARN, "ANIMAL", "Create Animal Eat Method Id Failed"); return; } //8.子类调用父类方法 eat //注意:birdObj是Bird的实例,animalClazz是Animal的Class引用,animalEatMethodID是Animal类中的方法ID (*env)->CallNonvirtualVoidMethod(env, birdObj, animalClazz, animalEatMethodID); //--------------华丽分割线------------------ // 9.获取父类调用方法getName jmethodID animalGetNameMethodID = (*env)->GetMethodID(env, animalClazz, "getName", "()Ljava/long/String;"); if (NULL == animalGetNameMethodID) { __android_log_print(ANDROID_LOG_WARN, "ANIMAL", "Create Animal Get Name Method Id Failed"); return; } //10.子类调用父类GetName 方法 jstring animalName = (*env)->CallNonvirtualObjectMethod(env, birdObj, animalClazz, animalGetNameMethodID); if (NULL != animalName) { const char *c_animal_name = (*env)->GetStringUTFChars(env, animalName, JNI_FALSE); if (NULL != c_animal_name) { __android_log_print(ANDROID_LOG_WARN, "ANIMAL animal name = %s", c_animal_name); //释放从java层获取到的字符串所分配的内存 (*env)->ReleaseStringUTFChars(env, animalName, c_animal_name); } } quit: // 删除局部引用变量 jmethod 不是引用类型 (jobject或jobject的子类才属于引用变量) (*env)->DeleteLocalRef(env, birdClazz); (*env)->DeleteLocalRef(env, animalClazz); (*env)->DeleteLocalRef(env, name); (*env)->DeleteLocalRef(env, birdObj); (*env)->DeleteLocalRef(env, birdName); (*env)->DeleteLocalRef(env, animalName); } ``` 总结 调用构造方法 jobject birdObj = (*env)->NewObject(env, birdClazz, birdInstanceMethodId, name); 我们通过上面的代码去创建一个为初始化的对像并分配非存空间,然后调用对象的构造器去初始化对象。其实也可以通过下民的方式去做 jobject birdObj = (*env)->AllocObject(env, birdClazz); if(NULL !=birdObj){ (*env)->CallNonvirtualVoidMethod(env,birdObj,birdClazz,birdInstanceMethodId,name); if((*env)->ExceptionCheck(env)){ goto quit; //跳转到释放函数表 } } AllocObject 函数创建的是一个未初始化的对象,后面在用这个对象之前,必须调用CallNonvirtualVoidMethod, 调用对象的构造函数初始化该对象。而且在使用时一定要非常小心,确保在一个对象上面,构造函数最多被调用一次。有时,先创建一个初始化的对象,然后在合适的时间再调用构造函数的方式是很有用的。尽管如此,大部分情况下,应该使用 NewObject,尽量避免使用容易出错的 AllocObject/CallNonvirtualVoidMethod 函数。 调用实例方法 如果一个方法被定义在父类中,在子类中被覆盖,也可以调用父类中的这个实例方法。JNI 提供了一系列函数CallNonvirtualXXXMethod 来支持调用各种返回值类型的实例方法。调用一个定义在父类中的实例方法,须遵循下面的步骤: 使用 GetMethodID 函数从一个指向父类的 Class 引用当中获取方法 ID。 //7.获取父类方法ID eat方法 jmethodID animalEatMethodID = (*env)->GetMethodID(env, animalClazz, "eat", "()V"); if (NULL == animalEatMethodID) { __android_log_print(ANDROID_LOG_WARN, "ANIMAL", "Create Animal Eat Method Id Failed"); return; } 传入子类对象、父类 Class 引用、父类方法 ID 和参数,并调用 CallNonvirtualVoidMethod、 CallNonvirtualBooleanMethod、CallNonvirtualIntMethod 等一系列函数中的一个。其中CallNonvirtualVoidMethod 也可以被用来调用父类的构造函数。 //8.子类调用父类方法 eat //注意:birdObj是Bird的实例,animalClazz是Animal的Class引用,animalEatMethodID是Animal类中的方法ID (*env)->CallNonvirtualVoidMethod(env, birdObj, animalClazz, animalEatMethodID);

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

24、【支付模块开发】——将下载下来的支付宝API Demo运行在web上

上一篇23、【支付模块快发】——Java对接支付宝步骤(沙箱环境)我们讲解了怎么配置相关配置文件,下面我们调试一下怎么使其在IDEA的web项目中跑起来,然后在浏览器中进行操作 我们用IDEA导入支付宝对接Demo的是时候发现不能运行,下面讲解一下怎么在IDEA中运行支付宝Demo并且在浏览器中运行出来~ 首先我们点击IDEA上面的这个按钮: image.png 或者点击: Project Structure... image.png 然后按图中操作: image.png 下一步选中我们的项目: image.png 然后点击下方的Apply... 下一步: image.png 选择我们的项目: image.png 点击OK: image.png 点击Add Configuration image.png image.png image.png image.png Apply... image.png 乌拉,下面就可以点击下面的运行按钮啦~ image.png 测试我们的二维码支付: image.png 填写参数: image.png 确认之后就会跳转到二维码啦: image.png image.png image.png perfect~

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

Spring Cloud Spring Boot mybatis分布式微服务云架构(八)开发Web应用(2)

在完成配置之后,举一个简单的例子,在快速入门工程的基础上,举一个简单的示例来通过Thymeleaf渲染一个页面。 @Controller public class HelloController { @RequestMapping("/") public String index(ModelMap map) { // 加入一个属性,用来在模板中读取 map.addAttribute("host", "http://blog.didispace.com"); // return模板文件的名称,对应src/main/resources/templates/index.html return "index"; } } <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8" /> <title></title> </head> <body> <h1 th:text="${host}">Hello World</h1> </body> </html> 如上页面,直接打开html页面展现Hello World,但是启动程序后,访问http://localhost:8080/,则是展示Controller中host的值:http://blog.didispace.com,做到了不破坏HTML自身内容的数据逻辑分离。 更多Thymeleaf的页面语法,还请访问Thymeleaf的官方文档查询使用。 Thymeleaf的默认参数配置 如有需要修改默认配置的时候,只需复制下面要修改的属性到application.properties中,并修改成需要的值,如修改模板文件的扩展名,修改默认的模板路径等。 # Enable template caching. spring.thymeleaf.cache=true # Check that the templates location exists. spring.thymeleaf.check-template-location=true # Content-Type value. spring.thymeleaf.content-type=text/html # Enable MVC Thymeleaf view resolution. spring.thymeleaf.enabled=true # Template encoding. spring.thymeleaf.encoding=UTF-8 # Comma-separated list of view names that should be excluded from resolution. spring.thymeleaf.excluded-view-names= # Template mode to be applied to templates. See also StandardTemplateModeHandlers. spring.thymeleaf.mode=HTML5 # Prefix that gets prepended to view names when building a URL. spring.thymeleaf.prefix=classpath:/templates/ # Suffix that gets appended to view names when building a URL. spring.thymeleaf.suffix=.html spring.thymeleaf.template-resolver-order= # Order of the template resolver in the chain. spring.thymeleaf.view-names= # Comma-separated list of view names that can be resolved. 支持JSP的配置Spring Boot并不建议使用,但如果一定要使用,可以参考此工程作为脚手架:JSP支持

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

Spring Boot开发时遇到的一系列问题及解决办法总结

问题一 Spring Boot扫描包提示找不到mapper的问题,异常信息内容: Considerdefiningabeanoftypeinyourconfiguration 分析原因:Spring Boot项目的Bean装配默认规则是根据Application类所在的包位置从上往下扫描,“Application类”是指Spring Boot项目入口类。如果Application类所在的包为:com.yoodb.blog,则只会扫描com.yoodb.blog包及其所有子包,如果service或dao所在包不在com.yoodb.blog及其子包下,则不会被扫描。 解决方法: 方式一:使用注解@ComponentScan(value=”com.yoodb.blog”),其中,com.yoodb.blog为包路径。 方式二:将启动类Application放在上一级包中,注意的是Application启动类必须要保证在包的根目录下。 问题二 启动Spring Boot时,,抛出异常信息如下: YourApplicationContextisunlikelytostartduetoa@ComponentScanofthedefaultpackage application.Java类文件内容如下: importorg.springframework.boot.autoconfigure.SpringBootApplication; importorg.springframework.context.annotation.Configuration; importorg.springframework.stereotype.Controller; importorg.springframework.web.bind.annotation.RequestMapping; importorg.springframework.web.bind.annotation.ResponseBody; importorg.springframework.boot.SpringApplication; @Controller @SpringBootApplication @Configuration publicclassHelloApplication{ @RequestMapping("hello") @ResponseBody publicStringhello(){ return"helloworld!"; } publicstaticvoidmain(String[]args){ SpringApplication.run(HelloApplication.class,args); } } 分析原因:Spring Boot启动时,抛出“** WARNING ** : Your ApplicationContext is unlikely to start due to a @ComponentScan of the default package.”警告信息,这是由于application.Java文件不能直接放在main/java文件夹下,必须要建一个包把它放进去。 解决办法:Spring Boot在写启动类的时候如果不使用@ComponentScan指明对象扫描范围,默认指扫描当前启动类所在的包里的对象,如果当前启动类没有包,则在启动时会抛出上述警告信息,导致项目出错。 问题三 Spring Boot连接数据库时,抛出异常信息如下: causedby:java.lang.NoClassDefFoundError:javassist/bytecode/ClassFile 分析原因:这是由于缺少javassist.jar包导致启动失败 解决办法:通过Eclipse执行Maven命令重构项目:Maven-Update Project,等待下载jar包即可,若还是失败请手动添加javassist.jar包的pom.xml配置信息。 Spring Boot使用spring-data-jpa插件,抛出异常信息如下: causedby:java.lang.illegalargumentexception:Notamanagedtype:classentity.User 分析原因:这是由于Spring Boot未找到实体对象指定的类名,缺少jpa entity配置路径 解决办法:在Repository配置类前面添加注解@EntityScan('entity对应的包路径')。 问题四 Spring Boot返回json字符串,增加APPLICATION_JSON参数代码如下: mvc.perform(MockMvcRequestBuilders.get("/hello").accept(MediaType.APPLICATION_JSON)) 在添加APPLICATION_JSON参数后,抛出“APPLICATION_JSON cannot be resolved or is not a field”异常信息。 分析原因:Bean实体中存在getX或setX方法,但是没有这个x属性,将导致json转换失败,抛出“APPLICATION_JSON cannot be resolved or is not a field”异常信息。 解决办法:去掉不存在属性的getX或setX方法或者增加上改属性即可。

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

如何解决spark开发中遇到需要去掉文件前几行数据的问题

版权声明:本文由董可伦首发于https://dongkelun.com,非商业转载请注明作者及原创出处。商业转载请联系作者本人。 https://blog.csdn.net/dkl12/article/details/80550095 我的原创地址:https://dongkelun.com/2018/05/27/sparkDelFirstNLines/ 前言 我碰到的问题是这样的,我需要读取压缩文件里的数据存到hive表里,压缩文件解压之后是一个txt,这个txt里前几行的数据是垃圾数据,而这个txt文件太大,txt是直接打不开的,所以不能手动打开删除前几行数据,而这个文件是业务人员从别人那拿到的所以也不能改,本文就是讲如何解决这个问题。 1、数据 首先造几条数据,以理解我的需求 data.txt id name addr time ------------ ------------------- --------------- -------------------- 1 zhangsan shanghai 2018-05-25 2 zhangsan shanghai 2018-05-25 3 zhangsan shanghai 2018-05-25 4 zhangsan shanghai 2018-05-25 5 zhangsan shanghai 2018-05-25 其中前三行是我不想要的数据,第一行为空,第二行为字段名,第三行应该是为了美观单独加了一行。 2、尝试用代码解决 2.1 思路一 用zipWithIndex给rdd加上索引,索引从0开始依次次递增1 val path = "files/data.txt" val rdd = sc.textFile(path) println("分区数:" + rdd.getNumPartitions) val rdd1 = rdd.zipWithIndex() //过滤掉索引小于等于2的 val rdd2 = rdd1.filter(_._2 > 2) rdd1.foreach(println) println("**********分割线***********") rdd2.map(kv => kv._1).foreach(println) 分区数:1 (,0) (id name addr time ,1) (------------ ------------------- --------------- --------------------,2) (1 zhangsan shanghai 2018-05-25,3) (2 zhangsan shanghai 2018-05-25,4) (3 zhangsan shanghai 2018-05-25,5) (4 zhangsan shanghai 2018-05-25,6) (5 zhangsan shanghai 2018-05-25,7) **********分割线*********** 1 zhangsan shanghai 2018-05-25 2 zhangsan shanghai 2018-05-25 3 zhangsan shanghai 2018-05-25 4 zhangsan shanghai 2018-05-25 5 zhangsan shanghai 2018-05-25 将rdd的分区改为8(大于1即可)测试一下 将 val rdd = sc.textFile(path) 改为 val rdd = sc.textFile(path, 8) 发现结果是一样的 因为我不太熟悉读取本地数据分区和读取hdfs数据分区的是否一样,所以将数据放在分布式的hdfs上测试一下 首先将data.txt上传的hdfs上 hadoop fs -put data.txt /tmp/dkl/ 将代码中的path改为 val path = "hdfs://ambari.master.com:8020/tmp/dkl/data.txt" 发现最后的结果也是一样的(分区数可能不一样) 那么这样看来这个思路是可以解决这个问题的,但是我举得例子数据量比较少,在实际工作中数据量大的话,用zipWithIndex会有性能问题。 2.2 思路2 尝试直接获取rdd的前几行数据,然后过滤掉这几行数据,但是这个前提是前几行数据在rdd里是唯一的,否在会过滤掉其他行一样的数据,我的使用场景是删掉垃圾数据,如果其他行也有一样的数据,那么正好删掉了~ val path = "files/data.txt" val rdd = sc.textFile(path, 8) println("分区数:" + rdd.getNumPartitions) //前三条 val arr = rdd.take(3) //过滤掉arr里的数据 val rdd3 = rdd.filter(!arr.contains(_)) rdd3.foreach(println) 结果 分区数:8 1 zhangsan shanghai 2018-05-25 2 zhangsan shanghai 2018-05-25 3 zhangsan shanghai 2018-05-25 4 zhangsan shanghai 2018-05-25 5 zhangsan shanghai 2018-05-25 从结果看是可以解决我的问题,且和分区多少无关,大家可以试一下。 2.3 关于rdd前几行的定义 一开始我对于rdd前几行的数据的定义是有疑惑的,不知道改变rdd分区的数目,通过rdd.first或者rdd.take获取到的前几条数据是否是固定的,此次通过写代码测试,确定是和分区无关的,而且我担心测试数据量过小,将1.5G的txt放在hdfs测试,并且不指定分区数目(默认)进行测试,发现分区默认大小13,前几行数据依旧是固定,由此更加确认和rdd分区无关。 2.4 关于rdd重新分区 可通过repartition和coalesce对rdd进行重新分区,通过如下代码测试 rdd.repartition(3).take(3).foreach(println) rdd.coalesce(3).take(3).foreach(println) 通过结果得出coalesce之后顺序和之前的顺序是一样的,而repartition之后的顺序和之前不一样了,也就是如果rdd进行repartition之后的前几行和原来的前几行是不一样的,但是重新分区的数目固定的话,每次repartition之后的顺序是一样的。 注:repartition 内部实现调用的 coalesce 且为coalesce中 shuffle = true的实现 关于Spark中repartition和coalesce的使用场景,参考Spark中repartition和coalesce的区别与使用场景解析 因为我没有repartition的需求,所以可以通过2.2的代码解决我的问题,且如果有repartition的需求,可以在删掉前几行之后再repartition~ 3、通过Linux命令删除文件前几行 命令如下: cat data.txt id name addr time ------------ ------------------- --------------- -------------------- 1 zhangsan shanghai 2018-05-25 2 zhangsan shanghai 2018-05-25 3 zhangsan shanghai 2018-05-25 4 zhangsan shanghai 2018-05-25 5 zhangsan shanghai 2018-05-25 tail -n+4 data.txt > data_new.txt cat data_new.txt 1 zhangsan shanghai 2018-05-25 2 zhangsan shanghai 2018-05-25 3 zhangsan shanghai 2018-05-25 4 zhangsan shanghai 2018-05-25 5 zhangsan shanghai 2018-05-25 mv data_new.txt data.txt mv:是否覆盖"data.txt"? y cat data.txt 1 zhangsan shanghai 2018-05-25 2 zhangsan shanghai 2018-05-25 3 zhangsan shanghai 2018-05-25 4 zhangsan shanghai 2018-05-25 5 zhangsan shanghai 2018-05-25 注:其中的cat只是为了便于理解每个操作步骤之后的结果 这样就可以删除文件前三条数据了,之后压缩,上传到hdfs再用spark程序处理即可 参考:linux删除大文件的前n行 4、最后 不知道我对spark的分区的理解是否正确,如果不对的话,欢迎大家提出指正~ 附录 最后附上将此格式的txt文件读取为rdd并转为df的示例程序 package com.dkl.leanring.spark.sql import org.apache.spark.sql.Row import org.apache.spark.sql.SparkSession import org.apache.spark.sql.types.StringType import org.apache.spark.sql.types.StructField import org.apache.spark.sql.types.StructType object Demo { def main(args: Array[String]): Unit = { val spark = SparkSession.builder().appName("DelFirstNLines").master("local").getOrCreate() val sc = spark.sparkContext val path = "files/data.txt" val data = sc.textFile(path, 8) val arr = data.take(3) val rdd = data.filter(!arr.contains(_)) //第二行为列名 val colName = arr(1).split(" +") // +表示根据一个或多个空格进行分割 val schema = StructType(colName.map(fieldName => StructField(fieldName, StringType, true))) val rowRDD = rdd.map(_.split(" +")).map(p => Row(p: _*)) val df = spark.createDataFrame(rowRDD, schema) df.show() spark.stop() } } +---+--------+--------+----------+ | id| name| addr| time| +---+--------+--------+----------+ | 1|zhangsan|shanghai|2018-05-25| | 2|zhangsan|shanghai|2018-05-25| | 3|zhangsan|shanghai|2018-05-25| | 4|zhangsan|shanghai|2018-05-25| | 5|zhangsan|shanghai|2018-05-25| +---+--------+--------+----------+

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

研究人员开发智能衣架Take Off,自带检测功能可对衣服进行杀菌和清洁

Take Off采用木质机身,通过5个可自动翻牌卡片做为“屏幕”来显示时间、温度和穿衣信息。 近来连续的阴雨天气,衣服总是干不了。面对这样的雨天,怎么办呢?如何晒衣服才能干的更快?近日,外国研究人员研发了一款名为Take Off的智能衣架,其采用木质机身,通过5个可自动翻牌卡片做为“屏幕”来显示时间、温度和穿衣信息。 当用户把衣物挂在Take Off顶端,Take Off就会自动开启对应相关衣物的清洁模式,包括清洁时间、温度等,然后喷出蒸汽清洁衣服,同时也会释放出负离子,清除衣服上的臭味和细菌。此外,Take Off还可以自动获取天气数据,如果是阴雨天或是雨雪天,它会提醒你多加衣服。当然,她还会告诉你室外温度,让你提前做好准备。 这款智能衣架在日常使用过程中,还考虑到了噪音问题,贴心的进行了降噪设计,日常使用中不会出现杂音。此外,Take Off还配有一个手持式吸尘器和四种不同质料的刷头,可清洁衣服上的灰尘。 研发人员表示,未来他们还会给Take Off添加更多功能,比如人脸识别或是语音交互功能。其最终目标是让Take Off不仅仅成为一款智能衣架,更是人们生活出行的好伙伴。据悉,这款智能衣架已经开启了预售,大约需要99美元。 如今,智能产品已经智能产品已经与我们的生活越来越近,Take Off的出现改变我们对衣架的看法。但相信随着科技的进步,更多的智能产品将对我们生活带来重大改变。 原文发布时间: 2018-05-09 11:40 本文作者: 星星 本文来自云栖社区合作伙伴镁客网,了解相关信息可以关注镁客网。

资源下载

更多资源
Mario

Mario

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

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

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部分的功能。

用户登录
用户注册