一、Java基础语法
1. 常用DOS命令
盘符切换:D:
查看当前路径下的内容:dir
单级目录进入:cd XX
单级目录回退:cd…
多级目录进入:cd XX\XX
多级目录回退:cd
清屏命令:cls
退出命令:exit
2. helle world 案例
3. 注释
// /**/
4. 空常量不能直接输出
5. 位(bit):计算机存储设备的最小信息单元
字节(byte):计算机中最小的存储单元,通常由“B”表示。
1B(字节)=8bit(位)
6. 变量使用注意事项:
名字不能重复
变量未赋值不能使用
long类型变量定义的时候,为防止整数过大,后面加L
float类型变量定义的时候,为防止类型不兼容,后面加F
7. 标识符
- 定义规则
由数字,字母,下划线(_),美元符号($)组成
不能以数字开头
不能是关键字
区分大小写 - 命名约定
小驼峰命名法:方法,变量
first firstName
大驼峰命名法:类
First FirstName
8. 算术运算符
‘+’ ‘-’ ‘*’ ‘/’ ‘%’
除法得到的是商,取余得到的是余数
整数相除只能得到整数,要想得到小数,必须有浮点数参与 eg:6.0/2
char 可以进行’+'操作:字符在计算机底层对应的数值进行计算
算术表达式包含多个基本数据类型的值时,整个算术表达式的类型会自动提升。
等级顺序:byte short char ->int->long->float->double
eg:“hello”+6+6 hello66
6+6+“hello” 66hello
9. 赋值运算符
10. 自增自减运算符
单独使用
i++; ++i; 结果一样
参与操作使用
i++ 先拿变量参与操作,再进行++;
++i 先进行++,后拿变量参与操作
11. 关系运算符
12. 逻辑运算符
且(&) 或 (|) 非 (!) 异或(^)
a&b:a和b都是true,结果为true,否则为false
a|b:a或b有一个是true,结果为true,否则为false
!a:与a结果相反
a^b:a和b结果相同false,不同为true
13. 短路逻辑运算符
14. 三元运算符
a>b?a:b;
若a>b则a为运算结果,否则是b
二、数据输入
- 导包
import java.util.Scanner;
快捷键导包:alt+enter - 创建对象
Scanner sc = new Scanner(System.in); - 接收数据
int x = sc.nextInt();
三、分支语句
1. 流程控制
1.1 流程控制语句概述
在一个程序执行的过程中,各条语句的执行顺序对程序的结果是有直接影响的。也就是说程序的流程对运行结果有直接的影响。在清楚每条语句的执行流程的前提下,才能通过控制语句的执行顺序来实现我们要完成的功能。
1.2 流程控制语句分类
1.2.1 顺序结构
顺序结构是程序中最简单最基本的流程控制,没有特定的语法结构,按照代码的先后顺序,依次执行,程序中大多数代码都是这样执行的。
1.2.2 分支结构(if,switch)
1.2.3 循环结构(for,while,do…while)
2. if语句
2.1 if语句格式1
//格式:
if(关系表达式){
语句体;
}
2.2 if语句格式2
//格式:
if(关系表达式){
语句体1;
}else{
语句体2;
}
2.3 if语句格式3
//格式:
if(关系表达式){
语句体1;
}else if(关系表达式2){
语句体2;
}
...
else{
语句体n+1;
}
3. switch语句
//格式:
switch(){
case 值1:
语句体1;
break;
case 值2:
语句体2;
break;
...
default:
语句体n+1;
[break;] //[]表示可选
}
计算表达式的值,然后依次与case后的值比较,若与所有case后的值都不匹配执行default里的语句。
如果 case1 case2 语句体一样,可写成:
switch(){
case1:
case2:
语句体;
break;
}
四、循环语句
1. for循环语句
for(int i=1;i<=5;i++){
i++;
}
2. while循环语句
int i = 1;
while(i<=5){
i++;
}
3.do…whlie循环语句
int i = 1;
do{
i++;
}while(i<=5);
do…while 会先执行一次{}中的。
死循环
for( ; ; ){}
while(true){}
do{
}while(true);
4.跳转控制语句
continue 跳过某次
break 结束循环
5. 循环嵌套
for(){
for(){}
}
6. Random
- 导包
import java.util.Random; - 创建对象
Random r = new Random(); - 获取随机数
int number = r.nextInt(10);//获取数据的范围:(0-10)包括0,不包括10
若需要1-10 :int number = r.nextInt(10)+1;
五、IDEA
1. idea 内容辅助键和快捷键
- 内容辅助键
psvm : main()
sout : 输出
ctrl+alt+space : 内容提示,代码补全 - 快捷键
注释
单行 :选中代码 ctrl+/ 再按取消
多行 :选中代码 ctrl+shift+/ 再按取消
格式化 :ctrl+alt+l
六、数组
int[] a = new int[3];
int[] a = new int[]{1,2,3};
int[] a = {1,2,3};
数组操作两个小问题:索引越界,空指针异常
七、方法
形参:方法定义中的参数
实参:方法调用中的参数
方法不能嵌套定义
void表示无返回值,可以省略return,也可以单独书写(return;),后面不加数据
方法重载:多个方法同一个类中 多个方法具有相同的方法名 多个方法参数不同:类型不同或数量不同
对于基本数据类型的参数,形参改变不影响实参的值。
对于引用类型的参数,形参改变实参改变。
八、Debug
供程序员使用的程序调试工具,它可以用于查看程序和执行流程,也可以用于追踪程序执行过程来调试程序。
加断点 运行 删除断点
九、面向对象基础
1、类和对象
1.1 对象是能够看的见摸得着的真实存在的实体
类是对现实生活中一类具有共同属性和行为的事物的抽象
类是对象的数据类型
类是具有相同属性和行为的一组对象的集合
类是对象的抽象 对象是类的实体
1.2 类的定义
类的重要性:是java程序的基本组成单位
类的组成:属性(成员变量)和行为(成员方法没有static)
- 定义类
- 编写成员变量
- 编写类的成员方法
public class Phone{
//成员变量
int price;
String brand;
//成员方法
public void call(){
System.out.println(" ");
}
}
1.3 对象的使用
- 创建对象:类名 对象名 = new 类名();
Phone p = new Phone(); - 使用对象:
p.brand p.call()
2.成员变量和局部变量
成员变量:类中方法外的变量;堆内存
局部变量:方法中的变量;方法声明上(形参);栈内存
3. 封装
3.1 private关键字
是一个权限修饰符
可以修饰成员(变量和方法)
作用保护成员不被别的类使用,被private修饰的成员只在本类中才能访问
针对private修饰的成员变量,如果需要被其他类使用:
提供“ get变量名() ”方法,用于获取成员变量的值,方法用public修饰
提供“ set变量名(参数) ”方法,用于设置成员变量的值,方法用public修饰
3.2 this关键字
3.2.1 this修饰的变量用于指代成员变量
3.2.2 解决局部变量隐藏成员变量的问题
3.2.3 this:代表所在类的对象引用
3.3 封装
3.3.1 封装概述:
是面向对象三大特征之一(封装,继承,多态)
是面向对象编程语言对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界无法直接操作的
3.3.2 封装原则:
将类的某些信息隐藏在类内部,不允许外部程序直接访问。而是通过该类提供的方法来实现对隐藏信息的操作和访问 成员变量private,提供对应getXxx() setXxx()方法
3.3.3 封装好处:
通过方法来控制成员变量的操作,提高了代码的安全性
将代码用方法进行封装,提高了代码的复用性
4. 构造方法
4.1 作用:
创建对象 完成对象数据初始化
public class Student{
public Student(){
//构造方法内书写的内容
}
}
4.2 注意事项:
- 构造方法的创建
如果没有定义构造方法,系统将给出一个默认的无参数构造方法
如果定义了构造方法,系统将不再提供默认的构造方法 - 构造方法的重载
如果定义了带参构造方法,还要使用无参构造方法,就必须再写一个无参构造方法
建议:无论是否使用,都手工书写无参数构造方法
十、字符串
1. API
API(Application Programming Interface)概述:应用程序编程接口
2. String
s.equals
s.charAT(int index):返回指定索引处的char值,字符串的索引从0开始。
3. StringBuilder
如果对字符串拼接,每次拼接都会创建一个新的String对象,既耗时间,又浪费内存空间,而这种操作不可避免。可以通过Java提供的StringBuilder类来解决这个问题。
3.1 概述
StringBuilder是一个可变的字符串类,可把它看成一个容器。StringBuilder对象中的内容是可变的。
3.2 构造方法
StringBuilder sb = new StringBuilder();
StringBuilder sb = new StringBuilder(“hello”);
3.3方法
sb.append(); 添加数据,并返回对象本身。
sb.reverse(); 返回相反的字符序列。
3.4 StringBuilder 和 String 相互转换
String s = "";
- StringBuilder转换为String:
sb.toString()
- String转换为StringBuilder:StringBuilder(String s)
StringBuilder sb = new StringBuilder(s);
- 反转:
String s1 = StringBuilder(s).reverse().toString();
十一、集合基础
1.概述
集合类提供一种存储空间可变的存储模型,存储的数据容量可以发生改变
eg:ArrayList
2. ArrayList构造方法和添加方法
public ArrayList():创建一个空的集合对象
public boolean add(E e):将指定元素追加到此集合的末尾
public void add(int index,E e):在此集合的指定位置插入指定的元素
ArrayList array = new ArrayList();
array.add(“hello”);
array.add(“world”);
array.add(1,“max”);
System.out.println(array);
3. 常用方法
public boolean remove(Object to):删除指定元素
public E remove(int index):删除索引处元素,返回被删除的元素
public E set(int index,E element):修改指定索引处的元素,返回被修改的元素
public E get(int index):返回索引处的元素
public int size():返回集合中元素的个数
十二、继承
1. 概述
可以使得子类具有父类的属性和方法,还可以在子类中重新定义,追加属性和方法。
public class Zi extends Fu{}
2. 好处和弊端
2.1 好处:
提高了代码的复用性(多个类相同的成员可以放到同一个类中)
提高了代码的维护性(如果方法的代码需要修改,修改一处即可)
2.2 弊端:
削弱了子类的独立性
3. 变量的访问特点
在子类中访问一个变量:
子类局部范围找
子类成员范围找
父类成员范围找
如果都没有就报错(不考虑父亲的父亲)
4. super
父类对象的引用
5. 方法重写
当子类需要父类的功能,而功能主体子类有自己特有的内容时,可以重写父类的方法
私有方法不能被重写
子类方法访问权限不能更低(public>默认>私有)
6. 注意事项
Java中类支持单继承,不支持多继承
Java中类支持多层继承
十三、修饰符
1. 包
1.1 概念:对类进行分类管理
手动建包
自动建包:javac -d.HelloWorld
java XX.XX.HelloWorld
1.2 导包
简化带包操作
import 包名;
2. 修饰符
2.1 权限修饰符
private default protected public
2.1 状态修饰符
2.1.1 final(最终态)
final修饰的方法是最终方法,不能被重写
修饰的变量是常量,不能再次被赋值
修饰的类是最终类,不能被继承
final 修饰局部变量
变量是基本类型:数据值不能改变
变量是引用类型:地址值不能改变,但地址里的内容可变
2.1.2 static(静态)
static 关键字是静态的意思,可以修饰成员方法,成员变量.
- 修饰特点:被类的所有对象共享(是否使用静态关键字的条件)
可以使用类名调用(推荐),也可以使用对象名调用。 - 访问特点
非静态的成员方法:能访问静态的和非静态的成员变量和方法。
静态的成员方法:能访问静态的成员变量和方法。静态的成员方法只能访问静态成员。
十四、多态
1. 概述
同一个对象,在不同时刻表现出来的不同形态
1.1 多态的前提和体现
有继承/实现关系
有方法重写
有父类引用指向子类对象
2. 成员访问特点
成员变量:编译看左边,执行看左边
成员方法(有重写):编译看左边,执行看右边
3. 多态的好处和弊端
好处:提高了程序的拓展性
具体体现:定义方法的时候,使用父类型作为参数,将来在使用的时候,使用具体的子类型参与操作。
弊端:不能使用子类的特有功能。
4. 多态中的转型
向上转型
从子到父;父类引用指向子类对象
Animal a = new Cat();
向下转型
从父到子;父类引用转为子类对象
Cat c = (Cat)a; //强转
十五、抽象类
1. 特点
抽象类和抽象方法必须使用abstract关键字修饰。
抽象类不一定有抽象方法,有抽象方法的类一定是抽象类。
抽象类不能实例化:通过子类对象实例化,这叫抽象类多态。
抽象类的子类:要么重写抽象类中的所有抽象方法,要么是抽象类。
2. 成员特点
成员变量:可以是变量,也可以是常量
构造方法:有构造方法,但不能实例化。用于子类访问父类数据的初始化。
成员方法:可以有抽象方法:限定子类必须完成某些动作;也可以有非抽象方法:提高代码复用性。
十六、接口
接口就是一种公共的规范标准
Java中的接口更多体现在对行为的抽象
1. 特点
用关键字interface修饰
类实现接口用implements表示
接口不能实例化:通过实现类对象实例化,接口多态
接口实现类:要么重写接口中所有的抽象方法 要么是抽象类
2. 成员特点:
成员变量只能是常量,默认修饰符:public static final
接口没有构造方法,因为接口主要是对行为进行抽象的,是没有具体存在。
一个类如果没有父类,默认继承自Object类
成员方法:只能是抽象方法 默认修饰符:public abstract
3. 类和接口的关系
3.1 成员区别
抽象类:变量,常量,有构造方法,抽象方法,非抽象方法
接口:常量,抽象方法
3.2 关系区别
类与类:继承,可以单继承,也可以多继承
类与接口:实现,可以单实现,也可以多实现
接口与接口:继承,单继承,多继承
3.3 设计理念区别
抽象类:对类抽象,包括属性,行为
接口:对行为抽象主要是行为
十七、形参和返回值
1. 类名作为形参和返回值
方法的形参是类名,其实需要的是该类的对象
方法的返回值是类名,其实返回的是该类的对象
2. 抽象类名作为形参和返回值
方法的形参是抽象类名,其实需要的是该抽象类的子类对象
方法的返回值是抽象类名,其实返回的是该抽象类的子类对象
3. 接口名作为形参和返回值
方法的形参是接口名,其实需要的是该接口的实现类对象
方法的返回值是接口名,其实返回的是该接口的实现类对象。
十八、内部类
1. 概述
就是在一个类中定义一个类。
访问特点:内部类可以直接访问外部类的成员,包括私有;外部类要访问内部类的成员,必须创建对象
按照内部类在类中定义的位置不同,可以分为:
在类的成员位置:成员内部类
在类的局部位置:局部内部类
2. 成员内部类
外界如何创建对象使用
格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
例子:Outer.Inner oi = new Outer().new Inner();
如果是私有:
3.局部内部类
局部内部类是在方法中定义的类,所以外界是无法直接使用,需要在方法内部创建对象并使用
该类可以直接访问外部类的成员,也可以访问方法内的局部变量
4.匿名内部类
前提:存在一个类或者接口,这里的类可以是具体类也可以是抽象类
格式:
new 类名或者接口名(){
重写方法;
}
十九、常用类
工具类的设计思想:构造方法用private修饰 成员用public static修饰
1. Math
pulic static int abs(int a); 返回参数绝对值
pulic static double ceil(double a); 向上取整
pulic static double floor(double a); 向下取整
pulic static int round(float a); 四舍五入
pulic static int max(int a,int b); 最大值
pulic static int min(int a,int b); 最小值
pulic static double pow(double a,double b); a的b次幂
pulic static double random(); 返回一个随机数 [0.0-1.0)
(int)(Math.random()*100)+1 :1-100随机数
直接调用:Math.xxx();
2. System
public static void exit(int status); 终止当前运行的Java虚拟机,非零表示异常终止
System.exit(0);
public static long currentTimeMillis(); 返回当前时间(以毫秒为单位)
3. Object
Object是类层次结构的根,每个类都可以将Object作为超类。所有类都直接或间接的继承自该类
public String toString(); 返回对象的字符串表示形式。建议所有子类重写此方法。自动生成
public booleean equals(Object obj); 比较对象是否相等。默认比较地址,重写可以比较内容,自动生成
4. Arrays
public static String toString(int[] a); 返回指定数组的内容的字符串表示形式
public static void sort(int[] a); 按照数字顺序排列指定的数组
5. 基本类型包装类
5.1 基本类型包装类概述
将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
装箱:把基本数据类型转换为对应的包装类类型
Integer i = Integer.valueOf(100);
Integer i1 = 100;(自动装箱)
拆箱:把包装类类型转换为对应的基本数据类型
i1 = i1.intValue() + 200;
i1 += 200;(自动拆箱,自动装箱)
5.2 Integer类的概述和使用
5.2.1 构造方法:
public Integer(int value) 根据int值创建Integer对象(过时)
public Integer(String s) 根据String值创建Integer对象(过时)
5.2.2 静态方法获取对象:
public static Integer valueOf(int i) 返回表示指定值的int值的Integer实例
public static Integer valueOf(String s) 返回一个保存指定值的Integer对象String
5.3 int 和 String 的相互转换
5.3.1 int 转换为 String
int number = 100;
String s1 = “”+number; //方式一
String s2 = String.valueOf(number); //方式二
5.3.2 String 转换为 int
String s = “123”;
Integer i = Integer.valueOf(s); //方式一
int x = i.intValue();
int y = Integer.parseInt(s); //方式二
5. 日期类
5.1 Date
Date 代表了一个特定的时间,精确到毫秒
构造方法
public Date() 分配一个Date对象,并初始化,以便他代表它被分配的时间,精确到毫秒
public Date(long date) 分配一个Date对象,并将其初始化为表示从基准时间起指定的毫秒数
常用方法
public long getTime(); 获取的是日对象从1970年1月1日00:00:00到现在的毫秒值
public void setTime(long time); 设置时间,给的是毫秒值。
5.2 SimpleDateFormat
SimpleDateFormat 是一个具体的类,用于以区域设置敏感的方式格式化和解析日期。我们重点学习日期格式化和解析。
日期和时间格式由日期和时间模式字符串指定,在日期和时间模式字符串中,从 ‘A’ 到 ‘Z’ 以及从 ‘a’ 到 ‘z’ 引导的字母被解释为表示日期或时间字符串的组件的模式字母
常用的模式字母对应关系如下:
y 年
M 月
d 日
H 时
m 分
s 秒
构造方法
public SimpleDateFormat() 构造一个SimpleDateFormat,使用默认模式和日期格式
public SimpleDateFormat(String pattern) 构造一个SimpleDateFormat,使用给定模式和默认日期格式
常用方法
public final String format(Date date); 将日期格式化成日期/时间字符串
public Date parse(String source); 从给定字符串的开始解析文本以生成日期
5.3 Calendar
获取对象
Calendar c = Calendar.getInstance();
public int get(int filed); 返回给定日历字段的值
int year = c.get(Calendar.YEAR); // 年月日
int month = c.get(Calendar.MONTH) + 1;
int date = c.get(Calendar.DATE);
public abstract void add(int filed, int amount); 根据日历的规则,将指定的时间量添加或减去给定的日历字段
public final void set(int year, int month, int date); 设置当前日历的年月日
二十、异常
1. 概述:就是程序出现了不正常的情况
Error :非常严重,不需要处理
Exception :称为异常类,他表示程序本身可以处理的问题
RuntimeException :在编译期是不检查的,出现问题后,需要我们回来修改代码
非 RuntimeException :编译期就必须处理的,否则程序不能通过编译,就更不能正常运行了
2. JVM的默认处理方案
把异常的名称,异常原因及异常出现的位置等信息输出在了控制台
程序停止运行
3. 异常处理
try…catch…
try{
可能出现异常的代码;
}catch(异常类 变量名){
异常的处理代码;
}
throws
针对出现的异常我们无法处理,Java 提供了 throws 的处理方案
格式: throws 异常类名; (跟在方法的括号后面)
只是抛出异常,将来谁调用谁处理(try…catch…)
4. Throwable的成员方法
public String getMessage(); 返回此 throwable 的详细消息字符串
public String toString(); 返回此可抛出的简短描述
public void printStackTrace(); 把异常的错误信息输出在控制台
5. Java中的异常被分为两大类:
编译时异常(受检异常)和运行时异常(非受检异常),所有 RuntimeException 类及其子类的实例被称为运行时异常,其他的异常都是编译时异常。
- 编译时异常:必须显示处理,否则程序就会发生错误,无法通过编译
- 运行时异常(需要修改代码):无需显示处理(可以不处理),也可以和编译异常一样处理
6. 自定义异常
格式:
public class 异常类名 extends Exception {
无参构造
带参构造
}
7. throws 和 throw 的区别
throws | throw |
---|---|
用在方法声明后面,跟的是异常类名 | 用在方法体内,跟的是异常对象名 |
表示抛出异常,由该方法的调用者来处理 | 表示抛出异常,由方法体内的语句处理 |
表示出现异常的一种可能性,并不一定会发生这种异常 | 执行throw一定抛出了某种异常 |
二十一、集合进阶
1. Collection
1.1 Collection集合概述:
是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素
JDK不提供此接口的任何直接实现,它提供更具体的子接口(如 Set 和 List)实现
1.2 创建Collection集合的对象
多态的方式
具体实现类ArrayList
1.3 常用方法
boolean add(E e); 添加元素
boolean remove(Object o); 从集合中移除指定元素
void clear(); 清空集合中的元素
boolean contains(Object o); 判断集合中是否存在指定的元素
boolean isEmpty(); 判断集合是否为空
int size(); 集合的长度,也就是集合中元素的个数
1.4 Collection集合的遍历
Iterator : 迭代器,集合的专用遍历方式
Iterator< E > iterator() : 返回此集合中元素的迭代器,通过集合的iterator()方法得到
迭代器是通过集合的iterator()方法得到的,所以我们说它是依赖于集合而存在的
Iterator中的常用方法
E next(); 返回迭代中的下一个元素
boolean hasNext(); 如果迭代具有更多元素,则返回true
1.5 集合的使用步骤
//创建集合对象
Collection<String> c = new ArrayList<String>();
//添加元素
c.add("hello");
//遍历集合
Iterator<String> i = c.iterator(); //通过集合对象获取迭代器对象
while (i.hasNext()){
String s = i.next();
System.out.println(s);
}
2. List
2.1 概述
有序集合(也称为序列),用户可以精确控制列表中每个元素的插入位置,用户可以通过整数索引访问元素,并搜索列表中的元素
与 Set 集合不同,列表通常允许重复的元素
2.2 特点
有序:存储和取出的元素顺序一致
可重复:存储的元素可以重复
List<String> l = new ArrayList<>();
2.3 特有方法
void add(int index, E element); 在此集合的指定位置插入指定的元素
E remove(int index); 删除指定索引处的元素,返回被删除的元素
E set(int index,E element); 修改指定索引处的元素,返回被修改的元素
E get(int inndex); 返回指定索引处的元素
2.4 并发修改异常
ConcurrentModificationException
产生原因:迭代器遍历过程中,通过集合对象修改了集合元素的长度,造成了迭代器获取元素中判断预期修改值和实际修改值不一致(迭代器获取元素时,会判断实际修改值与预期修改值是否相同,如果不同,抛出并发修改异常。)
解决方法:用for循环遍历,然后用集合对象做对应的操作即可
2.5 ListIterator :列表迭代器
通过List集合的 listIterator()方法得到,所以说它是List集合特有的迭代器
用于允许程序员沿任一方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置
常用方法
E next(); 返回迭代中的下一个元素
boolean hasNext(); 如果迭代具有更多元素,则返回true
E previous(); 返回列表中的上一个元素
boolean hasPrevious(); 如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回true
void add(E e); 将指定的元素插入列表
2.6 增强 for 循环
简化数组和Collection集合的遍历
实现Iterator接口的类允许其对象成为增强型for语句的目标
它是JDK5之后出现的,其内部原理是一个Iterator迭代器
格式:
for(元素数据类型 变量名 : 数组名或者Collection集合){
//在此处使用变量即可,该变量就是元素
}
2.7 数据结构
数据结构是计算机存储组织数据的方式。是指相互之间存在的一种或多种特定关系的数据元素集合。
通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率
2.7.1 常见数据结构之栈
栈是一种数据先进后出的模型
数据进入栈模型的过程成为:压/进栈
数据离开栈模型的过程成为:弹/出栈
2.7.2 常见数据结构之队列
队列是一种数据先进先出的模型
2.7.3 常见数据结构之数组
数组是一种查询快,增删慢的模型
查询数据通过索引定位,查询任意数据耗时相同,查询效率高
删除数据时,要将原始数据删除,同时后面每个数据迁移,删除效率低
添加数据时,添加位置后的每个数据后移,添加效率低
2.7.4 常见数据结构之链表
链表是一种增删快,查询慢的模型
2.8 List集合子类特点
2.8.1 List 集合常用子类:ArrayList,LinkedList
ArrayList:底层数据结构是数组,查询快,增删慢
LinkedList:底层数据结构是链表,查询慢,增删快
2.8.2 LinkedList集合的特有功能
public void addFirst(E e); 在该列表开头插入指定元素
public void addLast(E e); 将指定的元素追加到此列表的末尾
public E getFirst(); 返回此列表中的第一个元素
public E getLast(); 返回此列表中的最后一个元素
public E removeFirst(); 从此列表中删除并返回第一个元素
public E removeLast(); 从此列表中删除并返回最后一个元素
3. Set
3.1 特点:
不包含重复元素的集合
没有带索引的方法,所以不能使用普通for循环遍历
HashSet :对集合的迭代顺序不作任何保证
3.2 哈希值
哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
Object 类中有一个方法可以获取对象的哈希值
public int hashCode(); 返回对象的哈希码值
特点:
同一个对象多次调用hashCode()方法返回的哈希值是相同的
默认情况下,不同对象的哈希值是不相同的。而重写hashCode()方法,可以实现不同对象的哈希值相同
3.3 HashSet 集合概述和特点
特点:
底层数据结构是哈希表
对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致
没有带索引的方法,所以不能使用普通for循环遍历
由于是Set集合,所以不包含重复元素的集合
3.4 HashSet 集合保证元素唯一性的源码分析
HashSet 集合添加一个元素的过程
HashSet 集合存储元素:需要重写hashCode() 和 equals()
3.5 常见数据结构之哈希表
JDK8之前,底层采用数组+链表实现,可以说是一个元素为链表的数组
JDK8以后,在长度比较长的时候,底层实现了优化
HashSet 集合存储学生对象并遍历
定义学生类
创建学生对象
把学生添加到集合
遍历集合(增强for)
在学生类中重写两个方法 hashCode()和equals() 自动生成即可 (为保证元素唯一性)
3.6 LinkedHashSet 集合
特点:
哈希表和链表实现Set接口,具有可预测的迭代次序
由链表保证元素有序,也就是说元素存储和取出顺序是一致的
由哈希表保证元素唯一,也就是说没有重复的元素
3.7 TreeSet 集合
特点:元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法
TreeSet(); 根据其元素的自然排序进行排序
TreeSet(Comparator comparator); 根据指定的比较器进行排序
3.8 自然排序Comparable 的使用
用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法
重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
3.9 比较器排序Comparator的使用
用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的
比较器排序,就是让集合构造方法接收Comparator 的实现类对象,重写compare(T o1,T o2)方法
重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
4. 泛型
4.1 概述
4.1.1 泛型:
是JDK5中引入的特性,他提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型
它的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数
参数化类型:将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型
这种参数类型可以在类、方法和接口中,分别被称为泛型类、泛型方法、泛型接口。
4.1.2 定义格式:
< 类型 >:指定一种类型的格式。这里的类型可以看成是形参
< 类型1,类型2…>:指定多种类型的格式,多种类型之间用逗号隔开,这里的类型可以看成是形参
将来具体调用时给定的类型可以看成是实参,并且实参的类型只能是引用数据类型
好处:
把运行时期的问题提前到了编译期间
避免了强制类型转换
4.2 泛型类
格式:
修饰符 class 类名< 类型 > { }
eg: public class Generic< T >{ }
4.3 泛型方法:
格式:
修饰符 < 类型 > 返回值类型 方法名(类型 变量名) { }
eg: public < T > void show(T t) { }
4.4 泛型接口
格式:
修饰符 interface 接口名< 类型 >{}
eg: public interface Generic< T >{}
4.5 类型通配符
为了表示各种泛型List 的父类,可以使用类型通配符
类型通配符:< ? >
List< ? >:表示元素类型未知的List,他的元素可以匹配任何的类型
这种带通配符的List仅表示它是各种泛型List的父类,并不能把元素添加到其中
如果我们不希望List< ? >是任何泛型List的父类,只希望他代表某一类泛型List的父类,可以使用类型通配符的上限
类型通配符上限:< ?extends 类型>
List < ?extends Number>:它表示的类型是Number或者其子类型
除了可以指定类型通配符的上限,我们也可以指定类型通配符的下限
类型通配符下限:< ?super 类型>
List < ?super Number>:它表示的类型是Number或者其父类型
4.6 可变参数
4.6.1 概念
可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了
- 格式:修饰符 返回值类型 方法名(数据类型…变量名) { }
- 范例:public static int sum(int…a) {}
4.6.2 注意事项:
- 这里的变量其实是一个数组
- 如果一个方法有多个参数,包含可变参数,可变参数要放在最后
4.7 可变参数的使用:
4.7.1 Arrays工具类中有一个静态方法
- public static < T >List< T > asList(T… a); 返回由指定数组支持的固定大小的列表
- 返回的集合不能做增删操作,可以做修改操作
4.7.2 List接口中有一个静态方法
- public static < E >List< E > of(E… elements); 返回包含任意数量元素的不可变列表
- 返回的集合不能做增删改操作
4.7.3 Set接口中有一个静态方法
- public static < E >Set< E > of(E… elements); 返回一个包含任意数量元素的不可变集合
- 在给元素的时候,不能给重复的元素
- 返回的集合不能做增删操作,没有修改的方法
5. Map
5.1 概述
Interface Map< K,V > K:键的类型; V:值的类型
将键映射到值的对象;不能包含重复的键;每个键可以映射到最多一个值
创建Map集合的对象
多态的方式
具体的实现类HashMap
5.2 Map集合的基本功能
方法名 | 说明 |
---|---|
V put(K key,V value) | 添加元素 |
V remove(Object key) | 根据键删除键值对元素 |
void clear() | 移除所有键值对元素 |
boolean containsKey(Object key) | 判断集合是否包含指定的键 |
boolean containsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中键值对的个数 |
5.2 Map集合的获取功能
方法名 | 说明 |
---|---|
V get(Object key) | 根据键获取值 |
Set< K > keySet() | 获取所有键的集合 |
Collection< V >values() | 获取所有值的集合 |
Set< Map.Entry< K,V > >entrySet() | 获取所有键值对对象的集合 |
HashMap TreeMap |
6. Collections
6.1 概述
是针对集合操作的工具类
6.2 常用方法
public static < T extends Comparable< ?super T > > void sort(List < T > list); 将指定的列表按升序排序
public static void reverse(List < ? > list); 反转指定列表中元素的顺序
public static void shuffle(List< ? > list); 使用默认随机源随机排列指定的列表
二十二、IO流
1. File类
1.1 概述和构造方法
1.1.1 概述
File:他是文件和目录路径名的抽象表示
文件和目录是可以通过File封装成对象的
对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已。他可以是存在的,也可以是不存在的。将来是要通过具体的操作把这个路径的内容转换为具体存在的
1.1.2 构造方法
方法名 | 说明 |
---|---|
File(String pathname) | 通过将给定的路径名字符串转换为抽象路径名来创建新的File实例 |
File(String parent,String child) | 从父类路径名字符串和子类路径名字符串创建新的File实例 |
File(File parent,String child) | 从父抽象路径名和子路径名字符串创建新的File实例 |
1.2 File类创建功能
publlic boolean createNewFile(); 当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件
public boolean mkdir(); 创建由此默认路径命名的目录
public boolean mkdirs(); 创建由此抽象路径命名的目录,包括任何必需但不存在的父目录
1.3 File类判断和获取功能
public boolean isDirectory(); 测试此抽象路径名表示的File是否为目录
public boolean isFile(); 测试此抽象路径名表示的File是否为文件
public boolean exits(); 测试此抽象路径名表示的File是否存在
public String getAbsolutePath(); 返回此抽象路径名字符串
public String getPath(); 将此抽象路径名转换为路径名字符串
public String getName(); 返回此抽象路径名表示的文件或目录名称
public String[] list(); 返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
public File[] listFiles(); 返回此抽象路径名表示的目录中的文件和目录的File对象数组
1.4 File类删除功能
public boolean delete(); 删除由此抽象路径名表示的文件或目录
绝对路径和相对路径的区别
绝对路径:完整的路径名,不需要任何其他信息就可以定位它所表示的文件。
相对路径:必须使用取自其他路径名的信息进行解释。
1.5 递归
1.5.1 概述:
以编程的角度来看,递归指的是方法定义中调用方法本身的现象
1.5.2 递归解决问题的思路:
把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解
递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算
1.5.3 递归解决问题要找到两个内容
递归出口:否则会出现内存溢出
递归规则:与原问题相似的规模较小的问题
2. 字节流
IO流概述和分类
2.1 概述:
IO:输入/输出(Input/Output)
流:是一种抽象概念,是对数据传输的总称,也就是说数据在设备间的传输称为流。流的本质是数据传输
IO流就是用来处理设备间数据传输问题的
常见的应用:文件复制;文件上传;文件下载
2.2 分类
2.2.1 按数据的流向
输入流:读数据
输出流:写数据
2.2.2 按数据类型来分
字节流 字节输入流,字节输出流
字符流 字符输入流,字符输出流
一般来说,我们说IO流的分类是按照数据类型来分的。
2.2.3 两种流在什么情况下使用?
如果数据通过Window自带的记事本软件打开,我们还可以读懂里面的内容,就使用字符流,否则使用字节流,如果你不知道该使用哪种类型的流,就使用字节流。
2.3 字节流写数据
2.3.1 字节流抽象基类
InputStream:这个抽象类是表示字节输入流所有类的超类
OutPutStream:这个抽象类是表示字节输出流的所有类的超类
子类名特点:子类名称都是以其父类名作为子类名的后缀
FileOutoutStream:文件输出流用于将数据写入File
FileOutputStream(String name):创建文件输出流以指定的名称写入文件
2.3.2 使用字节输出流写数据的步骤:
创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
调用字节输出流对象的写数据方法
释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)
2.4 字节流写数据的3种方式
方法名 | 说明 |
---|---|
void write(int b) | 将指定的字节写入此文件输出流,一次写一个字节数据 |
void write(byte[] b) | 将b.length字节文件从指定的字节数组写入此文件输出流,一次写一个字节数组数据 |
void write(byte[] b,int off,int len) | 将len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流。一次写入一个字节数组的部分数据 |
2.5 字节流写数据的两个小问题
2.5.1 字节流写数据如何实现换行呢?
写完数据后,加换行符
window:\r \n
linux:\n
mac:\r
2.5.2 字节流写数据如何实现追加写入呢?
public FileOutputStream(String name,boolean append)
创建文件输出流以指定名称写入文件,如果第二个参数位true,则字节将写入文件的末尾而不是开头
2.6 字节流写数据加异常处理
finally:在异常处理时提供finally块来执行所有清除操作,比如清除操作、比如IO流中的释放资源
特点:被finally控制的语句一定会执行,除非JVM退出
try{
可能出现异常的代码;
}
catch (异常类名 变量名){
异常的处理代码;
}finally{
执行所有清除操作;
}
2.7 字节流读数据(一次读一个字节数据)
2.7.1 字节流读数据
FileInputStream:从文件系统中的文件获取输入字节
FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名 name命名
2.7.2 使用字节输入流读数据的步骤:
创建字节输入流对象
调节字节输入流对象的读数据方法
释放资源
2.8 字节缓冲流
2.8.1 字节缓冲流:
BufferedOutputStream:该类实现缓冲输出流。通过设置这样的输出流。应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用
BufferedInputStream:创建BufferedIutputStream将创建一个内部缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节。
2.8.2 构造方法:
字节缓冲输出流:BufferedOutputStream(OutputStream out)
字节缓冲输入流:BufferedInputStream(InputStream in)
2.8.3 为什么构造方法需要的是字节流,而不是具体的文件或者路径呢?
字节缓冲流仅仅提供缓冲区,而真正的读写数据还得依靠基本的字节流对象进行操作
3. 字符流
由于字节流操作中文不是很方便,所以Java就提供字符流
字符流=字节流+编码表
用字节流复制文本文件时,文本文件也会有中文但是没有问题,原因是最终底层操作会自动进行字节拼接成中文,如何识别是中文呢?
汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数
p290
进程和线程
1. 实现多线程
1.1 进程
进程:是正在运行的程序
是系统进行资源分配和调用的独立单位
每一个进程都有他自己的内存空间和系统资源
1.2 线程
线程:是进程中的单个顺序控制流,是一条执行路径
单线程:一个进程如果只有一条执行路径,则称为单线程程序
多线程:一个进程如果有多条执行路径,则称为多线程程序
1.3 多线程的实现方式
1.3.1 继承Thread类
定义一个类MyThread继承Thread类
在MyThread类中重写run()方法
创建MyThread类的对象
启动线程
两个小问题
问什么要重写run()方法?
因为run()是用来封装被线程执行的代码
run()方法和start()方法的区别?
run():封装线程执行的代码,直接调用,相当于普通方法的调用
start():启动线程;然后由JVM调用此线程的run()方法
1.3.2 实现Runnable接口
定义一个类MyRunnable实现Runnable接口
在MyRunnable类中重写run()方法
创建MyRunnable类的对象
创建Thread类的对象,把MyRunnable对象作为构造方法的参数
启动线程
相比继承Thread类,实现Runnable接口的好处
避免了Java单继承的局限性
适合多个相同程序的代码去处理同一个资源的情况,把线程和程序的代码,数据有效分离,较好的体现了面向对象的设计思想
1.4 设置和获取线程名称
Thread类中设置和获取线程名称的方法
void setName(String name):将此线程的名称更改为等于参数name
String getName():返回此线程的名称
通过构造方法也可以设置线程名称
如何获取main()方法所在的线程名称?
public static Thread currentThread();返回对当前正在执行的线程对象的引用
1.5 线程调度
线程有两种调度模型
分时调度模型:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片
抢占式调度模型:优先让优先级高的线程使用CPU,如果线程优先级相同,那么会随机选择一个,优先级高的线程获取CPU时间片相对多一些
Java使用的是抢占式调度模型
假如计算机只有一个CPU,那么CPU在某一个时间只能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行指令,所以说多线程程序的执行是有随机性,因为谁抢到CPU的使用权是不一定的
Thread类中设置和获取线程优先级的方法
public final int getPriority(); 返回此线程的优先级
public final void setPriority(int newPriority); 更改此线程的优先级
线程默认优先级是5;线程优先级的范围是:1-10
线程优先级高仅仅表示线程获取的CPU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看到你想要的效果
1.6 线程控制
方法名 | 说明 |
---|---|
static void sleep(long mills) | 使用当前正在执行的线程停留(暂停执行)指定的毫秒数 |
void join() | 等待这个线程死亡 |
void setDaemon(boolean on) | 将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出 |
1.7 线程的生命周期
2. 线程同步
2.1 相同的出现多次,出现负数原因:线程执行的随机性导致
2.2 多线程程序是否会有数据安全问题的标准
是否是多线程环境
是否共享数据
是否有多条语句操作共享数据
如何解决多线程安全问题呢?
基本思想:让程序没有安全问题环境
怎么实现呢?
把多条语句操作共享数据的代码给锁起来,让任一时刻只能有一个线程执行即可
Java提供了同步代码块的方式来解决
2.3 同步代码块
锁多条语句操作共享数据,可以使用同步代码块实现
格式:
synchronized(任意对象){
多条语句操作共享数据的代码
}
synchronized(任意对象):相当于给代码加锁了,任意对象就可以看成是一把锁
同步的好处和弊端
好处:解决了多线程的数据安全问题
弊端:当线程很多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率
2.4 同步方法
同步方法:就是把synchronized关键字加到方法上
格式:
修饰符 synchronized 返回值类型 方法名(方法参数) { }
同步方法的锁对象是什么呢?
this
同步静态方法:就是把synchronized关键字加到静态方法上
格式:
修饰符 static synchronized 返回值类型 方法名(方法参数) { }
同步静态方法的锁的对象是什么呢?
类名.class
2.5 线程安全的类
StringBuffer
线程安全,可变的字符序列
从版本JDK 5开始,被StringBuilder 替代。通常应该使用StringBuilder类,因为它支持所有相同的操作,但它更快,因为它不执行同步
Vector
从Java 2平台v1.2开始,该类进行了改进,实现Map接口,使其成为Java Collections Framework 的成员。与新的集合
Hashtable
该类实现了一个哈希表,它将键映射到值。任何非null对象都可以用作键或值
从Java 2平台v1.2开始,该类进行了改进,实现了Map接口,使其成为Java Collections Framework成员,与新的集合实现不同,Hashtable被同步。如果不需要线程安全的实现,建议使用HashMap代替Hashtable
2.5 Lock锁
Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作
Lock中提供了获得锁和释放锁的方法
void lock() : 获得锁
void unlock() : 释放锁
Lock是接口不能直接实例化,这里采用他的实现类ReentrantLock来实例化
ReentrantLock的构造方法
ReentrantLock() : 创建一个ReentrantLock的实例
3. 生产者消费者
3.1 生产者消费者模式概述
-
生产者消费者模式是一个十分经典的多线程协作的模式,弄懂生产者消费者问题能够让我们对多线程编程的理解更加深刻
-
所谓生产者消费者问题,实际上主要包含了两类线程:
一类是生产者线程用于生产数据
一类是消费者线程用于消费数据 -
为了解耦生产者和消费者的关系,通常会采用共享的数据区域,就像是一个仓库
生产者生产数据之后直接放置在共享数据区中,并不需要关心消费者的行为
消费者只需要从共享数据区域中去获取数据,并不需要关心生产者的行为 -
为了生产和消费过程中的等待和唤醒,Java就提供了几个方法供我们使用,这几个方法在Object类中。Object类的等待和唤醒方法:
|方法名 |说明 |
|–|–|
| void wait() | 导致当前线程等待,直到另一个线程调用该对象的notify()方法或notifyAll()方法 |
| void notify() | 唤醒正在等待对象监视器的单个线程|
|void notifyAll() | 唤醒正在等待对象监视器的所有线程 |