在 Java 语言中,变量名、函数名、数组名统称为标识符,Java 语言规定标识符只能由字母(a~z,A~Z)、数字(0~9)、下画线(_)和 $ 组成,并且标识符的第一个字符必须是字母、下画线或 $。
值得注意的是,在 Java 语言中,变量名是区分大小写的,例如 Count 与 count 被认为是两个不同的标识符,而非相同的标识符。
1)break 用于直接强行跳出当前循环,不再执行剩余代码。当循环中遇到 break 语句时,忽略循环体中任何其他语句和循环条件测试,程序控制在循环体后面的语句重新开始。所以,当多层循环嵌套,并且 break 语句出现在嵌套循环中的内层循环时,它将仅仅只是终止了内层循环的执行,而不影响外层循环的执行。
2)continue 用于停止当次循环,回到循环起始处,进入下一次循环操作。continue 语句之后的语句将不再执行,用于跳过循环体中的一部分语句,也就是不执行这部分语句,而不是跳出整个循环执行下一条语句,这就是 continue 与 break 的主要区别。简单来说,continue 只是中断一次循环的执行而已。
3)return 语句是一个跳转语句,用来表示从一个方法返回(返回一个值或其他复杂类型),可以使程序控制返回到调用该方法的地方。
break 只能跳出当前的循环,那么如何才能跳出多重循环呢?可以在多重循环的外面定义一个标识,然后在循环体里使用带有标识的 break 语句,这样即可跳出多重循环,示例如下:
1)final 用于声明属性、方法和类,分别表示属性不可变、方法不可覆盖和类不可被继承(不能再派生出新的子类)。
被 final 修饰的变量必须被初始化。一般可以通过以下几种方式对其进行初始化:① 在定义的时候初始化。②final 成员变量可以在初始化块中初始化,但不可在静态初始化块中初始化。③ 静态 final 成员变量可以在静态初始化块中初始化,但不可在初始化块中初始化。④ 在类的构造器中初始化,但静态 final 成员变量不可以在构造函数中初始化。
final 方法:当一个方法声明为 final 时,该方法不允许任何子类重写这个方法,但子类仍然可以使用这个方法。
final 参数:用来表示这个参数在这个函数内部不允许被修改。
final 类:当一个类被声明为 final 时,此类不能被继承,所有方法都不能被重写。但这并不表示 final 类的成员变量也是不可改变的,要想做到 final 类的成员变量不可改变,必须给成员变量增加 final 修饰。值得注意的是,一个类不能既被声明为 abstract,又被声明为 final。
2)finally 作为异常处理的一部分,它只能用在 try/catch 语句中,并且附带一个语句块,表示这段语句最终一定被执行,经常被用在需要释放资源的情况下。
3)finalize 是 Object 类的一个方法,在垃圾回收器执行时会调用被回收对象的 finalize()方法,可以覆盖此方法来实现对其他资源的回收,例如关闭文件等。需要注意的是,一旦垃圾回收器准备好释放对象占用的空间,将首先调用其 finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
4.3.4 assert 有什么作用
断言(assert)作为一种软件调试的方法,提供了一种在代码中进行正确性检查的机制,目前很多开发语言都支持这种机制。它的主要作用是对一个 boolean 表达式进行检查,一个正确运行的程序必须保证这个 boolean 表达式的值为 true,若 boolean 表达式的值为 false,则说明程序已经处于一种不正确的状态下,系统需要提供告警信息并且退出程序。在实际的开发中,assert 主要用来保证程序的正确性,通常在程序开发和测试时使用。为了提高程序运行的效率,在软件发布后,assert 检查默认是被关闭的。
static 关键字主要有两种作用:第一,为某特定数据类型或对象分配单一的存储空间,而与创建对象的个数无关。第二,实现某个方法或属性与类而不是对象关联在一起,也就是说,在不创建对象的情况下就可以通过类来直接调用方法或使用类的属性。具体而言,在 Java 语言中,static 主要有 4 种使用情况:成员变量、成员方法、代码块和内部类。
(1)static 成员变量
虽然 Java 语言中没有全局的概念,但可以通过 static 关键字来达到全局的效果。Java 类提供了两种类型的变量:用 static 关键字修饰的静态变量和不用 static 关键字修饰的实例变量。静态变量属于类,在内存中只有一个复制(所有实例都指向同一个内存地址),只要静态变量所在的类被加载,这个静态变量就会被分配空间,因此就可以被使用了。对静态变量的引用有两种方式,分别为「类.静态变量」
静态变量只有一个,被类拥有,所有对象都共享这个静态变量,而实例对象是与具体对象相关的。
(2)static 成员方法
与变量类似,Java 类同时也提供了 static 方法与非 static 方法。static 方法是类的方法,不需要创建对象就可以被调用,而非 static 方法是对象的方法,只有对象被创建出来后才可以被使用。
static 方法中不能使用 this 和 super 关键字,不能调用非 static 方法,只能访问所属类的静态成员变量和成员方法,因为当 static 方法被调用时,这个类的对象可能还没被创建,即使已经被创建了,也无法确定调用哪个对象的方法。同理,static 方法也不能访问非 static 类型的变量。
static 一个很重要的用途是实现单例模式。单例模式的特点是该类只能有一个实例,为了实现这一功能,必须隐藏类的构造函数,即把构造函数声明为 private,并提供一个创建对象的方法,由于构造对象被声明为 private,外界无法直接创建这个类型的对象,只能通过该类提供的方法来获取类的对象,要达到这样的目的只能把创建对象的方法声明为 static,程序示例如下:
用 public 修饰的 static 变量和方法本质上都是全局的,若在 static 变量前用 private 修饰,则表示这个变量可以在类的静态代码块或者类的其他静态成员方法中使用,但是不能在其他类中通过类名来直接引用。
(3)static 代码块
static 代码块(静态代码块)在类中是独立于成员变量和成员函数的代码块的。它不在任何一个方法体内,JVM 在加载类时会执行 static 代码块,如果有多个 static 代码块,JVM 将会按顺序来执行。static 代码块经常被用来初始化静态变量。需要注意的是,这些 static 代码块只会被执行一次,示例如下:
(4)static 内部类
static 内部类是指被声明为 static 的内部类,它可以不依赖于外部类实例对象而被实例化,而通常的内部类需要在外部类实例化后才能实例化。静态内部类不能与外部类有相同的名字,不能访问外部类的普通成员变量,只能访问外部类中的静态成员和静态方法(包括私有类型),示例如下:
2.static 与 final 结合使用表示什么意思?
在 Java 语言中,static 关键字常与 final 关键字结合使用,用来修饰成员变量与成员方法,有点类似于 C/C++ 语言中的「全局常量」。对于变量,若使用 static final 修饰,则表示一旦赋值,就不可修改,并且通过类名可以访问。
4.3.6 使用 switch 时有哪些注意事项
switch 语句用于多分支选择,在使用 switch(expr)时,expr 只能是一个枚举常量(内部也是由整型或字符类型实现)或一个整数表达式,其中整数表达式可以是基本类型 int 或其对应的包装类 Integer,当然也包括不同的长度整型,例如 short。由于 byte、short 和 char 类型的值都能够被隐式地转换为 int 类型,因此这些类型以及它们对应的包装类型都可以作为 switch 的表达式。但是,long、float、double、String 类型不能够隐式地转换为 int 类型,因此它们不能被用作 switch 的表达式。如果一定要使用 long、float 或 double 作为 switch 的参数,必须将其强制转换为 int 型才可以。
JDK5开始支持Enum枚举类型。###27.15_JDK5新特性(枚举的注意事项)
从本质上来讲,switch 对字符串的支持,其实是 int 类型值的匹配。它的实现原理如下:通过对 case 后面的 String 对象调用 hashCode()方法,得到一个 int 类型的 hash 值,然后用这个 hash 值来唯一标识这个 case。那么当匹配时,首先调用这个字符串 hashCode()函数,获取一个 hash 值(int 类型),用这个 hash 值来匹配所有 case,如果没有匹配成功,说明不存在;如果匹配成功了,接着会调用字符串的 String.equals()方法进行匹配(至于为什么需要调用 e-quals()方法,请参照 4.5.2 节内容)。由此可以看出,String 变量不能为 null,同时,switch 的 case 子句中使用的字符串也不能为 null。
在使用 switch 时,需要注意另外一个问题:一般必须在 case 语句结尾添加 break 语句。因为一旦通过 switch 语句确定了入口点,就会顺序执行后面的代码,直到遇到关键字 break。否则,会执行满足这个 case 之后的其他 case 的语句而不管 case 是否匹配,直到 switch 结束或者遇到 break 为止。如果在 switch 中省略了 break 语句,那么匹配的 case 值后的所有情况(包括 default 情况)都会被执行。
在用 Java 语言编写的程序中,有时为了提高程序的运行效率,编译器会自动对其进行优化,把经常被访问的变量缓存起来,程序在读取这个变量时有可能会直接从缓存(例如寄存器)中来读取这个值,而不会去内存中读取。这样做的一个好处是提高了程序的运行效率,但当遇到多线程编程时,变量的值可能因为别的线程而改变了,而该缓存的值不会相应改变,从而造成应用程序读取的值和实际的变量值不一致,例如,在本次线程内,当读取一个变量时,为提高存取速度,会先把变量读取到一个缓存中,当以后再取变量值时,就直接从缓存中取值,当变量值在本线程里改变时,会同时把变量的新值复制到该缓存中,以便保持一致。
volatile 是一个类型修饰符(type specifier),它是被设计用来修饰被不同线程访问和修改的变量。被 volatile 类型定义的变量,系统每次用到它时都是直接从对应的内存当中提取,而不会利用缓存。在使用了 volatile 修饰成员变量后,所有线程在任何时候所看到变量的值都是相同的。下面给出一个使用 volatile 的示例。
需要注意的是,由于 volatile 不能保证操作的原子性,因此,一般情况下 volatile 不能代替 sychronized。此外,使用 volatile 会阻止编译器对代码的优化,因此会降低程序的执行效率。所以,除非迫不得已,否则,能不使用 volatile 就尽量不要使用 volatile。
instanceof 是 Java 语言中的一个二元运算符,它的作用是判断一个引用类型的变量所指向的对象是否是一个类(或接口、抽象类、父类)的实例,即它左边的对象是否是它右边的类的实例。该运算符返回 boolean 类型的数据。
4.3.9 strictfp 有什么作用
关键字 strictfp 是 strict float point 的缩写,指的是精确浮点,它用来确保浮点数运算的准确性。JVM 在执行浮点数运算时,如果没有指定 strictfp 关键字,此时计算结果可能会不精确,而且计算结果在不同平台或厂商的虚拟机上会有不同的结果,导致意想不到的错误。而一旦使用了 strictfp 来声明一个类、接口或者方法,那么在所声明的范围内,Java 编译器以及运行环境会完全依照 IEEE 二进制浮点数算术标准(IEEE 754)来执行,在这个关键字声明的范围内所有浮点数的计算都是精确的。需要注意的是,当一个类被 strictfp 修饰时,所有方法都会自动被 strictfp 修饰。因此,strictfp 可以保证浮点数运算的精确性,而且在不同的硬件平台上会有一致的运行结果。下例给出了 strictfp 修饰类的使用方法: