深入学习java源码之Math.scalb()与 Math.powerOfTwoF()
final关键字
final在Java中是一个保留的关键字,可以声明成员变量、方法、类以及本地变量。一旦你将引用声明作final,你将不能改变这个引用了,编译器会检查代码,如果你试图将变量再次初始化的话,编译器会报编译错误
凡是对成员变量或者本地变量(在方法中的或者代码块中的变量称为本地变量)声明为final的都叫作final变量。final变量经常和static关键字一起使用,作为常量。
final也可以声明方法。方法前面加上final关键字,代表这个方法不可以被子类的方法重写。如果你认为一个方法的功能已经足够完整了,子类中不需要改变的话,你可以声明此方法为final。final方法比非final方法要快,因为在编译的时候已经静态绑定了,不需要在运行时再动态绑定。
使用final来修饰的类叫作final类。final类通常功能是完整的,它们不能被继承。Java中有许多类是final的,譬如String, Interger以及其他包装类。
final关键字的好处
- final关键字提高了性能。JVM和Java应用都会缓存final变量。
- final变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销。
- 使用final关键字,JVM会对方法、变量及类进行优化。
创建不可变类要使用final关键字。不可变类是指它的对象一旦被创建了就不能被更改了。String是不可变类的代表。不可变类有很多好处,譬如它们的对象是只读的,可以在多线程环境下安全的共享,不用额外的同步开销等等。
java中的assert(断言)
在Java中,assert关键字是从JAVA SE 1.4 引入的,为了避免和老版本的Java代码中使用了assert关键字导致错误,Java在执行的时候默认是不启动断言检查的(这个时候,所有的断言语句都 将忽略!),如果要开启断言检查,则需要用开关-enableassertions或-ea来开启。
assert关键字语法很简单,有两种用法:
1、assert <boolean表达式>
如果<boolean表达式>为true,则程序继续执行。
如果为false,则程序抛出AssertionError,并终止执行。
2、assert <boolean表达式> : <错误信息表达式>
如果<boolean表达式>为true,则程序继续执行。
如果为false,则程序抛出java.lang.AssertionError,并输入<错误信息表达式>。
1、assert关键字需要在运行时候显式开启才能生效,否则你的断言就没有任何意义。而现在主流的Java IDE工具默认都没有开启-ea断言检查功能。这就意味着你如果使用IDE工具编码,调试运行时候会有一定的麻烦。并且,对于Java Web应用,程序代码都是部署在容器里面,你没法直接去控制程序的运行,如果一定要开启-ea的开关,则需要更改Web容器的运行配置参数。这对程序的移 植和部署都带来很大的不便。
2、用assert代替if是陷阱之二。assert的判断和if语句差不多,但两者的作用有着本质的区别:assert关键字本意上是为测试 调试程序时使用的,但如果不小心用assert来控制了程序的业务流程,那在测试调试结束后去掉assert关键字就意味着修改了程序的正常的逻辑。
3、assert断言失败将面临程序的退出。这在一个生产环境下的应用是绝不能容忍的。一般都是通过异常处理来解决程序中潜在的错误。但是使用断言就很危险,一旦失败系统就挂了。
assert既然是为了调试测试程序用,不在正式生产环境下用,那应该考虑更好的测试JUint来代替其做用,JUint相对assert关键的所提供的功能是有过之而无不及。当然完全可以通过IDE debug来进行调试测试。在此看来,assert的前途一片昏暗。
因此,应当避免在Java中使用assert关键字,除非哪一天Java默认支持开启-ea的开关,这时候可以考虑。对比一下,assert能给你带来多少好处,多少麻烦,这是我们选择是否使用的的原则。
Modifier and Type | Method and Description |
---|---|
static double | scalb(double d, int scaleFactor) 返回 |
static float | scalb(float f, int scaleFactor) 返回 |
java源码
public final class Math {
private Math() {}
public static double scalb(double d, int scaleFactor) {
// magnitude of a power of two so large that scaling a finite
// nonzero value by it would be guaranteed to over or
// underflow; due to rounding, scaling down takes takes an
// additional power of two which is reflected here
final int MAX_SCALE = DoubleConsts.MAX_EXPONENT + -DoubleConsts.MIN_EXPONENT +
DoubleConsts.SIGNIFICAND_WIDTH + 1;
int exp_adjust = 0;
int scale_increment = 0;
double exp_delta = Double.NaN;
// Make sure scaling factor is in a reasonable range
if(scaleFactor < 0) {
scaleFactor = Math.max(scaleFactor, -MAX_SCALE);
scale_increment = -512;
exp_delta = twoToTheDoubleScaleDown;
}
else {
scaleFactor = Math.min(scaleFactor, MAX_SCALE);
scale_increment = 512;
exp_delta = twoToTheDoubleScaleUp;
}
// Calculate (scaleFactor % +/-512), 512 = 2^9, using
// technique from "Hacker's Delight" section 10-2.
int t = (scaleFactor >> 9-1) >>> 32 - 9;
exp_adjust = ((scaleFactor + t) & (512 -1)) - t;
d *= powerOfTwoD(exp_adjust);
scaleFactor -= exp_adjust;
while(scaleFactor != 0) {
d *= exp_delta;
scaleFactor -= scale_increment;
}
return d;
}
public static float scalb(float f, int scaleFactor) {
// magnitude of a power of two so large that scaling a finite
// nonzero value by it would be guaranteed to over or
// underflow; due to rounding, scaling down takes takes an
// additional power of two which is reflected here
final int MAX_SCALE = FloatConsts.MAX_EXPONENT + -FloatConsts.MIN_EXPONENT +
FloatConsts.SIGNIFICAND_WIDTH + 1;
// Make sure scaling factor is in a reasonable range
scaleFactor = Math.max(Math.min(scaleFactor, MAX_SCALE), -MAX_SCALE);
/*
* Since + MAX_SCALE for float fits well within the double
* exponent range and + float -> double conversion is exact
* the multiplication below will be exact. Therefore, the
* rounding that occurs when the double product is cast to
* float will be the correctly rounded float result. Since
* all operations other than the final multiply will be exact,
* it is not necessary to declare this method strictfp.
*/
return (float)((double)f*powerOfTwoD(scaleFactor));
}
// Constants used in scalb
static double twoToTheDoubleScaleUp = powerOfTwoD(512);
static double twoToTheDoubleScaleDown = powerOfTwoD(-512);
static double powerOfTwoD(int n) {
assert(n >= DoubleConsts.MIN_EXPONENT && n <= DoubleConsts.MAX_EXPONENT);
return Double.longBitsToDouble((((long)n + (long)DoubleConsts.EXP_BIAS) <<
(DoubleConsts.SIGNIFICAND_WIDTH-1))
& DoubleConsts.EXP_BIT_MASK);
}
static float powerOfTwoF(int n) {
assert(n >= FloatConsts.MIN_EXPONENT && n <= FloatConsts.MAX_EXPONENT);
return Float.intBitsToFloat(((n + FloatConsts.EXP_BIAS) <<
(FloatConsts.SIGNIFICAND_WIDTH-1))
& FloatConsts.EXP_BIT_MASK);
}
}
public final class StrictMath {
private StrictMath() {}
public static double scalb(double d, int scaleFactor) {
return Math.scalb(d, scaleFactor);
}
public static float scalb(float f, int scaleFactor) {
return Math.scalb(f, scaleFactor);
}
}