本文章更适用初学Java了解详细概念和长时间有所忘记,也适用于需要参加面试和笔试的考前复习材料,总结如有不全,请多指正
目录
Java知识及应用
一.Java 开发入门
Java:面向对象的高级编程语言。
Jara SE 标准版
Java EE 企业版
Java ME 微型版
特点:1、简单2面向对象3、安全性 4.跨平台性(J V M ) 5.支持多线程 6.分布性
(J D K)Java开发环境:Java编译器、Java打包工具、Java运行工具、Java文档生成工具
J V M :Java虚拟机(核心类库)
J R M :Java运行环境(核心类库+编译及调试工具)
J D K :Java开发工具包(核心类库+编译及调试工具+开发辅助工具)
二. Java编程基础
1.基本格式
代码必须放在一个类中,类使用class定义,class前可以有类的修饰符。
修饰符class类名{代码 } public class Hello world
(1)可分为结构定义语句和功能执行语句,最后必须用;结束.
(2)Java是严格区分大小写
(3)常用的编排方式是一行只写一条语句.{与语句同行,}独占一行
(4)一个连续的字符串不能分成两行书写,用+将两个字符串起来,+后换行。
2.注释
①单行注释 “//”
②多行注释 “/,/”
②文档注释“/*,/”
3.标识符
(包名.类名、方法名、参数名、变量名)
1.不得以数字开头 2.不能是关键字3.不能包含特殊符号4.不能包含空格等特殊字符
要求 1.包名中所有字母一律小写 2.类名、接口名中首字母都要大写
3.常量名中所有字母都大写.字母间用—连接
4.关键字
package声明包 import引入包 class声明类
注意:
所有关键字都小写、
数据类型分为基本数据类型和引用数据类型,基本数据类型分为数值(整型、浮点型)、字符、布尔型,引用数据类型分为类、接口、数组、枚举、注释
5.常量
①整型常量.(二进制、八进制、十进制、十六进制)
二进制: Ob或OB为开头
八进制:以0开头
十六进制:0X或0x开头
②浮点数常量
单精度浮点数float F 或f结尾
双精度浮点数double D 或d结尾(默认)
③字符常量
英文半角格式的单引号(‘’)拾起,表示一个字符
④字符串串量
英文半角格式的双引号(“”)抬起,一串连续的字符.
⑤布尔常量
true(✔) ) false(x) 区分事物的真与假.
⑥null常量
6.变量
(用于标识内存单元的标识符)
①整型类型变量
byte 字节型 8位(1字节) -128~+127
shore 短整型 16位(2字节) -2^15~2^15-1
int 整型 32位(4字节) -2^31~2^31-1 (相加时默认)
long 长整型 64位(8字节) -2^63~2^63-1
②浮点数类型变量.
float 32位(4字节)
double 64位(8字节) (默认)
③字符型变量
与常量格式相同
D=48 A=65 a=97
④布尔型变量.
与常量相同.
7.变量的类型转换
( byte<short<int<long)
①自动类型转换
条件:1.类型兼容 2取值范围扩大
情况:1.整型之间转换 2.整型→flout 3、其他→double
②强制类型转换
目标类型 变量=(目标类型)值
byte b1=11
byte b2=22
byte b3=(byte)(b1+b2)
8.运算符
①算术运算符.
+正号/加号 -负号/减号 *乘 /除
%取值 ++自增(前/后) --后城(前/后)
自增(前) b=++a; 先自增,后赋值 a=a+1,a赋值给b
自增(后) b=a++; 先赋值,后自增 a赋值给b,a=a+1
②赋值运算符
= 赋值 += 加等于 -= 减等于
*= 乘等于 /= 除等于 %= 模等于
③比较运算符
==等于 !=不等于 <小于
>大于 <=小于/等于 >=大于/等于
④逻辑运算符
& 与 一假为假
| 或 全假力假
三.循环结构语句
1.while语句循环
While循环语句和选择结构语句类似,都是根据条件决定是否执行大括号内的执行语句。但while语句会反复进行循环条件判断,只要条件成立,{}内的执行语句就会执行,条件不成立,则while循环结束。
While(循环条件){ 执行语句 }
2.do…while循环语句
do…while循环语句语法结构如下:
do { 执行语句 }while(循环条件);
上述语法结构中,关键词do后面{}中执行语句是循环体。Do…while循环语句将循环条件放在循环体之后,也就是说,循环体会无条件执行一次然后再根据条件是否继续执行。
3.For语句循环
For循环语句是最常用的循环语句,一般在循环次数已知的情况下,for循环语句语法格式如下:
For(初始化表达式;循环条件;操作表达式){ 执行语句 }
For I式可以自动生成该格式。
4.循环嵌套
循环嵌套是指在一个循环语句的循环体中再定义一个循环语句的语法结构。While、do…while、for循环语句都可以进行嵌套。
For(初始化表达式;循环条件;操作表达式){ … For(初始化表达式;循环条件;操作表达式){ 执行语句 … } … }
5.跳转语句
Break语句。
当break出现在switch条件语句中,作用是终止某个case并跳出switch结构。当它出现在循环语句中,作用是跳出循环语句执行后面的代码。
Continue语句
Continue用在循环语句中。它的作用是终止本次循环,执行下一次循环。
四.方法
1.方法的定义
方法就是可以重复调用的有名称的代码。
Java中定义一个方法的语法格式如下:
修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2,…) //public static int add(int a,int b)// { 执行语句 Return返回值 }
可执行程序必须有main方法,是程序的入口。
修饰符:方法的修饰符比较多,例如,对访问权限进行限定的修饰符、static 修饰符、final修饰符等,这些修饰符在后面的学习过程中会逐步介绍
返回值类型:用于限定方法返回值的数据类型。
参数类型:用于限定调用方法时传人参数的数据类型
参数名:是一个变量,用于接收调用方法时传入的数据。
return 关键字:用于返回方法指定类型的值并结束方法。
2.方法的重载
参数不同的方法有相同的名字,调用时会根据参数不同来确定调用哪个方法,这就是Java方法的重载机制。方法重载在同一个作用域内,方法名相同但参数个数或是参数类型不同的方法。
五.数组
1.数组的基本要素
一个数组由四个基本元素构成:数组名称、数组元素、元素索引、数组类型。
数组类型【】数组名; 数组名=new 数组类型【长度】;
需要注意的是,数组中最小的索引是0,最大的索引是数组的长度减1。
2.数组的遍历
在操作数组时,经常需要依次访问数组中的每个元素,这种操作称为数组的遍历。
在循环遍历时需要使用数组索引作为循环条件,只要索引没有越界,就可以访问数组元素。
3.数组最值的获取
定义一个临时变量 max,用于记录数组的最大值。在获取数组中的最大值时,首先假设数组中第一个元素 arr[0]为最大值,并将其赋值给 max;然后使用 for 循环对数组进行遍历,在遍历的过程中只要遇到比 max 值大的元素,就将该元素赋值给 max,这样一来,变量 max 就能够在循环结束时记录数组中的最大值。
六.面向对象
1.面向对象
对象:所有客观存在的可以被描述的事或物.(属性及方法),特性有封装性、继承性和多态性。
类名 对象名=null; 对象名=new 类名();
使用:
类名 对象名=new 类名(); //如:Student stu=new Student();//
封装 (private):面向对象的核心思想,将对象的属性和行为看成一个不可分割的整体。属性和有化,提供公有的读写方法。获取属性get,设置属性Set
继承(extends):类与类之间的关系,子类继承父类的属性和方法。子类只能访问用public和protected修饰的属性和方法。
多态:不同类的对象在调用同一个方法时表现出的多种不同行为,方法的重载和方法的重写,子类不能使用比父类更严格的访问权限。
重载:参数或返回值数型不同的同名方法。
重写:子类对父类的方法进行重写。
2.类和对象
类是用于描述多个对象的共同特征,是对象的模板,用于描述一组对象的共同特征和行为,可以定义成员变量和成员方法。针对类、成员方法、属性,有四种控制权限:private:私有访问权限,只能在本类中访问;default:默认访问权限,只能在本包中访问;protected:受保护访问权限,其他包中子类可访问;public:公共访问权限,可被所有类访问。
Class类名{ 成员变量; 成员方法; }
3.代码块
用{ }括起来的一段代码,分为普通代码块、构造块、静态代码块、同步代码块。构造块是直接在类中定义的代码块,优先级高于构造方法。
4.关键字
this;用于区别成员变量与局部变量,主要作用:1.调用本类中的属性2.调用成员方法3.调用构造方法 ,必须用于第一行,且只能出现一次。
super:访问父类的非私有方法,属性及构造方法,调用父类构造方法的必须任于子类构建方法的第一行具有出现一次。
注意:this和super不能同时出现。
static:修饰的属性可共享,属性称为静态属性(全局属性),不解修饰局部复查,只能修饰成员定量,修饰静态方法和静态代码块
类名.属性名
final:“最终”修饰的类不能有子类、方法不能重写、质量为常量. 名称要大写.
内部类:1、成员内部类:外部类各内部类名内部类对象=外部类对象,new内部类名( )
2.局部内部类
3.静态内部类用static修饰的成员内部类
4.匿名内部类只能用一次的类
new继承的父类/接口名( ){}
5.继承
在程序中,继承描述的是事物之间的从属关系,通过继承可以使多种事物之间形成一种关系体系。Java中,类的继承时指在一个现有类的基础上构建一个新的类,构建的新类被称为子类,现有类被成为父类。Java中如果想声明一个类继承另一个类需要使用关键字extends。语法格式如下:
Class 父类{ … } Class 子类 extends父类{ … }
子类除了可以继承父类的属性和方法,也可以定义自己的属性和方法。
子类只能访问父类中用 public和 protected 修饰的属性和方法父类中被默认修饰符 default 和 private 修饰的属性和方法不能被子类访问。
类的继承重要注意以下问题:
(1)在Java 中,类只支持单继承,不允许多继承。也就是说,一个类只能有一个直接父类。
(2)多个类可以继承一个父类。
(3)在 Java 中,多层继承也是可以的,即一个类的父类可以再继承另外的父类。
6.方法的重写
在继承关系中,子类会自动继承父类中定义的方法,但在有时子类需要对继承的方法进行修改,即为对父类方法进行重写。
子类重写父类方法时,不能使用比父类的方法更为严格的访问权限。
7.super关键字
使用 super 关键字可以在子类中访问父类的非私有方法、非私有属性以及构造方法。
使用 super 关键字访问父类的非私有属性或调用父类的非私有方法,具体格式如下:
super.属性 super.方法(参数 1,参数 2,..)
使用super关键字调用父类中指定的构造方法,具体格式如下:
super (参数 1,参数 2,..)
通过super调用父类构造方法的代码必须位于子类构造方法的第一行且只能出现一次。This和super不能同时出现。
8.final关键字
在默认情况下,所有的成员变量和成员方法都可以被子类重写。如果父类的成员不希望被子类重写,可以在声明父类的成员时使用 final 关键字修饰。
(1)使用 final 关键字修饰的类不能有子类
(2)使用 final 关键字修饰的方法不能被子类重写
(3)使用 final 关键字修饰的量是常量,常量不可修改。
9.抽象类和接口
抽象方法是使用abstract关键字修饰的成员方法,抽象方式在定义时不需要实现方法体。语法格式如下:
Abstract 返回值类型 方法名称(参数列表)
当一个类包含了抽象方法,该类就是抽象类。
抽象类的定义比普通类多了一个或多个抽象方法,其他地方与普通类的组成基本相同。
抽象类的定义规则如下:
(1)包含抽象方法的类必须是抽象类
(2)声明抽象类和抽象方法时都要使用abstract关键字修饰
(3)抽象方法只需要声明而不需要实现。
(4)如果一个非抽象类继承了抽象类之后,那么该类必须重写抽象类中的全部抽象方法。
接口时一直用来定义程序的协议,用于定义类或结构的一组相关行为。使用接口的目的是克服单继承的限制。
七.异常
1.异常的定义
异常是指程序运行时(非编译时)所发生的非正常情况或错误,当程序违反了语义规则时JVM就会将出现的错误表示为一个异常并抛出。是程序执行过程不希望出现的问题,异常的对立面就是正常。
如果执行过程中出现了异常,JVM就会终止,应用程序随之终止。运行时异常和编译时异常在Exception类中,除了RuntimeException类及其子类外,Exception的其他子类都是编译时异常。
编译时异常的特点是Java编译器会对异常进行检查,如果出现异常就必须对异常进行处理,否则程序无法通过编译。RuntimeException类及其子类都是运行时异常。运行时异常的特点是Java编译器不会对异常进行检查。也就是说,当程序中出现这类异常时,即使没有使用try...catch语句捕获或使用throws关键字声明抛出,程序也能编译通过。运行时异常一般是由程序中的逻辑错误引起的,在程序运行时无法恢复。
2.异常处理及语法
try { // 可能会发生异常的代码块 } catch (ExceptionType e) { // 异常处理代码块 } finally { // 最终要执行的代码块
无论是否有异常都会执行try语句块用于尝试执行可能会发生异常的代码。如果在执行该代码块时出现异常,程序会跳转到catch语句块中,并执行异常处理代码。该语句块可以捕获一种或多种异常类型或其父类,也可以使用多个catch语句块对不同类型的异常进行不同的处理。finally语句块中的代码无论是否发生异常都会执行。throw(执行的时候一定抛出某种异常对象), throws(出现异常的可能性,不一定会发生),系统自动抛异常。语法如下
throw new ExceptionType (); public void methodName () throws ExceptionType { //方法体 }
3.抛出异常
抛出异常是java中一个程序处理动作。如果一个方法没有捕获可能引发的异常,调用该方法的其他方法应该捕获并处理异常。为了明确指出一个方法不捕获某类异常,而让调用该方法的其他方法捕获该异常,可以在定义方法的时候,使用throws可选项,用以抛出该类异常。Java有3种抛出异常的形式:throw(执行的时候一定抛出某种异常对象), throws(出现异常的可能性,不一定会发生),系统自动抛异常。
4.自定义异常
一般将自定义异常类的类名命名为 XXXException,其中 XXX 用来代表该异常的作用。
自定义异常类一般包含两个构造方法:一个是无参的默认构造方法,另一个构造方法以字符串的形式接收一个定制的异常消息,并将该消息传递给超类的构造方法。
八. 集合
1.集合的概念
为了存储不同类型的多个对象, Java 提供了一系列特殊的类,这些类可以存储任意类型的对象,并且存储的长度可变,这些类统称为集合。集合可以简单地理解为一个长度可变,可以存储不同数据类型的动态数组。
是所有集合类的基础接口,它定义了一些常用的方法,如add、remove、contains和size等。
2.Array List与LinkedList
Array List和LinkedList是实现了List接口的集合类,它们都可以按照元素的顺序来存储数据,但是Array List的访问速度比LinkedList快。
3.Iterator接口和foreach循环
是用于遍历集合中元素的接口,它提供了一种遍历集合元素的方式,可以用于遍历List、Set和Map集合中的元素。
对于数组foreach循环实际上还是用的普通的for循环2、对于集合foreach循环实际上是用的iterator迭代器迭代
4.HashSet
HashSet是Set接口的一个实现类,它存储的元素是不可重复的。当向HashSet中添加一个元素时,首先会调用hash Code()方法确定元素的存储位置,然后再调用equals()方法确保该位置没有重复元素。Set接口与List接口存取元素的方式是一样的,但是Set集合中的元素是无序的
Linked Hash Set是链表和哈希表组合的一个数据存储的结构; 是基于哈希表和链表实现的,可以保证元素的顺序和插入顺序一致。
HashSet存储的元素是无序的,如果想让元素的存取顺序一致,可以使用Java提供的 Linked Hash Set类,Linked Hash Set类是HashSet的子类,与LinkedList一样,它也使用双向链表来维护内部元素的关系。
Tree Set则以二叉树的方式存储元素,它可以对集合中的元素进行排序。
九. 泛型
1.泛型的作用
1、类型安全。
泛型的主要目标是提高 Java 程序的类型安全。编译时的强类型检查;通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。
2、消除强制类型转换。
泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。
3、潜在的性能收益。
泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话,程序员会指定这些强制类型转换)插入生成的字节码中。但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来可能。由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改。所有工作都在编译器中完成,编译器生成类似于没有泛型(和强制类型转换)时所写的代码,只是更能确保类型安全而已。Java语言引入泛型的好处是安全简单。泛型的好处是在编译的时侯检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
4、更好的代码复用性,比如实现泛型算法
通过继承,实现抽象了所有公共方法,避免了每次都要写相同的代码。
2.泛型的优点
(1)提高类型的安全性。
使用泛型后,将类型的检查从运行期提前到编译期。在编译期进行类型检查,可以更早、更容易地找出因为类型限制而导致的类型转换异常,从而提高程序的可靠性。
(2)消除强制类型转换。
使用泛型后,程序会记住当前的类型形参,从而无须对传入的实参值进行强制类型转换,使得代码更加清晰和简洁,可读性更高。
(3)提高代码复用性。
使用泛型后,可以更好地将程序中通用的代码提取出来,在使用时传入不同类型的参数,避免了多次编写相同功能的代码,提高了代码的复用性。
(4)拥有更高的运行效率。
使用泛型前,传入的实际参数值作为Object类型传递时,需要进行封箱和拆箱操作,会增加程序运行的开销;使用泛型后,类型形参中都需要使用引用数据类型,即传入的实际参数的类型都是对应的引用数据类型,避免了封箱和拆箱操作,减少了程序运行的开销,提高了程序的运行效率。
3.泛型的使用
定义类时,在类名后加上用尖括号括起来类型形参,这个类就是泛型类。定义格式:
修饰符 <代表泛型的变量> 返回值类型 方法名(参数){ }super (参数 1,参数 2,..)
4.泛型接口
定义泛型接口和定义泛型类的语法格式类似,在接口名称后面加上用尖括号括起来类型形参即可。与集合相关的很多接口也是泛型接口,如collection、list等。定义泛型接口的基本语法格式如下:
public<泛型类型>返回类型方法名(泛型类型变量名){}
泛型方法,是在调用方法的时候指明泛型的具体类型,泛型方法是将类型形参的声明放在修饰符和返回值类型之间的方法。
定义格式:
修饰符<代表泛型的变量>返回值类型方法名(参数){}
5.类型通配符
类型通配符用一个问号(?)来表示。类型通配符可以匹配任何类型的类型形参。
固定上边界的通配符,采用<? extends E>的形式使用固定上边界的通配符的泛型, 就能够接受指定类及其子类类型的数据。要声明使用该类通配符,采用<?extends E>的形式,,这里的E就是该泛型的上边界。固定下边界的通配符,采用<? super E>的形式使用固定下边界的通配符的泛型, 就能够接受指定类及其父类类型的数据.。要声明使用该类通配符, 采用<? super E>的形式,,这里的E就是该泛型的下边界。
十. 反射机制
1.反射的特点
通过反射,可以将一个虚像映射到实物,这样就可以获取实物的某些形态特征。Java在常规情况下程序通过类创建对象,反射就是将这一过程反转,通过实例化对象来获取所属类的信息。
Java的反射机制可以动态获取程序信息以及动态调用对象的功能,它主要有以下4个作用:
(1)在程序运行状态中,构造任意一个类的对象。
(2)在程序运行状态中,获取任意一个对象所属的类的信息。
(3)在程序运行状态中,调用任意一个类的成员变量和方法。
(4)在程序运行状态中,获取任意一个对象的属性和方法。
优点是可以实现动态创建对象和动态调用对象和动态编译。
2.Class类的用法
根据全限定类名获取:Class.for Name(“全限定类名”)。
根据对象获取:对象名.get Class()。
根据类名获取:类名.class。
如果想通过Class类实例化其他类的对象,则可以调用new Instance()方法,在调用new Instance()方法实例化其他类的对象时,必须保证被实例化的类中存在无参构造方法。
如果类中没有无参构造方法,则可以通过有参构造方法实例化对象。通过有参构造方法实例化对象时,需要明确调用的构造方法,并传递相应的参数。通过有参构造方法实例化对象的操作步骤如下:
(1)通过调用Class类中的get Constructors()方法获取要实例化的类中的全部构造方法。
(2)获取实例化使用的有参构造方法对应的Constructor对象。
(3)通过Constructor类实例化对象。
3.通过反射获取类结构
如果要获取一个类的父类,可以调用Class类中的get Superclass()方法。get Superclass()方法声明格式如下:
public Class<? Super T>get Superclass();
get Superclass()方法返回一个Class类的实例,通过该实例调用Class类中的get Name()方法可以获取类的名称。
注:Person类在编写时没有显示地继承一个父类,会默认继承Object类。
获取类的构造方法需要调用Class类的get Constructors( )方法。调用get Constructors()方法获取的构造方法需要存储到Constructor类的数组中。通过调用Constructor类的方法可以获取构造方法的详细信息,如构造方法的权限、名称、参数信息等。
要获取类中的所有public修饰的成员方法对象,可以使用Class类中的get Methods()方法,该方法返回一个Method类的对象数组。如果想要进一步获取方法的具体信息,如方法的参数、抛出的异常声明等,可以调用Method 类提供的一系列方法。
get Modifiers() 获取方法的权限修饰符
get Name() 获取方法的名称
get Parameter Types() 获取方法的全部参数的类型
get Return Type() 获取方法的返回值类型
get Exception Type() 获取方法抛出的全部异常类型
new Instance(Object···in iftars)通过反射调用类中的方法
通过反射也可以获取一个类中的全部属性,类中的属性包括两种:从父类继承的属性和本类定义的属性。针对这两种属性,Java提供了两种获取方式,分别如下:
(1)获取本类中,以及实现的接口或继承的父类中的公共属性,需要调用get Fields()方法。get Fields()方法声明格式如下:
public Field [] get Fields () throws Security Exception;
(2)获取本类中的全部属性,需要调用get Declared Fields()方法。get Declare Fields()方法声明格式如下:
public Field [] get Declared Fields throws Security Exception;
上述两个方法返回的都是Field 数组,Field数组中的每一个Field对象表示类中的一个属性。如果要获取属性的详细信息,就需要调用Field 类提供的一系列方法。
4.利用反射实现调用方法
工具方法------反射调用setter
工具方法------反射调用getter
工具类------反射调用getter与setter
工具类与工具方法的区别:
工具方法适用于对同一对象进行较少次数的set与get
工具类适用于对同一对象进行较多次数的set与get
两个方法都自带异常处理机制,不会影响代码的后续运行,setter方法发生异常则相当于无效语句,getter方法发生异常则返回null值
注意:以下反射调用的方法都无视私有权限,但是只能本方法实现类的方法
在反射操作中,虽然可以通过调用类中的getter/setter方法访问类的属性,但是这样操作起来太烦琐。除了调用getter/setter方法访问类的属性之外,反射机制也可以直接通过Field类操作类中的属性,通过Field 类提供的set()方法和get()方法可以直接设置、获取类的属性值。
通过调用Field类的getter/setter方法访问类的属性时,首先要调用Field类中的set Accessible()方法将需要操作的属性权限设置成可以被外部访问。
十一. I/O
1.File 类
java.io包中的File类是唯一一个可以代表磁盘文件的对象,它定义了一些用于操作文件的方法。通过调用File 类提供的各种方法,可以创建、删除或者重命名文件,判断硬盘上某个文件是否存在,查询文件最后修改时间,等等。File 类提供了多个构造方法用于创建File 对象。File 类的常用构造方法声明和功能描述
File(String pathname)通过指定的一个字符串类型的文件路径创建一个File对象
File(String parent, String child)根据指定的一个字符串类型的父路径和一个字符串类型的子路径(包括文件名称)创建一个File对象
File(File parent, String child) 根据指定的一个File类的父路径和一个字符串类型的子路径(包括文 件名称)创建一个File对象。
File类的常用方法、声明,功能描述:
Boolean exists()判断File对象对应的文件或目录是否存在。若存在则返回true,否则返回false
Boolean delete()删除File对象对应的文件或目录。若删除成功则返回true,否则返回false
Boolean craneflies()当File对象对应的文件不存在时,该方法将新建一个文件。若创建成功则返 回true,否则返回false
String get Name()返回File对象表示的文件或目录的名称
String get Path()返回File对象对应的路径
String get Absolute Path()返回File对象对应的绝对路径(在UNIX/Linux等系统上,如果路径以斜线 开始,则这个路径是绝对路径;在Windows等系统上,如果路径以盘符开始, 则这个路径是绝对路径)
String get Parent File()返回File对象对应目录的父目录(即返回的目录不包含最后一级子目录)
Boolean can Read()判断File对象对应的文件或目录是否可读。若可读则返回true,否则返 回false
Boolean can Write()判断File对象对应的文件或目录是否可写。若可写则返回true,否则返 回false
Boolean is File()判断File对象对应的是否是文件(而不是目录)。若是文件则返回true,否则 返回false
Boolean is Directory()判断File对象对应的是否是目录(而不是文件)。若是目录则返回true,否则 返回false
Boolean is Absolute()判断File对象对应的文件或目录是否是绝对路径
long last Modified()返回1970年1月1日0时0分0秒到文件最后修改时间的毫秒值
long length()返回文件内容的长度(单位是字节)
String[]list()递归列出指定目录的全部内容(包括子目录与文件),只列出名称
File[]list Files()返回一个包含File对象所有子文件和子目录的File数组
2.遍历目录下的文件
File类中提供了list()方法,可以获取目录下所有文件和目录的名称。获取目录下所有文件和目录名称后,可以通过这些名称遍历目录下的文件,按照调用方法的不同,对目录下的文件遍历可分为以下3种方式。
1.遍历指定目录下的所有文件
2.遍历指定目录下指定扩展名的文件
3.遍历包括子目录下的文件在内的所有文件
可以使用File类提供的另一个方法——list Files()。该方法返回一个File对象数组,当对数组中的元素进行遍历时,如果元素中还有子目录需要遍历,则可以递归遍历子目录。
4.删除文件及目录
在操作文件时,可能会遇到需要删除一个目录下的某个文件或者删除整个目录的情况,这时可以调用File类的delete()方法。
所有文件都是以二进制(字节)形式存在的。对于字节的输入输出,I/O系统提供了一系列流,统称为字节流。字节流是程序中最常用的流,根据数据的传输方向可将其分为字节输入流和字节输出流。
JDK提供了两个抽象类——Input Stream和Output Stream,它们是字节流的顶级父类,所有的字节输入流都继承Input Stream,所有的字节输出流都继承Output Stream。
3.方法声明与功能描述
int read()从输入流读取一字节(8位),把它转换为0~255 的整数,并返回这一整数
int read(byte[]b)从输入流读取若干字节,把它们保存到参数b指定的字节数组中,返回的整数表示读取的字节数。
int read(byte[]b,int off, int len) 从输入流读取若干字节,把它们保存到参数b指定的字节数组中,off指定字 节数组保存数据的起始索引,len表示读取的字节数
void close() 关闭输入流并释放与其关联的所有系统资源
4.字节流读文件
Input Stream就是JDK提供的基本输入流,它是所有输入流的父类,File Input Stream 是Input Stream的子类,它是操作文件的字节输入流,专门用于读取文件中的数据。
因为从文件读取数据是重复的操作,所以需要通过循环语句实现数据的持续读取。
5.字节流写文件
Output Stream是JDK提供的基本输出流,与Input Stream类似,Output Stream是所有输出流的父类。Output Stream是一个抽象类,如果使用此类,则必须先通过子类实例化对象。Output Stream类有多个子类,其中File Output Stream子类是操作文件的字节输出流,专门用于把数据写入文件。
6.文件的复制
在应用程序中,I/O流通常都是成对出现的,即输入流和输出流一起使用。例如,文件的复制就需要通过输入流读取一个文件中的数据,再通过输出流将数据写入另一个文件。
十二.多线程
1.进程
进程是计算机中程序的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。虽说进程在程序执行时产生,但进程并不是程序。程序是“死”的,进程是“活”的,程序是指编译好的二进制文件,它存放在磁盘上,不占用系统资源,是具体的;而进程存在于内存中,占用系统资源,是抽象的。当一次程序执行结束之后,进程随之消失,进程所用的资源被系统回收。
线程:每个运行的程序都是一个进程,在一个进程中还可以有多个执行单 元同时运行,这些执行单元可以 看作程序执行的一条条线程。每一个进程中都至少存在一个线程。代码按照调用 顺序依次往下执行,没有出现 两段程序代码交替运行的效果,这样的程序称作单线程程序。如果希望程序中实现多段程序代码 交替运行的效果,则需要创建多个线程,即多线程程序。
多线程是指一个进程在执行过程中可以产生多个单线程,这些单线程程序在运行时是相互独立的,它们可以并发执行。多线程程序的执行过程
2.线程创建
1、Java提供了3种多线程的创建方式:
(1)继承java .ang包中的Thread类,重写Thread类的run ()方法,在run ()方法中实现多线程代码。
(2)实现java .ang .Runnable接口,在run ()方法中实现多线程代码。
(3)实现java .ut il.concurrent.Callable接口,重写call ()方法,并使用 Future接口获取call ()方法返回的结果。
为了实现多线程,Java提供了一个线程类Thread,通过继承Thread类,并重写Thread类中的run()方法便可实现多线程。Thread类中提供了一个start()方法用于启动新线程,新线程启动后,JVM会自动调用run()方法,如果子类重写了run()方法便会执行 子类中的run ()方法。通过继承Thread类实现了多线程,但是这种方式有一定的局限性。因为Java只支持单继承 ,一个类一旦继承了某个父类就无法再继承Thread类,比如学生类Student继承了Person类,那么Student类就无法再通过继承Thread类创建线程。
2、为了克服这种弊端 ,Thread类提供了另外一个构造方法Thread (Runnable target),其中参数 类型Runnable是一个接口,它只有一个run()方法。当通过Thread(Runnable target)构造方法创建线程对象时,只需为该方法 传递 一个实现了Runnable接口的对象,这样创建的线程将实现了Runnable接口中的run()方法作为运行代码 ,而不需要调用Thread类中的run()方法。克服弊端的方式:实现Runnable接口创建多线程
步骤一:定义MyThread03类实现Runnable接口,重写了Runnable接口中的run()方法。
步骤二:定义main()方法,创建MyThread03的实例对象,调用Thread类的构造方法将MyThread03类的实例对象作为参数传入,然后调用start()方法开启新线程执行MyThread03类中的代码,而主线程继续执行main()方法中的代码。
通过Thread类和Runnable接口实现多线程时,需要重写run()方法,但是由于run()方法没有返回值,因此无法从新线程中获取返回结果。为了解决这个问题,Java提供了一个Callable接口,来满足这种既能创建新线程又可以有返回值的需求。
(1)创建一个Callable接口的实现类,同时重写Callable接口的call()方法。
(2)创建Callable接口的实现类对象。
(3)通过Future Task线程结果处理类的有参构造方法封装Callable接口实现类对象。
(4)调用参数为Future Task类对象的Thread有参构造方法创建Thread线程实例。
(5)调用线程实例的start()方法启动线程。
3、Future接口的方法及说明
Boolean cancel(Boolean may Interrupt If Running):用于取消任务,参数may Interrupt If Running表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行的任务
Boolean is Cancelled():判断任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true
Boolean is Done():判断任务是否已经完成,若任务完成,则返回true
V get():用于获取执行结果,这个方法会发生阻塞,一直等到任务执行完毕才返回执行结果
V get(long timeout, Time Unit unit):用于在指定时间内获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。
Thread类创建多线程,无法保证多个线程对共享资源的正确操作,而Runnable接口可以保证多个线程对共享资源的正确访问。
4、前台线程和后台线程是一种相对的概念,新创建的线程默认都是前台线程,如果某个线程对象在启动之前执行了set Daemon(true)语句,这个线程就变成一个后台线程。对Java程序来说,只要还有一个前台线程在运行,这个进程就不会结束,如果一个进程中只有后台线程运行,这个进程就会结束。
3.线程的生命周期及状态转换
在线程整个生命周期中,基本状态一共有6种,分别是新建状态(New)、可运行(Runnable)、锁阻塞(Blocked)、无限等待(Waiting)、计时等待(Timed Waiting) 、被终止(Terminated),线程的不同状态表明了线程当前正在进行的活动。
1.新建状态
创建一个线程对象后,该线程对象就处于新建状态。此时还没调用start()方法进行启动,和其他Java对象一样,仅仅由JVM为其分配了内存,没有表现出任何线程的动态特征。
2.可运行状态
可运行状态也称为就绪状态。当线程对象调用了start()方法后,该线程就进入就绪状态。处于就绪状态的线程位于线程队列中,此时它只是具备了运行的条件,能否获得CPU的使用权并开始运行,还需要等待系统的调度。
3.锁阻塞状态
如果处于可运行的线程获得了CPU的使用权,并开始执行run()方法中的线程执行体,则该线程处于运行状态。一个线程启动后,它可能不会一直处于运行状态,当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入锁阻塞状态;当该线程持有锁时,该线程将变成可运行状态。
4.无限等待状态
一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入无限等待状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notify All方法才能够唤醒。
5.计时等待状态
计时等待状态是具有指定等待时间的等待线程的线程状态。线程由于调用了计时等待的方法(Thread. Sleep() 、Object. Wait()、Thread. Join()、Lock Support. Park Nanos()、Lock Support. park Until ()),并且指定了等待时间而处于计时等待状态。这一状态将一直保持到超时期满或者接收到唤醒通知。
6.被终止状态
被终止状态是终止线程的线程状态。线程因为run()方法正常退出而死亡,或者因为没有捕获的异常终止了run()方法而完成执行。
4.线程操作
在应用程序中,如果要对线程进行调度,最直接的方式就是设置线程的优先级。优先级越高的线程获得CPU执行的机会越大,而优先级越低的线程获得CPU执行的机会越小。线程的优先级用1~10之间的整数表示,数字越大优先级越高。除了可以直接使用数字表示线程的优先级,还可以使用Thread类中提供的三个静态常量表示线程的优先级。
线程休眠指让当前线程暂停执行,从运行状态进入阻塞状态,将CPU资源让给其他线程的一种调度方式,可以调用线程的操作方法sleep()来实现线程休眠,sleep()方法是java. lang. Thread类中定义的静态方法。使用sleep()方法时需要指定当前线程休眠的时间,传入一个long类型的数据作为休眠时间,单位为毫秒,并且任意一个线程的实例化对象都可以调用该方法。
线程插队是指将某个线程插入到当前线程中,由两个线程交替执行变成两个线程顺序执行,即一个线程执行完毕之后再来执行第二个线程,可以通过调用线程对象的join()方法来实现线程插队。
Thread类除了提供一个无参数的线程插队join()方法外,还提供了带有时间参数的线程插队方法join(long mills)。当执行带有时间参数的join(long mills)进行线程插队时,必须等待插入的线程指定时间过后才会继续执行其他线程。
join()表示在被调用线程执行完成之后才能执行其他线程,join(long mills)则表示被调用线程执行mills毫秒之后,无论是否执行完毕,其他线程都可以和它来争夺CPU资源。
线程让步是指在某个特定的时间点,让线程暂停抢占CPU资源的行为,即从运行状态或就绪状态到阻塞状态,从而将CPU资源让给其他线程使用。可以通过调用yield()方法来实现线程让步。
线程中断就是线程在执行过程中,通过手动操作来停止该线程。例如当用户在执行一次操作时,因为网络问题导致延迟,则对应的线程对象就一直处于运行状态。如果用户希望结束这个操作,即终止该线程,就要使用线程中断机制了。
5.线程同步
使用synchronized关键字创建同步代码块的语法格式如下:
synchronized(lock) { 操作共享资源代码块 }
在上面的代码中,lock是一个锁对象,它是同步代码块的关键,相当于为同步代码加锁。当某一个线程执行同步代码块时,其他线程将无法执行,进入阻塞状态。当前线程执行完后,再与其他线程重新抢夺CPU的执行权,抢到CPU执行权的线程将进入同步代码块,执行其中的代码。以此循环往复,直到共享资源被处理完为止。这个过程就好比一个公用电话亭,只有前一个人打完电话出来后,后面的人才可以打。
除了修饰代码块,synchronized关键字同样可以修饰方法,被synchronized关键字修饰的方法为同步方法。同步方法和同步代码块一样,同一时刻,只允许一个线程调用同步方法。synchronized关键字修饰方法的具体语法格式如下:
synchronized 返回值类型 方法名([参数1,...]){ }
重入锁(Reentrant Lock)的作用类似于synchronized关键字,synchronized是通过JVM实现的,而重入锁通过JDK实现。顾名思义,重入锁是指可以给同一个资源添加多个锁,并且释放锁的方式与synchronized也不同。synchronized的锁是线程执行完毕之后会自动释放的,而Reentrant Lock的锁必须手动释放。重入锁的语法格式如下所示:
private Reentrant Lock reentrant Lock = new
Reentrant Lock();//加锁
reentrant Lock. Lock();//需要锁的数据
reentrant Lock. Unlock(); //释放锁