版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Java库与案例分析Java API & Case Study刘 钦 南京大学软件学院 Outline 案例分析 Java API案例分析 Spec-用结构化方法我们怎么办? 自顶向下,逐步求精 High-level designGame play beginsCreate Three DotcomGame FinishesGamePlace themGive a ratingCheck the guess PromptStart a gameSinka Dot Com-结构化设计 Dot Com DataCommand DataBoard Data SimpleDotComGameDevel
2、oping a Classif(guess =cell) result = “hit”;numOfHits+;if(guess =cell) result =“hit”; numOfHits+;A Real “Sink a Dot Com” Goal: Sink all Dot Coms in the fewest number of guesses Setup:Three Dot Coms on 7x7 grid How you play: Guess - Hit, miss or kill?; Guess - Hit, miss or kill?; Win, Show your numbe
3、r of guessesWhat have been changed Number ofdotcom: 1 - 3 Position of dotcom: 1D - 2D Algorithm of the game: Easy - Complicated用面向对象方法我们怎么办? 职责分配,协作 过程 寻找职责 职责分配 对象的创建 对象的协作寻找职责 寻找数据职责 找名词 寻找行为职责 找动词 确定职责 去除冗余、无关 检查是否满足“封装”的条件名词与动词 游戏 猜测次数 棋盘大小 公司 公司数目 公司名字 公司位置 提示 猜测 判断是否猜中 判断游戏是否结束 输入 输出 游戏开始 游戏结束
4、名词与动词 游戏 猜测次数 公司数目 公司 公司名字 公司位置 IOHelper 提示 游戏开始 游戏结束(显示猜测次数) 判断游戏是否结束 判断是否猜中 输入 输出 职责 - DotComBust 数据职责 DotCom集合 猜测次数 行为职责 游戏开始 判断游戏结束 判断 游戏结束(显示猜测次数) 对象个数 1个职责 - DotCom 数据职责 DotCom位置 行为职责 判断是否猜中 对象个数 3个 Java APIOutline 案例分析 Java API String 输入输出 Java.lang Object the class that is the root of every
5、class hierarchy. Enum the base class for enumerationclasses. Class the class that is the root of the Java reflection system. Throwable the class that is the base class of the exception class hierarchy. Error, Exception, and RuntimeException the base classes for each exception type. Thread the class
6、that allows operations on threads. String the class for strings and string literals.Java.lang StringBuffer and StringBuilder classes for performing string manipulation. Comparable the interface that allows generic comparison and ordering of objects. Iterable the interface that allows generic iterati
7、on using the enhanced for loop. ClassLoader, Process, Runtime,SecurityManager, and System classes that provide system operations that manage the dynamic loading of classes, creation of external processes, host environment inquiries such as the time of day, andenforcement of security policies. Math a
8、nd StrictMath classes that provide basic math functions such as sine, cosine, and square root. The primitive wrapper classes that encapsulate primitive types as objects. The basic exception classes thrown for language-level and other common exceptions.Other Packages General Purpose Packages Java.io
9、Java.math J Java.text Java.util Special Purpose Packages Java.applet Java.beans Java.awt Java.rmi Java.sql Javax.swing字符串String类 1、String类是final的,不可被继承。public final class String。 2、String类是的本质是字符数组char, 并且其值不可改变。private final char value; 3、String类对象有个特殊的创建的方式,就是直接指定比如String x = abc,abc就表示一个字符
10、串对象。而x是abc对象的地址,也叫 做abc对象的引用。 4、String对象可以通过“+”串联。串联后会生成新的字符串。也可以通过concat()来串联。 5、创建字符串的方式很多,归纳起来有三类: 其一,使用new关键字创建字符串,比如String s1 = new String(abc); 其二,直接指定。比如String s2 = abc; 其三,使用串联生成新的字符串。比如String s3 = ab + c; public class StringTest1public static void main(String args) String str1 = abc; String
11、 str2 = abc;System.out.println(str1 = str2); public class StringTest2 public static void main(String args) String str1 = new String(abc); String str2 = new String(abc); System.out.println(str1 = str2);String对象的创建 原理1:当使用任何方式来创建一个字符串对象s时,Java运行时(运行中JVM)会拿着这个X在String池中找是否存在内容相同的字 符串对象,如果不存在,则在池中创建一个字符
12、串s,否则,不在池中添加。 原理2:Java中,只要使用new关键字来创建对象,则一定会(在堆区或栈区)创建一个新的对象。 原理3:使用直接指定或者使用纯字符串串联来创建String对象,则仅仅会检查维护String池中的字符串,池中没有就在池中创建一个,有则罢了!但绝不会在堆栈区再去创建该String对象。 原理4:使用包含变量的表达式来创建String对象,则不仅会检查维 护String池,而且还会在堆栈区创建一个String对象。不可变类 不可改变的字符串具有一个很大的优点:编译器可以把字符串设置为共享。 JAVA为了提高效率,所以对于String类型进行了特别的处理为String类型提
13、供了串池定义一个string类型的变量有两种方式: String name= tom ; String name =new String( tom ) 使用第一种方式的时候,就使用了串池;使用第二种方式的时候,就是一种普通的声明对象的方式 。如果你使用了第一种方式,那么当你再声明一个内容也是 tom 的String时,它将使用串池里原来的那个内存,而不会重新分配内存,也就是说,String name= tom ,将会指向同一块内存 另外关于String类型是不可改变的问题:String类型是不可改变的,也就是说,当你想改变一个String对象的时候,比如 name= madding 那么虚拟机
14、不会改变原来的对象,而是生成一个新的String对象,然后让name去指向 它,如果原来的那个 tom没有任何对象去引用它,虚拟机的垃圾回收机制将接收它。Case 1 - String “+” String tempstr = abcdefghijklmnopqrstuvwxyz; int times = 5000; long lstart1 = System.currentTimeMillis(); String str = ; for (int i = 0; i times; i+) str += tempstr; long lend1 = System.currentTimeMillis
15、(); long time = (lend1 - lstart1); System.out.println(time);Case 2 - StringBuffer String tempstr = abcdefghijklmnopqrstuvwxyz; int times = 5000; long lstart2 = System.currentTimeMillis(); StringBuffer sb = new StringBuffer(); for (int i = 0; i times; i+) sb.append(tempstr); long lend2 = System.curre
16、ntTimeMillis(); long time2 = (lend2 - lstart2); System.out.println(time2);Case 3 - StringBuffer more effectiveway String tempstr = abcdefghijklmnopqrstuvwxyz; int times = 5000; long lstart2 = System.currentTimeMillis(tempstr.length()*times); StringBuffer sb = new StringBuffer(); for (int i = 0; i le
17、ngth: 100000 time: 16concatStrBuild - length: 100000 time: 15concatStrAdd - length: 100000 time: 10437String +StringBuilderStringBuilder vsString Buffer Increasing the initial capacity for StringBuffer and StringBuilder doesnt make much difference. Clearly with only 100,000 iterations the numbers fo
18、r StringBuffer and StringBuilder are just noise.Iterations: 100000Capacity : 100000concatStrBuff - length: 100000 time: 15concatStrBuild - length: 100000 time: 16concatStrAdd - length: 100000 time: 10594 Lets crank it up but without the String concatenation test because it will never finish.Iteratio
19、ns: 100000000Capacity : 16concatStrBuff - length: 100000000 time: 15142concatStrBuild - length: 100000000 time: 10891 Now it is pretty clear StringBuilder is much faster because it avoids synchronization.Iterations: 100000000Capacity : 100000000concatStrBuff - length: 100000000 time: 14220concatStrB
20、uild - length: 100000000 time: 10611Allocating all the memory at once does make some difference but nothing really spectacular. But if we look at how the memory allocation peaks we get some more food for thought:Bump 1: StringBuffer with buffer 100000000Bump 2: StringBuffer with buffer 16Bump 3: Str
21、ingBuilder with buffer 100000000Bump 4: StringBuilder with buffer 16So StringBuilder is faster by a good percentage (34% on my machine in this case) but remember that it is not thread safe.Memory AllocationSern() 存在于.class文件中的常量池,在运行期被JVM 装载,并且可以扩充。String的intern()方法就是扩充常量池的一个方法; 当一个String实例
22、str调用intern()方法时,Java查 找常量池中是否有相同Unicode的字符串常量, 如果有,则返回其的引用, 如果没有,则在常量池中增加一个Unicode 等于str的字符串并返回它的引用 Java代码 String s0= “kvill”; String s1=new String(”kvill”); String s2=new String(“kvill”); System.out.println(s0=s1 ); System.out.println( “*” ); ern(); s2=ern(); /把常量池中“kvill”的引用赋给s2 Syste
23、m.out.println( s0=s1); System.out.println( s0=ern() ); System.out.println( s0=s2 ); 结果为: Java代码 false * false /虽然执行了ern(),但它的返回值没有赋给s1 true /说明ern()返回的是常量池中”kvill”的引用 Java代码 String s1=new String(kvill); String s2=ern(); System.out.println( s1=ern() ); System.out.println
24、( s1+ +s2 ); System.out.println( s2=ern() ); 结果: Java代码 false kvill kvill trueJava对象在JVM中的存储 一般而言,Java 对象在虚拟机的结构如下: 对象头(object header):8 个字节 Java原始类型数据:如 int, float, char等类型的数据,各类型数据占内存如 表1. Java 各数据类型所占内存. 引用(reference):4 个字节 填充符(padding)String在JVM中的存储 然而,一个 Java 对象实际还会占用些额外的空间,如:对象的 class 信息
25、、ID、在虚拟机中的状态。在 Oracle JDK 的 Hotspot 虚拟机中,一个普通的对象需要额外 8 个字节。 如果对于 String(JDK 6)的成员变量声明如下: private final char value; private final int offset; private final int count; private int hash; 那么因该如何计算该 String 所占的空间? 首先计算一个空的 char 数组所占空间,在 Java 里数组也是对象,因而数组也有对象头,故一个数组所占的空间为对象头所占的空间加上数组长度,即 8 + 4 = 12 字节 , 经过
26、填充后为 16 字节。 那么一个空 String 所占空间为: 对象头(8 字节)+ char 数组(16 字节)+ 3 个 int(3 4 = 12 字节)+1 个 char 数组的引用 (4 字节 ) = 40 字节。 因此一个实际的 String 所占空间的计算公式如下: 8*( ( 8+2*n+4+12)+7 ) / 8 = 8*(int) ( ( ( (n) *2 )+43) /8 ) 其中,n 为字符串长度。案例 在我们的大规模文本分析的案例中,程序需要统 计一个 300MB 的 csv 文件所有单词的出现次数,分析发现共有 20,000 左右的唯一单词,假 设每个单词平均包含 1
27、5 个字母,这样根据上述 公式,一个单词平均占用 75 bytes. 那么这样 75 *20,000 = 1500000,即约为 1.5M左右。但实际发现有上百兆的空间被占用。 实际使用的内存之所以与预估的产生如此大的差异是因为程序大量 使用String.split() 或 String.substring()来获取单 词。 public String substring(int beginIndex, int endIndex) if (beginIndex count) throw new StringIndexOutOfBoundsException(endIndex); if (beg
28、inIndex endIndex) throw new StringIndexOutOfBoundsException(endIndex - beginIndex); return (beginIndex = 0) & (endIndex = count) ? this : new String(offset + beginIndex, endIndex - beginIndex, value); 调用的 String 构造函数源码为: String(int offset, int count, char value) this.value = value; this.offset = off
29、set; this.count = count; 仔细观察粗体这行代码我们发现 String.substring()所返回的 String 仍然会保存原始 String, 这就是 20,000 个平均长度的单词竟然占用了上百兆的内存的原因。 一个 csv 文件中每一行都是一份很长的数据,包含了上千的单词,最后被 String.split() 或String.substring()截取出的每一个单词仍旧包含了其原先所在的上下文中,因而导致了出乎意料的大量的内存消耗。 当然,JDKString的源码设计当然有着其合理之处,对于通过 String.split()或 String.substring(
30、) 截取出大量 String 的操作,这种设计在很多时候可以很大程度的节省内存,因为这些 String 都复用了原始 String,只是通过 int 类型的 start, end 等值来标识每一个 String。 而对于我们的案例,从一个巨大的 String 截取少数 String 为以后所用,这样的设计则造成大量冗余数据。 因此有关通过 String.split()或 String.substring()截取 String 的操作的结论如下: 对于从大文本中截取少量字符串的应用,String.substring()将会导致内存的过度浪费。 对于从一般文本中截取一定数量的字符串,截取的字符串长
31、度总和与原始文本长度相差不大,现有的String.substring()设计恰好可以共享原始文本从而达到节省内存的目的。 既然导致大量内存占用的根源是 String.substring()返回结果中包含大量原始 String,那么一个显而易见的减少内存浪费的的途径就是去除这些原始 String。办法有很多种,在此我们采取比较直观的一种,即再次调用 newString构造一个的仅包含截取出的字符串的 String,我们可调用String.toCharArray()方法: String newString = new String(smallString.toCharArray();String
32、构造的方法选择 常见的创建一个 String 可以用赋值操作符= 或用 new 和相应的构造函数。初学者一定会想这两种有何区别,举例如下: String a1 = “Hello”; String a2 = new String(“Hello”); 第一种方法创建字符串时 JVM 会查看内部的缓存池是否已有相同的字符串存在:如果有,则不再使用构造函数构造一个新的字符串,直接返回已有的字符串实例;若不存在,则分配新的内存给新创建的字符串。 第二种方法直接调用构造函数来创建字符串,如果所创建的字符串在字符串缓存池中不存在则调用构造函数创建全新的字符串,如果所创建的字符串在字符串缓存池中已有则再拷贝一
33、份到 Java堆中。使用构造函数 string() 带来的内存性能隐患和缓解 仍然以之前的从 csv 文件中截取 String 为例,先前我们通过用 new String() 去除返回的 String 中附带的原始 String 的 方法优化了subString导致的内存消耗问题。然而,当我们下意识地使用 newString去构造一个全新的字符串而不是用 赋值符来创建(重用)一个字符串时,就导致了另一个潜在的性能问题,即:重复创建大量相同的字符串。说到这 里,您也许会想到使用缓存池的技术来解决这一问题,大概有如下两种方法: 方法一,使用 String 的 intern()方法返回 JVM 对字
34、符串缓存池里相应已存在的字符串引用,从而解决内存性能问题,但这个方法并不推荐!原因在于:首先,intern() 所使用的池会是 JVM 中一个全局的池,很多情况下我们的程序并不需要如此大作用域的缓存;其次,intern() 所使用的是 JVM heap 中 PermGen 相应的区域, 在 JVM 中 PermGen 是用来存放装载类和创建类实例时用到的元数据。程序运行时所使用的内存绝大部分存放在 JVM heap 的其他区域,过多得使用 intern()将导致 PermGen 过度增长而最后返回 OutOfMemoryError, 因为垃圾收集器不会对被缓存的 String 做垃圾回收。所以我们建议使用第二种方式。 方法
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- T/CPIA 0064-2024光伏封装胶膜表面粗糙度测试方法
- T/TIC 004-2023生态环境监测机构综合能力评价通用规范
- T/FSHW 05-2025道路保洁质量与作业规范
- T/CI 1481-2026农民用水合作组织运行制度设计规程
- T/CAAMTB 191-2024车用70MPa加氢口性能试验方法
- T/CPF 0114-2025温室气体 产品碳足迹量化方法与要求 成型纸盒
- 2025~2026学年安徽省阜阳市临泉县校联考北师大版六年级上册11月期中数学试卷【附答案】
- 2025-2026学年陕西省咸阳市初中政治八年级期末下册自测专项攻坚题附答案
- 人工智能在生物多样性监测中的应用
- Photoshop基础技能考核试题(含详细答案)
- 云南省西双版纳傣族自治州景洪市2026年公务员遴选试题题库及答案
- 临床检验标准化实验室完整SOP程序文件
- 2026年大数据工程师笔试试卷(附答案)
- 林下种植林地协议
- 第7课《社会主义好》第一课时(教学课件)
- 面料染色工艺质量控制细则
- 衰弱老年住院患者护理专家共识(2026完整版)
- 交通运输部所属事业单位统一招聘笔试真题2025
- 2026中国高端装备润滑材料技术门槛与军事应用价值报告
- 2026年抗菌药物合理使用全员培训计划表
- 戒烟健康科普 拥抱美好人生
评论
0/150
提交评论