1、数据类型
Java是一种强类型语言,在JAVA中一共有8种基本数据类型化
其中有4种整型,2种浮点型,一种用于表示Unicode编码的字符单元的字符类型char和一种用于表示真值的boolean类型
1.1、整型
整型表示没有小数部分的数值,它允许是负数,Java提供了四种整型
|
类型 | 存储需求 | 取值范围 |
---|---|---|
byte | 1 | -128 ~ 127 |
short | 2 | -32768 ~ 32767 |
int | 4 | |
long | 8 |
note:在Java中,整型的范围与运行JAVA代码的机器无关。这样就解决了软件从一个平台一直到另外一个平台度,或者在同一个平台中不同操作系统之间进行移植给程序员带来的诸多问题。与此相反,C和C++程序需要针对不同的处理器选择最为高效的整形,这样就有可能造成一个在32位处理器上运行很好的C程序在16为位系统上运行缺发生整数溢出
1.2、浮点类型
浮点类型用于表示有小数部分的数值,在Java中有两种浮点类型’
类型 | 存储需求 | 取值范围 |
---|---|---|
float | 4字节 | (有效位数为6~7位) |
double | 8字节 | (有效位数为15位) |
double表示这种类型的数值精度是float类型的两倍(有人称之为双精度值)。绝大部分应用程序都采用double类型。在很多情况下,。float类型的精度很难满足需求,
浮点数不使用于无法接受摄入误差的金融计算中。例如:命令System.out.println(2.0-1;1)将打印出0.899999,而不是人们想象的0.9==
如果在数值计算中不允许有任何摄入误差,就应该使用BigDecimal类‘
1.3、char类型
char类型原本用来表示单个字符,不过,下只能在情况已经油酸变化。如今,有些Unicode字符可以用一个char追描述,另外一些UniCode字符则需要连个char值
强烈建议不要在程序中使用char类型,除非确实需要处理UTF-16代码单元。最好将字符串作为抽象画类型处理
1.4、boolean类型
boolean(布尔)类型有两个值:false和true,用来判定逻辑条件。整型值和布尔值之间不能进行相互转换。
1.5、数值类型之间的转换
经常需要将一种数值类型转换为另一种数值类型
将位数长的转换为位数短的数据会造成数据信息丢失
上面两个数值进行二元操作时,(例如n+f,n是整数,f是浮点数),先要将两个操作数转换为同一种类型,然后再进行计算‘
- 如果两个操作数有一个是double类型,另一个操作数就会转换为double类型
- 否则,若果两个操作数中有一个是float类型,另一个操作数就会转换为float类型
- 否则,如果其中一个操作数是long类型,另一个操作数就会转换为long类型
- ’否则,两个操作数都将被转换为int类型
1.6、强制类型转换
在上一节中看到,在必要的时候,int类型的值将会自动的转换为double类型。但另一方面,有时也需要将double转换为int.在Java中,允许进行这种数值之间的类型转换。当然,有可能会丢失一些信息。在这种情况下,需要通过==强制类型装换(cast)==实现这个操作
语法
//待转换的数据类型 变量 = (带转换数据类型) 带转换变量名
double x = 9.997;
int nx = (int)x;
强制类型转换可能造成数据信息的丢失(谨慎使用)
1.6、数据类型拾遗
2、变量
2.1、变量定义
- 在声明变量时,变量的类型位于变量名之前
- 变量名必须是一个以字母开头语并由字母或数字构成的序列(字母包括’A’-‘Z’、’a’-‘z’、’_'或在某些语言中表示字母的任何Unicode字符,例如中文字符也可以)‘
- 大小写敏感,变量名的长度没有限制
- 不能使用Java保留字作为变量名
- 不提倡int i,j这种风格的命名。逐一声明每一个变量可以提高程序的可读性
2.2、变量的初始化
==不能使用未初始化的变量,==例如,Java编译期认为下面的语句序列是错误的:
int vacationDays;
System.out.println(vacationDays);
2.3、常量
常量可以理解为一种特殊的变量:也就 是这个变量一经定义就不会改变
在JAVA中,利用关键字final指示常量,例如
final doiuble CM_PER_I
关键字final表示这个变量只能被赋值一次。一旦被赋值之后,就不能改变
在Java中,经常希望某个常量可以在一个类中的的多个方法使用,通常将这些常量称为类常量。可以使用关键字static final设置一个类常量
public class Constants2{
public static final double CM_PER+INCH=2.54;
}
3、运算符
3.1、基础运算符
-
在Java中,使用算数运算符+,-,*,/ 表示加、减、乘、除运算。
-
当参与/运算的两个操作数都是整数时,表示整数除法;否则表示浮点除法
-
整数的求余操作用%表示
-
整数倍0除将会产生一个异常,而浮点数被0除将会得到无穷大会NAN结果
3.2、结合赋值运算符
可以在赋值中使用二元运算符,这时一种很方便的简写形式
x +=4;
如果运算符得到一个值,其类型与左侧操作数类型不同,就会发生强制类型转换
3.3、自增和自减运算符
3.4、关系和Boolean运算符
/**
Java中包含了丰富的关系运算符。
== :检测相等性
!= :检测不等性
< > <= >=
&&:逻辑与,按照短路方式求值啊,如果第一个操作数已经能够确定表达式的值,第二个操作数就不必计算
||: 逻辑或,同样是短路
condition?expression1:expression2: 若果表达式为true,就位第一个表达式的值,否则计算为第二个表达式的值
**/
3.5、位运算符
处理整型类型时,可以直接对组成整型数值的各个为完成操作
/**
位运算符包括:
& (and)
| (or)
^ (xor)
~ (not)
**/
4、枚举类型
**有时候,变量的值只在一个有限的集合内。**例如:销售的服装会披萨饼只有小中大或超大这四种尺寸
针对这种情况,可以自定义枚举类型,枚举类型包括有限个命名的值:
enum Size {SMALL.MEDIUM,LARGE,EXTRA_LARGE}
现在,可以声明这种类型的变量
Size s = Size.MEDIUM
5、字符串
从概念上将,JAVA字符串就是Unicode字符序列(不可变)
在方法区有一个常量池,字节码加载如虚拟机时字符串常量就已经加载进常量池并给它分配一个内存地址。字符串对象就引用该地址
5.0创建字符串对象
**创建字符串对象一共有两种方式: **
//str1存放(引用)常量池中的地址
String str1 = "abcd";
//str2存放(引用)堆中对象的地址,而堆中的数据存放的是常量池中的地址,多重引用
String str2 = new String("abcd");
如果常量区中有该字符串,就不重新存储,而是直接引用,这样节省了内存。该程序只在堆中开辟了一个空间。
5.1、Java对字符串的优化
//返回一个cd字符串
public static String getString() {
return "cd";
}
public static void main(String[] args) {
String str1 = "abcd";
String str2 = "a" + "b" + "c" + "d";
String str3 = "ab" + "cd";
String temp = "ab";
String str4 = "ab" + temp;
String str5 = "ab" + getString();//调用上面定义的方法得到cd
//注意:这里的‘==’比较的是它们的引用地址,而不是比较的它们的值
System.out.println(str1 == str2);//结果为true
System.out.println(str1 == str3);//结果为true
System.out.println(str1 == str4);//结果为false
System.out.println(str1 == str5);//结果为false
}
}
就是Java虚拟机对String经行了优化,这里str1、str2、str3引用了同一个地址,共用了常量区中的数据,所以它们的引用地址进行比较结果是相同的。-但是变量和方法无法确认它们准确的值只有运行到该行代码时才能却定,在堆中新创建一个空间(常量池是在编译时就已经确定)。所以str1、str4、str5引用地址的比较不相等.Java虚拟机的优化共用了资源,减少了内存的使用,从而释放了更多的空间。
常量池使用于编译期间
5.2、String创建对象个数分析
以下创建了多少对象?
String s1 = "he";
String s2 = "llo";
String s3 = new String("hello");
/**
答案是4个,分别为String常量池中的"he"、“llo”、“hello”、和堆中新创建的一个对象。注意这里的new String(“hello”)中的hello在编译期也会存入String常量池。
*/
以下创建了多少对象?
String s1 = "he"+"llo";
String s2 = new String("hello");
/**
答案是2个,这里的"he"+“llo"java做了优化机制,直接把结果hello存入String常量池而不是分别把"he"和"llo"存入(这里存入"he"和"llo"也无意义,因为并无使用到)。注意: 若是new String(“hello”+“world”);此语句也只会在常量池中存入"helloworld”,并不会分别存入
*/
以下创建了多少对象?
String s1 = "he";
String s2 = "llo";
String s3 = s1 + "llo"
/**
答案是3个,分别是常量池中的"he"、“llo”、和堆中的一个内容为"hello"的对象。这里的s1+"llo"实际上是使用StringBuffer对象连接的(查看jdk的API文档可知),笔者在这里也画了个图解
可能会有人产生疑问了,为什么String常量池里没有存入"hello"呢?笔者刚才也提过,常量池中的内容是在编译期确定的,s1+"llo"中,java虚拟机并不知道其结果是什么,而且此操作涉及StringBuffer对象也就是涉及其他类,在编译期并无法使用,只有等到运行时才能进行。所以结果"hello"是运行时产生的,不存在于常量池中
*/
以下代码创建了多少对象
String s1 = "he";
String s2 = "llo";
String s3 = s1 + "abc";
/*
答案是4个,和上一题类似,只不过上题中的"llo"在前面s2中已存入常量池。
*/
小结:
- 何时会加入常量池?在编译期间一些字面量会加入常量池
- 什么值会加入常量池?字面量会加入常量池,而对于一些变量或方法返回的值只有在编译器才会确定其值,因此不会将其结果加入常量池
- 因为有了常量池的存在,所以比较 = 等于值的结果会不一样,但是如果还是判断字符串的值是否相等的情况还是推荐使用equals,而不是使用等于号,具体参考5.6节
5.3、子串
5.4、拼接
与绝大多数程序设计语言一样,Java允许使用加号连接(拼接)两个字符串
当将一个字符串与一个非字符串的值进行拼接时,后者会被转成字符串(任何一个Java对象都将被展缓成字符串)
5.5、不可变字符串
String类没有提供用于修改字符串的方法,如果希望将greeting的内容修改为"heloper",不能直接的将greeting的最后两个位置的字符修改为’p’
5.6、检测字符串是否相等
可以使用equals方法检测两个字符串是否相等,
一定不要使用 等号 运算符来检测两个字符串是否相等,这个运算符只能确定两个字符串是否放在同一个位置上。当然,如果字符串放置在同一个位置上,它们必然相等,但是完全有可能将内容相同的多个字符串的拷贝放在不同的位置上
//凡是常量池中的内容相比较,如果只相等则使用==就相等
//如果没有直接使用常量池中的内容比较,即使相等使用==也不等
String s1 = "abcd";
String s2 ="abcd";
String s3 = "ab"+"cd"; //Java对其坐了优化,直接将其加入到常量池中
String s4 = new String("abcd");//直接创建了对象
String s0 = "ab";
String s5 = s0+"cd";//涉及到变量。在编译期间不会加入到常量池中
System.out.println(s1==s2);//true
System.out.println(s1==s3);//true
System.out.println(s1==s4);//false
System.out.println(s1==s5);//false
如果虚拟机始终将相同的字符串共享,就可以使用==运算符检测是否想相等。
但实际上,只要字符串常量是共享的,而+(在Java中这就涉及到StringBuffer)或subString等操作产生的结果并不是共享的。因此,千万不要使用 =运算符测试字符串的相等性,以避免在程序中出现bug**
小结:只要在常量池中的字符串使用等于号相比较就相等,否则不等
5.7、空串与Null串
空串“” 是长度为0的字符串。
空 串是一个Java对象,有自己的串长度(0)和内容(空)。
不过,String变量还可以存放一个特殊的值,名为null,这表示目前没有任何对象与该变量关联
5.8、String API
- length()
- indexOf()
- equals()’
- trim()
- subString()
- join()’
5.9构建字符串
背景
有时候,需要由较短的字符串构建字符串,例如,按键或来自文件中的单词。采用字符串连接的方式达到此目的的效率比较低。每次连接字符串,都会构建一个新的String对象,既耗时,又浪费空间,使用StringBuilder类就可以避免这个问题的发生
如果需要许多小段的字符串构建一个字符串,那么应该按照下列步骤进行,首先:构建一个空的字符串构建器:
StringBuilder sb = new StringBuilder();
当每次需要添加一部分内容时,就调用append方法
sb.append("`1")
在JDK5.0中引入StriingBuilder类。这个类的前身是StringBuffer,其效率稍有降低,但允许采用多线程的方式执行添加或删除字符的操作。
7、大数值
如果基本的整数和浮点数精度不能够满足需求,那么就可以使用java.math包中的很常用的类:BigInteger和BigDecimal。这两个类可以处理包含任意长度数字序列的数值
BigInteger类实现了任意精度的整数运算**
BigDecimal实现了任意精度的浮点运算
使用于银行,金融等行业
8、数组
数组是一种数据结构,用来存储同一类型值的集合。通过一个整型下标可以访问数组中的每一个值。例如,如果a是一个整型数组,a[i]就是数组中下标为i的整数
8.1、数组声明
在申明数组变量时,需要指出数组类型(数据元素类型紧跟[])和数组变量的名字。下面声明了整型数组:
int[] a;
创建一个数字数组时,所有元素都初始化为0
boolean数组的元素会初始化为false
对象数组的与元素则初始化为特殊值null
一旦创建了数组,就不能再改变它的大小(尽管可以改变每一个数组袁术)。如果需要经常在运行过程中扩展数组的大小,就应该使用另一种数据结构----数组列表(arrray list)
8.2、for each循环
Java有一种功能很强的循环结构,可以用来依次处理数组中的每个元素而不必指定下标值而分心
for(variable :collection){
}
8.3、数组排序
想要对数值类型数组进行排序,可以使用Arrays类中的sort方法
9、控制流程
与任何程序设计语言一样,Java使用条件语句和循环结构确定控制流程。
9.1、块作用域
块(即符合语句)是指由一对大括号括起来的若干条简单的Java语句。块确定了变量的作用域。一个块可以嵌套在另一个块中
不能在嵌套的两个块中声明同名的变量
{
int n;
{
int n;
}
}
9.2、条件语句
在Java中,条件语句的格式为
if(condition){
statement
}else if{
}
9.3、循环
9.3.1、while循环
当条件为true时,while循环中兴一条语句(也就是一个语句块),格式为:
while(conditiobn){
}
9.3.2r循环
for循环语句是支持迭的一种通用结构,利用每次迭代之后更新的计数器或类似的变量来控制迭代次数
for(int i=1;i<10;i++){
}
9.4、switch语句
在处理多个选项时,使用if/else结构时显得有些笨拙。Java提供了一个swith语句
switch(choice){
case case1:
.......
breadk;
case case2:
.......
breadk;
case case3:
.......
breadk;
default:
break;
}
switch语句将从与选项值相匹配的case标签处开始执行直到遇到break语句,如果没有相匹配的case标签,而有default字句,就执行这个子句
-
有可能触发多个case分支。如果在case分支语句的末尾没有break语句,那么会接着执行下一个case分支语句。这种情况相当危险,常常会引发错误。为此,我们在程序中从不使用switch语句。
case标签可以是:
- 类型为char、byte、short或int的常量表达式
- 枚举类型
- 从JavaSE 7开始,case标签还可以是字符串字面量