目录
一、Java类型分类
(一)内置数据类型
即Java基本数据类型,共有8种,6种数字类型(4个整数型,2个浮点型),一种字符类型,还有一种布尔型。
1.byte
byte 数据类型是8位、有符号的,以二进制补码表示的整数;
最小值是 -128(-2^7);
最大值是 127(2^7-1);
默认值是 0;
1B(byte,字节,简写为B)= 8 bit(位,简写为b);
1KB(Kibibyte)=1024byte;
byte 类型用在大型数组中节约空间,主要代替整数,因为 byte 变量占用的空间只有 int 类型的四分之一;
例子:byte a = 100,byte b = -50。
2.short
short 数据类型是 16 位、有符号的以二进制补码表示的整数;
最小值是 -32768(-2^15);
最大值是 32767(2^15 - 1);
Short 数据类型也可以像 byte 那样节省空间。一个short变量是int型变量所占空间的二分之一;
默认值是 0;
例子:short s = 1000,short r = -20000。
3.int
int 数据类型是32位、有符号的以二进制补码表示的整数;
最小值是 -2,147,483,648(-2^31);
最大值是 2,147,483,647(2^31 - 1);
一般地整型变量默认为 int 类型;
默认值是 0 ;
例子:int a = 100000, int b = -200000。
4.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 = -200000L。
"L"理论上不分大小写,但是若写成"l"容易与数字"1"混淆,不易分辩,最好大写。
5.float
float 数据类型是单精度、32位、符合IEEE 754标准的浮点数;
float 在储存大型浮点数组的时候可节省内存空间;
由于小数常量的默认类型是double型,所以float类型的后面一定要加f(F)。
默认值是 0.0f;
浮点数不能用来表示精确的值,如货币;
例子:float f1 = 234.5f。
6.double
double 数据类型是双精度、64 位、符合IEEE 754标准的浮点数;
浮点数的默认类型为double类型;
double类型同样不能表示精确的值,如货币;
默认值是 0.0d;
例子:double d1 = 123.4。
float和double参考:https://www.runoob.com/w3cnote/float-and-double-different.html
https://blog.csdn.net/weixin_41043145/article/details/93781928
精度丢失及解决:https://www.cnblogs.com/xujishou/p/7491932.html(使用BigDecmal)
decimal类型:https://www.cnblogs.com/chenweipeng/p/9627659.html
7.char
char类型是一个单一的 16 位 Unicode 字符;
最小值是 \u0000(即为0);
最大值是 \uffff(即为65,535);
char 数据类型可以储存任何字符;
例子:char letter = 'A';。
8.boolean
boolean数据类型表示一位的信息;
只有两个取值:true 和 false;
这种类型只作为一种标志来记录 true/false 情况;
默认值是 false;
例子:boolean one = true。
补充:对于数值类型的基本类型的取值范围,我们无需强制去记忆,因为它们的值都已经以常量的形式定义在对应的包装类中了(Boolean类型也有对应的类)。如下图:
(二)引用数据类型
即对象数据类型。在Java中,引用类型的变量非常类似于C/C++的指针。引用类型指向一个对象,指向对象的变量是引用变量。这些变量在声明时被指定为一个特定的类型,比如 Employee、Puppy 等。变量一旦声明后,类型就不能被改变。
Java有 5种引用类型(对象类型):类、接口、数组、枚举、标注。
1.所有引用类型的默认值都是null。
2.与基本数据类型对应的引用类型:
Byte,Short,Integer,Long,Float,Double,Character,Boolean
3.引用类型作为参数不改变值(详见值传递与引用传递)
引用类型的使用
JVM的内存空间:
(1).Heap 堆空间:分配对象 new Student()
(2).Stack 栈空间:临时变量 Student stu
(3).Code 代码区 :类的定义,静态资源 Student.class
Student stu = new Student(); //new在内存的堆空间创建对象
stu.study(); //把对象的地址赋给stu引用变量
上例实现步骤:
a.JVM加载Student.class 到Code区
b.new Student()在堆空间分配空间并创建一个Student实例
c.将此实例的地址赋值给引用stu,栈空间
(三)值传递与引用传递
1、基本类型作为参数传递时,是传递值的拷贝,无论你怎么改变这个拷贝,原值是不会改变的。
2、对象作为参数传递时,是把对象在内存中的地址拷贝了一份传给了参数。
示例1:
public class ReferencePkValue2 {
public static void main(String[] args) {
ReferencePkValue2 t = new ReferencePkValue2();
int a=99;
t.test1(a); //这里传递的参数a就是按值传递
System.out.println(a); //输出结果:99
MyObj obj=new MyObj();
t.test2(obj); //这里传递的参数obj就是引用传递
System.out.println(obj.b); //输出结果:100
}
public void test1(int a){
a=a++;
System.out.println(a);
}
public void test2(MyObj obj){
obj.b=100;
System.out.println(obj.b);
}
}
示例2:(数组也是引用传递)
public class Test {
String str = new String("good");
char[] ch = {'a', 'b', 'c'};
public static void main(String args[]) {
Test t = new Test();
t.change(t.str, t.ch);
System.out.print(t.str + " and ");
System.out.print(t.ch);
}
public void change(String str, char ch[]) {
str = "test ok";
ch[0] = 'g';
}
}
输出结果:good and gbc
示例3:(注意:String的 + 相当于生成了新对象)
public class ReferencePkValue1 {
public static void main(String[] args){
ReferencePkValue1 pk=new ReferencePkValue1();
//将地址拷贝一份传给函数的参数,此处的变量test1中存储的地址不变
String test1="Hello";
pk.change(test1);
System.out.println(test1); //输出结果:Hello
//StringBuffer和StringBuilder等是引用传递
StringBuffer test2=new StringBuffer("Hello");
pk.change(test2);
System.out.println(test2.toString()); //输出结果:Helloworld
}
public void change(String str){
str=str+"world";
}
public void change(StringBuffer str){
str.append("world");
}
}
(四)基本类型与包装类
Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的,这在实际使用时存在很多的不便,为了解决这个不足,在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class)。
1.在Java中有时候的运算必须是两个类对象之间进行的,不充许对象与数字之间进行运算。所以需要有一个对象,这个对象把数字进行了一下包装,这样这个对象就可以和另一个对象进行运算了。
2.对于包装类说,这些类的用途主要包含两种:
(1)作为和基本数据类型对应的类类型存在,方便涉及到对象的操作。
(2)包含每种基本数据类型的相关属性如最大值等,以及相关的操作方法。
3.Java基本类型存储在栈中,因此它们的存取速度要快于存储在堆中的对应包装类的实例对象。从Java5.0(1.5)开始,JAVA虚拟机(Java Virtual Machine)可以完成基本类型和它们对应包装类之间的自动转换。因此我们在赋值、参数传递以及数学运算的时候像使用基本类型一样使用它们的包装类,但这并不意味着你可以通过基本类型调用它们的包装类才具有的方法。另外,所有基本类型(包括void)的包装类都使用了final修饰,因此我们无法继承它们扩展新的类,也无法重写它们的任何方法。
(1)基本类型的优势:数据存储相对简单,运算效率比较高。
(2)包装类的优势:有的容易,比如集合的元素必须是对象类型,满足了Java一切皆是对象的思想。
4.int与Integer的区别
(1)Integer是int的包装类,int则是Java的一种基本数据类型
(2)Integer变量必须实例化后才能使用,而int变量不需要
(3)Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值
(4)Integer的默认值是null,int的默认值是0
延伸内容
(1)由于Integer变量实际上是对一个Integer对象的引用,所以两个通过new生成的Integer变量永远是不相等的(因为new生成的是两个对象,其内存地址不同)。
Integer i = new Integer(100);
Integer j = new Integer(100);
System.out.print(i == j); //false
(2)Integer变量和int变量比较时,只要两个变量的值是相等的,则结果为true。(因为包装类Integer和基本数据类型int比较时,Java会自动拆包装为int,然后进行比较,实际上就变为两个int变量的比较)
Integer i = new Integer(100);
int j = 100;
System.out.print(i == j); //true
Integer i = 100;
int j = 100;
System.out.print(i == j); //true
(3)非new生成的Integer变量和new Integer()生成的变量比较时,结果为false。(因为非new生成的Integer变量指向的是java常量池中的对象,而new Integer()生成的变量指向堆中新建的对象,两者在内存中的地址不同)
Integer i = new Integer(100);
Integer j = 100;
System.out.print(i == j); //false
(4)对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间-128到127之间,则比较结果为true,如果两个变量的值不在此区间,则比较结果为false。
Integer i = 100;
Integer j = 100;
System.out.print(i == j); //true
Integer i = 128;
Integer j = 128;
System.out.print(i == j); //false
Java在编译Integer i = 100 ;时,会翻译成为Integer i = Integer.valueOf(100);而Java API中对Integer类型的valueOf的定义如下:
public static Integer valueOf(int i){
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high){
return IntegerCache.cache[i + (-IntegerCache.low)];
}
return new Integer(i);
}
Java对于-128到127之间的数,会进行缓存,Integer i = 127时,会将127进行缓存,下次再写Integer j = 127时,就会直接从缓存中取,就不会new了。
5.long与Long的大小比较
注:Integer同理
(1)对于Long类型的数据,这个数据是一个对象,所以对象不可以直接通过“>”,“==”,“<”的比较,如果要比较两个对象的是否相等的话,我们可以用Long对象的.equals()方法:
Long l1 = new Long(100);
Long l2 = new Long(200);
System.out.println(l1.equals(l2));
如果要进行“>”,“<”的比较的话,可以通过Long对象的.longValue()方法:
System.out.println(l1.longValue()<l2.longValue());
(2)对于long类型的数据,这个数据是一个基本数据类型,不属于对象,所以可以直接通过“>”,“==”,“<”作比较。
6.String的比较
String内部用来存储的结果是一个char字符数组。
下面程序的运行结果是()
String str1 = "hello";
String str2 = "he" + new String("llo");
System.out.println(str1 == str2);
答案:false
解析:因为str2中的llo是新申请的内存块,而==判断的是对象的地址而非值,所以不一样。如果是String str2 = str1,那么就是true了。
下面这样写返回的是true
String str1 = "hello";
String str2 = "he" + new String("llo");
System.out.println(str1.equals(str2));
下面这样写返回的结果也是true
String str1 = "hello";
String str2 = str1;
System.out.println(str1 == str2);
补充:在调用方法时,若要使方法改变实参的值,可以用对象做参数(这里的对象实际上是在栈中存储的对象的地址)
二、Java常量
1.常量在程序运行时是不能被修改的。
2.在 Java 中使用 final 关键字来修饰常量,声明方式和变量类似:
final double PI = 3.1415927;
虽然常量名也可以用小写,但为了便于识别,通常使用大写字母表示常量。
字面量可以赋给任何内置类型的变量。例如:
byte a = 68;
(补充字面量:int i = 1;把整数1赋值给int型变量i,整数1就是Java字面量,同样,String s = "abc";中的abc也是字面量。)
3.byte、int、long、和short都可以用十进制、16进制以及8进制的方式来表示。
当使用常量的时候,前缀 0 表示 8 进制,而前缀 0x 代表 16 进制, 例如:
int decimal = 100;
int octal = 0144;
int hexa = 0x64;
4.字符串常量和字符常量都可以包含任何Unicode字符。字符型常量需用两个单引号括起来(注意字符串常量是用两个双引号括起来)。例如:
char a = '\u0001';
String a = "\u0001";
char a = 97; //正确,直接写数字,赋值给char会被当作ascii码处理
char c = 'a' + 1; //正确
int i = 1; char c = 'a' + i; //错误
char c='a'+1中'a'是字符型常量,1是数字常量。在编译器编译的时候,会自动合并,不会做类型转换。在编译阶段就完成。
char c='a'+x中'a'是字符型常量,但x是变量,在编译阶段无法合并,只能在运行时编译,运行时发现x是整型,'a'+x自动转换成整型,无法直接赋值给char型。需要进行强转。(char)('a'+x)正确。
5.Java中的字符占两个字节。一些特殊的转义字符序列如下:
符号 | 字符含义 |
\n | 换行 (0x0a) |
\r | 回车 (0x0d) |
\f | 换页符(0x0c) |
\b | 退格 (0x08) |
\0 | 空字符 (0x20) |
\s | 字符串 |
\t | 制表符 |
\" | 双引号 |
\' | 单引号 |
\\ | 反斜杠 |
\ddd | 八进制字符 (ddd) |
\uxxxx | 16进制Unicode字符 (xxxx) |
三、数据类型之间的转换
整型、实型(常量)、字符型数据可以混合运算。运算中,不同类型的数据先转化为同一类型,然后进行运算。
转换从低级到高级。(不是指占用字节的多少,而是指表示值的范围的大小)
低 ------------------------------------> 高
byte,short,char—> int —> long—> float —> double
数据类型转换必须满足如下规则:
1. 不能对boolean类型进行类型转换。
2. 不能把对象类型转换成不相关类的对象。
3. 在把容量大的类型转换为容量小的类型时必须使用强制类型转换。
4. 转换过程中可能导致溢出或损失精度,例如:
int i =128;
byte b = (byte)i;
因为 byte 类型是 8 位,最大值为127,所以当 int 强制转换为 byte 类型时,值 128 时候就会导致溢出。
5. 浮点数到整数的转换是通过舍弃小数得到,而不是四舍五入,例如:
(int)23.7 == 23;
(int)-45.89f == -45;
(一)自动类型转换
必须满足转换前的数据类型的位数要低于转换后的数据类型,具体地讲,当一个较"小"数据与一个较"大"的数据一起运算时,系统将自动将"小"数据转换成"大"数据,再进行运算。例如: short数据类型的位数为16位,就可以自动转换位数为32的int类型,同样float数据类型的位数为32,可以自动转换为64位的double类型。
①下面的语句可以在Java中直接通过:
byte b;
int i=b;
long l=b;
float f=b;
double d=b;
②如果低级类型为char型,向高级类型(整型)转换时,会转换为对应ASCII码值,例如
char c='c';
int i=c;
System.out.println("output:"+i); //输出结果:output:99;
③对于byte,short,char三种类型而言,他们是平级的,因此不能相互自动转换,可以使用下述的强制类型转换。
short i=99;
char c=(char)i;
System.out.println("output:"+c); //输出结果:output:c;
注意点:
a.常数在表数范围内是能够自动类型转换的
b.数据范围小的能够自动数据类型大的转换(int到float,long到float,long到double 是不会自动转换的,不然将会丢失精度)
c.引用类型能够自动转换为父类的
d.基本类型和它们包装类型是能够互相转换的
(二)强制类型转换
将"大"数据转换为"小"数据时,你可以使用强制类型转换。即你必须采用下面这种语句格式: int n=(int)3.14159/2; 可以想象,这种转换肯定可能会导致溢出或精度的下降。条件是转换的数据类型必须是兼容的。
byte b;
b=3;
b=(byte)(b*3); //必须声明byte
(三)包装类过渡类型转换
一般情况下,我们首先声明一个变量,然后生成一个对应的包装类,就可以利用包装类的各种方法进行类型转换了。例如:
①当希望把float型转换为double型时:
float f1=100.00f;
Float F1=new Float(f1);
double d1=F1.doubleValue();
注:F1.doubleValue()为Float类的返回double值型的方法
②当希望把double型转换为int型时:
double d1=100.00;
Double D1=new Double(d1);
int i1=D1.intValue();
简单类型的变量转换为相应的包装类,可以利用包装类的构造函数。即:Boolean(boolean value)、Character(char value)、Integer(int value)、Long(long value)、Float(float value)、Double(double value)
而在各个包装类中,总有形为XXValue()的方法,来得到其对应的简单类型数据。利用这种方法,也可以实现不同数值型变量间的转换,例如,对于一个双精度实型类,intValue()可以得到其对应的整型变量,而doubleValue()可以得到其对应的双精度实型变量。
(四)字符串与其他类型间的转换
1.其它类型向字符串的转换
①调用类的串转换方法:X.toString();
②自动转换:X+"";
③使用String的方法:String.volueOf(X);
2.字符串作为值,向其它类型的转换
①先转换成相应的封装器实例,再调用对应的方法转换成其它类型
例如,字符中"32.1"转换double型的值的格式为:new Float("32.1").doubleValue()。也可以用:Double.valueOf("32.1").doubleValue()
②静态parseXXX方法
String s = "1";
byte b = Byte.parseByte(s);
short t = Short.parseShort(s);
int i = Integer.parseInt(s);
long l = Long.parseLong(s);
Float f = Float.parseFloat(s);
Double d = Double.parseDouble(s);
③Character的getNumericValue(char ch)方法
(五)Date类与其他数据类型间的转换
整型和Date类之间并不存在直接的对应关系,只是你可以使用int型为分别表示年、月、日、时、分、秒,这样就在两者之间建立了一个对应关系,在作这种转换时,你可以使用Date类构造函数的三种形式:
①Date(int year, int month, int date):以int型表示年、月、日
②Date(int year, int month, int date, int hrs, int min):int表示年、月、日、时、分
③Date(int year, int month, int date, int hrs, int min, int sec):以int型表示年、月、日、时、分、秒
在长整型和Date类之间有一个很有趣的对应关系,就是将一个时间表示为距离格林尼治标准时间1970年1月1日0时0分0秒的毫秒数。对于这种对应关系,Date类也有其相应的构造函数:Date(long date)。
获取Date类中的年、月、日、时、分、秒以及星期你可以使用Date类的getYear()、getMonth()、getDate()、getHours()、getMinutes()、getSeconds()、getDay()方法,你也可以将其理解为将Date类转换成int。
而Date类的getTime()方法可以得到我们前面所说的一个时间对应的长整型数,与包装类一样,Date类也有一个toString()方法可以将其转换为String类。
有时我们希望得到Date的特定格式,例如20020324,我们可以使用以下方法:
import java.text.SimpleDateFormat;
import java.util.*;
java.util.Date date = new java.util.Date();
//如果希望得到YYYYMMDD的格式
SimpleDateFormat sy1=new SimpleDateFormat("yyyyMMDD");
String dateFormat=sy1.format(date);
//如果希望分开得到年,月,日
SimpleDateFormat sy=new SimpleDateFormat("yyyy");
SimpleDateFormat sm=new SimpleDateFormat("MM");
SimpleDateFormat sd=new SimpleDateFormat("dd");
String syear=sy.format(date);
String smon=sm.format(date);
String sday=sd.format(date);
参考资料: