Java学习笔记
Java学习笔记
一、基本格式
1.类
类是Java的基本结构,一个程序可以包含一个或多个类
类的申明:
/* |
2.修饰符
修饰符用于指定数据、方法、类的属性以及用法
修饰符示例:
public class HelloWorld{ //public修饰为公有的 |
3.块
Java中使用左大括号({)和右大括号(})将语句编组,组中的语句称为代码块或块语句
{ |
二、注释
1.单行注释
//xxxx |
2.多行注释
/* |
注:多行注释中可以嵌套单行注释,但多行注释中不能嵌套多行注释
三、基本数据类型
1.整数类型
在Java中,整数类型分为字节型(byte)、短整型(short)、整型(int)和长整型(long)四种
在Java中直接给出一个整数值,其默认类型就是int类型。使用中通常有两种情况:
(1)直接将一个在byte在short类型取值范围内的整数值赋给byte或short变量,系统会自动把这个整数当成byte或short类型来处理。
(2)将一个超出int取值范围内的整数值赋给long变量,系统不会自动把这个整数值当成long类型来处理。此时必须声明long类型常量,即在整数值后面添加字母l或L。如果数值未超过int型的取值范围,则可以省略字母l和L。
long x = 99999; //所赋的值未超出int取值范围,可以加L,也可省略 |
2.浮点数类型
在Java中,浮点数分为两种:单精度浮点数(float)和双精度浮点数(double)。
在Java中,使用浮点数数值时,默认的类型是double,在数值后面可加上d或D,作为double类型的标识。在数值后面加上f或F,则作为float类型的识别。若没有加上,Java就会将该数据视为double类型,而在编译时就会发生错误,提示可能会丢失精度。
double n = 10.0; //数值默认为double型 |
3.字符型
字符型变量用了存储单个字符,字符型值必须使用英文半角格式的单引号”‘“括起来。Java采用char表示字符型
char a = 'b'; //为一个char类型的变量赋值字符b |
4.布尔类型
布尔类型的值只有true(真)和false(假)两种,Java的布尔类型用boolean表示,占用1B内存空间。
boolean b1 = true; //声明boolean型变量值为true |
四、变量
1.声明变量
声明格式:
数据类型 变量名; |
2.变量的类型转换
隐式转换(自动类型转换):取值范围小的,和取值范围大的进行运算,小的会先提升为大的,再运算。byte、short、char三种类型的数据在运算的时候,都会直接提升为int,然后再进行运算
强制转换:如果把一个取值范围大的数值,赋值给取值范围小的变量,是不允许直接赋值的。如果一定要这么做,就需要加入强制转换。
格式:目标数据类型 变量名 = (目标数据类型)被强转的数据
注:强制转换可能出现错误
3.变量的作用域
变量声明在程序中的位置决定了变量的作用域。变量一定会声明在一对大括号中,该大括号所包含的代码区域就是这个变量的作用域。
4.常量
常量是不能被改变的数据。Java程序中使用的直接量称为常量,是在程序中通过源代码直接给出的值,在整个程序执行过程中都不会改变,也称最终量。
5.转义字符
- \b,退格键,Unicode码为\u0008
- \t,Tab键,Unicode码为\u0009
- \n,换行符,Unicode码为\u000A
- \r,回车符,Unicode码为\u000D
6.运算符
1.算术运算符
2.赋值运算符
3.关系运算符
&、&&运算符的区别:
都表示与操作,运算符前后的两个操作数皆为true,运算的结果才会为true,否则为flase。两者在使用上有一定的区别:使用&运算符,要求对运算符前后两个操作数都进行判断;而使用&&运算符,当运算符前面的操作数的值为false时,则其后面的操作数将不再判断。
|与||的区别同上。
4.位运算符
‘<<’ 左移 eg.0000 0001<<2 结果:0000 0100
‘>>’ 右移 eg.1000 0100>>2 结果:1110 0001
左移后右边空位补0,左边移出的舍弃;右移同理可得。
‘>>>’ 无符号右移运算符,将操作数的二进制位整体右移指定位数,右移后左边空位补0,右边移出去的舍弃。
进行位移运算遵循如下规则:
(1)对于低于int类型(byte、short和char)的操作数总是先自动转换为int类型后再位移。
(2)对于int类型的位移,当位移数大于int位数32时,Java先用位移数对32求余,得到的余数才是真正的位移数。
(3)对于long类型的位移,当位移数大于long位数64时,Java先用位移数对64求余,得到的余数才是真正的位移数。
但低于int类型的操作数进行无符号位移时,需注意,如果操作数是负数,在自动转换过程中会发生截断,数据丢失,导致位移结果不正确。
public class TestBitOperation{ |
五、程序的结构
一般来说,程序的结构分为顺序结构、选择结构和循环结构三种,它们都有一个共同的特点是都只有一个入口,也只有一个出口。
1.顺序结构
2.选择结构
Java提供了两种分支结构语句:if语句和switch语句。其中,if语句使用布尔表达式或布尔值作为分支条件来进行分支控制;而switch语句用于对多个整数值进行匹配,从而实现多分支控制。
1.if语句
if(布尔表达式){ |
package com; |
2.if-else语句
3.三目运算符
判断条件?表达式1:表达式2; |
当判断条件成立时,执行表达式1,否则将执行表达式2.
4.if-else if-else语句
由于if语句体或else语句体可以是多条语句,所以如果需要在if-else里判断多个条件,可以“随意”嵌套。
if(布尔表达式1){ |
5.switch语句
switch(表达式){ |
使用switch语句需注意:
- switch语句的判定条件只能是byte、short、char和int四种基本类型,JDK5.0开始支持枚举类型,JDK7.0开始支持String类型,不能是boolean类型。
- 常量1~常量N必须与判断条件类型相同,且为常量表达式,不能是变量。
- case字句后面可以有多条语句,这些语句可以使用大括号括起来。
- 程序将从第一个匹配的case字句处开始执行后面的所有代码(包括后面case字句中的代码)。可以使用break跳出switch语句。
- default语句是可选的,当所有case字句条件都不满足时执行。
3.循环结构
Java程序设计中引入了循环语句。循环语句共有三种常见的形式:while循环语句、do-while循环语句和for循环语句
1.while循环
while循环语句也是条件判断语句,用于事先不知道循环次数的情况,其语法格式如下: |
2.do-while循环
do{ |
do-while语句与while语句还有一个明显的区别是,如果while语句误添加分号,会导致死循环,而do-while的循环条件后面必须有一个分号,用来表明循环结束。
package com; |
3.for循环
for(赋初始值;循环条件;迭代语句){ |
4.循环中断
1.break语句
注:如果break语句出现在嵌套循环中的内层循环,则break语句只会跳出当前层的循环。
public class TestBreak{ |
在有些场景下,需要从很深的循环中退出时,可以使用带标记的break语句,标记必须break所在循环的外层循环之前定义才有意义,定义在当前循环之前,就失去标记的意义,因为break默认就是结束其所在循环。
package com; |
2.continue语句
在while、do-while和for语句的循环体中,执行continue语句可以结束本次循环而立即测试循环体的条件,执行下一次循环,但不会终止整个循环
六、数组
在一个数组中,数组元素的类型是唯一的,即一个数组中只能存储同一种数据类型的数据,而不能存储多种数据类型的数据。
定义方式1: |
1.数组的初始化
数组初始化,就是让数组名指向数组对象的过程,该过程主要分为两个步骤:一是对数组名进行初始化,即为数组中的元素分配内存空间和赋值;二是对数组名进行初始化,即将数组名赋值为数组对象的引用。
1.静态初始化
方式1: |
其中大括号包含数组元素值,元素值之间用逗号”,”分隔。
2.动态初始化
动态初始化是指程序员在初始化数组时指定数组的长度,由系统为数组元素分配初始值。
数组动态初始化的具体示例如下:
int[] array = new int[10]; //动态初始化数组 |
2.数组的常用操作
1.访问数组
在Java中,数组对象有一个length属性,用于表示数组的长度
获取数组长度的语法格式如下:
数组名.length |
接下来用length属性获取数组的长度,具体示例如下:
int[] list =new int[10]; //定义一个int类型的数组 |
2.数组元素的存取
通过操作数组的下标可以访问到数组中的元素,也可以实现数组元素的存取。
package com; |
3.数组遍历
for循环遍历
public class TestArrayTraversal{ |
4.数组最大值和最小值
5.数组排序——冒泡排序法
package com; |
3.二维数组
二维数组的声明
int[][]array; |
二维数组的动态初始化示例:
array = new int[3][2]; //动态初始化3×2的二维数组 |
二维数组的静态初始化示例:
array=new int[][]{ |
4.锯齿数组
二维数组中每一行就是一个一维数组,因此,各行的长度就可以不同,这样的数组称为锯齿数组。
七、方法
方法是一段可重复使用的代码,为执行一个操作组合在一起的语句集合,用于解决特定的问题。
1.方法的定义
修饰符 返回值类型 方法名([参数类型 参数名1,参数类型 参数名2,...]){ |
定义方法需注意:
(1)修饰符:方法的修饰符较多,有对访问去权限进行限定的,有静态修饰符static,还有最终修饰符final等。
(2)返回值类型:限定返回值的类型。
(3)参数类型:限定调用方法时传入参数的数据类型。
(4)参数名:是一个变量,用于接受调用方法指定类型的值。
(5)return:关键字,用于结束方法以及返回方法指定类型的值。
(6)返回值:被return返回的值,该值返回给调用者。
方法头中声明的变量称为实际参数,简称实参。形参列表是指形参的类型、顺序和数量。方法不需要任何参数,则形参列表为空。
2.方法的调用
int large = max(3,4); //将方法的返回值赋给变量 |
如果方法定义中包含形参,调用时必须提供实参。实参的类型必须与形参的类型兼容,实参顺序必须与形参的顺序一致。实参的值传递给方法的形参,称为值传递,方法内部对形参的修改不影响实参值。
package com; |
3.方法的重载
方法重载是指方法名称相同,但形参列表不同的方法。调用重载的方法时,Java编译器会根据实参列表寻找最匹配的方法进行调用。
package com; |
但值得一提的是,调用一个方法时,出现两个或多个可能的匹配时,编译器无法判断哪个是最精确的匹配,则会产生编译错误,称为歧义调用。
4.方法的递归
递归用于解决使用简单循环难以实现的问题。
package com; |
八、面向对象
1.面向对象的概念
面向对象思想是人类最自然的一种思考方式,它将所有预处理的问题抽象为对象,同时了解这些对象具有哪些相应的属性以及如何展示这些对象的行为,以解决这些对象面临的一些实际问题,这样就在程序开发中引入了面向对象设计的概念,面向对象设计实际上就是对现实世界进行建模工作。
1.封装
封装是面向对象程序设计的核心思想。它是指将对象的属性和行为封装起来,其载体就是类,类通常对客户隐藏其实现细节,这就是封装的思想。
eg.计算机的主机是由内存条、硬盘、风扇等部件组成,生产厂家把这些部件用一个外壳封装起来组成主机,用户在使用该主机时,无须关心其内部的组成及工作原理。
2.继承
继承是面向对象程序设计提高重用性的重要措施。它体现了特殊类与一般类之间的关系,当特殊类包含一般类的所有属性和行为,并且特殊类还可以有自己的属性和行为时,称作特殊类继承了一般类。一般类又称为父类或基类,特殊类又称为子类或派生类。
eg.已经描述了汽车模型这个类的属性和行为,如果需要描述一个小轿车类,只需让小轿车类继承汽车模型类,然后再描述小轿车类特有的属性和行为,而不必再重复描述一些在汽车模型类中已有的属性和行为。
3.多态
多态是面向对象程序设计的重要特征。
eg.生活中也有很多多态,如学校的下课铃声响后,有学生去买零食、有学生去打球、有学生在聊天等等。
2.类与对象
对象是事物存在的实体,如学生、汽车等。在计算机世界中,面向对象程序设计的思想要以对象来思考问题,首先要将现实世界的实体抽象为对象,然后考虑这个对象具备的属性和行为。
1.类的定义
class 类名{ |
eg.
class Person{ |
2.对象的创建与使用
声明对象格式:
类名 对象名 |
初始化类,Java使用new关键字来创建对象,也称为实例化对象,其语法格式如下:
对象名 = new 类名(); |
or
类名 对象名 = new 类名(); |
eg.
Person p = new Person(); |
访问对象的成员变量和成员方法:
对象名.成员变量; |
package LearnJava; |
另外,需要注意的是,一个对象能被多个变量所引用,当对象不被任何变量所引用时,该对象就会成为垃圾,不能再被使用。
package LearnJava; |
3.类的封装
class Person{ |
为了避免外界随意访问类中的属性,就需要用到封装,即不让使用者访问类的内部成员。Java中使用private关键字来修饰私有属性,私有属性只能在它所在的类中被访问。但这样做使所有的对象都不能访问这个类中的私有属性。为了让外部使用者访问类中的私有属性,需要提供public关键字修饰的属性访问器,即用于设置属性的setXxx()方法和获取属性的getXxx()方法。
package LearnJava; |
4.访问修饰符
Java中的访问修饰符是指能够控制类、成员变量、方法的使用权限的关键字。通常放在语句的最前端。类的访问修饰符只有一个public,属性和方法能够被四个修饰符修饰,分别是:public、private、protected,还有一个默认权限default。
1.公有访问控制符(public)
对所有类可见,被声明public的类、方法和接口允许被程序中的任何类访问。Java的类是通过包的概念来组织的。包是类的一个松散的集合,处于同一个包中的类可以不需要任何说明方便地相互访问和引用,而对于不同包中的类,则需要导入相应public类所在的包。每个java程序的主类必须是public修饰的类,否则Java解释器将不能运行该类。
2.私有访问控制符(private)
私有的,即在同一类内可见。被private修饰的属性或方法被提供了最高的保护级别,只能由该类自身访问或修改,而且不能被任何其他类(包括该类的子类)来获取或引用
3.保护防护控制符(protected)
受保护的,即对同一包的类和所有子类可见,可以用来修饰属性、方法,不能修饰类。protected修饰的成员变量可以被3种类所引用:该类自身、与它在同一个包中的其他类、在其他包中该类的子类。使用protected修饰符的主要作用是允许其他包中该类的子类来访问父类的特定属性。
4.默认访问控制符(defaulted)
默认访问控制权规定,该类只能被同一个包中的类访问和引用,而不可以被其他包中的类使用,这种访问特性又称为包访问性。
5.构造方法
1.构造方法的定义
构造方法是使用new关键字创建一个时被调用的,构造方法时需注意:
(1)构造方法名与类名相同。
(2)构造方法没有返回值类型。
(3)构造方法中不能使用return返回一个值。
package LearnJava; |
2.构造方法的重载
与普通方法一样,只要每个构造方法的参数列表不同,即可实现重载。
3.this关键字
类在定义成员方法时,局部变量和成员变量可以重名,但此时不能访问成员变量。为避免这种情形,Java提供了this关键字,表示当前对象,指向调用的对象本身。
class Person{ |
this关键字在程序中主要有三种用法,下面分别讲解各种用法。
1.使用this调用类中的属性
this关键字可以明确调用类的成员变量,不会与局部变量名发生冲突。
package LearnJava; |
2.使用this调用成员方法
this既然可以访问成员变量,那么也可以访问成员方法
class Person { |
3.使用this调用构造方法
构造方法是在实例化时被自动调用的,因此不能直接像调用成员方法一样去调用构造方法,但可以使用this([实参列表])的方式调用其他的构造方法
package LearnJava; |
另外,在使用this调用构造方法时,还需注意:在构造方法中,使用this调用构造方法的语句必须位于首行,且只能出现一次。
4.static关键字
1.静态变量
使用static修饰的成员变量,称为静态变量或类变量,它被类的所有对象共享,属于整个类所有,因此可以通过类名直接访问。而未使用static修饰的成员变量称为实例变量,它属于具体对象独有,只能通过引用变量访问。
class Person{ |
注:static关键字在修饰变量的时候只能修饰成员变量,不能修饰方法中的局部变量。
2.静态方法
使用static修饰的成员方法,称为静态方法,无须创建类的实例就可以调用静态方法,静态方法可以通过类名调用。
静态方法只能访问类的静态成员(静态变量、静态方法),不能访问类中的实例成员(实例变量和实例方法)。这是因为未被static修饰的成员都是属于对象的,所以需要先创建对象才能访问,而静态方法在被调用时可以不创建任何对象。
3.代码块
代码块是指用”{}”括起来的一段代码,根据位置和声明关键字不同,代码块分为普通、构造、静态、同步四种代码块。
普通代码块就是在方法名或方法体内用大括号”{}”括起来的一段代码。
构造代码块就是直接定义在类中的代码块,它没有任何前缀、后缀及关键字修饰。创建对象时,构造方法被自动调用,构造代码块也是在创建对象时被调用,但它在创造方法之前被调用,因此,构造代码块也可以用来初始化成员变量。另外,构造代码块会优先于构造方法执行。
package LearnJava; |
静态代码块就是使用static关键字修饰的代码块,它是最早执行的代码块
package LearnJava; |
5.内部类
1.成员内部类
成员内部类是指类作为外部类的一个成员,能直接访问外部类的所有成员,但在外部类中访问内部类,则需要在外部类中创建内部类的对象,使用内部类的对象来访问内部类中的成员。同时,若要在外部类外访问内部类,则需要通过外部类对象去创建内部类对象,在外部类创建一个内部类对象的语法格式如下:
外部类名.内部类名 引用变量名 = new 外部类名().new 内部类名() |
package LearnJava; |
2.静态内部类
static关键字修饰的内部类称为静态内部类。静态内部类可以有实例成员和静态成员,它可以直接访问外部类的静态成员,但如果想访问外部类的实例成员,就必须通过外部类的对象去访问。另外,如果在外部类外访问静态内部类成员,则不需要创建外部类对象,只需创建内部类对象即可。
创建内部类对象:
外部类名.内部类名 引用变量名 = new 外部类名.内部类名() |
3.方法内部类
在成员方法中定义的类,它与局部变量类似,作用域为定义它的代码块,因此它只能在定义该内部类的方法内实例化,不可以在此方法外对其实例化。
4.匿名内部类
匿名内部类就是没有名称的内部类。创建匿名内部类时会创建一个该类的对象,该类定义立即消失,匿名内部类不能重复使用。
6.类的继承
1.用法
class 子类名 extends 父类名{ |
Java使用extends关键字指明两个类之间的继承关系。子类继承了父类中的属性和方法,也可以添加新的属性和方法。
package LearnJava; |
Child类通过extends关键字继承了Parent类,继承了其所有的成员,且可以扩展功能。
但Java语言只支持单继承,不允许多重继承,即一个子类只能继承一个父类,否则会引发编译错误。
但它支持多层继承,即一个类的父类可以继承另外的父类。因此,java类可以有无限多个间接父类。
eg.
class A{} |
2.重写父类方法
在进行方法重写时必须考虑权限,即被子类重写的方法不能拥有比父类方法更加严格的访问权限。
package LearnJava; |
注:
(1)方法的重载是在同一个类中,方法的重写是在子类与父类中。
(2)方法重载要求:方法名相同,参数个数或参数类型不同。
(3)方法重写要求:子类与父类的方法名、返回值类型和参数列表相同。
3.super关键字
super.成员变量 |
super可以实现调用父类被重写的成员方法,可以在子类中访问被隐藏的父类成员。
子类继承父类时,并没有继承父类的构造方法,但子类构造方法可以调用父类的构造方法。在一个构造方法中调用另一个重组在的构造方法时应使用this关键字,在子类构造方法中调用父类的构造方法时应使用super关键字。
super([参数列表]) |
package LearnJava; |
另外,如果子类中没有显式地调用父类的构造方法,那么将自动调用父类中不带参数的构造方法。
4.final关键字
在Java中,为了考虑安全因素,要求某些类不允许被继承或者不允许被子类修改,这时可以用final关键字修饰。
(1)final修饰的类不能被继承
(2)final修饰的方法不能被子类重写。
(3)final修饰的变量是常量,初始化后不能再修改。
使用final关键字修饰的类称为最终类,表示不能再被其他类继承,如Java中的String类
使用final关键词修饰的方法,称为最终方法,表示子类不能再重写此方法
使用final关键词修饰的变量,称为常量,只能赋值一次。再次对该变量进行赋值时,程序在编译时会报错。
7.抽象类和接口
1.抽象类
Java中可以定义不含方法体的方法,方法的方法体由该类的子类根据实际需求去实现,这样的方法称为抽象方法,包括抽象方法的类必须是抽象类。
Java中提供了abstract关键字,表示抽象的意思,用abstract修饰的方法,称为抽象方法,是一个不完整的方法,只有方法的声明,没有方法体。用abstract修饰的类,称为抽象类。抽象类可以不包含任何抽象方法。
//用abstract修饰抽象类 |
抽象类不能被实例化,即不能用new关键字创建对象。因此,必须通过子类继承抽象去实现抽象方法。
//用abstract修饰抽象类 |
需要注意的是,具体子类必须实现抽象父类中的所有抽象方法,否则子类必须要声明为抽象类
另外,抽象方法不能用static来修饰,因为static修饰的方法可以通过类名调用,调用将调用一个没有方法体的方法,肯定会出错;抽象方法也不能用final关键字修饰,因为被final关键字修饰的方法不能被重写,而抽象方法的实现需要在子类中实现;抽象方法也饿不能用private关键字修饰,因为子类不能访问带private关键字的抽象方法。
抽象类中可以定义构造方法,因为抽象类仍然使用的是类继承关系,而且抽象类也可以定义成员变量。因此,子类在实例化时必须先对抽象类进行实例化。
2.接口
接口是全局常量和公共抽象方法的集合,可被看作一种特殊的类,也属于引用类型。每个接口都被编译成独立的字节码文件。Java提供interface关键字,用于声明接口
interface接口名{ |
接下来演示interface关键字的作用
//用interface声明接口 |
接口中定义的变量和方法都包含默认的修饰符,其中定义的变量默认声明为”public static final”,即全局常量。另外,定义的方法默认声明为”public abstract”,即抽象方法。
1.接口的实现
class 类名 implements 接口列表{ |
interface Person{ |
2.接口的继承
interface 接口名 extends 接口列表{ |
//用interface声明接口 |
8.多态
多态是指同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在Java中指把类中具有相似功能的不同方法使用同一个方法名实现,从而可以使用相同的方式来调用这些具有不同功能的同名方法。
package LearnJava2; |
动态绑定机制原理是:当调用实例方法时,Java虚拟机从该变量的实际类型开始,沿着继承链向上查找该方法的实现,直到找到为止,并调用首次找到的实现。
对象的类型转换是指可以将一个对象的类型转换成继承结构中的另一种类型。类型转换分两种:
(1)向上转型,是从子类到父类的转换,也称隐式转换。
(2)向下转型,是从父类到子类的转换,也称显示转换。
class Person{ |
9.Object类
Java中提供一个Object类,是所有类的父亲。如果一个类没有显式地指定继承类,则该类的父类默认为Object。
class ClassName{} |
在Object类中提供了很多方法
1.toString()方法
调用一个对象的toString()方法会默认返回一个描述该对象的字符串,它由该对象的所属类名、@和对象十六进制形式的内存地址组成
class Person{ |
2.equals()方法
equals()方法是用于测试两个对象是否相等
equals()方法与直接使用==运算符检测两个对象结果相同,比较的是地址
10.工厂设计模式
1.简单工厂模式
简单工厂模式又称静态工厂方法,它的核心是类中包含一个静态方法,该方法用于根据参数来决定返回实现同一接口不同类的实例
package LearnJava2; |
2.工厂方法模式
工厂方法模式为工厂类定义了接口,用多态来削弱了工厂类的职责
3.抽象工厂模式
抽象工厂模式用于意在创建一系列互相关联或互相依赖的对象
11.包
1.包的定义与使用
package 包名 |
包是Java提供的一种区别类的名字空间的机制,是类的组织方式,是一组相关类和接口的集合,它提供了访问权限和命名的管理机制。
需注意:
- 包名中字母一般都要小写。
- 包的命名规则:将公司域名反转作为包名
- package语句必须是程序代码中的第一行可执行代码
- package语句最多只有一句
包与文件目录类似,可以分成多级,多级之间用”.”符号进行分隔
package com.1000phone.www; |
如果在程序中已声明了包,就必须将编译生成的字节码文件保存到与包名同名的子目录中,可以使用带包编译命令。
javac -d .Source.java |
其中”-d”表示生成以package定义为准的目录,”.”表示在当前所在的文件夹中生成。编译器会自动在当前目录下建立与包名同名的子目录,并将生成的.class文件自动保存到与包名同名的子目录下。
2.import语句
import关键字用于导入指定包层次下的某个类或全部类,import语句应放在package语句之后,类定义之前,其语法格式如下:
import 包名.类名 //导入单类 |
3.给Java应用程序打包
在实际开发中,通常会将一些类提供给别人使用,直接提供字节码文件会比较麻烦,所以一般会将这些类文件打包成jar文件,以供别人使用。jar文件的全称是Java Archive File,意思就是Java归档文件,也称为jar包。将一个jar包添加到classpath环境变量中,Java虚拟机会自动解压jar包,根据包名所对应的目录结构去查找所需的类
通常使用jar命令来打包,可以把一个或多个路径压缩成一个jar文件。jar命令在JDK安装目录下的bin目录中,直接在命令行中输入jar命令,即可查看jar命令的提示信息
jar命令主要参数如下:
(1)c:创建新的文档
(2)v:生成详细的输出信息。
(3)f:指定归档的文件名
12.Lambda表达式
“->”可以称作箭头操作符或者Lambda操作符。当使用Lambda表达式进行代码编写的时候就需要使用这个操作符。箭头操作符将Lambda表达式分成左右两部分,在操作符的左侧代表着Lambda表达式的参数列表(接口中抽象方法的参数列表),在操作符的右侧代表着Lambda表达式中所需执行的功能(是对抽象方法的具体实现)Lambda表达式的语法格式如下:
(parameters)->experssion或(parameters) ->{statements;} |
上述语法还可以写成:
无参数无返回值:()->具体实现
有一个参数无返回值:(x)->具体实现,或x->具体实现
有多个参数,有返回值,并且Lambda体重有多条语句:(x,y)->{具体实现}
若方法体只有一条语句,那么大括号和return都可以省略
九.异常
异常是一个在程序执行期间发生的事件,它中断了正在执行程序的正常指令流。在程序中,错误可能产生于程序员没有预料到各种情况或是超出了程序员可控范围的环境因素,为了保证程序有效地执行,需要对发生的异常进行相应的处理。
1.异常的类型
- Error类:Throwable的一个子类,代表错误,该体系描述了Java运行系统中的内部错误以及资源耗尽的情形。该类错误是由Java虚拟机抛出的,如果发生,除了尽力使程序安全退出外,在其他方面是无能为力的。
- Exception类是另外一个重要的子类,它规定的异常是程序自身可以处理的异常。异常和错误的区别在于异常是可以被处理的,而错误是不能够被处理的。
2.异常的处理
1.使用try-catch处理异常
异常捕获结构:
try{ //捕获异常,该块用于监控可能发生异常的代码块是否发生异常,如果异常发生了 |
不管程序是否发生异常,还是在try块中使用return语句结束,finally块都会执行。
2.使用throws关键字抛出异常
如果方法不捕获被检查出的异常,那么方法必须声明它可以抛出的这些异常,用于告知调用者此方法有异常。Java通过throws子句表明方法可抛出的所有异常
数据类型 方法名(形参列表)throws 异常类1,异常类,...,异常类n{ |
throws声明的方法表示此方法不处理异常,而交给方法的调用者进行处理。因此,不管方法是否发生异常,调用者都必须进行异常处理。
3.使用throw关键字抛出异常
针对用户希望能亲自进行异常类对象的实例化操作,自己手动抛出异常
throw new 异常对象(); |
4.自定义异常
在特定的问题领域,可通过扩展Exception类或RuntimeException类来创建自定义的异常。异常类包含和异常相关的信息,这有助于负责捕获异常的catch代码块准确地分析并处理异常。
(1)创建自定义异常类并继承Exception基类,如果自定义Runtime异常,则继承RuntimeException基类
(2)此方法中通过throw关键字抛出异常对象。
(3)如果在当前抛出异常的方法中处理异常,可以使用try-catch语句块捕获并处理,否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
(4)在出现异常方法的调用者中捕获并处理异常。
5.断言
断言语句用于确保程序的正确性,以避免逻辑错误
assert 布尔表达式; |
使用第一种格式,当布尔类型表达式值为false时,抛出AssertionError异常,如果使用第二种格式,则输出错误消息。在默认情况下,断言不起作用,可用-ea选项激活断言
java -ea类名 |
十.多线程
线程是比进程更小的执行单位,线程是在进程的基础上进行的进一步划分。所谓多线程是指一个进程在执行过程中可以产生多个更小的程序单元,这些更小的单元称为线程,这些线程可以同时存在、同时运行,一个进程可能包含多个同时执行的线程
进程是程序的一次动态执行过程,需要经历从代码加载、代码执行到执行完毕的一个完整过程,这个过程也是进程本身从产生、发展到最终消亡的过程。每个运行中的程序就是一个进程。一般而言,进程在系统中独立存在,拥有自己独立的资源,多个进程可以在单个处理器上并发执行且互不影响。
操作系统可以同时执行多个进程,进程可以同时执行多个任务,其中每个任务就是线程。eg.杀毒软件程序是一个进程,那么它在喂计算机体检的同时可以清理垃圾文件,这就是两个线程同时运行。
1.线程的创建
1.继承Thread类创建线程
Java提供了Thread类代表线程,它位与java.lang包中
(1)定义Thread类的子类,并重写run()方法,run()方法称为线程执行体。
(2)创建Thread子类的实例,即创建了线程对象。
(3)调用线程对象的start()方法启动线程。
启动一个新线程时,需要创建一个Thread类实例。
public class TestThread{ |
2.实现Runnable接口创建线程
(1)定义Runnable接口实现类,并重写run()方法
(2)创建Runnable实现类的示例,并将实例对象传给Thread类的target来创建线程对象。
(3)调用线程对象的start()方法启动线程。
3.使用Callable接口和Futrue接口创建线程
重写run()方法实现功能代码有一定局限性,这样做方法没有返回值且不能抛出异常
Java提供了Callable接口来解决这样的问题,接口内有一个call()方法可以作为线程执行体,call()方法有返回值且可以抛出异常。
(1)定义