final关键字在java中有三个用途用途:
1.用final修饰的类不能被继承。
2.用final修饰的变量不可以被修改。
3.用final修饰的方法不可以被重写。
这些都是java语法中所规定的,我最近在看一本叫做《核心java》的书,让我受益匪浅,在这就和大家聊一下final的用法。
如果一个常量在一个类的多个方法中用到,那么就可以在类范围内声明一个用final修饰的常量,如下代码
*/
public static class CircleToolsBetter {
/** A value for PI. */
public static final double PI = 3.141;
/**
* Calculate the area of the circle with the given radius.
*
* @param radius The radius of the circle.
*
* @return The calculated area.
*/
public double getCircleArea(final double radius) {
return (Math.pow(radius, 2) * PI);
}
/**
* Calculate the circumference of the circle with the given radius.
*
* @param radius The radius of the circle.
*
* @return The calculated circumference.
*/
public double getCircleCircumference(final double radius) {
return ((radius * 2) * PI);
}
/**
* Calculate the extruded volume of the circle with the given radius.
*
* @param radius The radius of the circle.
* @param height The height of the cylinder to extrude
*
* @return The calculated circumference.
*/
public double getCircleExtrudedVolume(final double radius, final double height) {
return ((radius * 2 * height) * PI);
}
}
在多个方法中用到那么它的范围为类范围的常量,这样程序会显得更直观,用public修饰说明在其它的类中可以被调用,有一点需要注意 被 final static 修饰的 类范围的常量是在程序编译的时候分配到值的,如果在其它的类中用到了它,那么用到常量的这个类和常量所在的这个类需要一块进行编译,不然如果在代码中修改了常量的值而只编译了常量所的类的话,那么用到常量的另一个类中的值还是之前没有修改过的那个常量的值。这是非常危险的事情。
没必要把所有的常量的范围都定义为类范围,如果一个常量只在一个方法中用到了一次,那么完全没必要定义为类范围的常量,那样会消耗内存的。比如下面的代码:
public class SomeClassBetter {
/** Contains a constant for both equations. */
private static final double M = 9.3;
/**
* Calculate the results of an equation.
*
* @param inputValue Input to the equation.
*
* @return result of the equation.
*/
public double equation1(final double inputValue) {
final double K = 3.141;
final double X = 15.0;
return (((Math.pow(inputValue, 2.0d) / K) + X) / M);
}
/**
* Calculate the results of an equation.
*
* @param inputValue Input to the equation.
*
* @return result of the equation.
*/
public double equation2(final double inputValue) {
final double K = 1.414;
final double X = 45.0;
return (((Math.pow(inputValue, 3.0d) * K) + X) * M);
}
}
}
因为k,x这些变量只用到了一次,那么完全可以定义到方法内部,方法内部的常量在方法被调用的时候才会被创建,而调用结束会,又会被销毁。同时注意到,在上述代码中两个方法的参数都用到了final关键字,这是非常可取的一点。如果你传过来的参数一定不能被改变,那么final关键字是非常有用的,如果除了你之外的人在不知情的情况下贸然尝试在代码中修改你的参数,那么final关键字将会在编译的时候去阻止他,也许就能避免一场灾难了。
有时候final修饰的集合可能并不能让我们如愿:
public static class Rainbow {
/** The set of valid colors of the rainbow. */
public static final Set VALID_COLORS;
static {
VALID_COLORS = new HashSet();
VALID_COLORS.add(Color.red);
VALID_COLORS.add(Color.orange);
VALID_COLORS.add(Color.yellow);
VALID_COLORS.add(Color.green);
VALID_COLORS.add(Color.blue);
VALID_COLORS.add(Color.decode("#4B0082")); // indigo
VALID_COLORS.add(Color.decode("#8A2BE2")); // violet
}
/**
* A demo method.
*/
public static final void someMethod() {
Set colors = Rainbow.VALID_COLORS;
colors.add(Color.black); // <= logic error but allowed by compiler
System.out.println(colors);
}
}
在上述代码中VALID_COLORS虽然被声明为常量,那变量本身是不可变的,但是如果在其它的地方还有指向这个变量所指的内存的话,那么其它地方的变量将不受final的约束,那么通过这样的方式就可以去修改Rainbow中所谓的不可变的集合了。这也是很危险的。那么如何解决呢,看下面的代码:
public static class RainbowBetter {
/** The valid colors of the rainbow. */
public static final Set VALID_COLORS;
static {
Set temp = new HashSet();
temp.add(Color.red);
temp.add(Color.orange);
temp.add(Color.yellow);
temp.add(Color.green);
temp.add(Color.blue);
temp.add(Color.decode("#4B0082")); // indigo
temp.add(Color.decode("#8A2BE2")); // violet
VALID_COLORS = Collections.unmodifiableSet(temp);
}
/**
* Some demo method.
*/
public static final void someMethod() {
Set colors = RainbowBetter.VALID_COLORS;
colors.add(Color.black); // <= exception here
System.out.println(colors);
}
}
我们可以先定义一个临时集合,当这个临时集合初始化之后,再用Collections.unmodifiableSet()函数来将集合的内容锁住,那么无论再用什么用的方式去修改它的话,都会报异常。这样就可以避免错误的发生。