编写简单的程序
1计算圆的面积
圆的面积=半径*半径*π
下面如何完成这个流程(算法)
首先需要读入半径,然后利用公式计算,然后显示面积。
public static void main(String[] args) {
double radius; //半径
double area; //面积
//step1 read in radius
radius=50.0;
//step2 compute area
area=radius*radius*3.14159;
//step3 display area
System.out.println("the area for circle of radius "+radius+" is "+area);
}
2.从控制台输入半径
Scanner类你可以理解为是JDK为我们封装的一个扫描器,扫描器扫描设备的输入和输出。
在Java中将输入设备抽象封装为了System.in,将输出设备抽象封装为了System.out
我们只需要将输入设备放入到扫描器中就可以捕获键盘的输入了。
通过以上的案列引入下面的概念:标识符,变量,赋值表达式,常量,数据类型及其操作,数值型直接量
3标识符
标识符就是我们给类和变量或者方法等等自定义命名的单词。比如上面我们给输入的半径放入一个变量中(radius)这个radius就是我们给变量取得名字,这个名字就是标识符。并不是所有单词都可以作为标识符的,比如有的单词背JDK使用了,我们就不能用作标识符,这鞋被JDK使用的单词叫做保留字。Java的保留字有哪些自己去百度吧。
所有的标识符必须遵守如下原则:
- 由字母,数字,下划线或美元符号构成的序列
- 不能以数字开头
- 识符不能是保留字
- 长度可以任意
4变量
变量用来保存程序需要用到的数据。可以随时更改。我们上面的radius和area就是变量
使用变量一定要声明类型:变量类型声明 变量名
例如:
- float radius;
- int sum;
- String name;
5赋值表达式
给变量赋值的方式常用的就是几种:
变量=数据:radius=50;
变量=变量:area=area2;
变量=表达式:area=radius*radius*3.14;
以上都是右边的数据拷贝给左边。
如果一个数据要给很多变量那就可以这么写:i=j=t=k=88;它等价于:
k=88;
t=k;
j=t;
i=j;
在赋值中,右边和左边的类型要兼容,就是说int i=5.0是要报错的,左边是整数类型,右边确实浮点数,必须做类型转换。类型转换后面会提到。
6常量
如果一个变量赋值后不想这个变量再被改变,那么就要将这个变量变作常量。常量赋值一次后至始至终都不能改变其值
用final声明的变量就是常量
final double π=3.14;
final String ip="192.168.1.114";
7数据类型及其操作
Java为每个数据类型都分配了内存大小
数值型:
byte 一个字节 一个字节=8位,一位最多有相中状态,2*2*2*2*2*2*2*2=256,也就是说byte类型可以保存256个数字,因此可以保 存 -128到 +127之间的数值
short 二个字节 算法同上
int 四个字节 算法同上
long 8个字节 算法同上 范围是在-2的63次方到2的63次方减一的范围
float 4个字节 单精度
double 8个字节 双精度
float和double是IEEE 754标准下,制定的一个表示小数的标准。浮点数不能用于银行的人民币计算,只能用作普通的数据计算。因为浮点数不是绝对准确的。
7.1浮点数的问题
首先来看看浮点数不准的问题
public class Demo02 {
public static void main(String[] args) {
/*浮点数详解*/
float a = 2.0f -1.1f;
System.out.println(a);//0.9
//
double b = 2.0d -1.1d;
System.out.println(b);//0.899999999999999999999999999999
double c = sub(2.0d,1.1d);
System.out.println(c);
float unit = Float.valueOf(1000);//取出换算单位1000.0
float svt = ((20000000f+1))/unit;//加0.001
System.out.println(String.valueOf(svt));//精度丢失
double unit1 = Float.valueOf(1000);//取出换算单位1000.0
double svt1 = ((20000000d+1))/unit1;//加0.001
System.out.println(String.valueOf(svt1));//ok
System.out.println(Long.toBinaryString( Double.doubleToLongBits(20000001d)));
System.out.println(Integer.toBinaryString(Float.floatToIntBits(20000001)));
System.out.println(Integer.toBinaryString(Float.floatToIntBits(16777215)));
System.out.println(Integer.toBinaryString(Float.floatToIntBits(16777216)));
System.out.println(Integer.toBinaryString(20000001));
float f = 20000001;
System.out.println(f);
double d =20000001;
System.out.println(d);
}
public static double sub(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.subtract(b2).doubleValue();
}
}
输出结果让人大跌眼镜!!!
或者我们再看:
public static void main(String[] args) {
float f_v1 = 20;
float f_v2 = 20.3f;
float f_v3 = 20.5f;
double d_v1 = 20;
double d_v2 = 20.3;
double d_v3 = 20.5;
System.out.println((f_v1 == d_v1)?"true":"false");//true
System.out.println(f_v2 == d_v2?"true":"false");//false
System.out.println(f_v3 == d_v3?"true":"false");//true
}
奇怪了,貌似我们根本无法抓住浮点型的本质。要想搞清楚来龙去脉就一定要搞清楚浮点数是怎么存储的才行。我们都知道内存中存储的是二进制。普通十进制正数存储在内存中直接转二进制就行了。
但是以上可以确定的就是小数点后可以被2乘到10的就会为true,否则就是false,不信请看:
要搞清楚这里的谜团就要了解以下浮点数的存储原理。
7.2浮点数存储过程
1如何将十进制转换成二进制的浮点数?
首先会将整数部分转换为二进制,然后将小数部分转换为二进制,最后正数部分和小数部分相加
以20.5来说
20转换后是10100,而后面的0.5要转换为二进制徐亚乘2,乘完之后取整数部分,然后用
乘的结果减去整数部分,然后接着乘2,直至最后没有小数或者小数出现循环即乘完
如果等于0,就取前面不为0的部分
0.5*2=1.0(取1)
0.0*2=0(0)
所以转换后0.5就成了0.1,所以20.5转换后就成了:20.5=10100.1(二进制)
---------------------------------------------------------------------------------------------------------------
再看一个20.3
20=10100
0.3*2=0.6(取0)
0.6*2=1.2(取1)
0.2*2=0.4(0)
0.4*2=0.8(0)
0.8*2=1.6(1)
0.6....(到上一步就进入循环了)
因此就是:20.3=10100.010011001.............
Java 语言支持两种基本的浮点类型: float 和 double 。java 的浮点类型都依据 IEEE 754 标准。IEEE 754 定义了32 位和 64 位双精度两种浮点二进制小数标准。
2,如果要把十进制浮点数存储到内存空间中,也就四个字节中。首先要把浮点数转换为二进制的浮点数,然后再转换成科学计数法
拿20.5来说,20.5=10100.1(二进制)=1.01001E4(十进制的科学计数)=1.01001E100(二进制的科学技术),这里的E100
指的是2的100次方(此说有错误,因为10100.1变成了1.01001,小数点向前走了4位,正好就是二进制的100)。y因为float和double的存储空间不同,因此float和double就会存在看起来一样但是实际上不一样的情况,明白了吧?
再深入一点进去
在虚拟机中,float占据4个字节(32位),存储结构如下:
符号位:1位
指数为:8位
尾数位:23位
double类型占据8个字节,64位,存储结构如下:
符号位:1
指数位:11
尾数位:52
存储数据是一个萝卜一个坑, 首先存储符号位, 然后是 指数,最后尾数
比如20.5 = 1.010001E100(二进制)
这里使用到移位存储, 对于float 数值来说, 指数位要加上127, 即0111111(二进制)
000 001 00
+011 111 11
-------------------------
1000 0011
所以20.5 存储的数值 是 (float): 0-10000011-01001 00000 00000 00000 000
对于double来说,指数位要加上1023,即0111 111 111(二进制)
000 000 0100
+011 111 1111
--------------------
100 000 0011
所以在内存中存储为:0-1000000011-01001 +(47个0)
现在看到20.5 转换为float, double 的二进制数, 指数和尾数是不同的, 注意,
比较指数时 float 型会-127, double型 会-1023,因此:
float 型又变成了00000100
double型又变成0000000100
这时候比较,因为两个指数的位数不同,一个8位,一个10位,8位的数会在前面自动补0
比较尾数时,float型数会自动在后面补0直至与double 型相同的52位
同理20.3 存储的数值 是: (float) 0-10000011-01001 10010 10011 00101 001
(double)0-1000000011-01001(后面循环1001, 直至尾数为52位)
与20.5的比较相似, 20.3的float型二进制和double型二进制,符号位与指数位都相同, 但是尾数位不相同,float型到了23位之后都是0, double型一直1001循环到52位. 这就是float型与double型比较之后不相等的原因
如果要将三个比较结果 都为true, 需在d_v2加上 (float), 也就是将double强制转为float型
此处计算参考:https://blog.csdn.net/aduovip/article/details/47728921
总结,浮点数不是绝对精确的,double的精确度高于float,
7.3从键盘读取数值
如果你输入了类型不匹配或者数值大于了类型声明的范围就会报运行时异常。
7.4数值操作符
+
-
*
/ 除法中如果两个整数相除会舍去小数,除非其中有一个是浮点数。
% 求余,也叫做模运算。是求除法的余数的一种计算。6%3=0 6%2=0 6%4=2
求模运算多用在整数上,实际上也可以用在负整数和浮点数上。
在负整数上只有当被除数是负数的时候余数才是负数。
7.5 幂运算
使用方法Math.pow(a,b)来计算a的b次方。
8数值型直接量
直接量就是程序中直接出现的常量值。
比如:34 , 0.305
整型直接量
默认下一个整型直接量是int型的,只要直接量和变量类型一致就可以将直接量赋值给变量。
如果直接量的范围大过了变量的存储范围就会报编译错误。
如果要表示一个其他进制的直接量请这样写:
二进制:0B1111==15;
八进制:07777=4095;
十六进制:0xFFFF=65535;
浮点数直接量
5.0这个浮点直接量默认认为是double类型的。如果你想使用单精度那就要在数字后写上f,如:5.0F
double的精度比float高,如果不用于数值计算为了节约内存可以使用float。
System.out.println(1.0F/3.0F);
System.out.println(1.0/3.0);
回顾前面的浮点数的存储过程就知道为何double精度高于float了。
科学计数法
比如123456789这个数字你可以使用科学计数法
比如你可以这样表示:
1.23456789*(10的8次方)
也可以
1.23456789E8||1.23456789E+2
0.012=1.2E-2
E就是指数的意思
现在知道浮点数为何叫浮点数了吧,因为浮点数在内存中就是以科学计数法的方法存储的,当一个浮点数存储到内存中小数点就会浮动到一个新的位置,因此美名浮点数!
表达式以及操作符优先级
这个我一直没有记,总之我知道括号优先级最高,因此我需要有限计算的我就使用括号足矣
示例:显示当前时间
long totalMilliseconds=System.currentTimeMillis();
long totalSecond=totalMilliseconds/1000; //秒的总数
long currentSecond=totalSecond%60; //余多少秒
long totalMinutes=totalSecond/60; //分钟的总数
long currentMinute=totalMinutes%60; //余多少分
long totalHour=totalMinutes/60;
long currentHour=totalHour%24;
System.out.println("当前时间是:"+currentHour+"时"+currentMinute+"分"+currentSecond+"秒");
增强赋值操作符
+= i=i+5||i+=5;
-=
*=
/=
练习题(1)
int i=6;
i+=i+5;
练习题(2)
double a=6;
a/=2;
自增和自减操作符
++和--是对变量进行自增1好自减1的简写操作符。
int i=3,j=3;
i++;//4
j--;//2
这两个符号放在变量前面叫做前置操作,放在后面叫做后置操作。
数值类型转换
两个不同类型的数可以参加运算吗?可以。
一个整数和一个浮点数加入运算JDK会自动将整数转换为浮点数,比如:
3*5.0=====》》》3.0*5.0
总是可以将一个数值赋值给更大范围类型的变量
转换分为隐式转换和显示转换
隐式转换:总是可以将一个数值赋值给更大范围类型的变量。
显示装换:将大范围的类型转换为小范围的类型就必须显示转换。
警告:如果将一个大类型赋值给一个小类型,大类型必须显示转换,否则编译报错。转换必须小心,因为会导致精度丢失,但是不绝对。比如(double)1/2则精度增加。但是(int)6.5则精度丢失
double d=4.5;
int i=(int)d;
以上i变成了4,但是d还是4.5,Java中是值传递。
但是要注意,就目前JDK1.8来看
X1 op= X2形式的增强赋值表达式,走的过程是X1=(X1's Type)(X1 op X2)
int sum=0;
sum+=4.5;//sum=(int)(sum+4.5) -------------->4
int i=1;
byte b=i;//报错,int型变量给byte型需要显示转换。
但是整数直接量(默认整型)赋值给byte只要不超出范围就可以