-
如何学习java后台开发,有学习路线吗
-
区分类中重载方法的依据是( )。正确答案: C 你的答案: C (正确)不同的形参名称不同的返回值类型不同的形参列表不同的访问权限题解:两个重载函数必须在下列一个或两个方面有所区别:1、函数的参数个数不同。2、函数的参数类型不同或者参数类型顺序不同
-
设Tree为已定义的类名,下列语句能正确创建 Tree 对象的是 。正确答案: B 你的答案: B (正确)Tree t=new Tree;Tree t=new Tree();Tree t=Tree();Tree t[ ]=new Tree[10];题解:需要对象,当然只需new一个了,还有别忘了括号。
-
Eclipse:一个开放源代码的、基于Java的可扩展开发平台 。NetBeans:开放源码的Java集成开发环境,适用于各种客户机和Web应用。IntelliJ IDEA:在代码自动提示、代码分析等方面的具有很好的功能。 MyEclipse:由Genuitec公司开发的一款商业化软件,是应用比较广泛的Java应用程序集成开发环境 。EditPlus:如果正确配置Java的编译器“Javac”以及解释器“Java”后,可直接使用EditPlus编译执行Java程序 。
gongyudehuaweiyun
发表于2021-12-05 14:07:38
2021-12-05 14:07:38
最后回复
hw26536804
2021-12-06 00:11:07
2924 2 -
>摘要:在Java语言的日常编程中,也存在着容易被忽略的细节,这些细节可能会导致程序出现各种Bug。本文分享自华为云社区[《Java编程中容易忽略的细节总结丨【奔跑吧!JAVA】》](https://bbs.huaweicloud.com/blogs/273066?utm_source=csdn&utm_medium=bbs-ex&utm_campaign=other&utm_content=content),作者:jackwangcumt 。 Java语言构建的各类应用程序,在人类的日常生活中占用非常重要的地位,各大IT厂商几乎都会使用它来构建自己的产品,为客户提供服务。作为一个企业级应用开发语言,稳定和高效的运行,至关重要。在Java语言的日常编程中,也存在着容易被忽略的细节,这些细节可能会导致程序出现各种Bug,下面就对这些细节进行一些总结: # 1 相等判断中的==和equals 在很多场景中,我们都需要判断两个对象是否相等,一般来说,判定两个对象的是否相等,都是依据其值是否相等,如两个字符串a和b的值都为"java",则我们认为二者相等。在Java中,有两个操作可以判断是否相当,即==和equals,但二者是有区别的,不可混用。下面给出示例: String a = "java"; String b = new String("java"); System.out.println(a == b);//false System.out.println(a.equals(b));//true 字符串a和b的字面值都为"java",用a == b判断则输出false,即不相等,而a.equals(b)则输出true,即相等。这是为什么呢?在Java中,String是一个不可变的类型,一般来说,如果两个String的值相等,默认情况下,会指定同一个内存地址,但这里字符串String b用new String方法强制生成一个新的String对象,因此,二者内存地址不一致。由于 == 需要判断对象的内存地址是否一致,因此返回false,而equals默认(override后可能不一定)是根据字面值来判断,即相等。 下面再给出一个示例: //integer -128 to 127 Integer i1 = 100; Integer i2 = 100; System.out.println(i1 == i2);//true i1 = 300; i2 = 300; System.out.println(i1 == i2);//false System.out.println(i1.equals(i2));//true 这是由于Java中的Integer数值的范围为-128到127,因此在这范围内的对象的内存地址是一致的,而超过这个范围的数值对象的内存地址是不一致的,因此300这个数值在 == 比较下,返回false,但在equals比较下返回true。 # 2 switch语句中丢失了break 在很多场景中,我们需要根据输入参数的范围来分别进行处理,这里除了可以使用if ... else ...语句外,还可以使用switch语句。在switch语句中,会罗列出多个分支条件,并进行分别处理,但如果稍有不注意,就可能丢失关键字break语句,从而出现预期外的值。下面给出示例: //缺少break关键字 public static void switchBugs(int v ) { switch (v) { case 0: System.out.println("0"); //break case 1: System.out.println("1"); break; case 2: System.out.println("2"); break; default: System.out.println("other"); } } 如果我们使用如下语句进行调用: `switchBugs(0);` 则我们预期返回"0",但是却返回"0" "1"。这是由于case 0 分支下缺少break关键字,则虽然程序匹配了此分支,但是却能穿透到下一个分支,即case 1分支,然后遇到break后返回值。 # 3 大量的垃圾回收,效率低下 字符串的拼接操作,是非常高频的操作,但是如果涉及的拼接量很大,则如果直接用 + 符号进行字符串拼接,则效率非常低下,程序运行的速度很慢。下面给出示例: private static void stringWhile(){ //获取开始时间 long start = System.currentTimeMillis(); String strV = ""; for (int i = 0; i 100000; i++) { strV = strV + "$"; } //strings are immutable. So, on each iteration a new string is created. // To address this we should use a mutable StringBuilder: System.out.println(strV.length()); long end = System.currentTimeMillis(); //获取结束时间 System.out.println("程序运行时间: "+(end-start)+"ms"); start = System.currentTimeMillis(); StringBuilder sb = new StringBuilder(); for (int i = 0; i 100000; i++) { sb.append("$"); } System.out.println(strV.length()); end = System.currentTimeMillis(); System.out.println("程序运行时间: "+(end-start)+"ms"); } 上述示例分别在循环体中用 + 和 StringBuilder进行字符串拼接,并统计了运行的时间(毫秒),下面给出模拟电脑上的运行结果: //+ 操作 100000 程序运行时间: 6078ms StringBuilder操作 100000 程序运行时间: 2ms 由此可见,使用StringBuilder构建字符串速度相比于 + 拼接,效率上高出太多。究其原因,就是因为Java语言中的字符串类型是不可变的,因此 + 操作后会创建一个新的字符串,这样会涉及到大量的对象创建工作,也涉及到垃圾回收机制的介入,因此非常耗时。 # 4 循环时删除元素 有些情况下,我们需要从一个集合对象中删除掉特定的元素,如从一个编程语言列表中删除java语言,则就会涉及到此种场景,但是如果处理不当,则会抛出ConcurrentModificationException异常。下面给出示例: private static void removeList() { List lists = new ArrayList(); lists.add("java"); lists.add("csharp"); lists.add("fsharp"); for (String item : lists) { if (item.contains("java")) { lists.remove(item); } } } 运行上述方法,会抛出错误,此时可以用如下方法进行解决,即用迭代器iterator,具体如下所示: private static void removeListOk() { List lists = new ArrayList(); lists.add("java"); lists.add("csharp"); lists.add("fsharp"); Iterator hatIterator = lists.iterator(); while (hatIterator.hasNext()) { String item = hatIterator.next(); if (item.contains("java")) { hatIterator.remove(); } } System.out.println(lists);//[csharp, fsharp] } # 5 null引用 在方法中,首先应该对参数的合法性进行验证,第一需要验证参数是否为null,然后再判断参数是否是预期范围的值。如果不首先进行null判断,直接进行参数的比较或者方法的调用,则可能出现null引用的异常。下面给出示例: private static void nullref(String words) { //NullPointerException if (words.equals("java")){ System.out.println("java"); }else{ System.out.println("not java"); } } 如果此时我们用如下方法进行调用,则抛出异常: `nullref(null)` 这是由于假设了words不为null,则可以调用String对象的equals方法。下面可以稍微进行一些修改,如下所示: private static void nullref2(String words) { if ("java".equals(words)){ System.out.println("java"); }else{ System.out.println("not java"); } } 则此时执行则可以正确运行: nullref2(null) # 6 hashCode对equals的影响 前面提到,equals方法可以从字面值上来判断两个对象是否相等。一般来说,如果两个对象相等,则其hash code相等,但是如果hash code相等,则两个对象可能相等,也可能不相等。这是由于Object的equals方法和hashCode方法可以被Override。下面给出示例: package com.jyd; import java.util.Objects; public class MySchool { private String name; MySchool(String name) { this.name = name; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } MySchool _obj = (MySchool) o; return Objects.equals(name, _obj.name); } @Override public int hashCode() { int code = this.name.hashCode(); System.out.println(code); //return code; //true //随机数 return (int) (Math.random() * 1000);//false } } Set mysets = new HashSet(); mysets.add(new MySchool("CUMT")); MySchool obj = new MySchool("CUMT"); System.out.println(mysets.contains(obj)); 执行上述代码,由于hashCode方法被Override,每次返回随机的hash Code值,则意味着两个对象的hash code不一致,那么equals判断则返回false,虽然二者的字面值都为"CUMT"。 # 7 内存泄漏 我们知道,计算机的内存是有限的,如果Java创建的对象一直不能进行释放,则新创建的对象会不断占用剩余的内存空间,最终导致内存空间不足,抛出内存溢出的异常。内存异常基本的单元测试不容易发现,往往都是上线运行一定时间后才发现的。下面给出示例: package com.jyd; import java.util.Properties; //内存泄漏模拟 public class MemoryLeakDemo { public final String key; public MemoryLeakDemo(String key) { this.key =key; } public static void main(String args[]) { try { Properties properties = System.getProperties(); for(;;) { properties.put(new MemoryLeakDemo("key"), "value"); } } catch(Exception e) { e.printStackTrace(); } } /* @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; MemoryLeakDemo that = (MemoryLeakDemo) o; return Objects.equals(key, that.key); } @Override public int hashCode() { return Objects.hash(key); } */ } 此示例中,有一个for无限循环,它会一直创建一个对象,并添加到properties容器中,如果MemoryLeakDemo类未给出自己的equals方法和hashCode方法,那么这个对象会被一直添加到properties容器中,最终内存泄漏。但是如果定义了自己的equals方法和hashCode方法(被注释的部分),那么新创建的MemoryLeakDemo实例,由于key值一致,则判定为已存在,则不会重复添加,此时则不会出现内存溢出。
-
-
# 1. 服务说明 ModelArts在线服务:将训练好的模型通过modelarts在线服务平台部署为一个Web Service服务。对外提供一个标准的Restful API,可使用HTTPS协议访问。 # 2. Api对接前置说明 ## 2.1 确认服务正常 ### 2.1.1 确认服务运行状态 Ⅰ. 在华为云控制台查看已部署的在线服务,确认状态为运行中。  Ⅱ. 进入已运行的在线服务,进入预测功能,进行接口调用。 a.上传图片  b.图片预测  ### 2.1.2 获取token Ⅰ. 请求接口方式:https://support.huaweicloud.com/api-iam/iam_30_0001.html 集成华为SDK:https://sdkcenter.developer.huaweicloud.com/?product=%E7%BB%9F%E4%B8%80%E8%BA%AB%E4%BB%BD%E8%AE%A4%E8%AF%81%E6%9C%8D%E5%8A%A1&language=java Ⅱ 调试过程,可以使用API Explorer 调用统一身份认证服务 KeystoneCreateUserTokenByPassword接口获取IAM用户token: https://apiexplorer.developer.huaweicloud.com/apiexplorer/doc?product=IAM&api=KeystoneCreateUserTokenByPassword # 3. Demo适用服务说明 该服务调用demo适用于Java语言,调用华为云mdoelarts在线服务、APIG等涉及到图片上传的以及返接口返回信息为json串的接口。 # 4. Demo代码 import javax.net.ssl.HttpsURLConnection; import java.io.*; import java.net.URL; /** ** 向华为云上传图片的demo **/ public class UploadImageDemo { public static void main(String[] args) { // 服务器url String modelApi = "https://XXX"; // token String tokenStr = "XXXX"; // 图片的绝对路径 String imageUrl = "C:\\Users\\chuyunwei\\Desktop\\yully.jpg"; // 文件控件名称 String fileParamName = "images"; postData(modelApi, tokenStr, imageUrl, fileParamName); } // 发送post请求 public static void postData(String modelApi, String tokenStr, String imageUrl, String fileParamName) { String boundary = java.util.UUID.randomUUID().toString(); String prefix = "--", linend = "\r\n"; String charset = "UTF-8"; // 数据流 DataOutputStream outStream = null; // 连接 HttpsURLConnection connetion = null; // 读取图片的流 InputStream input = null; try { URL url = new URL(modelApi); connetion = (HttpsURLConnection) url.openConnection(); connetion.setReadTimeout(30 * 1000); // 缓存的最长时间 connetion.setDoInput(true);// 允许输入 connetion.setDoOutput(true);// 允许输出 connetion.setUseCaches(false); // 不允许使用缓存 connetion.setRequestMethod("POST"); connetion.setRequestProperty("connection", "keep-alive"); // 设置以二进制传输数据;multipart/form-data: 每个参数以 --boundary 开始 connetion.setRequestProperty("Content-Type", "multipart/form-data;Charsert=UTF-8;boundary=" + boundary); connetion.setRequestProperty("X-Auth-Token", tokenStr); File file = new File(imageUrl); // 设置内容参数 StringBuilder contentParam = new StringBuilder(prefix).append(boundary).append(linend) .append("Content-Disposition: form-data; name=" + fileParamName + "; filename=" + file.getName() + linend) .append("Content-Type: application/octet-stream; charset=" + charset).append(linend).append(linend); outStream = new DataOutputStream(connetion.getOutputStream()); outStream.write(contentParam.toString().getBytes()); input = new FileInputStream(file); byte[] buffer = new byte[1024]; int len = 0; while ((len = input.read(buffer)) != -1) { outStream.write(buffer, 0, len); } input.close(); outStream.write(linend.getBytes()); // 设置请求结束标志符: 以 --boundary-- 为结束符 byte[] endData = (prefix + boundary + prefix + linend).getBytes(); outStream.write(endData); outStream.flush(); // 获取响应结果流 InputStream connetionInput = connetion.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connetionInput, charset)); // 按行读取响应结果 String line = ""; // 读取响应的结果值 StringBuffer resultBuffer = new StringBuffer(); while ((line = bufferedReader.readLine()) != null) { resultBuffer.append(line); } // 向控制台打印结果 System.out.println(resultBuffer.toString()); } catch (Exception e) { // 打印错误堆栈 e.printStackTrace(); } finally { // 关闭资源 closeResources(outStream, connetion, input); } } // 关闭资源 private static void closeResources(DataOutputStream outStream, HttpsURLConnection connetion, InputStream input) { if (input != null) { try { input.close(); } catch (IOException e) { e.printStackTrace(); } } if (outStream != null) { try { outStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (connetion != null) { connetion.disconnect(); } } } # 5. Demo补充说明 ## 5.1 注释说明 // 服务器url String modelApi = "https://XXX"; // token String tokenStr = "XXXX"; // 图片的绝对路径 String imageUrl = "C:\\Users\\chuyunwei\\Desktop\\yully.jpg"; // 文件控件名称 String fileParamName = "images"; Ⅰ. rl获取,控制台在线服务器调用指南TOP 页获取:  Ⅱ. token,调试过程直接调用: KeystoneCreateUserTokenByPassword接口获取IAM用户token: https://apiexplorer.developer.huaweicloud.com/apiexplorer/doc?product=IAM&api=KeystoneCreateUserTokenByPassword Ⅲ. 图片的绝对路径: 图片存放本地,直接使用本机的绝对路径进行获取。 Ⅳ. 文件控件名称,即为在线服务API输入图片的参数名称:  # 6. 实测结果 ## 6.1 修改配置  ## 6.2 代码调试  调试成功,返回结果。 # 7. 问题记录及解决办法 ## 7.1 服务未启动,运行报错 Ⅰ. 在线服务未启动,调试报错如下,重新启动服务即可正常请求。  ## 7.2 请求报401错误 Ⅰ. 查看错误码,判断401错误为鉴权问题导致,查看modelarts的认证鉴权方式帮助文档。可知请求token时,“auth.scope”的取值需要选择“project”。  Ⅱ. 我的token获取方式:  Ⅲ. Modelart token获取方式:按照如下方式获取token后,请求正常。  # 8. 问题解决渠道说明 ## 8.1 华为云开发者技术支持界面 访问链接:https://support.developer.huaweicloud.com/feedback/#/  ## 8.2 华为云开发者论坛界面 访问链接:https://bbs.huaweicloud.com/forum/forum-1175-1.html 
-
## 作者:伍家华 > 编者按:笔者通过在 Hive 的场景发现 AppCDS 技术存在的价值,然后分析了 AppCDS 的工作原理,并将 JDK 11 中的特性移植到毕昇 JDK 8,在移植过程中由于 JDK 8 和 JDK 11 在类加载实现有所不同,JDK 11 在加载过程中增强了安全性检查,为了达到相同的效果没有对 JDK 8 中的类加载进行修改,而是通过额外的安全检查保证共享类的安全性。最后笔者介绍了如何使用 AppCDS 以及使用的注意事项,希望对读者有所帮助。 基于某产品集群业务中有使用 Hive 场景,我们发现该集群在执行任务时会启动大量的 Java 进程,且进程很快就执行结束。对于这种情况一个有效的解决方法是让 Java 进程之间重用部分公共数据,从而减少 Java 进程产生公共数据的耗时。在 JDK 11 中支持 CDS 和 AppCDS,CDS 的全称是 Class-Data Sharing,CDS 的作用是可以让类被预处理放到一个归档文件中,后续 Java 程序启动的时候可以直接带上这个归档文件,这样 JVM 可以直接将这个归档文件映射到内存中,以节约应用启动的时间。AppCDS 是 CDS 的扩展,不止能够作用于 Boot Class Loader,App Class Loader 和自定义的 Class Loader 也都能够起作用,加大了 CDS 的适用范围 [1]。技术原理是让多个 Java 进程共享类的元数据,其基本原理如下所示:  左右两边分别都是一个 Java 进程,双方通过共享内存达到节约内存、减少类解析的目的。下面通过案例介绍一下我们发现的现象,然后再介绍类共享机制的内部原理。 # 1. 技术背景 ## 1.1 环境介绍 Hive on tez 集群,4 个节点,一个管理节点,其他三个节点作为工作节点。软件版本:Hadoop 3.1.0,hive 3.1.2,tez-0.9.1,ambari2.6,TPC-DS 标准测试套。硬件环境:Kunpeng 920,128 核,512G 内存。 ## 1.2 系统负载情况 运行 TPC-DS 自带的 sql8,使用 top 观察其中的一个节点的工作负载,发现启动了大量的 JVM 进程。  ## 1.3 热点分布 同时使用 perf 采集整机的热点数据,发现 JVM 的 C1, C2 编译线程占比很高,如下图所示。因此判断 hive sql 的 startup 和 warmup 阶段占比比较高,可以考虑从这两个方向优化。  考虑到目前 JVM 的 C2 代码比较难维护,也很难引进新的 feature。因此考虑看看在启动阶段有没有优化的可能。jdk1.8 带有 cds 功能,能够 share jdk 自带的 java class,能够减少 JVM 的类加载时间,因此首先尝试使用默认的 cds 功能,测试发现效果不明显。原因是 hive sql 执行过程中加载的类大部分是应用程序 classpath 下的类,jdk 自身的类占比很小,因此收益不明显。考虑到 jdk10 以后有了 AppCDS 功能,能够 share classpath 下的 class,因此考虑在 jdk1.8 上面实现 AppCDS 功能。 # 2. AppCDS 实现 毕昇 JDK 支持 AppCDS,即在原生 CDS 的基础上也支持用户自己程序 classpath 中的类共享。原生 CDS 只支持由 `Bootstrap classloader` 和 `Ext Classloader` 加载的 class,即 jdk 自带的 class 在多进程之间共享。但是在实际场景中,尤其是在使用了大量开源软件的情况下,用户指定 classpath 下的 jar 远远大于 jdk 自带的 class,这样 CDS 的实际效果比较有限。 AppCDS 能够扩大 class 共享的范围,从而在节省内存使用以及 JVM 的启动时间两个方面进一步提升效果。 ## 2.1 create class list 文件 java class 文件被 JVM 执行之前首先要被加载进 JVM 内存里面,作为 meta data 存储在 JVM 的 metaspace 内存区域。其中一个关键步骤就是解析 class 文件。JVM 内部有个 ClassFileParser 类,提供了 parseClassFile 方法,解析成功之后会生成一个对应 Klass。AppCDS 的第一步逻辑就是在类被解析完成之后,如果 class 不是匿名类,且 class 文件的 major version 大于 JAVA_1_5 Version,则会把 class 对应的 qualified name 写去到 list 文件中去。  ## 2.2 create jsa 归档文件  在这一步 JVM 会按行读取 appcds.lst 文件中内容,然后使用 App ClassLoader 去加载对应的 class。由于 Java classloader 自身的 delegate 机制,能够确保 jdk 自身的 class 也能够得到加载。Class 被加载之后存在 JVM 的 metaspace 区域,这个 metaspace 是 JVM Native Memory 的一部分,里面包含 klass, ConstantPool, Annotation, ConstMethod, Method, MethodData 等 meta 信息。 当 lst 文件中对应的 class 都被 JVM 加载完成之后,JVM 会把其对应的 metadata 写入到从虚拟地址 0x800000000 开始的内存区域,其格式是 JVM 内部私有的一种表示,然后再把这部分数据 dump 到归档文件中。 ## 2.3 与 JDK 11 实现的差别 与 JDK 11 中的 AppCDS 实现差别主要体现在加载用户指定的 class 逻辑上。当加载用户 class 时,是需要计算获取一个 ProtectionDomain 来做安全验证的。JDK 11 是直接在 hotspot 中使用 JavaCalls 模块构造这个 ProtectionDomain,而毕昇 JDK 8 是在 Java 的 ClassLoader 中提供了一个 `getProtectionDomainInternal` 函数来获取,并在加载 class 的时候使用 JavaCalls 调用这个 java 方法。 # 3. AppCDS 使用说明 ## 3.1 创建 lst 文件 启动 JVM 的时候添加 `- Xshare:off` 和 `- XX:+DumpLoadedClassList=/path/to/class.lst` 这两个选项。这里比较重要的是第二个选项,这个选项同时支持 %P,可以按进程生成 class.lst 文件,生成的文件名会带上 JVM 进程的 pid。class.lst 本质上是个纯文本文件,里面记录 JVM 运行过程中加载的 class 列表。在 java 程序被 JVM 执行的过程中,会不断地从 classpath 中加载 class,并在 JVM 内部创建对应的 klass 对象。Klass 对象创建成功之后 JVM 会把 class 在 JVM 内部的 qualified name 写入到 class.lst 文件中,比如 `java.lang.Objectd` 对应的是 java/lang/Object。 **使用例子:** ```Bash java -Xms16M -Xmx16M -XX:+UseG1GC -cp test.jar -Xshare:off -XX:+UseAppCDS -XX:DumpLoadedClassList=appcds.lst com.example.App ``` ## 3.2 创建 archive 文件 第二步:创建 cds 归档文件。使用方式: ```Bash java -Xms16M -Xmx16M -XX:+UseG1GC -cp test.jar -Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=appcds.lst -XX:SharedArchiveFile=appcds.jsa com.example.App ``` ## 3.3 使用 archive 文件 使用示例: ```Bash java -Xms16M -Xmx16M -XX:+UseG1GC -cp test.jar -Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=appcds.jsa com.example.App ``` 第三步:JVM 在启动的过程中会把 jsa mmap 到内存中,然后在触发类加载时候 JVM 会首先尝试从这块 mmap 进来的内存中去获取 klass 对象,如果获取到则会更新 JVM 内部的 SystemDictionary,以后再来获取对应的 klass 对象则不需要从 jsa 中获取。如果获取失败,JVM 则会走正常的类加载流程,尝试从 classpath 中加载对应的 class 文件,解析,链接,初始化,然后再放入 SystemDictionary 中。 # 4. AppCDS 效果 TPC-DS 测试套的 10 个 sql 在 5T 数据的场景下测试了一下 AppCDS 的效果,结果收益好,最低是 8.42% 的性能提升,最高是 26.9% 的性能提升。  # 5. 注意事项 使用 AppCDS 三部曲过程中要保持 JVM 版本、JAVA_HOME 路径一致,不然会校验失败,无法启动 JVM。 在第二步加载 class 并创建 jsa 归档文件的时候,JVM 会记录 class 的 fingerprint 信息 (相当于 hash 值),在第三步使用 jsa 中的 class 信息时会校验这个 fingerprint 信息,因此如果业务侧代码发生变更,要重新部署的话,jsa 归档文件要重新制作。 使用 AppCDS 或者 CDS 的时候不能 debug java 程序。因为 debug 的时候 jvmti 会修改 class 对应的内容,而根据第二点,必然会导致 fingerprint 不一致。 目前 AppCDS 并不支持 `Custom ClassLoader`,因此在 tomcat、jetty、SpringBoot 这些使用较多 `Custom ClassLoader` 场景的,整体收益跟原生 CDS 应该差不多,class 可以 share 的范围仅仅多了一些 Application 自身的 boot class。 # 后记 如果遇到相关技术问题(包括不限于毕昇 JDK),可以进入毕昇 JDK 社区查找相关资源(点击[阅读原文](https://mp.weixin.qq.com/s/QVljVWthj9mvAL0HAiWFcw)进入官网),包括二进制下载、代码仓库、使用教学、安装、学习资料等。毕昇 JDK 社区每双周周二举行技术例会,同时有一个技术交流群讨论 GCC、LLVM、JDK 和 V8 等相关编译技术,感兴趣的同学可以添加如下微信小助手,回复 Compiler 入群。  # 参考 [1] https://juejin.cn/post/6844903581246914574 原文转载自 openEuler-[毕昇 JDK 8 中 AppCDS 实现介绍](https://mp.weixin.qq.com/s/QVljVWthj9mvAL0HAiWFcw)
-
作者:程经纬、谢照昆 > 编者按:两位笔者分享了不同的案例,一个是因为 JDK 小版本升级后导致运行出错,最终分析定位原因为应用启动脚本中指定了 Classpath 导致 JVM 加载了同一个类的不同版本,而 JVM 在选择加载的类则是先遇到的先加载,进而导致应用出错,该问题的根因是设置了错误的 Classpath。第二个案例是在相同的 OS、JDK 和应用,不同的文件系统导致应用运行的结果不一致,最终分析定位的原因是 JVM 在加载类时遇到了多个版本的问题,但是该问题的根因是没有指定 Classpath,JVM 加载类会依赖于 OS 读取文件的顺序,而不同的文件系统导致提供文件的顺序不同,导致了问题的发生。经过这两个案例的分析,可以得到 2 个结论:需要指定 Classpath 避免不同文件系统(或者 OS)提供不同的文件顺序;需要正确地指定 Classpath,避免加载错误的类。希望读者可以了解 JVM 加载类文件的基本原理,避免出现类似错误。 # 现象01 某产品线进行 JDK 升级,将 JDK 版本从 8u181 升级到 8u191 后,日志中报出大量 `java.lang.NoSuchFieldError`,导致基本服务功能不可用。具体报错如下:  # 分析 从这个调用栈来看,问题可能出现在 JDK 自身,并没有涉及到业务代码。首先自然应该去看一下 `ClientHandshaker.java` 的源码,确认一下出错时的上下文。先看 JDK 8u191 的代码,相关如下:  可以看到,虽然这里对 handshakeState 进行了 check,但是代码中完全没有出现 state 这个变量;那么 8u181 又如何呢?继续看代码:  这里的实现方式和 8u191 中有明显的不同,其中最重要的一点是,在 194 行中确确实实访问了 state 这个变量。追踪一下代码可以得知,ClientHandshaker 类继承自 Handshaker 类,state 也是从父类之中继承过来的一个 field。于是,可以得到一个初步的结论:JDK 8u191 中,ClientHandshaker 的实现方式与 8u181 不同,去除了 state 这个 field。 既然报错报了这个 field,因此可以确定,JVM 中加载的 ClientHandshaker 肯定不是 8u191 中的这一个。那么,可能是产品线在替换 JDK 时,没有替换完全,导致残留了一部分 8u181 的东西,让 JVM 加载了?这个猜测很快就被否定了,因为行号对不上:错误栈中的行号是 198,而 8u181 代码中对 state 的访问是在 194 行。 因此,为了直接推进问题,最好的办法就是确定 JVM 到底是从哪里加载了 ClientHandshaker。在 java 启动命令中加入如下参数,就可以追踪每一个 class 的加载: ```Java java -XX:+TraceClassLoading ``` 会产生类似于下面的输出:(加载的类 + 类的来源)  从这个输出中搜索一下 ClientHandshaker,最终发现了这么一行: ```Bash [Loaded sun.security.ssl.ClientHandshaker from /mypath2/lib/alpn-boot.jar] ``` 果然,出问题的 ClientHandshaker 并不是加载自 JDK 8u191 中,而是加载自 alpn-boot.jar 这个包。那么这个包又是从哪里找到的?检查了一下产品线的 java 启动命令,发现里面用 -cp 参数指定了许多 Classpath 路径,最后从里面找到了 "/mypath2/lib/alpn-boot.jar"。 到这个目录下,找到产品线所使用的 jar 包,然后将其中包含的 ClientHandshaker.class 反编译后,发现代码基本与 8u181 代码相同——也访问了 state,并且连行号(198)也能对应上。到此,根因基本确定。 alpn-boot.jar 是 Jetty 中用来实现 TLS 的扩展。产品线当时所使用的 alpn 版本是 8.1.12.v20180117,根据官方文档,这个版本只能兼容到 JDK 8u181,而 8u191 之后,alpn 的版本也应有相应的变化,以兼容新的 JDK 代码。为什么当时 alpn 没有自动适应 JDK 版本?因为产品的启动脚本里写死了那个老版本的 alpn-boot.jar,而在升级的时候却没有适配启动脚本。 # 现象02 笔者将相同的 java 应用和 JDK 部署在 Linux 环境中,一台机器上运行正常,另外一台和预期不一样。对于这个现象我们非常奇怪,从问题表象应该是外部环境导致了运行结果不同,为此我们对软件、硬件、环境进行排查,发现 2 台机器除了使用的文件系统不同外,其他并无不同。 为什么不同的文件系统会影响 JVM 的运行结果?根源在哪里? 通过排查发现有两个 jar 中存在全限定名相同的两个主类,那么 JDK 会去选择哪个主类加载呢,对于 Classpath 通配符 JDK 又是如何解析的,下面笔者对上面问题进行分析。 # 环境介绍 准备两台 Linux 机器,其中一台文件系统为 ext4,另一台为 xfs。可以使用 df -T 命令查看使用的文件系统。 复现问题的方式非常简单,可以创建两个全限定名一样的类,然后编译打成 jar 包放在同一个目录中。运行 java 进程时,指定的 Classpath 路径使用通配符。可以通过下面的 demo 复现这个问题。 - Demo 的目录结构  **moduleA Main.java** ```Java package com.example; public class Main { public static void main(String[] args) { System.out.println("module A"); } } ] ``` **moduleB Main.java** ```Java package com.example; public class Main { public static void main(String[] args) { System.out.println("module B"); } } ``` - 编译及打包 先使用 java 命令将这两个类编译,然后分别使用 jar 命令打包到 moduleA.jar 和 moduleB.jar 中,并保存在 lib 目录中。切换到 demo 目录,执行如下命令进行编译、打包。 ```Bash mkdir -p moduleA/out javac moduleA/src/com/example/Main.java -d moduleA/out/ mkdir -p moduleB/out javac moduleB/src/com/example/Main.java -d moduleB/out/ mkdir lib jar -cvf lib/moduleA.jar -C moduleA/out/ . jar -cvf lib/moduleB.jar -C moduleB/out/ . ``` - 运行 ```Bash java -cp .:/home/username/demo/lib/* com.example.Main ``` # 测试结果 对于不同文件系统的环境,输出的结果可能不同,下面以 ext 和 xfs 文件系统为例,可以看到输出不同的结果。 - ext4 moduleA.jar 创建时间早于 moduleB.jar,输出 module B。  moduleA.jar 创建时间晚于 moduleB.jar,输出 module B。  **无论是先创建 moduleA.jar 还是 moduleB.jar,最终的输出结果都是 module B**。 - xfs moduleA.jar 创建时间早于 moduleB.jar,输出 module A。  moduleA.jar 创建时间晚于 moduleB.jar,输出 module B。  **如果先创建 moduleA.jar,然后创建 moduleB.jar,输出的结果是 module A;反之,输出的结果是 module B。** # 原因分析 ## 排查方法 使用 JDK 8 进程启动时,添加 VM 参数 `-XX:+TraceClassPaths -XX:+TraceClassLoading`。其中以 ext 文件系统为例,可以得到如下的日志:  从日志可以发现 Classpath 解析后的路径是 moduleB.jar 在 moduleA.jar 之前,并且加载的是 moduleB.jar 的类。对于解析后的 Classpath,还可以通过添加 -XshowSettings 选项查看。  对于常驻进程,查看通配符解析后的 Classpath,可以使用 jcmd 命令查看。当然使用 jconsole 或者 visualvm 等工具连接进程也可以查看解析后的 Classpath。  ## Classpath 通配符如何解析 以 Linux 系统为例,在 Classpath 中使用冒号分割多个路径,并且按照定义的顺序进行通配符解析。如下所示,任何文件系统解析出来的路径始终是 lib 目录的 jar 包在 lib2 目录的 jar 包之前。 ```Bash .:/home/username/demo/lib/*:/home/username/demo/lib2/* ``` JVM 在解析通配符 * 时,最终会调用系统函数 opendir、readdir 读取遍历目录。ext4 创建文件的顺序与实际 readdir 读取的顺序不一致的原因主要在于 ext 系列文件系统有个 feature,即 dir_index,用于加快查找目录项(可直接计算其 hash 值定位到它的目录项),目录项也便成了以 hash 值大小进行排序。通常 dir_index 默认开启,可以通过 / etc/mke2fs.conf 查看默认配置。 创建一个 test_readdir.c 文件,用 C 语言实现一个 demo。通过调用系统 readdir 遍历目录,并且打印文件的 d_off、d_name 属性值。编译、执行命令如下所示: **编译** ```Shell gcc test_readdir.c -o test_readdir.out ``` **执行** ```Shell ./test_readdir.out /home/user/testdir ``` test_readdir.c 文件 ```C #includetypes.h> #include #include #include int main(int argc, char *argv[]) { DIR *dir; struct dirent *ptr; int i; if(argc==1) { dir = opendir("."); } else { dir = opendir(argv[1]); printf("%s\n",argv[1]); } while((ptr = readdir(dir))!=NULL) { printf(" d_off:%ld d_name: %s\n",ptr->d_off,ptr->d_name); } closedir(dir); return 0; } ``` **运行结果** 分别在 ext4、xfs 文件系统上按顺序创建 m1~m10 文件,然后查看运行结果。对比发现 readdir 函数在不同文件系统中都是按照 d_off 属性值从小到大顺序进行遍历,不同的是 xfs 文件 d_off 的值按照创建时间依次增大,而 ext4 和文件的创建顺序无关。 ext4  xfs  ## 解决办法&修复方法 可以将需要加载的主类所在的 jar 包存放在新创建的文件目录 libmain 下,并且将 libmain 目录放在 lib 目录之前,则指定 Classpath 路径的顺序如下所示: ```Bash .:/home/user/demo/libmain/*:/home/user/demo/lib/* ``` # 后记 如果遇到相关技术问题(包括不限于毕昇 JDK),可以进入毕昇 JDK 社区查找相关资源(点击[阅读原文](https://www.openeuler.org/zh/other/projects/bishengjdk/)进入官网),包括二进制下载、代码仓库、使用教学、安装、学习资料等。毕昇 JDK 社区每双周周二举行技术例会,同时有一个技术交流群讨论 GCC、LLVM、JDK 和 V8 等相关编译技术,感兴趣的同学可以添加如下微信小助手,回复 Compiler 入群。  原文转载自 openEuler-[JVM 中不正确的类加载顺序导致应用运行异常问题分析](https://mp.weixin.qq.com/s/nSl-xWbB3GKfm2AwxkHK6Q)
-
精度整数(不使用小数点或指数计数法)最多为 15 位。实例var x = 999999999999999; // x 为 999999999999999var y = 9999999999999999; // y 为 10000000000000000尝试一下 »小数的最大位数是 17,但是浮点运算并不总是 100% 准确:实例var x = 0.2+0.1; // 输出结果为 0.30000000000000004尝试一下 »八进制和十六进制如果前缀为 0,则 JavaScript 会把数值常量解释为八进制数,如果前缀为 0 和 "x",则解释为十六进制数。实例var y = 0377;var z = 0xFF;尝试一下 »lamp 绝不要在数字前面写零,除非您需要进行八进制转换。 默认情况下,JavaScript 数字为十进制显示。但是你可以使用 toString() 方法 输出16进制、8进制、2进制。实例var myNumber=128;myNumber.toString(16); // 返回 80myNumber.toString(8); // 返回 200myNumber.toString(2); // 返回 10000000尝试一下 »无穷大(Infinity)当数字运算结果超过了JavaScript所能表示的数字上限(溢出),结果为一个特殊的无穷大(infinity)值,在JavaScript中以Infinity表示。同样地,当负数的值超过了JavaScript所能表示的负数范围,结果为负无穷大,在JavaScript中以-Infinity表示。无穷大值的行为特性和我们所期望的是一致的:基于它们的加、减、乘和除运算结果还是无穷大(当然还保留它们的正负号)。实例myNumber=2;while (myNumber!=Infinity){ myNumber=myNumber*myNumber; // 重复计算直到 myNumber 等于 Infinity}尝试一下 »除以0也产生了无限:实例var x = 2/0;var y = -2/0;尝试一下 »NaN - 非数字值NaN 属性是代表非数字值的特殊值。该属性用于指示某个值不是数字。可以把 Number 对象设置为该值,来指示其不是数字值。你可以使用 isNaN() 全局函数来判断一个值是否是 NaN 值。实例var x = 1000 / "Apple";isNaN(x); // 返回 truevar y = 100 / "1000";isNaN(y); // 返回 false尝试一下 »除以0是无穷大,无穷大是一个数字:实例var x = 1000 / 0;isNaN(x); // 返回 false尝试一下 »数字可以是数字或者对象数字可以私有数据进行初始化,就像 x = 123;JavaScript 数字对象初始化数据, var y = new Number(123);实例var x = 123;var y = new Number(123);typeof(x) // 返回 Numbertypeof(y) // 返回 Object尝试一下 »实例var x = 123; var y = new Number(123);(x === y) // 为 false,因为 x 是一个数字,y 是一个对象尝试一下 »
-
为了增加我们中将的概率达到100人开启的宝箱 本仙女特意给大家来个普及1024如何开发的小文章 心情好一日俩更 勿催~还没开始的小伙伴点击链接:https://bbs.huaweicloud.com/forum/thread-161030-1-1.html 和小助手一起来做吧认真阅读要求:修改max什么的参数值 在后面一个单元添加什么命令 (这个命令应该是唯一的所以尽量自己做哈)1:点击开始实验2:点击runinmodelarts找到:修改max什么的参数值 默认是100我们可以修改为50or任何一个数字复制开题中的要求 !env | grep PROJECT_ID点击run all cells等待着~漫长而又快乐~如此这般 这般如此 id就出来了 回帖后小助手就会给你发有效的链接:切记一定要用java运行 不要用python或则其他工具如果电脑没有安java可以试试华为云的云端devcloud java开发环境 非常nice哦给大家一个小提示:如果在破解完小助手的代码后 打开链接右上角显示参数错误 就是整错了 后台不会有数据的!
-
## 作者: 吴言 > 编者按:目前许多公司同时使用 x86 和 AArch64 2 种主流的服务器。这两种环境的算力相当,内存相同的情况下:相同版本的 JVM 和 Java 应用,相同的 JVM 参数,应用性能在不同的平台中表现相差 30%,x86 远好于 AArch64 平台。本文分析了一个应用在 AArch64 平台上性能下降的例子,发现 JVM 的 CodeCache 大小是引起这个性能问题的根源,进而研究什么导致了不同平台上 CodeCache 大小的不同。最后笔者给出了不同平台中该如何设置参数规避该问题。希望本文能给读者一些启示:当使用不同的硬件平台时需要关注底层硬件对于上层应用的影响。 业务在 x86 和 AArch64 上同时部署时(相同的 JDK 和 Java 应用版本),发现 AArch64 平台性能下降严重问题。进一步查看日志,发现在 AArch64 平台中偶有如下情况:  这代表 JVM 中的 `CodeCache` 满了,导致编译停止,未编译的方法只能解释执行,进而严重影响应用性能。那什么是 `CodeCache`? # CodeCache 是什么 简单来说,`CodeCache` 用于存放编译后的方法,主要分为三部分: 1. `Non-nmethods`:包括运行时 Stub,Adapter 等; 2. `Profiled nmethod`:包括会采集信息的方法,即分层编译中第 2、3 层的方法; 3. `Non-Profiled nmethods`:包括不采集信息的方法,即分层编译中第 1、4 层的方法,也包括 JNI 的方法。 注:分层编译指的是 JVM 同时存在 C1 和 C2 两种编译器,C1 做一些简单的编译优化,耗时较短,C2 做更多复杂的编译优化,性能较好,编译耗时较多。分层编译的触发在 JVM 内会根据相应的条件进行触发,关于更多分层编译相关知识可以参考相关资料 [1]。 在 JDK 9 之后 [2],这些会分配到不同的区域(使用不同区域的优点:查找、回收等),JDK 8 中会分配到同一块区域。 JVM 平时会清理一些不可达的方法,例如由于退优化等产生的死方法,另外 `UseCodeCacheFlushing` 选项(默认开启),还会清理较老以及执行较少的方法。一旦 `CodeCache` 满了之后,会停止编译,直到 `CodeCache` 有空间,若关闭了 `UseCodeCacheFlushing` 选项,则会直接永久停止编译。 不同的 JVM 版本以及不同的参数,默认的 `CodeCache` 大小不同。JDK 11 中默认参数下 `CodeCache` 大小为 240M,若想获取(确认)默认情况下的 `CodeCache` 大小,建议使用 `- XX:+PrintFlagsFinal` 选项获取 `ReservedCodeCache` 的大小。 `CodeCache` 大小主要通过以下选项调节: | Option | Description | | ---- | ---- | | InitialCodeCacheSize | 初始的 CodeCache 大小(单位字节) | | ReservedCodeCacheSize | 预留的 CodeCache 大小,即最大CodeCache 大小(单位字节) | | CodeCacheExpansionSize | CodeCache 每次扩展大小(单位字节) | 使用 `–XX:+PrintCodeCache` 选项可以打印应用使用的 `CodeCache` 情况,如下:  其中 `max_used` 表示应用中使用到的 `CodeCache` 大小,据此可以设置合适的 `ReservedCodeCacheSize` 值。 # AArch64 vs x86_64 我们都知道 AArch64 和 x86 分别为 RISC 和 CISC 架构,因此代码密度方面存在一定差异,在这篇文章 [3] 中比较了不同指令集下手写汇编的大小,可以看到 AArch64 的代码密度是 RISC 架构中较优的,但相比 x86_64 仍稍差些(其中 RISC 最差,m68k 最好)。  另外笔者选用业界通用的 java 测试套 dacapo[4] 比较 AArch64 和 x86_64 下 `CodeCache` 占用的大小。  可以看到,在 AArch64 架构下,`CodeCache` 均比 x86_64 要大,但根据不同场景,大小差距不同,在 5%-20% 之间。因此在我们发现相同应用在 x86 和 AArch64 上时,`CodeCache` 大小需要进行相应的调节。 除此之外,还需要注意 `InlineSmallCode` 选项,JVM 只会 `inline` 代码体积比该值小的方法。JVM 通过 `inline` 可以触发更多的优化,因此 `inline` 对于性能提升也很重要。在 JDK 11 中,`InlineSmallCode` 在 x86 下的默认值为 2000 字节,在 AArch64 下的默认值为 2500 字节。而 JDK 8 中,`InlineSmallCode` 在 x86 和 AArch64 下默认值均为 2000 字节。因此建议迁移时也相应修改 `InlineSmallCode` 的值。业务通过对 `CodeCache ` 相关参数的调整,达到助力 JIT 的最佳编译效果。 # 后记 如果遇到相关技术问题(包括不限于毕昇 JDK),可以进入[毕昇 JDK 社区](https://www.openeuler.org/zh/other/projects/bishengjdk/)查找相关资源,包括二进制下载、代码仓库、使用教学、安装、学习资料等。毕昇 JDK 社区每双周周二举行技术例会,同时有一个技术交流群讨论 GCC、LLVM、JDK 和 V8 等相关编译技术,感兴趣的同学可以添加如下微信小助手,回复 Compiler 入群。  # 参考 [1]http://cr.openjdk.java.net/~thartmann/talks/2017-hotspot_under_the_hood.pdf [2]https://bugs.openjdk.java.net/browse/jdk-8015774 [3]http://web.eece.maine.edu/~vweaver/papers/iccd09/ll_document.pdf [4]http://dacapobench.org/
-
从4.1版本的设计器开始,可以免去下面繁琐的操作,建议使用4.1版本的设计器,具体安装见本帖2楼-------------------------------------------------------------------------------如果是操作1.8版本的Java,如用友2.0.0的2022版本,如下路径所示,可以直接使用10楼的方法,跳过后面的步骤。用户目录>Appdata>Local>UClient>share>java1.8.0_202-x64===========================================部分老的Java桌面程序也可以使用这种方法。操作思路:1、通过找到java/javaw的进程来找到程序的安装目录2、找到jre文件夹判断Java程序的版本是32位还是64位(可以通过查找安装目录里java.exe的文件,如果有多个,则每个目录都尝试一下找到jre目录,在CMD窗口使用java.exe -version来查看版本,注意并非见到32就是32位,见下图是64 Bit)3、导入java官方提供的bridge包实现拾取功能2021.12.25补充======已知可以适配的客户端有:(如果有其他,大家可以跟帖补充)1、用友2.0.02、金蝶EAS V8.5.0 / BOS 企业版8.5.03、华为U2000客户端4、用友 NC6.5 (Java1.7_64位)当前用友U8+应该不是Java框架,所以无法使用这种方法;可以使用桌面应用click+模拟人工+像素偏移(模拟人工选True后就出现了)的方式完成。在3.3.1以及以后的版本做了适配,增加name为空时的定位的修正,如果遇到特殊情况无法进行元素校验的,可以尝试在窗体标题的后面增加一个*来统配(如采购入库单页面操作)。======1、打开用友的客户端并打开要操作的系统。或者打开要操作的软件系统 按照①②③步骤打开,用友插件的系统的安装目录。注意识别是图的这个javaw.exe的图标,必须是在打开了用友软件以后进行,目的是让系统加载了javaw.exe.2、根据安装路径里是32位还是64位,进行相应的文件包复制粘贴找到软件安装目录后按照如下的操作可以完成设置,如果没有文件夹标明版本,则可以通过java.exe -version来查看版本注意:64位的javaw应用系统只能保留64位相应的dll,32位的javaw应用试用32位的dll。32位的dll复制进64位的目录后会引起系统默认加载32位的dll,从而仍是无法拾取。附件下载并解压后,如下所示:可以将文件夹里的内容直接复制到第一步打开的目录里即可,如果有文件覆盖,则选择覆盖。如下是演示32位java安装到系统里时的安装方式。安装目录在C:Program Files (x86)Javajre6 32位为例,64位可参考后面的跟帖 把压缩包里面的文件copy到本机的目录accessibility.properties=> C:Program Files (x86)Javajre6libaccess-bridge-32.jar=> C:Program Files (x86)Javajre6libextjaccess.jar=> C:Program Files (x86)Javajre6libextJavaAccessBridge-32.dll => C:Program Files (x86)Javajre6in JAWTAccessBridge-32.dll=> C:Program Files (x86)Javajre6in WindowsAccessBridge-32.dll => C:WindowsSysWOW64---可以放到前面的bin里WindowsAccessBridge-64.dll => C:WindowsSystem32---可以放到前面的bin里然后就可以使用 jab的工具AccessBridgeExplorer.exe来查看应用的控件了,或者就能用app录制了3、然后屏幕右下角退出用友,然后再从桌面启动用友。4、启动studio进行拾取即可,如果还不行则可能需要管理员权限运行。如果有异常可以对照本帖后面的跟帖来检查
This is WeAutomate
发表于2021-11-02 19:50:13
2021-11-02 19:50:13
最后回复
We are WeAutomate
2023-10-25 16:40:10
5206 11 -
经过一个多月的学习,相信大家对Java有了进一步的了解和认知我们迎来了第二阶段的最终考核请大家认真阅读考核要求,避免无法考核认证*报名活动才能参加最终考核考核截止时间11月04日(超出考核时间不计入成绩)请遵守考试秩序,考试之前请务必仔细阅读以下注意事项:1)正式考试前请确定邮箱已绑定,如未绑定的,请登录华为云官网,按照出现的页面完成邮箱绑定。2)考试请使用Google Chrome(48版本以上)浏览器完成。3)考试次数为5次,请珍惜考试机会。每次考试会从题库中随机抽题。4)考试时间为40分钟,考试期间无法暂停,一旦超时,系统将自动提交试卷。交卷后即可查看到成绩。5)考试共25题,题型包括判断、单选和多选,总分100分。6)考试过程中若有截屏或切屏行为,系统将发出警告,切屏次数达到5次,系统将自动提交试卷7)点击开始考试后,请耐心等待系统抽题,切勿重复刷新页面,否则导致题目抽取错误,成绩将会被作废。集齐三阶段电子证书可获得【Java编程创造营】结业实体证书考核流程点击下方链接进行Java开发技能考核点击进行Java开发技能测评(高级)将成绩截图及最高成绩回复到本帖阶段学习排行榜不仅有学习纪念证书,我们还为参与学习打卡的同学准备了实物奖品奖励通过获取积分,积分排行的方式获得奖励(以下奖励获取需满足积分≥30分)1)学习打卡赢积分点此学习Java学习路线序号阶段任务详情活动积分奖励附加奖励提交入口1每章随堂测试任务完成方式:在随堂测试打卡帖中,回复对应章节的随堂 回复格式:华为云ID+截图(露出右上角华为云ID,且有效回复次数≥1)2分 /每有效打卡/每章节在提交随堂测试的用户中,抽取1名幸运奖励华为云定制鼠标*1点击前往2每周学习笔记分享任务完成方式:在学习笔记征集帖中,回复本周课程内容的学习笔记 回复格式:华为云ID+笔记内容(字数≥200字)2分 /每有效打卡/每周在本提交学习笔记的用户中,抽取1名幸运奖励华为云定制鼠标*1敬请期待点击前往3相关文章征集任务完成方式:本学习阶段任意时间内,在“华为云-博客”,发表与学习内容相关的任意原创博客内容,将文章链接回复到指定帖内 回复格式:华为云ID+博客文章链接(字数≥600字)5积分 /每篇有效心得/每阶段 最高10/每阶段每阶段选取1篇最佳博文,奖励机械键盘*1点击前往4问答官排位赛任务完成方式:用户可在相关活动帖中发布自己学习中的疑惑或实践问题,其他用户可参与回答。由专家评审,同一问题下确定一名最佳答案。回复格式:华为云ID+提问的问题/解答答案5积分/每有效问题(最高10分)2积分/每有答复(最高4分)最终会全部每阶段参与互动的用户中,抽取3位幸运奖奖励华为云定制鼠标*1点击前往5完成阶段沙箱实验完成规定的沙箱实验20分/ 沙箱实验/点击前往6完成相关微认证完成规定的微认证并获得微认证证书30分/认证/点击前往注意事项:○获奖名单将在活动结束后3个工作日内公示。如有异议请于【华为云课程小助手】联系○所有活动奖品将在活动公示后15个工作日内完成发放;○活动奖品颜色、型号随机,且部分奖品数量有限发完即止,,若有缺货或其他情况将替换为同价值的其他奖品;○本次活动回帖内容需满足华为云论坛发帖规范:https://bbs.huaweicloud.com/forum/thread-23077-1-1.html想了解更多关于课程内容请移步主帖:https://bbs.huaweicloud.com/forum/forum.php?mod=viewthread&tid=125761
上滑加载中
推荐直播
-
华为云码道Agent集成与鸿蒙实战2026/08/11 周二 19:00-21:00
王一男-华为云码道产品规划专家;李炎-华为云码道产品专家;彭江敏-华为云鸿蒙端云一体化开发专家
本次直播带你解读华为云码道7月份产品新特性、新功能。更有专家演示码道Agent Space × 钉钉机器集成实战,从0到1打通消息通道;码道鸿蒙端云一体化实战,快速搭建员工签到系统。
回顾中 -
华为云开发者AI素养直播课·第五期2026/09/04 周五 16:00-18:00
林华鼎-华为云AI开发者运营负责人;蒋春阳-华为云AI开发者案例开发专家
本期直播内容: AI工具体验营 · 第5-8课连讲。Agent-Team 多智能体协作完成毕业设计实践
回顾中 -
华为云开发者AI素养ClassRoom·第六期2026/09/08 周二 19:00-20:00
樊渊-2026华为软件挑战赛冠军
高手来了:看软挑高手解析二维排样问题—从工业难题到算法突破
回顾中
热门标签