详尽笔记,用于复习和速查
将包含基础、进阶、高阶
目前更新到数据结构-JCF-Set
概述
Java SE(Standard Edition) 面向PC级应用开发
Java EE(Enterprise Edition) 面向企业级应用开发
Java ME(Micro Edition) 面向嵌入式应用开发
环境搭建
JDK下载
搜索java archive,选择版本下载。(本文选择JDK1.8)
安装JDK时,会同时安装JRE。
配置环境变量
新增
JAVA_HOME
C:\Java\jdk1.8.0_73
(jdk地址)
修改Path
新增%JAVA_HOME%\bin
上移到最高
打开cmd
java -version
有版本号输出
javac
有用法输出
即可。
配置Eclipse
修改字号
Window-Preferences-General-Appaerance-Colors and Fonts-右侧Java-Java Editor Text Font
显示行号
General-Editors-Text Editors-右侧show line numbers勾上
自动保存时间间隔
General-Workspace-右侧Workspace save interval(in minutes)(默认5分钟)
下方可以修改文本编码格式
复原视窗
Window-Perspective-Reset Perspective…
Eclipse使用教程
Java从编写到运行
编写:利用记事本/vi/IDE等完成代码文件(.java)编写
编译:利用JDK中javac.exe将代码(.java)编译成字节码文件(.class)
运行:java.exe读入并解释字节码文件(.class),最终在JVM上运行
编程标准
类名首字母大写,后面单词驼峰命名
方法名和变量名首字母小写,后面单词驼峰命名
阿里巴巴编程标准
基础知识
class类
java文件必须以.java作为扩展名
一个java文件只能有一个public class
public class的名字必须和文件名字一样,大小写都要完全一致
一个文件可有多个class,但是只能有一个是public。不提倡一个文件里面放多个类(内部类除外)
System.out.print 输出
System.out.println 换行输出
类是Java中最基础逻辑单位
Java所有内容都需放在类的范围中
类的构成
成员变量/属性
成员方法/函数
main函数
一个class最多只能有一个main函数**(经指正,一个类可以有多个main函数-通过重载,但只能有一个入口函数)**
类可以没有main函数,没有main函数的类不能主动执行,但可以被动执行(被调用执行)
程序入口都是main函数
main函数的形参和前缀修饰符public、static、void等都不能省略,是固定写法
注意区别
1
2
3
4
5
6
7
8
public static void main ( String [] args )
{
//PSVM,main函数
}
public void main ()
{
//普通main函数,不是入口函数
}
Copy
严格意义上说,main函数不属于这个类的所拥有函数。
只是因为Java要求所有内容都必须放置在class范围内,所有main函数“寄居”在某一个class中。
main函数无法被其它方法/类所调用。
一个Java程序可调用多个其它Java class。
String[] args是main函数的形参,即在main函数中可使用args的值(这些值在main函数启动时输入)。
右键test.java,Run As->Run Configuration-右侧Arguments-输入Program arguments程序参数-Run
多个变量需用空格隔开
八种基本类型
boolean 布尔
true false(默认)
byte 字节
1 byte = 8 bits
存储有符号的,以二进制补码表示的整数
最小值-128,最大值127,默认值0
该类型用在大型数组中可显著节约空间(占用空间只用int类型的四分之一),主要代替小整数
在二进制文件读写中使用较多
1
2
3
4
byte a = ( byte ) - 129 ;
System . out . println ( a ); //127
byte b = ( byte ) 128 ;
System . out . println ( b ); //-128
Copy 怎么理解:
标准值:-128127
两边可以延伸
左延伸-384(-128)-129(127)
右延伸128(-128)~383(127)
short/int/long 短整数/整数/长整数
short 16位 2个字节 -3276832767,-2^152^15-1,默认值0
int 32位,4个字节 -21474836482147483647,-2^312^31-1,默认值0
long 64位 8个字节 -92233720368547758089223372036854775807,-2^632^63-1,默认值0L
float/double 浮点数
float 单精度 32位 4个字节 1.410^-45~3.4 10^38 默认值0.0f
double 双精度 64位 8个字节 4.910^-324~1.7 10^308 默认值0.0d
float和double都不能用来表示很精确的数字
char 字符
16位 Unicode字符
最小值是 \u0000
(即为0)
最大值是\uffff
(即为65535)
(\u4e00
~\u9fa5
两万多汉字)
运算符
>>
右移 除以2
<<
左移 乘以2
自定义函数
重载(overload):同一个类中,函数名称可以相同,但函数参数的个数或者类型必须有所不同
不能以返回值来区分同名的函数
面向对象
对象=属性+方法
对象的规范=属性定义+方法定义
obj可看作是内存中一个对象(包含若干个数据)的句柄
在C/C++中,obj称为指针,在Java中称为Reference
对象赋值是Reference赋值,基本类型是直接值拷贝
理解:基本类型的变量值小,可直接拷贝;对象包含多个值,不容易复制,赋值采用共享同一块内存区域。
函数内的局部变量,编译器不会给默认值,需初始化;
类的成员变量,编译器会给默认值,可直接使用。
构造函数
构造函数名称必须和类名一样,且没有返回值
public void A(int x)不是构造函数,而是普通函数。
Java有构造函数,但没有析构函数
每个变量都有生命周期,它只能存储在离它最近的一对{}中**(经指正,此条不够严谨)**
Java具有内存自动回收机制,当变量退出其生命周期后,JVM会自动回收所分配的对象的内存。
对象回收效率依赖于垃圾回收器GC(Garbage Collector),其回收算法关系到性能好坏,是JVM研究热点。
每个Java类都必须有构造函数
若没有显式定义构造函数,Java编译器自动为该类产生一个空的无形参构造函数。若有显式构造函数,编译器就不会再产生构造函数
每个子类的构造函数的第一句话,都默认调用父类的无参数构造函数super(),除非子类的构造函数第一句话是super,而且super语句必须放在第一条
一个类可有多个构造函数,只要形参列表不同
多个class可写在一个.java文件中,但最多只有一个类是public class,并且public class类的名字必须和.java文件名相同。
信息隐藏原则
类的成员属性,是私有的private
类的方法,是共有的public,通过方法修改成员属性的值
get和set方法是公有public的,统称为getter和setter
外界对类成员的操作只能通过get和set方法
可用Java IDE快速生成
Source-Generate Getters and Setters…
this
1
2
3
4
5
6
7
8
9
10
11
12
public class Test {
private int id ;
public Test ( int id ){
//在这个构造函数里,形参优先级更高
this . id = id ;
}
public int getId (){
return id ;
}
}
Copy
1
this . add ( 1 , 2 ); //调用本类的add方法,this可忽略
Copy
1
this ( 5 ); //调用本类的一个形参的构造函数
Copy 继承、接口和抽象类
继承
父类/基类/超类
Parent class/Base class/Super class
子类/派生类
Child class/Derived class
子类继承父类所有的属性和方法(但不能直接访问private成员)
根据信息隐藏原则:子类会继承父类所有的方法,可直接使用
子类也会继承父类的父类所有的属性和方法(但不能直接访问private成员)
子类可以通过调用父类的方法来访问父类的私有的成员属性
在同样方法名和参数情况下,本类的方法会比父类的方法优先级高
区别于C++,单根继承
单根继承原则:每个类都只能继承一个类
若不写extends,Java类默认继承java.lang.Object类
Java所有类从java.lang.Object开始,构造出一个类型继承树
Object类里面默认就有clone, equals, finalize, getClass, hashCode, toString等方法
每个子类的构造函数的第一句话,都默认调用父类的无参数构造函数super(),除非子类的构造函数第一句话是super,而且super语句必须放在第一条
如果构造函数的第一句话不是super,编译器会自动增加一句super();。如果构造函数第一句是自己写的super语句,编译器就不会自动添加。
抽象类
若方法只有方法名字,形参列表,没有方法体,那所在的类就被定义为抽象类。
若一个类暂时有方法未实现,需被定义为抽象类。
一个类继承于抽象类,就不能继承于其他的(抽象)类
子类可继承于抽象类,但一定要实现父类们所有abstract的方法,若不能完全实现,子类也必须被定义为抽象类
接口
如果类的所有方法都没有实现,这个类就算是接口interface
1
2
3
4
public interface Animal {
public void eat ();
public void move ();
}
Copy
类只可以继承(extends)一个类,但可实现(implements)多个接口,继承和实现可以同时
接口不算类,或者说是特殊的类
接口可以继承(多个)接口,没有实现的方法将会叠加
类实现接口,就必须实现所有未实现的方法。若没有全部实现,只能成为一个抽象类
接口里可定义变量,但一般是常量 (经指正,成员变量只能是常量)
总结
抽象类和接口相同点:两者都不能被实例化,不能new操作
不同点:
抽象类abstract,接口interface
抽象类可有部分方法实现,接口所有方法不能有实现 (经指正,Java8后,接口可有默认实现)
一个类只能继承(extends)一个(抽象)类,实现(implenments)多个接口
接口可继承(extends)多个接口
抽象类有构造函数,接口没有构造函数
抽象类可有main,也能运行,接口没有main函数
抽象类方法可有private/protected,接口方法都是public
类转型
类型可相互转型,但只限制于有继承关系的类
子类可转换成父类(从大到小,向上转型),而父类不可转为子类(从小变大,向下转型)
父类转为子类有一种情况例外:这个父类本身就是从子类转化而来
1
2
Human obj1 = new Man (); //OK, Man extends Human
Man obj2 = ( Man ) obj1 ; //OK, because obj1 is born from Man class
Copy 多态
类型转换带来的作用就是多态
子类继承父类的所有方法,但子类可重新定义一个名字,参数和父类样的方法,这种行为是重写 (覆写,覆盖,overwrite/override,not overload(重载))
子类方法优先级高于父类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Man extends Human {
public void eat (){
System . out . println ( "I can eat more" );
}
public void plough () { }
public static void main ( String [] a ){
Man obj1 = new Man ();
obj1 . eat (); //call Man.eat()
Human obj2 = ( Human ) obj1 ;
obj2 . eat (); //call Man.eat()
Man obj3 = ( Man ) obj2 ;
obj3 . eat (); //call Man.eat()
}
}
Copy 契约设计:类不会直接使用另外一个类,而是采用接口的形式,外部可以“空投”这个接口下的任意子类对象
static、final和常量设计
static
static关键字可作用在:
变量
static变量只依赖于类存在(通过类即可访问),不依赖于对象实例存在。
所有对象实例,关于同一个变量的值都共享存储在一个共同的空间(栈)。
方法
静态方法无需通过对象来引用,而通过类名可直接引用。
静态方法中只能使用静态变量,不能使用非静态变量。
静态方法禁止引用非静态方法。
类
匿名方法块
static块只在类第一次被加载时调用,在程序运行期间,代码只运行一次
执行顺序:static块 > 匿名块 > 构造函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class StaticBlock
{
static
{
System . out . println ( "static 块" );
}
{
System . out . println ( "匿名块" );
}
public StaticBlock ()
{
System . out . println ( "构造函数" );
}
{
System . out . println ( "匿名块" );
}
}
Copy 单例模式
又名单态模式,Singleton
限定某一个类在整个程序运行过程中,只能保留一个实例对象在内存空间
GoF的23中设计模式(Design Pattern)(创建型、结构型、行为型)中经典的一种,属于创建型模式类型
采用static来共享对象实例
采用private构建函数,防止外界new操作
final
final关键字用来修饰
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class FinalObject
{
int a = 10 ;
}
public class FinalObjectTest {
public static void main ( String [] args ){
final FinalObject obj1 = new FinalObject ();
System . out . println ( obj1 . a );
obj1 . a = 20 ;
System . out . println ( obj1 . a ); //正确,可以修改内部值
obj1 = new FinalObject (); //报错,不能修改指针
}
}
Copy 常量设计
Java没有constant关键字
不能修改, final
不会修改/只读/只要一份, static
方便访问public
Java中的常量
public static final
建议变量名字全大写,以连字符相连,如UPPER_BOUND
一种特殊的常量:接口内定义的变量默认是常量
常量池
Java为很多基本类型的包装类/字符串都建立常量池
常量池:相同的值只存储一份,节省内存,共享访问
基本类型的包装类
Boolean: true, false
Byte:-128127
Short, Integer, Long:-128127
Character:0~127
不包括Float, Double:没有缓存(常量池)
1
2
3
4
5
6
7
8
9
10
11
Long l1 = - 128L ;
Long l2 = - 128L ;
System . out . println ( String . valueOf ( l1 == l2 )); //true
Float f1 = 0 . 5f ;
Float f2 = 0 . 5f ;
System . out . println ( String . valueOf ( f1 == f2 )); //false
Double d1 = 0 . 5 ;
Double d2 = 0 . 5 ;
System . out . println ( String . valueOf ( d1 == d2 )); //false
Copy
Java为常量字符串都建立常量池缓存机制
基本类型的包装类和字符串有两种创建方式
常量式(字面量)复制创建,放在栈内存(将被常量化)
1
2
Integer a = 10 ;
String b = "abc" ;
Copy
new对象进行创建,放在堆内存(不会常量化)
1
2
Integer c = new Integer ( 10 );
String d = new String ( "abc" );
Copy 这两种创建方式导致创建的对象存放的位置不同
栈内存读取速度快但容量小
堆内存读取速度慢但容量大
基本类型和包装类比较,将对包装类自动拆箱
对象比较,比较地址
加法+会自动拆箱
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int i1 = 10 ;
Integer i2 = 10 ; //自动装箱
System . out . println ( i1 == i2 ); //true
//自动拆箱 基本类型和包装类进行比较,包装类自动拆箱
Integer i3 = new Integer ( 10 );
System . out . println ( i1 == i3 ); //true
//自动拆箱 基本类型和包装类进行比较,包装类自动拆箱
System . out . println ( i2 == i3 ); //false
//两个对象比较,比较其地址
//i2是常量,放在栈内存常量池中,i3是new出对象,放在堆内存中
Integer i4 = new Integer ( 5 );
Integer i5 = new Integer ( 5 );
System . out . println ( i1 == ( i4 + i5 )); //true
System . out . println ( i2 == ( i4 + i5 )); //true
System . out . println ( i3 == ( i4 + i5 )); //true
//i4+i5操作将会使得i4,i5自动拆箱为基本类型并运算得到10
//基础类型10和对象相比,将会使对象自动拆箱,做基本类型比较
Integer i6 = i4 + i5 ; //+操作使得i4,i5自动拆箱,得到10,因此i6 == i2
System . out . println ( i1 == i6 ); //true
System . out . println ( i2 == i6 ); //true
System . out . println ( i3 == i6 ); //false
Copy
常量赋值(堆内存)和new创建(栈内存)不是同一个对象
编译器只会优化确定的字符串,并缓存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
String s0 = "abcdef" ;
String s1 = "abc" ;
String s2 = "abc" ;
String s3 = new String ( "abc" );
String s4 = new String ( "abc" );
System . out . println ( s1 == s2 ); //true常量池
System . out . println ( s1 == s3 ); //false一个栈内存,一个堆内存
System . out . println ( s3 == s4 ); //false两个都是堆内存
String s5 = s1 + "def" ; //设计到变量,编译器不优化
String s6 = "abc" + "def" ; //都是常量,编译器会自动优化成abcdef
String s7 = "abc" + new String ( "def" ); //设计到new对象,编译器不优化
System . out . println ( s5 == s6 ); //false
System . out . println ( s6 == s7 ); //false
System . out . println ( s0 == s6 ); //true
String s8 = s3 + "def" ; //涉及到new对象,编译器不优化
String s9 = s4 + "def" ; //设计到new对象,编译器不优化
String s10 = s3 + new String ( "def" ); //涉及到new对象,编译器不优化
System . out . println ( s8 == s9 ); //false
System . out . println ( s8 == s10 ); //false
System . out . println ( s9 == s10 ); //false
Copy 不可变对象和字符串
不可变对象
不可变对象(Immutable Object)
一旦创建,该对象(状态/值)不能被更改
其内在的成员变量的值不能修改
如八个基本型别的包装类
String, BigInteger和BigDecimal等
可变对象(Mutable Object)
普通对象
1
2
3
4
5
String a = new String ( "abc" );
String b = a ;
System . out . println ( b ); //abc
a = "def" ;
System . out . println ( b ); //abc
Copy 不可变对象是指值对象不再修改,即abc不会被修改,而指针(句柄/变量名)a的指向可以修改。
不可变对象,也是传指针(引用)
由于不可变,临时变量指向新内存,外部实参的指针不改动
1
2
3
4
5
6
7
public static void change ( String b )
{
b = "def" ;
}
a = new String ( "abc" );
change ( a );
System . out . println ( a ); //abc
Copy a->abc
b–^
change(a)后
a->abc
b->def
字符串
不可变对象
字符串内容比较:equals方法
是否指向同一个对象:指针比较==
1
2
String a = "abc" ;
a = a + "def" ; //String不可修改,需新申请空间,效率差
Copy 使用SrringBuffer/StringBuilder类的append方法进行修改
StringBuffer/StringBuilder的对象都是可变对象
StringBuffer(同步,线程安全,修改快速),StringBuilder(不同步,线程不安全,修改更快)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public static void changeValue ( int a )
{
a = 10 ;
}
public static void changeValue ( String s1 )
{
s1 = "def" ;
}
public static void changeValue ( StringBuffer s1 )
{
s1 . append ( "def" );
}
public static void main ( String [] args )
{
int a = 5 ;
String b = "abc" ;
StringBuffer c = new StringBuffer ( "abc" );
changeValue ( a );
changeValue ( b );
changeValue ( c );
System . out . println ( a ); //5
System . out . println ( b ); //abc
System . out . println ( c ); //abcdef
}
Copy package, import和classpath
package和import
若所有Java类都是放置在同一个目录下的,类之间相互调用无需显式声明调用
同一个目录下,两个类的名字不能相同
文件过多不方便查找
Java支持多个目录放置Java,并通过package/import/classpath/jar等机制配合使用,可支持跨目录放置和调用Java类
1
2
3
4
package cn.edu.pku ;
public class PackageExample
{
}
Copy 类全称cn.edu.pku.PackageExample,短名称PackageExample
引用类时,必须采用全称引用;程序正文可用短名称
PackageExample.java必须严格放置在cn/edu/pku目录下
包名尽量唯一
域名是唯一的,因此常用域名做包名
域名逆序:cn.edu.pku,范围通常从大到小
类的完整名字:包名+类名,cn.edu.pku.PackageExample
包名:和目录层次一样,cn\edu\pku\PackageExample.java
包具体放在上面位置不重要,编译和运行时再制定
举个栗子
1
2
3
4
5
6
7
8
9
10
11
12
package cn.edu.pku ;
import cn.edu.pku.PackageExample ;
//或import cn.edu.pku.*
//但不能是import cn.*
//若PackageExample和当前类在同一个目录,可省略import
public class PackageExampleTest {
public static void main ( String [] args ){
PackageExample obj = new PackageExample ();
//此处可用类的短名称来引用
}
}
Copy “*”代表这个目录下所有文件,但不包括子文件夹和子文件夹内的文件。
import规则
import必须全部放在package之后,类定义之前
package必须是第一句话
多个import的顺序无关
可用来引入一个目录下的所有类,比如import java.lang. ;
注意:不能递归包含其下各个目录下的文件
import尽量精确,不推荐*,以免新增同名程序会使老程序报错
jar
用于可执行程序文件的传播,实际上是一组class文件的压缩包
项目引入一个jar文件,就可以使用jar文件中所有类(.class文件),无需类的源码(.java文件)。
jar只包含.class文件,没有.java文件,不会泄露源码。不过Java里的一些反编译工具,可从class反编译到Java。
利用Eclipse的Export功能导出jar文件
选中项目,点击顶部菜单File-Export-Java-Jar File
classpath
手动创建c:\temp\cn\com\test\Man.java
编译:
1
javac c : \ temp \ cn \ com \ test \ Man . java
Copy 运行:
1
java -classpath .;c:\temp cn.com.test.Man
Copy -classpath固定格式参数,简写为-cp
.;c:\temp
windows是分号,Linux/Mac是冒号
当在某一个子路径找到所需类后,后续子路径不再寻找
在classpath中,子路径排在前面优先级高
当所有子路径都寻找不到所需类,系统会报告NoClassDefFoundException错误
编译和运行规则
编译一个类,需java文件全路径,包括拓展名
运行一个类,需写类名全称(非文件路径),无需写扩展名
编译类时,需给出这个类所依赖的类(包括依赖的类再次依赖的所有其他类)的所在路径
运行类时,需给出这个类,以及被依赖类的路径总和
classpath参数也可以包含jar包。若路径内有空格,请将classpath参数整体加双引号。
1
java -classpath ".;c:\test.jar;c:\temp;c:\a bc" cn.com.test.Man
Copy Java访问权限
private:私有,只能本类访问
default(通常忽略不写):同一个包内访问
protected: 同一个包,子类均可以访问
public:公开,所有类都可访问
四种都可用来修饰成员变量、成员方法、构造函数
default和public可修饰类
1
2
class A { } //default class
public class B { } //public class
Copy 权限表
同一个类 同一个包 不同包的子类 不同包的非子类
private √
default √ √
protected √ √ √
public √ √ √ √
Java常用类
Java类库文档
https://docs.oracle.com/en/
https://docs.oracle.com/en/java/javase/13/docs/api/index.html
这些文档原先是程序中的注释。利用JavaDoc技术,将这些注释抽取出来,组织形成的以HTML为表现形式的API文档。
数字类
Java数字类
整数Short, Int, Long
浮点数Float, Double
大数类BigInteger(大整数), BigDecimal(大浮点数)
大数类没有限制,可表示无穷大的数字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
BigInteger b1 = new BigInteger ( "123456789" );
BigInteger b2 = new BigInteger ( "987654321" );
System . out . println ( b2 . add ( b1 )); //加法操作
System . out . println ( b2 . subtract ( b1 )); //减法操作
System . out . println ( b2 . multiply ( b1 )); //乘法操作
System . out . println ( b2 . divide ( b1 )); //除法操作
System . out . println ( b2 . max ( b1 )); //求出最大数
System . out . println ( b2 . min ( b1 )); //求出最小数
BigInteger result [] = b2 . divideAndRemainder ( b1 ); //求出余数的除法操作
System . out . println ( "商是:" + result [ 0 ] + ";余数是:" + result [ 1 ] ); //求出余数的除法操作
System . out . println ( b1 . equals ( b2 )); //是否等价
int flag = b1 . compareTo ( b2 );
if ( flag == - 1 )
System . out . println ( "比较操作:b1<b2" );
else if ( flag == 0 )
System . out . println ( "比较操作:b1==b2" );
else
System . out . println ( "比较操作:b1>b2" );
Copy 尽量采用字符串对BigDecimal赋值,这样精度更准确。
1
2
3
4
5
6
7
8
System . out . println ( new BigDecimal ( "2.3" ));
System . out . println ( new BigDecimal ( 2 . 3 )); //2.29999999999999
BigDecimal num1 = new BigDecimal ( "10" );
BigDecimal num2 = new BigDecimal ( "3" );
//需要指定位数,防止无限循环,或者包含在try-catch中
BigDecimal num3 = num1 . divide ( num2 , 3 , BigDecimal . ROUND_HALF_UP );
System . out . println ( num3 );
Copy BigDecimal做除法操作,需要注意截断,防止出现无限循环小数。
随机数类Random
nextInt() 返回一个随机Int
nextInt(int a) 返回一个[0,a)之间的随机int
nextDouble() 返回一个[0.0,1.0]之间double
ints方法批量返回随机数数组
Math.random() 返回一个[0.0,1.0]之间double
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//第一种,采用Random类随机生成
Random rd = new Random ();
System . out . println ( rd . nextInt ());
System . out . println ( rd . nextInt ( 100 )); //0-100的随机数
System . out . println ( rd . nextLong ());
System . out . println ( rd . nextDouble ());
//第二种,生成一个范围内的随机数 例如0-10之间的随机数
System . out . println ( Math . round ( Math . random () * 10 ));
//JDK 8 新增方法
rd . ints (); //返回无限个int类型范围内的数据
int [] arr = rd . ints ( 10 ). toArray (); //生成10个int范围类的个数
for ( int i = 0 ; i < arr . length ; i ++ ){
System . out . println ( arr [ i ] );
}
arr = rd . ints ( 5 , 10 , 100 ). toArray (); //5个10-100的随机数
for ( int i = 0 ; i < arr . length ; i ++ ){
System . out . println ( arr [ i ] );
}
arr = rd . ints ( 10 ). limit ( 5 ). toArray ();
for ( int i = 0 ; i < arr . length ; i ++ ){
System . out . println ( arr [ i ] );
}
Copy 工具类Math
java.math包
java.lang.Math
绝对值函数abs
对数函数log
比较函数max、min
幂函数pow
四舍五入函数round
向下取整floor
向上取整ceil
字符串相关类
String
Java使用频率最高的类
一个不可变对象,加减操作性能较差
常用:
charAt, concat, contains, endsWith, equals, equalsIgnoreCase, hashCode, indexOf, length, matches, replace, replaceAll, split, startsWith, subString, trim, valueOf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
String a = "123;456,789,123 " ;
System . out . println ( a . charAt ( 0 )); //返回第0个元素
System . out . println ( a . indexOf ( ";" )); //返回第一个;的位置
System . out . println ( a . concat ( ";000" )); //连接一个新字符串并返回,a不变
System . out . println ( a . contains ( "000" )); //判断a是否包含000
System . out . println ( a . endWith ( "000" )); //判断a是否以000结尾
System . out . println ( a . equals ( "000" )); //判断是否等于000
System . out . println ( a . equalsIgnoreCase ( "000" )); //判断在忽略大小写情况下是否等于000
System . out . println ( a . length ()); //返回a长度
System . out . println ( a . trim ()); //返回a去除前后空格后的字符串,a不变
String [] b = a . split ( ";" ); //将a字符串按照;分割成数组
for ( int i = 0 ; i < b . length ; i ++ ){
System . out . println ( b [ i ] );
}
System . out . println ( a . substring ( 2 , 5 )); //截取a的第2个到第5个字符 a不变
System . out . println ( a . replace ( "1" , "a" ));
System . out . println ( a . replaceAll ( "1" , "a" ); //replaceAll第一个参数是正则表达式
String s1 = "123456789" ;
String s2 = s1 . replace ( "?" , "a" );
String s3 = s1 . replaceAll ( "[?]" , "a" );
//这里的[?]才表示字符问号,这样才能正常替换。不然在正则中会有特殊的意义就会报异常
Copy trim方法去掉的是字符串的前后空格,无法去除字符串中间的空格。
可变字符串
StringBuffer(字符串加减,同步,性能好)
StringBuilder(字符串加减,不同步,性能更好)
StringBuffer/StringBuilder:方法一样,区别在同步
append/insert/delete/replace/substring
length字符串实际大小,capacity字符串占用空间大小
trimToSize():去除空隙,将字符串存储压缩到实际大小
如有大量append,事先预估大小,再调用相应构造函数
时间类
java.util.Date(基本废弃,Deprecated)
getTime(),返回自1970.1.1以来的毫秒数
java.spl.Date(和数据库对应的时间类)
Calendar是目前程序中最常用的,但是是抽象类
Calendar gc = Calendar.getInstance();
Calendar gc = new GregorianCalendar();
简单工厂模式
查看CalendarClassTest.java
Calendar
get(Field) 来获取时间中每个属性的值,注意,月份0-11
getTime() 返回相应的Date对象
getTimeInMillis() 返回自1970.1.1以来的毫秒数
set(Field) 设置时间字段
add(field, amount) 根据指定字段增加/减少时间
roll(field, amount) 根据指定字段增加/减少时间,但不影响上一级的时间段
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
Calendar calendar = Calendar . getInstance ();
public void test1 (){
//获取年
int year = calendar . get ( Calendar . YEAR );
//获取月
int month = calendar . get ( Calendar . MONTH ) + 1 ;
//获取日
int day = calendar . get ( Calendar . DAY_OF_MONTH );
//获取时
int hour = calendar . get ( Calendar . HOUR );
//获取分
int minute = calendar . get ( Calendar . MINUTE );
//获取秒
int second = calendar . get ( Calendar . SECOND );
//星期,从星期日算起
int weekday = calendar . get ( Calendar . DAY_OF_WEEK );
}
//一年后的今天
public void test2 (){
calendar . add ( Calendar . YEAR , 1 );
//获取年
int year = calendar . get ( Calendar . YEAR );
//获取月
int month = calendar . get ( Calendar . MONTH ) + 1 ;
//获取日
int day = calendar . get ( Calendar . DAY_OF_MONTH );
}
//获取任意一个月的最后一天
public void test3 (){
//假设求6月的最后一天
int currentMonth = 6 ;
//先求出7月份的第一天
calendar . set ( calendar . get ( Calendar . YEAR ), currentMonth , 1 );
calendar . add ( Calenadr . DATA , - 1 );
//获取日
int day = calendar . get ( Calendar . DAY_OF_MONTH );
}
//设置日期
public void test4 (){
calendar . set ( Calendar . YEAR , 2000 );
System . out . println ( "现在是" + calendar . get ( Calendar . YEAR ) + "年" );
calendar . set ( 2018 , 1 , 2 );
//获取年
int year = calendar . get ( Calendar . YEAR );
//获取月
int month = calendar . get ( Calendar . MONTH ) + 1 ;
//获取日
int day = calendar . get ( Calendar . DAY_OF_MONTH );
}
public void test5 (){
calendar . set ( 2018 , 7 , 8 );
calendar . add ( Calendar . DAY_OF_MONTH , - 8 );
//获取年
int year = calendar . get ( Calendar . YEAR );
//获取月
int month = calendar . get ( Calendar . MONTH ) + 1 ;
//获取日
int day = calendar . get ( Calendar . DAY_OF_MONTH );
System . out . println ( "2018.7.8,用add减少8天,现在是" + year + "." + month + "." + day );
//2018.7.31
calendar . set ( 2018 , 7 , 8 );
calendar . roll ( Calendar . DAY_OF_MONTH , - 8 );
//获取年
int year = calendar . get ( Calendar . YEAR );
//获取月
int month = calendar . get ( Calendar . MONTH ) + 1 ;
//获取日
int day = calendar . get ( Calendar . DAY_OF_MONTH );
System . out . println ( "2018.7.8,用roll减少8天,现在是" + year + "." + month + "." + day );
//2018.8.31只改变天数,不改变月份
}
Copy roll函数做加减法,只影响当前字段,不影响进位。add函数则会影响进位。
Java 8 退出新的时间API
java.time包
旧的设计不好(重名的类、线程不安全等)
新版本优点:不变性,在多线程环境下;遵循设计模式,设计得更好,可扩展性强
Java 8 时间包概述
java.time包:新的Java日期/时间API的基础包
主要类:LocalDate日期类
LocalTime时间类(时分秒-纳秒)
LocalDateTime:LocalDate + LocalTime
Instant时间戳
java.time.chrono包:为非ISO的日历系统定义了一些泛化的API
java.time.format包:格式化和解析日期时间对象的类
java.time.temporal包:包含一些时态对象,可以用其找出关于日期/时间对象的某个特定日期或时间
java.time.zone包:包含支持不同时区以及相关规则的类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//当前时间
LocalDate today = LocalDate . now ();
//根据指定时间创建LocalDate
LocalDate firstDay_2014 = LocalDate . of ( 2014 , Month . JANUARY , 1 );
//给定错误时间参数,将报异常java.time.DateTimeException
//LocalDate firstDay_2014 = LocalDate.of(2014, Month.FEBRUARY, 29);
//可更改时区
LocalDate todayBeijing = LocalDate . now ( ZoneId . of ( "Asia/Shanghai" ));
//从纪元日01/01/1970开始365天
LocalDate dateFromBase = LocalDate . ofEpochDay ( 365 );
//2014年的第100天
LocalDate hundredDay2014 = LocalDate . ofYearDay ( 2014 , 100 );
//当前时间 时分秒 纳秒
LocalTime time = LocalTime . now ();
//根据时分秒
LocalTime specificTime = LocalTime . of ( 12 , 20 , 25 , 40 );
//错误的时间参数 将报DateTimeException
//LocalTime invalidTime = LocalTime.of(25,20);
//上海时间
LocalTime timeSH = LocalTime . mow ( ZoneId . of ( "Asia/Shanghai" ));
//一天当中第几秒
LocalTime specificSecondTime = LocalTime . ofSecondOfDay ( 10000 );
//当前时间戳
Instant timestamp = Instant . now ();
//从毫秒数来创建时间戳
Instant specificTime = Instant . ofEpochMilli ( timestamp . toEpochMilli ());
Date date = Date . from ( timestamp );
LocalDate today = LocalDate . now ();
//判断是否是闰年
System . out . println ( "Year " + today . getYear () + "is Leap Year" + today . isLeapYear ());
//今天和01/01/2015比较
System . out . println ( "Today is before 01/01/2015" + today . isBefore ( LocalDate . of ( 2015 , 1 , 1 )));
//当前时分秒
System . out . println ( "Current Time =" + today . atTime ( LocalTime . now ()));
//加减时间
System . out . println ( "10 days after today will be " + today . plusDays ( 10 ));
System . out . println ( "3 weeks after today will be " + today . plusWeeks ( 3 ));
System . out . println ( "20 months after today will be " + today . plusMonths ( 20 ));
System . out . println ( "10 days after today will be " + today . minusDays ( 10 ));
System . out . println ( "3 weeks after today will be " + today . minusWeeks ( 3 ));
System . out . println ( "3 weeks after today will be " + today . minusMonths ( 20 ));
//调整时间
System . out . println ( "First date of this month = " + today . with ( TemporalAdjusters . firstDayOfMonth ()));
LocalDate lastDayOfYear = today . with ( TemporalAdjusters . lastDayOfYear ());
System . out . println ( "Last date of this year = " + lastDayOfYear );
//时间段计算
Period period = today . until ( lastDayOfYear );
System . out . println ( "Period Format = " + period );
System . out . println ( "Months remaining in the year = " + period . getMonths ());
Copy
java.text包java.text.Format的子类
NumberFormat:数字格式化,抽象类
– DecimalFormat 工厂模式
例如:将1234567格式化输出为1,234,567
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
DecimalFormat df1 , df2 ;
//整数部分为0,#认为整数不存在,可不写;0认为没有,但至少写一位,写0
df1 = new DecimalFormat ( "#.00" );
df2 = new DecimalFormat ( "0.00" );
System . out . println ( df1 . format ( 0 . 1 )); //.10
System . out . println ( df2 . format ( 0 . 1 )); //0.10
df1 = new DecimalFormat ( "0.00" );
df2 = new DecimalFormat ( "0.##" );
System . out . println ( df1 . format ( 0 . 1 )); //0.10
System . out . println ( df2 . format ( 0 . 1 )); //0.1
df1 = new DecimalFormat ( "0.00" );
df2 = new DecimalFormat ( "#.00" );
System . out . println ( df1 . format ( 2 )); //2.00
System . out . println ( df2 . format ( 2 )); //2.00
System . out . println ( df1 . format ( 20 )); //20.00
System . out . println ( df2 . format ( 20 )); //20.00
System . out . println ( df1 . format ( 200 )); //200.00
System . out . println ( df2 . format ( 200 )); //200.00
Copy MessageFormat:字符串格式化
支持多个参数-值对位复制文本S
支持变量的自定义格式
例如将“Hello {1}”根据变量值格式化为Hello World
1
2
3
4
5
6
7
String message = "{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}{13}{14}{15}{16}" ;
object [] array = new Object [] { "A" , "B" , "C" , "D" , "E" , "F" , "G" , "H" , "I" , "J" , "K" , "L" , "M" , "N" , "O" , "P" , "Q" };
String value = MessageFormat . format ( message , array );
System . out . println ( value );
message = "oh, {0,number,#.##} is a good number" ;
array = new Object [] { new Double ( 3 . 1415 )};
value = MessageFormat . format ( message , array );
Copy 输出
1
2
ABCDEFGHIJKLMNOPQ
oh, 3.14 is a good number
Copy DateFormat:日期/时间格式化,抽象类
– SimpleDateFormat 工厂模式
parse:将字符串格式化为时间对象
format:将时间对象格式化为字符串
如将当前时间转为YYYY-MM-DD HH24:MI:SS输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
String strDate = "2008-10-19 10:11:30.345" ;
//准备第一个模板,从字符串中提取出日期数字
String pat1 = "yyyy-MM-dd HH:mm:ss.SSS" ;
//准备第二个模板,将提取后的日期数字变为指定的格式
String pat2 = "yyyy年MM月dd日 HH时mm分ss秒SSS毫秒" ;
SimpleDateFormat sdf1 = new SimpleDateFormat ( pat1 );
SimpleDateFormat sdf2 = new SimpleDateFormat ( pat2 );
Date d = null ;
try {
d = sdf1 . parse ( strDate ); //将给定的字符串中的日期提取出来
} catch ( Exception e ){ //如果提供的字符串格式有错误,则进行异常处理
e . printStackTrace (); //打印异常信息
}
System . out . println ( sdf2 . format ( d )); //将日期变为新的格式
Copy
java.time.format包下
java.time.format.DateFormatter:时间格式化
JDK 8 发布,线程安全(vs SimpleDateFormat 线程不安全)
ofPattern:设定时间格式
parse:将字符串格式化为时间对象
format:将时间对象格式化为字符串
如将当前时间转为YYYY-MM-DD HH24:MI:SS输出
1
2
3
4
5
6
7
8
9
10
11
//将字符串转化为时间
String dateStr = "2020年1月1日" ;
DateTimeFormatter formatter = DateTimeFormatter . ofPattern ( "yyyy年MM月dd日" );
LocalDate date = LocalDate . parse ( dateStr , formatter );
System . out . println ( date . getYear () + "-" + date . getMonthValue () + "-" + date . getDayOfMonth ());
//将日期转换为字符串输出
LocalDateTime now = LocalDateTime . now ();
DateTimeFormatter format = DateTimeFormatter . ofPattern ( "yyyy年MM月dd日 hh:mm:ss" );
String nowStr = now . format ( format );
System . out . println ( nowStr );
Copy LocalDate类的月份是1-12,不用加1;Calendar类的月份是0-11,需要加1。
异常和异常处理
异常
Java异常分成Exception(程序相关)和Error(系统相关)。
Exception分为RuntimeException程序自身的错误(如5/0,空指针,数组越界)和非RuntimeException外界相关的错误(如打开一个不存在的文件,加载一个不存在的类)。
IOException是非RuntimeException的典型示例。
另一种分类方法:
Unchecked Exception:(编译器不会辅助检查的,需要管理员自己管的)异常,包括Error子类和RuntimeException子类。
非RuntimeException的Exception的子类:(编译器会辅助检查的)异常,checked exception。
注意:编译器会检查程序是否为checked exception配置了处理。若没有处理,会报错。
异常处理
try-catch-finally:一种保护代码正常运行的机制。
异常结构
try…catch(catch可以有多个,下同)
try…catch…finally
try…finally
try必须有,catch和finally至少要有一个
try:正常业务逻辑代码
catch:当try发生异常,将执行catch代码。若无异常,绕之。
finally:当try或catch执行结束后,必须要执行finally。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
try
{
int a = 5 / 2 ;
System . out . println ( a );
}
catch ( Exception ex )
{
ex . printStackTrace ();
}
finally
{
System . out . println ( "1 over" );
}
try
{
int a = 5 / 0 ;
System . out . println ( a );
}
catch ( Exception ex )
{
ex . printStackTrace ();
}
finally
{
System . out . println ( "2 over" );
}
try
{
int a = 5 / 0 ;
System . out . println ( a );
}
catch ( Exception ex )
{
ex . printStackTrace ();
int a = 5 / 0 ;
}
finally
{
System . out . println ( "3 over" );
}
Copy 3中,第一个异常执行完finally后再执行第二个异常。(catch内部再次发生异常也不影响finally的正常运行。)
进入catch块后,并不会返回到try发生异常的位置,也不会执行后续的catch块,一个异常只能进入一个catch块。
一般将小异常(具体的异常子类,如ArithmeticException)写在前面,大(宽泛)的异常(如Exception)写在末尾。
允许包含:
1
2
3
4
5
6
7
8
9
try{
try-catch-finally结构
}
catch(){
try-catch-finally结构
}
finally{
try-catch-finally结构
}
Copy
方法存在可能异常的语句,但不处理,可使用throws来声明异常。
调用带有throws异常(checked exception)的方法,要么处理这些异常,或者再次向外throws,直到main函数为止。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class ThrowsDemo
{
public static void main ( String [] args )
{
try
{
int result = new Test (). divide ( 3 , 1 );
System . out . println ( "1 result:" + result );
}
catch ( ArithmeticException ex )
{
ex . printStackTrace ();
}
int result = new Test (). divide ( 3 , 0 );
System . out . println ( "2 result:" + result );
}
}
class Test
{
//ArithmeticException is a RuntimeException, not checked exception
public int divide ( int x , int y ) throws ArithmeticException
{
int result = x / y ;
return x / y ;
}
}
Copy
一个方法被覆盖,覆盖它的方法不限抛出相同的异常,或者异常的子类。
如果父类的方法抛出多个异常,那么重写的子类方法必须抛出那些异常的子集,也就是不能抛出新的异常。
Father.java
1
2
3
4
5
6
public class Father {
public void f1 () throws ArithmeticException
{
}
}
Copy Son.java
1
2
3
public class Son extends Father {
public void f1 () throws Exception //错误
}
Copy 自定义异常
自定义异常需要继承Exception类或其子类。
继承自Exception,就变成Checked Exception。
继承自RuntimeException,就变成Unchecked Exception。
(非RuntimeException,是Checked Exception,IDE辅助检查;RuntimeException,是Unchecked Exception,IDE不会辅助检查,是程序员自行处理。)
自定义重点在构造函数
调用父类Exception的message构造函数
可自定义自己的成员变量
在程序中采用throw主动抛出异常
MyException.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class MyException extends Exception {
private String returnCode ; //异常对应的返回码
private String returnMsg ; //异常对应的描述信息
public MyException (){
super ();
}
public MyException ( String returnMsg ){
super ( returnMsg );
this . returnMsg = returnMsg ;
}
public MyException ( String returnCode , String returnMsg ){
super ( returnMsg );
this . returnCode = returnCode ;
this . returnMsg = returnMsg ;
}
public String getReturnCode (){
return returnCode ;
}
public String getReturnMsg (){
return returnMsg ;
}
}
Copy 在方法内部程序中,抛出异常采用throw关键字;在方法头部声明中,声明异常采用throws关键字。
MyExceptionTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MyExceptionTest {
public static void testException () throws MyException {
throw new MyException ( "10001" , "The reason of myException" );
}
public static void main ( String [] args ) {
//MyExceptionTest.testException();注释1 要报错需注释掉下方代码
try {
MyExceptionTest . testException ();
} catch ( MyException e ) {
e . printStackTrace ();
System . out . println ( "returnCode:" + e . getReturnCode ());
System . out . println ( "returnCode:" + e . getReturnMsg ());
}
}
}
Copy 注释1:main函数里调用了一个声明MyException异常的方法,但没处理。因为MyException继承Exception,是属于非RuntimeException,也就是Checked Exception,因此编译器会检查到程序没处理而报错。解法:1)采用try-catch-finally结构 2)main函数也throws MyException。
DivideByMinusException.java
1
2
3
4
5
6
7
8
9
10
11
12
public class DivideByMinusException extends Exception {
int divisor ;
public DivideByMinusException ( String msg , int divisor )
{
super ( msg );
this . divisor = divisor ;
}
public int getDevisor ()
{
return this . getDevisor ();
}
}
Copy Student.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
public class Student {
public int divide ( int x , int y )
{
return x / y ;
}
public static void main ( String [] args ) throws DivideByMinusException {
Student newton = new Student ();
//newton.divide2(5,0);
newton . divide5 ( 5 , - 2 );
}
public int divide2 ( int x , int y )
{
int result ;
try
{
result = x / y ;
System . out . println ( "result is " + result );
}
catch ( ArithmeticException ex )
{
System . out . println ( ex . getMessage ());
return 0 ;
}
catch ( Exception ex )
{
ex . printStackTrace ();
return 0 ;
}
}
public int divide3 ( int x , int y ) throws ArithmeticException //unchecked exception
{
return x / y ;
}
public int divide4 ( int x , int y )
{
// try
// {
// return divide3(x,y);
// }
// catch(ArithmeticException ex)
// {
// ex.printStackTrace();
// return 0;
// }
return divide3 ( x , y ); //尽管divide3报告异常,但divide4无需处理。
//若调用divide5(x,y);就需要做try-catch处理。
}
public int divide5 ( int x , int y ) throws DivideByMinusException
{
try
{
if ( y < 0 )
{
throw new DivideByMinusException ( "The divisor is negative" , y );
}
return divide3 ( x , y );
}
catch ( ArithmeticException ex )
{
ex . printStackTrace ();
return 0 ;
}
}
}
Copy 对于CheckedException,编译器要求调用者处理,要么采用try-catch-finally处理,要么采用throws声明异常。
数据结构
数组
1
2
3
4
5
6
7
8
9
10
11
12
13
int a [] ; //还没有new操作,实际上是null,也不知道内存位置
int [] b ;
int [] c = new int [ 2 ] ; //c有2个元素,都是0
c [ 0 ] = 1 , c [ 1 ] = 2 ; //初始化
int d [] = new int [] { 1 , 2 , 3 }; //同时定义和初始化
int d1 [] = { 1 , 2 , 3 }; //同时定义和初始化
//声明变量时没有分配内存,不需要指定大小,以下是错误的
//int a[2];
//int[2] b;
//int[2] c = new int[2];
//int d[2] = new int[2];
Copy
数组索引
数组的length属性标识数组的长度
从0开始,到length-1
1
int [] a = new int [ 5 ] ; //a[0]~a[4],a.length是5
Copy 数组不能越界访问,否则会报ArrayIndexOutOfBoundsException异常
1
2
3
4
5
6
7
8
9
10
11
//需控制索引位置
for ( int i = 0 ; i < d . length ; i ++ )
{
System . out . println ( d [ i ] );
}
//无需控制索引位置
for ( int e : d )
{
System . out . println ( e );
}
Copy
1
2
3
4
5
6
7
8
//规则数组
int a [][] = new int [ 2 ][ 3 ] ;
//不规则数组
int b [][] ;
b = new int [ 3 ][] ;
b [ 0 ] = new int [ 3 ] ;
b [ 1 ] = new int [ 4 ] ;
b [ 2 ] = new int [ 5 ] ;
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int k = 0 ;
for ( int i = 0 ; i < a . length ; i ++ )
{
for ( int j = 0 ; j < a [ i ] . length ; j ++ )
{
a [ i ][ j ] = ++ k ;
}
}
for ( int [] items : a )
{
for ( int item : items )
{
System . out . println ( item + ", " );
}
System . out . println ();
}
Copy JCF
Java Collection Framework
容器:能够存放数据的空间结构
数组/多维数组,只能线性存放
列表/散列集/树/…
容器框架:为表示和操作容器而规定的一种标准体系结构
对外的接口:容器中所能存放的抽象数据类型
接口的实现:可复用的数据结构
算法:对数据的查找和排序
容器框架优点:提高数据存取效率,避免程序员重复劳动
C++的STL, Java的JCF
Java 1.1和以前的数据结构
Vector, Stack, Hashtable, Enumeration等
Java 1.2和以后,JCF集合框架
功能更强大,易于学习
接口和实现分离,多种设计模式更灵活
泛型设计
主要由列表(List)、散列集合(Set)、映射(Map)组成。(还有Arrays和Collection工具类)
Dictionary和Hashtable属于JDK1.1的类,已经较少使用了。
早期接口Enumeration
JCF的集合接口是Collection
add, contains, remove, size
iterator
JCF的迭代器接口Iterator
hasNext, next, remove
JCF主要的数据结构实现类
列表(List, ArrayList, LinkedList)
集合(Set, HashSet, TreeSet, LinkedHashSet)
映射(Map, HashMap, TreeMap, LinkedHashMap)
JCF主要的算法类
Arrays: 对数组进行查找和排序等操作
Collections: 对Collection及其子类进行排序和查找操作
List
List 列表
有序的Collection
允许重复元素
{1, 2, 3, {1, 2}, 1, 3}
List主要实现
ArrayList(非同步)
LinkedList(非同步)
Vector(同步)
ArrayList
以数组实现的列表,不支持同步
利用索引位置可以快速定位访问
不适合指定位置的插入、删除操作
适合变动不大,主要用于查询的数据
和Java数组相比,其容量是可动态调整的//Java数组是静态的,长度确定不可修改
ArrayList在元素填满容器时会自动扩充容器大小的50%
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import java.util.ArrayList ;
//Vector几乎和ArrayList一样,除了Vector本身是同步的
public class ArrayListTest {
public static void main ( String [] a ){
ArrayList < Integer > al = new ArrayList < Integer > (); //ArrayList<Integer> al 是泛型表示,意思是al这个数据结构里只能容纳Integer的对象,其它对象无法放入
al . add ( 1 ); //ArrayList只能装对象,当add(1)时,会自动将普通int变量1自动装箱为Integer(1)的对象,然后放入ArrayList容器中
al . add ( 2 );
al . add ( 3 );
al . add ( 4 );
al . add ( new Integer ( 6 ));
System . out . println ( al . get ( 3 ));
al . remove ( 3 ); //删除第4个元素,后面元素往前挪
al . add ( 3 , 0 ); //将0插入到第3个元素,后面元素往后挪
//遍历方法
ArrayList < Integer > as = new ArrayList < Integer > ( 100000 );
for ( int i = 0 ; i < 100000 ; i ++ )
{
as . add ( i );
}
traverseByIterator ( as );
traverseByIndex ( as );
traverseByFor ( as );
}
//迭代器遍历
public static void traverseByIterator ( ArrayList < Integer > al )
{
long startTime = System . namoTime ();
Iterator < Integer > iter1 = al . iterator ();
while ( iter1 . hasNext ()){
iter1 . next ();
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
//随机索引值遍历
public static void traverseByIndex ( ArrayList < Integer > al )
{
long startTime = System . namoTime ();
for ( int i = 0 ; i < al . size (); i ++ )
{
al . get ( i );
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
//for循环遍历
public static void traverseByFor ( ArrayList < Integer > al )
{
long startTime = System . namoTime ();
for ( Integer item : al )
{
;
}
long endTime = System . namoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
}
Copy 结果表明:for循环遍历最快,随机索引值遍历和for差距不大,迭代器最慢。
LinkedList
以双向链表实现的列表,不支持同步
可被当作堆栈、队列和双端队列进行操作
顺序访问高效、随机访问较差,中间插入和删除高效
适用于经常变化的数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import java.util.ArrayList ;
public class LinkedListTest {
public static void main ( String [] a ){
LinkedList < Integer > ll = new LinkedList < Integer > ();
ll . add ( 1 );
ll . add ( 2 );
ll . add ( 3 );
ll . add ( 4 );
System . out . println ( ll . size ());
ll . addFirst ( 0 ); //在头部增加0
ll . add ( 3 , 5 ); //将5插入到第四个元素,四及后续元素往后挪
ll . remove ( 3 ); //将第四个元素删除
LinkedList < Integer > list = new LinkedList < Integer > ();
for ( int i = 0 ; i < 100000 ; i ++ )
{
list . add ( i );
}
traverseByIterator ( list );
traverseByIndex ( list );
traverseByFor ( list );
}
//迭代器遍历
public static void traverseByIterator ( LinkedList < Integer > list )
{
long startTime = System . namoTime ();
Iterator < Integer > iter1 = list . iterator ();
while ( iter1 . hasNext ()){
iter1 . next ();
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
//随机索引值遍历
public static void traverseByIndex ( LinkedList < Integer > list )
{
long startTime = System . namoTime ();
for ( int i = 0 ; i < list . size (); i ++ )
{
list . get ( i );
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
//for循环遍历
public static void traverseByFor ( LinkedList < Integer > list )
{
long startTime = System . namoTime ();
for ( Integer item : list )
{
;
}
long endTime = System . namoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
}
Copy 结果:for循环最快,迭代器稍微慢一些,随机索引特别慢。
性能比较
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import java.util.ArrayList ;
public class ListCompareTest {
public static void main ( String [] args ) {
int times = 10 * 1000 ;
ArrayList < Integer > arrayList = new ArrayList < Integer > ();
LinkedList < Integer > linkedList = new LinkedList < Integer > ();
//ArrayList add
long startTime = System . nanoTime ();
for ( int i = 0 ; i < times ; i ++ ) {
arrayList . add ( 0 , i ); //add到头部
}
long endTime = System . namoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
//LinkedList add
startTime = System . nanoTime ();
for ( int i = 0 ; i < times ; i ++ ) {
linkedList . add ( 0 , i );
}
endTime = System . namoTime ();
duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
//ArrayList get
startTime = System . nanoTime ();
for ( int i = 0 ; i < times ; i ++ ) {
arrayList . get ( i );
}
endTime = System . namoTime ();
duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
//LinkedList get
startTime = System . nanoTime ();
for ( int i = 0 ; i < times ; i ++ ) {
linkedList . get ( i );
}
endTime = System . namoTime ();
duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
//ArrayList remove
startTime = System . nanoTime ();
for ( int i = 0 ; i < times ; i ++ ) {
arrayList . remove ( 0 );
}
endTime = System . namoTime ();
duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
//LinkedList remove
startTime = System . nanoTime ();
for ( int i = 0 ; i < times ; i ++ ) {
linkedList . remove ( 0 );
}
endTime = System . namoTime ();
duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
}
Copy 结果:add ArrayList时间远大于LinkedList
get ArrayList时间远小于LinkedList
remove ArrayList时间远大于LinkedList
结论:ArrayList适用于较多查询的(静态)数据,LinkedList适用于频繁增删的数据。
Vector(同步)
和ArrayList类似,可变数组实现的列表
Vector同步,适合在多线程下使用
原先不属于JCF框架,属于Java最早的数据结构,性能较差
从JDK 1.2开始,Vector被重写,并纳入到JCF
官方文档建议在非同步情况下,优先采用ArrayList
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import java.util.ArrayList ;
public class VectorTest {
public static void main ( String [] args ) {
Vector < Integer > v = new Vector < Integer > ();
v . add ( 1 );
v . add ( 2 );
v . add ( 3 );
v . remove ( 2 );
v . add ( 1 , 5 );
System . out . println ( v . size ());
//遍历方法
Vector < Integer > v2 = new Vector < Integer > ( 100000 );
for ( int i = 0 ; i < 100000 ; i ++ ) {
v2 . add ( i );
}
traverseByIterator ( v2 );
traverseByIndex ( v2 );
traverseByFor ( v2 );
traverseByEnumeration ( v2 );
}
//迭代器遍历
public static void traverseByIterator ( Vector < Integer > v )
{
long startTime = System . namoTime ();
Iterator < Integer > iter1 = v . iterator ();
while ( iter1 . hasNext ()){
iter1 . next ();
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
//随机索引值遍历
public static void traverseByIndex ( Vector < Integer > v )
{
long startTime = System . namoTime ();
for ( int i = 0 ; i < v . size (); i ++ )
{
v . get ( i );
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
//for循环遍历
public static void traverseByFor ( Vector < Integer > v )
{
long startTime = System . namoTime ();
for ( Integer item : v )
{
;
}
long endTime = System . namoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
//Enumeration遍历
public static void traverseByEnumeration ( Vector < Integer > v )
{
long startTime = System . namoTime ();
for ( Enumeration < Integer > enu = v . elements (); enu . hasMoreElements ();) {
enu . nextElement ();
}
long endTime = System . namoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
}
Copy 结果:for循环是最快的,位置索引第二名,Enumeration第三,迭代器最慢。
Set
确定性:对任意对象都能判定其是否属于某一个集合
互异性:集合内每个元素都是不相同的,内容互异
无序性:集合内的顺序无关
集合接口Set
HashSet 基于散列函数的集合,无序,不支持同步
基于HashMap实现的,可以容纳null元素,不支持同步
但以下方法可以实现同步
1
Set s = Collections.synchronizedSet(new HashSet(...));
Copy add 添加一个元素
clear 清除整个HashSet
contains 判定是否包含一个元素
remove 删除一个元素 size 大小
retainAll 计算两个集合交集
TreeSet 基于树结构的集合,可排序的,不支持同步
LinkedHashSet 基于散列函数和双向链表的集合,可排序的,不支持同步
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import java.util.ArrayList ;
import java.util.HashSet ;
import java.util.Iterator ;
public class HashSetTest {
public static void main ( String [] args ) {
HashSet < Integer > hs = new HashSet < Integer > ();
hs . add ( null );
hs . add ( 1 );
hs . add ( 2 );
hs . add ( 3 );
hs . add ( 40000 );
hs . add ( 5000000 );
hs . add ( 3 ); //3 重复
hs . add ( null ); //null重复
System . out . println ( hs . size ()); //6
if ( ! hs . contains ( 6 ))
{
hs . add ( 6 );
}
System . out . println ( hs . size ()); //7
hs . remove ( 4 );
System . out . println ( hs . size ()); //6
//hs.clear();
//System.out.println(hs.size()); //0
//or循环遍历
for ( Integer item : hs )
{
System . out . println ( item );
}
//测试集合交集
HashSet < String > set1 = new HashSet < String > ();
HashSet < String > set2 = new HashSet < String > ();
set1 . add ( "a" );
set1 . add ( "b" );
set1 . add ( "c" );
set2 . add ( "c" );
set2 . add ( "d" );
set2 . add ( "e" );
//交集
set1 . retainAll ( set2 );
System . out . println ( "交集是 " + set1 );
//测试遍历方法速度
HashSet < Integer > hs2 = new HashSet < Integer > ();
for ( int i = 0 ; i < 100000 ; i ++ ) {
hs2 . add ( i );
}
traverseByIterator ( hs2 );
traverseByFor ( hs2 );
}
public static void traverseByIterator ( HashSet < Integer > hs )
{
long startTime = System . nanoTime ();
//迭代器遍历
Iterator < Integer > iter1 = hs . iterator ();
while ( iter1 . hasNext ()){
iter1 . next ();
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
public static void traverseByFor ( HashSet < Integer > hs )
{
long startTime = System . nanoTime ();
//for循环遍历
for ( Integer item : hs )
{
;
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
}
Copy 迭代器慢于for循环。
LinkedHashSet
继承HashSet,也是基于HashMap实现的,可容纳null元素
不支持同步
1
Set s = Collections.synchronizedSet(new LinkedHashSet(...));
Copy
方法和HashSet基本一致
add,clear,contains,remove,size
通过一个双向链表维护插入顺序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import java.util.ArrayList ;
import java.util.HashSet ;
import java.util.Iterator ;
import java.util.LinkedHashSet ;
public class LinkedHashSetTest {
public static void main ( String [] args ) {
LinkedHashSet < Integer > lhs = new LinkedHashSet < Integer > ();
lhs . add ( null );
lhs . add ( 1000 );
lhs . add ( 20 );
lhs . add ( 3 );
lhs . add ( 40000 );
lhs . add ( 5000000 );
lhs . add ( 3 ); //3 重复
lhs . add ( null ); //null 重复
System . out . println ( lhs . size ()); //6
if ( ! lhs . contains ( 6 ))
{
lhs . add ( 6 );
}
System . out . println ( lhs . size ()); //7
lhs . remove ( 4 );
System . out . println ( lhs . size ()); //6
//lhs.clear();
//System.out.println(lhs.size()); //0
//for循环遍历
for ( Integer item : lhs )
{
System . out . println ( item );
}
LinkedHashSet < Integer > lhs2 = new LinkedHashSet < Integer > ();
for ( int i = 0 ; i < 100000 ; i ++ )
{
lhs2 . add ( i );
}
traverseByIterator ( lhs2 );
traverseByFor ( lhs2 );
}
public static void traverseByIterator ( LinkedHashSet < Integer > hs )
{
long startTime = System . nanoTime ();
//迭代器遍历
Iterator < Integer > iter1 = hs . iterator ();
while ( iter1 . hasNext ()){
iter1 . next ();
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
public static void traverseByFor ( LinkedHashSet < Integer > hs )
{
long startTime = System . nanoTime ();
//for循环遍历
for ( Integer item : hs )
{
;
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
}
Copy LinkedHashSet是保留顺序的,其遍历顺序和插入顺序一致;而HashSet没有保留顺序,其遍历顺序无序。
TreeSet
基于TreeMap实现的,不可以容纳null元素,不支持同步
1
SortedSet s = Collections . synchronizedSortedSet ( new TreeSet (...));
Copy add 添加一个元素
clear 清除整个TreeSet
contains 判定是否包含一个元素
remove 删除一个元素
size 大小
根据compareTo方法或指定Comparator排序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import java.util.ArrayList ;
import java.util.HashSet ;
import java.util.Iterator ;
import java.util.LinkedHashSet ;
import java.util.TreeSet ;
public class TreeSetTest {
public static void main ( String [] args ) {
TreeSet < Integer > ts = new TreeSet < Integer > ();
// ts.add(null); 错误,不支持null
ts . add ( 1000 );
ts . add ( 20 );
ts . add ( 3 );
ts . add ( 40000 );
ts . add ( 5000000 );
ts . add ( 3 ); //3 重复
System . out . println ( ts . size ()); //5
if ( ! ts . contains ( 6 ))
{
ts . add ( 6 );
}
System . out . println ( ts . size ()); //6
ts . remove ( 4 );
System . out . println ( ts . size ()); //5
//lhs.clear();
//System.out.println(lhs.size()); //0
//for循环遍历
for ( Integer item : ts )
{
System . out . println ( item );
}
TreeSet < Integer > ts2 = new TreeSet < Integer > ();
for ( int i = 0 ; i < 100000 ; i ++ )
{
ts2 . add ( i );
}
traverseByIterator ( ts2 );
traverseByFor ( ts2 );
}
public static void traverseByIterator ( TreeSet < Integer > hs )
{
long startTime = System . nanoTime ();
//迭代器遍历
Iterator < Integer > iter1 = hs . iterator ();
while ( iter1 . hasNext ()){
iter1 . next ();
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
public static void traverseByFor ( TreeSet < Integer > hs )
{
long startTime = System . nanoTime ();
//for循环遍历
for ( Integer item : hs )
{
;
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
}
Copy HashSet是无序输出的
LinkedHashSet是按照插入的顺序进行遍历输出的
TreeSet是按照所存储对象大小升序输出的
HashSet, LinkedHashSet, TreeSet的元素都只能是对象
HashSet和LinkedHashSet判定元素重复的原则
判定两个元素的hashCode返回值是否相同,不同则返回false
若两者hashCode相同,判定equals方法,不同则返回false
hashCode和equals方法是所有类都有的,因为Object类有
TreeSet判定元素重复的原则
需要元素继承自Comparable接口
比较两个元素的compareTo方法
HashSetJudgeRuleTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.util.HashSet ;
public class HashSetJudgeRuleTest {
public static void main ( String [] args ) {
HashSet < Cat > hs = new HashSet < Cat > ();
hs . add ( new Cat ( 1 ));
hs . add ( new Cat ( 2 ));
hs . add ( new Cat ( 3 ));
hs . add ( new Cat ( 3 ));
System . out . println ( hs . size ()); //4
}
}
Copy Cat.java
1
2
3
4
5
6
7
8
9
10
class Cat
{
private int size ;
public Cat ( int size )
{
this . size = size ;
}
}
Copy Dog.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Dog {
private int size ;
public Dog ( int s ) {
size = s ;
}
public int getSize () {
return size ;
}
public boolean equals ( Object obj2 ) {
System . out . println ( "Dog equals()~~~~~~~~~~~" );
if ( 0 == size - (( Dog ) obj2 ). getSize ()) {
return true ;
} else {
return false ;
}
}
public int hashCode () {
System . out . println ( "Dog hashCode()~~~~~~~~~~~" );
return size ;
}
public String toString () {
System . out . print ( "Dog toString()~~~~~~~~~~~" );
return size + "" ;
}
}
Copy Tiger.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Tiger implements Comparable {
private int size ;
public Tiger ( int s ) {
size = s ;
}
public int getSize () {
return size ;
}
public int compareTo ( Object o ) {
System . out . println ( "Tiger compareTo()~~~~~~~~~~~" );
return size - (( Tiger ) o ). getSize ();
}
}
Copy Tiger实现Comparable接口,所以必须实现compareTo方法来比较大小。
compareTo方法具体规则如下:
1
int a = obj1 . compareTo ( obj2 );
Copy 若a>0,则obj1>obj2;
若a==0,则obj1==obj2;
若a<0,则obj1<obj2。
HashSet的元素判定规则只和hashCode、equals这2个方法有关,和compareTo方法无关。
Java的四个重要接口:
Comparable可比较的
Clonable可克隆的
Runnable可线程化的
Serializable可序列化的
ObjectHashSetTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import java.util.HashSet ;
import java.util.Iterator ;
import java.util.LinkedHashSet ;
import java.util.TreeSet ;
public class ObjectHashSetTest {
public static void main ( String [] args ) {
System . out . println ( "==========Cat HashSet ==============" );
HashSet < Cat > hs = new HashSet < Cat > ();
hs . add ( new Cat ( 2 ));
hs . add ( new Cat ( 1 ));
hs . add ( new Cat ( 3 ));
hs . add ( new Cat ( 5 ));
hs . add ( new Cat ( 4 ));
hs . add ( new Cat ( 4 ));
System . out . println ( hs . size ()); //6
System . out . println ( "========================" );
LinkedHashSet < Cat > lhs = new LinkedHashSet < Cat > ();
lhs . add ( new Cat ( 2 ));
lhs . add ( new Cat ( 1 ));
lhs . add ( new Cat ( 3 ));
lhs . add ( new Cat ( 5 ));
lhs . add ( new Cat ( 4 ));
lhs . add ( new Cat ( 4 ));
System . out . println ( lhs . size ()); //6
System . out . println ( "==========Dog HashSet ==============" );
HashSet < Dog > hs2 = new HashSet < Dog > ();
hs2 . add ( new Dog ( 2 ));
hs2 . add ( new Dog ( 1 ));
hs2 . add ( new Dog ( 3 ));
hs2 . add ( new Dog ( 5 ));
hs2 . add ( new Dog ( 4 ));
hs2 . add ( new Dog ( 4 ));
System . out . println ( hs2 . size ()); //5
System . out . println ( "========================" );
LinkedHashSet < Dog > lhs2 = new LinkedHashSet < Dog > ();
lhs2 . add ( new Dog ( 2 ));
lhs2 . add ( new Dog ( 1 ));
lhs2 . add ( new Dog ( 3 ));
lhs2 . add ( new Dog ( 5 ));
lhs2 . add ( new Dog ( 4 ));
lhs2 . add ( new Dog ( 4 ));
System . out . println ( lhs2 . size ()); //5
System . out . println ( "==========Tiger HashSet ==============" );
HashSet < Tiger > hs3 = new HashSet < Tiger > ();
hs3 . add ( new Tiger ( 2 ));
hs3 . add ( new Tiger ( 1 ));
hs3 . add ( new Tiger ( 3 ));
hs3 . add ( new Tiger ( 5 ));
hs3 . add ( new Tiger ( 4 ));
hs3 . add ( new Tiger ( 4 ));
System . out . println ( hs3 . size ()); //6
System . out . println ( "========================" );
LinkedHashSet < Tiger > lhs3 = new LinkedHashSet < Tiger > ();
lhs3 . add ( new Tiger ( 2 ));
lhs3 . add ( new Tiger ( 1 ));
lhs3 . add ( new Tiger ( 3 ));
lhs3 . add ( new Tiger ( 5 ));
lhs3 . add ( new Tiger ( 4 ));
lhs3 . add ( new Tiger ( 4 ));
System . out . println ( lhs3 . size ()); //6
}
}
Copy Cat类本身没有hashCode(),而是继承Object类,而Object的hashCode()会返回对象信息和内存地址经过运算后的一个int值。两个不同的Cat(4)对象,它们的hashCode()返回值是不同的。
Dog类本身改写了hashCode()方法,其返回值是具体的size。所以两个不同Dog(4),它们的hashCode()返回值是相同的。
这三个方法三位一体:equals()是相同的;hashCode()是相同的;toString()也应该是相同的。
ObjectTreeSetTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import java.util.TreeSet ;
public class ObjectTreeSetTest {
public static void main ( String [] args ) {
/*
System.out.println("==========Cat TreeSet ==============");
TreeSet<Cat> ts = new TreeSet<Cat>();
ts.add(new Cat(2));
ts.add(new Cat(1));
ts.add(new Cat(3));
ts.add(new Cat(5));
ts.add(new Cat(4));
ts.add(new Cat(4));
System.out.println(ts.size()); //5
System.out.println("==========Dog TreeSet ==============");
TreeSet<Dog> ts2 = new TreeSet<Dog>();
ts2.add(new Dog(2));
ts2.add(new Dog(1));
ts2.add(new Dog(3));
ts2.add(new Dog(5));
ts2.add(new Dog(4));
ts2.add(new Dog(4));
System.out.println(ts2.size()); //5
*/
//添加到TreeSet的,需要实现Comparable接口,即实现compareTo方法
System . out . println ( "==========Tiger TreeSet ==============" );
TreeSet < Tiger > ts3 = new TreeSet < Tiger > ();
ts3 . add ( new Tiger ( 2 ));
ts3 . add ( new Tiger ( 1 ));
ts3 . add ( new Tiger ( 3 ));
ts3 . add ( new Tiger ( 5 ));
ts3 . add ( new Tiger ( 4 ));
ts3 . add ( new Tiger ( 4 ));
System . out . println ( ts3 . size ()); //5
}
}
Copy Map
定义:两个集合之间的元素对应关系。
一个输入对应到一个输出。
{Key, Value} 键值对,K-V对
Hashtable 同步,慢,数据量小
HashMap 不支持同步,快,数据量大
Properties 同步,文件形式,数据量小
Hashtable
K-V对,K和V都不允许为null
同步,多线程安全
无序的
适合小数据量
主要方法:clear, contains/containsValue, containsKey, get, put, remove, size
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import java.util.Enumeration ;
import java.util.Hashtable ;
import java.util.Iterator ;
import java.util.Map ;
import java.util.Map.Entry ;
public class HashtableTest {
public static void main ( String [] args ) {
Hashtable < Integer , String > ht = new Hashtable < Integer , String > ();
//ht.put(1, null); 编译不报错 运行报错
//ht.put(null,1); 编译报错
ht . put ( 1000 , "aaa" );
ht . put ( 2 , "bbb" );
ht . put ( 30000 , "ccc" );
System . out . println ( ht . contains ( "aaa" ));
System . out . println ( ht . containsValue ( "aaa" ));
System . out . println ( ht . containsKey ( 30000 ));
System . out . println ( ht . get ( 30000 ));
ht . put ( 30000 , "ddd" ); //更新覆盖ccc
System . out . println ( ht . get ( 30000 ));
ht . remove ( 2 );
System . out . println ( "size: " + ht . size ());
ht . clear ();
System . out . println ( "size: " + ht . size ());
Hashtable < Integer , String > ht2 = new Hashtable < Integer , String > ();
for ( int i = 0 ; i < 100000 ; i ++ )
{
ht2 . put ( i , "aaa" );
}
traverseByEntry ( ht2 );
traverseByKeySet ( ht2 );
traverseByKeyEnumeration ( ht2 );
}
public static void traverseByEntry ( Hashtable < Integer , String > ht )
{
long startTime = System . nanoTime ();
System . out . println ( "============Entry迭代器遍历==============" );
Integer key ;
String value ;
Iterator < Entry < Integer , String >> iter = ht . entrySet (). iterator ();
while ( iter . hasNext ()) {
Map . Entry < Integer , String > entry = iter . next ();
// 获取key
key = entry . getKey ();
// 获取value
value = entry . getValue ();
//System.out.println("Key:" + key + ", Value:" + value);
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
public static void traverseByKeySet ( Hashtable < Integer , String > ht )
{
long startTime = System . nanoTime ();
System . out . println ( "============KeySet迭代器遍历==============" );
Integer key ;
String value ;
Iterator < Integer > iter = ht . keySet (). iterator ();
while ( iter . hasNext ()) {
key = iter . next ();
// 获取value
value = ht . get ( key );
//System.out.println("Key:" + key + ", Value:" + value);
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
public static void traverseByKeyEnumeration ( Hashtable < Integer , String > ht )
{
long startTime = System . nanoTime ();
System . out . println ( "============KeyEnumeration迭代器遍历==============" );
Integer key ;
String value ;
Enumeration < Integer > keys = ht . keys ();
while ( keys . hasMoreElements ()) {
key = keys . nextElement ();
// 获取value
value = ht . get ( key );
//System.out.println("Key:" + key + ", Value:" + value);
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
}
Copy 运行结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
true
true
true
ccc
ddd
size: 2
size: 0
============Entry迭代器遍历==============
11238700纳秒
============KeySet迭代器遍历==============
10546900纳秒
============KeyEnumeration迭代器遍历==============
11115100纳秒
Copy
HashMap
K-V对,K和V都运行为null
不同步,多线程不安全
Map m = Collections.synchronizedMap(new HashMap(…));
无序的
主要方法:clear, containsValue, containsKey, get, put, remove, size
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import java.util.Enumeration ;
import java.util.HashMap ;
import java.util.Iterator ;
import java.util.Map ;
import java.util.Map.Entry ;
public class HashMapTest {
public static void main ( String [] args ) {
HashMap < Integer , String > hm = new HashMap < Integer , String > ();
hm . put ( 1 , null );
hm . put ( null , "abc" );
hm . put ( 1000 , "aaa" );
hm . put ( 2 , "bbb" );
hm . put ( 30000 , "ccc" );
System . out . println ( hm . containsValue ( "aaa" ));
System . out . println ( hm . containsKey ( 30000 ));
System . out . println ( hm . get ( 30000 ));
hm . put ( 30000 , "ddd" ); //更新覆盖ccc
System . out . println ( hm . get ( 30000 ));
hm . remove ( 2 );
System . out . println ( "size: " + hm . size ());
hm . clear ();
System . out . println ( "size: " + hm . size ());
HashMap < Integer , String > hm2 = new HashMap < Integer , String > ();
for ( int i = 0 ; i < 100000 ; i ++ )
{
hm2 . put ( i , "aaa" );
}
traverseByEntry ( hm2 );
traverseByKeySet ( hm2 );
}
public static void traverseByEntry ( HashMap < Integer , String > ht )
{
long startTime = System . nanoTime ();
System . out . println ( "============Entry迭代器遍历==============" );
Integer key ;
String value ;
Iterator < Entry < Integer , String >> iter = ht . entrySet (). iterator ();
while ( iter . hasNext ()) {
Map . Entry < Integer , String > entry = iter . next ();
// 获取key
key = entry . getKey ();
// 获取value
value = entry . getValue ();
//System.out.println("Key:" + key + ", Value:" + value);
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
public static void traverseByKeySet ( HashMap < Integer , String > ht )
{
long startTime = System . nanoTime ();
System . out . println ( "============KeySet迭代器遍历==============" );
Integer key ;
String value ;
Iterator < Integer > iter = ht . keySet (). iterator ();
while ( iter . hasNext ()) {
key = iter . next ();
// 获取value
value = ht . get ( key );
//System.out.println("Key:" + key + ", Value:" + value);
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
}
Copy 运行结果
1
2
3
4
5
6
7
8
9
10
true
true
ccc
ddd
size: 4
size: 0
============Entry迭代器遍历==============
13389400纳秒
============KeySet迭代器遍历==============
12616200纳秒
Copy
LinkedHashMap
基于双向链表的维持插入顺序的HashMap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import java.util.LinkedHashMap ;
import java.util.Iterator ;
import java.util.Map ;
import java.util.Map.Entry ;
public class LinkedHashMapTest {
public static void main ( String [] args ) {
LinkedHashMap < Integer , String > hm = new LinkedHashMap < Integer , String > ();
hm . put ( 1 , null );
hm . put ( null , "abc" );
hm . put ( 1000 , "aaa" );
hm . put ( 2 , "bbb" );
hm . put ( 30000 , "ccc" );
System . out . println ( hm . containsValue ( "aaa" ));
System . out . println ( hm . containsKey ( 30000 ));
System . out . println ( hm . get ( 30000 ));
hm . put ( 30000 , "ddd" ); //更新覆盖ccc
System . out . println ( hm . get ( 30000 ));
hm . remove ( 2 );
System . out . println ( "size: " + hm . size ());
//hm.clear();
//System.out.println("size: " + hm.size());
System . out . println ( "遍历开始==================" );
Integer key ;
String value ;
Iterator < Entry < Integer , String >> iter = hm . entrySet (). iterator ();
while ( iter . hasNext ()) {
Map . Entry < Integer , String > entry = iter . next ();
// 获取key
key = entry . getKey ();
// 获取value
value = entry . getValue ();
System . out . println ( "Key:" + key + ", Value:" + value );
}
System . out . println ( "遍历结束==================" );
LinkedHashMap < Integer , String > hm2 = new LinkedHashMap < Integer , String > ();
for ( int i = 0 ; i < 100000 ; i ++ )
{
hm2 . put ( i , "aaa" );
}
traverseByEntry ( hm2 );
traverseByKeySet ( hm2 );
}
public static void traverseByEntry ( LinkedHashMap < Integer , String > ht )
{
long startTime = System . nanoTime ();
System . out . println ( "============Entry迭代器遍历==============" );
Integer key ;
String value ;
Iterator < Entry < Integer , String >> iter = ht . entrySet (). iterator ();
while ( iter . hasNext ()) {
Map . Entry < Integer , String > entry = iter . next ();
// 获取key
key = entry . getKey ();
// 获取value
value = entry . getValue ();
//System.out.println("Key:" + key + ", Value:" + value);
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
public static void traverseByKeySet ( LinkedHashMap < Integer , String > ht )
{
long startTime = System . nanoTime ();
System . out . println ( "============KeySet迭代器遍历==============" );
Integer key ;
String value ;
Iterator < Integer > iter = ht . keySet (). iterator ();
while ( iter . hasNext ()) {
key = iter . next ();
// 获取value
value = ht . get ( key );
//System.out.println("Key:" + key + ", Value:" + value);
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
}
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
true
true
ccc
ddd
size: 4
遍历开始==================
Key:1, Value:null
Key:null, Value:abc
Key:1000, Value:aaa
Key:30000, Value:ddd
遍历结束==================
============Entry迭代器遍历==============
9191900纳秒
============KeySet迭代器遍历==============
9211800纳秒
Copy HashMap遍历是无序的
LinkedHashMap遍历的顺序和它的插入的顺序保持一致
TreeMap遍历的顺序是按照大小或者compareTo方法规定的
TreeMap
基于红黑树的Map,可以根据key的自然排序或者compareTo方法进行排序输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import java.util.TreeMap ;
import java.util.Iterator ;
import java.util.Map ;
import java.util.Map.Entry ;
public class TreeMapTest {
public static void main ( String [] args ) {
TreeMap < Integer , String > hm = new TreeMap < Integer , String > ();
hm . put ( 1 , null );
//hm.put(null, "abc"); 编译没错,运行报空指针异常
hm . put ( 1000 , "aaa" );
hm . put ( 2 , "bbb" );
hm . put ( 30000 , "ccc" );
System . out . println ( hm . containsValue ( "aaa" ));
System . out . println ( hm . containsKey ( 30000 ));
System . out . println ( hm . get ( 30000 ));
hm . put ( 30000 , "ddd" ); //更新覆盖ccc
System . out . println ( hm . get ( 30000 ));
//hm.remove(2);
System . out . println ( "size: " + hm . size ());
//hm.clear();
//System.out.println("size: " + hm.size());
System . out . println ( "遍历开始==================" );
Integer key ;
String value ;
Iterator < Entry < Integer , String >> iter = hm . entrySet (). iterator ();
while ( iter . hasNext ()) {
Map . Entry < Integer , String > entry = iter . next ();
// 获取key
key = entry . getKey ();
// 获取value
value = entry . getValue ();
System . out . println ( "Key:" + key + ", Value:" + value );
}
System . out . println ( "遍历结束==================" );
TreeMap < Integer , String > hm2 = new TreeMap < Integer , String > ();
for ( int i = 0 ; i < 100000 ; i ++ )
{
hm2 . put ( i , "aaa" );
}
traverseByEntry ( hm2 );
traverseByKeySet ( hm2 );
}
public static void traverseByEntry ( TreeMap < Integer , String > ht )
{
long startTime = System . nanoTime ();
System . out . println ( "============Entry迭代器遍历==============" );
Integer key ;
String value ;
Iterator < Entry < Integer , String >> iter = ht . entrySet (). iterator ();
while ( iter . hasNext ()) {
Map . Entry < Integer , String > entry = iter . next ();
// 获取key
key = entry . getKey ();
// 获取value
value = entry . getValue ();
//System.out.println("Key:" + key + ", Value:" + value);
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
public static void traverseByKeySet ( TreeMap < Integer , String > ht )
{
long startTime = System . nanoTime ();
System . out . println ( "============KeySet迭代器遍历==============" );
Integer key ;
String value ;
Iterator < Integer > iter = ht . keySet (). iterator ();
while ( iter . hasNext ()) {
key = iter . next ();
// 获取value
value = ht . get ( key );
//System.out.println("Key:" + key + ", Value:" + value);
}
long endTime = System . nanoTime ();
long duration = endTime - startTime ;
System . out . println ( duration + "纳秒" );
}
}
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
true
true
ccc
ddd
size: 4
遍历开始==================
Key:1, Value:null
Key:2, Value:bbb
Key:1000, Value:aaa
Key:30000, Value:ddd
遍历结束==================
============Entry迭代器遍历==============
12081400纳秒
============KeySet迭代器遍历==============
19865000纳秒
Copy
Properties
继承于Hashtable
可以将K-V对保存在文件中
适用于数据量少的配置文件
继承自Hashtable的方法: clear, contains/containsValue, containsKey, get, put, remove, size
从文件加载的load方法,写入到文件中的store方法
获取属性getProperty,设置属性setProperty
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import java.io.BufferedInputStream ;
import java.io.File ;
import java.io.FileInputStream ;
import java.io.FileOutputStream ;
import java.io.IOException ;
import java.io.InputStream ;
import java.io.OutputStream ;
import java.util.Enumeration ;
import java.util.Properties ;
//关于Properties类常用的操作
public class PropertiesTest {
//根据Key读取Value
public static String GetValueByKey ( String filePath , String key ) {
Properties pps = new Properties ();
try {
InputStream in = new BufferedInputStream ( new FileInputStream ( filePath ));
pps . load ( in ); //所有的K-V对都加载了
String value = pps . getProperty ( key );
//System.out.println(key + " = " + value);
return value ;
} catch ( IOException e ) {
e . printStackTrace ();
return null ;
}
}
//读取Properties的全部信息
public static void GetAllProperties ( String filePath ) throws IOException {
Properties pps = new Properties ();
InputStream in = new BufferedInputStream ( new FileInputStream ( filePath ));
pps . load ( in ); //所有的K-V对都加载了
Enumeration en = pps . propertyNames (); //得到配置文件的名字
while ( en . hasMoreElements ()) {
String strKey = ( String ) en . nextElement ();
String strValue = pps . getProperty ( strKey );
//System.out.println(strKey + "=" + strValue);
}
}
//写入Properties信息
public static void WriteProperties ( String filePath , String pKey , String pValue ) throws IOException {
File file = new File ( filePath );
if ( ! file . exists ())
{
file . createNewFile ();
}
Properties pps = new Properties ();
InputStream in = new FileInputStream ( filePath );
//从输入流中读取属性列表(键和元素对)
pps . load ( in );
//调用 Hashtable 的方法 put。使用 getProperty 方法提供并行性。
//强制要求为属性的键和值使用字符串。返回值是 Hashtable 调用 put 的结果。
OutputStream out = new FileOutputStream ( filePath );
pps . setProperty ( pKey , pValue );
//以适合使用 load 方法加载到 Properties 表中的格式,
//将此 Properties 表中的属性列表(键和元素对)写入输出流
pps . store ( out , "Update " + pKey + " name" );
out . close ();
}
public static void main ( String [] args ) throws IOException {
System . out . println ( "写入Test.properties================" );
WriteProperties ( "Test.properties" , "name" , "12345" );
System . out . println ( "加载Test.properties================" );
GetAllProperties ( "Test.properties" );
System . out . println ( "从Test.properties加载================" );
String value = GetValueByKey ( "Test.properties" , "name" );
System . out . println ( "name is " + value );
}
}
Copy 运行结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
true
true
ccc
ddd
size: 4
遍历开始==================
Key:1, Value:null
Key:2, Value:bbb
Key:1000, Value:aaa
Key:30000, Value:ddd
遍历结束==================
============Entry迭代器遍历==============
13335400纳秒
============KeySet迭代器遍历==============
20651700纳秒
Copy 工具类
JCF中工具类
不存储数据,而是在数据容器上,实现高效操作
排序
搜索
Arrays类
排序:对数组排序,sort/parallelSort
查找:从数组中查找一个元素,binarySearch
批量拷贝:从源数组批量复制元素到目标数组,copyOf。
批量赋值:对数组进行批量赋值,fill。
等价性比较:判定两个数组内容是否相同,equals。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import java.util.Arrays ;
import java.util.Random ;
public class ArraysTest {
public static void main ( String [] args ) {
testSort ();
testSearch ();
testCopy ();
testFill ();
testEquality ();
}
public static void testSort () {
Random r = new Random ();
int [] a = new int [ 10 ] ;
for ( int i = 0 ; i < a . length ; i ++ ) {
a [ i ] = r . nextInt ();
}
System . out . println ( "===============测试排序================" );
System . out . println ( "排序前" );
for ( int i = 0 ; i < a . length ; i ++ ) {
System . out . print ( a [ i ] + "," );
}
System . out . println ();
System . out . println ( "排序后" );
Arrays . sort ( a );
for ( int i = 0 ; i < a . length ; i ++ ) {
System . out . print ( a [ i ] + "," );
}
System . out . println ();
}
public static void testSearch () {
Random r = new Random ();
int [] a = new int [ 10 ] ;
for ( int i = 0 ; i < a . length ; i ++ )
{
a [ i ] = r . nextInt ();
}
a [ a . length - 1 ] = 10000 ;
System . out . println ( "===========测试查找============" );
System . out . println ( "10000 的位置是" + Arrays . binarySearch ( a , 10000 ));
}
public static void testCopy () {
Random r = new Random ();
int [] a = new int [ 10 ] ;
for ( int i = 0 ; i < a . length ; i ++ )
{
a [ i ] = r . nextInt ();
}
int [] b = Arrays . copyOf ( a , 5 );
System . out . println ( "===========测试拷贝前五个元素============" );
System . out . print ( "源数组:" );
for ( int i = 0 ; i < a . length ; i ++ )
{
System . out . print ( a [ i ] + "," );
}
System . out . println ();
System . out . print ( "目标数组:" );
for ( int i = 0 ; i < b . length ; i ++ )
{
System . out . print ( b [ i ] + "," );
}
System . out . println ();
}
public static void testFill () {
int [] a = new int [ 10 ] ;
Arrays . fill ( a , 100 );
Arrays . fill ( a , 2 , 8 , 200 );
System . out . println ( "===========测试批量赋值============" );
System . out . print ( "数组赋值后:" );
for ( int i = 0 ; i < a . length ; i ++ )
{
System . out . print ( a [ i ] + "," );
}
System . out . println ();
}
public static void testEquality () {
int [] a = new int [ 10 ] ;
Arrays . fill ( a , 100 );
int [] b = new int [ 10 ] ;
Arrays . fill ( b , 100 );
System . out . println ( Arrays . equals ( a , b ));
b [ 9 ] = 200 ;
System . out . println ( Arrays . equals ( a , b ));
}
}
Copy
Collections类
处理对象是Collection及其子类
排序:对List进行排序,sort
搜索:从List中搜索元素,binarySearch
批量赋值:对List批量赋值,fill
最大、最小:查找集合中最大/小值,max,min
反序:将List反序排列,reverse
对象比较
对象实现Comparable接口(需要修改对象类)
compareTo方法
“>” 返回1,"==“返回0,"<” 返回-1
Arrays和Collections在进行对象sort时,自动调用该方法
新建Comparator(适用于对象类不可更改的情况)
compare方法
“>” 返回1,"==“返回0,"<” 返回-1
Comparator比较强将作为参数提交给工具类的sort方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import java.util.Arrays ;
public class Person implements Comparable < Person > {
String name ;
int age ;
public String getName () {
return name ;
}
public int getAge () {
return age ;
}
public Person ( String name , int age ) {
this . name = name ;
this . age = age ;
}
public int compareTo ( Person another ) {
int i = 0 ;
i = name . compareTo ( another . name ); // 使用字符串的比较
if ( i == 0 ) {
// 如果名字一样,比较年龄, 返回比较年龄结果
return age - another . age ;
} else {
return i ; // 名字不一样, 返回比较名字的结果.
}
}
public static void main ( String ... a ) {
Person [] ps = new Person [ 3 ] ;
ps [ 0 ] = new Person ( "Tom" , 20 );
ps [ 1 ] = new Person ( "Mike" , 18 );
ps [ 2 ] = new Person ( "Mike" , 20 );
Arrays . sort ( ps );
for ( Person p : ps ) {
System . out . println ( p . getName () + "," + p . getAge ());
}
}
}
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Person2 {
private String name ;
private int age ;
public String getName () {
return name ;
}
public int getAge () {
return age ;
}
public Person2 ( String name , int age )
{
this . name = name ;
this . age = age ;
}
}
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.util.Arrays ;
import java.util.Comparator ;
public class Person2Comparator implements Comparator < Person2 > {
public int compare ( Person2 one , Person2 another ) {
int i = 0 ;
i = one . getName (). compareTo ( another . getName ());
if ( i == 0 ) {
// 如果名字一样,比较年龄,返回比较年龄结果
return one . getAge () - another . getAge ();
} else {
return i ; // 名字不一样, 返回比较名字的结果.
}
}
public static void main ( String [] args ) {
// TODO Auto-generated method stub
Person2 [] ps = new Person2 [ 3 ] ;
ps [ 0 ] = new Person2 ( "Tom" , 20 );
ps [ 1 ] = new Person2 ( "Mike" , 18 );
ps [ 2 ] = new Person2 ( "Mike" , 20 );
Arrays . sort ( ps , new Person2Comparator ());
for ( Person2 p : ps ) {
System . out . println ( p . getName () + "," + p . getAge ());
}
}
}
Copy 运行结果
1
2
3
Mike , 18
Mike , 20
Tom , 20
Copy 文件读写
文件系统及Java文件基本操作
文件系统是由OS(操作系统)管理的
文件系统和Java进程是平行的,是两套系统
文件系统是由文件夹和文件递归组合而成
文件目录分隔符
Linux/Unix 用/隔开
Windows用\隔开,涉及到转义,在程序中需用/或\代替
文件包括文件里面的内容和文件基本属性
文件基本属性:名称、大小、扩展名、修改时间等
文件类File
java.io.File是文件和目录的重要类(JDK6及以前是唯一)
目录也使用File类进行表示
File类与OS无关,但会受到OS的权限限制
常用方法
createNewFile,delete,exists, getAbsolutePath, getName, getParent,getPath, isDirectory, isFile, length, listFiles, mkdir, mkdirs
注意:File不涉及到具体的文件内容,只涉及属性
Preview: