本篇文章的学习资源来自Java入门视频教程:Java核心技术_华东师范大学_中国大学MOOC(慕课)
本篇文章的学习笔记即是对Java核心技术课程的总结,也是对自己学习的总结
文章目录
第一章:Java概述
Java简介
- Java1995年诞生
- 出身于SUN公司,现被Oracle(甲骨文)收购
- 目标:一次编写,到处运行。兼容各种不同体系结构的CPU、操作系统
- Java是一种面向对象的语言
- 将源代码编译成字节码(bytecode,中间态)
- 然后依赖各种不同平台上的虚拟机来解释执行字节码
- 实现"一次编写,到处运行"的跨平台特性
Java三大分支:
Java SE(Standard Edition)面向PC级应用开发
Java EE(Enterprise Edition)面向企业级应用开发,学习EE主要是学习框架SSM,spring Boot
Java ME(Micro Edition)面向嵌入式应用开发
Java环境搭建
Java技术体系
Java技术体系至少包含四个部分:
1、Java程序设计语言
2、各种平台上的Java虚拟机(JVM)
3、Java API类库
4、一系列辅助工具,如javac
JDK>JRE>JVM
1+2+3+4=JDK;2+3=JRE;
注:IDE是不会编译和运行程序的。程序的编译与运行需要JDK的支持。
.NET的编译和运行(MSBuild编译器)集成在VS中,而Java开发仅有IDE是不行的,还需要依赖JDK
Java和.NET的类比:
Java包括:1、Java语言;2、JVM;3、Java API;4、JDK
.NET包括:1、多种程序设计语言(C#、VB.NET、C++.NET、J#);2、CLR;3、.NET基础类库
.NET中MSBuilder类似JDK,集成在VS中。CLR类似JVM
Java从编写到运行
编写:利用IDE等完成代码文件(.java)编写
编译:利用JDK中javac.exe将代码(.java)编译成字节码文件(.class)
运行:java.exe读入并解释字 节码文件(.class),最终在JVM上运行
第二章:Java类基础知识
一、java类结构
Java文件必须以.java作为扩展名
一个Java文件只能有一个public class
public class的名字必须与文件名字完全一致
多个class可以写在一个.java文件中,但是最多只能有一个类是public class,并且public class类的名字必须和.java的文件名相同
System.out.print输出
System.out.println输出换行
类是Java中最基本的逻辑单位
Java所有的内容都是需要放在类的范围中
内容不允许游离在类以外
换言之,Java项目就是由一个个类组成的
类的构成:
成员变量
成员函数
main函数
main函数是一个Java文件的总入口
main函数不属于成员函数
严格来说,main函数不属于这个类的所拥有函数,只是“寄存”在这个类中
二、基本类型和运算符
基本类型(8个):boolean、byte、short、int、long、float、double、char
注:
byte:-128~127,
short大小2字节,
int大小4字节,大约10位数,首位为2
long在数字末尾要加L
float在数字末尾要加f
double在数字末尾可以省略d
char是一个单一的16位Unicode字符
注:
八种基本类型的内部属性默认值分别为:
bool false
byte 0 short 0 int 0 long 0L
float 0.0f double 0.0d
char ‘\u0000’(空格)
算数运算符
- ~ >>右移 a>>1 //右移,除以2
- ~<<左移 b<<2 //左移,乘以4
三、选择和循环结构
四、自定义函数
第三章:面向对象和类
注:函数内的局部变量,编译器不会给默认值,需要初始化后才可以使用;类的成员变量,编译器会给默认值,可以直接使用
原因:类的构造函数
构造函数的有参构造函数调用无参构造函数:
class Test {
public Test() {
System.out.println("1");
}
public Test(int a) {
this();
System.out.println("2");
}
}
第四章:继承、接口和抽象类
继承
关键字:extends
单根继承原则:每个类都只能继承一个类。如果不写extends,Java类都默认继承自java.lang.Object类
注:每个子类的构造函数的第一句话,都默认调用父类的无参构造函数super(),除非子类的构造函数第一句话是super,而且super语句必须放在第一条,不会出现连续两条super语句。
抽象类和接口
抽象类:abstract,抽象类不能new
子类可以继承于抽象类,但是一定要实现父类们所有abstract的方法。如果不能完全实现,那么子类也必须被定义为抽象类。
接口:interface 关键字:implements
如果类的所有方法都没有实现,那么这个类就算是接口类
类只可以继承(extends)一个类,但可以实现(implements)多个接口,继承和实现可以同时
interface是一种特殊的类
接口可以继承多个接口,没有实现的方法将会叠加
类实现接口,必须实现所有未实现的方法。如果没有全部实现,那么只能成为一个抽象类。
接口里可以定义变量,但是一般是常量。
注:extends必须写在implements前面
抽象类和接口相同点:两者都不能被实例化,不能new操作
不同点:
抽象类(abstract) | 接口(Interface) |
---|---|
可以有部分方法实现 | 所有方法都不能实现 |
一个类只能继承(extends)一个(抽象)类 | 一个类可以实现(implements)多个接口 |
接口可以继承(extends)多个接口 | |
抽象类有构造函数 | 接口没有构造函数 |
抽象类有main函数 | 接口没有main函数 |
抽象类可以有private/protected | 接口方法都是public |
转型、多态和契约设计
-
变量支持互相转化,比如int a=(int)3.5;
-
类型可以相互转型,但是只限于有继承关系的类
子类可以转换成父类,而父类不可以转为子类
子类继承父类所有的财产,子类可以变成父类(从大到小,即向上转型);从父类直接变成子类(从小变大,即向下转型)则不允许。
父类转为子类有一种情况例外,就是这个父类本身就是从子类转化过来的。
第五章:static、final和常量设计
1、static
static方法:
- 在静态方法中,只能使用静态变量,不能使用非静态变量;
- 静态方法禁止引用非静态方法
static块:
- static块只在类第一次被加载时调用,只运行一次
- 执行顺序:static块>匿名块>构造函数
注:不建议编写块代码,因为块代码会给程序带来混淆。建议将块代码封装成函数再调用
2、单例模式
- 单例模式,又名单态模式,Singleton。
- 限定某一个类在整个程序运行过程中,只能保留一个实例对象在内存空间。
- 内存空间中,一个类只有一个对象存在,这就是单例模式
- 创建型设计模式
单例模式:保证一个类有且只有一个对象
采用static来共享对象实例
采用private构造函数,防止外界new操作
3、final
- final关键字可以用来修饰类、方法、字段
- final的类,不能被继承
- 父类中如果有final的方法,子类中不能改写此方法
- final的变量,不能再次赋值
- 如果是基本型别的变量,不能·修改其值
- 如果是对象实例,不能修改其指针,但是可以修改对象内部的值
final类:没有子类继承
final方法:不能被子类改写
final字段:基本类型不能修改值,对象类型不能修改指针
4、常量设计与常量池
常量:
- 不能修改,final(java没有const关键字,所以相当于在final充到const的位置)
- 不会修改/只读/只要一份,static
- 方便访问public
所以:java中的常量:public static final
- 一种特殊的常量:接口内定义的变量默认是常量
常量池
- Java为很多基本类型的包装类/字符串都建立常量池
- 常量池:相同的值只存储一份,节省内存,共享访问
- 基本类型的包装类:
- Boolean,Byte,Short,Integer,Long,Character,Float,Double
- Boolean:true,false
- Character:0-127
- Byte,Short,Int,Long:-128-127
- Float,Double:没有缓存(常量池)
- Java为常量字符串都建立常量池缓存机制
- 在常量池中的这些字符串不会被垃圾收集器回收
常量池的作用:
- 节约内存
- 共享访问
基本类型的包装类和字符串有两种创建方式:
- 常量式(字面式)赋值创建,放在栈内存(将被常量化)
- Integer a = 10;
- String b = “abc”;
- new对象进行创建,放在堆内存(不会常量化)
- Integer c = new Integer(10);
- String d = new String(“abc”);
- 这两种创建方式导致创建的对象存放的位置不同
- 栈内存读取速度快但容量小
- 堆内存读取速度慢但容量大
基本类型:
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和对象比较,将会使对象自动拆箱,做基本类型比较
字符串
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(s5==s7);//false
System.out.println(s6==s7);//false
System.out.println(s0==s6);//true
总结:
- Java中的常量:static和final
- Java接口中的变量都是常量
- 对象生成有两种:常量赋值(栈内存)和new创建(堆内存)
- Java为Boolean,Byte,Character,Short,Int,Long,String的常量赋值建立常量池,没有包括Float和Double
- Java编译器会优化已经确定的变量
5、不可变对象和字符串
**不可变对象:**值对象不再修改,而指针的指向可以修改
- 一旦创建,这个对象(状态/值)不能被更改了
- 其内在的成员变量的值就不能修改了
- 包括八个基本型别的包装类,String,BigInteger和BigDecimal等
可变对象:普通对象,
不可变对象优点:
- 只读,线程安全
- 并发读,提高性能
- 可以重复使用
缺点:
- 制造垃圾,浪费空间
Java字符串
- 字符串是Java使用最多的类,是一种典型的不可变对象
- String定义有2种:
- String a = “abc”;//常量赋值,栈分配内存
- String b = new String(“abc”);//new对象,堆分配内存
- 由于String不可修改,效率差
- StringBuffer/StringBuilder的对象都是可变对象
- StringBuffer(同步,线程安全,修改快速);StringBuilder(不同步,线程不安全,修改更快)
- 在程序运行当中,如果需要大量的字符串加法操作,建议使用StringBuffer或StringBuilder
第六章:package、import和classpath
package、import
- package(包),和C#中的导入引用,nameplace类似
- import(引用),和C#中的using类似
注:可以用*来引入一个目录下的所有类,但仅限于该目录下的,不包含其下的子文件夹下的目录
并且,import尽量精确,不推荐使用*,以免新增的同名程序会使得老程序报错
jar文件导出和导入
- .java文件最终会被编译成.class文件(二进制),并被分发到其他机器上使用
- jar文件,一种扩展名为jar的文件,是Java所特有的一种文件格式,用于可执行程序文件的传播
- jar文件实际上是一组class文件的压缩包
- 项目引入一个jar文件,就可以使用jar文件中的所有类(.class文件),无需类的源码(.java文件)
- jar文件与C#的dll文件类似
Java访问方法
类的权限:
- public
- default
内部类的权限:
- public
- protected
- default
- private
第七章 Java常用类
1、Java类库概述
Java类库主要包含Java、javac、org三个
- java.io.* 数据流、对象序列、文件系统的输入输出
- java.lang.* Java编程语言的基础类库
- java.math.* 基本数学函数
- java.text.* 格式化文本
- java.time 日期、时间类
- java.util.* 包括集合类、时间处理模式、日期时间工具等各类常用工具包
2、数字相关类
Java数字类
- 整数 Short,Int,Long
- 浮点数 Float,Double
- 大数类 BigInteger(大数类),BigDecimal(大浮点数)
- 随机数Random
- 工具类Math
Random随机数用法
- nextInt()返回一个随机int
- nextInt(int a)返回一个[0,a)之间的随机int
- nextDouble()返回一个[0.0,1.0]之间double
- ints方法批量返回随机数数组
- Math.random()返回一个[0.0,1.0]之间double
Math函数用法
- 绝对值abs
- 对数log
- 比较函数max\min
- 幂函数pow
- 四舍五入函数round
- 向下取整floor
- 向上取整ceil
3、字符串相关类
- 是一个不可变对象,加减操作性能较差
- 常用方法:
- charAt() 返回第x个元素
- indexOf(d) 返回第一个d的位置
- concat() 连接一个新字符串并返回,但原字符串不变化
- contain()包含操作
- endsWith()是否以…结尾
- equals()判断是否等于 equalsIgnoreCase()忽略大小写
- length()返回长度
- trim()去除前后空格
- split(d)将字符串按照d分割成数组
- substring(num1,num2)截取第num1到num2的字符,原字符串不变
可变字符串
- StringBuffer(字符串加减,同步,性能好)
- StringBuilder(字符串加减,不同步,性能更好)
- append/insert/delete/replace/substring
- length字符串实际大小,capacity字符串占用空间大小
4、时间相关类
-
java.util.Date(基本废弃,Deprecated)
-
java.sql.Date(和数据库对应的时间类)
-
Calendar是目前程序中最常用的,但是是抽象类
-
Calendar gc=Calendar.getInstance(); Calendar gc=new GregorianCalendar();
- get(Field) 来获取时间中每个属性的值。注意,月份0-11
- getTime() 返回相应的Date对象
- getTimeInMillis(),返回自1970.1.1以来的毫秒数
-
Calendar instance = Calendar.getInstance();
int year = instance.get(Calendar.YEAR);
int month = instance.get(Calendar.MONTH) + 1;
int day = instance.get(Calendar.DAY_OF_MONTH);
int hour = instance.get(Calendar.HOUR);
int hour1 = instance.get(Calendar.HOUR_OF_DAY);
int minute = instance.get(Calendar.MINUTE);
int second = instance.get(Calendar.SECOND);
int weekday = instance.get(Calendar.DAY_OF_WEEK);
4、java.time
- LocalDate:日期类
- LocalTime:时间类
- LocalDateTime:LocalDate+LocalTime
- Instant:时间戳
LocalDate today=LocalDate.now();
//根据指定时间创建LocalDate
LocalDate firstDay=LocalDate.of(2001, Month.JANUARY,1);
5、格式化相关类
java.text.Format包
-
NumberFormat:数字格式化,抽象类
- DecimalFormat
-
MessageFormat:字符串格式化
-
MessageFormat.format(mess,array); String world = MessageFormat.format("hello{0}", "world");
-
-
DateFormat:日期/时间格式化,抽象类
- SimpleDateFormat 工厂模式
- parse:将字符串格式化为时间对象
- format:将时间对象格式化为字符串
- SimpleDateFormat 工厂模式
第八章:Java异常处理与分类
1、Java异常分类
分类一:
- Throwable:所有错误的祖先
- Error:系统内部错误或者资源耗尽。不管
- Exception:程序有关的异常。重点关注。
- RuntimeException:程序自身的错误
- 5/0,空指针,数组越界…
- 非RuntimeException:外界相关的错误
- 打开一个不存在的文件
- 加载一个不存在的类…
- RuntimeException:程序自身的错误
分类2:
- Unchecked Exception:(编译器不会辅助检查的,需要程序员自己管的)异常,包括Error子类和RuntimeException子类。以发生前预防为主
- Checked Exception:(编译器会辅助检查的)异常,非RuntimeException子类。以发生后处理为主
2、Java异常处理
try-catch-finally
try-catch-finally快捷键:
选中想被 try / catch / finally 包围的语句,同时按下 Ctrl + Alt + T
注:若catch内部再次发生异常,也不影响finally的正常运行。异常发生时,先执行finally,再程序报错
- catch块可以有多个,但一个异常只能进入一个catch块
- catch块的异常匹配从上到下
- 所以一般是将小的异常写在前面,一些大(宽泛)的异常写在后面
throw(手动抛出异常)
- 调用带有throws异常的方法,要么处理这些异常,或者再次向外throws,直到main函数为止
try块与throw的异同:
try块与throw的目的相同,用途不同。
- 都是捕获异常。try块是捕获异常并抛出异常,throw向外抛异常
- 底层用throw抛出异常,经过多层处理,在顶层try捕获异常,并作出相应处理
3、自定义异常
-
自定义异常,需要继承Exception类或其子类
- 继承自Exception,就变成Checked Exception
- 继承自RuntimeException,就变成Unchecked Exception
-
自定义重点在构造函数
- 调用父类Exception的message构造函数
- 可以自定义自己的成员变量
-
在程序中采用throw主动抛出异常
-
在方法内部程序中,抛出异常采用throw关键字;在方法头部声明中,声明异常采用throws关键字
自定义异常类:
public class MyExceptionTest extends Exception {
private String returnCode;//异常对应的返回码
private String returnMsg;//异常对应的描述信息
public MyExceptionTest() {
super();
}
public MyExceptionTest(String returnMsg) {
super(returnMsg);
this.returnMsg = returnMsg;
}
public MyExceptionTest(String returnCode, String returnMsg) {
super();
this.returnCode = returnCode;
this.returnMsg = returnMsg;
}
public String getReturnCode(){
return returnCode;
}
public String getReturnMsg(){
return returnMsg;
}
}
public static void main(String[] args) {
try {
MyExceptionTestTest.TestException();
} catch (MyExceptionTest e){
e.printStackTrace();
System.out.println("e.getReturnCode() = " + e.getReturnCode());
System.out.println("e.getReturnMsg() = " + e.getReturnMsg());
}
}
//这是一个测试自定义异常的方法
public static void TestException() throws MyExceptionTest{
throw new MyExceptionTest("10001","The reason of myException");
}
public static void main(String[] args) throws MyExceptionTest {
int a = 9 / 3;
if (a == 3) {
throw new MyExceptionTest("1001", "a=3");
}
}
第九章:Java数据结构
1、数组
- 数组是一个存放多个数据的容器
- 数据是同一种类型
- 所有的数据是线性规则排列
- 可通过位置索引来快速定位访问数据
- 需明确容器的长度
Java数组的定义和初始化
int a[];
int[] b;//还没有new操作,实际上是null,也不知道内存位置
int[] c = new int[2];//c有两个元素,都是0
int[] d = new int[]{0,2,4};
数组初始化两种方式:
-
动态初始化(指定长度),在创建数组时,直接指定数组中元素的个数
String[] arr = new String[2];
-
静态初始化(指定内容),在创建数组时,不指定数组长度,赋值内容,由编译器自动判断数组长度
int[] arr1 = new int[]{5, 15, 25};
-
静态初始化,格式可以省略一下
int[] arr2 = {5, 15, 25};
-
2、JCF(容器):Java Collection Framework
-
容器:能够存放数据的空间结构
- 数组/多维数组,只能线性存放
- 列表/散列集/树/…
-
容器框架:为表示和操作容器而规定的一种标准体系结构
- 对外的接口:容器中所能存放的抽象数据类型
- 接口的实现:可复用的数据结构
- 算法:对数据的查找和排序
-
容器框架优点:提高数据存储效率,避免程序员重复劳动
-
JCF的集合接口是Collection
-
add,contains,remove,size
-
iterator(迭代器接口)
迭代:迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。
- hasNext 判断是否有下一个元素
- next 获取下一个元素
- remove 移除某一个元素
-
-
JCF主要的数据结构实现类:
- 列表(ArrayList,LinkedList,Vector)
- 集合/散列集(Set,HashSet,TreeSet,LinkedHashSet)
- 映射(Map,HashMap,TreeMap,LinkedHashMap)
-
JCF主要的算法类(工具类)
- Arrays:对数组进行查找和排序等操作
- Collections:对Collection及其子类进行排序和查找操作
3、列表List
-
有序的Collection
-
允许重复元素 {1,2,4,{5,2},1,3}
-
List主要实现
- ArrayList(非同步的)
- LinkedList(非同步)
- Vector(同步)
-
ArrayList:
- 缺点:以数组实现的列表,不支持同步
- 利用索引位置可以快速定位访问
- 不适合指定位置的插入、删除操作(会导致后面数据的大规模移动)
- 适合变动不大,主要用于查询的数据
- 和数组相比,其容量是可动态调整的
- ArrayList在元素填满容器时会自动扩充容器大小的50%
- ArrayList遍历方式
- Iterator遍历(最慢)
- 索引位置遍历
- foreach遍历
/** * Iterator遍历ArrayList的方法 */ private static void testArrayListIterator(ArrayList<Integer> a1) { long startTime = System.nanoTime(); System.out.println("Iterator遍历"); Iterator<Integer> iter1 = a1.iterator(); while (iter1.hasNext()) { iter1.next(); } long endTime = System.nanoTime(); long duration = endTime - startTime; System.out.println("duration = " + duration); } /** * 索引位置遍历ArrayList */ private static void testIndexArrayList(ArrayList<Integer> a1) { long startTime = System.nanoTime(); System.out.println("Index遍历"); for (int i = 0; i < a1.size(); i++) { a1.get(i); } long endTime = System.nanoTime(); long duration = endTime - startTime; System.out.println("duration = " + duration); }; /** * foreach位置遍历ArrayList */ private static void testForeachArrayList(ArrayList<Integer> a1) { long startTime = System.nanoTime(); System.out.println("Foreach遍历"); for (Integer item : a1) { ; } long endTime = System.nanoTime(); long duration = endTime - startTime; System.out.println("duration = " + duration); }
-
LinkedList
- 以双向链表实现的列表,不支持同步
- 可被当做堆栈、队列和双端队列进行操作
- 顺序访问高效,随机访问较差,中间插入和删除高效
- 适合于经常变化的数据
- LinkList遍历方式
- Iterator遍历
- 索引位置遍历(最慢)
- foreach遍历
ArrayList与LinkedList比较:ArrayList适用于较多查询的(静态数据),LinkedList适用于频繁增删的数据
- Vector(同步)
- 和ArrayList类似,可变数组实现的列表
- Vector同步,适合在多线程下使用
- 官方文档建议:在非同步情况下,优先采用ArrayList
- 同步采用Vector,非同步情况下,根据数据操作特点选取ArrayList/LinkedList
4、集合Set
集合Set:
- 确定性:对任意对象都能判定其是否属于某一个集合
- 互异性:集合内每个元素都是不相同的,注意是内容互异
- 无序性:集合内的顺序无关
Java中的集合接口Set
- HashSet(基于散列函数的集合,无序,不支持同步)
- TreeSet(基于树结构的集合,可排序的,不支持同步)
- LinkedHashSet(基于散列函数和双向链表的集合,可排序的,不支持同步)
HashSet:
-
基于HashMap实现的,可以容纳null元素,不支持同步
-
同步操作:Set s = Collections.synchronizedSet(new HashSet<>());
-
-
add/clear/contains/remove/size
-
retainAll计算两个集合的交集
-
遍历方法
- Iterator迭代器
- foreach(快)
LinkedHashSet:
-
继承HashSet,也是基于HashMap实现的,可以容纳null元素,有序的,不支持同步
-
同步操作:Set s = Collections.synchronizedSet(new LinkedHashSet<>());
-
-
方法与HashSet基本一致。HashSet无序,而LinkedHashSet有序
-
通过一个双向链表维护插入顺序
TreeSet:
-
基于TreeMap实现,不可以容纳null元素,不支持同步
-
同步操作:SortedSet s = Collections.synchronizedSortedSet(new TreeSet<>());
-
-
add/clear/contains/remove/size
-
TreeSet是按照所存储对象大小升序输出的
-
根据compareTo方法或指定Comparator排序
HashSet/LinkedHashSet/TreeSet三者比较
-
HashSet/LinkedHashSet/TreeSet三者的元素都只能是对象
-
HashSet是无序输出的;LinkedHashSet是按照插入顺序进行遍历输出的;TreeSet是按照所存储对象大小升序输出的
-
判定元素重复原则:
-
HashSet和LinkedHashSet判定元素重复:
- 判定两个元素的hashCode返回值是否相同,若不同,则返回false;
- 若hashCode相同,判定equals方法,若不同,返回false;否则返回true
- hashCode和equals方法是所有类都有的,因为Object类有
-
TreeSet判定元素重复原则:
-
需要元素继承自Comparable接口
-
比较两个元素的CompareTo方法
-
-
这3个方法三位一体:
- equals()是相同的;
- hashCode()是相同的;
- toString()也应该是相同的
-
Java的四个重要接口
- Comparable:可比较的
- Clonable:可克隆的
- Runnable:可线程化的
- Serializable:可序列化的
-
5、映射Map
Map映射
- 数学定义:两个集合之间的元素对应关系
- 一个输出对应到一个输出
- {1,张三},{Key,Value},键值对,K-V对
Java中Map
- HashTable(同步,慢,数据量小);
- HashMap(不支持同步,快,数据量大);
- Properties(同步,文件形式,数据量小)
HashTable
- K-V对,K和V都不允许为null
- 同步,多线程安全
- 无序的
- 适合小数据量
- clear/contains/containsValue/containsKey/get/put/remove/size
- contains等同于containsValue
- get根据key获取相应的值,返回Value
- put增加新的K-V对
- remove删除某一个K-V对
- 遍历方法
- 根据Entry迭代器遍历
- 根据Key的Iterator遍历
- 根据Key的Enumeration遍历(老接口,只读)
public static void main(String[] args) {
Hashtable<Integer, String> integerStringHashtable = new Hashtable<>();
for (int i = 0; i < 10000; i++) {
integerStringHashtable.put(i, "aaa");
}
traverseByEnter(integerStringHashtable);
traverseByKeyIterator(integerStringHashtable);
traverseByKeyEnumeration(integerStringHashtable);
}
private static void traverseByEnter(Hashtable<Integer, String> ht) {
long startTime = System.nanoTime();
System.out.println("Entry迭代器遍历");
Integer key;
String value;
Iterator<Map.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();
}
long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println("duration = " + duration);
}
private static void traverseByKeyIterator(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);
}
long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println("duration = " + duration);
}
private 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);
}
long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println("duration = " + duration);
}
HashMap:
- K-V对,K和V都允许为null
- 不同步,多线程,不安全
- 无序的
- 主要方法与HashTable类似
- 遍历方法
- 根据Entry迭代器遍历
- 根据Key的Iterator遍历
LinkedHashMap
- 基于双向链表的维持插入顺序的HashMap
TreeMap
- 基于红黑树的Map,可以根据key的自然排序或者compareTo方法进行排序输出
Properties
- 继承于HashTable
- 可以将K-V对保存在文件中
- 适用于数据量小的配置文件
- 继承自HashTable的方法:clear/contains/containsValue/containsKey/get/put/remove/size
- 从文件加载的load方法,写入到文件中的store方法
- 获取属性getProperty,设置属性setProperty
总结:
- HashMap是最常用的映射结构
- 如需排序,考虑LinkedHashMap和TreeMap
- 如需将K-V存储为文件,可采用Properties
6、工具类
JCF中工具类
- 不存储数据,而是在数据容器上,实现高效操作
- 排序
- 搜索
- Arrays类
- Collections类
Arrays:处理对象是数组
- 排序:对数组排序,sort/parallelSort
- 查找:从数组中查找一个元素,binarySearch
- 批量拷贝:从源数组批量复制元素到目标数组,copyOf
- 批量赋值:对数组进行批量赋值,fill
- 等价性比较:判定两个数组内容是否相同,equals
Collections:处理的对象是Collection及其子类
- 排序:对List进行排序,sort
- 搜索,从List中搜索元素,binarySearch
- 批量赋值:对List批量赋值,fill
- 最大最小:查找集合中最大/最小值,max,min
- 反序:将List反序排列,reverse
对象比较
- 对象实现Comparable接口(需要修改对象类)
- compareTo方法
- >返回1,==返回0,<返回-1
- Arrays和Collections在进行对象sort时,自动调用该方法
- compareTo方法
- 新建Comparator(适合于对象类不可更改的情况)
- compare方法
- >返回1,==返回0,<返回-1
- Comparator比较器将作为参数提交给工具类的sort方法
- compare方法
第十章:Java文件读写
1、文件系统及Java基本操作
Java文件类File
- java.io.File
- 常用方法:createNewFile,delete,exists,getAbsolutePath,getName,getParent,getPath,isDirecotry,isFile,length,listFiles,mkdir,mkdirs
- createNewFile创建新文件(非目录)
- mkdir:创建一级(一层)目录;mkdirs:创建多级(多层)目录
- isDirectory是否是目录;isFile是否是目录
- getName,获取文件名字;getParent获取上一层目录路径;getPath获取文件全路径;length获取文件大小;lastModifiedTime返回文件最后一次修改时间
- listFiles列出当前目录的所有子文件,但不包括子目录下的文件
- File不涉及到具体的文件内容,只涉及属性
- **注:**java中目录和文件都是采用File类
NIO包:是java.io.File的有益补充
- Path类
- file的移动(move)、复制、属性访问…
2、Java io包概述
- Java读写文件,只能以(数据)流的形式进行读写
- java.io流中包括字节流、字符流、其他流(System)、文件处理
- java.io包中
- 节点类:直接对文件进行读写
- 包装类
- 转化类:字节/字符/数据类型的转化类
- 装饰类:装饰节点类
- 节点类:直接操作文件类
- InputStream.OutputStream(字节)
- FileInputStream,FileOutputStream
- Reader,Writer(字符)
- FileReader,FileWriter
- InputStream.OutputStream(字节)
- 转换类:字符到字节之间的转化
- InputStreamReader:文件读取时字节,转换为字符
- OutputStreamWriter:Java向文件输出时,字符转换为字节
- 装饰类:装饰节点类
- DataInputStream,DataOutputStream:封装数据流
- BufferInputStream,BufferOutputStream:缓存字节流
- BufferedReader,BufferedWriter:缓存字符流
3、文本文件读写
- 文件类型
- 一般文本文件(若干行字符构成的文件),如txt等
- 一般二进制文件,如数据文件dat,照片文件等
- 带特殊格式的文本文件,如xml
- 带特殊格式的二进制文件,如doc,ppt等
- 文件很大,注定了Java只能以流形式依次处理
写文件:
-
FileOutputStream,OutputStreamWriter,BufferedWriter
- FileOutputStream:往文件写字节
- OutputStreamWriter:字节和字符转化
- BufferWriter:写缓冲区类,加速写操作
- write
- newLine //换行
-
try-resource语句,自动关闭资源
-
关闭最外层的数据流,将会把其上所有的数据流关闭(所以关闭时只需关闭最外层的流)
private static void WriteFile(){
try (BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("f:/abc.txt")))){
bw.write("我们是");
bw.newLine();
bw.write("abc");
} catch (Exception exception){
exception.printStackTrace();
}
};
注:try后面跟上(),在try结束后会自动释放()内的资源
读文件:
-
与写文件类似
-
FileInputStream,InputStreamReader,BufferedReader
-
BufferReader:readLine
-
FileInputStream字节类,负责读字节 InputStreamReader转化类,负责字节到字符转化 BufferedReader装饰类,负责从缓冲区读入字符 三者构建关系: BufferedReader(InputStreamReader(FileInputStream))
-
总结:
- 理解节点类、转换类和包装类的联合用法
- 尽量使用try-resource语句,自动关闭资源
4、二进制文件读写
- 二进制文件
- 狭义上说,采用字节编码,而非字符编码的文件
- 广义上说,一切文件都是二进制文件
- 用记事本等无法打开或阅读
写文件:
- FileOutputStream,BufferedOutputStream,DataOutputStream
- DataOutputStream
- flush 刷新缓存
- write/writeBoolean/writeByte/writeChars/writeDouble/writeInt/WriteUTF/…
- try-resource语句,自动关闭内存
- 关闭最外层的数据流,将会把其上所有的数据流关闭(所以关闭时只需关闭最外层的流)
读文件:
- FileInputStream,BufferedInputStream,DataInputStream
- DataInputStream
- read/readBoolean/readChar/readDouble/readFloat/readInt/readUTF/…
private static void ReadBinFile() {
try (DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream("f:/abc.dat")))) {
String a, b;
int c, d;
a = dis.readUTF();
c = dis.readInt();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
5、Zip文件读写
zip文件操作类:java.util.zip中
- ZipInputStream,ZipOutputStream压缩文件输入/输出流
- ZipEntry压缩项
单个/多个压缩
- 打开输出zip文件
- 添加一个ZipEntry
- 打开一个输入文件,读数据,向ZipEntry写数据,关闭输入文件
- 重复以上步骤,写入多个文件到zip文件中
- 关闭zip文件
单个文件压缩:
public static void main(String[] args) throws IOException {
File file = new File("F:/abc.txt");//定义要压缩的文件
File zipFile = new File("F:/abc.zip");//定义压缩文件名称
InputStream input = new FileInputStream(file);//定义文件的输入流
ZipOutputStream zipOut = null;//声明压缩流对象
zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
zipOut.putNextEntry(new ZipEntry(file.getName()));//设置zipEntry对象
zipOut.setComment("single file zip");//设置注释
//压缩过程
int temp = 0;
while ((temp = input.read()) != -1) {//读取内容
zipOut.write(temp);//压缩输出
}
input.close();//关闭输入流
zipOut.close();//关闭输出流
System.out.println("single file zip done");
}
单个/多个解压: