Java常见类知识概括
java.util.regex类与String类的正则
String类的正则:
- JDK1.4之后我们可以直接通过String类来进行正则的调用,String类中有如下方法支持正则的开发:
- public boolean matches(String regex):
进行字符串验证,匹配某个正则;
- public String replaceALL(String regex,String replacement):
根据正则的描述替换全部;
- public String replaceFirst(String regex,String replacement):
根据正则的描述替换首个;
- public String[] split(String regex):
根据正则进行全部拆分;
- public String[] split(String regex,int limit):
部分拆分;
什么是正则表达式?
- 正则表达式(regular expression)是根据字符串集合内每个字符串共享的共同特性来描述字符串集合的一种途径。正则表达式可以用于搜索、编辑或者处理文本和数据。
- Java.util.regex主要包含以下三类:
①pattern类:pattern 对象是一个正则表达式的编译表示。
Pattern 类没有公共构造方法。要创建一个 Pattern 对象,你必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。
②Matcher类:Matcher 对象是对输入字符串进行解释和匹配操作的引擎。
与Pattern 类一样,Matcher 也没有公共构造方法。你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。
③PatternSyntaxException:PatternSyntaxException 是一个非强制异常类,它表示一个正则表达式模式中的语法错误。 - 前后端中的正则:
①前端语法:var 变量 = /正则表达式
/匹配模式
②后端语法:后端不需要前端中的/和/匹配模式,只需要填写正则表达式即可。
- 总结:
①Pattern类只能做一些简单的匹配操作,要想得到更强更便捷的正则匹配操作,那就需要将Pattern与Matcher一起合作.Matcher类提供了对正则表达式的分组支持,以及对正则表达式的多次匹配支持.
②链接:
<1>java.util.regex包详解
<2>java.util.regex类与String类的正则详解
Pattern和Matcher详解:
compile(String regex):
将正则表达式编译到Pattern中。该方法是个静态方法pattern() 返回正则表达式的字符串形式:
其实就是返回Pattern.complile(String regex)的regex参数Pattern.split(CharSequence input):
Pattern有一个split(CharSequence input)方法,用于分隔字符串,并返回一个String[],我猜String.split(String regex)就是通过Pattern.split(CharSequence input)来实现的。Pattern.matcher(String regex,CharSequence input):
Pattern.matcher(String regex,CharSequence input)是一个静态方法,用于快速匹配字符串,该方法适合用于只匹配一次,且匹配全部字符串;Pattern.matcher(CharSequence input):
Pattern.matcher(CharSequence input)返回一个Matcher对象. Matcher类的构造方法也是私有的,不能随意创建,只能通Pattern.matcher(CharSequence input)方法得到该类的实例. Pattern类只能做一些简单的匹配操作,要想得到更强更便捷的正则匹配操作那就需要将Pattern与Matcher一起合作,Matcher类提供了对正则表达式的分组支持,以及对正则表达式的多次匹配支持。Matcher.matches():
Matcher类提供三个匹配操作方法(Matcher.matches()/ Matcher.lookingAt()/ Matcher.find() ),三个方法均返回boolean类型,当匹配到时返回true,没匹配到则返回false ,matches()对整个字符串进行匹配,只有整个字符串都匹配了才返回true。Matcher.lookingAt():
lookingAt()对前面的字符串进行匹配,只有匹配到的字符串在最前面才返回true。Matcher.find():
find()对字符串进行匹配,匹配到的字符串可以在任何位置.Mathcer.start()/ Matcher.end()/ Matcher.group() :
当使用matches(),lookingAt(),find()执行匹配操作后,就可以利用以下三个方法得到更详细的信息.
①start():返回匹配到的子字符串在字符串中的索引位置.
②end():返回匹配到的子字符串的最后一个字符在字符串中的索引位置.
③group():返回匹配到的子字符串
Pattern p=Pattern.compile("\\w+");
p.pattern();//返回 \w+
Pattern p=Pattern.compile("\\d+");
String[] str=p.split("我的姓名是:456456我的电话是:0532214我的邮箱是:aaa@aaa.com");
Pattern.matches("\\d+","2223");//返回true
Pattern.matches("\\d+","2223aa");//返回false,需要匹配到所有字符串才能返回true,这里aa不能匹配到
Pattern.matches("\\d+","22bb23");//返回false,需要匹配到所有字符串才能返回true,这里bb不能匹配到
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("22bb23");
m.pattern();//返回p 也就是返回该Matcher对象是由哪个Pattern对象的创建的
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("22bb23");
m.matches();//返回false,因为bb不能被\d+匹配,导致整个字符串匹配未成功.
Matcher m2=p.matcher("2223");
m2.matches();//返回true,因为\d+匹配到了整个字符串
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("22bb23");
m.lookingAt();//返回true,因为\d+匹配到了前面的22
Matcher m2=p.matcher("aa2223");
m2.lookingAt();//返回false,因为\d+不能匹配前面的aa
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("22bb23");
m.find();//返回true
Matcher m2=p.matcher("aa2223");
m2.find();//返回true
Matcher m3=p.matcher("aa2223bb");
m3.find();//返回true
Matcher m4=p.matcher("aabb");
m4.find();//返回false
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("aaa2223bb");
m.find();//匹配2223
m.start();//返回3
m.end();//返回7,返回的是2223后的索引号
m.group();//返回2223
Scanner类
简述:
- Scanner类用于获取键盘输入(是一个基于正则表达式的文本扫描器),它可以从文件、字符串、输入流中解析出基本类型值和字符串值。
- Scanner类提供了多个构造器,不同的构造器可以接收文件、字符串和输入流作为数据源,用于从文件、字符串和输入流中解析数据。
- Scanner类主要提供了两个方法来扫描输入:
①hasNextXx():是否还有下一个输入项,其中Xxx可以是Int、Long等代表基本数据类型的字符串。如果只是判断是否包含下一个字符串,则直接使用hasNext()。
②nextXxx():获取下一个输入项。Xxx的含义同上。 - 默认情况下,Scanner使用空白(包括空格、Tab空白和回车)作为多个输入项的分隔符。
Hutool
简介:
- Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。
- Hutool中的工具方法来自于每个用户的精雕细琢,它涵盖了Java开发底层代码中的方方面面,它既是大型项目开发中解决小问题的利器,也是小型项目中的效率担当;
- Hutool是项目中“util”包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大限度的避免封装不完善带来的bug。
Hutool名称的由来:
- Hutool = Hu + tool,是原公司项目底层代码剥离后的开源库,“Hu”是公司名称的表示,tool表示工具。
- Hutool谐音“糊涂”,一方面简洁易懂,一方面寓意“难得糊涂”。
Hutool如何改变我们的coding方式:
- Hutool的目标是使用一个工具方法代替一段复杂代码,从而最大限度的避免“复制粘贴”代码的问题,彻底改变我们写代码的方式。
- 以计算MD5为例:
①【以前】打开搜索引擎 -> 搜“Java MD5加密” -> 打开某篇博客-> 复制粘贴 -> 改改好用
②【现在】引入Hutool -> SecureUtil.md5() - Hutool的存在就是为了减少代码搜索成本,避免网络上参差不齐的代码出现导致的bug。
包含组件:
- 一个Java基础工具类,对文件、流、加密解密、转码、正则、线程、XML等JDK方法进行封装,组成各种Util工具类,同时提供以下组件:
- 可以根据需求对每个模块单独引入,也可以通过引入hutool-all方式引入所有模块。
Apache Common
简述:
- Apache Commons包含了很多开源的工具,用于解决平时编程经常会遇到的问题,减少重复劳动。
Charset类
这里涉及两个概念:编码、解码:
- 编码(encode):把明文的字符序列转化成二进制的字节序列。
- 解码(decode):把二进制的字节序列转换成明文的字符序列。
简述:
- java默认的使用Unicode字符集,但是有的操作系统不支持,所以当从操作系统读取到java程序的时候,就可能出现乱码的情况。
- jdk1.4提供了Charset类来处理字节序列和字符序列之间的转换。Charset类是不可变类。
- Charset类提供了一个availiableCharset()静态方法来获取当前jdk支持的所有字符集。
- 常用的字符集:
GBK:简体中文。BIG5:繁体中文。ISO-8859-1:ISO拉丁字母表No.1,也叫ISO-LATIN-1.UTF-8:8位UCS转换格式。 - 知道了字符集的别名之后,就可以使用Charset的forName()方法,创建字符集对象。如下
Charset cs = Charset.forName("UTF-8");
- 获得Charset对象之后就可以调用该对象的newDecode()/newEncode()这两个方法返回CharsetDecoder/CharsetEncoder对象,这两个对象代表Chars的解码器和编码器。
- 调用CharsetDecoder的decode方法就可以将字符序列字节序列转换成字符序列(ByteBuffer)->(CharBuffer),同理调用encode就可以将字符序列转换成字节序列(CharBuffer)->(ByteBuffer)
- defaultCharset()返回此Java虚拟机的默认字符集。
①默认字符集在虚拟机启动期间确定,通常取决于底层操作系统的区域设置和字符集。
②结果 :默认字符集的字符集对象
字符集和字符编码
简述:
- 字符集合(ASCII、Unicode):由一套用于特定用途的字符组成,例如支持西欧语言的字符集合,支持中文的字符集合。字符集合只定义了符号和他们的语意,其实跟计算机没有直接关系。现实生活中,不同的语系有自己的字符集合,例如藏文有自己的字符集合,汉文有自己的字符集合。到计算机的世界中,也有各种字符集合,例如ASCII字符集合,GB2312字符集合,GBK字符集合。还有一个其他字符集合的超集–Unicode字符集定义了几乎绝大部分现存语言需要的字符,是一种通用的字符集,来支持多语言环境(可以同时处理多种语言混合的情况)。各个国家和地区在制定编码标准的时候,“字符集合”和“字符编码”一般都是同时制定的。所以像ASCII字符集合一样,它也同时代表了一种字符的编码。
- 字符编码:是一套规则,定义了在计算机内存中如何表示字符,是字符集中的每个字符与计算机内存中字节之间的转换关系,也可以认为是把字符数字化,规定每个“字符”分别用一个字节还是多个字节存储,用哪些字节来存储。例如ASCII编码[你没看错,它既是一种字符集合,也是一种字符编码],定义了英文字母和符号在计算机中的表示方式,是用一个字节来表示。Unicode字符集合,有好几种字符编码方式,例如变长度编码的UTF8,UTF16等。中文字符集也有很多字符编码,例如上文提到的GB2312编码,GBK编码等。
char、unicode、string和UTF8、UTF16之间的关系描述:
- Java语言内部使用的就是16位的Unicode编码,从概念上讲java字符串就是Unicode字符序列,Unicode字符集合的码点(码点:指与一个编码表中的某个字符对应的代码值)可以分成17个代码级别,第一个代码级别称为基本的多语言级别,码点从U+0000到U+FFFF,即65536个码点,只有第一级别的码点可以用一个char值表示;其余的16个级别码点从U+10000到U+10FFFF,其中包含一些辅助字符,需要两个char值才能表示一个码点;
- Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储,二进制与16进制等可以灵活转换,只是数值的表示方式变化而已,其值的大小不变。
- UTF8、UTF16即为采用什么样的规则表示所有的码点,在UTF16的编码规则中,UTF16采用不同长度的编码表示所有的Unicode码点,在基本的多语言级别,每个字符用16位表示,通常被称为代码单元;而辅助字符采用一对连续的代码单元进行编码。U+D800~U+DFFF为空闲的2048个替代区域,U+D800~U+DBFF用于第一个代码单元,U+DC00~U+DFFF用于第二个代码单元,这样的设计可以迅速的知道一个代码单元是一个字符的编码还是一个辅助字符的第一或第二部分。
Unicode 是不是只有两个字节,为什么能表示超过 65536 个字符?
-
Unicode 目前规划的总空间是17个平面(平面0至16),0x0000 至 0x10FFFF。每个平面有 65536个码点。你只是大致知道平面0(「Basic Multilingual Plane」,即「BMP」)的 65536 个码点(即 0x0000至 0xFFFF)如何编码,这不是 Unicode 的全部。
-
BMP 的字符是 Unicode 中最基础和最常用的一部分,以 UTF-16 编码时使用2字节,以 UTF-8 编码时使用1至3字节。超出BMP 的字符以 UTF-16 或 UTF-8 编码都需要4字节。
-
另外还有一个比较少用的编码形式,UTF-32,它编码任何 Unicode 字符都需要4个字节。Unicode的基础是一个编号的字符集,在字符集之上又规定了模块化的编码等等技术层次,各种具体的编码形式并不一致,因此「Unicode 只有两个字节」这句话根本不成立。
为啥需要Unicode:
- 我们知道计算机其实挺笨的,它只认识0101这样的字符串,当然了我们看这样的01串时肯定会比较头晕的,所以很多时候为了描述简单都用十进制,十六进制,八进制表示.实际上都是等价的,没啥太多不一样.其他啥文字图片之类的其他东东计算机不认识.那为了在计算机上表示这些信息就必须转换成一些数字.你肯定不能想怎么转换就怎么转,必须得有定些规则.
- 于是刚开始的时候就有ASCII字符集(American Standard Code for InformationInterchange, "美国信息交换标准码),它使用7bits来表示一个字符,总共表示128个字符,我们一般都是用字节(byte,即8个01串)来作为基本单位.那么怎么当用一个字节来表示字符时第一个bit总是0,剩下的七个字节就来表示实际内容.后来IBM公司在此基础上进行了扩展,用8bit来表示一个字符,总共可以表示256个字符.也就是当第一个bit是0时仍表示之前那些常用的字符.当为1时就表示其他补充的字符.
- 英文字母再加一些其他标点字符之类的也不会超过256个.一个字节表示主足够了.但其他一些文字不止这么多 ,像汉字就上万个.于是又出现了其他各种字符集.这样不同的字符集交换数据时就有问题了.可能你用某个数字表示字符A,但另外的字符集又是用另外一个数字表示A.这样交互起来就麻烦了
- 于是就出现了Unicode和ISO这样的组织来统一制定一个标准,任何一个字符只对应一个确定的数字.ISO取的名字叫UCS(Universal Character Set),Unicode取的名字就叫unicode了.
- 总结起来为啥需要Unicode就是为了适应全球化的发展,便于不同语言之间的兼容交互,而ASCII不再能胜任此任务了.
- Unicode详细介绍
字符集合与编码分类:
- 由来:计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字。就将各个国家的文字用数字来表示,并一一对应,形成一张表,这就是编码表。
- 常见的编码表:
①ASCII:美国标准信息交换码。用一个字节的7位可以表示。
②ISO8859-1:拉丁码表。欧洲码表用一个字节的8位表示。
③GB2312:中国的中文编码表。最多两个字节编码所有字符
④GBK:中国的中文编码表升级,融合了更多的中文文字符号。最多两个字节编码
⑤Unicode:国际标准码,融合了目前人类使用的所有字符。为每个字符分配唯一的字符码。所有的文字都用两个字节来表示。
⑥UTF-8:变长的编码方式,可用1-4个字节来表示一个字符。
ANSI和ASCII区别:
- ANSI码(American National Standards Institute)美国国家标准学会的标准码。
- ASCII码(America Standard Code for Information Interchange)美国信息交换标准码是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统,并等同于国际标准ISO/IEC646。
- 可以认为是不同的东西!ANSI码仅在前126个与ASCII码相同。
- 在简体中文Windows操作系统中,ANSI 编码代表 GBK 编码;在英文Windows操作系统中,ANSI 编码代表ASCII编码;在繁体中文Windows操作系统中,ANSI编码代表Big5;在日文Windows操作系统中,ANSI 编码代表Shift_JIS 编码。
总得来说可以这样划分:
Java中char类型占用多少个字节:
- 先区分unicode和UTF
- unicode :Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。统一的字符编号,仅仅提供字符与编号间映射。符号数量在不断增加,已超百万。
- UTF :unicode转换格式 (unicode transformation format)。定义unicode中编号的编码方式。utf8和utf16便是其中两种实现方式。其中utf8为变长表示,长度可能时1~6个字节;utf16为变长表示,长度可能是2或4个字节。
- 再分清内码(internal encoding)和外码(external encoding)
- 内码 :某种语言运行时,其char和string在内存中的编码方式。
①JVM中内码采用UTF16。早期,UTF16采用固定长度2字节的方式编码,两个字节可以表示65536种符号(其实真正能表示要比这个少),足以表示当时unicode中所有字符。
②但是随着unicode中字符的增加,2个字节无法表示所有的字符,UTF16采用了2字节或4字节的方式来完成编码。Java为应对这种情况,考虑到向前兼容的要求,Java用一对char来表示那些需要4字节的字符。
③所以,java中的char是占用两个字节,只不过有些字符需要两个char来表示。 - 外码 :除了内码,皆是外码。
①Java的class文件采用UTF8来存储字符,也就是说,class中字符占1~6个字节。
②Java序列化时,字符也采用UTF8编码,占1~6个字符。 - 要注意的是,源代码编译产生的目标代码文件(可执行文件或class文件)中的编码方式属于外码。
- 案例分析:
public class BytesOfChar {
public static byte[] getBytesUTF8 (char c ) {
Charset cs = Charset.forName("utf-8");
CharBuffer cb = CharBuffer.allocate (1);
cb.put (c);
cb.flip ();
ByteBuffer bb = cs.encode (cb);
return bb.array();
}
public static byte[] getBytesGBK (char c) {
Charset cs = Charset.forName("GBK");
CharBuffer cb = CharBuffer.allocate (1);
cb.put(c);
cb.flip ();
ByteBuffer bb = cs.encode (cb);
return bb.array();
}
public static void main(String[] args) throws UnsupportedEncodingException {
char c='a';
char cc='中';
String str="a";
String strr="中";
String s="a";
System.out.println("编码为UTF8:");
System.out.println("char值为英文字符所占字节长度:"+getBytesUTF8(c).length);
System.out.println("char值为中文字符所占字节长度:"+getBytesUTF8(cc).length);
System.out.println("编码为GBK(默认编码):");
System.out.println("char值为英文字符所占字节长度:"+getBytesGBK(c).length);
System.out.println("char值为中文字符所占字节长度:"+getBytesGBK(cc).length);
System.out.println("-------------------------------");
System.out.println("编码为UTF8");
System.out.println("String为英文字母所占字节长度:"+str.getBytes("utf-8").length);
System.out.println("String为中文字母所占字节长度:"+strr.getBytes("utf-8").length);
System.out.println("编码为GBK:");
System.out.println("String为英文字母所占字节长度:"+str.getBytes("GBK").length);
System.out.println("String为中文字母所占字节长度:"+strr.getBytes("GBK").length);
System.out.println("String为英文字母(全角)所占字节长度:"+s.getBytes("GBK").length);
}
}
运行结果:
编码为UTF8:
char值为英文字符所占字节长度:1
char值为中文字符所占字节长度:3
编码为GBK(默认编码):
char值为英文字符所占字节长度:2
char值为中文字符所占字节长度:2
-------------------------------
编码为UTF8
String为英文字母所占字节长度:1
String为中文字母所占字节长度:3
编码为GBK:
String为英文字母所占字节长度:1
String为中文字母所占字节长度:2
String为英文字母(全角)所占字节长度:2
- 总结:
①java中内码(运行内存)中的char使用UTF16的方式编码,一个char占用两个字节,但是某些字符需要两个char来表示。所以,一个字符会占用2个或4个字节。
②java中外码中char使用UTF8的方式编码,一个字符占用1~6个字节。
③UTF16编码中,英文字符占两个字节;绝大多数汉字(尤其是常用汉字)占用两个字节,个别汉字(在后期加入unicode编码的汉字,一般是极少用到的生僻字)占用四个字节。
④在UTF8编码中:一个英文字符占用一个字节;绝大多数汉字占用三个字节,个别汉字占用四个字节。
③在GBK编码中:一个英文字符占一个字节,一个汉字占两个字节。
中英文与编码方案总结:
- ASCII码:一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节的空间。一个二进制数字序列,在计算机中作为一个数字单元,一般为8位二进制数,换算为十进制。最小值-128,最大值127。如一个ASCII码就是一个字节。
- UTF-8编码:一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。中文标点占三个字节,英文标点占一个字节。
- Unicode编码(UTF-16):一个英文等于两个字节,一个中文(含繁体)等于两个字节。中文标点占两个字节,英文标点占两个字节。
- char类型的确是两个字节。
- getBytes()方法的功能是使用系统默认字符集对字符串进行编码,返回字节数组。中文系统默认GBK编码。GBK兼容ASCII编码,就是说,127以内的字符和ASCII编码表一样一样滴。
①"AAA".getBytes()按照默认GBK编码返回的就是长度为3字节的数组,所以长度为3。
②"哈哈哈".getBytes()按照默认GBK编码返回的就是长度为6字节的数组,因为每个汉字编码为2个字节。 - 使用InputStream从文件中读取时,也要看文件采用的是何种编码。根据编码将读入的字节进行解码才能得到正确的字符。
- 总结:
①java中的char类型是两个字节。就是说,'A’和’哈’都各占2个字节。
②getBytes()方法是获取编码后的字节数组。注意,是编码(外码)后,就是我前面说过的,默认采用GBK编码。你可能要问,编码前咋存放啊?事实上,在JAVA语言中,字符都是使用UTF16编码存放的(内码)。
③任何一个文字刚出现都是以某种编码存在。(例如在编辑器中右下角会标注该文件使用了哪种编码)
编码、解码、字符集总结:
- 编码:电脑只能处理0100110这样的二进制数字,字符是日常生活中我们使用的符号,为了使电脑能够存储、传输和展示字符,我们需要把字符转换为0100101这样的二进制码,这就是编码。
- 解码:相反,把0100110这样的二进制码转换为字符的过程就是解码。
- 字符集:至于把哪个字符映射到哪个二进制串上,是由国家(国家标准)、国际组织(国际标准)等来决定的。一般不用二进制串来表示字符的编码(看和阅读都很困难),而是用十六进制的串来表示某个字符的编码。因此,字符<–>十六进制串,之间的映射的集合就是我们所说的字符集了。
①我们经常见到的字符集有:Unicode,UTF-8,GBK,GB2312,GB18030,Big-5,ISO-8859-1(又叫Latin-1)
编码标识:
- 关于Unicode: 用Unicode编码后的“中国”,其编码的前面有FE,FF两个额外的字节,这两个字节称为BOM(Byte Order Mark)。“中”这个汉字,它的Unicode编码是4E,2D,那么在传输的过程中,是把4E放在前面,还是把2D放在前面呢?这有BOM来决定,如果BOm是FEFF(称为Big Endian),表示4E在前面,如果BOM是FFFE(称为Little Endian),表示2D在前。也就是,如果你的文件编码是Unicode(也可以叫做UTF-16),那么文件开头的字节就是FEFF(以这种方式开头的编码叫UTF-16BE)或FEFF(以这种方式开头的叫UTF-16LE)。UTF-16BE、UTF-16、Unicode是一样的。
- 关于UTF-8: UTF-8编码的文件,其文件也有一段标识:EF BB BF
- 其他编码:其他编码的文件。其文件头没有什么标识,关于ISO-8859-1对于“中国”的编码是3F,3F,两个相同,是应为它的字符集中根本就没有“中国”这两个字,所以用3F代替。
Java中的编码和解码问题:
- JAVA可以把字符存储在内存中(即也是以01101110的形式存储在内存中)。Java在内存中存储的编码格式是Unicode。不过Java的class文件是以UTF-8的方式来编码的。Java虚拟机读取class文件后,通过UTF-8编码把文件读入内存,再转换为UTF-16编码.因此,如果语句是new String(byte[], “GB18030”),就是把字节流(以GB18030编码的)转换为Unicode编码的字节流存入内存中。
- 如果想把一个字节流转换为字符流,就需要知道该字节流是以什么方式来编码的,然后根据他的编码方式来解码就可以了。 开源工具:chardet,可以用来猜测某一段字节流是用什么编码的。
- 如果我们拿到的一个字符串,输出时发现是一串乱码,那么是否可以通过某种技术手段来解决这个乱码问题呢?答案是:不一定。
①因为,首先该字符串一定是先根据某个字符集将一个字节流进行解码而得到的。
②那么如果它是按照ISO-8859-1字符集对字节流进行解码而得到的字符串,恭喜你,你可以通过某种手段,把手中的乱码重新转换为正确的字符串。方法就是:先getBytes(“ISO-8859-1”),得到一个字节流,再用new String(Byte[], “正确的字符集”)转换为正确的字符串即可。
③如果它不是按照ISO-8859-1 字符集来解码的,那很大可能就不能再转换为正确的字符串了。 - 关于编程中编码和解码的问题
几种常见的字符集编码及相互关系:
- ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)。是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统,并等同于国际标准ISO/IEC 646。占用一个Byte,用一个Byte(8 bit)的低7位表示,共128个。其中33为空制字符,95个为可打印字符。
- ISO-8859-1编码是单字节编码,向下兼容ASCII,是ASCII的扩展,共256个。Latin1是ISO-8859-1的别名,有些环境下写作Latin-1。ISO-8859-1与ASCII的兼容关系如下:
- GB2312收录简化汉字及符号、字母、日文假名等共7445个图形字符,其中汉字占6763个。GB2312规定“对任意一个图形字符都采用两个字节表示.
- GBK 向下与 GB 2312 编码兼容,向上支持 ISO 10646.1国际标准,是前者向后者过渡过程中的一个承上启下的产物。 GBK与GB2312、ASCII、BIG5(港台地区使用的繁体字字符集)的关系如下:
- Unicode(中文:万国码、国际码、统一码、单一码)是计算机科学领域里的一项业界标准。它对世界上大部分的文字系统进行了整理、编码,使得电脑可以用更为简单的方式来呈现和处理文字。
- 几种常见的字符集编码及相互关系
为什么会出现乱码?
- 乱码也就是英文常说的mojibake(由日语的文字化け音译)。
- 简单的说乱码的出现是因为:编码和解码时用了不同或者不兼容的字符集。
- 对应到真实生活中:就好比是一个英国人为了表示祝福在纸上写了bless(编码过程)。而一个法国人拿到了这张纸,由于在法语中bless表示受伤的意思,所以认为他想表达的是受伤(解码过程)。这个就是一个现实生活中的乱码情况。
- 在计算机科学中一样:一个用UTF-8编码后的字符,用GBK去解码。由于两个字符集的字库表不一样,同一个汉字在两个字符表的位置也不同,最终就会出现乱码。
- 如何识别乱码的本来想要表达的文字?
①假设我们在页面上看到“寰堝睂”这样的乱码,而又得知我们的浏览器当前使用GBK编码。那么第一步我们就能先通过GBK把乱码编码成二进制表达式。
②现在我们得到了解码后的二进制字符串E5BE88E5B18C。然后我们将它按字节拆开。
③然后套用之前UTF-8编码介绍章节中总结出的规律,就不难发现这6个字节的数据符合UTF-8编码规则。如果整个数据流都符合这个规则的话,我们就能大胆假设乱码之前的编码字符集是UTF-8。
④然后我们就能拿着 E5BE88E5B18C 用UTF-8解码,查看乱码前的文字了。
Java中的Base64:
- 标准的Base64并不适合直接放在URL里传输,因为URL编码器会把标准Base64中的“/”和“+”字符变为形如“%XX”的形式,而这些“%”号在存入数据库时还需要再进行转换,因为ANSI SQL中已将“%”号用作通配符。
- 为解决此问题,可采用一种用于URL的改进Base64编码,它不在末尾填充’='号,并将标准Base64中的“+”和“/”分别改成了“*”和“-”,这样就免去了在URL编解码和数据库存储时所要作的转换,避免了编码信息长度在此过程中的增加,并统一了数据库、表单等处对象标识符的格式。
- 另有一种用于正则表达式的改进Base64变种,它将“+”和“/”改成了“!”和“-”,因为“+”,“*”以及前面在IRCu中用到的“[”和“]”在正则表达式中都可能具有特殊含义。此外还有一些变种,它们将“+/”改为“-”或“.”(用作编程语言中的标识符名称)或“.-”(用于XML中的Nmtoken)甚至“_:”(用于XML中的Name)。
Base64类
为什么使用Base64?
- 出于种种原因,我们为了适应调试方便、简单直观、兼容性、速度效率、大小等就会对原本内存中的数据进行转换,把好端端的内存文件转成其他形式(当然不转换就是内存映像)。
- 比如为了适应http传输我们把本来不是用文本编码的数据转编码成文本格式,用的时候再解码,这个就是base64存在的意义。
- 当然单纯文本的格式就有很多,也就是各种乱码的根源,哎!文本在网络传输或是程序解析的时候,有的程序或是网元会自己过滤(特指老的路由设备),你这个字符不应该出现在文本格式里面的呀。把你给删了或是干脆扔了,再或是就直接崩溃了。
- 这个世界上其实最通用的,也是大多数程序能接受,不会乱来的文本就是【a-z】【0-9】【少量的符号】。所以我们为了兼容考虑还是转化成这几种靠谱,base64就做了这个。
HTTP文本协议简述:
- http是基于tcp的一种上层实现
- 底层一定是二进制的, 网线和光缆都只能传输脉冲二进制啊。
- 按照官方资料,http传输的是超级文本(所有WWW文件/网络资源在这里应该都是属于超级文本了),而这些文件本身就是二进制,一个img图片、一个Js文件、一个mp3文件都是二进制形式存在的啊,只不过通过编辑器看到的“文本”是把这个二进制解释成高级“文本”来展现罢了,就算用记事本打开一张图片,依然可以看到一堆文本啊,这不过图片的二进制和记事本(编辑器)的解释器不匹配,所以看起来是乱码;但是这些都是抽象出来的,并不是说我们在浏览器看到的res就是http收到的数据,只能说这是经过浏览器处理解析后的可视化数据,本质上通过http传输的,或者说通过tcp,或者说通过光缆/无线电波传输的信息都是二进制的形式,具体在哪一层如何界定,这个真不容易量化和界定。
- 所以:此文本非彼“文本”,超文本是啥,就是二进制文件在http协议中的存在形式,或者叫编码更合适。
为什么Http使用文本协议?
- html主要是脚本语言,所以适合用文本协议,而不是二进制协议,二进制协议可读性差,调试困难;
- 当然二进制的优点也很明显,就是效率高,作为协议,开销要比文本小得多,但是脚本作为解释型语言的优点就是修改方便啊,至于执行性能就交给浏览器了,虽然不如二进制,但是开发效率高啊;
- 传输效率方面,文本也要低很多,不过一般大家都能接受,而且网速在不断提高 ,这东西一旦形成标准了,也就没法再更改了;
- 标准不定一是效率最高的,比如键盘的字母布局,当前使用的字母布局打字效率其实不是最优,有人曾经统计过和种字母在单词中出现的频率,再给26个字母重新布局分配位置,打字效率可以提高30%,但是因为大家用当前的键盘习惯了,也就不再愿意重新熟悉一个新的键盘布局了,所以当前的键盘还是延用了老的键盘设计作为标准;
MIME简述:
- Multipurpose Internet Mail Extensions-多用途互联网邮件扩展
- MIME是一种保证非ASCII码文件在internet上传播的规格。原本是用于邮内件系统传送除了容ASCII就是纯文本文件的内容外,可以传送图片等其他格式使用的。后来,浏览器也支持这种规范,所以除了HTML等文本格式外,可以有很多其他格式。
- MIME已经预定义了许多种文件格式,包括大部分的图象格式jpg,gif,png等等,由于MIME本身是允许被扩展的,这样更多的公司都为自己的产品所使用的格式注册了MIME类型,比如Adobe的pdf和ps等等。最后,MIME针对安全加密信息的规范是 S/MIME。
- MIME规范受 IETF (http://www.ietf.org/) 负责。
- http/0.9是不支持非文本的,1.0之后才支持的,因为其增加了MIME。
MIME编码方式简介:
- Base64编码
①Base64是一种通用的方法,其原理很简单,就是把三个Byte的数据用4个Byte表示。在这四个Byte中,实际用到的都只有前面6bit,这样就不存在只能传输7bit的字符的问题了。Base64的缩写一般是“B”。
②Base64将输入的字符串或一段数据编码成只含有{‘A’-‘Z’, ‘a’-‘z’, ‘0’-‘9’, ‘+’, ‘/’}这64个字符的串,'=‘用于填充。
③其编码的方法是,将输入数据流每次取6bit,用此6bit的值(0-63)作为索引去查表,输出相应字符,这样,每3个字节将编码为4个字符(3×8 → 4×6);不满4个字符的以’='填充。
④有的场合,以“=?charset?B?xxxxxxxx?=”表示xxxxxxxx是Base64编码,且原文的字符集是charset。在段体内则直接编码,适当时机换行,MIME建议每行最多76个字符。
⑤Base64的算法很简单,它将字符流顺序放入一个24位的缓冲区,缺字符的地方补零,然后将缓冲区截断成为4个部分,高位在先,每个部分6位,用64个字符重新表示。如果输入只有一个或两个字节,那么输出将用等号“=”补足。这可以隔断附加的信息造成编码的混乱。 - QP编码
①另一种方法是QP(Quote-Printable) 方法,通常缩写为“Q”方法,其原理是把一个8bit的字符用两个16进制数值表示,然后在前面加“=”。所以我们看到经过QP编码后的文件通常是这个样子:=B3=C2=BF=A1=C7=E5=A3= AC=C4=FA=BA=C3=A3=A1。
②Quoted -printable根据输入的字符串或字节范围进行编码,若是不需编码的字符,直接输出。若需要编码,则先输出’=‘,后面跟着以2个字符表示的十六进制字节值。
③有的场合,以“=?charset?Q?xxxxxxxx?=”表示xxxxxxxx是Quoted-printable编码,且原文的字符集是charset。在段体内则直接编码,适当时机换行,换行前额外输出一个’='。
Base64注意:
- Base64是一种数据编码方式,目的是让数据符合传输协议的要求。标准Base64编码解码无需额外信息即完全可逆,即使你自己自定义字符集设计一种类Base64的编码方式用于数据加密,在多数场景下也较容易破解。
- 对于数据加密应该使用专门的目前还没有有效方式快速破解的加密算法。比如:对称加密算法AES-128-CBC,对称加密需要密钥,只要密钥没有泄露,通常难以破解;也可以使用非对称加密算法,如RSA,利用极大整数因数分解的计算量极大这一特点,使得使用公钥加密的数据,只有使用私钥才能快速解密。
- 对于数据校验,也应该使用专门的消息认证码生成算法,如 HMAC -一种使用单向散列函数构造消息认证码的方法,其过程是不可逆的、唯一确定的,并且使用密钥来生成认证码,其目的是防止数据在传输过程中被篡改或伪造。将原始数据与认证码一起传输,数据接收端将原始数据使用相同密钥和相同算法再次生成认证码,与原有认证码进行比对,校验数据的合法性。
- Base64编码原理与应用
文本文件和二进制文件
案例:
String b = "100000";
int a = 100000;
-
a变量占6字节,b变量占4个字节。
-
将a保存到ASCII文件:ASCII文件中表示a时,也是“看起来”的样子,而不是n在内存里的实际表示形式。
-
将a保存到二进制文件:是用对二进制文件写入的方式,将a输出到文件b.dat中。
-
由此可以看出二进制文件和ASCII文件的区别:前者,用和内存中一样的方式保存数据;而后者,用和OUT显示一样的方式保存,存的是人“看起来”的那个样子。
简述:
- 从存储方式来说,文件在磁盘上的存储方式都是二进制形式,所以,文本文件其实也应该算二进制文件。先从他们的区别来说,虽然都是二进制文件,但是二进制代表的意思不一样。打个比方,一个人,我们可以叫他的大名,可以叫他的小名,但其实都是代表这个人。二进制读写是将内存里面的数据直接读写入文本中,而文本呢,则是将数据先转换成了字符串,再写入到文本中。
- 我们说文本文件是特殊的二进制文件,是因为文本文件实际上的解释格式已经确定了:ASCII或者unicode编码。文本文件的一个缺点是,它的熵往往较低,也就是说,其实本可以用更小的存储空间记录这些信息。比如,文本文件中的一个数字65536,需要用5个字节来存储;但是用二进制格式,采用int存储,仅仅需要2个字节。而二进制文件elf和bmp等,都往往有一个head,告诉你文件信息和解释方式。
- 记事本支持文本文件而不支持二进制文件,所以如果你用记事本打开文本文件那么一切正常,如果打开的是二进制文件就会出现乱码。但也有不乱码的地方,你会注意到那些地方都是字符编码的,而对于int、double等类型所对应的值都是乱码的,这是由于记事本只能够识别字符类型,而无法识别其他类型。
- 字符数据本身在内存中就经过了编码,所以无论是二进制还是文本形式都是一样的,而对于非字符数据来说,例如inti=10;如果用二进制来进行存储的话为1010,但是如果需要用文本形式来进行存储的话就必须进行格式化编码(对1和0分别编码,即形式为‘1’和‘0’分别对应的码值)。
如何判断文件类型:
- 任何文件都存储的是二进制数据,只是解析的时候会调用不同的程序。计算机系统一般可以通过“魔数”来判断文件类型,进而进行解析。
- 一般这个“魔数位于文件开头”。
- 除了魔数剩下的就是真实有用的二进制数据了。
总结:
- 二进制文件和文本文件简述
- 形式:
①二进制文件是把内存中的数据按其在内存中的存储形式原样输出到磁盘上存放,也就是说存放的是数据的原形式。
②文本文件是把数据的终端形式的二进制数据输出到磁盘上存放,也就是说存放的是数据的终端形式。 - 编码:
①文本文件是基于字符编码的文件,常见的编码有ASCII编码,UNICODE编码等等。
②二进制文件是基于二进制编码的文件,你可以根据具体应用,指定某个值是什么意思。 - 结论:文本文件之所以和其他二进制文件分开是因为所表示的数值如8,9,10不同于二进制编码的格式。而图像音频视频中所表达的数值如8,9,10还是按照二进制编码的格式。
常见编码:
- 文本可以看看unicode,音频就aac,视频就h.264。
- 简单一点的文本就ASCII,音频就wav,视频avi。
编码方式和文件类型的区别:
- 编码方式则是指容器格式中数据的压缩编码方式,例如Mpeg-4,H.264,H.263,等等。而数据采用了何种编码方式是无法单单从文件格式的后缀上看出来的。就是说你无法从一个盖着盖子的便当盒外面看出里面装了什么配菜。
- 文件类型一般情况下从文件的后缀名就能看出来,比如AVI,Mp4,3gp,mov,rmvb等等。这些格式又叫做容器格式(container format),顾名思义就是用来装东西的,你可以把它想象成为一个便当盒,或者野餐篮(兄弟,你没吃早饭吧)。
- 例如,Mpeg-4是视频编码方式,而Mp4是容器格式,两者本来就不是一个范畴里的东西。
为什么要使用二进制文件:
- 第一是二进制文件比较节约空间,这两者储存字符型数据时并没有差别。但是在储存数字,特别是实型数字时,二进制更节省空间,比如储存 Real*4的数据:3.1415927,文本文件需要 9 个字节,分别储存:3 . 1 4 1 5 9 2 7 这 9 个 ASCII值,而二进制文件只需要 4 个字节(DB 0F 49 40)。
- 第二个原因是,内存中参加计算的数据都是用二进制无格式储存起来的,因此,使用二进制储存到文件就更快捷。如果储存为文本文件,则需要一个转换的过程。在数据量很大的时候,两者就会有明显的速度差别了。
- 第三,就是一些比较精确的数据,使用二进制储存不会造成有效位的丢失。
java.security MessageDigest类
MessageDigest类:
-
java 1.6api介绍:此类为应用程序提供信息摘要功能,如:MD5/SHA等.信息摘要是简单的单向哈希函数,它接收任意长度的数据,并返回固定长度的哈希值
-
获得对象:一般通过getInstance("算法名称")方法获得
-
常用方法:
通过update()方法处理数据,任何时候都可以通过reset()方法重置摘要,一旦所有更新数据都更新完了,应该调用digest()方法完成哈希计算,对于定量的数据计算,digest()方法只能被调用一次,MessageDigest对象恢复到初始状态
-
其他方法:
clone();如果实现是可复制的,则返回一个副本
digest();通过执行诸如填充之类的操作完成哈希计算
digest(byte[] input)通过指定的数组完成最后更新操作,并计算哈希
digest(byte[] buf, int offset, int len)通过指定数组,并指定开始位置(偏移量),和数字长度,来进行最后更新,并计算哈希
getAlgorithm();返回指定的算法名称
getDigestLength()返回以字节为单位的摘要长度,如果实现不支持,则返回0
getInstance(String algorithm)返回指定算法的MessageDigest对象
getInstance(String algorithm, Provider provider)通过指定算法提供者和算法名称返回MessageDigest对象
getInstance(String algorithm, String provider)通过指定算法提供者和算法名称返回MessageDigest对象
getProvider();返回此信息摘要对象的提供者
isEquals();比较两个信息摘要对象的相等性
reset();重置摘要以供再次使用
toString();返回此信息摘要对象的字符串表示形式
update(byte input);通过指定的字节更新摘要
update(byte[] input)通过指定字节数组更新摘要
update(byte[] input, int offset, int len)通过指定字节数组从指定偏移量开始更新摘要
update(ByteBuffer input)通过指定ByteBuffer更新摘要
- 支持的算法:
MD2
MD5
SHA-1
SHA-256
SHA-384
SHA-512
- 特征:
①在计算上,查找两个哈希值为相同值的消息是不可行的。
②文摘不应该揭示用于生成它的输入的任何信息。
java的awt和swing包
简介:
Java中awt和swing的关系和区别:
- 概述:
①awt是抽象组件窗口工具包,是Java最早的用于编写图形应用程序的开发包。
②Swing是为了补充awt的一些功能性的缺失问题而开发的包,以awt为基础的。 软件包 java.awt 的描述:
①包含用于创建用户界面和绘制图形图像的所有类。在 AWT 术语中,诸如按钮或滚动条之类的用户界面对象称为组件。Component 类是所有 AWT 组件的根。有关所有 AWT 组件的公共属性的详细描述,请参见 Component。
②当用户与组件交互时,一些组件会激发事件。AWTEvent 类及其子类用于表示 AWT 组件能够激发的事件。有关 AWT 事件模型的描述,请参见 AWTEvent。
③容器是一个可以包含组件和其他容器的组件。容器还可以具有布局管理器,用来控制容器中组件的可视化布局。AWT 包带有几个布局管理器类和一个接口,此接口可用于构建自己的布局管理器。
④由于AWT 是依靠本地方法来实现其功能的,我们通常把AWT控件称为重量级控件。软件包 javax.swing的描述:
①提供一组“轻量级”(全部是 Java 语言)组件,尽量让这些组件在所有平台上的工作方式都相同。
- 总结:
①由于实现的不同,awt是机遇本地方法的C/C++程序,运行速度比较快,消耗资源少;
②Swing是基于awt的Java程序,所以运行速度慢。
③对于嵌入式应用,往往采用AWT;通常在标准的Java应用中,使用Swing牺牲运行速度换取开发效率和功能。
java的script包
script包:
java中的javax.script,它开始存在于JDK1.6,它可以解析通用的表达式,如三目,还可以利用js函数语法,创造一个就像java的函数一样存在于内存中随时可以被调用的函数,更可以将js中的对象直接转换成java对象。
- script包最主要的几个类和接口为:ScriptEngineManager,ScriptEngine,CompiledScript和Bindings。
①ScriptEngineManager:是一个工厂的集合
,可以通过name或者tag的方式获取某一个脚本的工厂,并且生成一个脚本的ScriptEngine.
②ScriptEngine:是一个脚本引擎
,包含一些操作方法,eval,createBindings,setBindings
③CompliedScript: engine 实现该接口,可以将ScriptEngine解析一段脚本的结果存起来
,方便多次调用,需要将engine向上转换
④Bindings:用来存放数据的容器,
它有3个层级,为Global级、Engine级和Local级,前2者通过ScriptEngine.getBindings()获得,是唯一的对象,而Local Binding由ScriptEngine.createBindings()获得,很好理解,每次都产生一个新的。Global对应到工厂,Engine对应到ScriptEngine,向这2者里面加入任何数据或者编译后的脚本执行对象,在每一份新生成的Local Binding里面都会存在。
//获取js引擎
ScriptEngine engine=new ScriptEngineManager().getEngineByName("JavaScript");
//js引擎执行eval方法
//option 可以是一段js代码,函数,函数传参需要调用 engine.createBindings获得
//bindings,bindings.put(key,value)来传入参数
engine.eval(option); //option:"10+((D-parseInt(D/28)*28)/7+1)*10";
//保存结果
Compilable compilable=(Compilable) engine;
CompiledScript JSFunction=compilable.compile(option); //解析编译脚本函数
Bindings bindings=engine.createBindings();
bindings.put(key,value);
JSFunction.eval(bingdings);
常见对象(BigInteger)
BigInteger,为什么要说这个?
- 我们从他字面意思就知道Big(大),Integer(int),大的Int类型
- 这就说明是Integer的升级版,那Integer表示的数有多大呢
class test{
public static void main(String[] args){
System.out.println(Integer.MAX_VALUE);
//输出结果:2147483647
//这个就是Integer所能表示的最大数据
//如果输出的数超过这个值会怎么样?
Integer i = new Integer(2147483647);
System.out.println(i);
//输出结果为:2147483647
Integer ii = new Integer(2147483648);
System.out.println(ii);
//这个就会报错,显示NumberFormatException
}
}
- 所以,Integer还是不够大,因此就需要更大的BigInteger来进行运算数据
BigInteger:可以让超过Integer范围的数据进行运算:
- 构造方法:
BigInteger(byte[] val)
将包含 BigInteger 的二进制补码表示形式的 byte 数组转换为BigInteger。
BigInteger(int signum, byte[] magnitude)
将 BigInteger 的符号-数量表示形式转换为 BigInteger。
BigInteger(int bitLength, int certainty, Random rnd)
构造一个随机生成的正 BigInteger,它可能是一个具有指定 bitLength 的素数。
BigInteger(int numBits, Random rnd)
构造一个随机生成的 BigInteger,它是在 0 到 (2numBits - 1)(包括)范围内均匀分布的值。
BigInteger(String val)
将 BigInteger 的十进制字符串表示形式转换为 BigInteger。
BigInteger(String val, int radix)
将指定基数的 BigInteger 的字符串表示形式转换为 BigInteger。
- 其中重要的就是:
BigInteger(String val)
将 BigInteger 的十进制字符串表示形式转换为 BigInteger。
import java.math.BigInteger;
class test{
public static void main(String[] args){
BigInteger bi = new BigInteger("2147483648");
System.out.println("bi:"+bi);
//如果打印的是地址值,就证明没有重写,如果不是就说明重写了构造方法
//输出结果为:bi:2147483648
//证明重写了
}
}
BigInteger的加,减,乘,除方法:
- public BigInteger add(BigInteger val):加
- public BigInteger subtract(BigInteger val):减
- public BigInteger multiply(BigInteger val):乘
- public BigInteger divide(BigInteger val):除
- public BigInteger[] divideAndRemainder(BigInteger val):返回商和余数的数组
import java.util.BigInteger;
class test{
public static void main(String[] args){
BigInteger bi1 = new BigInteger("10");
BigInteger bi2 = new BigInteger("5");
//public BigInteger add(BigInteger val)
//返回其值为 (this + val) 的 BigInteger。
//加法
System.out.println("add:"+bi1.add(bi2));
//输出结果为:add:15
//public BigInteger subtract(BigInteger val):减
//返回其值为 (this - val) 的 BigInteger
//减法
System.out.println("subtract:"+bi1.subtract(bi2));
//输出结果为:subtract:5
// public BigInteger multiply(BigInteger val):乘
//返回其值为 (this * val) 的 BigInteger
//乘法
System.out.println("multiply:"+bi1.multiply(bi2));
//输出结果为:multiply:50
//public BigInteger divide(BigInteger val):除
//返回其值为 (this / val) 的 BigInteger
//除法
System.out.println("divide:"+bi1.divide(bi2));
//输出结果为:divide:2
//public BigInteger[] divideAndRemainder(BigInteger val):
//返回商和余数的数组,返回的是数组,所以要找个数组接收
//返回包含 (this / val) 后跟 (this % val) 的两个 BigInteger 的数组
//两个 BigInteger 的数组:商 (this / val) 是初始元素,余数 (this % val) 是最终元素。
BigInteger[] big = bi1.divideAndRemainder(bi2);
System.out.println("商:"+big[0]);
System.out.println("余数:"+big[1]);
//第一个输出结果为:商:2
//第二个输出结果为:余数:0
}
}