目录
一、Eclipse创建项目及验证四种整型取值范围
关于Eclipse的安装可以自行baidu。我们使用的Ecelipse的版本信息如下:
Eclipse Java EE IDE for Web Developers.
Version: Oxygen Release (4.7.0)
Build id: 20170620-1800
1、新增一个Java工程 day01_dataType
【文件】-【新建】-【Java项目】,输入项目名称:day01_Type
注意:我们机器中使用的JDK需要前置做安装,并在项目中选择好对应的JRE五环境
2、新增包:com.xiaoxie
右键项目名称-【新建】-【包】-输入包名:com.xiaoxie
3、在新增的包下新增测试类Test1
右键包名-【新建】-【类】-输入类名:Test1
package com.xiaoxie.test;
public class Test1 {
public static void main(String[] args) {
/*
* 定义8个变量,
* 保存四种整数的最小值和最大值
* JDK中对于每个类型都对应的类,Byte,Short,Integer,Long
*/
//byte类型
byte a = Byte.MIN_VALUE;
byte b = Byte.MAX_VALUE;
//short类型
short c = Short.MIN_VALUE;
short d = Short.MAX_VALUE;
//int类型
int e = Integer.MIN_VALUE;
int f = Integer.MAX_VALUE;
//long类型
long g = Long.MIN_VALUE;
long h = Long.MAX_VALUE;
//打印出每种类型的最小值和最大值
System.out.println("Byte.MIN_VALUE = " + a);
System.out.println("Byte.MAX_VALUE = " + b);
System.out.println("Short.MIN_VALUE = " + c);
System.out.println("Short.MAX_VALUE = " + d);
System.out.println("Integer.MIN_VALUE = " + e);
System.out.println("Integer.MAX_VALUE = " + f);
System.out.println("Long.MIN_VALUE = " + g);
System.out.println("Long.MAX_VALUE = " + h);
}
}
顺便在这里提一下几个在编程中的默认规则及eclipse涉及到的常用键
1、包名:包名小写
2、类名:使用驼峰格式(如果类名中存在多个单词则每个单词的首字母大写)
3、main方法是所有程序的入口方法,执行时是从main处开始执行的
3、main方法在eclipse中存在模板,可以在输入main后按下Alt + /做补全
4、eclipse中当完成编码后要执行,可以使用快捷键:Ctrl + F11
二、浮点数类型的取值范围
Java中的浮点数有两个:
float:单精度浮点数
double:双精度浮点数
与上面的程序类似再新增一个测试类Test2
package com.xiaoxie.test;
public class Test2 {
public static void main(String[] args) {
//定义四个变量,保存两个浮点数的最小值最大值
//float类型
float a = Float.MIN_VALUE;
float b = Float.MAX_VALUE;
//double类型
double c = Double.MIN_VALUE;
double d = Double.MAX_VALUE;
System.out.println("Float.MIN_VALUE = " + a);
System.out.println("Float.MAX_VALUE = " + b);
System.out.println("Double.MIN_VALUE = " + c);
System.out.println("Double.MAX_VALUE = " + d);
}
}
三、char类型说明
char类型表示字符,或者是表示字符的整数编码,在java中char类型的字符使用单号括起来。
java中char类型表示人为制定的Unicode的编码表。
我们知道char的字节数是2,那么就表示有16个bit。
00000000 00000000 ~ 11111111 11111111,表示的范围也就是 0~65535,每个编码位置放置一个字符
注意:由于它是从0开始的最高位不用来表示符号位而是表示数值位
几个常见的编码
A 65
B 66
a 97
b 98
z 122
中 20013
在计算机中表示任何数据都是使用二进制的数字来表示的,这个编码表则对应的给定了数字与字符的对应关系。
如下:
char c1 = 'a';
char c2 = 97;
上面的这两个赋值的方式都是赋以字符a
package com.xiaoxie.test;
public class Test5 {
public static void main(String[] args) {
char c1 = 'a';
char c2 = 97;
char c3 = 'b';
char c4 = 98;
char c5 = '中';
char c6 = 20013;
char c7 = 20014;
System.out.println("c1 = " + c1); // c1 = a
System.out.println("c2 = " + c2); // c2 = a
System.out.println("c3 = " + c3); // c3 = b
System.out.println("c4 = " + c4); // c4 = b
System.out.println("c5 = " + c5); // c5 = 中
System.out.println("c6 = " + c6); // c6 = 中
System.out.println("c7 = " + c7); // c7 = 丮
}
}
四、boolean类型说明
boolean表示真和假,这里的真和假用到两个关键字true(真)、false(假)。它在内存中占用1个字节,8个bit。
boolean在内存中表示真假以最未尾为1或0来代表真假
0000 0001 ====> 真
0000 0000 ====> 假
boolean一般用来做条件判断,判断条件是还是假,从而决定程序的走向。
五、基本类型的字面值
字面值五条规则:
1、整数字面值:int类型
int a = 65535;
long b = 5555555555; //这里存在问题:右侧字面值超过int范围
2、byte,short,char比int小的整数,它们都是2个字节,可以使用范围内的值直接赋值
byte a = 127; //这里虽然是使用了整数的字面值,会自动转为byte类型
byte b = 128; //这里存在问题,128已经超过了byte的可取值范围
3、浮点数的字面值是double类型
double a = 5.5;
float b = 5.5; //这里存在问题,字面值是double类型,转到字节少的flaot当中存在精度丢失风险,不允许
4、字面值后缀,后缀大小写都是可以的,为了与数字区分明显建议使用大写
L ----> long
long a = 5555555555L; //OK
F ----> float
float a = 3.14f ; //OK
D ---->double
double a = 3.0;
double a = 3D; //这里3D表示这个字面值是一个double类型
5、字面值前缀,用来代表进制
0x ----> 16进制
16进制是逢16进位,0123456789abcdef
16进制换算为10进制 0xCA85 转为10进制为 51845
在计算机当中使用16进制表示,是由于描述上的方便,16进制的一个位则可以代表二进制中的4位(两个16进制的字符就可以表示一个字节了),这样写起来和看起来会简便一些。
0 ----> 8进制
8进制与16进制同理,它是一个位表示二进制中的3位,相对于16进制来说8进制不是那么地常用。
\u ----> char类型16进制
我们看一下'a'字符它表示的是97,97用16进制表示是61,则如果字符'a'用16进制表示则为'\u0061'(注意:这里的写法,要用单引号括起来,两个字节要补全)
新增一个测试类,我们可以看看各进制下的数据情况
package com.xiaoxie.test;
public class Test6 {
public static void main(String[] args) {
int i16 = 0xff;
int i8 = 0377;
char z = '\u4e2d';
//Unicode中文字符的范围[\u4e00,\u9fa5]
char startChar4CN = '\u4e00';
char endChar4CN = '\u9fa5';
System.out.println("i16 = " + i16);
System.out.println("i8 = " + i8);
System.out.println("z = " + z);
System.out.println("startChar4CN = " + startChar4CN);
System.out.println("endChar4CN = " + endChar4CN);
}
}
程序运行结果如下:
i16 = 255
i8 = 255
z = 中
startChar4CN = 一
endChar4CN = 龥
六、基本类型的运算规则
基本类型的运算规则有五条:
1、计算结果的数据类型,与最大的参与运算的数据类型一致
4/3 的结果是1,因为参与运算的两个字面值4和3都是int类型,这样最大的类型就是int类型,得到的结果是1也为int类型。
4/3.0 的结果是1.3333333333333333,因为参与运算的两个字面值4为int类型,3.0为double类型,那么结果1.3333333333333333也为double类型(参与运算类型中的最大类型)。
注意一个我们常常会不小心犯的错,double d = 1/2 * 3.5 *2; 这个的计算通常是与我们预期有所偏差的,因为1/2已经为0了,后面的乘3.5,乘2无法改变最终结果,最终d的结果是0。如果我们调整一下运算的顺序,double d = 3.5 * 2 * 1 / 2;这个时候d的结果又会是3.5,这个时候是由于在计算的过程中,操作数的最大运算类型在变化,先计算3.5*2===>double类型7.0===>7.0*1====>double类型7.0====>7.0/2====>double类型3.5。
2、byte,short,char三种比int小的整数,运算时会先转为为int再做运算
byte a = 3;
byte b = 4;
byte c = a+b; //这条语句是错误的,两边的类型不一致,编译器会提示不能从int转换为byte
3、整数运算溢出
Integer.MAX_VALUE + 1 ====>会得到负最小值
Integer.MIN_VALUE - 1 ====>会得到正的最大值
这种溢出就像一个首尾相连的一个圈,到最大后再走就会到最小。
4、浮点数运算不精确
这个并不算是bug,是由于的规范所导致的。
这种不精确的计算也会产生很多问题,比如我们在做科学运算时,在做财务方面的运算时是一定要求精确计算的,Java为了解决这个问题,提供了精确运算类:BigDecimal(使用字符串的形式做入参构造对象,使用这个类提供的方法进行运算)
5、浮点数的特殊值
Infinity ====>无穷大,-Infinity ====>负无穷大
对于浮点数来说是可以做除0的,这个也是由于它的不精确的特性的一个侧面表现
如:2.0/0 它得到的结果就是一个无穷大Infinity
注意:整数是不可以做除0的,如果除0则在运行时会报错
NaN ====> 不是一个数
用一个负数开平方就会得到NaN,如:Math.sqrt(-4)
package com.xiaoxie.test;
import java.math.BigDecimal;
public class Test7 {
public static void main(String[] args) {
/*
* 运算规则一:计算结果的数据类型,与最大的参与运算的数据类型一致
*/
System.out.println("3/2 = " + 3/2); //1
System.out.println("3D/2 = " + 3D/2); //1.5
System.out.println("1/2 * 3.5 * 2 = " + 1/2 * 3.5 *2); //0.0
System.out.println("3.5 * 2 * 1/2 = " + 3.5 * 2 * 1/2); //3.5
System.out.println("============== 我是华丽分割线 ================");
/*
* 运算规则二,byte,short,char三种比int小的整数,运算时会先转为为int再做运算
*/
byte a = 3;
byte b = 4;
//下面这条语句byte c = a + b;是无法通过编译的,编译器会提示无法从int转为byte,如果要通过编译要进行类型强转,因为在运算是超过类型的取值范围概率太大了,所以定这个规则以免出错
//byte c = a + b;
byte c = (byte) (a + b);
System.out.println("a + b = " + c);
System.out.println("============== 我是华丽分割线 ================");
/*
* 运算规则三:整数运算溢出,这种溢出就像一个首尾相连的一个圈,到最大后再走就会到最小。
*/
//下面这个输出会产生整数运算溢出
System.out.println("Integer.MAX_VALUE + 1 = " + (int)(Integer.MAX_VALUE + 1));
//下面这个语句有两处错误,首先,3000000000就超过了字面类型int;其次,对于整个运算会超过int型的取值范围会产生溢出
//int gn = 3000000000*60*60*24*365;
Long gn = 3000000000L*60*60*24*365;
System.out.println(gn);
System.out.println("============== 我是华丽分割线 ================");
/*
* 运算规则四:浮点数运算不精确
*/
//这里直接计算得到的结果不精确
System.out.println("2-1.9 = " + (2-1.9));
System.out.println("2-1.8 = " + (2-1.8));
System.out.println("2-1.7 = " + (2-1.7));
System.out.println("2-1.6 = " + (2-1.6));
System.out.println("2-1.5 = " + (2-1.5));
/*
* 使用BigDecimal进行精确计算,构造BigDecimal的时候入参要使用字符串类型
*/
BigDecimal d1 = new BigDecimal("2");
BigDecimal d2 = new BigDecimal("1.9");
System.out.println("2-1.9 = " + d1.subtract(d2));
System.out.println("============== 我是华丽分割线 ================");
/*
* 运算规则五:浮点数的特殊值
* NaN:不是一个数
* Infinity:无穷大,-Infinity:负无穷大
*/
System.out.println("0.2/0 = " + (2.0/0));
System.out.println("Double.MAX_VALUE * 1.2 = " + (Double.MAX_VALUE * 1.2));
System.out.println("0.2/0 = " + (-2.0/0));
System.out.println("-Double.MAX_VALUE*1.2 = " + (-Double.MAX_VALUE*1.2));
System.out.println("Math.sqrt(-4) = " + Math.sqrt(-4)); //NaN
}
}
七、基本类型的类型转换
类型的转换,可以分为两大类:
1、小类型转大类型
byte-->short-->int-->long 可以直接转
char-->int-->long 可以直接转
int-->float-->double 可以直接转 (整数转浮点数可能存在不精确的情况!!)
从小到大的转换是自动转换,不需要写转型运算
转成浮点数可以会产生不精确的情况
2、大类型转小类型
可能会导致数据截取后的数据损失
必须要手动进行转型,使用强制转型运算
浮点数转整数,小数位部分全部舍弃(注意:这里不是做四舍五入,而是直接丢)
package com.xiaoxie.test;
public class Test8 {
public static void main(String[] args) {
/*
* 整数类型从小类型到类型转换是自动进行的,不是引起精度丢失的问题
*/
byte b = 127;
int i = b;
System.out.println("b = " + b);
System.out.println("i = " + i);
b = -1;
i = b;
System.out.println("b = " + b);
System.out.println("i = " + i);
/*转为浮点数的时候产生了精度丢失问题,导致不精确*/
long l = 478235234328888234L;
float f = l;
System.out.println("l = " + l);
System.out.println("f = " + f);
double d = l;
System.out.println("d = " + d);
/*从大类型转到小类型时,及有可能导致数据被截断,这个时候编译器是要求做强制转型运算的*/
int i1 = 365;
byte b1 = (byte) i1; //byte存不下这么大的数,超出的高位bit直接截取掉
System.out.println("i1 = " + i1);
System.out.println("b1 = " + b1);
double d1 = 356.901;
i1 = (int) d1; //小数位丢弃不做四舍五入
System.out.println("i1 = " + i1);
System.out.println("d1 = " + d1);
}
}
八、Java运算符
1、基本数学运算:+、-、*、/
2、字符串的连接:+
1 + 2 + "abc" ===>"3abc" "abc" + 1 + 2===>"abc12"
3、取余,求模运算:%
判断一个变量a的值是否可以被2整除 if(a%2 == 0)
3、判断是否相等 ==,判断是否不相等 !=,这两个运算符是互斥的,返回的结果是boolean值
4、大小比较:>、>=、<、<=,返回的结果是boolean值
5、逻辑运算符:|| (或)&&(且) !(非)
|| :只要左右两边有一个为真则结果为真,只有当两边为假时结果才为假(当左边为真时,会产生短路的效果,右边不再执行,直接判断为真)
&&:只要左右两边有一个为假结果为假,只有当两边为真时结果才为真(当左边为假时,会产生短路的效果,右边不再执行,直接判断结果为假)
!:取互斥面,如!a,这个表示当a为真则结果为假,当a为假时结果为真
6、三目运算符 ? :
a==0?a+1:a-1; ====>如果a==0这个判断为真(true),返回a+1,否则返回a-1
7、++ 自增、-- 自减 运算符
int a = 1;
int b = a++; //这个时候b的值是1,a的值是2(因为它做自增),这里是使用的后++(先使用,后做自增运算 )
int c = ++a; //运行到这里的时候a的初值已经是2了,c的值为3,a的值为3,这里是使用的前++(先自增运算,后使用)
8、位运算:&(位与)、|(位或)、^(异或)、~(取反)、>>(带符号向右移位)、>>>(不带符号向左移位)、<<(向左移位)
如:有如下两个int类型,按二进制的位进行
&:按位与,每一位进行与运算
0000 0000 0000 0000 0000 0000 0101 1011
0000 0000 0000 0000 0000 0000 1100 1101 &
---------------------------------------------------------------------
0000 0000 0000 0000 0000 0000 0100 1001
|:按位或,每一位进行或运算
0000 0000 0000 0000 0000 0000 0101 1011
0000 0000 0000 0000 0000 0000 1100 1101 |
---------------------------------------------------------------------
0000 0000 0000 0000 0000 0000 1101 1111
^:异或,每一位只要两位不同时才为1,否则为0,这里有一个特点:同一个值异或两次会得到它的原值
0000 0000 0000 0000 0000 0000 0101 1011
0000 0000 0000 0000 0000 0000 1100 1101 ^
---------------------------------------------------------------------
0000 0000 0000 0000 0000 0000 1001 0101
~:求返运算,只有一个运算数,0变为1,1变为0
0000 0000 0000 0000 0000 0000 1100 1101 ~
---------------------------------------------------------------------
1111 1111 1111 1111 1111 1111 0011 0010
>>:向右移位,它的原值不会改变,它会新分配一个内存空间进行存储新的值,当符号为0则左边补0,符号位为1则左边补1
>>>:不带符号的移位,它不管符号位是1还是0左边补的都是0
<<:左移位,它是与符号位没有关系的,移位的时候右边都是补0
0000 0000 0000 0000 0000 0000 1100 1101 >>2
---------------------------------------------------------------------
0000 0000 0000 0000 0000 0000 0011 0011
1000 0000 0000 0000 0000 0000 1100 1101 >>2
---------------------------------------------------------------------
1110 0000 0000 0000 0000 0000 0011 0011
1000 0000 0000 0000 0000 0000 1100 1101 >>>2
---------------------------------------------------------------------
0010 0000 0000 0000 0000 0000 0011 0011
1000 0000 0000 0000 0000 0000 1100 1101 <<2
---------------------------------------------------------------------
1000 0000 0000 0000 0000 0000 1100 1100
九、相关编程练习
练习1:分别由a和b变量保存两个整数值,如何交互两个变量保存的整数值
package com.xiaoxie.test;
import java.util.Scanner;
public class Test3 {
public static void main(String[] args) {
//Scanner对像初始化接收控制台的输入
Scanner scanner = new Scanner(System.in);
System.out.print("请输入整数a的值:");
int a = scanner.nextInt();
System.out.print("请输入整数b的值:");
int b = scanner.nextInt();
System.out.println("源数据情况:a=" + a + ",b=" + b);
System.out.println("-----交换变量的值后----");
//接龙交换法,定时临时变量
int temp;
//开始首尾接龙赋值
temp = a;
a = b;
b = temp;
System.out.println("执行交换后:a=" + a + ",b=" + b);
}
}
Scanner类:Java类库中的类,它所在的包:java.util包下,需要先把这个类导入,以指定类的路径
import java.util.Scanner;
从上面的编码中我们可以看到使用了“首尾接龙”的方式进行变量的值交互,具体看下图示意:
我们可以看到上面我们使用了Scanner存在重复代码(提示字符串,获取值),我们可以考虑,新增自己的utils类MyScanner,对于系统的Scanner进行简单的包装以获取从控制中的输入数据。
改造后:
新增一个包:com.xiaoxie.utils
新增一个类:在新增的包中新增类 MyScanner
package com.xiaoxie.utils;
public class MyScanner {
private static final java.util.Scanner scanner = new java.util.Scanner(System.in);
public static <T> Object Result(String tips,Class<T> type) {
System.out.print(tips);
if(type.getSimpleName().equals("Integer")) {
return scanner.nextInt();
} else if(type.getSimpleName().equals("Long")) {
return scanner.nextLong();
} else if(type.getSimpleName().equals("Float")) {
return scanner.nextFloat();
} else if(type.getSimpleName().equals("Double")) {
return scanner.nextDouble();
} else if(type.getSimpleName().equals("Byte")) {
return scanner.nextByte();
} else {
return scanner.nextLine();
}
}
}
对于主方法则改为如下:
package com.xiaoxie.test;
import com.xiaoxie.utils.MyScanner;
public class Test3 {
public static void main(String[] args) {
//从控制台获取两个整型变量
int a = (int) MyScanner.Result("请输入a的值:", Integer.class);
int b = (int) MyScanner.Result("请输入b的值:", Integer.class);
System.out.println("源数据情况:a=" + a + ",b=" + b);
System.out.println("-----交换变量的值后----");
//接龙交换法,定时临时变量
int temp;
//开始首尾接龙赋值
temp = a;
a = b;
b = temp;
System.out.println("执行交换后:a=" + a + ",b=" + b);
System.out.println(Integer.class.getSimpleName());
}
}
练习2:根据用户输入的电有灯的功率,以及使用小时数,一共耗了多少度电?每度电5.6元,那么总共花废了多少钱?
package com.xiaoxie.test;
import java.text.DecimalFormat;
import com.xiaoxie.utils.MyScanner;
public class Test4 {
/*每度电5.6元这里定义一个常量*/
private static final double PRICE = 5.6;
public static void main(String[] args) {
//从控制读入用户输入条件
int wa = (int) MyScanner.Result("电灯的瓦数:", Integer.class);
double time = (double) MyScanner.Result("电灯使用的时间:", Double.class);
//使用的电度数
double ds = (wa * time) / 1000;
//花费的金额
double cost = PRICE * ds;
DecimalFormat df = new DecimalFormat("0.00");
System.out.println("共总使用了:" + df.format(ds) + "度电," +"一共花费:" + df.format(cost) + "元" );
}
}
注意:
1、浮点数的计算永远是不精确的,所以我们对于结果使用了DecimalFormat进行 格式化操作
2、对于程序中我们尽量使用double,而不使用Float,因为double的精度更高一些,对于当前的设备一般内存不至于低到要考虑这些内存的情况,所以一般选用double
练习3:牛郎星到织女星有16.4光年,光速是299792458米/秒,一只喜鹊长度是0.46米,那么牛郎与织女相会需要我少只喜鹊?
package com.xiaoxie.test;
public class Test9 {
public static void main(String[] args) {
/*
* 牛郎星到织女星有16.4光年,光速是299792458米/秒,一只喜鹊长度是0.46米,那么牛郎与织女相会需要我少只喜鹊?
*/
long y = 299792458L * 60 * 60 *24 * 365;
double distance = 16.4 * y;
double length = 0.46;
double num = Math.ceil(distance/length); //Math类中的方法ceil表示向上取整,注意,这个函数返回的结果还是一个double
System.out.println("总共需要喜鹊数:" + (long)num);
}
}
注意:在上面计算这么大的数值时还是会存在一定的精确问题,因为这里面涉及到浮点数据运算就一定有精度丢失的风险
练习4:输入年号,显示是平年还是闰年
闰年的条件:1、能被4整除且不能被100整除,2、能被400整除(这两个条件只要有一个满足则为闰年)
package com.xiaoxie.test;
import com.xiaoxie.utils.MyScanner;
public class Test10 {
public static void main(String[] args) {
int year = (int) MyScanner.Result("请输入需要验证的年份:", Integer.class); //使用自己简单封装的Scanner
//判断是否为闰年,调用自定义方法,在判断过程中使用三目运算符
System.out.println(isRun(year)?year + "年是闰年":year+"年不是闰年");
}
private static boolean isRun(int year) {
boolean isRun = false;
if(((year % 4 == 0) && (year % 100 != 0)) || (year%400==0) ) {
isRun = true;
}
return isRun;
}
}
练习5:int的四个字节拆分成byte
package com.xiaoxie.test;
public class Test11 {
public static void main(String[] args) {
//把int的四个字节拆分成byte类型
/*
* byte只有两个字节,int有四个字节,
* 把int看作是四个byte
*/
//从高位向低位分四个字节处理
int i = 56234;
// 第一个字节
int temp = 0xFF0000;
//把temp与i进行位的与运算后再向右移24位
int result_1 = ((i & temp)>>>24);
//第二个字节
temp = 0x00FF0000;
//把temp与i进行位的与运算后再向右移16位
int result_2 = ((i & temp)>>>16);
//第三个字节
temp = 0x0000FF00;
//把temp与i进行位的与运算后再向右移8位
int result_3 = ((i & temp)>>>8);
//第四个字节
temp = 0x000000FF;
int result_4 = (i & temp);
//打印结果
System.out.println(i + "的32位字节二进制表示为:" + String.format("%32s", Integer.toBinaryString(i)).replace(" ", "0"));
System.out.print("第一个字节:" + String.format("%8s", Integer.toBinaryString(result_1)).replace(" ", "0"));
System.out.print("第二个字节:" + String.format("%8s", Integer.toBinaryString(result_2)).replace(" ", "0"));
System.out.print("第三个字节:" + String.format("%8s", Integer.toBinaryString(result_3)).replace(" ", "0"));
System.out.print("第四个字节:" + String.format("%8s", Integer.toBinaryString(result_4)).replace(" ", "0"));
}
}