首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

再谈 Send 与 Sync | Rust学习笔记

Send 与 Sync 可能是Rust多线程以及异步代码种最常见到的约束。在前面一篇讨论多线程的文章中介绍过这两个约束的由来。但是,真正书写比较复杂的代码时,还是会经常遇到编译器的各种不配合。这里借用我的同事遇到的一个问题再次举例谈一谈 Send 与 Sync 的故事。 基本场景 C/C++中不存在Send/Sync的概念,数据对象可以任意在多线程中访问,只不过需要程序员保证线程安全,也就是所谓“加锁”。而在Rust中,由于所有权的设计,不能直接将一个对象分成两份或多份,每个线程都放一份。一般地,如果一份数据仅仅子线程使用,我们会将数据的值转移至线程中,这也是Send的基础含义。因此,Rust代码经常会看到将数据clone(),然后move到线程中: let b = aa.clone(); thread::spawn(move || { b... }) 假如,数据需要在多线程共享,情况会复杂一些。我们一般不会在线程中直接使用外部环境变量引用。原因很简单,生命周期的问题。线程的闭包要求‘static,这会与被借用的外部环境变量的生命周期冲突,错误代码如下: let bb = AA::new(8); thread::spawn( || { let cc = &bb; //closure may outlive the current function, but it borrows `bb`, which is owned by the current function }); 包裹一个Arc可以解决这个问题,Arc恰好就是用来管理生命周期的,改进后的代码如下: let b = Arc::new(aa); let b1 = b.clone(); thread::spawn(move || { b1... }) Arc提供了共享不可变引用的功能,也就是说,数据是只读的。如果我们需要访问多线程访问共享数据的可变引用,即读写数据,那么还需要在原始数据上先包裹Mutex<T>,类似于RefCell<T>,提供内部可变性,因此我们可以获取内部数据的&mut,修改数据。当然,这需要通过Mutex::lock() 来操作。 let b = Arc::new(Mutex::new(aa)); let b1 = b.clone(); thread::spawn(move || { let b = b1.lock(); ... }) 为什么不能直接使用RefCell完成这个功能?这是因为RefCell不支持 Sync,没办法装入Arc。注意Arc的约束: unsafe impl<T: ?Sized + Sync + Send> Send for Arc<T> {} 若 Arc<T>是Send,条件是 T:Send+Sync。RefCell不满足 Sync,因此 Arc<RefCell<>> 不满足Send,无法转移至线程中。错误代码如下: let b = Arc::new(RefCell::new(aa)); let b1 = b.clone(); thread::spawn(move || { ^^^^^^^^^^^^^ `std::cell::RefCell<AA<T>>` cannot be shared between threads safely let x = b1.borrow_mut(); }) 异步代码:跨越 await 问题 如上所述,一般地,我们会将数据的值转移入线程,这样只需要做正确的 Send和Sync 标记即可,很直观,容易理解。典型的代码如下: fn test1<T: Send + Sync + 'static>(t: T) { let b = Arc::new(t); let bb = b.clone(); thread::spawn( move|| { let cc = &bb; }); } 根据上面的分析,不难推导出条件 T: Send + Sync + 'static 的来龙去脉:Closure: Send + 'static ⇒ Arc<T>: Send + ’static ⇒ T: Send + Sync + 'static。 然而,在异步协程代码中有一种常见情况,推导过程则显得比较隐蔽,值得说道说道。考察以下代码: struct AA<T>(T); impl<T> AA<T> { async fn run_self(self) {} async fn run(&self) {} async fn run_mut(&mut self) {} } fn test2<T: Send + 'static>(mut aa: AA<T>) { let ha = async_std::task::spawn(async move { aa.run_self().await; }); } test2 中,限定 T: Send + ‘static,合情合理。async fn 生成的 GenFuture 要求 Send + ‘static,因此被捕获置入 GenFuture 匿名结构中的 AA 也必须满足 Send + ‘static,进而要求AA 泛型参数也满足Send + ‘static。 然而,类似的方式调用 AA::run() 方法,编译失败,编译器提示 GenFuture 不满足 Send。代码如下: fn test2<T: Send + 'static>(mut aa: AA<T>) { let ha = async_std::task::spawn(async move { ^^^^^^^^^^^^^^^^^^^^^^ future returned by `test2` is not `Send` aa.run().await; }); } 原因在于,AA::run()方法的签名是 &self,所以run()是通过 aa 的不可变借用 &AA 来调用。而run()又是一个异步方法,执行了await,也就是所谓的&aa 跨越了 await,故而要求GenFuture匿名结构除了生成aa之外,还需要生成 &aa,示意代码如下: struct { aa: AA aa_ref: &AA } 正如之前探讨过,生成的 GenFuture需要满足 Send,因此 AA 以及 &AA 都需要满足 Send。而&AA满足 Send,则意味着 AA 满足 Sync。这也就是各种 Rust教程中都会提到的那句话的真正含义: 对于任意类型 T,如果 &T是 Send ,T 就是 Sync 的 之前出错的代码修改为如下形式,增加 Sync标记,编译通过。 fn test2<T: Send + Sync + 'static>(mut aa: AA<T>) { let ha = async_std::task::spawn(async move { aa.run().await; }); } 另外,值得指出的是上述代码中调用 AA::run_mut(&mut self) 不需要 Sync 标记: fn test2<T: Send + 'static>(mut aa: AA<T>) { let ha = async_std::task::spawn(async move { aa.run_mut().await; }); } 这是因为 &mut self 并不要求 T: Sync。参见以下标准库中关于Sync定义代码就明白了: mod impls { #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<T: Sync + ?Sized> Send for &T {} #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<T: Send + ?Sized> Send for &mut T {} } 可以看到,&T: Send 要求 T: Sync,而 &mut T 则 T: Send 即可。 总结 总而言之,Send约束在根源上是由 thread::spawn() 或是 task::spawn() 引入的,因为两个方法的闭包参数必须满足 Send。此外,在需要共享数据时使用Arc<T>会要求 T: Send + Sync。而共享可写数据,需要Arc<Mutex<T>>,此时 T: Send 即可,不再要求Sync。 异步代码中关于 Send/Sync 与同步多线程代码没有不同。只是因为GenFuture 的特别之处使得跨越 await 的变量必须是 T: Send,此时需要注意通过 T 调用异步方法的签名,如果为 &self,则必须满足 T:Send + Sync。 最后,一点经验分享:关于 Send/Sync 的道理并不复杂,更多时候是因为代码中层次比较深,调用关系复杂,导致编译器的错误提示很难看懂,某些特定场合编译器可能还会给出完全错误的修正建议,这时候需要仔细斟酌,追根溯源,找到问题的本质,不能完全依靠编译器提示。 作者:谢敬伟,江湖人称“刀哥”,20年IT老兵,数据通信网络专家,电信网络架构师,目前任Netwarps开发总监。刀哥在操作系统、网络编程、高并发、高吞吐、高可用性等领域有多年的实践经验,并对网络及编程等方面的新技术有浓厚的兴趣。 深圳星链网科科技有限公司(Netwarps),专注于互联网安全存储领域技术的研发与应用,是先进的安全存储基础设施提供商,主要产品有去中心化文件系统(DFS)、企业联盟链平台(EAC)、区块链操作系统(BOS)。 微信公众号:Netwarps

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

C++之友元的学习总结

一、友元的概念: 1、什么是友元? 友元是c++中的一种关系 友元关系发生在函数与类之间或者类与类之间 友元关系是单项的,不能传递 2、友元的用法: 在类中以friend关键字声明友元 类的友元可以是其它类或者具体函数 友元不是类的一部分 友元不受类中访问级别的限制 友元可以直接访问具体类的所有成员 3、友元的语法: 在类中使用friend 关键字对函数或者类进行声明: classTest{doublex;doubley;friendvoidfunc(Test&t);};voidfunc(Test&t){} 注意:func() 全局函数是 Test 类的友元,func() 可以访问Test 类的所有成员,但是 func() 不是 Test 的成员函数。 示例代码: #include<stdio.h>#include<math.h>classTest{doublex;doubley;public:Test(doublex,doubley){this->x=x;this->y=y;}doublegetX(){returnx;}doublegetY(){returny;}frienddoublefunc(Test&t1,Test&t2);};doublefunc(Test&t1,Test&t2){doubleret=0;ret=(t2.y-t1.y)*(t2.y-t1.y)+(t2.x-t1.x)*(t2.x-t1.x);ret=sqrt(ret);returnret;}intmain(){Testt1(1,2);Testt2(10,20);printf("t1(%f,%f)\n",t1.getX(),t1.getY());printf("t2(%f,%f)\n",t2.getX(),t2.getY());printf("(t1,t2)=%f\n",func(t1,t2));return0;} 输出结果: root@txp-virtual-machine:/home/txp/add#g++test.cpproot@txp-virtual-machine:/home/txp/add#./a.outt1(1.000000,2.000000)t2(10.000000,20.000000)(t1,t2)=20.124612 4、友元的尴尬: 友元是为了兼顾c语言的高效而诞生的 友元直接破坏了面向对象的封装性 友元在实际开发产品中的高效是得不偿失的 友元在软件工程中已经慢慢被遗弃了 5、注意事项: 友元关系不具备传递性 类的友元可以是其它类的成员函数 类的友元可以是某个完整的类 所有的成员函数都是友元 代码测试: #include<stdio.h>classClassC{constchar*n;public:ClassC(constchar*n){this->n=n;}friendclassClassB;};classClassB{constchar*n;public:ClassB(constchar*n){this->n=n;}voidgetClassCName(ClassC&c){printf("c.n=%s\n",c.n);}friendclassClassA;};classClassA{constchar*n;public:ClassA(constchar*n){this->n=n;}voidgetClassBName(ClassB&b){printf("b.n=%s\n",b.n);}/*voidgetClassCName(ClassC&c){printf("c.n=%s\n",c.n);}*/};intmain(){ClassAA("A");ClassBB("B");ClassCC("C");A.getClassBName(B);B.getClassCName(C);return0;} 输出结果: root@txp-virtual-machine:/home/txp/add#./a.outb.n=Bc.n=C 如果把上面屏蔽的那部分代码打开,编译就会报错(因为友元没有传递性哦): root@txp-virtual-machine:/home/txp/add#g++test.cpptest.cpp:Inmemberfunction‘voidClassA::getClassCName(ClassC&)’:test.cpp:5:17:error:‘constchar*ClassC::n’isprivateconstchar*n;^test.cpp:48:32:error:withinthiscontextprintf("c.n=%s\n",c.n);^ 6、小结: 友元是为了兼顾c语言的高效而诞生的 友元直接破坏了面向对象的封装性 友元关系不具备传递性 类的友元可以是其它类的成员函数 类的友元可以是某个完成的类 二、总结: 好了,今天的分享就到这里,如果文章中有错误或者不理解的地方,可以交流互动,一起进步。我是txp,下期见! 本文分享自微信公众号 - TXP嵌入式(txp1121518wo-)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

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

ES7学习笔记(九)搜索

搜索是ES最最核心的内容,没有之一。前面章节的内容,索引、动态映射、分词器等都是铺垫,最重要的就是最后点击搜索这一下。下面我们就看看点击搜索这一下的背后,都做了哪些事情。 分数(score) ES的搜索结果是按照相关分数的高低进行排序的,咦?! 怎么没说搜索先说搜索结果的排序了?咱们这里先把这个概念提出来,因为在搜索的过程中,会计算这个分数。这个分数代表了这条记录匹配搜索内容的相关程度。分数是一个浮点型的数字,对应的是搜索结果中的_score字段,分数越高代表匹配度越高,排序越靠前。 在ES的搜索当中,分为两种,一种计算分数,而另外一种是不计算分数的。 查询(query context) 查询,代表的是这条记录与搜索内容匹配的怎么样,除了决定这条记录是否匹配外,还要计算这条记录的相关分数。这个和咱们平时的查询是一样的,比如我们搜索一个关键词,分词以后匹配到相关的记录,这些相关的记录都是查询的结果,那这些结果谁排名靠前,谁排名靠后呢?这个就要看匹配的程度,也就是计算的分数。 过滤(filter context) 过滤,代表的含义非常的简单,就是YES or NO,这条记录是否匹配查询条件,它不会计算分数。频繁使用的过滤还会被ES加入到缓存,以提升ES的性能。下面我们看一个查询和过滤的例子,这个也是ES官网中的例子。 GET /_search { "query": { "bool": { "must": [ { "match": { "title": "Search" }}, { "match": { "content": "Elasticsearch" }} ], "filter": [ { "term": { "status": "published" }}, { "range": { "publish_date": { "gte": "2015-01-01" }}} ] } } } 我们看一下请求的路径/_search,这个是请求的路径,而请求的方法是GET,我们再看请求体中,有一个query,这个代表着查询的条件。而bool中的must被用作query context,它在查询的时候会计算记录匹配的相关分数。filter中的条件用作过滤,只会把符合条件的记录检索出来,不会计算分数。 组合查询 组合查询包含了其他的查询,像我们前面提到的query context和filter context。在组合查询中,分为很多种类型,我们挑重点的类型给大家介绍一下。 Boolean Query boolean查询,前面我们写的查询语句就是一个boolean查询,boolean查询中有几个关键词,表格如下: 关键词 描述 must 必须满足的条件,而且会计算分数, filter 必须满足的条件,不会计算分数 should 可以满足的条件,会计算分数 must_not 必须不满足的条件,不会计算分数 我们看看下面的查询语句: POST _search { "query": { "bool" : { "must" : { "term" : { "user" : "kimchy" } }, "filter": { "term" : { "tag" : "tech" } }, "must_not" : { "range" : { "age" : { "gte" : 10, "lte" : 20 } } }, "should" : [ { "term" : { "tag" : "wow" } }, { "term" : { "tag" : "elasticsearch" } } ], "minimum_should_match" : 1, "boost" : 1.0 } } } 上面的查询是一个典型的boolean组合查询,里边的关键词都用上了。很多小伙伴们可能对must和should的区别不是很了解,must是必须满足的条件,我们的例子中must里只写了一个条件,如果是多个条件,那么里边的所有条件必须满足。而should就不一样了,should里边现在列出了两个条件,并不是说这两个条件必须满足,到底需要满足几个呢?我们看一下下面的关键字minimum_should_match,从字面上我们就可以看出它的含义,最小should匹配数,在这里设置的是1,也就是说,should里的条件只要满足1个,就算匹配成功。在boolean查询中,如果存在一个should条件,而没有filter和must条件的话,那么minimum_should_match的默认值是1,其他情况默认值是0。 我们再看一个实际的例子吧,还记得前面我们创建的ik_index索引吗?索引中存在着几条数据,数据如下: _index _type _id ▲_score id title desc ik_index _doc fEsN-HEBZl0Dh1ayKWZb 1 1 苹果 苹果真好吃 ik_index _doc 2 1 1 香蕉 香蕉真好吃 ik_index _doc 1 1 1 香蕉 香蕉真好吃 ik_index _doc 3 1 1 橘子 橘子真好吃 ik_index _doc 4 1 1 桃子 桃子真好吃 只有5条记录,我们新建一个查询语句,如下: POST /ik_index/_search { "query":{ "bool":{ "must":[ { "match":{ "desc":"香蕉好吃" } } ] } }, "from":0, "size":10, } 我们查询的条件是desc字段满足香蕉好吃,由于我们使用的ik分词器,查询条件香蕉好吃会被分词为香蕉和好吃,但是5的数据的desc中都有好吃字段,所有5条数据都会被查询出来,我们执行一下,看看结果: _index _type _id ▲_score id title desc ik_index _doc 2 0.98773474 1 香蕉 香蕉真好吃 ik_index _doc 1 0.98773474 1 香蕉 香蕉真好吃 ik_index _doc 3 0.08929447 1 橘子 橘子真好吃 ik_index _doc 4 0.08929447 1 桃子 桃子真好吃 ik_index _doc fEsN-HEBZl0Dh1ayKWZb 0.07893815 1 苹果 苹果真好吃 哈哈,5条数据全部查询出来了,和我们的预期是一样的,但是,我们需要注意一点的是_score字段,它们的分数是不一样的,我们的查询条件是香蕉好吃,所以既包含香蕉又包含好吃的数据分数高,我们看到分数到了0.98,而另外3条数据只匹配了好吃,所以分数只有0.7,0.8。 Boosting Query 这个查询比较有意思,它有两个关键词positive和negative,positive是“正”,所有满足positive条件的数据都会被查询出来,negative是“负”,满足negative条件的数据并不会被过滤掉,而是会扣减分数。那么扣减分数要扣减多少呢?这里边有另外一个字段negative_boost,这个字段是得分的系数,它的分数在0~1之间,满足了negative条件的数据,它们的分数会乘以这个系数,比如这个系数是0.5,原来100分的数据如果满足了negative条件,它的分数会乘以0.5,变成50分。我们看看下面的例子, POST /ik_index/_search { "query": { "boosting": { "positive": { "term": { "desc": "好吃" } }, "negative": { "term": { "desc": "香蕉" } }, "negative_boost": 0.5 } } } positive条件是好吃,只要desc中有“好吃”的数据都会被查询出来,而negative的条件是香蕉,只要desc中包含“香蕉”的数据都会被扣减分数,扣减多少分数呢?它的得分将会变为原分数*0.5。我们执行一下,看看效果, index type _id score _source.id source.title source.desc ik_index _doc 3 0.08929447 1 橘子 橘子真好吃 ik_index _doc 4 0.08929447 1 桃子 桃子真好吃 ik_index _doc fEsN-HEBZl0Dh1ayKWZb 0.07893815 1 苹果 苹果真好吃 ik_index _doc 2 0.044647235 1 香蕉 香蕉真好吃 ik_index _doc 1 0.044647235 1 香蕉 香蕉真好吃 我们可以看到前3条数据的分数都在0.09左右,而后两条的数据在0.044左右,很显然,后两条数据中的desc包含香蕉,它们的得分会乘以0.5的系数,所以分数只有前面数据的分数的一半。 全文检索 在前面几节的内容中,我们介绍过,只有字段的类型是text,才会使用全文检索,全文检索会使用到分析器,在我们的ik_index索引中,title和desc字段都是text类型,所以,这两个字段的搜索都会使用到ik中文分词器。全文检索比起前面的组合检索要简单一点,当然,在ES的官方文档中,全文检索中的内容还是挺多的,在这里我们只介绍一个标准的全文检索。 我们看看下面的语句, POST /ik_index/_search { "query": { "match": { "desc": { "query": "苹果" } } } } 在请求体中,match代替了之前的bool,match是标准的全文索引的查询。match后面跟的字段是要查询的字段名,在咱们的例子中,查询的字段是desc,如果有多个字段,可以列举多个。desc字段里,query就是要查询的内容。我们还可以在字段中指定分析器,使用analyzer关键字,如果不指定,默认就是索引的分析器。我们执行一下上面的查询,结果如下: index type _id score source.id source.title source.desc ik_index _doc fEsN-HEBZl0Dh1ayKWZb 1.2576691 1 苹果 苹果真好吃 我们可以看到相应的数据已经检索出来了。 最后 在ES中,检索的花样是比较多的,这里也不能一一给大家介绍了,只介绍一些最基本、最常用的查询功能。下一篇我们看一下ES的聚合查询功能。

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

SAP Commerce(SAP Hybris)学习资料汇总

版本号:v1.02@TOC SAP官方帮助文档 Installer-Recipe 不能用于生产用途。文件夹位置:installer/recipes. 这个链接包含了所有recipe的说明。 Extension和Addon的概念 若干extensions组合在一起,以module的形式发布。 An extension can contain business logic, type definitions, a web application, or a Hybris Management Console configuration. That way, you link up in one place all of the functionality that covers a certain field of use, for example a webshop. Addon是一种特殊的extension,扩展了Commerce Accelerator的功能。这种extension添加了UI页面,但又没有直接修改Storefront的实现。 AddOns extend the functionality of the SAP Commerce Accelerator. They are a type of extension that allow you to add front-end files such JSP, HTML, CSS, and JavaScript files, and images without modifying the storefront front-end files directly. 这个链接包含了一个表格,可以查询Extension和Addon的ID和description. 总体架构 Extension专题 An extension is an encapsulated piece of software that extends SAP Commerce functionality by either modifying existing features, or introduction new features. Extension modules are structural elements of an extension. Extension module是extension的一部分。 You can implement JUnit tests for the extension's core extension module. The files for these JUnit tests must be located in the testsrc directory of the extension. 每个extension都有一个名叫core的 extension module,包含了该extension的type system definition,items.xml, 位于resources文件夹内。命名规范: The name of this file is always defined accordingly: <$extension> -items.xml where <$extension> is the name of an extension. 与类型相关的Java source code文件也位于core extension module内。 items.xml的链接. web extension module: 是extension的一部分,可以通过浏览器访问: To launch a web extension module via your web browser, go to the URL path to Platform on the server/name of extension/starting page. For example, if you are running myExtension locally on default settings, the URL would be http://localhost:9001/myExtension. Web application filter 如何创建新的extension Internationalization-and-localization 什么是extension的core module: A core module consists of an items.xml file (and therefore allows to add new types to the system), a manager class, classes for the JaLo Layer and the ServiceLayer and JUnit test classes. The following directories are required: /src, /resources, /testsrc. While the Commerce Platform can run without any package, no package can run without the Commerce Platform. Commerce platform也是由extension组成的,称为core extension. 在这些core extension之上才是build framework,和tomcat server. Hybris-initialization和update过程 什么是Hybris的initialization: Initialization drops existing type definitions from the database prior to rebuilding, so the entire type system is created from scratch. So during an initialization, type system definitions are created to match the type system definition in the items.xml files. Update: items.xml里定义的新类型,会施加到类型系统里。 Model 基于items.xml的定义生成types. SAP-Commerce里的Spring框架 是Service Layer的foundation. Dependent Injection: 组件的依赖不是其自身维护,而是配置在外部。 Dependency injection is a software architecture pattern in which a component's dependencies are not managed by the component itself but are configured externally. A so-called container (application context) reads the configuration file, resolves the dependencies, and puts together the objects. When the objects are ready, all the dependencies are already injected. <bean class="de.hybris.platform.order.OrderService"> <property name="stockService"> <bean class="de.hybris.platform.stock.StockService"/> </property> </bean> xml文件的位置:${HYBRIS_BIN_DIR}/platform/ext/core/resources命名规范: There you find files with the name pattern |component|-spring.xml, where is something like product, order, i18n, security, and so on. For the beans themselves, a name pattern such as xyzService is recommended, such as: productService, catalogService, and so on. Service Layer的API通过interface暴露出来。interface的实现就是Spring beans,id name可以从SAP commerce API doc里找到。 Accelerator SAP Commerce Accelerator is a ready-to-use web implementation template that enables you to jumpstart your implementation and easily build and maintain a feature-rich and flexible commerce solution. China Accelerator Service-Layer 是三层的统称:ServiceLayer Framework (including the actual ServiceLayer, the Infrastructure Services, and the Business Services) relies on so-called models, which are POJOs. Attributes on models have automatically generated getter and setter methods. Models are generated based on types. ProductModel是service layer的概念,基于type自动生成,getter和setter.Type layer也就是items.xml. Hybris-Type-System 类型系统是对象的模板。platform里每个对象都是类型的实例。 Types定义了持久化对象: Attribute存储对象的数据。 Deployment定义数据库表 java class A Type is the type definition in items.xml and its Java implementation. An object instance of a type is called an item: 类型分两种:System-related types and business-related types. System-related types又由下列类型组成: Infrastructure types: ComposedTypes (also referred to as ItemTypes) set up type definitions and may carry attributes to hold information. In the end, every persistent object in the SAP Commerce is an instance of ComposedType or of one of its subtypes. Business-related types: (like Order, Discount, Shoe) allow you to manage product and / or customer information so that you can run your business. every object stored in SAP Commerce is an instance of a type. Even type definitions are instances of the type Type. This means that there are two aspects of a type definition: it is an item and, at the same time, it defines other items. To differentiate between normal object instances and type definitions, non-type objects in Platform are referred to as items. The lower case spelling item refers to an object in Platform; the upper case spelling Item refers to the type definition. 小写的items代表platform里non-type对象, 大写的代表类型定义。 The following code snippet defines an item called SpecialProduct that is a subtype of Product but its type is not defined as a ComposedType, but as a SpecialComposedType (via the metatype attribute). Instances of SpecialProduct are thus subtypes of Product, but the type definition is stored as a SpecialComposedType. <item code="SpecialProduct" metatype="SpecialComposedType" extends="Product"> 类型定义attribute,如同Java 类定义fields, attribute可以是复合类型或者简单Java类型。 Platform-Services-and-Utilities backoffice 一个实际的例子:2455449 - How-to: Hide Backoffice explorer-tree nodes based on user access rights 其他网友的资料 SAP成都研究院Commerce开发人员Zhang Jonathan的三篇概述文章: 从产品展示页面谈谈Hybris的特有概念和设计结构 从产品展示页面谈谈Hybris系列之二: DTO, Converter和Populator 从产品展示页面谈谈Hybris系列之三:Hybris Service层介绍 Jerry Wang的文章: 浅谈SAP CRM和Hybris Commerce里的价格架构折扣 其它文章: 安装和目录介绍 本文来自云栖社区合作伙伴“汪子熙”,了解相关信息可以关注微信公众号"汪子熙"。

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

Java学习第4天:分支结构

二、程序流程控制 流程控制语句是用来控制程序中各语言执行顺序的语句,可以把语句组合成能完成一定功能的小逻辑模块。三种基本流程结构: 顺序结构 程序从上到下逐行执行,中间没有任何判断和跳转。 分支结构 根据条件,选择性地执行某段代码。有if-else和switch-case两种分支语句。 循环结构 根据循环条件,重复性的执行某段代码。有while、do……while,for三种循环语句注:JDK1.5提供了foreach循环,方便的遍历集合、数组元素。 if-else 所有三元运算符都可以用if-else结构替代,if-else不一定能改成三元运算符。如果既可以使用三元运算符又可以使用if-else,优先选用三元运算符。原因:简洁、执行效率高。例如,3个数取最大值class SanYuan{public static void main(String[] args){int n1=12;int n2=30;int n3=-43;int max=((n1>n2?n1:n2)>n3)?(n1>n2?n1:n2):n3;//不建议这么写,可读性差System.out.println("The max of n1 n2 n3 is " + max);int max1,max2;if(n1>n2){max1=n1;} else{max1=n2;} if(max1>n3){max2=max1;} else{max2=n3;}System.out.println("The max of n1 n2 n3 is " + max2);}} if语句三种结构(条件判断结构): 1、if(条件表达式){执行代码块} //只有一种选择2、if(条件表达式){执行代码块1} else {执行代码块2} //二选一3、if(条件表达式){执行代码块1} else if(条件表达式2){执行代码块2} else{执行代码块3} 多选一,中间可以多个elseif &和&&的异同 都是且的关系左边true,右边都执行左边false,短路与后面不执行,逻辑与后面执行 Scanner类 从键盘获取不同类型的变量,char型的获取,Scanner没有提供相关办法,只能获取一个字符串。当输入的值和获取的类型不一致时会报错。具体实现步骤:1、导包:import java.util.Scanner;写在类的上面,类Scanner在包util下。2、Scanner的实例化,Scanner scan=new Scanner(System.in);3、调用Scanner类的相关方法获取指定类型的变量,int num=scan.nextInt(); 例1: 输入一个整数并输出。import java.util.Scanner;class Scan{public static void main(String[] args){Scanner sc = new Scanner(System.in);int i = sc.nextInt();System.out.println("The input number is "+i);}}javac Scanner.java$ java Scan88The input number is 88 例2: 输入字符串。import java.util.Scanner;class ScannerString{public static void main(String[] args){Scanner sc =new Scanner(System.in);System.out.println("请输出你的名字:n");String userName = sc.next();System.out.println("欢迎"+userName+"登录系统");}}$ javac ScannerString.java$ java ScannerString请输出你的名字: lisi欢迎lisi登录系统 例3: 输入期末考试成绩,100分降落宝马,80-99奖励手机,60-80奖励玩具,不及格什么都没有。import java.util.Scanner;class IfTest{public static void main(String[] args){int score;Scanner scan = new Scanner(System.in);System.out.println("请输入成绩,在0到100之间");score=scan.nextInt();if(score == 100){System.out.println("奖励一辆BMW");}else if(score < 100 && score > 80){System.out.println("奖励一个手机");}else if(score >= 60 && score <= 80){System.out.println("奖励一个玩具"); }else{System.out.println("什么都没有");}}}说明1、else结构是可选的。2、针对条件表达式:如果多个条件表达式之间是“互斥”关系,哪个判断在上面或下面都无所谓;如果有交集,应该考虑清楚哪个条件应该在上面;如果条件表达式之间有包含关系,需要将范围小的声明在上面,否则小的永远不会执行,因为if else只有一个出口。 例4: 输入3个整数,按小到大输出排序。import java.util.Scanner;class SortTest{public static void main(String[] args){Scanner scan = new Scanner(System.in);System.out.println("Please insert the first number");int num1 = scan.nextInt();System.out.println("Please insert the second number"); int num2 = scan.nextInt();System.out.println("Please insert the third number"); int num3 = scan.nextInt();if(num1 > num2){if(num2 > num3){System.out.println(num3 + "," + num2 + "," + num1);}else if(num3 > num1){System.out.println(num2 + "," + num1 + "," + num3);} else{System.out.println(num2 + "," + num3 + "," + num1); }} else {if(num1 > num3){ System.out.println(num3 + "," + num1 + "," + num2); }else if(num3 > num2){ System.out.println(num1 + "," + num2 + "," + num3); } else{ System.out.println(num1 + "," + num3 + "," + num2); }}}}$ java SortTestPlease insert the first number1000Please insert the second number0Please insert the third number8880,888,1000说明:1、if-else可以互相嵌套,不过一遍不要嵌套3层以上,3层以上自己就晕了。2、if-else 后面如果只有一行执行语句,可以省略{},一般不建议省略.Java用法:String isHandsome=scan.next();if(isHandsome.equals("是")) switch-case 结构switch(表达式){case 常量1: 语句1; //break; case 常量2; 语句2; //break; case 常量N: 语句N; // default: 语句; //break; }分支结构之二:switch-case说明:1、根据switch表达式中的值,依次匹配各个case中的常量,一旦匹配成功,会进入相应case中,调用其执行语句。当调用完执行语句以后,则仍然继续向下执行其他case结构中的执行语句,直到遇到break关键字或到switch-case结构末尾为止结束,后面的case条件不会做判断。 例子: class SwitchCase{public static void main(String[] args){int num1=2;switch(num1){case 0:System.out.println("zero");case 1: System.out.println("one");case 2: System.out.println("two");case 3: System.out.println("three");default:System.out.println("others");}}}$ java SwitchCasetwothreeothers2、break可以用在switch-case结构中,表示一旦执行到次关键字就跳出switch-case结构3、switch结构中的表达式,只能是如下6中数据类型之一:byte、short、char、int、枚举类型(JDK5.0新增)、String类型(JDK7.0新增)。4、case后面只能声明常量,不能是范围值。5、break关键字是可选的,不是必须加的,绝大多数情况都需要加。6、default相当于if-else中的else,default选项是可选的,而且位置是灵活的,通常放到最后。 例1 switch-case判断成绩,小于60输出不合格,大于等于60输出合格。class Test{public static void main(String[] args){int score=78;switch(score/60){case 0:System.out.println("不及格");break;case 1:System.out.println("及格");break;default:System.out.println("输入值有误");break;}}} 例2: 输入年月日,计算出是第几天import java.util.Scanner;class Date{public static void main(String[] args){Scanner scan = new Scanner(System.in);System.out.println("请输入年份");int years = scan.nextInt();System.out.println("请输入月份,1-12");int months = scan.nextInt();System.out.println("请输入日期,1-31");int days = scan.nextInt();int sum=0;switch(months){case 12:sum += 30;case 11:sum += 31;case 10:sum += 30;case 9:sum += 31;case 8:sum += 31;case 7:sum += 30;case 6:sum += 31;case 5:sum += 30;case 4:sum += 31;case 3://判断是否闰年if((years % 4 == 0 && years % 100 != 0)||(years % 400 == 0)){sum += 29;}else{sum += 28;}case 2:sum +=31;case 1:sum +=days;System.out.println(years + "年" + months + "月" + days + "日" + "是当年的第" + sum + "天");break;default:System.out.println("月份输入错误");}}}$ java Date请输入年份2019请输入月份,1-1212请输入日期,1-31312019年12月31日是当年的第365天 总结: 1、凡是可以使用switch-case的结构都可以转换为if-else。反之,不成立。2、当我们写分支结构时,我们发现既可以使用switch-case,case取值不太多,又可以使用if-else时,优先选择使用switch-case。原因:switch-case执行效率稍高。

资源下载

更多资源
Mario

Mario

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

腾讯云软件源

腾讯云软件源

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

Spring

Spring

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

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册