Java基础语法
对象、类、方法、实例变量
一个 Java 程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作
- 对象:对象是类的一个实例,有状态和行为
- 类:类是一个模板,它描述一类对象的行为和状态
- 方法:方法就是行为,一个类可以有很多方法
- 实例变量:每个对象都有独特的实例变量,对象的状态由这些实例变量的值决定
变量
- 局部变量
- 类变量(静态变量)
- 成员变量(非静态变量)
基本语法
编写 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枚举
枚举限制变量只能是预先设定好的值。使用枚举可以减少代码中的 bug。 枚举可以单独声明或者声明在类里面。方法、变量、构造函数也可以在枚举中定义。
java 关键字
关键字不能用于常量、变量、和任何标识符的名称。
- 访问控制
- private 私有的
- protected 受保护的
- public 公共的
- default 默认
- 类、方法和变量修饰符
- abstract 声明抽象
- class 类
- extends 扩充,继承
- final 最终值,不可改变的
- implements 实现(接口)
- interface 接口
- native 本地,原生方法(非 Java 实现)
- new 新,创建
- static 静态
- strictfp 严格,精准
- synchronized 线程,同步
- transient 短暂
- volatile 易失
- 程序控制语句
- 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 是关键字,但不能使用 Java 的 null 不是关键字,类似于 true 和 false,它是一个字面常量,不允许作为标识符使用。
继承
在 Java 中,一个类可以由其他类派生。如果你要创建一个类,而且已经存在一个类具有你所需要的属性或方法,那么你可以将新创建的类继承该类。
利用继承的方法,可以重用已存在类的方法和属性,而不用重写这些代码。被继承的类称为超类(super class),派生类称为子类(subclass)。
接口
在 Java 中,接口可理解为对象间相互通信的协议。接口在继承中扮演着很重要的角色。 接口只定义派生要用到的方法,但是方法的具体实现完全取决于派生类。
对象和类
java 面向对象
Java作为一种面向对象语言。支持以下基本概念:
- 多态
- 继承
- 封装
- 抽象
- 类
- 对象
- 实例
- 方法
- 重载
对象和类的概念
- 对象:对象是类的一个实例,有状态和行为
- 类:类是一个模板,它描述一类对象的行为和状态 对象的状态就是属性,行为通过方法体现。 方法操作对象内部状态的改变,对象的相互调用也是通过方法来完成。
一个类可以包含以下类型变量:
- 局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
- 成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
- 类变量:类变量也声明在类中,方法体之外,但必须声明为 static 类型。 一个类可以拥有多个方法。
构造方法
每个类都有构造方法,如果没有显式地为类定义构造方法,java编译器会为该类提供一个默认构造方法。在创建一个对象的时候,至少要调用一个构造方法。构造方法的名称必须与类同名,一个类可以有多个构造方法。
创建对象
对象是根据类创建的。在Java中,使用关键字new来创建一个新的对象,创建对象需要以下三步:
- 声明:声明一个对象,包括对象名称和对象类型。
- 实例化:使用关键字new 来创建一个对象。
- 初始化:使用new 创建对象时,会调用构造方法初始化对象
源文件声明规则
当在一个源文件中定义多个类,并且还有import语句和packeage语句时,要特别注意这些规则
- 一个源文件中只能有一个public类
- 一个源文件可以有多个非public类
- 源文件的名称应该和public类的类名保持一致。例如:源文件中public类的类名是Employee,那么源文件应该命名为Employee.java
- 如果一个类定义在某个包中,那么package语句应该在源文件的首行。
- 如果源文件包含import语句,那么应该放在packet语句和类定义之间,如果没有package 语句,那么import语句应该在源文件中最前面。
- import语句和package语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明。
包
包主要用来对类和接口进行分类。
import语句
在java中,如果给出一个完整的限定名,包括包名、类名,那么java编译器就可以很容易地定位到源代码或者类。import 语句就是用来提供提供一个合理的路径,是的编译器可以找到某个类
基本数据类型
当创建变量的时候,需要在内存中申请空间。 内存管理系统根据变量的类型为变量分配存储空间,分配的空间只能用来存储该类型数据。 因此,通过定义不同类型的变量,可以在内存中储存整数、小数或者字符。 java的两大数据类型:
- 内置数据类型
- 引用数据类型
内置数据类型
java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。 byte:
- byte数据类型是8位,有符号的,以二进制补码表示的整数;
- 最大值是 -128 (-2^7)
- 最大值是 127 (2^7-1)
- 默认值是 0
- byte类型在大型数组中节约空间,主要代替整数,因为byte变量所占的空间只有int类型的四分之一
- 例子:byte a = 100; byte b = -50;
short:
- short 数据类型是16位,有符号的,以二进制补码表示的整数
- 最小值是 -32768(-2^15);
- 最大值是 32767(2^15 - 1)
- short数据类型也可以向byte那样节省空间,一个short变量是int变量所占空间的二分之一
- 默认值是 0
- 例子: short s = 1000; short r = -20000;
int:
- int数据类型是32位,有符号的,以二进制补码表示的整数;
- 最小值是 -2,147,483,648(-2^31);
- 最大值是 2,147,483,647(2^31 - 1);
- 一般的整型变量默认为int类型;
- 默认值为 0;
- 例子:int a = 100000;int b = -2000000;
long:
- long数据类型是64位、有符号的,以二进制补码表示的整数
- 最小值是 -9,223,372,036,854,775,808(-2^63);
- 最大值是 9,223,372,036,854,775,807(2^63 -1);
- 这种类型主要使用在需要比较大整数的系统上;
- 默认值是 0L;
- 例子:long a = 100000L; Long b = -2000000L。 "L"理论上不分大小写,但是小写的"l"与数字"1"容易混淆,所以最好使用大写
float:
- float数据类型是单精度、32位、符合IEEE 754标准的浮点数;
- float在储存大型浮点数组的时候可以节省内存空间;
- 默认值是0.0f
- 浮点数不能用来表示精确的值,如货币;
- 例子:float f1 = 234.5f
double:
- double数据类型是双精度、64位、符合IEEE 754标准的浮点数;
- 浮点数的默认类型是double类型;
- double类型同样不能表示精确的值,如货币;
- 默认值是 0.0d
- 例子:double d1 = 7D; double d2 = 7.; double d3 = 8.0; double d4 = 8.D; double d5 = 12.9867;
boolean:
- boolean 数据类型表示一位的信息;
- 只有两个取值:true 和 false;
- 这种类型只作为一致标志来记录true/false情况;
- 默认值是 false;
- 例子:boolean one = true;
char:
- char类型是一个单一的16位Unicode字符;
- 最小值是 \u0000(十进制等效值为 0);
- 最大值是 \uffff(即为 65535);
- char数据类型可以储存任何字符;
- 例子: char latter='A';
对于数据类型的基本类型的取值范围,无需强制去记忆,因为他们的值已经以 常量的影响是定义在对应的包装类中了。 byte的包装类:java.lang.Byte short的包装类:java.lang.Short int的包装类:java.lang.Integer long的包装类:java.lang.Long float的包装类:java.lang.Float double的包装类:java.lang.Double boolean的包装类:java.lang.Bool char的包装类:java.lang.Character
Float和Double的最小值和最大子都是以科学计数法的形式输出的,结尾的"E+数字"表示E之前的数字要乘以10的多少次方,比如 3.14E3就是3.14 × 103 =3140,3.14E-3 就是 3.14 x 10-3 =0.00314。 实际上java中还存在另外一种基本类型void,它也有对应的包装类java.lang.Void,不过我们无法直接对他们进行操作
类型默认值: byte:0 short:0 int:0 long:0L float:0.0f doubleL0.0 char:'u0000' boolean:false String(or any obkect):null
引用类型
- 在java中,引用类型的变量非常类似于c/c++的指针。引用类型指向一个对象,指向对象的变量是引用变量。这些变量在声明是被指定为一个特定的类型,比如Employee,Puppy等。变量一旦声明后,类型就不能被改变了。
- 对象、数组都是引用数据类型
- 所以引用类型的默认值都是null
- 一个引用变量可以用来引用任何与之兼容的类型。
- 例子:Site site = new Site("Runoob");
java常量
常量在程序运行时是不能被修改的。 在Java中使用final关键字来修饰常量,声明方式和变量类似: final double PI = 3.1415927; 虽然常量名也可以用小写,但是为了便于识别,通常使用大写字母表示。 常量可以赋值给任何内置类型的变量。 byte、short、int、long都可以用十进制、16尽早以及8进制的方式表示 前缀0表示8进制,前缀0x代表16进制 int decimal = 100; int octal = 0144; int hexa = 0x64; java的字符串常量也是包含在两个引号之间的字符序列。下面是字符串常量的例子: "Hello World" "two\nlines" ""This is in quotes"" 字符串常量和字符常量都可以包含任何Unicode字符。例如: char a = '\u0001'; String a = "\u0001";
转义字符
\n 换行 \r 回车 \f 换页符 \b 退格 \0 空字符 \s 空格 \t 制表符 " 双引号 ' 单引号 \ 反斜杠 \ddd 八进制字符 \uxxxx 16进制Unicode字符
自动类型转换
整型、实型(常量)、字符型数据可以混合运算。运算中,不同类型的数据先转化为同一类型,然后进行运算。 转换从低级到高级: 低-->高 byte,short,char -> int -> long -> float -> double 数据类型转换必须满足如下规则:
- 不能对boolean类型进行类型转换
- 不能把对象类型转换成不相关类的对象
- 在把容量大的类型转换为容量小的类型时必须使用强制类型转换
- 转换过程中可能导致溢出或损失精度,例如 int i = 128; byte b = (byte) i; 因为byte类型是8位,最大值为127,所以当interesting强制转换为byte类型时,值128就会导致溢出。
- 浮点数到整数的转换是通过舍弃小数得到,而不是四舍五入,例如 (int)23.7 == 23; (int) -45.89f == -45;
自动类型转换
必须满足转换前的数据类型的位数要低于转换后的数据类型,例如:short数据类型的位数为16位,就可以自动转换为32的int类型,同样float数据类型的位数为32,库自动转换为64位的double类型。 char可以自动类型转换为int
强制类型转换
- 条件是转换的数据类型必须是兼容的
- 格式:(type)value, type是要强制类型转换后的数据类型 可以把int强制类型转换成byte
隐含强制类型转换
- 整数的默认类型是int
- 小数默认是double类型浮点数,在定义float类型时必须子啊数字后面跟上F或者f
Java变量类型
在java语言中,所有的变量在使用前必须声明。声明变量的基本格式如下: type identifier [ = value][,identifier [=value] ...]; 格式说明,type为java数据类型,identifier是变量名。可以使用都会隔开来声明多个同类型变量。 Java语言支持的变量类型有:
- 类变量:独立于方法之外的变量,用static修饰
- 实例变量:独立于方法 之外的变量,不过没有static修饰
- 局部变量:类的方法中的变量
Java局部变量
- 局部变量声明在方法、构造方法或者语句块中;
- 局部变量在方法、构造方法、或者与健康被执行的时候创建,当它们执行完成后,变量会被销毁;
- 访问修饰符不能用于局部变量
- 局部变量只在声明它的方法、构造方法或语句块中可见;
- 局部变量是在栈上分配的
- 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用
实例变量
- 实例变量声明在一个类中,但在方法、构造方法和语句块之外;
- 当一个对象被实例化之后,每个实例变量的值就跟着确定;
- 实例变量在对象创建的时候创建,在对象被销毁的时候销毁
- 实例变量的值至少被一个方法、构造方法、或者语句块引用,使得外部能够通过这些方式获得实例变量信息;
- 实例变量可以声明在使用前或者使用后;
- 访问修饰符可以修饰实例变量
- 实例变量对于类中的方法、构造方法或语句块是可见。一般情况下应该把实例变量设为私有。 通过使用访问修饰符可以使实例变量对子类可见;
- 实例变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的默认值是null。变量的值可以在声明时指定,也可以在构造方法中指定。
- 实例变量可以直接通过变量名访问。但在静态方法以及其他类中,就应该使用完全限定名:ObjectRence VariableName
类变量(静态变量)
- 类变量也称为静态变量,在类中以static关键字声明,但必须在方法之外
- 无论一个类创建了多傻瓜对象,类只拥有类变量的一份拷贝
- 静态变量除了被声明为常量外很少使用,静态变量是指声明为public/private,final和static类型的变量。静态变量初始化后不可改变。
- 静态变量储存在静态存储区。经常被声明为常量,很少单独使用static声明变量
- 静态变量在第一次被访问时常见,在程序结束时销毁。
- 于实例变量具有相似的可见性。但为了对类的使用者可见,大多数静态变量声明为pulic类型;
- 默认值和实例变量相似。数值型变量默认值是0,布尔型默认值是false,引用类型默认值是null。变量的值可以在声明的时候指定,也可以在构造方法中指定。此外,静态变量还可以在静态语句块中初始化。
- 静态变量可以通过:ClassName.VariableName的方式访问。
- 类变量被声明为public static final 类型时,类变量名一边建议使用大写字母。如果静态变量不是public和final类型,其命名方式与实例变量和局部变量的命名方式一致。
java 修饰符
Java语言提供了很多修饰符,主要分为以下两类:
- 访问修饰符
- 非访问修饰符 访问修饰符用来定义类、方法或者变量,通常放在语句的最前端。
访问控制修饰符
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。 Java支持4中不同的访问权限:
- default(即默认,什么也不写):在同一包内可见,不适应任何修饰符。使用对象:类、接口、变量、方法
- private:在同一类内可见。使用对象:变量、方法。注意:不能修饰类(外部类)
- public:对所有类可见。使用对象:类、接口、变量、方法
- protected:对同一包内的类和所有子类可见。使用对象:变量、方法。注意:不能修饰类(外部类)。
| 修饰符 | 当前类 | 同一包内 | 子孙类(同一包) | 子孙类(不同包) | 其他包 |
|---|---|---|---|---|---|
public | Y | Y | Y | Y | Y |
protected | Y | Y | Y | Y/N | N |
default | Y | Y | Y | N | N |
private | Y | N | N | N | N |
默认访问修饰符-不适应任何关键字
使用默认访问修饰符声明的变量和方法,对同一个包内的类是可见的。接口里的变量都隐式声明为 public static final,而接口里的方法默认情况下访问权限为public
私有访问修饰符-private
私有访问修饰符是最严格的访问级别,所有被声明为private的方法、变量和构造方法只能被所属类访问,并且类和接口不能声明为private。 声明为私有访问类型的变量只能通过类中公共的getter方法被外部类访问。 private访问修饰符的使用主要用来因此类的实现细节和保护类的数据。
公有有访问修饰符-public
被声明为public的类、方法、构造方法和接口都能够被任何其他类访问。 如果几个相互访问的public类分布在不同的包中,则需要导入相应public类所占的包。由于类的继承性,类的所有公寓方法和变量都能被其子类继承。 Java程序的main()必须设置成公有的,赋值Java解释器将不能运行该类
受保护的访问修饰符-protected
protected需要从以下两个点来分析说明:
- 子类与基类(父类)在同一包中:被声明为protected的变量、方法和构造方法能够被同一包中的任何其他类访问;
- 子类与基类(父类)不在同一包中:那么在子类中,子类实例可以访问其从基类继承而来的protected方法,而不能访问基类实例的protected方法。 protected可以修饰数据成员、构造方法、方法成员,不能修饰类(内部类除外)。 接口以及接口的成员变量和成员方法不能声明为protected。 子类能访问protected修饰符声明的方法和变量,这样就能保护不相关的类使用这些方法和变量。 如果我们指向让该方法对其所在类的子类可见,则将该方法声明为protected。
访问控制和继承
请注意以下方法继承的规则:
- 父类中声明为public的方法在子类中也必须为public
- 父类中声明为protected的方法在子类在要么声明为protected要么声明为public,不能声明为private。
- 父类中声明为private的方法,不能被子类继承
非访问修饰符
static修饰符,可以修饰类方法和类变量; final修饰符,可以用来修饰类、方法和变量,final修饰的类不能被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可更改的。 abstract修饰符,用来创建抽象类和抽象方法。 synchronized和valatile修饰符,主要用于线程的编程。
static修饰符
- 静态变量:static关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。静态变量也被称为类变量。局部变量不能声明为static变量。
- 静态方法:static关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。 对类对象(静态变量)和静态方法的访问可以直接使用classname.variabelname和classname.methodname的方式访问。
final修饰符
- final变量:final表示"最后的、最终的"换域,变量一旦赋值后,不能重新赋值。被final修饰的实例变量必须显示指定初始值。 final修饰符通常和static修饰符一起使用来常见类常量。
- final方法 父类在的final方法可以被子类继承,但是不能被子类重写。 声明final方法的主要目的是防止该方法的内容被修改。
- final类 final类不能被继承,没有类能够继承final类的任何特性
abstract修饰符
抽象类:抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该该类进行扩充。 一个类不能同时被abstract和final修饰,如果一个类包含抽象方法,那该类一定要声明为抽象类,否则将出现编译错误。 抽象类可以包含抽象方法和非抽象方法。 抽象方法:抽象方法是一种没有任何实现的发,还方法的具体实现由子类提供。 抽象方法不能被声明成final和static。 任何继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类。 如果一个类包含若干个抽象方法,那么该类必须声明为抽象类。抽象类可以不包含抽象方法。 抽象方法的声明以分号结尾,例如:public abstact sample();
synchronized修饰符
synchronized关键字声明方法同一时间只能被一个线程访问。synchronized修饰符可以应用于四个访问修饰符。例如:public synchronized void showEdtails(){}
transient修饰符
序列化的对象包含被transient修饰的实例变量时,Java虚拟机(jvm)跳过该特定的变量。 该修饰符包含在定义变量的语句中,用来预处理类和变量的数据类型。 例如:public transient int limit = 55; //不会持久化 public int b; //持久化
volatile修饰符
volatile修饰的成员变量每次在被线程访问时,都强制从共享内存中抽象读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。 一个volatile对象引用可能是null; 例如:
public class MyRunale implements Runable
{
private volatile boolean active;
public void run(){
activie = true;
while(active){//第一行
//
}
}
public void stop(){
active = false;//第二行
}
}
通常情况下,在一个相乘调用run()方法(在Runnable开启的线程),在另外一个线程调用stop()方法。如果第一行中缓冲区的active值被使用,那么在第二行的active值为false时循环不会停止
Java运算符
可以把运算符分成以下几组:
- 算术运算符
- 关系运算符
- 位运算符
- 逻辑运算符
- 赋值运算符
- 其他运算符
算术运算符
- :加法
- :减法
- :乘法 / :除法 % :取余 余数 ++ :自增 -- :自减
自增自减运算符
- 自增(++)自减(--)运算发是一种特殊的算术运算发,在算术运算发中虚脱两个操作数来进行运算,而自增自减运算发是一个操作数。
- 前缀自增自减法(++a,--a):先进行自增或自减运算,再进行表达式运算。
- 后缀自增自减法(a++,a--):先进行表达式运算,再进行自增或自减运算。
关系运算符
== 检查两个操作数的值是否相等,如果相对则条件为真。 != 检查两个操作数的值是否相关,如果值不相等则条件为真 > 检查左操作数的值是否大于右操作数的值,如果是则条件为真 < 检查左操作数的值是否小于右操作数的值,如果是则条件为真 >= 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真 <= 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真
位运算符
& 如果相对应位都是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
逻辑运算符
&& 称为逻辑与运算符。当且仅当两个操作数都为真,条件才为真。(A && B)为假。
|| 称为逻辑或操作符。如果任何两个操作数任何一个为真,条件为真。(A | | B)为真。
! 称为逻辑非运算符。用来反转操作数的逻辑状态。如果条件为true,则逻辑非运算符将得到false。 !(A && B)为真。
短路逻辑运算符
当使用与逻辑运算发时,当两个操作数都为true时,结果才为true,但是当得到第一个操作为false时,其结果必定是false,这时候就不会判断第二个操作了
赋值运算符
= 简单的赋值运算符,将右操作数的值赋给左侧操作数
+= 加和赋值操作符,它把左操作数和右操作数相加赋值给左操作数
-= 减和赋值操作符,它把左操作数和右操作数相减赋值给左操作数
*= 乘和赋值操作符,它把左操作数和右操作数相乘赋值给左操作数
/= 除和赋值操作符,它把左操作数和右操作数相除赋值给左操作数
(%)= 取模和赋值操作符,它把左操作数和右操作数取模后赋值给左操作数
>>= 右移位赋值运算符
&= 按位与赋值运算符
^= 按位异或赋值操作符
= 按位或赋值操作符
条件运算符 ?:
条件运算符也称为三元运算符。该运算的有3个操作数,并且需要判断布尔表达式的值。该运算符的主要是决定哪个值应该赋值给变量。
vaiable x = (expression) ? value if true : value if false
instanceof 运算符
该运算符用于操作对象实例,检查该对象是否是一个特定类型(类类型或接口类型) instanceof运算符使用格式如下: (Object reference variable) instanceof (class/interface type) 如果运算符左侧变量所在的对象,是操作符右侧类或接口(class/interface)的一个对象,那么结果为真。 如果被比较的对象兼容于右侧类型,该运算符仍然返回true。
Java运算的优先级
下表中具有最高优先级的运算符在的表的最上面,最低优先级的在表的底部。
| 类别 | 操作符 | 关联性 | ||
|---|---|---|---|---|
| 后缀 | () [] . (点操作符) | 左到右 | ||
| 一元 | expr++ expr-- | 从左到右 | ||
| 一元 | ++expr --expr + - ~ ! | 从右到左 | ||
| 乘性 | * /% | 左到右 | ||
| 加性 | + - | 左到右 | ||
| 移位 | >> >>> << | 左到右 | ||
| 关系 | > >= < <= | 左到右 | ||
| 相等 | == != | 左到右 | ||
| 按位与 | & | 左到右 | ||
| 按位异或 | 左到右 | |||
| 按位或 | 左到右 | |||
| 逻辑与 | && | 左到右 | ||
| 逻辑或 | 左到右 | |||
| 条件 | ?: | 从右到左 | ||
| 赋值 | = + = - = * = / =%= >> = << =&= ^ = | = | 从右到左 | |
| 逗号 | , | 左到右 |
java循环结构
java中有三种主要的循环结构:
- while循环
- do...while循环
- for循环
while循环
while是最基本的循环,它的结构为:
while(布尔表达式){
//循环内容
}
只要布尔表达式为true,循环就会一直执行下去
do...while循环
对于while语句而言,如果不满足条件,则不能进入循环。但有时候我们需要即使不满足条件,也至少执行一次。 do...while循环和while循环相似,不同的是,do...while循环至少会执行一次
do{
//代码语句
} while(布尔表达式);
注意:布尔表达式在循环体的后面,所以语句块在检测布尔表达式之前已经执行了。如果布尔表达式的值为true,则语句块一直执行,直到布尔表达式的值为false。
for循环
for循环执行的次数是在执行前就确定的,语法格式如下:
for(初始化;布尔表达式;更新){
//代码语句
}
关于for循环有以下几点说明:
- 最先执行初始化步骤。可以声明一种类型,但可初始化一个或多个循环控制变量,也可以是空语句。
- 然后,检测布尔表达式的值。如果为true,循环体被执行。如果为false,循环终止,开始执行循环体后面的语句。
- 执行一次循环后,更新循环控制变量。
- 在册检测布尔表达式。循环执行上面的过程。
Java增强for循环
Java增强for循环语法格式如下:
for(声明语句:表达式){
//代码
}
声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定在循环语句块,其值与此时数组元素的值相等; 表达式:表达式是要范围的数组名,或者返回值为数组的方法。
break关键字
break主要用在循环语句或switch语句中,用来跳出整个语句块。 break 跳出最里层的循环,并且继续执行该循环下面的语句。
continue关键字
continue适用于任何循环控制结构中。左右是让程序立即跳转到下一次循环的迭代。 在for循环中,continue语句使程序立即跳转到更新语句。 在while或者do...while循环中,程序立即跳转到布尔表达式的判断语句。
条件语句
一个if语句包含一个布尔表达式和一条或多条语句。 if语句的语法如下:
if(布尔表达式){
//如果布尔表达式为true将执行的语句
}
如果布尔表达式的值为true,则执行if语句中的代码块,否则执行if语句块后面的代码
if...else语句
if语句后面可以跟else语句,当if语句的布尔表达式值为false时,else语句块会被执行 if...else的用法如下:
if(布尔表达式){
//如果布尔表达式的值为true
}else{
//如果布尔表达式的值为false
}
if...else if...else语句
if语句后面可以跟else if...else语句,这种语句可以检测到多张可能的情况。 需要注意下面几点:
- if语句至多有一个else语句,else语句在所有的else if语句之后。
- if语句可以有若干个else if语句,他们必须在else语句之前
- 一旦其中一个else if语句检测为true,其他的else if以及else语句都将跳过执行 语法格式如下:
if(布尔表达式 1){
//如果布尔表达式1的值为true执行代码
}else if(布尔表达式 2){
//如果布尔表达式2的值为true执行代码
}else if(布尔表达式 3){
//如果布尔表达式3的值为true执行代码
}else {
//如果以上布尔表达式都不为true执行代码
}
嵌套的if...else语句
使用嵌套的if...else语句是合法的,也就是说你可以在另一个if或者else if中使用if或者else if语句。 嵌套的if...else语法格式如下:
if(布尔表达式 1){
//如果布尔表达式1的值为true执行代码
if(布尔表达式 2){
//如果布尔表达式2的值为true执行代码
}
}
java switch case
switch case 语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支 switch case 语法格式如下:
switch (expression){
case value:
//语句
break;//可选
case value:
//语句
break;//可选
//你可以有任意数量的case语句
default: //可选
//语句
}
switch case 语句有如下规则:
- swicth语句中的变量类型可以是:byte、short、int或者char。从java SE 7开始,switch支持字符串String类型了,同时case变迁必须为字符串常量或字面量。
- switch语句可以拥有多个case语句。每个case后面跟一个要比较的值和冒号。
- case语句中的值的数据类型必须与变量的数据类型相同,而且不像是常量或者字面常量。
- 单反表变量的值与case语句的值相等时,那么case语句之后的语句开始执行,直到break语句出现才会跳出switch语句
- 当遇到break语句时,switch语句终止。程序跳转到switch语句后面的语句执行。case语句不必须包含braek语句。如果没有break语句出现,程序会继续执行下一条case语句,直到出现break语句。
- switch语句可以包含一个default分支,该分支一般是switch语句的最后一个分支(可以在任何位置,但建议在最后一个)。default在没有case语句的值和变量值相等的时候执行,default分支不需要break语句。 switch case执行时,一定会先进行匹配,匹配成功返回当前case的值,再根据是否有break,帕努但是否继续输出,或是跳出判断。 如果case语句块中没有break语句时,jvm并不会顺序输出每一个case对应的返回值,而是继续匹配,匹配不成功则返回默认case。 如果case语句块中没有break语句时,匹配成功后,从当前case开始,后续所有case的值都会输出。 如果当前匹配成功的case语句块没有break语句,则从当前case开始,后续所有case的值都会输出,如果后续的case语句块有break语句则会跳出判断。
java Number & Math 类
java语言为每一个内置数据类型提供了对应的包装类。 所有的包装类(Integer、Long、Byte、Double、Float、Short)都是抽象类Number的子类。 包装类 基本数据类型 Byte byte Short short Integer int Long long Float float Double double Boolean boolean Character char 这种由编译器特别支持的包装称为装箱,所以当内置数据类型被当作对象使用的时候,编译器会把内置类型装箱为包装类。类似的,编译器也可以把一个对象茶香为内置类型。Number类属于java.langb包。
下面是一个使用Integer对象的实例:
Integet x = 5;
x = x + 10;
当x被赋为整型值时,由于x是一个对象,所以编译器对x进行装箱。然后,为了使x能够进行加运算,所以要对x进行拆箱。
java Math类
java的Math包含了用于执行基本数学运算的属性和方法,如初等指数、对数、平方根和三角函数。 Math的方法都被定义为static形式,通过Math类可以在主函数中直接调用。
Numer& Math常用方法
- xxxValue() 将Number对象转换为xxxs数据类型的值并返回
- 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() 将笛卡尔坐标转换为极坐标,斌返回极坐标的角度值
- toDegrees() 将参数转换为角度
- toRadians() 将角度转换为弧度
- random() 返回一个随机数
Math的floor round 和ceil的方法实例比较
| 参数 | Math.floor | Math.round | Math.ceil |
|---|---|---|---|
| 1.4 | 1 | 1 | 2 |
| 1.5 | 1 | 2 | 2 |
| 1.6 | 1 | 2 | 2 |
| -1.4 | -2 | -1 | -1 |
| -1.5 | -2 | -1 | -1 |
| -1.6 | -2 | -2 | -1 |
java Character类
Chraracter类用于对单个地方进行操作。 Character类在对象中包装一个基本类型char的值 Character类提供了一系列方法来操纵字符,你可以使用Character类对象,例如:
Charracter ch = new Character('a');
在某些情况下,java编译器会自动创建一个Character对象。 例如,将一个char类型的参数传递给需要一个Character类型参数的方法时,那么编译器会自动地将char类型参数转换为Character对象。这种特征称为装箱,反过来称为拆箱。
//原始字符'a'装箱到Character对象ch中
Character ch = 'a';
//原始字符'x'用test方法装箱
//返回装箱的值到'c'
char c = test('x');
转义序列
前面有反斜杠()的字符代表转义字符,它对编译器来说是有特殊含义的 \t 在文中该处插入一个tab键 \b 在文中该处插入一个后退键 \n 在文中该处换行 \r 在文中该处插入回车 \f 在文中该处插入换页符 ' 在文中该处差人单引号 " 在文中该处插入双引号 \ 在文中该处插入反斜杠
Character方法
- isLetter() 是否是一个字母
- isDigit() 是否是一个数字
- isWhitespace() 是否是一个空白字符
- isUpperCase() 是否是大写字母
- isLowerCasee() 是否是小写字母
- toUpperCase() 指定字母的大写形式
- toLowerCase() 指定字母的小写形式
- toString() 返回字符的字符串形式,字符串的长度仅为1
java String 类
在Java中字符串属于对象,java提供了String类来创建和操作字符串。 String 创建的字符串存储在公共池中,而new String 创建的字符串对象在堆上 String类是不可改变的,所以你一旦创建了String对象,那它的值就无法改变了 如果需要对字符串做很多修改,那么一个选择使用String Buffer StringBuilder类
字符串长度
用于获取有关对象的信息的方法称为访问器方法。 String 类的一个访问器方法是length()方法,它返回字符串对象包含的字符数。
连接字符串
string1.concat(string2); 返回string2连接string1的新字符串。也可以对字符串常量使用concat()方法 更常用的是使用'+'操作符来连接字符串
创建格式化字符串
输出格式数字可以使用printf()和format()方法 String类使用静态方法format()返回一个String对象而不是PrintStream对象。 String类是静态方法formait能用来创建可复用的格式化字符串,而不仅仅是用于一次打印输出
String 常用方法
- char charAt(int index) 返回指定索引处的char值
- int compareTo(Object o) 把这个字符串和另一个对象比较
- int compareTo(String antherString) 按字典顺序比较两个字符串
- int compareToIgnoreCase(String str) 按字典顺序比较两个字符串,不考虑大小写
- String concat(String str) 将指定字符串连接到此字符串的结尾
- boolean contenEquals(StringBuffer sb) 当且仅当字符串与指定的StringBuffer有相同顺序的字符时候返回true
- static String copyValueOf(char[] data) 返回指定数组表示该字符序列的String
- static String copyValueOf(char[] data,int offset,int count) 返回指定数组表示该字符序列的String
- boolean endWith(String suffix) 测试此字符串是否以指定的后缀结束
- boolean equals(Object anObject) 将此字符串与指定的对象比较
- boolean equalsIgnoreCase(String antherString) 将此String与另一个String比较,不考虑大小写
- byte[] getBytes() 使用平台默认的字符集将此String编码为byte序列,并将结果存储到一个新的byte数组中
- byte[] getBytes(String charseName) 使用指定的字符集将此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) 返回指定子字符在此字符串中最后一次出现处的所念,从指定的所以开始反向搜索。
- int length() 返回此字符串的长度
- boolean matches(String regex) 告知此字符串是否匹配给定的正则表达式
- boolean regionMatches(boolean ignoreCase,int toffset,String other,int ooffset,int len) 测试两个字符串区域是否相等。
- boolean reginMatches(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) 使用给定的repalcement替换此字符串匹配geodesic的正则表达式的子一个子字符串。
- String[] split(String regex) 根据给定正则表达式的匹配拆分此字符串
- String[] split(String regex,int limit) 根据给定正则表达式的匹配拆分此字符串
- boolean startsWith(String prefix) 测试此字符串是否以指定的前缀开始。
- boolean startsWith(String prefix,int toffset) 测试此字符串是否从指定所有开始的子字符串是否以指定的前缀开始。
- CharSequence subSwquence(int beginIndex,int endIndex) 返回一个新的字符序列,它是此序列的一个子序列。
- String substring(int beginIndex) 返回一个新的字符串,它是此字符串的一个子字符串。
- String substring(int beginIndex,int denIndex) 返回一个新字符串,他说此字符串的一个子字符串。
- Char[] toCharArray() 将此字符串转换为一个新的字符数组。
- String toLowerCase() 使用默认语言环境的规则将此String中的所有字符都转换为小写
- String toLowerCase(Locate locate) 使用给定Locate的规则将此String中的所有字符都转换为小写
- String toString() 返回此对象本身(它以及是一个字符串)
- String toUpperCase() 使用默认语言环境的规则将此String中的所有字符都转换为大写
- String toUpperCase(Locate locate) 使用给定Locate的规则将此String中的所有字符都转换为大写
- String trim() 返回字符串的副本,忽略前导空白和尾部空白。
- static String valueOf(primitive data type x) 返回给定data type类型x参数的字符串表示形式。
- contains(Charsequence chars) 判断是否包含指定的字符序列
- isEmpty() 判断字符串是否为空
java StringBuffer和String Builder类
当对字符串进行修改的时候,需要使用StringBuffer 和StringBuilder类。 和String类不同的是,StringBuffer和StringBuilder类的对象能够被多次的修改,并且不产生新的未使用对象。 在使用StringBuffer类时,每次都会对StringBuffer对象本身进行操作,而不是生产新对象,所有如果需要对字符串进行修改推荐使用StringBuffer。 StringBuilder类早java5中被提出,它和StringBuffer之间的最大不同在于StringBuilder的方法是线程安全的(不能同步访问) 由于StringBuilder相较于StringBuffer有速度又是,所有多数情况下建议使用StringBuilder类。
StringBuilder sb = new StringBuilder(10);
sb.append("Runoob..");
sb.append("!");
sb.insert(8,"java");
sb.delete(5,8);
StringBuffer方法
- public StringBuffer append(String s) 将指定的字符串追加到此字符序列
- public StringBuffer reverse() 将此字符序列用其反转形式取代
- public delete(int start,int end) 移除此序列的子字符串中的字符
- public insert(int offset,int i) 将int参数的字符串表示形式插入此序列中。
- insert(int offset,String str) 将str参数的字符串插入此序列中
- replace(int start,int end,String str) 使用给定String中字符替换此序列的子字符串中的字符
- int capacity() 返回当前容量
- char charAt(int index) 返回此序列中指定索引处的char值
- void ensureCapacity(int miminumCapacity) 确保容量至少等于指定的最小值
- void getChars(int srcBegin,int srcEnd,char[] dst,int dstBegin) 将字符从此序列复制到目标字符数组dst。
- int indexOf(String str) 返回第一次出现的指定子字符串在该字符串中的索引。
- int indexOf(String str,int framIndex) 从指定的索引处开始,返回第一次出现的指定子字符串在给字符串中的索引
- int lastIndexOf(String str) 返回最右边出现的指定子字符串在此字符串中的索引。
- int lasetIndexOf(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数组
数组对应每一门编程语言来说都是重要的数据结构之一。 java语言中提供的数组是用来存储固定大小的同类型元素。
声明数组变量
首先必须声明数组变量,才能在程序中使用数组。下面是声明数组变量的语法:
dataType[] arrayRefvar;//首选的方法
dataType arrayRevar[]; //效果相同,但不是首选方法
创建数组
java语言使用new操作符来创建数组,语法如下:
arrarRefVar = new dataType[arraySize];
- 使用dataTye[arraySize]创建了一个数组
- 把创建的数组的引用赋值给变量arrayRefvar 数组变量的声明和创建数组可以使用一条语句完成:
dataType[] arrayRefVar = new dataType[arraySize];
另外,你还可以使用如下的方式创建数组:
dataType[] arrayrefVar = {value0,value1,...valuek};
数组的元素是通过索引访问的。数组索引从0开始,索引所以在从0到arrayRefVar.length-1
处理数组
数组的元素类型和数组的大小都是确定的,索引当处理数组元素时候,我们通常使用基本循环或者For-Each循环
For-Each循环
jdk1.5引进,又被称为加强型循环,它能在不适应下表的情况下遍历数组。
数组作为函数的参数
数组可以作为参数传递给方法
数组作为函数的返回值
多维数组
多维数组可以看成是数组的数组,比如二维数组就是一个普通的一维数组,其每一个元素都是一个一维数组。
多维数组的动态初始化(以二维数组为例)
- 直接为每一维分配空间,格式如下:
type[][] typeName = new type[typeLength1][typeLength2];
type可以为基本数据类型和符合数据类型,typeLength1和typeLength2必须为正整数,typelength1为行数,typeLength2为列数。
- 从最高维开始,分别为每一维分配空间
多为数组的引用(以二维数组为例)
arrayName[index1][index2]
Arrays类
java.utils.Arrays类能方便地操作数组,它提供的所有方法都是静态的,具有以下功能:
-
给数组赋值:通过fill方法
-
给数组排序:通过sort方法,按升序
-
比较数组:通过equals方法比较数组中元素值是否相等
-
查找数组元素:通过binarySerach方法能对排序号的数组进行二分查找操作
-
public staric int binarySearch(Object[] a,Object key)
-
public static boolean equals(object[] a,long[] a2)
-
public static void fill(int[] a,int val)
-
public static void sort(object[] a)
Java日期时间
java.util包提供了Date类来封装当前的日期和时间。Date类提供两个构造函数来实例化Date对象
- 第一个构造函数使用当前日期和时间来初始化对象。
- 第二个构造函数接收一个参数,该参数是从1970年1月1日起的毫秒数。 Date对象创建和,可以调用下面的方法:
- boolean after(Date date) 若调用此方法的Date对象在指定日期之后返回true
- boolean before(Date date) 若调用此方法的Date对象在指定日期之前返回true
- Obejct clone() 返回此对象的副本
- int compareTo(Date date) 比较当调用此方法的Date对象和指定日期。两者相等时候返回0,调用对象在指定日期之前返回负数,之后返回正数。
- int copmareTo(Object obj) 若obj是Date类型则操作等同于compareTo(Date)。佛则抛出ClassCaseException
- boolean equals(Object date) 当调用此方法的Date对象和指定日期向德国时返回true
- 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是一周中的某一天
获得当前日期时间
使用Date对象的toString()方法打印当前日期和时间
日期比较
- 使用getTime()方法获取两个日期,然后比较这两个值
- 使用方法before() after() equals()
- 使用compareTo()方法,它是由Compareble接口定义的,Date类实现了这个接口
使用SimpleDateFormat格式化日期
SimpleDateFormat是一个以语言环境敏感的方法来格式化和分析日期的类。允许选择任何用户自定义日期时间格式来运行。
Date now = new Date();
SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
ft.format(now);
注意:有的格式大写,有的格式小写,例如MM是月份,mm是分,HH是24小时制,hh是12小时制。
日期和时间的格式化编码
G 纪元标记
y 四位年份
M 月份
d 一个月的日期
h A.M./P.M.(112)格式小时
H 一天中的小时(024)
m 分钟数
s 秒数
S 毫秒数
E 星期几
D 一年中的第多少天
F 一个月第几周的周几
w 一年中第几周
W 一个月中第几周
a A.M. /P.M.标记
k 一天中的小时(124)
K A.M /P.M. (011)格式小时
z 时区
' 文字定界符
'' 单引号
使用printf格式化日期
以%t开通并且以下面的一个字母结尾
- c 包括全部日期和时间信息
- F "年-月-日"格式
- D "月/日/年"格式
- r "HH:MM:SS PM"格式(12时制)
- T "HH:MM:SS"格式 (24时制)
- R "HH:MM"格式 (24时制)
如果你需要重复提供日期,那么利用这种方式来格式化它的每一部分就有点复杂了。因此,可以利用一个格式化字符串指出要被格式化的参数的索引。 索引必须紧跟在%后面,并且必须要以$结束
Date date = new Date();
System.out.printf("%1$s %2$tB %2$td, %2$tY", "Due date:", date);
解析字符串为时间
SimoeldateFomat类有一些附加的方法,特别是parse(),它试图按照给定的SimpleDateFormat对象的格式化存储来解析字符串。
java休眠(sleep)
sleep()使当前线程进入停滞状态(阻塞当前线程),让出CPU的使用、目的是不让当前线程独自霸占改进程所获得CPI资源,以留一定时间给其他线程执行的机会。
Thread.sleep(1000*3);//休眠3秒
测量时间间隔
long start = System.currentTimeMillis();
Thread.sleep(5*60*10);
long end = System.curretTimeMillis();
long diff = end - start;
Calendar类
Calendar类是一个抽象类,在实际使用时实现特定子类的对象,创建对象的过程对程序员来说是透明的,只需要使用getInstance方法创建即可。
创建一个代表系统当前日期的Calendar对象
Calendar c = Calendar.getInstance();//默认是当前日期
创建一个指定日期的Calendar对象
使用Calendar类代表特定的时间,需要首选创建一个Calendar的对象,然后再设定该对象中的年月日参数来完成。
//常见一个代表2009年6月12日的Calendar对象
Calendar c1 =Calendar.getInstance();
c1.set(2009,6-1,12);
Calendar类对象字段类型
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 mouth,int date)
把Calendar对象c1的年月日分别设为:2009,6,12
c1.set(2009,6,12);
利用字段类型设置 如果只设定某个字段,例如日期的值,则可以使用如下set方法:
public void set(int field,int value)
把c1对象代表的日期设置为10号,其他所有的数组会被重新计算
c1.set(Calendar.DATE,10);
把c1对象代表的年份设置为2008年,其他所有数组会被重新计算
c1.set(Calendar.YEAR,2008);
Add设置:
Calendar c1 = Calendar.getInstance();
把c1对象的日期加上10,也就是c1也就表示为10天后的日期,其他的所有数值会被重新计算
c1.add(Calendar.DATE,10);
把c1对象的日期减去10,也就是c1也就表示为10天前的日期,其他的所有数值会被重新计算
c1.add(Calendar.DATE,-10);
get: 注意:与Date类不同,c1.get(Calendar.DAY_OF_WEEK); 1代表星期日,2代表星期一...
GregorianCalendar类
Calendar类实现了公历日历,GregorianCalendar类是Calendar类的一个具体实现。 Calendar类的getInstance()方法返回一个默认用当前的语言环境和时区初始化的GregorianCalendar对象。 定义了两个字段:AD和BC。这是代表公历定义的两个时代。 GregorianCalendr对象的几个构造方法:
- 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()
- 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也没有公共构造方法,你需要调用Pttern对象的matcher方法来获得一个Matcher对象
- PatternSyntaxException:PatternSyntaxException是一个非强制异常类,它表示一个正则表达式模式中语法错误。
java方法
什么是方法
Java方法是语句的集合,它们在一起执行一个功能
- 方法是解决一类问题的步骤的有序组合
- 方法包含于类或对象中
- 方法在程序中被创建,在其他地方被引用
方法的优点
- 使程序变得更简短而清晰
- 有利于程序维护
- 可以提高程序开发的效率
- 提高了代码的复用性
方法的命名规则
- 方法的名字的第一个单词应该以小写字母为开通,后面的单词则用大写字母开头写,不使用连接符。例如addPerson。
- 下划线可能出现在JUnit测试方法明成祖用以分割名称的逻辑组件。一个典型的模式是:
test<MethodUnderTest>_<state>,例如test_emptyStack
方法的定义
语法: 修饰符 返回值类型 方法名(参数类型 参数名){ ... 方法体 ... return 返回值; } f方法包含一个方法头和一个方法体。下面是一个方法的所有部分:
- 修饰符:修饰符这是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型。
- 返回值类型:方法可能会返回值。returnValueType是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值,这种情况下,使用关键字void
- 方法名:是方法的实际名称。方法和参数表共同构成方法签名。
- 参数类型:参数像是一个占位符。当方法被调用时,传递值给参数。这个值被称为试产或变量。参数列表是值方法的参数类型、顺序和参数的个数。参数是可选的,方法可以不包含任何参数。
- 方法体:方法体包含具体的语句,定义该方法的功能
注意在一些其他语言中方法指过程和函数。一个返回非void类型返回值的方法称为函数,一个返回void类型返回值的方法加做过程。
方法的调用
java支持两种调用方法的方式,根据方法是否返回值来选择。 当程序调用一个方法时,程序的控制权交给了被调用的方法。当被调用方法的返回语句执行或者到达方法头比括号时候交还控制权给程序。 当方法返回一个值的时候,方法调用通常被当作一个值。
void 关键字
一个void方法的调用一定是一个语句。
通过值传递参数
调用一个方法时候需要提供参数,你必须按照参数列表指定的顺序提供。
方法的重载
一个类的两个方法拥有相同的名字,但是有不同的参数列表。 方法重载可以让程序更清晰易读。执行密切相关任务的方法应该使用相同的名字。 重载的方法必须拥有不同的参数列表。不能仅仅根据修饰符或者返回类型的不同来重载方法。
变量作用域
变量的范围是程序中该变量可以被引用的部分。 方法内定义的变量称为局部变量。 局部变量的作用返回从声明开始,直到包含它的块结束。 局部变量必须声明才可以使用。 方法的参数返回涵盖整个方法,实际上是一个局部变量。 for循环的初始化部分声明的变量,其作用范围在整个循环。 但循环体内部声明的变量其适用范围是从它声明到循环体结束。 你可以在一个方法里,不同的非嵌套块中,多次声明一个具有相同的名称局部变量,但你不能在嵌套块内两次声明局部变量。
命令行参数的使用
命令行参数是在执行程序时候紧跟在程序名字后面的信息。
构造方法
当一个对象被创建时候,构造方法用来初始化该对象。构造方法和它所在类的名字相同,但构造方法没有返回值。 通常会使用构造方法给一个类的实例变量赋初值,或者执行其他必要的步骤来创建一个完整的对象。 不管你是否自定义构造方法,所以类都有构造方法,因为jav自动提供了一个默认构造方法,默认构造方法的访问修饰符和类的访问修饰符相同,类为pulic,构造函数也为public,类改为protected,构造函数也改为protected。 一旦你定义了自己的构造方法,默认构造方法就会失效。
可变参数
jdk 1.5开始,java支持传递同类型的可变参数给一个方法。 方法的可变参数的声明如下: type name ... parameterName 在方法声明中,在指定参数类型后加一个省略号 一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。
public class VarargsDemo {
public static void main(String args[]) {
// 调用可变参数的方法
printMax(34, 3, 3, 2, 56.5);
printMax(new double[]{1, 2, 3});
}
public static void printMax( double... numbers) {
if (numbers.length == 0) {
System.out.println("No argument passed");
return;
}
double result = numbers[0];
for (int i = 1; i < numbers.length; i++){
if (numbers[i] > result) {
result = numbers[i];
}
}
System.out.println("The max value is " + result);
}
}
finalize()方法
Java允许定义这样的方法,它在对象被垃圾收集器析构(回收)之前调用,这个方法叫做finalize(),它用来清除回收对象。 例如,你可以使用finalize()来确保一个对象打开的文件被关闭了。 在finalize()方法里,你必须指定在对象销毁时要执行的操作。 finalize()一般格式是: protected void finalize(){ //在这里终结代码 } 关键字protected是一个限定符,它确保finalize()不会被该类以外的代码调用 当然,java的内存回收可以由JVM来自动完成。如果你手动使用,则可以使用上面的方法
public class FinalizationDemo {
public static void main(String[] args) {
Cake c1 = new Cake(1);
Cake c2 = new Cake(2);
Cake c3 = new Cake(3);
c2 = c3 = null;
System.gc(); //调用Java垃圾收集器
}
}
class Cake extends Object {
private int id;
public Cake(int id) {
this.id = id;
System.out.println("Cake Object " + id + "is created");
}
protected void finalize() throws java.lang.Throwable {
super.finalize();
System.out.println("Cake Object " + id + "is disposed");
}
}
java流(stream)、文件(File)和IO
java.io包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。 java.io包中的流支持很多格式,比如:基本类型,对象,本地化字符集等。 一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示香一个目标写数据。
读取控制台输入
Java的控制台输入由System.in完成。 为了获得绑定搭配控制台的字符流,你可以把System.in包装在一个BufferedReader对象中来创建字符流。 创建bufferedreader的基本语法: BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); Bufferedreader对象创建后,我们可以使用read()方法从控制台读取一个字符,或者使用readLine()方法赌气一个字符串。
从控制台读取多字符输入
从 BufferedReader 对象读取一个字符要使用 read() 方法,它的语法如下:
int read( ) throws IOException
每次调用 read() 方法,它从输入流读取一个字符并把该字符作为整数值返回。 当流结束的时候返回 -1。该方法抛出 IOException。
下面的程序示范了用 read() 方法从控制台不断读取字符直到用户输入 q。
BRRead.java 文件代码:
从 BufferedReader 对象读取一个字符要使用 read() 方法,它的语法如下: int read( ) throws IOException 每次调用 read() 方法,它从输入流读取一个字符并把该字符作为整数值返回。 当流结束的时候返回 -1。该方法抛出 IOException。 下面的程序示范了用 read() 方法从控制台不断读取字符直到用户输入 q。
//使用 BufferedReader 在控制台读取字符
import java.io.*;
public class BRRead {
public static void main(String[] args) throws IOException {
char c;
// 使用 System.in 创建 BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("输入字符, 按下 'q' 键退出。");
// 读取字符
do {
c = (char) br.read();
System.out.println(c);
} while (c != 'q');
}
}
从控制台读取字符串
从标准输入读取一个字符串需要使用 BufferedReader 的 readLine() 方法。 它的一般格式是: String readLine( ) throws IOException 下面的程序读取和显示字符行直到你输入了单词"end"。
//使用 BufferedReader 在控制台读取字符
import java.io.*;
public class BRReadLines {
public static void main(String[] args) throws IOException {
// 使用 System.in 创建 BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str;
System.out.println("Enter lines of text.");
System.out.println("Enter 'end' to quit.");
do {
str = br.readLine();
System.out.println(str);
} while (!str.equals("end"));
}
}
控制台输出
控制台的输出由 print( ) 和 println() 完成。这些方法都由类 PrintStream 定义,System.out 是该类对象的一个引用。 PrintStream 继承了 OutputStream类,并且实现了方法 write()。这样,write() 也可以用来往控制台写操作。 PrintStream 定义 write() 的最简单格式如下所示: void write(int byteval) 该方法将 byteval 的低八位字节写到流中。 下面的例子用 write() 把字符 "A" 和紧跟着的换行符输出到屏幕:
import java.io.*;
//演示 System.out.write().
public class WriteDemo {
public static void main(String[] args) {
int b;
b = 'A';
System.out.write(b);
System.out.write('\n');
}
}
注意:write() 方法不经常使用,因为 print() 和 println() 方法用起来更为方便。
读写文件
下图是一个描述输入流和输出流的类层次图。
FileInputStream
该流用于从文件读取数据,它的对象可以用关键字 new 来创建。 有多种构造方法可用来创建对象。
可以使用字符串类型的文件名来创建一个输入流对象来读取文件:
InputStream f = new FileInputStream("C:/java/hello");
也可以使用一个文件对象来创建一个输入流对象来读取文件。我们首先得使用 File() 方法来创建一个文件对象:
File f = new File("C:/java/hello"); InputStream in = new FileInputStream(f);
创建了InputStream对象,就可以使用下面的方法来读取流或者进行其他的流操作。
- 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
该类用来创建一个文件并向文件中写数据。 如果该流在打开文件进行输出前,目标文件不存在,那么该流会创建该文件。 有两个构造方法可以用来创建 FileOutputStream 对象。
使用字符串类型的文件名来创建一个输出流对象:
OutputStream f = new FileOutputStream("C:/java/hello")
也可以使用一个文件对象来创建一个输出流来写文件。我们首先得使用File()方法来创建一个文件对象:
File f = new File("C:/java/hello");
OutputStream fOut = new FileOutputStream(f);
创建OutputStream 对象完成后,就可以使用下面的方法来写入流或者进行其他的流操作。
- 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中。 下面是一个演示 InputStream 和 OutputStream 用法的例子:
import java.io.*;
public class fileStreamTest {
public static void main(String[] args) {
try {
byte bWrite[] = { 11, 21, 3, 40, 5 };
OutputStream os = new FileOutputStream("test.txt");
for (int x = 0; x < bWrite.length; x++) {
os.write(bWrite[x]); // writes the bytes
}
os.close();
InputStream is = new FileInputStream("test.txt");
int size = is.available();
for (int i = 0; i < size; i++) {
System.out.print((char) is.read() + " ");
}
is.close();
} catch (IOException e) {
System.out.print("Exception");
}
}
}
上面的程序首先创建文件test.txt,并把给定的数字以二进制形式写进该文件,同时输出到控制台上。
以上代码由于是二进制写入,可能存在乱码,你可以使用以下代码实例来解决乱码问题:
//文件名 :fileStreamTest2.java
import java.io.*;
public class fileStreamTest2 {
public static void main(String[] args) throws IOException {
File f = new File("a.txt");
FileOutputStream fop = new FileOutputStream(f);
// 构建FileOutputStream对象,文件不存在会自动新建
OutputStreamWriter writer = new OutputStreamWriter(fop, "UTF-8");
// 构建OutputStreamWriter对象,参数可以指定编码,默认为操作系统默认编码,windows上是gbk
writer.append("中文输入");
// 写入到缓冲区
writer.append("\r\n");
// 换行
writer.append("English");
// 刷新缓存冲,写入到文件,如果下面已经没有写入的内容了,直接close也会写入
writer.close();
// 关闭写入流,同时会把缓冲区内容写入文件,所以上面的注释掉
fop.close();
// 关闭输出流,释放系统资源
FileInputStream fip = new FileInputStream(f);
// 构建FileInputStream对象
InputStreamReader reader = new InputStreamReader(fip, "UTF-8");
// 构建InputStreamReader对象,编码与写入相同
StringBuffer sb = new StringBuffer();
while (reader.ready()) {
sb.append((char) reader.read());
// 转成char加到StringBuffer对象中
}
System.out.println(sb.toString());
reader.close();
// 关闭读取流
fip.close();
// 关闭输入流,释放系统资源
}
}
Java中的目录
创建目录:
File类中有两个方法可以用来创建文件夹:
- mkdir( ) 方法创建一个文件夹,成功则返回true,失败则返回false。失败表明File对象指定的路径已经存在,或者由于整个路径还不存在,该文件夹不能被创建。
- mkdirs() 方法创建一个文件夹和它的所有父文件夹。
读取目录
一个目录其实就是一个 File 对象,它包含其他文件和文件夹。 如果创建一个 File 对象并且它是一个目录,那么调用 isDirectory() 方法会返回 true。 可以通过调用该对象上的 list() 方法,来提取它包含的文件和文件夹的列表。
删除目录或文件
删除文件可以使用 java.io.File.delete() 方法。 需要注意的是当删除某一目录时,必须保证该目录下没有其他文件才能正确删除,否则将删除失败。
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 类
java.util.Scanner 是 Java5 的新特征,我们可以通过 Scanner 类来获取用户的输入。
下面是创建 Scanner 对象的基本语法:
Scanner s = new Scanner(System.in);
通过 Scanner 类的 next() 与 nextLine() 方法获取输入的字符串,在读取前我们一般需要 使用 hasNext 与 hasNextLine 判断是否还有输入的数据:
使用 next 方法:
import java.util.Scanner;
public class ScannerDemo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
// 从键盘接收数据
// next方式接收字符串
System.out.println("next方式接收:");
// 判断是否还有输入
if (scan.hasNext()) {
String str1 = scan.next();
System.out.println("输入的数据为:" + str1);
}
scan.close();
}
}
使用 nextLine 方法:
import java.util.Scanner;
public class ScannerDemo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
// 从键盘接收数据
// nextLine方式接收字符串
System.out.println("nextLine方式接收:");
// 判断是否还有输入
if (scan.hasNextLine()) {
String str2 = scan.nextLine();
System.out.println("输入的数据为:" + str2);
}
scan.close();
}
}
next() 与 nextLine() 区别
next():
- 一定要读取到有效字符后才可以结束输入。
- 对输入有效字符之前遇到的空白,next() 方法会自动将其去掉。
- 只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
- next() 不能得到带有空格的字符串。 nextLine():
- 以Enter为结束符,也就是说 nextLine()方法返回的是输入回车之前的所有字符。
- 可以获得空白。 如果要输入 int 或 float 类型的数据,在 Scanner 类中也有支持,但是在输入之前最好先使用 hasNextXxx() 方法进行验证,再使用 nextXxx() 来读取:
import java.util.Scanner;
public class ScannerDemo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
// 从键盘接收数据
int i = 0;
float f = 0.0f;
System.out.print("输入整数:");
if (scan.hasNextInt()) {
// 判断输入的是否是整数
i = scan.nextInt();
// 接收整数
System.out.println("整数数据:" + i);
} else {
// 输入错误的信息
System.out.println("输入的不是整数!");
}
System.out.print("输入小数:");
if (scan.hasNextFloat()) {
// 判断输入的是否是小数
f = scan.nextFloat();
// 接收小数
System.out.println("小数数据:" + f);
} else {
// 输入错误的信息
System.out.println("输入的不是小数!");
}
scan.close();
}
}
Java 异常处理
异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。
异常发生的原因有很多,通常包含以下几大类:
- 用户输入了非法数据。
- 要打开的文件不存在。
- 网络通信时连接中断,或者JVM内存溢出。
要理解Java异常处理是如何工作的,你需要掌握以下三种类型的异常:
- 检查性异常: 最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
- 运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
- 错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
Exception 类的层次
所有的异常类是从 java.lang.Exception 类继承的子类。
Exception 类是 Throwable 类的子类。除了Exception类外,Throwable还有一个子类Error 。
Java 程序通常不捕获错误。错误一般发生在严重故障时,它们在Java程序处理的范畴之外。
Error 用来指示运行时环境发生的错误。
例如,JVM 内存溢出。一般地,程序不会从错误中恢复。
异常类有两个主要的子类:IOException 类和 RuntimeException 类。
Java 内置异常类
Java 语言定义了一些异常类在 java.lang 标准包中。
标准运行时异常类的子类是最常见的异常类。由于 java.lang 包是默认加载到所有的 Java 程序的,所以大部分从运行时异常类继承而来的异常都可以直接使用。 Java 根据各个类库也定义了一些其他的异常,下面的表中列出了 Java 的非检查性异常。
| 异常 | 描述 |
|---|---|
| ArithmeticException | 当出现异常的运算条件时,抛出此异常。例如,一个整数"除以零"时,抛出此类的一个实例。 |
| ArrayIndexOutOfBoundsException | 用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。 |
| ArrayStoreException | 试图将错误类型的对象存储到一个对象数组时抛出的异常。 |
| ClassCastException | 当试图将对象强制转换为不是实例的子类时,抛出该异常。 |
| IllegalArgumentException | 抛出的异常表明向方法传递了一个不合法或不正确的参数。 |
| IllegalMonitorStateException | 抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。 |
| IllegalStateException | 在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。 |
| IllegalThreadStateException | 线程没有处于请求操作所要求的适当状态时抛出的异常。 |
| IndexOutOfBoundsException | 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。 |
| NegativeArraySizeException | 如果应用程序试图创建大小为负的数组,则抛出该异常。 |
| NullPointerException | 当应用程序试图在需要对象的地方使用 null 时,抛出该异常 |
| NumberFormatException | 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。 |
| SecurityException | 由安全管理器抛出的异常,指示存在安全侵犯。 |
| StringIndexOutOfBoundsException | 此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小。 |
| UnsupportedOperationException | 当不支持请求的操作时,抛出该异常。 |
下面的表中列出了 Java 定义在 java.lang 包中的检查性异常类。
| 异常 | 描述 |
|---|---|
| ClassNotFoundException | 应用程序试图加载类时,找不到相应的类,抛出该异常。 |
| CloneNotSupportedException | 当调用 Object 类中的 clone 方法克隆对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。 |
| IllegalAccessException | 拒绝访问一个类的时候,抛出该异常。 |
| InstantiationException | 当试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象因为是一个接口或是一个抽象类而无法实例化时,抛出该异常。 |
| InterruptedException | 一个线程被另一个线程中断,抛出该异常。 |
| NoSuchFieldException | 请求的变量不存在 |
| NoSuchMethodException | 请求的方法不存在 |
异常方法
下面的列表是 Throwable 类的主要方法:
| 序号 | 方法及说明 |
|---|---|
| 1 | public String getMessage() 返回关于发生的异常的详细信息。这个消息在Throwable 类的构造函数中初始化了。 |
| 2 | public Throwable getCause() 返回一个 Throwable 对象代表异常原因。 |
| 3 | public String toString() 返回此 Throwable 的简短描述。 |
| 4 | public void printStackTrace() 将此 Throwable 及其回溯打印到标准错误流。。 |
| 5 | public StackTraceElement [] getStackTrace() 返回一个包含堆栈层次的数组。下标为0的元素代表栈顶,最后一个元素代表方法调用堆栈的栈底。 |
| 6 | 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(异常类型1 异常的变量名1){ // 程序代码 }catch(异常类型2 异常的变量名2){ // 程序代码 }catch(异常类型3 异常的变量名3){ // 程序代码 }
上面的代码段包含了 3 个 catch块。
可以在 try 语句后面添加任意数量的 catch 块。
如果保护代码中发生异常,异常被抛给第一个 catch 块。
如果抛出异常的数据类型与 ExceptionType1 匹配,它在这里就会被捕获。
如果不匹配,它会被传递给第二个 catch 块。
如此,直到异常被捕获或者通过所有的 catch 块。
throws/throw 关键字
如果一个方法没有捕获到一个检查性异常,那么该方法必须使用 throws 关键字来声明。throws 关键字放在方法签名的尾部。
也可以使用 throw 关键字抛出一个异常,无论它是新实例化的还是刚捕获到的。 一个方法可以声明抛出多个异常,多个异常之间用逗号隔开。
finally关键字
finally 关键字用来创建在 try 代码块后面执行的代码块。
无论是否发生异常,finally 代码块中的代码总会被执行。
在 finally 代码块中,可以运行清理类型等收尾善后性质的语句。
finally 代码块出现在 catch 代码块最后,语法如下: try{ // 程序代码 }catch(异常类型1 异常的变量名1){ // 程序代码 }catch(异常类型2 异常的变量名2){ // 程序代码 }finally{ // 程序代码 }
声明自定义异常
在 Java 中你可以自定义异常。编写自己的异常类时需要记住下面的几点。\
- 所有异常都必须是 Throwable 的子类。
- 如果希望写一个检查性异常类,则需要继承 Exception 类。
- 如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。
可以像下面这样定义自己的异常类:
class MyException extends Exception{ }
只继承Exception 类来创建的异常类是检查性异常类。
下面的 InsufficientFundsException 类是用户定义的异常类,它继承自 Exception。
一个异常类和其它任何类一样,包含有变量和方法。
通用异常
在Java中定义了两种类型的异常和错误。
- JVM(Java 虚拟机 ) 异常: 由 JVM 抛出的异常或错误。例如:NullPointerException 类,ArrayIndexOutOfBoundsException 类,ClassCastException 类。
- 程序级异常: 由程序或者API程序抛出的异常。例如 IllegalArgumentException 类,IllegalStateException 类。
java继承
继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
类的继承格式
在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:
class 父类 {
}
class 子类 extends 父类 {
}
继承类型
需要注意的是 Java 不支持多继承,但支持多重继承。
继承的特性
- 子类拥有父类非 private 的属性、方法。
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
- Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
- 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
继承关键字
继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承object(这个类在 java.lang包中,所以不需要 import)祖先类。
extends关键字
在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类。
implements关键字
使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)。
super 与 this 关键字
super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。 this关键字:指向自己的引用。
final关键字
final 关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写:
- 声明类:
final class 类名 {//类体} - 声明方法:
修饰符(public/private/default/protected) final 返回值类型 方法名(){//方法体}
注:实例变量也可以被定义为 final,被定义为 final 的变量不能被修改。被声明为 final 类的方法自动地声明为 final,但是实例变量并不是 final
构造器
子类是不继承父类的构造器(构造方法或者构造函数)的,它只是调用(隐式或显式)。如果父类的构造器带有参数,则必须在子类的构造器中显式地通过 super 关键字调用父类的构造器并配以适当的参数列表。
如果父类构造器没有参数,则在子类的构造器中不需要使用 super 关键字调用父类构造器,系统会自动调用父类的无参构造器。
Java 重写(Override)与重载(Overload)
重写(Override)
重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写! 重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。例如: 父类的一个方法申明了一个检查异常 IOException,但是在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类,抛出 IOException 异常或者 IOException 的子类异常。
在面向对象原则里,重写意味着可以重写任何现有方法。
方法的重写规则
- 参数列表与被重写方法的参数列表必须完全相同。
- 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,java7 及更高版本可以不同)。
- 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。
- 父类的成员方法只能被它的子类重写。
- 声明为 final 的方法不能被重写。
- 声明为 static 的方法不能被重写,但是能够被再次声明。
- 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
- 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
- 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
- 构造方法不能被重写。
- 如果不能继承一个类,则不能重写该类的方法。
Super 关键字的使用
当需要在子类中调用父类的被重写方法时,要使用 super 关键字。
重载(Overload)
重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。 每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。 最常用的地方就是构造器的重载。 重载规则:
- 被重载的方法必须改变参数列表(参数个数或类型不一样);
- 被重载的方法可以改变返回类型;
- 被重载的方法可以改变访问修饰符;
- 被重载的方法可以声明新的或更广的检查异常;
- 方法能够在同一个类中或者在一个子类中被重载。
- 无法以返回值类型作为重载函数的区分标准。
重写与重载之间的区别
| 区别点 | 重载方法 | 重写方法 |
|---|---|---|
| 参数列表 | 必须修改 | 一定不能修改 |
| 返回类型 | 可以修改 | 一定不能修改 |
| 异常 | 可以修改 | 可以减少或删除,一定不能抛出新的或者更广的异常 |
| 访问 | 可以修改 | 一定不能做更严格的限制(可以降低限制) |
方法的重写(Overriding)和重载(Overloading)是java多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式。
- (1)方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overloading)。
- (2)方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Overriding)。
- (3)方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。
java多态
多态是同一个行为具有多个不同表现形式或形态的能力。 多态就是同一个接口,使用不同的实例而执行不同操作。 多态性是对象多种表现形式的体现。
多态的优点
-
- 消除类型之间的耦合关系
-
- 可替换性
-
- 可扩充性
-
- 接口性
-
- 灵活性
-
- 简化性
多态存在的三个必要条件
- 继承
- 重写
- 父类引用指向子类对象:Parent p = new Child(); 当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
多态的好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。
虚函数
虚函数的存在是为了多态。 Java 中其实没有虚函数的概念,它的普通函数就相当于 C++ 的虚函数,动态绑定是Java的默认行为。如果 Java 中不希望某个函数具有虚函数特性,可以加上 final 关键字变成非虚函数。
重写
我们将介绍在 Java 中,当设计类时,被重写的方法的行为怎样影响多态性。 我们已经讨论了方法的重写,也就是子类能够重写父类的方法。 当子类对象调用重写的方法时,调用的是子类的方法,而不是父类中被重写的方法。 要想调用父类中被重写的方法,则必须使用关键字 super。
多态的实现方式
- 重写
- 接口
- 抽象类和抽象方法
Java 抽象类
抽象类
在 Java 语言中使用 abstract class 来定义抽象类
抽象方法
Abstract 关键字同样可以用来声明抽象方法,抽象方法只包含一个方法名,而没有方法体。 抽象方法没有定义,方法名后面直接跟一个分号,而不是花括号。 声明抽象方法会造成以下两个结果:
- 如果一个类包含抽象方法,那么该类必须是抽象类。
- 任何子类必须重写父类的抽象方法,或者声明自身为抽象类。 继承抽象方法的子类必须重写该方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该抽象方法,否则,从最初的父类到最终的子类都不能用来实例化对象。
抽象类总结规定
-
- 抽象类不能被实例化(初学者很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。
-
- 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
-
- 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。
-
- 构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。
-
- 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。
Java 封装
封装的优点
-
- 良好的封装能够减少耦合。
-
- 类内部的结构可以自由修改。
-
- 可以对成员变量进行更精确的控制。
-
- 隐藏信息,实现细节。
实现Java封装的步骤
- 修改属性的可见性来限制对属性的访问(一般限制为private)
- 对每个值属性提供对外的公共方法访问,也就是创建一对赋取值方法,用于对私有属性的访问。通常情况下,这些方法被称为getter和setter方法。因此,任何要访问类中私有成员变量的类都要通过这些getter和setter方法。 采用 this 关键字是为了解决实例变量(private String name)和局部变量(setName(String name)中的name变量)之间发生的同名的冲突。
Java接口
接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。 接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。 除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。 接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在 Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。
接口与类相似点:
- 一个接口可以有多个方法。
- 接口文件保存在 .java 结尾的文件中,文件名使用接口名。
- 接口的字节码文件保存在 .class 结尾的文件中。
- 接口相应的字节码文件必须在与包名称相匹配的目录结构中。
接口与类的区别:
- 接口不能用于实例化对象。
- 接口没有构造方法。
- 接口中所有的方法必须是抽象方法,Java 8 之后 接口中可以使用 default 关键字修饰的非抽象方法。
- 接口不能包含成员变量,除了 static 和 final 变量。
- 接口不是被类继承了,而是要被类实现。
- 接口支持多继承。
接口特性
- 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
- 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final变量(并且只能是 public,用 private 修饰会报编译错误)。
- 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
抽象类和接口的区别
-
- 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
-
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
-
- 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
-
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。 注:JDK 1.8 以后,接口里可以有静态方法和方法体了。 注:JDK 1.8 以后,接口允许包含具体实现的方法,该方法称为"默认方法",默认方法使用 default 关键字修饰。 注:JDK 1.9 以后,允许将方法定义为 private,使得某些复用的代码不会把方法暴露出去。
接口的声明
接口的声明语法格式如下:
[可见度] interface 接口名称 [extends 其他的接口名] {
// 声明变量
// 抽象方法
}
接口有以下特性:
- 接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
- 接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字。
- 接口中的方法都是公有的。
接口的实现
当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类。 类使用implements关键字实现接口。在类声明中,Implements关键字放在class声明后面。 实现一个接口的语法,可以使用这个公式: 接口语法:
...implements 接口名称[, 其他接口名称, 其他接口名称..., ...] ...
重写接口中声明的方法时,需要注意以下规则:
- 类在实现接口的方法时,不能抛出强制性异常,只能在接口中,或者继承接口的抽象类中抛出该强制性异常。
- 类在重写方法时要保持一致的方法名,并且应该保持相同或者相兼容的返回值类型。
- 如果实现接口的类是抽象类,那么就没必要实现该接口的方法。 在实现接口的时候,也要注意一些规则:
- 一个类可以同时实现多个接口。
- 一个类只能继承一个类,但是能实现多个接口。
- 一个接口能继承另一个接口,这和类之间的继承比较相似。
接口的继承
一个接口能继承另一个接口,和类之间的继承方式比较相似。接口的继承使用extends关键字,子接口继承父接口的方法。
接口的多继承
在Java中,类的多继承是不合法,但接口允许多继承。 在接口的多继承中extends关键字只需要使用一次,在其后跟着继承接口。如下所示:
public interface Hockey extends Sports, Event
标记接口
最常用的继承接口是没有包含任何方法的接口。 标记接口是没有任何方法和属性的接口.它仅仅表明它的类属于一个特定的类型,供其他代码来测试允许做一些事情。 标记接口作用:简单形象的说就是给某个对象打个标(盖个戳),使对象拥有某个或某些特权。 例如:java.awt.event 包中的 MouseListener 接口继承的 java.util.EventListener 接口定义如下:
package java.util; public interface EventListener {}
没有任何方法的接口被称为标记接口。标记接口主要用于以下两种目的:
- 建立一个公共的父接口: 正如EventListener接口,这是由几十个其他接口扩展的Java API,你可以使用一个标记接口来建立一组接口的父接口。例如:当一个接口继承了EventListener接口,Java虚拟机(JVM)就知道该接口将要被用于一个事件的代理方案。
- 向一个类添加数据类型: 这种情况是标记接口最初的目的,实现标记接口的类不需要定义任何接口方法(因为标记接口根本就没有方法),但是该类通过多态性变成一个接口类型。
Java 枚举(enum)
Java 枚举是一个特殊的类,一般表示一组常量,Java 枚举类使用 enum 关键字来定义,各个常量使用逗号 , 来分割。
内部类中使用枚举
枚举类也可以声明在内部类中: 每个枚举都是通过 Class 在内部实现的,且所有的枚举值都是 public static final 的。
迭代枚举元素
可以使用 for 语句来迭代枚举元素:
enum Color
{
RED, GREEN, BLUE;
}
public class MyClass {
public static void main(String[] args) {
for (Color myVar : Color.values()) {
System.out.println(myVar);
}
}
}
在 switch 中使用枚举类
枚举类常应用于 switch 语句中:
enum Color
{
RED, GREEN, BLUE;
}
public class MyClass {
public static void main(String[] args) {
Color myVar = Color.BLUE;
switch(myVar) {
case RED:
System.out.println("红色");
break;
case GREEN:
System.out.println("绿色");
break;
case BLUE:
System.out.println("蓝色");
break;
}
}
}
values(), ordinal() 和 valueOf() 方法
enum 定义的枚举类默认继承了 java.lang.Enum 类,并实现了 java.lang.Seriablizable 和 java.lang.Comparable 两个接口。 values(), ordinal() 和 valueOf() 方法位于 java.lang.Enum 类中:
- values() 返回枚举类中所有的值。
- ordinal()方法可以找到每个枚举常量的索引,就像数组索引一样。
- valueOf()方法返回指定字符串值的枚举常量。
枚举类成员
枚举跟普通类一样可以用自己的变量、方法和构造函数,构造函数只能使用 private 访问修饰符,所以外部无法调用。 枚举既可以包含具体方法,也可以包含抽象方法。 如果枚举类具有抽象方法,则枚举类的每个实例都必须实现它。
Java 包(package)
为了更好地组织类,Java 提供了包机制,用于区别类名的命名空间。
包的作用
- 1、把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。
- 2、如同文件夹一样,包也采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。因此,包可以避免名字冲突。
- 3、包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。 Java 使用包(package)这种机制是为了防止命名冲突,访问控制,提供搜索和定位类(class)、接口、枚举(enumerations)和注释(annotation)等。 package(包) 的作用是把不同的 java 程序分类保存,更方便的被其他 java 程序调用。 一个包(package)可以定义为一组相互联系的类型(类、接口、枚举和注释),为这些类型提供访问保护和命名空间管理的功能。
创建包
创建包的时候,你需要为这个包取一个合适的名字。之后,如果其他的一个源文件包含了这个包提供的类、接口、枚举或者注释类型的时候,都必须将这个包的声明放在这个源文件的开头。 包声明应该在源文件的第一行,每个源文件只能有一个包声明,这个文件中的每个类型都应用于它。 如果一个源文件中没有使用包声明,那么其中的类,函数,枚举,注释等将被放在一个无名的包(unnamed package)中。
import 关键字
为了能够使用某一个包的成员,我们需要在 Java 程序中明确导入该包。使用 "import" 语句可完成此功能。 在 java 源文件中 import 语句应位于 package 语句之后,所有类的定义之前,可以没有,也可以有多条, 类文件中可以包含任意数量的 import 声明。import 声明必须在包声明之后,类声明之前。
package 的目录结构
类放在包中会有两种主要的结果:
- 包名成为类名的一部分,正如我们前面讨论的一样。
- 包名必须与相应的字节码所在的目录结构相吻合。