Java语言三大平台
JavaSE: Java PlatForm Standrad Edtion
-- Java标准版
-- 适用于开发桌面型, C/S架构型的应用程序
-- C/S: Client/Server(客户端/服务器)
-- B/S: Browser/Server(浏览器/服务器)
JavaEE: Java PlatForm Enterprise Edtion
-- Java企业版(基于B/S架构的应用程序)
JavaME: Java PlatForm Micro Edtion
-- Java微型版(嵌入式, 手机应用开发)
Java特性:
1. 面向对象
2. 跨平台(一次编译, 到处运行)
3. 健壮性
4. 安全性(强类型语言, 取消指针)
跨平台实现:
1. 源代码
2. 将源代码(.java)编译成为字节码(.class)
3. 字节码文件运行在JVM(Java虚拟机)中
5. 实现跨平台(一次编译, 到处运行), 是通过不同的系统所对应的JVM实现
Java核心机制:
1. JVM: Java虚拟机(Java Virtual Machine)
2. GC: 垃圾回收器(Garbage Collection)
GUI: 图形化用户接口
AWT
Swing
JVM: Java虚拟机(Java Virtual Machine)
-- 运行Java应用程序
JRE: Java运行时环境(Java Runtime Envirment)
-- 提供Java的基础jar包
-- 包含JVM
JDK: Java开发工具包(Java Development Kit)
-- 开发所需要的工具
-- 包含JRE
开发Java应用程序步骤:
1. 编写源代码
2. 将源代码编译成为字节码
-- javac
-- javac 源代码文件名.扩展名
3. 运行字节码
-- java
-- java 字节码文件
-- 注意:不能加文件扩展名
访问修饰符
public class HelloWorld{
public static void main(String[] args){
System.out.println("Hello World......");
}
}
public: 访问修饰符
class: 类修饰符
HelloWorld: 类名
-- 类名必须与文件名相同(大小写区分)
声明程序入口(格式固定)
public static void main(String[] args){
}
一个源代码文件中可以有多个class, 但只能有一个class被public修饰
-- 被public修饰的class类名必须与文件名相同
Java语言严格区分大小写
Java语言中所有的符号均为半角符号
每条语句必须以分号结束
Java注释:
1. //: 单行注释
-- 将双斜杠后的内容不做任何处理
2. /* 注释内容 */ : 多行注释
-- 一般作用于对多行代码的注释
3. /** 注释内容 */ : 文档注释
-- 声明在类上或方法上
类名, 方法名, 参数名, 变量名...
-- 开发人员自行命名的东西
都称之为标识符
标识符命名规则:
1. 由字母、数字、特殊符号(下划线_、美元符号$)组成
2. 不能以数字开始
3. 长度无限制
4. 尽量使用英文单词命名
-- 拼音
5. 不能使用Java中的保留字与关键字
见名知意
常量: 在应用程序中不能被修改的值
常量命名: 全部大写, 多个单词之间使用下划线分隔
final int COUNT = 20;
使用关键字 final 表示常量
""表示字符串
字符串: 由多个字符组成的内容
"a"
''表示字符
字符: 由单个字符组成
'a'
"abc"
Java中的八种(四大类)基本数据类型:
1. 整型数值
1.1 字节: byte(在内存占用8位, 8个bit)
1.2 短整型: short(在内存中占用16位,2个字节)
1.3 整型: int(在内存中占用32位, 4个字节)
1.4 长整型: long(在内存中占用64位, 8个字节)
2. 浮点数值
2.1 单精度浮点值:float (在内存中占用32位, 4个字节)
2.2 双精度浮点值:double(在内存中占用64位, 8个字节)
3. 字符
3.1 字符: char(在内存中占用16位,2个字节)
4. 布尔
4.1 布尔:boolean(在内存中占用8位, 一个字节)
true, false
1 0
特殊类型: 引用类型/对象类型
数据类型转换:
- 自动升级
a) 在做运算过程中,级别低的数据类型自动升级为高级别的
b) byte, short, char在运算时自动升级成为int类型
c) byte->short/char->int->long->float->double
- 强制转换
a) 将高级别的数据类型强制转换成为低级别
b) 将运算之后产生的数据类型强制转换为指定的数据类型
c) 强制转换可能后造成数据精度丢失, 所以要小心使用
变量:
是一个可以在内存中保存数据的内存地址
在数据使用之前必须先向内存申请地址(声明变量)
在变量第一次使用之前必须先给变量赋值
相同的变量名称在作用域范围之内不允许重复声明定义, 但可以重新赋值
一次声明一个变量 :int num;
一次声明一个变量并赋值: int num = 123;
一次声明多个变量: int n, m, I, k;
一次声明多个变量并赋值:int n = 1, m = 2, i = 3, k = 4;
按声明的位置:
- 局部变量
a) 有效范围只在当前所属的大括号之内
- 成员变量/成员属性/全局变量
a) 有效范围在当前的类中
类中包含:
- 成员属性
- 成员方法
- 构造方法
- 基本类型变量
按声明的数据类型划分:
a) 声明的数据类型为八种基本类型
- 引用类型变量/对象类型
a) 除基本类型之外的类型
程序执行过程:
- 将源代码编译成为字节码
- 将字节码加载至内存中
- 内存区域划分为
a) 方法区
- 类信息, 类变量(静态变量), 常量池
b) 堆栈区
- 保存的是局部变量
- 如果在引用变量, 则保存引用对象的内存地址值
c) 堆区
- 保存的是引用对象
运算符
+、-、*、/、%、++、--
前++、后++: 对指定的值进行加1、减1的运算
前++:先将变量的值加1之后再处理
后++:先将变量进行处理之后再进行加1
逻辑运算符
&&:逻辑与
所有的表达式全部为true, 结果为true
如果有一个为false,结果为false
||:逻辑或
表达式中有一个结果为true, 结果为true
如果有一个表达式的结果为true, 那么后面所有的表达式将不会参与运算
!:取反
位运算(将数值转换为二进制进行运算)
~:按位取反
遇0得1, 遇1得0
&:按位与
有一个为0,结果为0
|:按位或
有一个为1, 结果为1
^:按位异或
相同为0, 不同为1
0000 0001 0000 0001 0000 0001
& 0000 0000 | 0000 0000 ^0000 0000
—————— —————— ——————
0000 0000 0000 0001 0000 0001
位移运算
有符号
<< : 左移, 低位补0
>>:右移, 高位被补符号位(之前符号位为0补0, 之前符号位为1被1)
无符号
>>> 右移, 高位补0
表达式:
- 表达式运算之后的值需要与声明的变量的数据类型一致
- 运算符的优先级使用小括号提升即可
程序流程控制
- 顺序结构
a) 程序代码由上自下顺序执行
- 选择结构
a) 通过让指定的代码在满足指定条件的情况下执行
- if…else…
- switch…case…default
- 循环结构
a) 指定的代码被执行N次(N次由循环条件决定)
- for循环
- do…while循环
- while…循环
三种循环的区别
- do…while是先执行一次, 再判断条件
- while是先判断条件, 根据表达式的值决定是否执行
- for循环固定循环次数
a) 明确确定循环次数的确定下优先使用for
循环特殊控制:
- break: 跳出当前循环体
- continue:跳出当前循环, 继续下一次循环
进制之间的转换
十进制:逢10进1
二进制:逢2进1
八进制:逢8进1
十六进制:逢16进1 (0-9、A、B、C、D、E、F)
方法: 面向对象语言中的一种叫法
将能够实现某一种特定的功能的代码声明在某一段语句块之内,然后在需要实现该功能的地方调用
该语句块可以声明成为一个方法
-- 在一个类中方法不能够够重复声明
声明语法:
[访问控制修饰符] [静态修饰符] [常量修饰符] 返回类型 方法名称(参数列表){
方法体实现代码
}
返回类型: 每个方法必须指定相应的返回类型(数据类型)
-- 返回值使用关键字 return指定
-- 如果方法没有返回值, 必须声明为void
参数列表语法:数据类型 参数名称[,数据类型2 参数名2,…]
方法调用:
在需要实现指定方法的功能时, 直接调用即可
调用方式:
- 在本类中调用
a) 直接指定方法名并且给定相应的参数即可
- 在不同类中调用
a) 需要使用类名.方法名([参数值列表])
- 如果被调用的方法为非静态方法
a) 对象名.方法名([参数值列表))
参数:
- 实参: 调用方法时给定的实际值
- 形参:在方法声明时指定的参数
程序代码是顺序执行, 如果在代码中调用了指定的方法, 则先执行该方法中的代码, 方法中的代码执行完毕之后, 返回至原调用的地方, 再按顺序向下执行其它代码
方法参数:
- 参数长度/参数个数必须相同
- 参数的数据类型必须一一对应
- 形参与实参的名称可以不同
返回类型
- 方法无返回时必须声明 void
- 如果有返回值, 方法声明中必须指定对应的返回数据类型, 而且方法最后必须使用return返回一个具体的值
- 方法声明的返回类型必须与return 的数据类型一致
- 接收返回值的数据类型必须方法声明的返回类型一致
- 如果方法没有声明返回的具体数据类型(声明为void), 方法体中可以使用return关键字,但return表示结束当前方法的运行,直接返回至调用的地方
a) 需要注意reutrn 关键字的逻辑问题导致编译无法通过
方法的重载(overload)
在一个类中可以重复定义同名的方法
- 方法重载必须在同一个类中
- 参数个数不能同
- 如果参数个数相同, 参数的数据类型不同
a) 在调用方法时,优先匹配数据类型相同的方法
- 如果参数个数相同, 且数据类型相同, 参数声明的顺序不能相同
- 方法声明的返回类型不影响重载
数组:
作用: 一个变量中可以保存多个值, 所有值的数据类型必须相同
数组的数据类型属于对象类型/引用类型
-- 引用变量保存在栈中的是一个指向堆内存的引用地址
声明语法:
数据类型[] 数组名称;
int[] arr; ―― Java规范
//int arr[]; 不建议使用此方式
数组初始化方式:
- 静态初始化:在声明数组时进行初始化赋值
a) int[] array = {10, 20, 30};
b) 声明并且赋值之后, 数组长度也就确定
- 动态初始化:在使用前进行初始化赋值
a) int[] array = new int[数组长度];
b) int[] array = new int[5];
c) array[0] = 12; array[1] = 23; array[4] = 123;
访问数组元素的方式
通过元素对应的索引/下标来访问
第一元素对应的索引值为0
array[索引值] -> array[0]
array[1], array[2]
数组对象提供了一个length的属性, 方便获取该数组的长度
―― 获取元素个数
―― 数组中最后一个元素的下标数组长度减一
数组长度一旦确定, 不能修改
可变参数:
方法的参数个数是未知的, 但数据类型必须确定
语法:
数据类型… 参数名称
public void test(int… params){
方法体代码;
}
可变参数按照数组的方式去处理
注: 可变参数必须声明在参数列表的最后
冒泡排序(Bubble Sort)
v 原理:将相邻的两个元素进行比较, 如果不等,则进行交换
顺序查找: 从第一个元素开始顺序比较查找
二分查找: 又称折半查找. 从已排序的数组中进行查找
– 首先确定该查找区间的中间点位置: int mid = (low+upper) / 2;
– 然后将待查找的值与中间点位置的值比较:
– 若相等,则查找成功并返回此位置。
– 若中间点位置值大于待查值,则新的查找区间是中间点位置的左(或右)边区域。
– 若中间点位置值小于待查值,则新的查找区间是中间点位置的右(或左)边区域。下一次查找是针对新的查找区间进行的。
二维数组
一维数组中嵌套一维数组
语法
数据类型[][] 数组名;
数据类型[][] 数组名 = new int[行数][];
数据类型[][] 数组名 = new int[行数][列数];
初始化:
- 静态初始化
a) 数据类型[][] 数组名 = {{1,2, 3}, {2, 3, 4}, {3, 4,5}};
b) 数据类型[][] 数组名 = new数据类型[][]{{1, 2, 3}, {2, 3, 4}, {3, 4,5}};
- 动态初始化
堆栈
保存局部变量的值, 相对于引用变量保存的是内存地址
堆
保存的是对象的所有成员属性的值
方法区: 类的信息
数据区: 静态变量的值与常量值及字符中常量值
静态方法:
本类中调用: 直接使用方法名(参数列表)
非本类中调用: 类名.方法名(参数列表)
-- 也可以以 对象名.方法名(参数列表) 的方式被调用
非静态方法:
本类中调用: 直接使用方法名(参数列表)
非本类中调用: 对象名.方法名(参数列表)
注: 在静态方法中不能直接访问非静态成员(成员属性/成员方法)
在非静态方法中可以直接调用静态成员
方法参数传递:
- 以值的方式传递
- 以引用的方式传递
Java中参数传递是以值的方式时行 传递
在被调用的方法中, 如果修改参数(形参)值, 不会影响调用之前的实参的值
在传递的过程中, 将实参的值复制一份交给形参
-- 形参是实参的一个副本
基本数据类型传递的是实际的值
引用类型传递的是对象的引用地址
面向对象的三大特征
- 封装
- 继承
- 多态
封装: 将类中的成员隐藏起来, 对外部不可见(外部不可以直接访问)
-- 关键字: private 私有的,
可以修饰成员属性, 成员方法, 构造器
不能将类修饰成为private
被private修饰的成员, 只能在本类中访问, 在其它类中, 不能访问
将成员属性声明为private, 然后提供对应的公共的(public)get/set方法以方便获取/修改其值
-- 将类中所有的成员属性修饰为private
-- 类中所有的成员方法修饰为public
Person p = new Person();
它在内存中做了哪些事情?
答案:
A :将 Person.class 文件加载到内存中。
B :在堆内存中创建一个对象 Person 。
C :把 Person 中的属性进行默认初始化。
D :把 Person 中的属性进行显示初始化。
E :调用构造代码块( 如果没有,不执行这个操作) 。
F :调用构造函数进行初始化。
G :在栈内存中声明 Person 类型的变量 P 。
H :把堆内存的地址( 引用) 赋给了栈内存中 P
抽象类
具体类: 对现实世界的具体事物进行描述
抽象类: 对现实世界中的某一种事物进行描述
-- 所有事物都有共同的行为, 但实现方式不同
-- 在抽象类中对行为不进行实现, 而是由具体子类去实现该行为
-- 抽象类中可以包含抽象方法, 也可以包含成员方法
使用关键字 abstract 声明抽象类
抽象类中可以有抽象方法
-- 没有方法体
-- 抽象方法必须使用abstract 关键字修饰
public abstract void eat();
具体子类继承抽象类之后, 必须实现(重写/覆盖)抽象父类中的抽象方法
或将该子类声明成为抽象类
抽象类不能被实例化
抽象类中的构造方法是为了给成员属性赋值
如果一个类中有抽象方法,那么该类必须声明为抽象类
接口:
具体类: 对现实世界的具体事物进行描述
抽象类: 对现实世界中的某一种事物进行描述
接口:
-- 不同事物的共同行为(抽象方法)
接口使用关键字interface实现
接口中可以包含:
- 静态常量
a) 接口定义的成员属性默认为静态常量
- 抽象方法
a) 在接口只能定义抽象方法
b) 声明的方法默认就是抽象方法
接口所有成员默认的访问控制修饰符为 public
接口不能被实例化
接口不能被子类继承, 只能由子类实现
- 使用关键字 implements
实现子类必须重写/覆盖接口中的所有抽象方法,如果没有全部实现, 该实现子类必须声明成为抽象类
接口可以继承接口, 且可以继承多个父接口
多个类可以实现同一个接口
一个类可以实现多个不同的接口
final
可以修饰:
- 变量
a) 被final修饰的变量称之为常量, 值不能被改变
- 显式赋值
- 动态代码块中赋值
- 构造器赋值
- 如果声明为静态常量, 那么赋值方式:
- 显式赋值
- 静态代码块赋值
- 方法
a) 被final修饰的方法称之最终方法, 不能被子类重写/覆盖
- 类
a) 被final修饰的类称之为最终类, 不能被继承
多态:
- 本态: 对象的本类类型
Teacher t = new Teacher();
本态引用: 对象引用类型为本类类型(声明的数据类型为本类类型)
- 多态: 对象的父类类型
Person p = new Teacher();
多态引用: 父类的引用指向子类的实例对象
-- 运行时使用子类类型
编译时使用父类类型
多态参数:
由多态产生的问题:
由于编译时使用父类类型进行编译, 也就是无法调用子类中独有的方法
在实际开发中,使用多态参数的方式来解决此访问
方法接收一个父类类型的参数
内部类:
内部类中能否访问外部类的成员
内部类可以直接访问外部类的成员
外部类中否访问内部类的成员
外部类必须通过内部类的实例对象访问内部类的成员
内部类怎么实例化对象
- 外部类名.内部类名 内部类对象名 = new外部类名().new内部类名();
- 外部类名 外部类对象名 = new外部类名();
外部类名.内部类名 内部类对象名 = 外部类对象名. new内部类名();
静态内部类:
静态内部类中能否访问外部类的成员
只能直接访问外部类的静态成员
如果要访问外部类的非静态成员,必须以外部类的实例对象的方式调用
外部类中否访问静态内部类的成员
不能直接访问静态内部类的成员
也不能以静态类名.方法名的方式调用
只能以静态内部类的对象方式调用
静态内部类怎么实例化对象
外部类名.内部类名 内部类对象名 = new外部类名.内部类名();
方法中的内部类
能否访问外部类成员
可以直接访问外部类的成员
外部类能否直接访问方法中的内部类成员
不能
方法中的内部的有效范围只在所属方法体中
异常
异常: 在应用程序运行期间产生错误而进行通知的一种机制
一旦出现异常, 应用程序会因意外而中止运行
异常中包含:
- 异常的原因
- 异常的信息(错误信息)
- 异常的位置
异常是以堆栈的方式抛出
异常分类 :
- 运行时异常: 应用程序在编译时可以通过, 但在运行时可能会抛出异常
a) 非受检异常
b) 在应用程序运行时,由用户输入了错误的信息而造成
c) 由RuntimeException对象及Error对象
- 非运行时异常: 在编译期间, 由编译器做出检查
a) 受检异常
b) Exception对象
- RuntimeException
– ArithmeticException:数学计算异常
– NullPointerException:空指针异常
– NegativeArraySizeException:负数组长度异常
– ArrayIndexOutOfBoundsException:数组索引越界异常
– ClassNotFoundException:类文件未找到异常
– ClassCastException:造型异常
- IOException
– FileNotFoundException:文件未找到异常
– EOFException:读写文件尾异常
– MalformedURLException:URL格式错误异常
– SocketException:Socket异常
– IOException
处理异常的方式
- 捕获
- 抛出
- 捕获再抛出
捕获:
try{
必须是可能抛出异常的代码
}catch(异常类名 对象名){
捕获异常后的处理
}
异常处理:
- 打印异常的错误信息
a) 异常对象名.getMessage();
- 打印异常的堆栈信息
a) 异常对象名.printStackTrace();
catch语句块中声明的异常类必须与代码产生的异常对象是同一类型
-- 可以是产生的异常对象的本类类型或父类类型
在finally语句块中会执行关闭相关连接或释放资源的操作
如果语句块中的return, 那么finally语句块会在return 前执行
抛出
在代码中产生异常应用程序直接抛出一个异常对象
使用关键字throw或throws声明抛出
throw: 代码级抛出
-- 开发人员可以自行决定在哪行代码抛出异常
-- 实例化异常对象时可以指定异常的错误信息
-- 使用throw 抛出的异常如果为运行时异常, 那么调用的地方无需捕获
如果抛出的异常如果为非运行时异常, 那么调用的地方必须捕获
且必须使用throws声明抛出
-- throw == return
throws: 方法级抛出
-- 一般声明抛出的是非运行时异常(受检异常)
-- 如果throws声明抛出的是运行时异常(非受检异常), 调用的地方无需捕获
-- 如果throws声明抛出的是非运行时异常(受检异常), 调用的地方必须捕获
使用throws可以直接声明抛出异常, 无需使用throw关键字
-- 声明多个异常, 多个异常之间使用逗号分隔
捕获抛出
先将产生的异常对象声明为一个新的异常对象, 对这个新的异常对象进行抛出处理
自定义异常:
自定义类必须继承一个异常类
- RuntimeException: 将自定义异常类声明为一个运行时异常类
- Exception: 将自定义异常类声明为一个非运行时异常类
声明重载构造器
String是一个不可变的字符序列
String类是final类型, 不能被继承
常用方法:
concat(str): 字符串连接
replace(oldChar, newChar): 以指定的新内容替换字符串中指定的旧的内容
substring(startIndex): 从指定的索引开始,截取字符串至结尾
substring(startIndex, endIndex): 返回从指定的索引开始至指定的结束索引之间的内容(结束索引处的字符不包含在内)
toLowerCase(): 将指定的字符串内容全部转换为小写
toUpperCase(): 将指定的字符串内容全部转换为大写
trim(): 去掉字符串首尾的空格及制表符
toCharArray(): 将指定的字符串转换成为字符数组
endWith(str): 当前字符串是否以指定的内容结束
startWith(str) : 当前字符串是否以指定的内容开始
indexOf(char)
indexOf(int)
indexOf(String): 返回指定字符串第一个字符的索引位置
indexOf(String str, int startIndex)
正向查找(从前向后)
从当前字符串中查询指定内容第一次出现的索引位置
如果未找到, 返回-1
lastIndexOf(int )
lastIndexOf(char )
lastIndexOf(String )
lastIndexOf(String str, int startIndex)
反向查找(从后向前)
equals(str): 当前字符串与指定的字符串进行比较, 是否相等
equalsIgnoreCase(str): 当前字符串与指定的字符串进行比较, 忽略大小写
compareTo(str):
charAt(index): 获取指定索引处的字符
length(): 是一个方法, 获取当前字符串的长度
数组长度是一个属性
split(str): 以指定的内容对当前字符串进行分隔, 返回字符串数组
集合: 是Java提供的一系列类的实例
-- 一系列类组成了集合框架(Collection系列)
集合作用:
用来存储多个元素
与数组的区别:
可以看作是一个可变长度的数组
可以存储不同类型的对象
集合元素必须是对象类型,不能是基本类型
数组长度一旦确定, 不能更改
数组元素必须是同一种类型的对象
数组既可以是基本数据类型也可以是对象类型
Collection
List
ArrayList
LinkedList
Vector
Set
HashSet
SortedSet
TreeSet
Map
HashMap
Hashtable
SortedMap
TreeMap
List: 有序且可重复
有序: 添加元素的顺序
可重复: 相等的两个元素可以添加至同一集合中
Set: 无序且不可重复
无序: 依次获取元素时不按添加顺序
不可重复: 相等的元素不能添加到同一集合中
Map: 映射集合
Key-Value
Collection常用API
– int size(); 返回此collection中的元素数。
– boolean isEmpty(); 判断此collection中是否包含元素。
– boolean add(Object element); 向此collection中添加元素。
– boolean addAll(Collection c);将指定collection中的所有元素添加到此collection中
– boolean contains(Object obj); 判断此collection是否包含指定的元素。
– boolean containsAll(Collection c); 判断此collection是否包含指定collection中的所有元素。
– boolean remove(Object element); 从此collection中移除指定的元素。
– boolean removeAll(Collection c); 移除此collection中那些也包含在指定collection中的所有元素。
– void clear(); 移除collection中所有的元素。
– boolean retainAll(Collection c); 仅保留此collection与c的交集元素,其他删除,此方法与removeAll()正好相反。
– Iterator iterator(); 返回在此collection的元素上进行迭代的迭代器。
– Object[] toArray(); 把此collection转成数组。
List:
ArrayList: 使用数组结构保存元素
- 根据索引查找元素速度快
- 添加/删除效率较低(涉及数组中大量元素的移动)
- 是非线程安全的
LinkedList: 使用链表结构保存元素
- 查询元素效率较低
- 添加/删除效率较高(不会涉及元素的大量移动)
- 是非线程安全的
Vector: 使用数组结构保存元素
- 是线程安全的
- 查询/添加/删除效率都较低
List常用API
- public Object get(int index)
- 返回列表中的元素数
- public Object add(int index, Object element);
- 在列表的指定位置插入指定元素.将当前处于该位置的元素(如果有的话)和所有后续元素向右移动
- public Object set(int index, Object element) ;
- 用指定元素替换列表中指定位置的元素
- public Object remove(int index)
- 移除列表中指定位置的元素
- public ListIterator listIterator()
- 返回此列表元素的列表迭代器
Set集合:
Set: 无序且不可重复
HashSet: 使用的是Hash算法实现
是基于HashMap映射集合实现的
向Set集合中添加元素时,执行方式如下:
- 调用hashCode()方法, 比较两个对象的hash值, 如果hash值不同, 直接将元素添加到Set集合中, 如果hash值相同, 那么执行第二步
- 调用equals(obj)方法, 如果比较结果为false, 那么将元素添加到Set集合中,如果比较结果为true, 不会添加
在实体类中, 需要重写hashCode()与equals(Object obj)两个方法
-- 确定该类的实例对象需要保存到Set集合中时
SortedSet
TreeSet 是有序, 按照自然排序的规则进行排序
二叉树
Map集合: 是映射集合
以key-Value键值对的形式保存数据
key必须在集合中是唯一的不能重复
一个key对应一个value
如果要新增的key与value在map中已存在, 新增的key会被丢弃,value会覆盖之前的vlaue
Map:
HashMap
SortedMap
TreeMap
Hashtable
Map<Key, Value> map = new HashMap<Key, Value>();
Map<Integer, String> map = new HashMap<Integer, String >();
常用API:
put(key, value) 向当前集合中添加元素
get(key): 根据指定的key从集合中查找对应的value
keySet(): 返回当前集合中的包含所有key的Set集合
entrySet(): 返回当前集合中的所有的key与value的Set集合
HashMap:
key与value允许为null
非线程安全的
Hashtable
key与value都不允许为null
线程安全的
File: 对应系统中的某一个文件
public class TestFile {
public static void main(String[] args) {
File file = new File("d:/share/test.txt");
boolean flag = file.exists();
System.out.println(file + " 是否存在: "
// 没有物理文件的文件对象不能读写
System.out.println("是否能读: "
System.out.println("是否能写: "
File f = new File("src/com/io/test/TestFile.java");
// 有物理文件的文件对象能进行读写操作
System.out.println("是否能读: "
System.out.println("是否能写: "
System.out.println("是否存在: "
System.out.println("文件名: "
System.out.println("文件绝对路径: "
System.out.println("文件相对路径: "
System.out.println("文件上级父路径: "
long time = f.lastModified();
System.out.println("最后修改时间: "
Date date = new Date(time);
// yyyy-MM-dd
DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String str = df.format(date);
System.out.println(str);
System.out.println("文件长度: "
System.out.println("是否文件夹: "
System.out.println("是否文件: "
System.out.println("是否为隐藏文件: "
File fd = new File("d:/share/day01");
flag = fd.isDirectory();
System.out.println("fd.isDirectory = " + flag);
String[] strs = fd.list();
for(String s : strs){
System.out.println(s);
}
File[] files = fd.listFiles();
for(File f2 : files){
if(f2.isDirectory()){
// 是目录
}
// 非目录
}
File f3 = new File("test");
// mkdir(), createNewFile()
if(!f3.exists()){
flag = f3.mkdir();
System.out.println("test目录创建成功: "
}
File f4 = new File("test/test.txt");
try {
if(!f4.exists()){
flag = f4.createNewFile();
System.out.println("test/test.txt创建成功: "
}
} catch (IOException e) {
e.printStackTrace();
}
File f5 = new File("test/te/ts/t");
/*if(!f5.exists()){
flag = f5.mkdir();
System.out.println("t目录创建成功: " + flag);
}*/
if(!f5.exists()){
flag = f5.mkdirs();
System.out.println("t目录创建成功: "
}
}
}
I/O
Input: 输入流 => 读取/接收数据
Output: 输出流 => 写入/发送数据
流分类:
1按数据流动方向分:
输入流
输出流
2 按数据量(数据类型)分:
字节流: 一次传输8位(1个字节)
以Stream结尾
字符流: 一次传输16位(2个字节)
以Reader/Writer结尾
注: InputStreamReader/OutputStreamWriter是转换流
InputStreamReader: 将字节流转换成为字符流
OutputStreamWriter: 将字符流转换成为字节流
3 按对数据的处理功能分:
基本流/节点流
包装流/处理流: 扩展了更加强大的处理功能, 处理数据更为方便
InputStream
是所有输入流的父类
read() // 读取一个字节
read(byte[])
read(byte[] b, int offset, int len)
close()
OutputStream
是所有输出流的父类
write(int)
write(byte[])
write(byte[] b, int offset, int len)
flush();
close();
节点流 = 基本流
处理流 = 包装流
BufferedInputStream
bufferedOutputStream
缓冲字节流
BufferedReader
readLine()
BufferedWriter
缓冲字符流
文件读写开发步骤:
- 创建流对象
- 读:输入流/写: 输出流
a) 如果文件为二进制文件, 使用字节流
b) 如果文件为普通文件, 使用字符流
- 关闭流
一、java中多线程的执行:抢占式执行
二、创建线程的方式
1、继承Thread类
(1)创建线程类继承Thread并覆盖run()方法
(2)在主线程中创建线程类的对象
(3)调用线程对象的start()方法启动线程
2、实现Runnable接口
(1)创建线程类实现Runnble接口并实现run()方法
(2)在main方法中创建线程类的实例
(3)使用第2步创建的实例创建Thread对象
(4)调用start()方法启动线程
3、线程的状态
三、线程的状态
1、创建:创建Thread对象
2、创建-可运行:调用start()方法
3、可运行-正在运行:抢占到CPU资源
4、正在运行-可运行:CPU资源被其他线程抢走
5、正在运行-结束:run()方法执行结束
四、线程中常用的方法
1、获取当前的线程Thread对象:Thread.currentThread()
2、获取线程对象的名字:getName()
3、当前线程的是否活动:isAlive()
4、当前线程的状态:getState()
5、设置线程的名称:setName()
6、线程睡眠:sleep(long n)
(1)使线程暂停执行n毫秒
(2)当前程睡眠时,就不再参与抢占CPU资源,提供其他线程优先执行的机会
(3)唤醒睡眠线程
a.主动唤醒:时间到了
b.被动唤醒:调用interrupt()方法,抛出InterruptedException异常信号唤醒线程
(4)线程从运行状态变为阻塞状态,该状态不能抢占CPU资源
7、线程暂停执行:yield()
(1)线程从运行状态变为可运行状态(就绪状态)
(2)当该线程回到了可运行状态后,仍然可以与其他线程抢占CPU资源执行。
8、调用的线程先执行,其他线程阻塞:join()
(1)暂停的线程从运行变为阻塞状态,就不再参与抢占CPU资源
(2)唤醒阻塞的线程
a.结束唤醒:优先执行的线程结束
b.主动唤醒:时间到了
c.被动唤醒:调用interrupt()方法,抛出InterruptedException异常信号
反射:
通过反射机制可以实现获取类中的字段, 方法, 并且调用
可以创建已知类名字符串的实例对象
类的类名字符串:
类的全名, 包括类所在的包名