Java教程
Java简介
什么是Java?
Java是由Sun Microsystems公司于1995年5月推出的Java面向对象程序设计语言和Java平台的总称。
Java分为三个体系:
JavaSE(J2SE,Java2 Platform Standard Edition,java平台标准版)
JavaEE(J2EE,Java 2 Platform Enterprise Edition,java平台企业版)
JavaME(J2ME,Java 2 Platform Micro Edition,java平台微型版)。
Java的主要特性
-
Java语言是简单的
Java丢弃了C++中令人难以理解的指针、多继承等概念,使得开发者不需要担忧内存管理。
-
Java语言是面向对象的
面向对象(Object Oriented):将相关数据和方法看做一个整体。
面向过程(Process Oriented):已过程为中心的编程思想。 -
Java语言是分布式的
Java语言支持Internet应用的开发,在基本的Java应用编程接口中有一个网络应用编程接口(java net),它提供了用于网络应用编程的类库,包括URL、URLConnection、Socket、ServerSocket等。Java的RMI(远程方法激活)机制也是开发分布式应用的重要手段。
-
Java语言是健壮的
Java的强类型机制、异常处理、垃圾的自动收集等为Java程序健壮性提供了重要保证。
-
Java语言是安全的
Java提供了一个安全机制以防恶意代码的攻击。除了Java语言具有的许多安全特性以外,Java对通过网络下载的类具有一个安全防范机制(类ClassLoader),如分配不同的名字空间以防替代本地的同名类、字节代码检查,并提供安全管理机制(类SecurityManager)让Java应用设置安全哨兵。
-
Java语言是体系结构中立的
Java程序(后缀为java的文件)在Java平台上被编译为体系结构中立的字节码格式(后缀为class的文件),然后可以在实现这个Java平台的任何系统中运行。这种途径适合于异构的网络环境和软件的分发。
-
Java语言是可移植的
Java时跨平台的,已编译的Java程序可以在任何带有JVM的系统上运行。
-
Java语言是解释型的
Java程序经过Java平台编译为字节码文件(.class文件),然后就可在Java平台的任何系统运行。
-
Java是高性能的
Java不仅可以解释执行还可以编译执行。
解释执行:我们编写的代码通过javac编译器编译产生字节码(bytecode)文件,JVM的解释器将字节码转换为机器码,运行效率较低。
编译执行:Hotspot JVM提供的动态编译器JIT(Just-In-Time)编译器能够运行时将代码编译为机器码,运行效率较高。 -
Java语言是多线程的
在Java语言中,线程是一种特殊的对象,它必须由Thread类或其子(孙)类来创建。通常有两种方法来创建线程:其一,使用型构为Thread(Runnable)的构造子类将一个实现了Runnable接口的对象包装成一个线程,其二,从Thread类派生出子类并重写run方法,使用该子类创建的对象即为线程。值得注意的是Thread类已经实现了Runnable接口,因此,任何一个线程均有它的run方法,而run方法中包含了线程所要运行的代码。线程的活动由一组方法来控制。Java语言支持多个线程的同时执行,并提供多线程之间的同步机制(关键字为synchronized)。
-
Java语言是动态的
Java语言的设计目标之一是适应于动态变化的环境。Java程序需要的类能够动态地被载入到运行环境,也可以通过网络来载入所需要的类。这也有利于软件的升级。另外,Java中的类有一个运行时刻的表示,能进行运行时刻的类型检查。
Java开发环境
Oracle 提供了Java的两种环境
- JDK(Java Development Kit,Java开发标准开发工具包)
- JRE(Java Runtime Environment,Java运行环境)
JDK
整个Java的核心,包括了Java运行环境(JRE),一些Java工具和Java的核心类库(Java API)。
来自网站https://docs.oracle.com/javase/8/docs/的Java概念图
点击Description of Java Conceptual Diagram跳转到Java概念图描述
附:Java SE Development Kit 8 Documentation Download
JRE
JRE是个运行环境,因此运行Java程序时需要JRE。而JDK里面包含了JRE,因此只需安装JDK即可。
Java基础语句
类、对象、方法和实例变量的概念
对象:对象是类的一个实例,有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
类:类是一个模板,它描述一类对象的行为和状态。
方法:方法就是行为,一个类可以有很多方法。逻辑运算、数据修改以及所有动作都是在方法中完成的。
实例变量:每个对象都有独特的实例变量,对象的状态由这些实例变量的值决定。
基本语法
- 大小写敏感:Java 是大小写敏感的,这就意味着标识符 Hello 与 hello 是不同的。
- 类名:对于所有的类来说,类名的首字母应该大写。如果类名由若干单词组成,那么每个单词的首字母应该大写,例如 MyFirstJavaClass。
- 方法名:所有的方法名都应该以小写字母开头。如果方法名含有若干单词,则后面的每个单词首字母大写。
- 源文件名:源文件名必须和类名相同。当保存文件的时候,你应该使用类名作为文件名保存(切记 Java 是大小写敏感的),文件名的后缀为.java。(如果文件名和类名不相同则会导致编译错误)。
- 主方法入口:所有的 Java 程序由 public static void main(String[] args) 方法开始执行。
Java 标识符
Java 所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。
关于 Java 标识符,有以下几点需要注意:
- 所有的标识符都应该以字母(A-Z 或者 a-z),美元符($)、或者下划线(_)开始
- 首字符之后可以是字母(A-Z 或者 a-z),美元符($)、下划线(_)或数字的任何字符组合
- 关键字不能用作标识符
- 标识符是大小写敏感的
- 合法标识符举例:age、$salary、_value、__1_value
- 非法标识符举例:123abc、-salary
Java修饰符
Java可以使用修饰符来修饰类中方法和属性。主要有两类修饰符:
- 访问控制修饰符 : default, public , protected, private
- 非访问控制修饰符 : final, abstract, static, synchronized
Java 变量
Java 中主要有如下几种类型的变量
- 局部变量
- 类变量(静态变量)
- 成员变量(非静态变量)
Java 数组
数组是储存在堆上的对象,可以保存多个同类型变量。
Java 关键字
这些Java 关键字不能用于常量、变量、和任何标识符的名称。
类别 | 关键字 | 说明 |
---|---|---|
访问控制 | private protected public default | 私有的 受保护的 公共的 默认 |
类、方法和变量修饰符 | abstract class extends final implements interface native new static strictfp synchronized transient volatile | 声明抽象 类 扩充,继承 最终值,不可改变的 实现(接口) 接口 本地,原生方法(非 Java 实现) 新,创建 静态 严格,精准 线程,同步 短暂 易失 |
程序控制语句 | break case switch continue default do else for if instanceof return switch while | 跳出循环 定义一个值以供 选择 继续 默认 运行 否则 循环 如果 实例 返回 根据值选择执行 循环 |
错误处理 | assert catch finally throw throws try | 断言表达式是否为真 捕捉异常 有没有异常都执行 抛出一个异常对象 声明一个异常可能被抛出 捕获异常 |
包相关 | import package | 引入 包 |
基本类型 | boolean byte char double float int long short | 布尔型 字节型 字符型 双精度浮点 单精度浮点 整型 长整型 短整型 |
变量引用 | super this void | 父类,超类 本类 无返回值 |
保留关键字 | goto const null | 是关键字,但不能使用 是关键字,但不能使用 空 |
Java注释
单行注释
// 这是单行注释
多行注释
/* 这
是多
行注释 */
继承
在 Java 中,一个类可以由其他类派生。如果你要创建一个类,而且已经存在一个类具有你所需要的属性或方法,那么你可以将新创建的类继承该类。
利用继承的方法,可以重用已存在类的方法和属性,而不用重写这些代码。被继承的类称为超类(super class),派生类称为子类(subclass)。
接口
在 Java 中,接口可理解为对象间相互通信的协议。接口在继承中扮演着很重要的角色。
接口只定义派生要用到的方法,但是方法的具体实现完全取决于派生类。
Java 源程序与编译型运行区别
如下图所示:
Java 对象和类
Java作为一种面向对象语言。支持以下基本概念:
- 多态
- 继承
- 封装
- 抽象
- 类
- 对象
- 实例
- 方法
- 重载
对象和类的概念:
对象:对象是类的一个实例(对象不是找个女朋友),有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
类:类是一个模板,它描述一类对象的行为和状态。
下图的两个男孩同属于一个类(class)即男孩,而这两个男孩分别属于不同的个体即对象(object)。
Java中的类的定义
public class Car {
// 车的属性
String color;
String speed;
String brand;
// 车的方法
public void turn() {
}
public void brake() {
}
public void fire() {
}
}
一个类可以包含以下类型变量:
- 局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
- 成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
- 类变量:类变量也声明在类中,方法体之外,但必须声明为 static 类型。
构造方法
每个类都有构造方法。如果没有显式地为类定义构造方法,Java 编译器将会为该类提供一个默认构造方法。在创建一个对象的时候,至少要调用一个构造方法。构造方法的名称必须与类同名,一个类可以有多个构造方法。
public class Puppy{
public Puppy(){
}
public Puppy(String name){
// 这个构造器仅有一个参数:name
}
}
创建对象
对象是根据类创建的。在Java中,使用关键字 new 来创建一个新的对象。创建对象需要以下三步:
- 声明:声明一个对象,包括对象名称和对象类型。
- 实例化:使用关键字 new 来创建一个对象。
- 初始化:使用 new 创建对象时,会调用构造方法初始化对象。
public class Car {
public Car(String brand) {
System.out.println("车的品牌是:" + brand);
}
public static void main(String[] args) {
Car myCar = new Car("BMW");
}
}
运行效果
访问实例变量和方法
通过已创建的对象来访问成员变量和成员方法
/* 实例化对象 */
Object referenceVariable = new Constructor();
/* 访问类中的变量 */
referenceVariable.variableName;
/* 访问类中的方法 */
referenceVariable.methodName();
public class Car {
String carColor;
public Car(String brand) {
System.out.println("车的品牌是:" + brand);
}
public void selectColor(String color) {
carColor = color;
}
public String getColor() {
System.out.println("车的颜色:" + carColor);
return carColor;
}
public static void main(String[] args) {
Car myCar = new Car("BMW");
myCar.selectColor("Quantum blue");
myCar.getColor();
}
}
运行效果
源文件声明规则
- 一个源文件中只能有一个 public 类
- 一个源文件可以有多个非 public 类
- 源文件的名称应该和 public 类的类名保持一致。例如:源文件中 public 类的类名是
Employee,那么源文件应该命名为Employee.java。 - 如果一个类定义在某个包中,那么 package 语句应该在源文件的首行。
- 如果源文件包含 import 语句,那么应该放在 package 语句和类定义之间。如果没有 package 语句,那么 import语句应该在源文件中最前面。
- import 语句和 package 语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明。
Java 包
包主要用来对类和接口进行分类。当开发 Java 程序时,可能编写成百上千的类,因此很有必要对类和接口进行分类。
import 语句
在 Java 中,如果给出一个完整的限定名,包括包名、类名,那么 Java 编译器就可以很容易地定位到源代码或者类。import 语句就是用来提供一个合理的路径,使得编译器可以找到某个类。
例如,下面的命令行将会命令编译器载入 java_installation/java/io 路径下的所有类
import java.io.*;
Java基本数据类型
变量就是申请内存来存储值。也就是说,当创建变量的时候,需要在内存中申请空间。
内存管理系统根据变量的类型为变量分配存储空间,分配的空间只能用来储存该类型数据。
Java 语言中的数据类型可以分为以下两大类
- 基本数据类型
- 引用数据类型
基本数据类型
-
整数型
byte 字节, 1 byte = 8 bits,默认值为0;
short 占用2个字节(16位),1 short = 16 bits,默认值为0;
int 占用4个字节(32位),1 int = 32 bits,默认值为0;
long 占用8个字节(64位),1 long = 64 bits,默认值为0L; -
浮点型
float (单精度浮点数),占用4个字节(32位),1 float = 32 bits,默认值为0.0f;
double (双精度浮点数), 占用8个字节(64位),1 double = 64 bits,默认值为0.0d; -
字符型
char类型是一个单一的16位Unicode字符,最小值为 \u0000(0),最大值是 \uffff(65536),char类型可以存储任何字符,如:char letter = ‘A’;
-
布尔型
boolean只有两种值:true 和 false,占用1位,默认值为 false。
基本类型值的范围
public class BaseType {
public static void main(String[] args) {
// byte
System.out.println("基本类型:byte 二进制位数:" + Byte.SIZE);
System.out.println("包装类:java.lang.Byte");
System.out.println("最小值:Byte.MIN_VALUE=" + Byte.MIN_VALUE);
System.out.println("最大值:Byte.MAX_VALUE=" + Byte.MAX_VALUE);
System.out.println();
// short
System.out.println("基本类型:short 二进制位数:" + Short.SIZE);
System.out.println("包装类:java.lang.Short");
System.out.println("最小值:Short.MIN_VALUE=" + Short.MIN_VALUE);
System.out.println("最大值:Short.MAX_VALUE=" + Short.MAX_VALUE);
System.out.println();
// int
System.out.println("基本类型:int 二进制位数:" + Integer.SIZE);
System.out.println("包装类:java.lang.Integer");
System.out.println("最小值:Integer.MIN_VALUE=" + Integer.MIN_VALUE);
System.out.println("最大值:Integer.MAX_VALUE=" + Integer.MAX_VALUE);
System.out.println();
// long
System.out.println("基本类型:long 二进制位数:" + Long.SIZE);
System.out.println("包装类:java.lang.Long");
System.out.println("最小值:Long.MIN_VALUE=" + Long.MIN_VALUE);
System.out.println("最大值:Long.MAX_VALUE=" + Long.MAX_VALUE);
System.out.println();
// float
System.out.println("基本类型:float 二进制位数:" + Float.SIZE);
System.out.println("包装类:java.lang.Float");
System.out.println("最小值:Float.MIN_VALUE=" + Float.MIN_VALUE);
System.out.println("最大值:Float.MAX_VALUE=" + Float.MAX_VALUE);
System.out.println();
// double
System.out.println("基本类型:double 二进制位数:" + Double.SIZE);
System.out.println("包装类:java.lang.Double");
System.out.println("最小值:Double.MIN_VALUE=" + Double.MIN_VALUE);
System.out.println("最大值:Double.MAX_VALUE=" + Double.MAX_VALUE);
System.out.println();
// char
System.out.println("基本类型:char 二进制位数:" + Character.SIZE);
System.out.println("包装类:java.lang.Character");
// 以数值形式而不是字符形式
System.out.println("最小值:Character.MIN_VALUE="
+ (int) Character.MIN_VALUE);
// 以数值形式而不是字符形式
System.out.println("最大值:Character.MAX_VALUE="
+ (int) Character.MAX_VALUE);
}
}
输出结果如下
引用类型
在Java中,引用类型的变量非常类似于C/C++的指针。引用类型指向一个对象,指向对象的变量是引用变量。变量一旦声明后,类型就不能被改变了。
- 对象、数组都是引用数据类型。
- 所有引用类型的默认值都是null。
- 一个引用变量可以用来引用任何与之兼容的类型。
Java 常量
常量在程序运行时是不能被修改的。
在 Java 中使用 final 关键字来修饰常量,声明方式和变量类似:
final double PI = 3.14;
Java语言的转义字符
符号 | 字符含义 |
---|---|
\n | 换行 (0x0a) |
\r | 回车 (0x0d) |
\f | 换页符(0x0c) |
\b | 退格 (0x08) |
\0 | 空字符 (0x0) |
\s | 空格 (0x20) |
\t | 制表符 |
" | 双引号 |
’ | 单引号 |
\ | 反斜杠 |
\ddd | 八进制字符 (ddd) |
\uxxxx | 16进制Unicode字符 (xxxx) |
自动类型转换
低 ——> 高
byte,short,char—> int —> long—> float —> double
数据类型转换必须满足如下规则:
-
不能对boolean类型进行类型转换。
-
不能把对象类型转换成不相关类的对象。
-
在把容量大的类型转换为容量小的类型时必须使用强制类型转换。
-
转换过程中可能导致溢出或损失精度,例如:
int i =128;
byte b = (byte)i;
因为 byte 类型是 8 位,最大值为127,所以当 int 强制转换为 byte 类型时,值 128 时候就会导致溢出。
- 浮点数到整数的转换是通过舍弃小数得到,而不是四舍五入,例如:
(int)23.7 == 23;
(int)-45.89f == -45
自动类型转换
必须满足转换前的数据类型的位数要低于转换后的数据类型,例如: short数据类型的位数为16位,就可以自动转换位数为32的int类型,同样float数据类型的位数为32,可以自动转换为64位的double类型。
public class AutomaticTransaction {
public static void main(String[] args) {
char c1='a';//定义一个char类型
int i1 = c1;//char自动类型转换为int
System.out.println("char自动类型转换为int后的值等于"+i1);
char c2 = 'A';//定义一个char类型
int i2 = c2+1;//char 类型和 int 类型计算
System.out.println("char类型和int计算后的值等于"+i2); }
}
运行结果为
强制类型转换
- 条件是转换的数据类型必须是兼容的。
- 格式:(type)value type是要强制类型转换后的数据类型
public class ConstraintTransaction {
public static void main(String[] args){
int i1 = 123;
byte b = (byte)i1; // 强制类型转换为byte
System.out.println("int强制类型转换为byte后的值等于"+b);
}
}
运行结果
隐含强制类型转换
- 整数的默认类型是 int。
- 浮点型不存在这种情况,因为在定义 float 类型时必须在数字后面跟上 F 或者 f。
Java 变量类型
在Java语言中,所有的变量在使用前必须声明。声明变量的基本格式如下:
type identifier [ = value][, identifier [= value] ...] ;
格式说明:type为Java数据类型。identifier是变量名。可以使用逗号隔开来声明多个同类型变量。
Java语言支持的变量类型有:
- 类变量:独立于方法之外的变量,用 static 修饰。
- 实例变量:独立于方法之外的变量,不过没有 static 修饰。
- 局部变量:类的方法中的变量。
public class Variable{
static int classVariable=0; // 类变量
String str="hello"; // 实例变量
public void method(){
int i =0; // 局部变量
}
}
Java 局部变量
- 局部变量声明在方法、构造方法或者语句块中;
- 局部变量在方法、构造方法、或者语句块被执行的时候创建,当它们执行完成后,变量将会被销毁;
- 访问修饰符不能用于局部变量;
- 局部变量只在声明它的方法、构造方法或者语句块中可见;
- 局部变量是在栈上分配的。
- 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用。
实例变量
- 实例变量声明在一个类中,但在方法、构造方法和语句块之外;
- 当一个对象被实例化之后,每个实例变量的值就跟着确定;
- 实例变量在对象创建的时候创建,在对象被销毁的时候销毁;
- 实例变量的值应该至少被一个方法、构造方法或者语句块引用,使得外部能够通过这些方式获取实例变量信息;
- 实例变量可以声明在使用前或者使用后;
- 访问修饰符可以修饰实例变量;
- 实例变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把实例变量设为私有。通过使用访问修饰符可以使实例变量对子类可见;
- 实例变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的默认值是null。变量的值可以在声明时指定,也可以在构造方法中指定;
- 实例变量可以直接通过变量名访问。但在静态方法以及其他类中,就应该使用完全限定名:ObejectReference.VariableName。
类变量(静态变量)
- 类变量也称为静态变量,在类中以 static 关键字声明,但必须在方法之外。
- 无论一个类创建了多少个对象,类只拥有类变量的一份拷贝。
- 静态变量除了被声明为常量外很少使用。常量是指声明为public/private,final和static类型的变量。常量初始化后不可改变。
- 静态变量储存在静态存储区。经常被声明为常量,很少单独使用static声明变量。
- 静态变量在第一次被访问时创建,在程序结束时销毁。
- 与实例变量具有相似的可见性。但为了对类的使用者可见,大多数静态变量声明为public类型。
- 默认值和实例变量相似。数值型变量默认值是0,布尔型默认值是false,引用类型默认值是null。变量的值可以在声明的时候指定,也可以在构造方法中指定。此外,静态变量还可以在静态语句块中初始化。
- 静态变量可以通过:ClassName.VariableName的方式访问。
- 类变量被声明为public static final类型时,类变量名称一般建议使用大写字母。如果静态变量不是public和final类型,其命名方式与实例变量以及局部变量的命名方式一致。
Java 修饰符
Java语言提供了很多修饰符,主要分为以下两类:
- 访问修饰符
- 非访问修饰符
修饰符用来定义类、方法或者变量,通常放在语句的最前端。
private boolean myFlag;
static final double weeks = 9.5;
protected static final int BOXWIDTH = 42;
public static void main(String[] arguments) {
// 方法体
}
访问控制修饰符
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
- default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
- private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
- public : 对所有类可见。使用对象:类、接口、变量、方法
- protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
默认访问修饰符-不使用任何关键字
使用默认访问修饰符声明的变量和方法,对同一个包内的类是可见的。接口里的变量都隐式声明为 public static final,而接口里的方法默认情况下访问权限为 public。
String version = "1.5.1";
boolean processOrder() {
return true;
}
私有访问修饰符-private
私有访问修饰符是最严格的访问级别,所以被声明为 private 的方法、变量和构造方法只能被所属类访问,并且类和接口不能声明为 private。
声明为私有访问类型的变量只能通过类中公共的 getter 方法被外部类访问。
Private 访问修饰符的使用主要用来隐藏类的实现细节和保护类的数据。
public class Logger {
private String format;
public String getFormat() {
return this.format;
}
public void setFormat(String format) {
this.format = format;
}
}
公有访问修饰符-public
被声明为 public 的类、方法、构造方法和接口能够被任何其他类访问。
如果几个相互访问的 public 类分布在不同的包中,则需要导入相应 public 类所在的包。由于类的继承性,类所有的公有方法和变量都能被其子类继承。
public static void main(String[] args) {
// ...
}
受保护的访问修饰符-protected
- 子类与基类在同一包中:被声明为 protected 的变量、方法和构造器能被同一个包中的任何其他类访问;
- 子类与基类不在同一包中:那么在子类中,子类实例可以访问其从基类继承而来的 protected
方法,而不能访问基类实例的protected方法。
protected 可以修饰数据成员,构造方法,方法成员,不能修饰类(内部类除外)。接口及接口的成员变量和成员方法不能声明为 protected。
访问控制和继承
请注意以下方法继承的规则:
- 父类中声明为 public 的方法在子类中也必须为 public。
- 父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private。
- 父类中声明为 private 的方法,不能够被继承。
非访问修饰符
为了实现一些其他的功能,Java 也提供了许多非访问修饰符。
static 修饰符,用来修饰类方法和类变量。
final 修饰符,用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。
abstract 修饰符,用来创建抽象类和抽象方法。
synchronized 和 volatile 修饰符,主要用于线程的编程。
static 修饰符
- 静态变量:static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。静态变量也被称为类变量。局部变量不能被声明为 static 变量。
- 静态方法:static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。
final 修饰符
final 变量:final 表示"最后的、最终的"含义,变量一旦赋值后,不能被重新赋值。被 final 修饰的实例变量必须显式指定初始值。
public class Test{
final int value = 10;
// 下面是声明常量的实例
public static final int BOXWIDTH = 6;
static final String TITLE = "Manager";
public void changeValue(){
value = 12; //将输出一个错误
}
}
final 方法
父类中的 final 方法可以被子类继承,但是不能被子类重写。声明 final 方法的主要目的是防止该方法的内容被修改。
public class Test{
public final void changeName(){
// 方法体
}
}
final 类
final 类不能被继承,没有类能够继承 final 类的任何特性。
public final class Test {
// 类体
}
abstract 修饰符
抽象类:抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充。
一个类不能同时被 abstract 和 final 修饰。如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将出现编译错误。抽象类可以包含抽象方法和非抽象方法。
abstract class Caravan{
private double price;
private String model;
private String year;
public abstract void goFast(); //抽象方法
public abstract void changeColor();
}
抽象方法
抽象方法是一种没有任何实现的方法,该方法的的具体实现由子类提供。抽象方法不能被声明成 final 和 static。任何继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类。如果一个类包含若干个抽象方法,那么该类必须声明为抽象类。抽象类可以不包含抽象方法。抽象方法的声明以分号结尾,例如:public abstract sample();。
public abstract class SuperClass{
abstract void m(); //抽象方法
}
class SubClass extends SuperClass{
//实现抽象方法
void m(){
.........
}
}
synchronized 修饰符
synchronized 关键字声明的方法同一时间只能被一个线程访问。synchronized 修饰符可以应用于四个访问修饰符。
public synchronized void showDetails(){
// .......
}
transient 修饰符
序列化的对象包含被 transient 修饰的实例变量时,java 虚拟机(JVM)跳过该特定的变量。该修饰符包含在定义变量的语句中,用来预处理类和变量的数据类型。
public transient int limit = 55; // 不会持久化
public int b; // 持久化
volatile 修饰符
volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。一个 volatile 对象引用可能是 null。
public class MyRunnable implements Runnable
{
private volatile boolean active;
public void run()
{
active = true;
while (active) // 第一行
{
// 代码
}
}
public void stop()
{
active = false; // 第二行
}
}
通常情况下,在一个线程调用 run() 方法(在 Runnable 开启的线程),在另一个线程调用 stop() 方法。 如果 第一行 中缓冲区的 active 值被使用,那么在 第二行 的 active 值为 false 时循环不会停止。
但是以上代码中我们使用了 volatile 修饰 active,所以该循环会停止。
Java运算符
算术运算符
表格中的实例假设整数变量A的值为10,变量B的值为20:
操作符 | 描述 | 例子 |
---|---|---|
+ | 加法 - 相加运算符两侧的值 | A + B 等于 30 |
- | 减法 - 左操作数减去右操作数 | A – B 等于 -10 |
* | 乘法 - 相乘操作符两侧的值 | A * B等于200 |
/ | 除法 - 左操作数除以右操作数 | B / A等于2 |
% | 取余 - 左操作数除以右操作数的余数 | B%A等于0 |
++ | 自增: 操作数的值增加1 | B++ 或 ++B 等于 21 |
– | 自减: 操作数的值减少1 | B-- 或 --B 等于 19 |
public class ArithmeticOperation {
public static void main(String[] args) {
int a = 10;
int b = 20;
System.out.println("a + b = " + (a + b) );
System.out.println("a - b = " + (a - b) );
System.out.println("a * b = " + (a * b) );
System.out.println("b / a = " + (b / a) );
System.out.println("b % a = " + (b % a) );
System.out.println("a++ = " + (a++) );
System.out.println("a-- = " + (a--) );
// 查看 a++ 与 ++a 的不同
System.out.println("a++ = " + (a++) );
System.out.println("++a = " + (++a) );
}
}
运行结果
关系运算符
表格中的实例整数变量A的值为10,变量B的值为20:
运算符 | 描述 | 例子 |
---|---|---|
== | 检查如果两个操作数的值是否相等,如果相等则条件为真 | (A == B)为假 |
!= | 检查如果两个操作数的值是否相等,如果值不相等则条件为真 | (A != B) 为真 |
> | 检查左操作数的值是否大于右操作数的值,如果是那么条件为真 | (A> B)为假 |
< | 检查左操作数的值是否小于右操作数的值,如果是那么条件为真 | (A <B)为真 |
>= | 检查左操作数的值是否大于或等于右操作数的值,如果是那么条件为真 | (A> = B)为假 |
<= | 检查左操作数的值是否小于或等于右操作数的值,如果是那么条件为真 | (A <= B)为真 |
public class RelationalOperation {
public static void main(String[] args) {
int a = 10;
int b = 20;
System.out.println("a == b = " + (a == b) );
System.out.println("a != b = " + (a != b) );
System.out.println("a > b = " + (a > b) );
System.out.println("a < b = " + (a < b) );
System.out.println("b >= a = " + (b >= a) );
System.out.println("b <= a = " + (b <= a) );
}
}
运行结果
位运算符
按位运算符用来比较整数基本类型中的每个比特位,也就是二进制位。
假设整数变量 A 的值为 60 和变量 B 的值为 13
操作符 | 描述 | 例子 |
---|---|---|
& | 如果相对应位都是1,则结果为1,否则为0 | (A&B),得到12,即0000 1100 |
| | 如果相对应位都是 0,则结果为 0,否则为 1 | (A | B)得到61,即 0011 1101 |
^ | 如果相对应位值相同,则结果为0,否则为1 | (A ^ B)得到49,即 0011 0001 |
〜 | 按位取反运算符翻转操作数的每一位,即0变成1,1变成0 | (〜A)得到-61,即1100 0011 |
<< | 按位左移运算符。左操作数按位左移右操作数指定的位数 | A << 2得到240,即 1111 0000 |
>> | 按位右移运算符。左操作数按位右移右操作数指定的位数 | A >> 2得到15即 1111 |
>>> | 按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充 | A>>>2得到15即0000 1111 |
public class BitOperation {
public static void main(String[] args) {
int a = 60; // 60 = 0011 1100
int b = 13; // 13 = 0000 1101
int c = 0;
c = a & b; // 12 = 0000 1100
System.out.println("a & b = " + c );
c = a | b; // 61 = 0011 1101
System.out.println("a | b = " + c );
c = a ^ b; // 49 = 0011 0001
System.out.println("a ^ b = " + c );
c = ~a; //-61 = 1100 0011
System.out.println("~a = " + c );
c = a << 2; // 240 = 1111 0000
System.out.println("a << 2 = " + c );
c = a >> 2; // 15 = 1111
System.out.println("a >> 2 = " + c );
c = a >>> 2; // 15 = 0000 1111
System.out.println("a >>> 2 = " + c );
}
}
运行结果
逻辑运算符
假设布尔变量A为真,变量B为假
操作符 | 描述 | 例子 |
---|---|---|
& | 逻辑与,当两个操作数都为真,条件才为真 | (A & B)为假 |
&& | 短路与 | (A && B)为假 |
| | 逻辑或,如果任何两个操作数任何一个为真,条件为真 | (A | B)为真 |
| | | 短路或 | (A | | B)为真 |
! | 逻辑非,用来反转操作数的逻辑状态。如果条件为true,则逻辑非运算符将得到false | !(A && B)为真 |
public class LogicalOperation {
public static void main(String[] args) {
boolean a = true;
boolean b = false;
System.out.println("a && b = " + (a&&b));
System.out.println("a || b = " + (a||b) );
System.out.println("!(a && b) = " + !(a && b));
}
}
运行结果
赋值运算符
操作符 | 描述 | 例子 |
---|---|---|
= | 简单的赋值运算符,将右操作数的值赋给左侧操作数 | C = A + B将把A + B得到的值赋给C |
+ = | 加和赋值操作符,它把左操作数和右操作数相加赋值给左操作数 | C + = A等价于C = C + A |
- = | 减和赋值操作符,它把左操作数和右操作数相减赋值给左操作数 | C - = A等价于C = C - A |
* = | 乘和赋值操作符,它把左操作数和右操作数相乘赋值给左操作数 | C * = A等价于C = C * A |
/ = | 除和赋值操作符,它把左操作数和右操作数相除赋值给左操作数 | C / = A,C 与 A 同类型时等价于 C = C / A |
%= | 取模和赋值操作符,它把左操作数和右操作数取模后赋值给左操作数 | C%= A等价于C = C%A |
<< = | 左移位赋值运算符 | C << = 2等价于C = C << 2 |
>> = | 右移位赋值运算符 | C >> = 2等价于C = C >> 2 |
&= | 按位与赋值运算符 | C&= 2等价于C = C&2 |
^ = | 按位异或赋值操作符 | C ^ = 2等价于C = C ^ 2 |
| = | 按位或赋值操作符 | C | = 2等价于C = C | 2 |
条件运算符(?:)
条件运算符也被称为三元运算符。该运算符有3个操作数,并且需要判断布尔表达式的值。该运算符的主要是决定哪个值应该赋值给变量。
条件表达式?表达式1:表达式2
variable x = (expression) ? value if true : value if false
instanceof 运算符
该运算符用于操作对象实例,检查该对象是否是一个特定类型(类类型或接口类型)。
instanceof运算符使用格式如下:
( Object reference variable ) instanceof (class/interface type)
如果运算符左侧变量所指的对象,是操作符右侧类或接口(class/interface)的一个对象,那么结果为真。
下面是一个例子:
String name = "James";
boolean result = name instanceof String; // 由于 name 是 String 类型,所以返回真
Java运算符优先级
下表中具有最高优先级的运算符在的表的最上面,最低优先级的在表的底部。
类别 | 操作符 | 关联性 |
---|---|---|
后缀 | () [] . (点操作符) | 左到右 |
一元 | expr++ expr– | 从左到右 |
一元 | ++expr --expr + - ~ ! | 从右到左 |
乘性 | * /% | 左到右 |
加性 | + - | 左到右 |
移位 | >> >>> << | 左到右 |
关系 | > >= < <= | 左到右 |
相等 | == != | 左到右 |
按位与 | & | 左到右 |
按位异或 | ^ | 左到右 |
按位或 | | | 左到右 |
逻辑与 | && | 左到右 |
逻辑或 | | | | 左到右 |
条件 | ?: | 从右到左 |
赋值 | = + = - = * = / =%= >> = << =&= ^ = | = | 从右到左 |
逗号 | , | 左到右 |
Java控制流程
Java 条件语句
if(boolean expression)
{
// 如果布尔表达式为true将执行的语句
}
if…else语句
if(boolean expression){
// 如果布尔表达式的值为true
}else{
// 如果布尔表达式的值为false
}
if…else if…else 语句
使用if…else if…else 语句的时候,需要注意下面几点:
- if 语句至多有 1 个 else 语句,else 语句在所有的 else if 语句之后。
- if 语句可以有若干个 else if 语句,它们必须在 else 语句之前。
- 一旦其中一个 else if 语句检测为 true,其他的 else if 以及 else 语句都将跳过执行。
if(boolean expression 1){
// 如果布尔表达式 1的值为true执行代码
}else if(boolean expression 2){
// 如果布尔表达式 2的值为true执行代码
}else if(boolean expression 3){
// 如果布尔表达式 3的值为true执行代码
}else {
// 如果以上布尔表达式都不为true执行代码
}
switch语句
switch case 语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。
switch case 语句有如下规则:
- switch 语句中的变量类型可以是: byte、short、int 或者 char。从 Java SE 7 开始,switch支持字符串 String 类型了,同时 case 标签必须为字符串常量或字面量。
- switch 语句可以拥有多个 case 语句。每个 case 后面跟一个要比较的值和冒号。
- case 语句中的值的数据类型必须与变量的数据类型相同,而且只能是常量或者字面常量。
- 当变量的值与 case 语句的值相等时,那么 case 语句之后的语句开始执行,直到 break 语句出现才会跳出 switch 语句。
- 当遇到 break 语句时,switch 语句终止。程序跳转到 switch 语句后面的语句执行。case 语句不必须要包含 break
语句。如果没有 break 语句出现,程序会继续执行下一条 case 语句,直到出现 break 语句。 - switch 语句可以包含一个 default 分支,该分支一般是 switch
语句的最后一个分支(可以在任何位置,但建议在最后一个)。default 在没有 case 语句的值和变量值相等的时候执行。default分支不需要 break 语句。
switch case 执行时,一定会先进行匹配,匹配成功返回当前 case 的值,再根据是否有 break,判断是否继续输出,或是跳出判断。
switch(expression){
case value :
// 语句
break; // 可选
case value :
// 语句
break; // 可选
// 你可以有任意数量的case语句
default : // 可选
// 语句
}
循环结构
Java中有三种主要的循环结构:
- while 循环
- do…while 循环
- for 循环
while 循环
只要布尔表达式为 true,循环就会一直执行下去。
while(boolean expression) {
// 循环内容
}
do…while 循环
对于 while 语句而言,如果不满足条件,则不能进入循环。但有时候我们需要即使不满足条件,也至少执行一次。
do…while 循环和 while 循环相似,不同的是,do…while 循环至少会执行一次。
do {
// 代码语句
}while(boolean expression);
注意:布尔表达式在循环体的后面,所以语句块在检测布尔表达式之前已经执行了。 如果布尔表达式的值为 true,则语句块一直执行,直到布尔表达式的值为 false。
for循环
for循环执行的次数是在执行前就确定的。
for(初始化; 布尔表达式; 更新) {
//代码语句
}
for 循环说明:
- 最先执行初始化步骤。可以声明一种类型,但可初始化一个或多个循环控制变量,也可以是空语句。
- 然后,检测布尔表达式的值。如果为 true,循环体被执行。如果为false,循环终止,开始执行循环体后面的语句。
- 执行一次循环后,更新循环控制变量。
- 再次检测布尔表达式。循环执行上面的过程。
Java 增强 for 循环
for(声明语句 : 表达式)
{
//代码句子
}
声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定在循环语句块,其值与此时数组元素的值相等。
表达式:表达式是要访问的数组名,或者是返回值为数组的方法。
跳转语句
在Java中的三种跳转语句:
- break
- continue
- return
break 关键字
break 主要用在循环语句或者 switch 语句中,用来跳出整个语句块。break 跳出最里层的循环,并且继续执行该循环下面的语句。
break;
continue 关键字
continue 适用于任何循环控制结构中。作用是让程序立刻跳转到下一次循环的迭代。
continue;
Java Number & Math 类
所有的包装类(Integer、Long、Byte、Double、Float、Short)都是抽象类 Number 的子类。
包装类 | 基本数据类型 |
---|---|
Boolean | boolean |
Byte | byte |
Short | short |
Integer | int |
Long | long |
Character | char |
Float | float |
Double | double |
Java Math 类
Java 的 Math 包含了用于执行基本数学运算的属性和方法,如初等指数、对数、平方根和三角函数Math 的方法都被定义为 static 形式,通过 Math 类可以在主函数中直接调用。
public class Test {
public static void main (String []args)
{
System.out.println("90 度的正弦值:" + Math.sin(Math.PI/2));
System.out.println("0度的余弦值:" + Math.cos(0));
System.out.println("60度的正切值:" + Math.tan(Math.PI/3));
System.out.println("1的反正切值: " + Math.atan(1));
System.out.println("π/2的角度值:" + Math.toDegrees(Math.PI/2));
System.out.println(Math.PI);
}
}
Number & Math 类方法
方法 | 描述 |
---|---|
xxxValue() | 将 Number 对象转换为xxx数据类型的值并返回 |
compareTo() | 将number对象与参数比较 |
equals() | 判断number对象是否与参数相等 |
valueOf() | 返回一个 Number 对象指定的内置数据类型 |
toString() | 以字符串形式返回值 |
parseInt() | 将字符串解析为int类型 |
abs() | 返回参数的绝对值 |
ceil() | 返回大于等于( >= )给定参数的的最小整数,类型为双精度浮点型 |
floor() | 返回小于等于(<=)给定参数的最大整数 |
rint() | 返回与参数最接近的整数。返回类型为double |
round() | 它表示四舍五入,算法为 Math.floor(x+0.5),即将原来的数字加上 0.5 后再向下取整,所以,Math.round(11.5) 的结果为12,Math.round(-11.5) 的结果为-11 |
min() | 返回两个参数中的最小值 |
max() | 返回两个参数中的最大值 |
exp() | 返回自然数底数e的参数次方 |
log() | 返回参数的自然数底数的对数值 |
pow() | 返回第一个参数的第二个参数次方 |
sqrt() | 求参数的算术平方根 |
sin() | 求指定double类型参数的正弦值 |
cos() | 求指定double类型参数的余弦值 |
tan() | 求指定double类型参数的正切值 |
asin() | 求指定double类型参数的反正弦值 |
acos() | 求指定double类型参数的反余弦值 |
atan() | 求指定double类型参数的反正切值 |
atan2() | 将笛卡尔坐标转换为极坐标,并返回极坐标的角度值 |
toDegrees() | 将参数转化为角度 |
toRadians() | 将角度转换为弧度 |
random() | 返回一个随机数 |
Java Character 类
Character 类用于对单个字符进行操作。Character 类在对象中包装一个基本类型 char 的值。
char ch = 'a';
// Unicode 字符表示形式
char uniChar = '\u039A';
// 字符数组
char[] charArray ={ 'a', 'b', 'c', 'd', 'e' };
Character的构造方法创建一个Character类对象
Character ch = new Character('a');
Character 方法
方法 | 描述 |
---|---|
isLetter() | 是否是一个字母 |
isDigit() | 是否是一个数字字符 |
isWhitespace() | 是否是一个空白字符 |
isUpperCase() | 是否是大写字母 |
isLowerCase() | 是否是小写字母 |
toUpperCase() | 指定字母的大写形式 |
toLowerCase() | 指定字母的小写形式 |
toString() | 返回字符的字符串形式,字符串的长度仅为1 |
Java String 类
字符串广泛应用 在 Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。
创建字符串
String str = "Hello World!";
字符串长度
用于获取有关对象的信息的方法称为访问器方法。String 类的一个访问器方法是 length() 方法,它返回字符串对象包含的字符数。
public class Test {
public static void main(String[] args) {
String str = "悲剧就是把美撕碎给人,每个人的人生都不会十全十美";
int len = str.length();
System.out.println("字符串长度:" + len);
}
}
连接字符串
String 类提供了连接两个字符串的方法:
string1.concat(string2);
public class Test {
public static void main(String[] args) {
String str = "有些人必生所追求的东西往往是另一些人与生就俱来的东西。而当人生将走到尽头时," +
"也许必生追求的人得到了所渴望的,而与生俱来的人却失去了他们仅有的。";
System.out.println("Hello,".concat("World!"));
System.out.println("1." + str);
}
}
创建格式化字符串
String 类使用静态方法 format() 返回一个String 对象而不是 PrintStream 对象。
String 类的静态方法 format() 能用来创建可复用的格式化字符串,而不仅仅是用于一次打印输出。
System.out.printf("浮点型变量的值为 " +
"%f, 整型变量的值为 " +
" %d, 字符串变量的值为 " +
"is %s", floatVar, intVar, stringVar);
或
String fs;
fs = String.format("浮点型变量的值为 " +
"%f, 整型变量的值为 " +
" %d, 字符串变量的值为 " +
" %s", floatVar, intVar, stringVar);
String 方法
方法 | 描述 |
---|---|
char charAt(int index) | 返回指定索引处的 char 值 |
int compareTo(Object o) | 把这个字符串和另一个对象比较 |
int compareTo(String anotherString) | 按字典顺序比较两个字符串 |
int compareToIgnoreCase(String str) | 按字典顺序比较两个字符串,不考虑大小写 |
String concat(String str) | 将指定字符串连接到此字符串的结尾 |
boolean contentEquals(StringBuffer sb) | 当且仅当字符串与指定的StringBuffer有相同顺序的字符时候返回真 |
static String copyValueOf(char[] data) | 返回指定数组中表示该字符序列的 String |
static String copyValueOf(char[] data, int offset, int count) | 返回指定数组中表示该字符序列的 String |
boolean endsWith(String suffix) | 测试此字符串是否以指定的后缀结束 |
boolean equals(Object anObject) | 将此字符串与指定的对象比较 |
boolean equalsIgnoreCase(String anotherString) | 将此 String 与另一个 String 比较,不考虑大小写 |
byte[] getBytes() | 使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中 |
byte[] getBytes(String charsetName) | 使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中 |
void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) | 将字符从此字符串复制到目标字符数组 |
int hashCode() | 返回此字符串的哈希码 |
int indexOf(int ch) | 返回指定字符在此字符串中第一次出现处的索引 |
int indexOf(int ch, int fromIndex) | 返回在此字符串中第一次出现指定字符处的索引,从指定的索引开始搜索 |
int indexOf(String str) | 返回指定子字符串在此字符串中第一次出现处的索引 |
int indexOf(String str, int fromIndex) | 返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始 |
String intern() | 返回字符串对象的规范化表示形式 |
int lastIndexOf(int ch) | 返回指定字符在此字符串中最后一次出现处的索引 |
int lastIndexOf(int ch, int fromIndex) | 返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索 |
int lastIndexOf(String str) | 返回指定子字符串在此字符串中最右边出现处的索引 |
int lastIndexOf(String str, int fromIndex) | 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索 |
int length() | 返回此字符串的长度 |
boolean matches(String regex) | 告知此字符串是否匹配给定的正则表达式 |
boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) | 测试两个字符串区域是否相等 |
boolean regionMatches(int toffset, String other, int ooffset, int len) | 测试两个字符串区域是否相等 |
String replace(char oldChar, char newChar) | 返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的 |
String replaceAll(String regex, String replacement) | 使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串 |
String replaceFirst(String regex, String replacement) | 使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串 |
String[] split(String regex) | 根据给定正则表达式的匹配拆分此字符串 |
String[] split(String regex, int limit) | 根据匹配给定的正则表达式来拆分此字符串 |
boolean startsWith(String prefix) | 测试此字符串是否以指定的前缀开始 |
boolean startsWith(String prefix, int toffset) | 测试此字符串从指定索引开始的子字符串是否以指定前缀开始 |
CharSequence subSequence(int beginIndex, int endIndex) | 返回一个新的字符序列,它是此序列的一个子序列 |
String substring(int beginIndex) | 返回一个新的字符串,它是此字符串的一个子字符串 |
String substring(int beginIndex, int endIndex) | 返回一个新字符串,它是此字符串的一个子字符串 |
char[] toCharArray() | 将此字符串转换为一个新的字符数组 |
String toLowerCase() | 使用默认语言环境的规则将此 String 中的所有字符都转换为小写 |
String toLowerCase(Locale locale) | 使用给定 Locale 的规则将此 String 中的所有字符都转换为小写 |
String toString() | 返回此对象本身(它已经是一个字符串!)。 |
String toUpperCase() | 使用默认语言环境的规则将此 String 中的所有字符都转换为大写 |
String toUpperCase(Locale locale) | 使用给定 Locale 的规则将此 String 中的所有字符都转换为大写 |
String trim() | 返回字符串的副本,忽略前导空白和尾部空白 |
static String valueOf(primitive data type x) | 返回给定data type类型x参数的字符串表示形式 |
Java StringBuffer
当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。
和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。
StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。
由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。
StringBuffer 方法
方法 | 描述 |
---|---|
public StringBuffer append(String s) | 将指定的字符串追加到此字符序列 |
public StringBuffer reverse() | 将此字符序列用其反转形式取代 |
public delete(int start, int end) | 移除此序列的子字符串中的字符 |
replace(int start, int end, String str) | 使用给定 String 中的字符替换此序列的子字符串中的字符 |
方法 | 描述 |
---|---|
int capacity() | 返回当前容量 |
char charAt(int index) | 返回此序列中指定索引处的 char 值 |
void ensureCapacity(int minimumCapacity) | 确保容量至少等于指定的最小值 |
void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) | 将字符从此序列复制到目标字符数组 dst |
int indexOf(String str) | 返回第一次出现的指定子字符串在该字符串中的索引 |
int indexOf(String str, int fromIndex) | 从指定的索引处开始,返回第一次出现的指定子字符串在该字符串中的索引 |
int lastIndexOf(String str) | 返回最右边出现的指定子字符串在此字符串中的索引 |
int lastIndexOf(String str, int fromIndex) | 返回 String 对象中子字符串最后出现的位置 |
int length() | 返回长度(字符数) |
void setCharAt(int index, char ch) | 将给定索引处的字符设置为 ch |
void setLength(int newLength) | 设置字符序列的长度 |
CharSequence subSequence(int start, int end) | 返回一个新的字符序列,该字符序列是此序列的子序列 |
String substring(int start) | 返回一个新的 String,它包含此字符序列当前所包含的字符子序列 |
String substring(int start, int end) | 返回一个新的 String,它包含此序列当前所包含的字符子序列 |
String toString() | 返回此序列中数据的字符串表示形式 |
Java 数组
声明数组变量
首先必须声明数组变量,才能在程序中使用数组。
dataType[] arrayRefVar; // 首选的方法
或
dataType arrayRefVar[]; // 效果相同,但不是首选方法
创建数组
Java语言使用new操作符来创建数组
arrayRefVar = new dataType[arraySize];
还可以使用如下的方式创建数组
dataType[] arrayRefVar = {value0, value1, ..., valuek};
数组的元素是通过索引访问的。数组索引从 0 开始,所以索引值从 0 到 arrayRefVar.length-1。
处理数组
数组的元素类型和数组的大小都是确定的,所以当处理数组元素时候,我们通常使用基本循环或者 For-Each 循环
数组作为函数的参数
数组可以作为参数传递给方法。
public static void printArray(int[] array) {
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
}
多维数组
多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组
String str[][] = new String[3][4];
多维数组的动态初始化
type[][] typeName = new type[typeLength1][typeLength2];
多维数组的引用
Arrays 类
a[1][0];
java.util.Arrays 类能方便地操作数组,它提供的所有方法都是静态的。
具有以下功能:
- 给数组赋值:通过 fill 方法。
- 对数组排序:通过 sort 方法,按升序。
- 比较数组:通过 equals 方法比较数组中元素值是否相等。
- 查找数组元素:通过 binarySearch 方法能对排序好的数组进行二分查找法操作。
方法 | 说明 |
---|---|
public static int binarySearch(Object[] a, Object key) | 用二分查找算法在给定数组中搜索给定值的对象(Byte,Int,double等)。数组在调用前必须排序好的。如果查找值包含在数组中,则返回搜索键的索引;否则返回 (-(插入点) - 1) |
public static boolean equals(long[] a, long[] a2) | 如果两个指定的 long 型数组彼此相等,则返回 true。如果两个数组包含相同数量的元素,并且两个数组中的所有相应元素对都是相等的,则认为这两个数组是相等的。换句话说,如果两个数组以相同顺序包含相同的元素,则两个数组是相等的。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等) |
public static void fill(int[] a, int val) | 将指定的 int 值分配给指定 int 型数组指定范围中的每个元素。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等) |
public static void sort(Object[] a) | 对指定对象数组根据其元素的自然顺序进行升序排列。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等) |
Java 日期时间
java.util 包提供了 Date 类来封装当前的日期和时间。 Date 类提供两个构造函数来实例化 Date 对象。
第一个构造函数使用当前日期和时间来初始化对象。
Date( )
第二个构造函数接收一个参数,该参数是从1970年1月1日起的毫秒数。
Date(long millisec)
方法 | 描述 |
---|---|
boolean after(Date date) | 若当调用此方法的Date对象在指定日期之后返回true,否则返回false |
boolean before(Date date) | 若当调用此方法的Date对象在指定日期之前返回true,否则返回false |
Object clone( ) | 返回此对象的副本 |
int compareTo(Date date) | 比较当调用此方法的Date对象和指定日期。两者相等时候返回0。调用对象在指定日期之前则返回负数。调用对象在指定日期之后则返回正数 |
int compareTo(Object obj) | 若obj是Date类型则操作等同于compareTo(Date) 。否则它抛出ClassCastException |
boolean equals(Object date) | 当调用此方法的Date对象和指定日期相等时候返回true,否则返回false |
long getTime( ) | 返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数 |
int hashCode( ) | 返回此对象的哈希码值 |
void setTime(long time) | 用自1970年1月1日00:00:00 GMT以后time毫秒数设置时间和日期 |
String toString( ) | 把此 Date 对象转换为以下形式的 String: dow mon dd hh:mm:ss zzz yyyy 其中: dow 是一周中的某一天 (Sun, Mon, Tue, Wed, Thu, Fri, Sat) |
Java中使用 Date 对象的 toString() 方法来打印当前日期和时间
import java.util.Date;
public class DateDemo {
public static void main(String args[]) {
// 初始化 Date 对象
Date date = new Date();
// 使用 toString() 函数显示日期时间
System.out.println(date.toString());
}
}
日期比较
- 使用 getTime() 方法获取两个日期(自1970年1月1日经历的毫秒数值),然后比较这两个值。
- 使用方法 before(),after() 和 equals()。例如,一个月的12号比18号早,则 new Date(99, 2,
12).before(new Date (99, 2, 18)) 返回true。 - 使用 compareTo() 方法,它是由 Comparable 接口定义的,Date 类实现了这个接口。
使用 SimpleDateFormat 格式化日期
SimpleDateFormat 是一个以语言环境敏感的方式来格式化和分析日期的类。SimpleDateFormat 允许你选择任何用户自定义日期时间格式来运行。
import java.util.*;
import java.text.*;
public class DateDemo {
public static void main(String args[]) {
Date dNow = new Date( );
SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss");
System.out.println("当前时间为: " + ft.format(dNow));
}
}
日期和时间的格式化编码
时间模式字符串用来指定时间格式。在此模式中,所有的 ASCII 字母被保留为模式字母,定义如下:
字母 | 描述 | 示例 |
---|---|---|
G | 纪元标记 | AD |
y | 四位年份 | 2001 |
M | 月份 | July or 07 |
d | 一个月的日期 | 10 |
h | A.M./P.M. (1~12)格式小时 | 12 |
H | 一天中的小时 (0~23) | 22 |
m | 分钟数 | 30 |
s | 秒数 | 55 |
S | 毫秒数 | 234 |
E | 星期几 | Tuesday |
D | 一年中的日子 | 360 |
F | 一个月中第几周的周几 | 2 (second Wed. in July) |
w | 一年中第几周 | 40 |
W | 一个月中第几周 | 1 |
a | A.M./P.M. 标记 | PM |
k | 一天中的小时(1~24) | 24 |
K | A.M./P.M. (0~11)格式小时 | 10 |
z | 时区 | Eastern Standard Time |
’ | 文字定界符 | Delimiter |
" | 单引号 | ` |
使用printf格式化日期
printf 方法可以很轻松地格式化时间和日期。使用两个字母格式,它以 %t 开头并且以下面表格中的一个字母结尾。
转换符 | 说明 |
---|---|
c | 包括全部日期和时间信息 |
F | "年-月-日"格式 |
D | "月/日/年"格式 |
r | "HH:MM:SS PM"格式(12时制) |
T | "HH:MM:SS"格式(24时制) |
R | "HH:MM"格式(24时制) |
Java 休眠(sleep)
sleep()使当前线程进入停滞状态(阻塞当前线程),让出CPU的使用、目的是不让当前线程独自霸占该进程所获的CPU资源,以留一定时间给其他线程执行的机会。
Thread.sleep(1000*3); // 休眠3秒
Calendar类
Calendar类是一个抽象类,在实际使用时实现特定的子类的对象,创建对象的过程对程序员来说是透明的,只需要使用getInstance方法创建即可。
创建一个代表系统当前日期的Calendar对象
Calendar c = Calendar.getInstance();//默认是当前日期
创建一个指定日期的Calendar对象
使用Calendar类代表特定的时间,需要首先创建一个Calendar的对象,然后再设定该对象中的年月日参数来完成。
//创建一个Calendar对象
Calendar c1 = Calendar.getInstance();
c1.set(2021, 9 - 7, 12);
Calendar类对象字段类型
Calendar类中用以下这些常量表示不同的意义,jdk内的很多类其实都是采用的这种思想
常量 | 描述 |
---|---|
Calendar.YEAR | 年份 |
Calendar.MONTH | 月份 |
Calendar.DATE | 日期 |
Calendar.DAY_OF_MONTH | 日期 |
Calendar.HOUR | 12小时制的小时 |
Calendar.HOUR_OF_DAY | 24小时制的小时 |
Calendar.MINUTE | 分钟 |
Calendar.SECOND | 秒 |
Calendar.DAY_OF_WEEK | 星期几 |
Calendar类对象信息的设置
Set设置
Calendar c1 = Calendar.getInstance();
调用:
public final void set(int year,int month,int date)
c1.set(2021, 9, 7);//把Calendar对象c1的年月日分别设这为:2021、9、7
利用字段类型设置
如果只设定某个字段,例如日期的值,则可以使用如下set方法:
public void set(int field,int value)
把 c1对象代表的日期设置为10号,其它所有的数值会被重新计算
c1.set(Calendar.DATE,10);
把c1对象代表的年份设置为2021年,其他的所有数值会被重新计算
c1.set(Calendar.YEAR,2021);
其他字段属性set的意义以此类推
Add设置
Calendar c1 = Calendar.getInstance();
把c1对象的日期加上10,也就是c1也就表示为10天后的日期,其它所有的数值会被重新计算
c1.add(Calendar.DATE, 10);
把c1对象的日期减去10,也就是c1也就表示为10天前的日期,其它所有的数值会被重新计算
c1.add(Calendar.DATE, -10);
其他字段属性的add的意义以此类推
Calendar类对象信息的获得
Calendar c1 = Calendar.getInstance();
// 获得年份
int year = c1.get(Calendar.YEAR);
// 获得月份
int month = c1.get(Calendar.MONTH) + 1;
// 获得日期
int date = c1.get(Calendar.DATE);
// 获得小时
int hour = c1.get(Calendar.HOUR_OF_DAY);
// 获得分钟
int minute = c1.get(Calendar.MINUTE);
// 获得秒
int second = c1.get(Calendar.SECOND);
// 获得星期几(注意(这个与Date类是不同的):1代表星期日、2代表星期1、3代表星期二,以此类推)
int day = c1.get(Calendar.DAY_OF_WEEK);
GregorianCalendar类
Calendar类实现了公历日历,GregorianCalendar是Calendar类的一个具体实现。
Calendar 的getInstance()方法返回一个默认用当前的语言环境和时区初始化的GregorianCalendar对象。GregorianCalendar定义了两个字段:AD和BC。这是代表公历定义的两个时代。
构造函数 | 说明 |
---|---|
GregorianCalendar() | 在具有默认语言环境的默认时区内使用当前时间构造一个默认的 GregorianCalendar |
GregorianCalendar(int year, int month, int date) | 在具有默认语言环境的默认时区内构造一个带有给定日期设置的GregorianCalendar |
GregorianCalendar(int year, int month, int date, int hour, int minute) | 为具有默认语言环境的默认时区构造一个具有给定日期和时间设置的 GregorianCalendar |
GregorianCalendar(int year, int month, int date, int hour, int minute, int second) | 为具有默认语言环境的默认时区构造一个具有给定日期和时间设置的 GregorianCalendar |
GregorianCalendar(Locale aLocale) | 在具有给定语言环境的默认时区内构造一个基于当前时间的 GregorianCalendar |
GregorianCalendar(TimeZone zone) | 在具有默认语言环境的给定时区内构造一个基于当前时间的 GregorianCalendar |
GregorianCalendar(TimeZone zone, Locale aLocale) | 在具有给定语言环境的给定时区内构造一个基于当前时间的GregorianCalendar |
方法 | 说明 |
---|---|
void add(int field, int amount) | 根据日历规则,将指定的(有符号的)时间量添加到给定的日历字段中 |
protected void computeFields() | 转换UTC毫秒值为时间域值 |
protected void computeTime() | 覆盖Calendar ,转换时间域值为UTC毫秒值 |
boolean equals(Object obj) | 比较此 GregorianCalendar 与指定的 Object |
int get(int field) | 获取指定字段的时间值 |
int getActualMaximum(int field) | 返回当前日期,给定字段的最大值 |
int getActualMinimum(int field) | 返回当前日期,给定字段的最小值 |
int getGreatestMinimum(int field) | 返回此 GregorianCalendar 实例给定日历字段的最高的最小值 |
Date getGregorianChange() | 获得格里高利历的更改日期 |
int getLeastMaximum(int field) | 返回此 GregorianCalendar 实例给定日历字段的最低的最大值 |
int getMaximum(int field) | 返回此 GregorianCalendar 实例的给定日历字段的最大值 |
Date getTime() | 获取日历当前时间 |
long getTimeInMillis() | 获取用长整型表示的日历的当前时间 |
TimeZone getTimeZone() | 获取时区 |
int getMinimum(int field) | 返回给定字段的最小值 |
int hashCode() | 重写hashCode. |
boolean isLeapYear(int year) | 确定给定的年份是否为闰年 |
void roll(int field, boolean up) | 在给定的时间字段上添加或减去(上/下)单个时间单元,不更改更大的字段 |
void set(int field, int value) | 用给定的值设置时间字段 |
void set(int year, int month, int date) | 设置年、月、日的值 |
void set(int year, int month, int date, int hour, int minute) | 设置年、月、日、小时、分钟的值 |
void set(int year, int month, int date, int hour, int minute, int second) | 设置年、月、日、小时、分钟、秒的值 |
void setGregorianChange(Date date) | 设置 GregorianCalendar 的更改日期 |
void setTime(Date date) | 用给定的日期设置Calendar的当前时间 |
void setTimeInMillis(long millis) | 用给定的long型毫秒数设置Calendar的当前时间 |
void setTimeZone(TimeZone value) | 用给定时区值设置当前时区 |
String toString() | 返回代表日历的字符串 |
Java 正则表达式
正则表达式
一个字符串其实就是一个简单的正则表达式,例如 Hello World 正则表达式匹配 “Hello World” 字符串。
.(点号)也是一个正则表达式,它匹配任何一个字符如:“a” 或 “1”。
java.util.regex 包主要包括以下三个类:
- Pattern 类:pattern 对象是一个正则表达式的编译表示。Pattern 类没有公共构造方法。要创建一个 Pattern对象,你必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。
- Matcher 类:Matcher 对象是对输入字符串进行解释和匹配操作的引擎。与Pattern 类一样,Matcher也没有公共构造方法。你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。
- PatternSyntaxException:PatternSyntaxException是一个非强制异常类,它表示一个正则表达式模式中的语法错误。
捕获组
捕获组是把多个字符当一个单独单元进行处理的方法,它通过对括号内的字符分组来创建。
例如,正则表达式 (dog) 创建了单一分组,组里包含"d",“o”,和"g"。
捕获组是通过从左至右计算其开括号来编号。例如,在表达式((A)(B(C))),有四个这样的组:
- ((A)(B©))
- (A)
- (B©)
- ©
可以通过调用 matcher 对象的 groupCount 方法来查看表达式有多少个分组。groupCount 方法返回一个 int 值,表示matcher对象当前有多个捕获组。
还有一个特殊的组(group(0)),它总是代表整个表达式。该组不包括在 groupCount 的返回值中。
正则表达式语法
在其他语言中,\ 表示:我想要在正则表达式中插入一个普通的(字面上的)反斜杠,请不要给它任何特殊的意义。
在 Java 中,\ 表示:我要插入一个正则表达式的反斜线,所以其后的字符具有特殊的意义。
所以,在其他的语言中(如Perl),一个反斜杠 \ 就足以具有转义的作用,而在 Java 中正则表达式中则需要有两个反斜杠才能被解析为其他语言中的转义作用。也可以简单的理解在 Java 的正则表达式中,两个 \ 代表其他语言中的一个 \,这也就是为什么表示一位数字的正则表达式是 \d,而表示一个普通的反斜杠是 \\。
字符 | 说明 |
---|---|
|将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如,“n"匹配字符"n”。"\n"匹配换行符。序列"\\“匹配”\","\(“匹配”("。 | |
^ | 匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与"\n"或"\r"之后的位置匹配 |
$ | 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与"\n"或"\r"之前的位置匹配。 |
* | 零次或多次匹配前面的字符或子表达式。例如,zo* 匹配"z"和"zoo"。* 等效于 {0,} |
+ | 一次或多次匹配前面的字符或子表达式。例如,"zo+"与"zo"和"zoo"匹配,但与"z"不匹配。+ 等效于 {1,} |
? | 零次或一次匹配前面的字符或子表达式。例如,"do(es)?“匹配"do"或"does"中的"do”。? 等效于 {0,1} |
{n} | n 是非负整数。正好匹配 n 次。例如,"o{2}"与"Bob"中的"o"不匹配,但与"food"中的两个"o"匹配 |
{n,} | n 是非负整数。至少匹配 n 次。例如,"o{2,}“不匹配"Bob"中的"o”,而匹配"foooood"中的所有 o。"o{1,}“等效于"o+”。"o{0,}“等效于"o*” |
{n,m} | m 和 n 是非负整数,其中 n <= m。匹配至少 n 次,至多 m 次。例如,"o{1,3}"匹配"fooooood"中的头三个 o。‘o{0,1}’ 等效于 ‘o?’。注意:您不能将空格插入逗号和数字之间 |
? | 当此字符紧随任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后时,匹配模式是"非贪心的"。"非贪心的"模式匹配搜索到的、尽可能短的字符串,而默认的"贪心的"模式匹配搜索到的、尽可能长的字符串。例如,在字符串"oooo"中,"o+?“只匹配单个"o”,而"o+“匹配所有"o” |
. | 匹配除"\r\n"之外的任何单个字符。若要匹配包括"\r\n"在内的任意字符,请使用诸如"[\s\S]"之类的模式 |
(pattern) | 匹配 pattern 并捕获该匹配的子表达式。可以使用 $0…$9 属性从结果"匹配"集合中检索捕获的匹配。若要匹配括号字符 ( ),请使用"(“或者”)" |
(?:pattern) | 匹配 pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用"or"字符 ( |
(?=pattern) | 执行正向预测先行搜索的子表达式,该表达式匹配处于匹配 pattern 的字符串的起始点的字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,'Windows (?=95 |
(?!pattern) | 执行反向预测先行搜索的子表达式,该表达式匹配不处于匹配 pattern 的字符串的起始点的搜索字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,'Windows (?!95 |
x|y | 匹配 x 或 y。例如,'z |
[xyz] | 字符集。匹配包含的任一字符。例如,"[abc]“匹配"plain"中的"a” |
[^xyz] | 反向字符集。匹配未包含的任何字符。例如,"[^abc]“匹配"plain"中"p”,“l”,“i”,“n” |
[a-z] | 字符范围。匹配指定范围内的任何字符。例如,"[a-z]"匹配"a"到"z"范围内的任何小写字母 |
[^a-z] | 反向范围字符。匹配不在指定的范围内的任何字符。例如,"[^a-z]"匹配任何不在"a"到"z"范围内的任何字符 |
\b | 匹配一个字边界,即字与空格间的位置。例如,“er\b"匹配"never"中的"er”,但不匹配"verb"中的"er" |
\B | 非字边界匹配。“er\B"匹配"verb"中的"er”,但不匹配"never"中的"er" |
\cx | 匹配 x 指示的控制字符。例如,\cM 匹配 Control-M 或回车符。x 的值必须在 A-Z 或 a-z 之间。如果不是这样,则假定 c 就是"c"字符本身 |
\d | 数字字符匹配。等效于 [0-9] |
\D | 非数字字符匹配。等效于 [^0-9] |
\f | 换页符匹配。等效于 \x0c 和 \cL |
\n | 换行符匹配。等效于 \x0a 和 \cJ |
\r | 匹配一个回车符。等效于 \x0d 和 \cM |
\s | 匹配任何空白字符,包括空格、制表符、换页符等。与 [ \f\n\r\t\v] 等效 |
\S | 匹配任何非空白字符。与 [^ \f\n\r\t\v] 等效 |
\t | 制表符匹配。与 \x09 和 \cI 等效 |
\v | 垂直制表符匹配。与 \x0b 和 \cK 等效 |
\w | 匹配任何字类字符,包括下划线。与"[A-Za-z0-9_]"等效 |
\W | 与任何非单词字符匹配。与"[^A-Za-z0-9_]"等效 |
\xn | 匹配 n,此处的 n 是一个十六进制转义码。十六进制转义码必须正好是两位数长。例如,"\x41"匹配"A"。"\x041"与"\x04"&"1"等效。允许在正则表达式中使用 ASCII 代码 |
\num | 匹配 num,此处的 num 是一个正整数。到捕获匹配的反向引用。例如,"(.)\1"匹配两个连续的相同字符 |
\n | 标识一个八进制转义码或反向引用。如果 \n 前面至少有 n 个捕获子表达式,那么 n 是反向引用。否则,如果 n 是八进制数 (0-7),那么 n 是八进制转义码 |
\nm | 标识一个八进制转义码或反向引用。如果 \nm 前面至少有 nm 个捕获子表达式,那么 nm 是反向引用。如果 \nm 前面至少有 n 个捕获,则 n 是反向引用,后面跟有字符 m。如果两种前面的情况都不存在,则 \nm 匹配八进制值 nm,其中 n 和 m 是八进制数字 (0-7) |
\nml | 当 n 是八进制数 (0-3),m 和 l 是八进制数 (0-7) 时,匹配八进制转义码 nml |
\un | 匹配 n,其中 n 是以四位十六进制数表示的 Unicode 字符。例如,\u00A9 匹配版权符号 (©) |
Matcher 类的方法
索引方法
索引方法提供了有用的索引值,精确表明输入字符串中在哪能找到匹配:
方法 | 说明 |
---|---|
public int | start()返回以前匹配的初始索引 |
public int start(int group) | 返回在以前的匹配操作期间,由给定组所捕获的子序列的初始索引 |
public int end() | 返回最后匹配字符之后的偏移量 |
public int end(int group) | 返回在以前的匹配操作期间,由给定组所捕获子序列的最后字符之后的偏移量 |
查找方法
查找方法用来检查输入字符串并返回一个布尔值,表示是否找到该模式:
方法 | 说明 |
---|---|
public boolean lookingAt() | 尝试将从区域开头开始的输入序列与该模式匹配 |
public boolean find() | 尝试查找与该模式匹配的输入序列的下一个子序列 |
public boolean find(int start) | 重置此匹配器,然后尝试查找匹配该模式、从指定索引开始的输入序列的下一个子序列 |
public boolean matches() | 尝试将整个区域与模式匹配 |
替换方法
替换方法是替换输入字符串里文本的方法:
方法 | 说明 |
---|---|
public Matcher appendReplacement(StringBuffer sb, String replacement) | 实现非终端添加和替换步骤 |
public StringBuffer appendTail(StringBuffer sb) | 实现终端添加和替换步骤 |
public String replaceAll(String replacement) | 替换模式与给定替换字符串相匹配的输入序列的每个子序列 |
public String replaceFirst(String replacement) | 替换模式与给定替换字符串匹配的输入序列的第一个子序列 |
public static String quoteReplacement(String s) | 返回指定字符串的字面替换字符串。这个方法返回一个字符串,就像传递给Matcher类的appendReplacement 方法一个字面字符串一样工作 |
matches 和 lookingAt 方法
matches 和 lookingAt 方法都用来尝试匹配一个输入序列模式。它们的不同是 matches 要求整个序列都匹配,而lookingAt 不要求。
lookingAt 方法虽然不需要整句都匹配,但是需要从第一个字符开始匹配。
replaceFirst 和 replaceAll 方法
replaceFirst 和 replaceAll 方法用来替换匹配正则表达式的文本。不同的是,replaceFirst 替换首次匹配,replaceAll 替换所有匹配。
appendReplacement 和 appendTail 方法
Matcher 类提供了appendReplacement 和 appendTail 方法用于文本替换
PatternSyntaxException 类的方法
PatternSyntaxException 是一个非强制异常类,它指示一个正则表达式模式中的语法错误。
PatternSyntaxException 类提供了下面的方法来帮助我们查看发生了什么错误。
方法 | 说明 |
---|---|
public String getDescription() | 获取错误的描述 |
public int getIndex() | 获取错误的索引 |
public String getPattern() | 获取错误的正则表达式模式 |
public String getMessage() | 返回多行字符串,包含语法错误及其索引的描述、错误的正则表达式模式和模式中错误索引的可视化指示 |
Java 方法
System.out.println()是什么呢?
- println() 是一个方法。
- System 是系统类。
- out 是标准输出对象。
这句话的用法是调用系统类 System 中的标准输出对象 out 中的方法 println()。
Java方法是语句的集合,它们在一起执行一个功能。
- 方法是解决一类问题的步骤的有序组合
- 方法包含于类或对象中
- 方法在程序中被创建,在其他地方被引用
方法的优点
- 使程序变得更简短而清晰。
- 有利于程序维护。
- 可以提高程序开发的效率。
- 提高了代码的重用性。
方法的命名规则
- 方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头写,不使用连接符。例如:addPerson。
- 下划线可能出现在 JUnit 测试方法名称中用以分隔名称的逻辑组件。一个典型的模式是:test_,例如testPop_emptyStack。
方法的定义
- 修饰符:修饰符,这是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型。
- 返回值类型 :方法可能会返回值。returnValueType
是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值。在这种情况下,returnValueType 是关键字void。 - 方法名:是方法的实际名称。方法名和参数表共同构成方法签名。
- 参数类型:参数像是一个占位符。当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表是指方法的参数类型、顺序和参数的个数。参数是可选的,方法可以不包含任何参数。
- 方法体:方法体包含具体的语句,定义该方法的功能。
修饰符 返回值类型 方法名(参数类型 参数名){
...
方法体
...
return 返回值;
}
方法调用
Java 支持两种调用方法的方式,根据方法是否返回值来选择。
当程序调用一个方法时,程序的控制权交给了被调用的方法。当被调用方法的返回语句执行或者到达方法体闭括号时候交还控制权给程序。
当方法返回一个值的时候,方法调用通常被当做一个值。
int larger = max(30, 40);
方法的重载
重载的方法必须拥有不同的参数列表
public static double max(double num1, double num2) {
if (num1 > num2)
return num1;
else
return num2;
}
变量作用域
变量的范围是程序中该变量可以被引用的部分。
方法内定义的变量被称为局部变量。局部变量的作用范围从声明开始,直到包含它的块结束。局部变量必须声明才可以使用。
方法的参数范围涵盖整个方法。参数实际上是一个局部变量。
构造方法
当一个对象被创建时候,构造方法用来初始化该对象。构造方法和它所在类的名字相同,但构造方法没有返回值。
通常会使用构造方法给一个类的实例变量赋初值,或者执行其它必要的步骤来创建一个完整的对象。
不管你是否自定义构造方法,所有的类都有构造方法,因为Java自动提供了一个默认构造方法,默认构造方法的访问修改符和类的访问修改符相同(类为 public,构造函数也为 public;类改为 protected,构造函数也改为 protected)。
一旦你定义了自己的构造方法,默认构造方法就会失效。
finalize() 方法
Java 允许定义这样的方法,它在对象被垃圾收集器析构(回收)之前调用,这个方法叫做 finalize( ),它用来清除回收对象。在 finalize() 方法里,你必须指定在对象销毁时候要执行的操作。
protected void finalize()
{
// 在这里终结代码
}
Java 流(Stream)、文件(File)和IO
Java.io 包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。
Java.io 包中的流支持很多种格式,比如:基本类型、对象、本地化字符集等等。
一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。
读取控制台输入
Java 的控制台输入由 System.in 完成。
为了获得一个绑定到控制台的字符流,你可以把 System.in 包装在一个 BufferedReader 对象中来创建一个字符流。
BufferedReader br = new BufferedReader(newInputStreamReader(System.in));
从控制台读取多字符输入
BufferedReader 对象读取一个字符要使用 read() 方法
int read( ) throws IOException
每次调用 read() 方法,它从输入流读取一个字符并把该字符作为整数值返回。 当流结束的时候返回 -1。该方法抛出 IOException。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
public class Demo {
public static void main(String[] args) throws IOException {
char a;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("输出输入的字符,按下q键结束");
do {
a = (char)br.read();
System.out.println(a);
} while (a != 'q');
}
}
运行结果
从控制台读取字符串
从标准输入读取一个字符串需要使用 BufferedReader 的 readLine() 方法。
String readLine( ) throws IOException
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
public class Demo {
public static void main(String[] args) throws IOException {
String str;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
do {
str = br.readLine();
} while (!str.equals("end"));
}
}
运行结果
控制台输出
控制台的输出由 print( ) 和 println() 完成。这些方法都由类 PrintStream 定义,System.out 是该类对象的一个引用。
PrintStream 继承了 OutputStream类,并且实现了方法 write()。这样,write() 也可以用来往控制台写操作。
void write(int byteval)
public class Demo {
public static void main(String[] args) {
int a;
a = 'A';
System.out.write(a);
System.out.write('\n');
}
}
运行结果
读写文件
如前所述,一个流被定义为一个数据序列。输入流用于从源读取数据,输出流用于向目标写数据。
FileInputStream
该流用于从文件读取数据,它的对象可以用关键字 new 来创建。
使用字符串类型的文件名来创建一个输入流对象来读取文件:
InputStream f = new FileInputStream("C:/java/hello");
使用一个文件对象来创建一个输入流对象来读取文件。我们首先得使用 File() 方法来创建一个文件对象:
File f = new File("C:/java/hello");
InputStream out = new FileInputStream(f);
方法 | 描述 |
---|---|
public void close() throws IOException{} | 关闭此文件输入流并释放与此流有关的所有系统资源。抛出IOException异常 |
protected void finalize()throws IOException {} | 这个方法清除与该文件的连接。确保在不再引用文件输入流时调用其 close 方法。抛出IOException异常 |
public int read(int r)throws IOException{} | 这个方法从 InputStream 对象读取指定字节的数据。返回为整数值。返回下一字节数据,如果已经到结尾则返回-1 |
public int read(byte[] r) throws IOException{} | 这个方法从输入流读取r.length长度的字节。返回读取的字节数。如果是文件结尾则返回-1 |
public int available() throws IOException{} | 返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取的字节数。返回一个整数值 |
FileOutputStream
如果该流在打开文件进行输出前,目标文件不存在,那么该流会创建该文件。
使用字符串类型的文件名来创建一个输出流对象:
OutputStream f = new FileOutputStream("C:/java/hello")
也可以使用一个文件对象来创建一个输出流来写文件。我们首先得使用File()方法来创建一个文件对象:
File f = new File("C:/java/hello");
OutputStream f = new FileOutputStream(f);
方法 | 描述 |
---|---|
public void close() throws IOException{} | 关闭此文件输入流并释放与此流有关的所有系统资源。抛出IOException异常 |
protected void finalize()throws IOException {} | 这个方法清除与该文件的连接。确保在不再引用文件输入流时调用其 close 方法。抛出IOException异常 |
public void write(int w)throws IOException{} | 这个方法把指定的字节写到输出流中 |
public void write(byte[] w) | 把指定数组中w.length长度的字节写到OutputStream中 |
Java ByteArrayOutputStream类
字节数组输出流在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中。创建字节数组输出流对象有以下几种方式。
下面的构造方法创建一个32字节(默认大小)的缓冲区。
OutputStream bOut = new ByteArrayOutputStream();
另一个构造方法创建一个大小为n字节的缓冲区。
OutputStream bOut = new ByteArrayOutputStream(int a)
方法 | 描述 |
---|---|
public void reset() | 将此字节数组输出流的 count 字段重置为零,从而丢弃输出流中目前已累积的所有数据输出 |
public byte[] toByteArray() | 创建一个新分配的字节数组。数组的大小和当前输出流的大小,内容是当前输出流的拷贝 |
public String toString() | 将缓冲区的内容转换为字符串,根据平台的默认字符编码将字节转换成字符 |
public void write(int w) | 将指定的字节写入此字节数组输出流 |
public void write(byte []b, int off, int len) | 将指定字节数组中从偏移量 off 开始的 len 个字节写入此字节数组输出流 |
public void writeTo(OutputStream outSt) | 将此字节数组输出流的全部内容写入到指定的输出流参数中 |
Java DataOutputStream类
数据输出流允许应用程序以与机器无关方式将Java基本数据类型写到底层输出流。
下面的构造方法用来创建数据输出流对象。
DataOutputStream out = new DataOutputStream(OutputStream out);
创建对象成功后,可以参照以下列表给出的方法,对流进行写操作或者其他操作。
方法 | 描述 |
---|---|
public final void write(byte[] w, int off, int len)throws IOException | 将指定字节数组中从偏移量 off 开始的 len 个字节写入此字节数组输出流 |
Public final int write(byte [] b)throws IOException | 将指定的字节写入此字节数组输出流。 |
public final void writeBooolean()throws IOException public final void writeByte()throws IOException public final void writeShort()throws IOException public final void writeInt()throws IOException | 这些方法将指定的基本数据类型以字节的方式写入到输出流 |
Public void flush()throws IOException | 刷新此输出流并强制写出所有缓冲的输出字节 |
public final void writeBytes(String s) throws IOException | 将字符串以字节序列写入到底层的输出流,字符串中每个字符都按顺序写入,并丢弃其高八位 |
文件和I/O
Java File类
Java文件类以抽象的方式代表文件名和目录路径名。该类主要用于文件和目录的创建、文件的查找和文件的删除等。
File对象代表磁盘中实际存在的文件和目录。通过以下构造方法创建一个File对象。
通过给定的父抽象路径名和子路径名字符串创建一个新的File实例。
File(File parent, String child);
通过将给定路径名字符串转换成抽象路径名来创建一个新 File 实例。
File(String pathname)
根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。
File(String parent, String child)
通过将给定的 file: URI 转换成一个抽象路径名来创建一个新的 File 实例。
File(URI uri)
创建File对象成功后,可以使用以下列表中的方法操作文件。
方法 | 描述 |
---|---|
public String getName() | 返回由此抽象路径名表示的文件或目录的名称 |
public String getParent() | 返回此抽象路径名的父路径名的路径名字符串,如果此路径名没有指定父目录,则返回 null |
public File getParentFile() | 返回此抽象路径名的父路径名的抽象路径名,如果此路径名没有指定父目录,则返回 null |
public String getPath() | 将此抽象路径名转换为一个路径名字符串 |
public boolean isAbsolute() | 测试此抽象路径名是否为绝对路径名 |
public String getAbsolutePath() | 返回抽象路径名的绝对路径名字符串 |
public boolean canRead() | 测试应用程序是否可以读取此抽象路径名表示的文件 |
public boolean canWrite() | 测试应用程序是否可以修改此抽象路径名表示的文件 |
public boolean exists() | 测试此抽象路径名表示的文件或目录是否存在 |
public boolean isDirectory() | 测试此抽象路径名表示的文件是否是一个目录 |
public boolean isFile() | 测试此抽象路径名表示的文件是否是一个标准文件 |
public long lastModified() | 返回此抽象路径名表示的文件最后一次被修改的时间 |
public long length()返回由此抽象路径名表示的文件的长度。 | |
public boolean createNewFile() throws IOException | 当且仅当不存在具有此抽象路径名指定的名称的文件时,原子地创建由此抽象路径名指定的一个新的空文件 |
public boolean delete() | 删除此抽象路径名表示的文件或目录 |
public void deleteOnExit() | 在虚拟机终止时,请求删除此抽象路径名表示的文件或目录 |
public String[] list() | 返回由此抽象路径名所表示的目录中的文件和目录的名称所组成字符串数组 |
public String[] list(FilenameFilter filter) | 返回由包含在目录中的文件和目录的名称所组成的字符串数组,这一目录是通过满足指定过滤器的抽象路径名来表示的 |
public File[] listFiles() | 返回一个抽象路径名数组,这些路径名表示此抽象路径名所表示目录中的文件 |
public File[] listFiles(FileFilter filter) | 返回表示此抽象路径名所表示目录中的文件和目录的抽象路径名数组,这些路径名满足特定过滤器 |
public boolean mkdir() | 创建此抽象路径名指定的目录 |
public boolean mkdirs() | 创建此抽象路径名指定的目录,包括创建必需但不存在的父目录 |
public boolean renameTo(File dest) | 重新命名此抽象路径名表示的文件 |
public boolean setLastModified(long time) | 设置由此抽象路径名所指定的文件或目录的最后一次修改时间 |
public boolean setReadOnly() | 标记此抽象路径名指定的文件或目录,以便只可对其进行读操作 |
public static File createTempFile(String prefix, String suffix, File directory) throws IOException | 在指定目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称 |
public static File createTempFile(String prefix, String suffix) throws IOException | 在默认临时文件目录中创建一个空文件,使用给定前缀和后缀生成其名称 |
public int compareTo(File pathname) | 按字母顺序比较两个抽象路径名 |
public int compareTo(Object o) | 按字母顺序比较抽象路径名与给定对象 |
public boolean equals(Object obj) | 测试此抽象路径名与给定对象是否相等 |
public String toString() | 返回此抽象路径名的路径名字符串 |
Java FileReader类
FileReader类从InputStreamReader类继承而来。该类按字符读取流中数据。可以通过以下几种构造方法创建需要的对象。
在给定从中读取数据的 File 的情况下创建一个新 FileReader。
FileReader(File file)
在给定从中读取数据的 FileDescriptor 的情况下创建一个新 FileReader。
FileReader(FileDescriptor fd)
在给定从中读取数据的文件名的情况下创建一个新 FileReader。
FileReader(String fileName)
创建FIleReader对象成功后,可以参照以下列表里的方法操作文件。
方法 | 描述 |
---|---|
public int read() throws IOException | 读取单个字符,返回一个int型变量代表读取到的字符 |
public int read(char [] c, int offset, int len) | 读取字符到c数组,返回读取到字符的个数 |
Java FileWriter类
FileWriter 类从 OutputStreamWriter 类继承而来。该类按字符向流中写入数据。可以通过以下几种构造方法创建需要的对象。
在给出 File 对象的情况下构造一个 FileWriter 对象。
FileWriter(File file)
在给出 File 对象的情况下构造一个 FileWriter 对象。
FileWriter(File file, boolean append)
参数:
- file:要写入数据的 File 对象。
- append:如果 append 参数为 true,则将字节写入文件末尾处,相当于追加信息。如果 append 参数为 false,
则写入文件开始处。
构造与某个文件描述符相关联的 FileWriter 对象。
FileWriter(FileDescriptor fd)
在给出文件名的情况下构造 FileWriter 对象,它具有指示是否挂起写入数据的 boolean 值。
FileWriter(String fileName, boolean append)
创建FileWriter对象成功后,可以参照以下列表里的方法操作文件。
方法 | 描述 |
---|---|
public void write(int c) throws IOException | 写入单个字符c。 |
public void write(char [] c, int offset, int len) | 写入字符数组中开始为offset长度为len的某一部分 |
public void write(String s, int offset, int len) | 写入字符串中开始为offset长度为len的某一部分 |
Java中的目录
创建目录
File类中有两个方法可以用来创建文件夹:
- mkdir()方法创建一个文件夹,成功则返回true,失败则返回false。失败表明File对象指定的路径已经存在,或者由于整个路径还不存在,该文件夹不能被创建。
- mkdirs()方法创建一个文件夹和它的所有父文件夹。
import java.io.File;
public class Demo {
public static void main(String[] args) {
String dirname = "C/IDea/java/bin";
File d = new File(dirname);
d.mkdirs();
}
}
读取目录
一个目录其实就是一个 File 对象,它包含其他文件和文件夹。
如果创建一个 File 对象并且它是一个目录,那么调用 isDirectory() 方法会返回 true。
可以通过调用该对象上的 list() 方法,来提取它包含的文件和文件夹的列表。
import java.io.File;
public class DirList {
public static void main(String args[]) {
String dirname = "/tmp";
File f1 = new File(dirname);
if (f1.isDirectory()) {
System.out.println("目录 " + dirname);
String s[] = f1.list();
for (int i = 0; i < s.length; i++) {
File f = new File(dirname + "/" + s[i]);
if (f.isDirectory()) {
System.out.println(s[i] + " 是一个目录");
} else {
System.out.println(s[i] + " 是一个文件");
}
}
} else {
System.out.println(dirname + " 不是一个目录");
}
}
}
删除目录或文件
删除文件可以使用 java.io.File.delete() 方法。
以下代码会删除目录 /tmp/java/,需要注意的是当删除某一目录时,必须保证该目录下没有其他文件才能正确删除,否则将删除失败。
import java.io.File;
public class DeleteFileDemo {
public static void main(String args[]) {
File folder = new File("/tmp/java/");
deleteFolder(folder);
}
// 删除文件及目录
public static void deleteFolder(File folder) {
File[] files = folder.listFiles();
if (files != null) {
for (File f : files) {
if (f.isDirectory()) {
deleteFolder(f);
} else {
f.delete();
}
}
}
folder.delete();
}
}
Java Scanner 类
Scanner s = new Scanner(System.in);
Scanner 类的 next() 与 nextLine() 方法获取输入的字符串,在读取前我们一般需要 使用 hasNext 与 hasNextLine 判断是否还有输入的数据
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("next方式接收:");
if (scan.hasNext()) {
String str = scan.next();
System.out.println("输入的数据为:" + str);
}
}
}
运行结果
使用 nextLine 方法
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("nextline方式接收:");
if (scan.hasNextLine()) {
String str = scan.nextLine();
System.out.println("输入的数据为:" + str);
}
}
}
运行结果
next() 与 nextLine() 区别
next():
- 一定要读取到有效字符后才可以结束输入。
- 对输入有效字符之前遇到的空白,next() 方法会自动将其去掉。
- 只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
- next() 不能得到带有空格的字符串。
nextLine():
- 以Enter为结束符,也就是说 nextLine()方法返回的是输入回车之前的所有字符。
- 可以获得空白。
如果要输入 int 或 float 类型的数据,在 Scanner 类中也有支持,但是在输入之前最好先使用 hasNextXxx() 方法进行验证,再使用 nextXxx() 来读取
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int a = 0;
System.out.println("输入整数:");
// 判断整数
if (scan.hasNextInt()) {
a = scan.nextInt();
System.out.println("整数:" + a);
} else {
System.out.println("输入的不是整数");
}
}
}
Java 异常处理
异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。
三种类型的异常:
- 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
- 运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
- 错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
Exception 类的层次
所有的异常类是从 java.lang.Exception 类继承的子类。Exception 类是 Throwable 类的子类。除了Exception类外,Throwable还有一个子类Error 。Java 程序通常不捕获错误。错误一般发生在严重故障时,它们在Java程序处理的范畴之外。Error 用来指示运行时环境发生的错误。
例如,JVM 内存溢出。一般地,程序不会从错误中恢复。
异常类有两个主要的子类:IOException 类和 RuntimeException 类。
Java 内置异常类
Java 语言定义了一些异常类在 java.lang 标准包中。
标准运行时异常类的子类是最常见的异常类。由于 java.lang 包是默认加载到所有的 Java 程序的,所以大部分从运行时异常类继承而来的异常都可以直接使用。
Java 的非检查性异常
异常 | 描述 |
---|---|
ArithmeticException | 当出现异常的运算条件时,抛出此异常。例如,一个整数"除以零"时,抛出此类的一个实例。 |
ArrayIndexOutOfBoundsException | 用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。 |
ArrayStoreException | 试图将错误类型的对象存储到一个对象数组时抛出的异常。 |
ClassCastException | 当试图将对象强制转换为不是实例的子类时,抛出该异常。 |
IllegalArgumentException | 抛出的异常表明向方法传递了一个不合法或不正确的参数。 |
IllegalMonitorStateException | 抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。 |
IllegalStateException | 在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。 |
IllegalThreadStateException | 线程没有处于请求操作所要求的适当状态时抛出的异常。 |
IndexOutOfBoundsException | 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。 |
NegativeArraySizeException | 如果应用程序试图创建大小为负的数组,则抛出该异常。 |
NullPointerException | 当应用程序试图在需要对象的地方使用 null 时,抛出该异常 |
NumberFormatException | 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。 |
SecurityException | 由安全管理器抛出的异常,指示存在安全侵犯。 |
StringIndexOutOfBoundsException | 此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小。 |
UnsupportedOperationException | 当不支持请求的操作时,抛出该异常。 |
java.lang 包中的检查性异常类。
异常 | 描述 |
---|---|
ClassNotFoundException | 应用程序试图加载类时,找不到相应的类,抛出该异常 |
CloneNotSupportedException | 当调用 Object 类中的 clone 方法克隆对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。 |
IllegalAccessException | 拒绝访问一个类的时候,抛出该异常。 |
InstantiationException | 当试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象因为是一个接口或是一个抽象类而无法实例化时,抛出该异常。 |
InterruptedException | 一个线程被另一个线程中断,抛出该异常。 |
NoSuchFieldException | 请求的变量不存在 |
NoSuchMethodException | 请求的方法不存在 |
异常方法
Throwable 类的主要方法:
方法 | 说明 |
---|---|
public String getMessage() | 返回关于发生的异常的详细信息。这个消息在Throwable 类的构造函数中初始化了 |
public Throwable getCause() | 返回一个Throwable 对象代表异常原因。 |
public String toString() | 使用getMessage()的结果返回类的串级名字 |
public void printStackTrace() | 打印toString()结果和栈层次到System.err,即错误输出流。 |
public StackTraceElement [] getStackTrace() | 返回一个包含堆栈层次的数组。下标为0的元素代表栈顶,最后一个元素代表方法调用堆栈的栈底 |
public Throwable fillInStackTrace() | 用当前的调用栈层次填充Throwable 对象栈层次,添加到栈层次任何先前信息中 |
捕获异常
使用 try 和 catch 关键字可以捕获异常。try/catch 代码块放在异常可能发生的地方。try/catch代码块中的代码称为保护代码,使用 try/catch 的语法如下:
try
{
// 程序代码
}catch(ExceptionName e1)
{
//Catch 块
}
Catch 语句包含要捕获异常类型的声明。当保护代码块中发生一个异常时,try 后面的 catch 块就会被检查。如果发生的异常包含在 catch 块中,异常会被传递到该 catch 块,这和传递一个参数到方法是一样。
多重捕获块
一个 try 代码块后面跟随多个 catch 代码块的情况就叫多重捕获。可以在 try 语句后面添加任意数量的 catch 块。
如果保护代码中发生异常,异常被抛给第一个 catch 块。如果抛出异常的数据类型与 ExceptionType1 匹配,它在这里就会被捕获。如果不匹配,它会被传递给第二个 catch 块。如此,直到异常被捕获或者通过所有的 catch 块。
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}
hrows/throw 关键字
如果一个方法没有捕获到一个检查性异常,那么该方法必须使用 throws 关键字来声明。throws 关键字放在方法签名的尾部。也可以使用 throw 关键字抛出一个异常,无论它是新实例化的还是刚捕获到的。
import java.io.*;
public class className
{
public void deposit(double amount) throws RemoteException
{
// Method implementation
throw new RemoteException();
}
//Remainder of class definition
}
一个方法可以声明抛出多个异常,多个异常之间用逗号隔开。
finally关键字
finally 关键字用来创建在 try 代码块后面执行的代码块。
无论是否发生异常,finally 代码块中的代码总会被执行。
在 finally 代码块中,可以运行清理类型等收尾善后性质的语句。
finally 代码块出现在 catch 代码块最后,语法如下:
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}finally{
// 程序代码
}
注意:
- catch 不能独立于 try 存在。
- 在 try/catch 后面添加 finally 块并非强制性要求的。
- try 代码后不能既没 catch 块也没 finally 块。
- try, catch, finally 块之间不能添加任何代码。
声明自定义异常
在 Java 中你可以自定义异常。编写自己的异常类时需要记住下面的几点。
- 所有异常都必须是 Throwable 的子类。
- 如果希望写一个检查性异常类,则需要继承 Exception 类。
- 如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。
可以像下面这样定义自己的异常类:
class MyException extends Exception{
}
只继承Exception 类来创建的异常类是检查性异常类。下面的 InsufficientFundsException 类是用户定义的异常类,它继承自 Exception。一个异常类和其它任何类一样,包含有变量和方法。
通用异常
在Java中定义了两种类型的异常和错误。
- JVM(Java虚拟机) 异常:由 JVM 抛出的异常或错误。例如:NullPointerException
类,ArrayIndexOutOfBoundsException 类,ClassCastException 类。 - 程序级异常:由程序或者API程序抛出的异常。例如 IllegalArgumentException
类,IllegalStateException 类。