JavaSE笔记
最后更新时间:2022年9月20日
参考书籍:Java核心技术 卷1
一、Java基础
1、8中基本数据类型及默认值:
-
byte short int long 这四种基本数据类型数组默认值为0
-
float double 这两种数组默认值是0.0
-
char这种类型数组默认值为空格
-
boolean类型数组默认值为false
2. for循环
2.1传统for循环
for(表达式 1;表达式 2;表达式 3){
语句序列
}
2.2增强for循环(foreach)
foreach语句是for语句的特殊简化版本,不能完全取代for语句,但任何foreach语句都可以改写为for语句版本。foreach并不是一个关键字,习惯上将这种特殊的for语句格式称为foreach语句。foreach语句在遍历数组等方面为程序员提供了大量方便
for(元素类型 x:遍历对象 obj){
引用了x的java语句
}
foreach语句中的元素变量 x,不必对其进行初始化。
public class Test04 {
public static void main(String[] args) {
int arr[] ={2,5,6};
System.out.println("一维数组中的元素分别为:");
//x的类型与arr元素的类型相同。for循环依次取出arr中的值并赋给x
for (int x :arr ) {
System.out.println(x);
}
}
}
//一维数组中的元素分别为:
//2
//5
//6
3.数组的复制
System.arraycopy(src , srcPos,dest,destPos,length);
- src :源数组
- srcPos:原数组起始索引
- dest:目标数组
- destPos:目标数组的起始索引
- length:在这里插入代码片
4.数组的排序的方法
4.1冒泡排序(Bubble esort)
public class Bubblesort {
public static void main(String[] args) {
int[] numbers=new int[]{1,5,8,2,3,9,4};
//需进行length-1次冒泡
for(int i=0;i<numbers.length-1;i++)
{
for(int j=0;j<numbers.length-1-i;j++)
{
if(numbers[j]>numbers[j+1]) //需要从大到小排序将大于号改为小于号
{
int temp=numbers[j];
numbers[j]=numbers[j+1];
numbers[j+1]=temp;
}
}
}
System.out.println("从小到大排序后的结果是:");
for(int i=0;i<numbers.length;i++)
System.out.print(numbers[i]+" ");
}
4.2快速排序(Quicklysort)
public class Quicklysort {
public static void main(String[] args) {
int a[]= {3,4,11,2,0,9,8,5,7};
Quicksort(a,0,a.length-1);
for (int i : a) {
System.out.print(i+" ");
}
}
private static void Quicksort(int[] a, int left, int right) {
if(left>right)
return;
int i=left;
int j=right;
int base=a[left];
while(i!=j) {
while(a[j]>=base&&i<j)
j--;
while(a[i]<=base&&i<j)
i++;
int temp;
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
a[left]=a[i];
a[i]=base;
Quicksort(a,left,i-1);
Quicksort(a,i+1,right);
}
4.3 反转排序(Reversesort)
public class Reversesort {
public static void main(String[] args) {
Reversesort xl = new Reversesort();
//创建冒泡排序类的对象
Scanner input = new Scanner(System.in);
int[] array = new int[4];
//定义一个长度为4的数组
for (int i = 0 ; i < array.length ; i++){
System.out.println("请输入第" + (i+1) + "个数字");
array[i] = input.nextInt();
}
System.out.println("排序前:");
xl.pxunprint(array);
//使用for循环,让用户输入数字
System.out.println("排序后:");
xl.pxun(array);
//调用排序方法
}
public void pxun(int[] array){
for (int i = 0 ; i < array.length/2 ; i++){
int a = array[i];
array[i] = array[array.length-i-1];
array[array.length-i-1] = a;
}
pxunprint(array);
}
//排序方法
public void pxunprint(int[] array){
for (int i : array){
System.out.print(i + " ");
}
System.out.println();
}
//输出每个数组元素的方法
}
4.4 插入排序(insertSort)
public static void insertSort(int[] array){
// 第一个元素被认为默认有序,所以遍历无序元素从i1开始。
for(int i=1;i<array.length;i++){
int sortItem = array[i];
int j = i;
// 将当前元素插入到前面的有序元素里,将当前元素与前面有序元素从后往前挨个对比,然后将元素插入到指定位置。
while (j>0 && sortItem < array[j-1]){
array[j] = array[j-1];
j--;
}
// 若当前元素在前面已排序里面不是最大的,则将它插入到前面已经确定了位置里。
if(j !=i){
array[j] = sortItem;
}
}
}
5.成员变量和局部变量
Java 语言中变量按声明的位置分类,可以分为:成员变量、局部变量,而成员变量又分为:实例变量、全局变量。实例变量是指不使用static修饰的变量,全局变量是指使用static修饰的变量。 局部变量包括:方法内声明的变量、方法的形参、构造器的形参、代码块内声明的变量。
相同点:
- 1.声明格式相同
格式: 数据类型 变量名 = 变量值 - 2.变量,必须先声明后使用
- 3.变量,都有其作用域
不同点:
-
1.声明的位置不同:
成员变量:直接声明在类的内部
局部变量:方法内声明的变量
方法的形参、构造器的形参
代码块内声明的变量。 -
2.权限修饰符的使用:
成员变量:可以在声明的类型前,指明权限修饰符。
权限修饰符有:private、public、protected、缺省
局部变量:不可以声明权限修饰符 -
3.默认初始化值:
成员变量:在声明时,如果没有显示赋值。则其有默认初始化值。
byte/short/int/long : 0
float/double : 0.0
char : 0 或 ‘\u0000’
boolean : false
引用类型: null
局部变量:在使用变量前,一定要进行显示初始化。即:局部变量没有初始化值
对于方法的形参(局部变量的一种)而言,是在调用方法时,给形参赋值。 -
4.在内存中加载的位置不同:
成员变量:声明在堆空间中
局部变量:声明在栈空间中
二、面向对象
1.封装 (属性私有化方法公开化)
定义:
利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体。数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。用户无需知道对象内部的细节,但可以通过对象对外提供的接口来访问该对象。
优点
- 减少耦合: 可以独立地开发、测试、优化、使用、理解和修改
- 减轻维护的负担: 可以更容易被程序员理解,并且在调试的时候可以不影响其他模块
- 有效地调节性能: 可以通过剖析确定哪些模块影响了系统的性能
- 提高软件的可重用性
- 降低了构建大型系统的风险: 即使整个系统不可用,但是这些独立的模块却有可能是可用的
2.继承
-
继承实现了 IS-A 关系,例如 Cat 和 Animal 就是一种 IS-A 关系,因此 Cat 可以继承自 Animal,从而获得 Animal 非 private 的属性和方法。
-
继承应该遵循里氏替换原则,子类对象必须能够替换掉所有父类对象。
-
Cat 可以当做 Animal 来使用,也就是说可以使用 Animal 引用 Cat 对象。父类引用指向子类对象称为 向上转型 。
3.多态
多态分为编译时多态和运行时多态:
编译时多态主要指方法的重载
运行时多态指程序中定义的对象引用所指向的具体类型在运行期间才确定
运行时多态有三个条件:
- 继承
- 覆盖(重写)
- 向上转型
4.重载与重写
- 方法重载:
同名不同参(参数不同:数量不同,参数类型不同,参数顺序不同)方法重载跟返回值类型没有关系、方法重载跟访问权限修饰符没有关系、方法重载在同一个类中
在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同甚至是参数顺序不同)则视为重载。同时,重载对返回类型没有要求,可以相同也可以不同,但不能通过返回类型是否相同来判断重载。
- 方法重写:同名同参同返回值
在子类继承父类中,子类的访问权限必须大于等于父类方法
子类方法的返回类型必须是父类方法返回类型或为其子类型
子类中把父类本身有的方法重新写一遍。子类继承了父类原有的方法,但有时子类并不想原封不动的继承父类中的某个方法,所以在方法名,参数列表,返回类型(除过子类中方法的返回值是父类中方法返回值的子类时)都相同的情况下, 对方法体进行修改或重写,这就是重写。但要注意子类函数的访问修饰权限不能少于父类的。
5.静态变量和静态方法(static)
静态变量与静态方法的作用通常是为了提供共享数据或方法
5.1静态变量(类变量)
也就是说这个变量属于类的,类所有的实例都共享静态变量,可以直接通过类名来访问它;静态变量在内存中只存在一份。
实例变量: 每创建一个实例就会产生一个实例变量,它与该实例同生共死。
6.final关键字
作用: 在Java中声明类、变量和方法时,可使用关键字final来修饰,表示"最终的,不可更改的".
使用范围: 在Java中,可用final修饰变量、成员属性、成员方法、类本身
-
类 :final修饰的类不能有子类,不能被继承(太监类)
-
方法:final 修饰的方法不能被重写
-
属性:final 修饰的属性必须要赋初始值;而且不能被修改
-
临时变量 :final 可以修饰临时变量,但临时变量不能修改
7.super与this的比较
- 调用super()必须写在子类构造方法的第一行, 否则编译不通过
- super从子类调用父类构造, this在同一类中调用其他构造均需要放在第一行
- 尽管可以用this调用一个构造器, 却不能调用2个
- this和super不能出现在同一个构造器中, 否则编译不通过
- this()、super()都指的对象,不可以在static环境中使用
- 本质this指向本对象的指针。super是一个关键字
8.构造函数
访问权限修饰符 返回值类型 方法名(参数列表){}
1:类中是默认存在无参构造函数
2:若类中写了有参的构造函数,则默认的无参构造函数自动消失
Person person = new Person();调用类中的构造函数,返回的是这个类对应的一个对象
3:构造函数支持方法重载
4:构造函数可以私有化:在别的类中无法new出对象
5:单例模式
(1)申明一个静态的属性
(2)构造函数私有化
(3)提供一个静态的公开的方法返回对象
优点:只创建一个对象,节省内存资源
8.抽象类与接口
-
抽象类中可以有普通方法,也可以有抽象方法
-
抽象类中可以有构造函数,不可以创建抽象类的对象
-
抽象类中可以有静态代码块,代码块
-
抽象类中可以用static修饰属性,也可以修饰方法;可以用final修饰
8.1:成员的区别
抽象类:
构造方法:有构造方法,用于子类实例化使用。
成员变量:可以是变量,也可以是常量。
成员方法:可以是抽象的,也可以是非抽象的。
接口:
构造方法:没有构造方法
成员变量:只能是常量。默认修饰符:public static final
成员方法:jdk1.7只能是抽象的。默认修饰符:public abstract (推荐:默认修饰符请自己永远手动给出)
jdk1.8可以写以default和static开头的具体方法
8.2类和接口的关系区别
类与类:
继承关系,只能单继承。可以多层继承。
类与接口:
实现关系,可以单实现,也可以多实现。
类还可以在继承一个类的同时实现多个接口。
接口与接口:
继承关系,可以单继承,也可以多继承。
8.3体现的理念不同
抽象类里面定义的都是一个继承体系中的共性内容。
接口是功能的集合,是一个体系额外的功能,是暴露出来的规则。
9.常用工具类
9.1 Math类
方法 | 说明 |
---|---|
static int / long / float / double abs(int / long / float / double a ) | 返回a的绝对值 |
static int max(int a,int b) | 返回x和y的最大值 |
9.2 system
- currentTimeMillis方法: 该方法的作用是返回当前的计算机时间
9.3 String类
作用:处理Java中的字符串
注意:
- String是一个final类,代表不可变的字符序列。
- 字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。
- String对象的字符内容是在存储在一个字符数组value[]中的
- String类不能被继承
常用方法:
方法 | 含义 |
---|---|
int length() | 返回字符串的长度:return value.length |
char charAt(int index) | 返回某处索引处的字符return value[index] |
boolean isEmpty() | 判断是否是空字符串:return value.length == 0 |
String toLowerCase() | 使用默认语言环境,将String中所有的字符转换为小写 |
String toUpperCase() | 使用默认语言环境,将String中所有的字符转换为大写 |
String trim() | 返回字符串副本,忽略前导空白和尾部空白 |
boolean equals(Object obj) | 比较字符串的内容是否相同 |
boolean equalslgnoreCase(String anotherString) | 与equals方法类似,忽略大小写 |
String concat(String str) | 将指定字符串接到此处字符串的结尾。等价于用+ |
int compareTo(String anotherString) | 比较两个字符串的大小 |
String substring(int beginIndex) | 返回一个新的字符串,它是字符串的从beginIndex开始截取到最后的一个子字符串 |
9.4 String、StringBuffer、StringBuilder比较
- StringBuffer
1、StringBuffer可以被继承
2、使用append方法进行字符串拼接,不可以使用加号进行字符串的拼接
3、StringBuffer的变量值确定之后可以被更改的,表示值得char[] value没有被final修饰
4、append是被synchronize修饰,是线程安全的、效率低 - StringBuilder
1、StringBuilder不可以被继承 。
2、使用append方法进行字符串拼接,不可以使用加号进行字符串的拼接
3、append没有被synchronize修饰,是线程不安全的、效率更高
4、StringBuilder的变量值确定后 可以被更改,表示值得char[] value没有被final修饰 - String
1、不能被继承
2、使用加号进行字符串拼接
3、String的变量值确定之后不可以改变;因为String的类中char[]是被final 修饰了
10.正则表达式
(常用正则表达式)
- 正则表达式:正确规则的表达式;通常用来检测字符是否符合某规则、根据某规则切分字符串或替换符合规则的文本
注意点:
[]中的取值范围一般用 -
{}中取值范围一般用 ,
String emailReg = “[1-9]{1}[0-9]{4,9}@qq.com”
boolean f = email.matches(emailReg);
正则表达式的应用:
用户注册功能:在获取用户输入的信息之后,判断用户
example:
按需求完成下列功能注册,依次获取控制台输入的用户名,密码,邮箱,手机号,当满足对应的要求规则时,则提示注册成功,若不满足,则提示不满足规则,请重新输入
用户名规则:第一位为大写字母,2,3,4位为小写字母,后由数字组成,总长度为6~8位
String name = “[A-Z]{1}[a-z]{2,3,4}[0-9]{2,4}”
密码规则:总长度6-12位,由数字,大小写字母任意组成
邮箱规则:首字位为1,第二字位为3,4,5,7,8中的一个,后面的取值范围为[0-9],个数为9个,最后以@163.com结尾,总长度为19位。
手机号的规则:要求为11位数字,第1位为1,第二位为3,4,5,7,8中的一个,后面9位为0到9之间的任意数字。
11.时间类
DateFormat是一个抽象类,不能创建对象,需要使用它的子类。它的子类不需要我们自己创建,而是java帮我们创建过了,simpleDataFormat,它是一个不与语言环境有关的方式来格式化和解析日期的具体类。
格式(日期---->文本)
- simpleDataFormat():默认的模式和语言环境创建对象
- public SimpleDataFormat(String pattern):该构造方法可以用参数pattern指定的格式创建一个对象,该对象调用public String format(Date date)方法格式化时间对象date
解析(文本---->日期):
- public Date parse(String source):从给定的字符串的开始解析文本,以生成一个日期
利用DateFormat对象进行字符串时间格式的转换
注意点:声明DataFormat对象时需要指定时间的格式
String str = “2022-09-12 12:12:12”
DataFormat df = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);
三、集合
1、概述
Java集合用来解决数组的弊端,提供更大的数据处理能力。它可以存储数量不等的多个对象,还可用于保存具有映射关系的关联数组。
1.1Java数组的弊端:
- 数组初始化以后,长度就确定了,不便于扩展
- 数组声明的类型,就决定了进行元素初始化时的类型
- 数组中提供的属性和方法少,不便于进行添加、删除、插入等操作,且效率不高。同时无法直接获取存储元素的个数
1.2Java集合的分支体系
- Collection接口(里面存储的都是value对象)
- List(Collection的实现,他自己也是一个接口)
特点:有序可重复
序:顺序,即添加进去的元素与取得元素的顺序一致
重复:两个对象元素一致 - Set(Collection的实现,它自己也是一个接口)
特点:无序无重复
- List(Collection的实现,他自己也是一个接口)
- Map接口(存储的都是以Key-value形式存在,key无序无重复,value无序可重复)
1.3容器优点
- 降低编程难度
- 提高程序性能
- 提高API间的互操作性
- 降低学习难度
- 降低设计和实现相关API的难度
- 增加程序的重用性
2、Collection接口
Collection接口是List、set的父接口,该接口里定义的方法既可用于操作Set集合,也可以用于操作List集合
- Collection接口常用方法
方法 | 含义 |
---|---|
add(Object obj) | 添加元素 |
addAll(Collection coll) | 批量添加元素 |
int size() | 获取有效元素的个数 |
void clear() | 清空集合 |
boolean isEmpty() | 是否清空集合 |
boolean contains(Object obj) | 是否包含某个元素,通过元素的equals方法来判断是否是同一个对象 |
boolean containsAll(Collection c) | 是否包含某个元素,也是调用元素的equals方法比较的。拿两个集合的元素挨个比较 |
boolean remove(Object obj) | 通过元素的equals方法判断是否是要删除的那个元素。只会删除找到的第一个元素 |
boolean removeAll(Collection coll) | 取当前集合的差集 |
boolean retainAll(Collection c) | 把交集的结果存在当前结集合中,不影响c |
Object[] | toArray) |
iterator() | 返回迭代器对象,用于集合遍历 |
- Collections是关于集合的工具类,内部含有很多操作集合的静态方法
- collection是关于集合的一个接口
3、List接口
特点:
- List集合类中元素有序、可重复 ,集合中的每个元素都有其对应的顺序索引。
- List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
JDK API中List接口的实现类常用的有:ArrayList、LinkedList。
List除了从Collection集合继承的方法外,还添加了一些根据索引来操作集合元素的方法:
方法 | 含义 |
---|---|
void add (int index,Object ele) | 在index位置插入ele元素 |
boolean addAll(int index,Collection eles) | 从index位置开始将eles中的所有元素添加进来 |
Object get(int index) | 获取指定index位置的元素 |
int indexOf(Object obj) | 返回obj在集合中首次出现的位置 |
int lastIndexOf(Object obj) | 返回obj在当前集合中末次出现的位置 |
Object remove(int index) | 移除指定index位置的元素,并返回此元素 |
Object set (int index , Object ele) | 设置指定index位置的元素ele |
List subList(intfromIndex,int toIndex) | 返回fromIndex到toIndex位置的子集合 |
4.泛型
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
- 注意:
泛型的引用不可以是基本数据类型,必须是引用数据类型
泛型可以指定数组,因为数组是引用数据类型
5、Map接口
- Map与Collection并列存在。用于保存具有映射关系的数据:key-value
- Map 中的 key 和 value 都可以是任何引用类型的数据
- Map 中的 key 用Set来存放,不允许重复,即同一个 Map 对象所对应的类,须重写hashCode()和equals()方法
- key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到唯一的、确定的 valueMap接口的常用实现类:HashMap、TreeMap、LinkedHashMap和Properties。其中,HashMap是 Map 接口使用频率最高的实现类
四、异常
1、异常的分类:
运行期异常和编译期异常
2、异常的处理方式:
try{}catch(){};抛出去
看异常信息:根据控制台的异常信息定位代码的问题所在
常见异常:
- 数组下标越界java.lang.ArrayIndexOutOfBoundsException
- 空指针异常
- 日期与字符串的格式转换
- 算术异常(分母为0)java.lang.ArithmeticException
- 类型转换异常 数据类型
- 文件未找到(FileNotFound)
- 类找不到(ClassNotFound)
- NoSuchBean
3、异常关键字
- try – 用于监听。将要被监听的代码(可能抛出异常的代码)放在try语句块之内,当try语句块内发生异常时,异常就被抛出。
- catch – 用于捕获异常。catch用来捕获try语句块中发生的异常。
- finally – finally语句块总是会被执行。它主要用于回收在try块里打开的物力资源(如数据库连接、网络连接和磁盘文件)。只有finally块,执行完成之后,才会回来执行try或者catch块中的return或者throw语句,如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止。
- throw – 用于抛出异常。
- throws – 用在方法签名中,用于声明该方法可能抛出的异常。
4、异常的声明(throws)
在Java中,当执行的语句必属于某个方法,Java解释器调用main方法执行开始执行程序。若方法中存在检查异常,如果不对其捕获,那必须在方法头中显示声明该异常,以便告知方法调用者此2方法有异常,需要进行处理。在方法中声明一个异常,方法头中便于关键字throws,后面接上要声明的异常。若声明多个异常,则使用逗号分割。
public static void method() throws IOException, FileNotFoundException{
//something statements
}
-
注意:
若是父类的方法没有声明异常,则子类继承后,也不能声明异常。 -
通常,应该捕获那些知道如何处理的异常,将不知道如何处理的异常继续传递下去。传递异常可以在方法签名处使用 throws 关键字声明可能会抛出的异常。
- 如果是不可查异常(unchecked exception),即Error、RuntimeException或它们的子类,那么可以不使用throws关键字来声明要抛出的异常,编译仍能顺利通过,但在运行时会被系统抛出。
- 必须声明方法可抛出的任何可查异常(checked exception)。即如果一个方法可能出现受可查异常,要么用try-catch语句捕获,要么用throws子句声明将它抛出,否则会导致编译错误
- 仅当抛出了异常,该方法的调用者才必须处理或者重新抛出该异常。当方法的调用者无力处理该异常的时候,应该继续抛出,而不是囫囵吞枣。
- 调用方法必须遵循任何可查异常的处理和声明规则。若覆盖一个方法,则不能声明与覆盖方法不同的异常。声明的任何异常必须是被覆盖方法所声明异常的同类或子类。
5、异常的抛出(throw)
如果代码可能会引发某种错误,可以创建一个合适的异常类实例并抛出它,这就是抛出异常。如下所示:
public static double method(int value) {
if(value == 0) {
throw new ArithmeticException("参数不能为0"); //抛出一个运行时异常
}
return 5.0 / value;
}
大部分情况下都不需要手动抛出异常,因为Java的大部分方法要么已经处理异常,要么已声明异常。所以一般都是捕获异常或者再往上抛。
6、异常的自定义
习惯上,定义一个异常类应包含两个构造函数,一个无参构造函数和一个带有详细描述信息的构造函数(Throwable 的 toString 方法会打印这些详细信息,调试时很有用), 比如上面用到的自定义MyException:
public class MyException extends Exception {
public MyException(){ }
public MyException(String msg){
super(msg);
}
}
五、IO流
- 输入流:把数据从其他设备上读取到内存中的流。
- 输出流:把数据从内存中写到其他设备上的流
以内存(程序)为基准去记 - 关闭流的步骤:先开后关;后开的先关
格局数据的类型分为:字节流和字符流
字节流:以字节为单位,读取数据的流
字符流:以字符为单位,读取数据的流
输入流 | 输出流 | |
---|---|---|
字节流 | 字节输入流InputStream | 字节输出流OutputStream |
字符流 | 字符输入流Reader | 字符输出流Writer |
1、 字节输入流读取文件在控制台输出
public static void main(String[] args) {
InputStream is = null;
try {
String path = "D://wk.txt";
File file = new File(path);
is = new FileInputStream(file);
byte []b = new byte[1024];
//2:利用字节输入流对象进行读取文件中的数据
int i ;
int len = 0;
while ((i= is.read())!= -1){
//执行读取到的数据 进行操作 i的值为-1时就读完
byte num = (byte) i;
b[len] = num;
len++;
}
System.out.println(new String(b,0,len));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
if(is!=null){
try {
is.close();//关闭流操作
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
2、字节输出流在磁盘中创建一个文件
public static void main(String[] args) {
//创建出 输出流对象,用来写文件
String path = "D://wk1.txt";
OutputStream os = null;
File file = new File(path);
String str = "芜湖起飞";
try {
os = new FileOutputStream(new File("D://wk1.txt"));
byte []b =str.getBytes();
os.write(b);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if(os!=null){
try {
os.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
3、用字节流复制图片
public static void main(String[] args) {
InputStream is = null;
OutputStream os = null;
try {
is = new FileInputStream(new File("D://bac.png"));
os =new FileOutputStream(new File("E://bac1.png"));
int i ;
while ((i = is.read())!=-1){
os.write(i);
}
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
if(is!=null){
try {
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(os!= null){
try {
os.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
4、字符流输入
public static void main(String[] args) {
Reader reader = null;
char []b = new char[1024];
try {
reader = new FileReader(new File("D://wk.txt"));
int i ;
int len = 0;
while ((i=reader.read())!=-1){
b[len]=(char) i;
len++;
}
System.out.println(new String(b,0,len));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
if(reader!=null){
try {
reader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
5、字符流输出
public class test12 {
public static void main(String[] args) {
Writer writer = null;
String str = "qwer";
try {
writer = new FileWriter(new File("D://b.txt"));
writer.write(str);
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
if(writer!=null){
try {
writer.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
6、字符流复制
public class Test14 {
public static void main(String[] args) {
Reader reader = null;
Writer writer = null;
try {
reader = new FileReader(new File("D://wk.txt"));
writer = new FileWriter(new File("D://1.txt"));
int i;
while((i = reader.read())!= -1) {
writer.write(i);
}
} catch (FileNotFoundException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}finally {
if(reader!=null) {
try {
reader.close();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
if(writer!=null) {
try {
writer.close();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
}
7、缓冲流输出
public class Test13 {
public static void main(String[] args) {
String str = "芜湖,起飞";
BufferedWriter bw = null;
Writer out = null;
try {
out = new FileWriter(new File("D://a.txt"));
bw = new BufferedWriter(out);
bw.write(str);//利用缓冲流去写入
//缓冲流:存在一个缓冲区;当数据量达到一定的时候,一次性写入(一次性:刷新缓冲流)
bw.newLine();//换行
bw.flush();//刷新缓冲流
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
六、多线程
6.1概念
基本概念
程序:可以理解为是一组静态代码
进程(process):正在进行(执行)的程序,是静态的代码运行起来
线程(thread):操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
注意:
- 若一个进程统一时间并行执行多个线程,就是支持多线程的
- 线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开销小
- 一个进程中的多个线程共享相同的内存单元/内存地址空间它们从同一堆中分配对象,可以访问相同的变量和对象。这就使得线程间通信更简便、高效。但多个线程操作共享的系统资源可能就会带来安全的隐患。
- 启动一个Java程序就会启动一个JVM,每个JVM实际上就是在操作系统中启动一个进程,每个Java程序的运行至少有三个线程: main()主线程,gc()垃圾回收线程,异常处理线程
- 线程不属于任何语言,属于操作系统级别,CPU说了算
- 线程就是独立的执行路径;
- 在程序运行时,即使没有自己创建,后台也会有多个线程,如主线程,gc线程;
- main()称之为主线程,为系统的入口,用于执行整个程序;
- 在一个进程中,如果开辟多个线程,线程的运行由调度器安排,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的;
- 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;
- 线程会带来额外的开销,如CPU调度时间,并发控制开销;
- 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致;
6.2线程的创建
创建线程的方式一:继承Thread类,重写run()方法,调用start开启线程
注意:线程开启不一定立即执行,由CPU调度执行
public class TestThread extends Thread{
public void run(){
//run方法线程体
for (int i = 0;i<20;i++){
System.out.println(“富强、明主、文明、和谐———“+i);
}
}
public static void main (String[] rags){
//main线程,主线程
//创建一个线程对象
TestThread1 testThread1 = new TestThread1();
//调用start()方法开启线程
testThread1.start();
for(int i=0;i<200;i++){
System.out.println(“自由、平等、公正、法制——-“+i);
}
}
}
注意:
1、线程类的创建方式 继承Thread类,重写run();
2、线程的启动方式 创建线程对象,调用start();
sleep() 、 join()、yield()的区别
sleep():线程睡眠多长时间,时间已过,自动接着去执行
join();线程阻塞;当前停住。另一个阻塞的线程执行完成之后,阻塞才放行;
yield():线程让步,将CPU的资源让给别的线程,让别的线程有更大的概率获取到CPU资源
方法 | 含义 |
---|---|
void start() | 启动线程,并执行对象的run()方法 |
run() | 线程在被调度时执行的操作 |
String getName() | 返回线程的名称 |
void setName(String name) | 设置该线程名称 |
static void yield() | 线程让步,暂停当前正在执行的线程,把执行机会让给优先级或更高的线程,若队列中没有同优先级的线程,忽略此方法 |
join() | 当某个程序执行流中调用其他线程的join()方法时,调用线程将被阻塞,直到join()方法加入的join线程执行完为止 |
static void sleep (long millis) | 令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后重排队 |
stop() | 强制线程生命周期结合,不推荐使用 |
boolean isAlive() | 判断线程是否还活着 |
创建线程的方式
1、继承Thread类,重写run()方法
2、实现Runnable接口,重写run()
基于扩展性的考虑,因为类具有单继承,多实现的特性;所以一般情况下采用第二种 创建线程
6.3线程池
线程池(Thread pool):一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能,而线程池维护着多个线程。
线程池就是存放线程的池子,池子里存放了很多可以复用的线程。
创建线程和销毁线程的花销是比较大的(手动new Thread类),创建和消耗线程的时间有可能比处理业务的时间还要长。这样频繁的创建线程和销毁线程时比较消耗资源的。
- 使用线程池的优势
1、提高效率,创建好一定数量的线程放在池中,等需要使用的时候就从池中拿一个,这要比需要的时候创建一个线程对象要快的多
2、减少创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
3、提升系统响应速度,假如创建线程用的时间为T1,执行任务用的时间为T2,销毁线程用的时间为T3,那么使用线程池就免去了T1和T3的时间;
七、枚举
点击查看
枚举详细说明
注意:
1、枚举类中的构造方法的修饰是私有的,不能是public
2、声明枚举类中的常量;位置得写在枚举类的第一行
3、枚举类中的常量之间用逗号隔开;且最后结尾以分号结尾
4、枚举类中常量的名字命名全部大写
八、JDBC连接数据库步骤
1、添加MySQL数据库驱动包
2、编写测试类,加载数据库驱动类
3、获取数据库的连接对象
4、利用数据库的连接对象获取出执行SQL语句的对象
5、利用SQL语句的执行对象执行SQL语句(前提条件:SQL语句已备好)获取返回结果resultset
6、分析返回结果,获取到数据库中的具体信息
九、注解与反射
1、注解(Annotation)
Annotation的作用:
不是程序本身,可以对程序作出解释
可以被其他程序读取
内置注解
1、@override:定义在java.lang.Override中,此注释只适用于修饰方法,表示一个方法声明打算重写超类中的另一个方法声明。
2、@Deprecated:定义在java.lang.Deprecate中,此注释可以用于修辞方法,属性,类,表示不鼓励程序员使用这样的元素,通常是因为他很危险或者存在更好的选择。
3、@SuppressWarnings:定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息
元注解
-
元注解的作用就是负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型作说明。
-
这些类型和他们所支持的类在java.lang.annotation包中可以找到(@Target,@Retention,@Document,@Inherited)
- @Target:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
- @Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(SOURCE<CLASS<RUNTIME)
- @Document:说明该注解将被包含在javadoc中
- @Inherited:说明子类可以继承父类中的该注解
自定义注解
使用@interface自定义注解时,自动继承了java.lang.annotation接口
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class Test02 {
//注解可以显示赋值,如果没有默认值,我们就必须给注解赋值
@MyAnnotation(age = 18, name = "ai")
public void test() {
}
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
//注解的参数:参数类型+参数名();
String name() default "";
int age();
int id() default -1;//如果默认值为-1,代表不存在
String[] games() default {"荒野大嫖客","2077"};
}
2、反射机制(Reflection)
Reflection(反射)是java被视为动态语言的关键,反射机制允许程序在执行期借助ReflectionAPI取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
Class c = Class.forName(“java.lang.String”)
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。