1.Java中的数据类型int、double等不是对象,无法通过向上转型获取到Object提供的方法,
而像String却可以,只因为String是一个对象而不是一个类型
2.基本数据类型由于这样的特性,导致无法参与转型、泛型、反射等过程
3.为了弥补这个缺陷,Java提供了包装类(将基本的数据类型以及一些辅助方法包装到类中)
主要将基本数据类型封装在包装类中,如int类数值包装类Integer,boolean型的包装类Boolean等
包装类及其对应的基本数据类型(java.lang)
包装类 | 对应基本数据类型 |
---|---|
Byte | byte |
Short | short |
Integer | int |
Long | long |
Float | float |
Double | double |
Character | char |
Boolean | Boolean |
Byte类、Short类、Integer类和Long类,将byte、short、int、long封装为一个类,由于这些都是Number的子类,区别是封装不同的数据类型,包含的方法基本相同。 |
(1)基本类型:byte,short,int,long,boolean,float,double,char
(2)引用类型:所有class和interface类型
引用类型可以赋值为null,表示空;基本类型不能赋值为null
把int基本类型变成一个引用类型,可以定义一个Integer类,它只包含一个实例字段int,这样,Integer类就可以视为int的包装类(Wrapper Class)
public class Integer {
private int value;
public Integer(int value) {
this.value = value;
}
public int intValue() {
return this.value;
}
}
直接把int变为Integer的赋值写法。基本类型变为引用类型
把Integer变为int的赋值写法。引用类型变为基本类型
在Java SE5之前,要进行装箱,可以通过以下代码:
Integer i = new Integer(100);
在Java SE5中,为了减少开发人员的工作,Java提供了自动拆箱与自动装箱功能
Integer i=100;
i为一个Integer类型的引用,100为Java中的基础数据类型(primitive data type)。而这种直接将一个基础数据类型传给其相应的封装类(wrapper class)的做法,便是自动装箱(Autoboxing)
装箱:JDK完成了调用Integer.valueOf(100)
拆箱:JDK自动完成了对Integer.intValue()的调用
区别:基本类型效率更高,包装类型的对象却可以携带更多的信息
注意:自动装箱和自动拆箱只发生在编译阶段,目的是为了少写代码
装箱和拆箱会影响代码的执行效率,因为编译后的class代码是严格区分基本类型和引用类型的。并且自动拆箱执行时可能会报NullPointerException。
所有的包装类型都是不变类。一旦创建了Integer对象,该对象就是不变的。对两个Integer实例进行比较要特别注意:绝对不能用“==”比较,因为Integer是引用类型,必须使用equals()比较。
Integer x = 127;
Integer y = 127;
Integer m = 99999;
Integer n = 99999;
System.out.println("x == y: " + (x == y)); // true
System.out.println("m == n: " + (m == n)); // false
System.out.println("x.equals(y): " + x.equals(y)); // true
System.out.println("m.equals(n): " + m.equals(n)); // true
==比较,较小的两个相同的Integer返回true,较大的两个相同的Integer返回false
因为Integer是不变类,编译器把Integer x = 127;自动变为Integer x = Integer.valueOf(127);,为了节省内存,Integer.valueOf()对于较小的数,始终返回相同的实例,因此,比较“恰好”为true,但绝不能因为Java标准库的Integer内部有缓存优化就用“”比较,必须用equals()方法比较两个Integer
所有的整数和浮点数的包装类型都继承自Number,因此,可以非常方便地直接通过包装类型获取各种基本类型:
// 向上转型为Number:
Number num = new Integer(999);
// 获取byte, int, long, float, double:
byte b = num.byteValue();
int n = num.intValue();
long ln = num.longValue();
float f = num.floatValue();
double d = num.doubleValue();
注意:在计算机内存中,只用二进制表示,不存在十进制或十六进制的表示方法。在内存中总是以4字节的二进制表示
程序设计的一个重要原则:数据的存储和显示要分离
处理无符号整型
在Java中,并没有无符号整型(Unsigned)的基本数据类型。byte、short、int和long都是带符号整型,最高位是符号位。而C语言则提供了CPU支持的全部数据类型,包括无符号整型。无符号整型和有符号整型的转换在Java中就需要借助包装类型的静态方法完成。
byte是有符号整型,范围是-128 ~ +127,但如果把byte看作无符号整型,它的范围就是0~255。一个负的byte按无符号整型转换为int。
public class Main {
public static void main(String[] args) {
byte x = -1;
byte y = 127;
System.out.println(Byte.toUnsignedInt(x)); // 255
System.out.println(Byte.toUnsignedInt(y)); // 127
}
}
(1)Java核心库提供的包装类型可以把基本类型包装为class
(2)自动装箱和自动拆箱都是在编译期完成的(JDK>=1.5)
(3)装箱和拆箱会影响执行效率,且拆箱时可能发生NullPointerException
(4)包装类型的比较必须使用equals()
(5)整数和浮点数的包装类型都继承自Number
(6)包装类型提供了大量实用方法
Integer(int number) 以一个int型变量作为参数创建Integer对象
Integer number=new Integer(7);
Integer(String str) 以一个String型变量作为参数创建Integer对象
Integer number=new Integer(“16”);
**注意:**如果要使用字符串变量创建Integer对象,字符串变量一定要是数值型的,否则会抛出NumberFormatException异常。
方法 | 描述 |
---|---|
Integer valueOf(String str) | 返回保存指定的String值的Integer对象 |
int parseInt(String str) | 返回包含在由str指定的字符串的数字的等价整数值 |
String toString() | 返回一个表示该Integer值的String对象(可以指定进制基数) |
String toBinaryString(int i) | 以二进制无符号整数形式返回一个整数参数的字符串表达形式 |
String toHexString(int i) | 十六进制无符号整数形式返回一个整数参数的字符串表达形式 |
String toOctalString(int i) | 以八进制无符号整数形式返回一个整数参数的字符串表达形式 |
boolean equals(Object IntegerObj) | 比较此对象与指定的对象是否相等 |
int intValue() | 以int类型返回此Integer对象 |
short shortValue() | 以short类型返回此Integer对象 |
byte byteValue() | 以byte类型返回此Integer对象 |
int compareTo(Integeranother Integer) | Integeranother相当于坐标原点 在数字上比较两个Integer对象,如果这两个相等,则返回0;如果调用对象的数值小于Integeranother的数值,则返回负值;如果调用对象的数值大于anotherInteger的数值,则返回正值 |
Integer提供了4个常量
常量 | 描述 |
---|---|
MAX_VALUE | 表示int类型的最大值2^31-1 |
MIN_VALUE | 表示int类型的最小值-2^31 |
SIZE | 二进制补码形式表示int值的位数 |
TYPE | 表示基本数据类型int的Class实例 |
(1)BigInteger用于表示任意大小的整数
(2)BigInteger是不变类,并且继承自Number
(3)将BigInteger转换成基本类型时可使用longValueExact()等方法保证结果准确
由CPU原生提供的整型最大范围是64位long型整数。使用long型整数可以直接通过CPU指令进行计算,速度非常快。
对BigInteger做运算的时候,只能使用实例方法,例如,加法运算。
BigInteger i1 = new BigInteger("1234567890");
BigInteger i2 = new BigInteger("12345678901234567890");
BigInteger sum = i1.add(i2); // 12345678902469135780
和long型整数运算比,BigInteger不会有范围限制,但缺点是速度比较慢
也可以把BigInteger转换成long型:]
BigInteger i = new BigInteger("123456789000");
System.out.println(i.longValue()); // 123456789000
System.out.println(i.multiply(i).longValueExact());
// java.lang.ArithmeticException: BigInteger out of long range
使用longValueExact()方法时,如果超出了long型的范围,会抛出ArithmeticException
BigInteger和Integer、Long一样,也是不可变类,并且也继承自Number类。因为Number定义了转换为基本类型的几个方法。
方法 | 描述 |
---|---|
byteValue() | 转换为byte |
shortValue() | 转换为short |
intValue() | 转换为int |
longValue() | 转换为long |
floatValue() | 转换为float |
doubleValue() | 转换为double |
因此,通过上述方法,可以把BigInteger转换成基本类型。如果BigInteger表示的范围超过了基本类型的范围,转换时将丢失高位信息,即结果不一定是准确的。如果需要准确地转换成基本类型,可以使用intValueExact()、longValueExact()等方法,在转换时如果超出范围,将直接抛出ArithmeticException异常。 |
如果BigInteger的值甚至超过了float的最大范围(3.4x1038),那么返回的float是什么呢?
public class Main {
public static void main(String[] args) {
BigInteger n = new BigInteger("999999").pow(99);
float f = n.floatValue();
System.out.println(f);
}
}
Float类在一个对象中包含一个原始类型float的值。类型为Float的对象包含一个单一字段,其类型为float。此外,该类还提供了几种将float转换为String和String转换为float,以及在处理float时有用的其他常数和方法。
Float(double value) 构造一个新分配 Float对象,它表示转换为类型参数float
Float(float value) 构造一个新分配的 Float对象,该对象表示基元 float参数
Float(String s) 构造一个新分配 Float对象,它表示类型的浮点值 float用字符串表示
浮点数都是以二进制数的形式存储的,这样就会产生一个问题,有许多的小数无法被准确的表示。如同十进制无法准确表示 1/3 那样,二进制也有许多无法精确表示的数,计算机只能进行舍入,取近似值来表示
// 以double参数创建Double类对象
Double number=new Double(3.14);
// 以String型变量作为参数获取Double对象
Double number=new Double(“3.14”);
方法 | 描述 |
---|---|
double valueOf(String str) | 返回保存用参数字符串str表示的double值的Double对象 |
double parseDoble(String s) | 返回一个新的double值,该值被初始化为指定String表示的值,这与Double的valueOf方法一样 |
double doubleValue() | 以double形式返回此Double对象 |
boolean isNaN() | 如果此double值是非数字(NaN)值,则返回true;否则返回false |
int intValue() | 以int形式返回double值 |
byte byteValue() | 以byte形式返回Double对象值(通过强制转换) |
long longValue() | 以long形式返回此double的值(通过强制转换为long类型) |
int compareTo(Double d) | 对两个Double对象进行数值比较。如果两个值相等,则返回0;如果调用对象的数值小于d的数值,则返回负值;如果调用的对象大于d的值,则返回正值 |
boolean equals(Object ojb) | 将此对象与指定的对象比较 |
String toString() | 返回此Double对象的字符串表示形式 |
String toHexString(double d) | 返回double参数的十六进制字符串表示形式 |
常量 | 描述 |
---|---|
MAX_EXPONENT | 返回int值,表示有限double变量可能具有最大的指数 |
MIN_EXPONENT | 返回int值,表示标准化double变量可能具有最小的指数 |
NEGATIVE_INFINITY | 返回double值,表示保存double类型的负无穷大值的常量 |
POSITIVE_INFINITY | 返回double值,表示保存double类型的正无穷大值的常量 |
和BigInteger类似,BigDecimal可以表示一个任意大小且精度完全准确的浮点数
BigDecimal bd = new BigDecimal("123.4567");
System.out.println(bd.multiply(bd)); // 15241.55677489
//BigDecimal用scale()表示小数位数
BigDecimal d1 = new BigDecimal("123.45");
BigDecimal d2 = new BigDecimal("123.4500");
BigDecimal d3 = new BigDecimal("1234500");
System.out.println(d1.scale()); // 2,两位小数
System.out.println(d2.scale()); // 4
System.out.println(d3.scale()); // 0
通过BigDecimal的stripTrailingZeros()方法,可以将一个BigDecimal格式化为一个相等的,但去掉了末尾0的BigDecimal:
BigDecimal d1 = new BigDecimal("123.4500");
BigDecimal d2 = d1.stripTrailingZeros();
System.out.println(d1.scale()); // 4
System.out.println(d2.scale()); // 2,因为去掉了00
BigDecimal d3 = new BigDecimal("1234500");
BigDecimal d4 = d3.stripTrailingZeros();
System.out.println(d3.scale()); // 0
System.out.println(d4.scale()); // -2
如果一个BigDecimal的scale()返回负数,例如,-2,表示这个数是个整数,并且末尾有2个0
可以对一个BigDecimal设置它的scale,如果精度比原始值低,那么按照指定的方法进行四舍五入或者直接截断
import java.math.BigDecimal;
import java.math.RoundingMode;
public class Main {
public static void main(String[] args) {
BigDecimal d1 = new BigDecimal("123.456789");
// 四舍五入,123.4568
BigDecimal d2 = d1.setScale(4, RoundingMode.HALF_UP);
// 直接截断,123.4567
BigDecimal d3 = d1.setScale(4, RoundingMode.DOWN);
System.out.println(d2);
System.out.println(d3);
}
}
Boolean类将基本类型为boolean的值包装在一个对象中,一个Boolean类型的对象只包含一个类型为boolean的字段,此类还为boolean和String的相互转换提供了许多方法,并提供了处理boolean时非常有用的其他常量和方法
// 该方法创建一个表示value参数的Boolean对象
new Boolean(boolean value);
// 该方法以String变量作为参数创建Boolean对象,如果String参数不为null且在忽略大小时等于true,则分配一个表示true值得Boolean对象,否则获得一个false值得Boolean对象
new Boolean(String str);
方法 | 描述 |
---|---|
booleanValue() | 将Boolean对象的值以对应的boolean值返回 |
equals(Object obj) | 判断调用该方法的对象与obj是否相等,仅当参数不是null,而且与调用该方法的对象一样都表示同一个boolean值的Boolean对象时,才返回true |
parseBoolean(String s) | 将字符串参数解析为boolean值 |
valueOf(String s) | 返回一个用指定的字符串表示值的boolean值 |
toString() | 返回表示该boolean值的String对象 |
常量 | 描述 |
---|---|
TRUE | 对应基值true的Boolean对象 |
FALSE | 对应基值false的Boolean对象 |
TYPE | 基本类型boolean的Class对象 |
// 该类的构造方法的参数必须是一个char类型的数据,将一个char类型数据包装成一个Character类对象;一旦Character类被创建,它包含的数值就不能改变了
new Character(char value);
new Character mychar=new Character(‘s’);
方法 | 描述 |
---|---|
int compareTo(Character anotherCharacter) | 根据数字比较两个Character对象,若两个对象相等则返回0 |
boolean equals(Object obj) | 将调用该方法的对象与指定的对象项比较 |
char toUpperCase(char ch) | 将字符参数转换为大写 |
char toLowerCase(Char ch) | 将字符参数转换为小写 |
String toString() | 返回一个表示指定char值的对象 |
char charValue() | 返回此Character对象的值 |
boolean isUpperCase(char ch) | 判断指定字符是否是大写字符 |
boolean isLowerCase(char ch) | 判断指定字符是否为小写字符 |
boolean isLetter(char ch) | 判断指定字符是否为字母 |
boolean isDigit(char ch) | 判断指定字符是否为数字 |
常量 | 描述 |
---|---|
CONNECTOR_PUNCTUATION | 返回byte型值,表示Unicode规范中的常规类别“Pc.” |
UNASSIGNED | 返回byte型值,表示Unicode规范中的常规类别“Cn.” |
TITLECASE_LETTER | 返回byte型值,表示Unicode规范中的常规类别“Lt.” |
对于数值型的包装类,他们有一个共同的父类(Number类);该类是个抽象类,它是Byte、Interger、Short、Long、Float、Double类的父类,其子类必须提供将表示的数值转换为byte、short、int、long、float、double的方法
数值型包装类的共有方法
方法 | 描述 |
---|---|
xxxValue() | 以xxx形式返回指定的数值 |
xxx为八种基本数据类型(上所列,有不包含)
系统默认调用(就是默认导入这个包),提供了许多的数学函数;主要包括三角函数方法、指数函数方法、取整数函数方法、取最大值、最小值、绝对值等;这些方法都被定义为static形式
常量 | 描述 |
---|---|
Math.PI | 圆周率的值 |
Math.E | 自然对数底数e的值 |
方法 | 返回值 | 功能 |
---|---|---|
sin(double a) | Double 返回角的三角正弦 | |
cos(double a) | 返回角的三角余弦 | |
tan(double a) | 返回角的三角正切 | |
asin(double a) | 返回一个值的反正弦 | |
acos(double a) | 返回一个值的反余弦 | |
atan(double a) | 返回一个值的反正切 | |
toRadians(double angdeg) | 将角度转换为弧度 | |
toDegrees(double angrad) | 将弧度转换为角度 |
方法 | 返回值 | 功能 |
---|---|---|
exp(double a) | Double 用于获取e的a次方,即取e^a | |
log(double a) | 用于取自然对数,即取ln a的值 | |
log10(double a) | 用于取底数为10的对数 | |
sqrt(double a) | 用于取a的平方根,其中a的值不能为负值 | |
cbrt(double a) | 用于取a的立方根 | |
pow(double a,double b) | 用于取a的b次方 |
方法 | 返回值 | 功能 |
---|---|---|
ceil(double a) | Double 返回大于等于参数的最小整数 | |
floor(double a) | 返回小于等于参数的最大整数 | |
rint(double a) | 返回与参数最接近的整数,如果两个同为整数且同样接近,则结果取偶数 | |
round(float a) | 将参数加上0.5后返回与参数最近的整数 | |
Round(double a) | 将参数加上0.5后返回与参数最近的整数,然后强制转换为长整型 |
方法 | 功能 |
---|---|
Double max(double a,double b) | 取a与b之间的最大值 |
int min(int a,int b) | 取a与b之间的最小值,参数为整型 |
long min(long a,long b) | 取a与b之间的最小值,参数为长整型 |
float min(float a,float b) | 取a与b之间的最小值,参数为浮点型 |
Double min(double a,double b) | 取a与b之间的最小值,参数为双精度型 |
int abs(int a) | 返回整型参数的绝对值 |
long abs(long a) | 返回长整型参数的绝对值 |
float abs(float a) | 返回浮点型参数的绝对值 |
Double abs(double a) | 返回双精度参数的绝对值 |
方法 | 功能 |
---|---|
Math.random() | 取值范围:0<=Math.random()<1.0 类型:double类型随机数 |
除了Math类中的random()方法可以产生随机数之外,Java还提供了一种可以获取随机数的方式
Random用来创建伪随机数。所谓伪随机数,是指只要给定一个初始的种子,产生的随机数序列是完全一样的。
要生成一个随机数,可以使用nextInt()、nextLong()、nextFloat()、nextDouble()
Random r = new Random();
Random r = new Random(seedValue);
r:Random类对象
seedValue:随机数生成器种子
以这种方式实例化对象时,Java编译器以系统当前时间作为随机数生成器的种子,因为每时每刻的事件不可能相同,所以生成的随机数将不同,但是运行速度太快,也会生成两次运行结果相同的随机数。
方法 | 功能 |
---|---|
int nextInt() | 返回一个随机整数 |
int nextInt(int n) | 返回一个大于等于0小于n的随机数 |
long nextLong() | 返回一个随机长整型值 |
boolean nextBoolean() | 返回一个数据布尔值 |
float nextFloat() | 返回一个随机浮点型值 |
Double nextDouble() | 返回一个随机双精度型值 |
Double nextGaussian() | 返回一个概率密度为高斯分布的双精度值 |
有伪随机数,就有真随机数。实际上真正的真随机数只能通过量子力学原理来获取,而想要的是一个不可预测的安全的随机数,SecureRandom就是用来创建安全的随机数的(java.security.SecureRandom;)
SecureRandom sr = new SecureRandom();
System.out.println(sr.nextInt(100));
SecureRandom无法指定种子,它使用RNG(random number generator)算法。JDK的SecureRandom实际上有多种不同的底层实现,有的使用安全随机种子加上伪随机数算法来产生安全的随机数,有的使用真正的随机数生成器。实际使用的时候,可以优先获取高强度的安全随机数生成器,如果没有提供,再使用普通等级的安全随机数生成器:
// 获取高强度安全随机数生成器
SecureRandom sr = SecureRandom.getInstanceStrong();
SecureRandom sr = new SecureRandom(); // 获取普通的安全随机数生成器
byte[] buffer = new byte[16];
sr.nextBytes(buffer); // 用安全随机数填充buffer
System.out.println(Arrays.toString(buffer));
SecureRandom的安全性是通过操作系统提供的安全的随机种子来生成随机数。这个种子是通过CPU的热噪声、读写磁盘的字节、网络流量等各种随机事件产生的“熵”
在密码学中,安全的随机数非常重要。如果使用不安全的伪随机数,所有加密体系都将被攻破。因此,时刻牢记必须使用SecureRandom来产生安全的随机数
需要使用安全随机数的时候,必须使用SecureRandom,绝不能使用Random