2019.6.4 14:15 三刷结束留念 ——小楠楠
2019.4.10 17:22 二刷结束留念
day01的笔记拖了好久才写好,其实实际用时并不是特别长。写好之后阅览了一下自己的成果,好有成就感,没想到可以写那么多,细节也都写的很详细,不论是自己复习或者给其他人看,都是很清楚明了、简单易懂的,开心(*^▽^*)更坚定了我写下去的决心,有了更多的动力~
接下来就开始day2的学习啦。刚开始都是比较简单基础的内容,一定要把这个基础打好,每一个细节都不可以忽视~这次要加快速度,不能那么拖沓~
上节课讲了Java的搭建环境,这节课讲Java语言的基本组成~
Java语言的基本组成包括:关键字,标识符,注释,常量和变量,运算符,语句,函数,数组。
我们如果学C#,C++,也都会学这些东西,只是表现形式不同。学习的时候,将它们的使用特点记住了,等有一天即使不做Java,例如换成C++,编程思想也一模一样,只不过表达形式不同而已。就像用中文、英文,见了面都要说你好一样,思想没变,表达形式不同。
01-标识符
学英语的时候,先学音标、字母、单词,再学句子、短文,Java也一样,它里面的东西都是固定的,写错了的话,虚拟机就不识别了。
关键字:被Java赋予了特殊含义的单词。(C++也具有关键字,有一些被C++赋予了特殊含义的单词,但和Java的关键字会有不同)
标识符:我们在程序中自定义的一些名称,比如说类名。它由:26个英文字母大小写,数字0-9,符号_和$组成。
定义合法标识符的规则:1.数字不可以开头。2.不可以使用关键字。
Java语言中严格区分大小写。
Java中的名称规范:
包名:多单词组成时所有字母都小写,如xxxyyyzzz。
类名接口名:多单词组成时,所有单词的首字母大写,如XxxYyyZzz。
变量名和函数名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写,如xxxYyyZzz。
常量名:所有字母都大写。多单词时每个单词用下划线连接,如XXX_YYY_ZZZ。
注释:单行、多行、文档注释(文档注释是Java语言特有的注释)。
对于单行和多行注释,被注释的文字,不会被JVM(java虚拟机)解释执行。
对于文档注释,是java特有的注释,其中注释内容可以被JDK提供的工具javadoc所解析,生成一套以网页文件形式提现的该程序的说明文档。
注释是一个程序员必须要具有的良好编程习惯。
02-常量
常量表示不能改变的数值。
Java中常量的分类:
1,整数常量。所有整数。
2,小数常量。所有小数。
3,布尔型常量。较为特有,只有两个数值,true false。
4,字符常量。将一个数字字母或者符号用单引号(‘’)标识。一般包括字母、数字、符号。
注意区分字符和数字,‘4’是字符,用单引号括着,4是数字。
注意:单引号只可以存放单个字符。
5,字符串常量。将一个或者多个字符用双引号标识。双引号可以存放多个字符。
“ab”、“a”、“”都是字符串,“”是空内容的字符串(哈哈哈,不管穿多少肉都是羊肉串,哪怕吃光了还是一串吃光了的羊肉串)。
6,null常量。只有一个数值就是null。
对于整数:Java有三种表现形式。(确切的说有四种,最后一种二进制会单独列出来说)
十进制:0-9,满10进1.
八进制:0-7,满8进1,用0开头表示。
十六进制:0-9,A-F,满16进1,用0x开头表示。
03-进制的特点
进制的由来:任何数据在计算机中都是以二进制的形式存在的。二进制早期由电信号开关演变而来。
二进制的产生要表示一些数据,它有一个基本的规则,就是它由八位/八个开关来表示一个最小的单位,叫做字节。
一个整数在内存中一样也是二进制的,但是使用一大串的1或者0组成的数值进行使用很麻烦。所以就想把一大串缩短点,将二进制中的三位用一位表示,这三位可以取到的最大值就是7,超过7就进位了,这就是八进制。但三位有时候也会有点短,可以将二进制中的四位用一位表示,这就是十六进制。之所以有八进制、十六进制等等,就是为了更方便的表示数据。进制越大,表现形式越短。
代码示例:打印“60”和“0x3c”,结果都是60。60是十进制表现形式,0x3c是60的十六进制表现形式。一个整数有四种表现形式:二进制,八进制,十进制,十六进制。计算机里存的是二进制,无论什么样的数据,计算机里存的都是二进制。
04-进制转换(十进制和二进制)
十进制——>二进制。
原理:对十进制数进行除2运算。
以6为例:
当然也不需要拿笔去算,这里只是展示一下它的原理,我们有更便捷的方法。
二进制——>十进制。
原理:二进制乘以2的过程。
一些常见的2的次幂的数字和所对应的位,哪一位是1就加上对应的数字。
当上述所有位都是1的时候,将128,64,...,1相加,结果是255,因此,一个字节的最大值是255。
IP地址每一段的最大值也是255,因为每一段都由一个字节来表示~
二进制的运算,其实和十进制方法都是一样哒。
05-进制转换(八进制和十六进制)
二进制——>十六进制:
四个二进制位就是十六进制位。
二进制——>八进制:
三个二进制位代表一位。
06-进制转换(负数二进制)
其实就是所对应的正数的二进制取反加1。
以-6为例:
注意:负数的最高位都是1。
07-变量
常量是一个固定不变的值,而变量是变化的。
我们可以在内存中开辟一个空间,把这个不确定的要运算的值存放在该空间中,这个空间存在的好处是,这个空间中的值可以任意的变化,你只要操作该空间,就可以操作该空间的值。
变量:就是将不确定的数据进行存储。也就是需要在内存中开辟一个空间。
运算是在内存中进行的,内存就是一个运算区域。为什么内存越大运行越快呢,因为内存越大里面存储的数据越多,这个时候往往需要提高CPU的性能,CPU处理得数据越多,代表越快,如果内存小,CPU只能处理这么一点数据,运行得快也没有意义。所以内存就是这台机子的瓶颈,CPU够快呢,内存就要够大,这也就是为什么双核、四核的内存配备的内存基本都是2G以上(这是当年的数据,现在内存已经非常大了)。
那么如何开辟内存空间呢?
这个空间的类型,称为数据类型,一个内存空间的数据类型是确定的,它只能存放这种类型的数据。这个空间的名称,称为变量名。
开辟内存空间,就是通过明确数据类型、变量名称、数据来完成。
首先说数据类型,怎么表示不同的数据类型呢?
Java语言是强类型语言,对于每一种数据都定义了明确的具体数据类型,在内存中分配了不同大小的内存空间。
数据分为两大类型,基本数据类型和引用数据类型,今天主要说基本数据类型,引用数据类型先放一放。 基本数据类型包括数值型、字符型、布尔型三种。
数值型-整数类型:
之所以划分出这么多类型,是因为它们在内存中开辟的空间不一样大,多大的数据用多大的“碗”装,这样可以节约内存。
byte:字节。一个8位,即8个二进制位。-128~127,即-2^7~2^7-1。
为什么8位有符号类型的数值范围是-128~127?
我查阅到了另外一篇文章,里面有详细的说明,在这里做一些引用,更详细的可以去这篇文章中阅览。
在计算机的存储和计算中,统一的是采用补码进行处理和运算的,在弄清楚采用补码的好处之前,我们需要明确如下三个概念:
原码:是一种计算机中对数字的二进制定点表示方法。原码表示法在数值前面增加了一位符号位(即最高位为符号位):正数该位为0,负数该位为1(0有两种表示:+0和-0),其余位表示数值的大小。
反码:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。
补码:正数的补码与其原码相同;负数的补码等于其反码+1。
-128在原码和反码中无法表示,在补码中却可以表示(用-127的补码1000 0001减1得到1000 0000)。而计算机中数值以补码形式存储和运算,当然-128可以表示出来,因此8位有符号数值的范围是-128~127,同理其他位数(16、32、64)也可以以此类推。
short:短整型。两个8位,即16个二进制位。-32768~32767,即-2^15~2^15-1。
int:整型。四个8位,即32个二进制位。-2^31~2^31-1。
long:长整型。八个8位,即64个二进制位。-2^63~2^63-1。
CPU里面的内存,我们称为缓存,是用来缓冲数据用的,缓存越大,里面存放的数据量越大,处理的东西也更多一些。所以去买硬盘、CPU,要看缓存~硬盘现在有一些技术在里面,比如寻道方式,这些方式是通过软件来操纵的,硬盘中用小芯片来操作这些东西,运算的时候,硬盘本身带内存的话,在硬盘内存里运算就可以了,这就是硬盘的缓存~
数值型-浮点类型:
单精度和双精度的最大区别就是精确程度不同,在内存中占用的空间也不一样大。
float:单精度浮点型。四个8位,即32个二进制位。
double:双精度浮点型。八个8位,即64个二进制位。
字符型:
char:两个8位。取值范围是0~65535。
PS:直接写 char ch =数字,不要加单引号,Java会自动把它转换为对应编码的字符。
布尔型:
boolean:取值只有两个,true和false。
PS:整数默认:int,小数默认:double。
定义变量的格式:
数据类型 变量名=初始化值;
例:
定义一个int类型变量,取值为4;
int x=4;
其中int是这个空间的类型,x是这个空间的名称,4是这个空间里面存储的值。
只要数据是不确定的,就用定义变量的方式来存储。在C++有可能定义变量的格式会发生改变,表达形式会变,但思想是不会变的。
除了存储数据以外,这个变量块可以被重用。
比如想把数据变成10,直接在int x=4;后面接:x=10,注意不能用:int x=10,因为相当于又重新申请了一个空间x,就重复了。
int x=4;
x=10;
演示其他数据类型:
byte b=2;//在-128~127这个区间内取值都可以;
试一下
byte b1=128;
编译,看会出现什么情况。
128已经超过一两的米饭啦,非要给里面塞一两多的米,肯定会有米掉出来~
short s=30000;//同理在-32768~32767之间就OK。
long l=4;//也可以给后面用l表示一下,l代表long,long l=4l;
定义:float f=2.3;编译:
因为小数默认是double,所以不能把八两的数据存放到四两的碗里面去。如果非要存,也可以,在2.3后面加f,标识一下2.3其实是单精度。
float f=2.3f;
double d=34.56;//这个就完全没有问题
接下来是char类型,char类型的标识是单引号:
char ch=‘4’;
char ch1='a';
char ch2='+';
char ch3=' ';//空格也是字符
布尔类型,只有两种取值:
boolean bo=true;
boolean bo1=false;
再复习一下:
什么时候定义变量呢?
当数据不确定的时候,需要对数据进行存储时,就定义一个变量来完成存储动作。
如下代码的后台运算过程:在内存空间里有一个变量a值为5,把5取出来,和6做运算,再把相加后的结果重新赋值给a,这时a的值就变化了。
int a=5;
a=a+6;
08-类型转换
如下代码,明明是一个非常简单的加法运算,为什么会编译错误呢?
这是由Java的强类型导致的。
b是字节型变量,由一个8位组成,2整型变量默认为int型,由4个八位组成,如果一个小方框代表一个8位,则这个加法运算可以表示为如下图,显然是不可以的。
对于整数类型的数据,它们之间是可以做运算的,但是得有一个操作作为前提,叫做自动类型提升(或自动类型转换/隐式类型转换),先要把两个数据类型提升为同一种类型的数据,才能够做运算。
怎么提升呢?
原则是以大的为主,小的向大的提升。
自动类型提升后,运算的结果类型也是int型,是否可以将结果复制给b(byte型)呢?显然不可以。这就是刚才编译失败的原因~
那为什么byte b=3;的时候不会报错呢?因为3是整数常量,它赋值给字节型变量b会自动判断是否在字节型变量的范围之内,在这个范围之内的话,就赋值成功。而b=b+2;会报错的原因是,=后面的b是一个变化的值,运算结果提升为整数之后数值是不确定的,所以会报错说容易丢失精度。(此处还是有一点没看懂)(20190410:看懂啦。就是b的值不确定,所以不确定b加上2之后的结果是否还在byte的范围之内。而b=3不会报错是因为3是一个确定的值,可以直接判断它是否在这个范围之内。)
一些数据类型自动提升的情况:
所有的byte型(一个8位)、short型(两个8位)和char型(两个8位)的值将被提升到int(四个8位)型。
如果一个操作数是long型,计算结果就是long型。
如果一个操作数是float型,计算结果就是float型。
如果一个操作数是double型,计算结果就是double型。
比如int型和long/float/double型做运算,结果就是long/float/double型。
如果非要把b+2的值赋值给b呢?
这个时候可以进行强制类型转换(显式类型转换)。
把前三个8位强行丢弃,只留最后一个8位。
如果前三个8位都是0,丢掉肯定不影响,如果都是1,丢掉之后就会丢失精度。
强制类型转换,想转换成什么类型,就给前面加括号,里面写上这个类型,如:
b=(byte)(b+2);
再来一个特殊的情况:
System.out.println('a');//打印一个字符a,打印结果为a
System.out.println('a'+1);//打印结果为98
每一个字符都有它的二进制形式,进而也有对应的十进制表现形式。a的十进制表现形式是97。a是字符型,由两个8位组成,1是整型,由四个8位组成,这两者做运算,a会进行自动类型提升,提升为整型,也就是97,因而最后运算结果为98。
如果想看98所对应的字符是什么怎么做呢?
System.out.println((char)('a'+1));//打印结果为b
System.out.println('A'+0);//打印结果为65,即A的十进制表现形式为65
System.out.println((char)4);//会打印出对应十进制表现形式为4的字符
System.out.println((char)5);//会打印出对应十进制表现形式为5的字符
所以char型也是可以运算哒,因为它们都有对应的数字表现形式~
09-算术运算符
常量也讲啦,也把常量存到内存里面去了,接下来是不是应该做运算了呢?计算机存储数据的目的就是为了做运算(捂嘴笑)。
因此接下来讲运算符,运算符包括:
算数运算符
赋值运算符
比较运算符
逻辑运算符
位运算符
三元运算符
这节课先讲算数运算符~
int x=4270;
x=x/1000*1000;
System.out.println(x);//输出结果为:4000
因为x和1000都是整型,两者相除结果还是整型,为4,4再和1000相乘,结果就是4000。
取模运算(即取余数):
System.out.println(10%4);//输出为2
System.out.println(1%5);//输出为1
System.out.println(-1%5);//输出为-1
System.out.println(1%-5);//输出为1
取模运算的一个规律:左边如果小于右边,结果是左边;左边等于右边,结果是0;右边是1,结果是0;如果出现负数,结果是左边。这个问题开发一般不多见,面试可能会考,因为是边边角角的东西,不知道近几年面试的行情怎样啦。
自增/自减运算:
int a=3,b;
b=a++;
System.out.println(b);//输出为3
System.out.println(a);//输出为4
a++;这句话的意思是说,给a中变量的值进行一次加1操作,并把加1操作后的值重新赋给a,相当于a=a+1;,但是a++;每次只可以加1,a=a+1;中的1也可以换成别的数字~
当b=a++;时,就涉及到了++先算后算的问题。它会先把a中的值赋值给b,然后a再自增1。当b=++a;时,a先自增1,然后再将a中的值赋值给b。
哈哈哈,b=a++;是先出去玩再吃饭,b=++a是先吃饭再出去玩。
字符串连接:
System.out.println("hahahahaha"+"hahahahaha");
字符串数据和任何数据使用+都是相连接,最终都会变成字符串。
System.out.println("ab"+5+5);//输出为ab55
System.out.println("5+5="+5+5);//输出为5+5=55
System.out.println("5+5="+(5+5));//输出为5+5=10
10-转义字符
System.out.println("hello world");
现在想要在hello和world中间加一个换行,就要用到一个特殊符号:\n。
System.out.println("hello\nworld");
转义字符:通过\来转变后面字母或者符号的含义。
如:
\n:换行。
\b:退格。
\t:制表符。相当于tab键。
\r:按下回车键。windows系统中,回车符是由两个字符来表示:\r\n。
需求:想在屏幕上打印一个带着双引号的hello world。
System.out.println(""hello world"");
这样写是不可以的,因为第一个双引号是字符串开始,第二个双引号是字符串结束,从h开始就是无效代码了。这个时候就需要转变双引号的含义,给前面加\,将它变成一个单纯的双引号。
System.out.println("\"hello world\"");
需求:打印一个两端都是反斜杠\的hello world。
System.out.println("\\hello\\");
另外
char ch='\n';
这样写也是可以的,因为\把n转义了,变成了一个换行符。
char ch='\"';//一个双引号
char ch='\'';//一个单引号
如果不写\就挂掉了~
char c='你';//一个汉字两个字节,char类型也是两个字节,所以是OK哒
11-赋值和比较运算符
先说赋值运算符~
=:把右边赋值给左边。
+=:把左右两边的和赋值给左边。
-=、*=、/=、%=同理。
一个例子:
short s=4;
s=s+5;//如果这样写会报错
s+=5;//如果这样写OK的
因为s=s+5;是两次运算,先做加法再做赋值运算。=右边的s是两个字节,5是4个字节,s+5时s会自动进行类型提升,变成四个字节,但是=左边的s还是两个字节,因此会报错。
而s+=5只会进行一次赋值运算,直接将左右两边的和赋值给s,在这个过程中会对+=左边的s进行自动类型提升,因此编译是没有问题的~(20190410:有点不懂。是因为直接将左右两边的和复制给s,而左右两边的和是一个确定的数,所以不影响吗?)
一种特殊的形式,同时给a、b、c赋值:
int a,b,c;
a=b=c=5;
接下来说比较运算符~
比较运算符有一个特点,它运算完的结果要么是真,要么是假。
如:
System.out.println(3>4);//输出为false
12-逻辑运算符
所谓逻辑运算符,就代表一种关系~
逻辑运算符用于连接boolean类型的表达式。
假设x=4。
x>3 & x<6 = true & true =true;
&(与):只要两边的boolean表达式结果有一个为false,那么结果就是false。
只有两边都为true,结果才为true。
|(或):两边只要有一个为true,结果为true。
只有两边都有false,结果为false。
^(异或):两边相同结果是false,两边不同结果是true。就是和|有点不一样,也不是全部不一样。不一样的地方是:true^true=false。
!(非):略。
&和&&的特点:
&:无论左边是true是false,右边都运算。
&&:当左边为false时,右边不运算。
|和||的特点:
|:无论左边是true是false,右边都运算。
||:当左边为true时,右边不运算。
13-位运算符(左移右移)
位运算符中的“位”就是二进制位,所以位运算符是进行二进制运算的运算符。
3<<2示例:
左移前的3的二进制表现形式:
左移:
右边补零:
结果为12。
即3<<2=12。
6>>2示例:
右移前:
右移:
左边补0:
结果为1。
即6>>2=1。
发现一个规律,一个数往左移,越移越大,一个数往右移,越移越小。
其实,往左移几位,就相当于给这个数乘以2的几次幂;往右移几位,就相当于给这个数除以2的几次幂。
因此,最快的运算是位运算。但是也有局限性,只能是2的倍数。
>>:最高位补什么由原有数据的最高位值而定。
如果最高位0,右移后,用0补空位。
如果最高位1,右移后,用1补空位。
>>>(无符号右移):无论最高位是什么,右移后,都用0补。
14-位运算符(与-或-异或)
6&3示例:
6|5示例:
6^5示例:
一个数异或同一个数两次,结果还是那个数:
是最简单的加密解密方式,但是这种太简单啦~
15-位运算符(练习)
练习1:最有效率的方式算出2乘以8等于几?
我们可以很简单的直接写2*8,但这并不是最高效的方式,运算过程还是稍微有点复杂的:
但是位运算就非常快,直接左移三位就OK咯。
所以这道题的正确答案是:2<<3。
练习2:对两个整数变量的值进行互换(不需要第三方变量)。
int n=3,m=8;
/*
n=n+m;
m=n-m;
n=n-m;
*/
//但是如果n和m的值非常大,容易超出int范围,用下面这个方法就可以解决这个问题:
n=n^m;
m=n^m;//(n^m)^m
n=n^m;//(n^m)^n
//这种方式是一种技巧型方式,一般不太容易想到,平常开发的时候,都会用引入第三方变量这个方法。
System.out.println("交换前:n="+n+",m="+m);
System.out.println("交换后:n="+n+",m="+m);
16-位运算符(练习2&三元运算符)
取最低四位:
取次低四位,将它右移四位再&:
以此类推,可以拿到它的所有的四位,就可以轻松将二进制转换成十六进制了。
例,取60的十六进制:
以此类推,就可以完成60的十六进制的转换。
用代码实现:
int num=60;
//获取60的最低4位,通过&15
int n1=num&15//=12;
System.out.println(n1>9?(char)(n1-10+'A'):n1); //这句代码是有问题的,:n2是int型,但:前面是char型,这里先略过,后面会讲解决方式
//要获取下一组4位,将60右移4位
int temp=60>>>4;//注意这里要用三个>的右移,因为如果是>>,是带符号右移,负数前面永远会补1,这个数永远移不完。而用>>>才可以把原有的数据移光~
//对temp的值进行最低四位的获取
int n2=temp&15//=3;
System.out.println(n2>9?(char)(n2-10+'A'):n2);
这只是一个例子,代码还有些问题,明白思想就好~后面会讲完整的获取十六进制的方式。
17-语句(if)
程序流程控制:
判断结构
选择结构
循环结构
先讲判断结构~有一个典型的就是if语句。
它有三种格式,第一种是只有if。
if(x>1)
{
System.out.println("yes");
}
System.out.println("over");
如果if控制的语句只有一条,花括号也可以不写~
if(x>1)
System.out.println("yes");
System.out.println("over");
第二种是有一个else:
if(x>1)
{
System.out.println("yes");
}
else
{
System.out.println("over");
}
会发现有点像三元运算符,其实三元运算符是if-else的简写形式。
但它们也是有区别的:
if else结构 简写格式:变量=(条件表达式)?表达式1:表达式2;
三元运算符:
好处:可以简化if else代码。
弊端:因为是一个运算符,所以运算完必须要有一个结果,而if else就不一定需要一个运算结果。
第三种是有多个else,满足任意一条则语句执行结束:
int n=3;
if(n>1)
System.out.println("a");
else if(n>2)
System.out.println("b");
else if(n>3)
System.out.println("c");
else
System.out.println("d");
而下述几个if不是一个整体,满足之后还会执行下一个:
int n=3;
if(n>1)
System.out.println("a");
if(n>2)
System.out.println("b");
if(n>3)
System.out.println("c");
else
System.out.println("d");
18-语句(if练习)
需求1:根据用户定义的数值不同,打印对应的星期英文。
int num=2;
if(num==1)
System.out.println("monday");
else if(num==2)
System.out.println("tsd");
......
else
System.out.println("nono");
需求2:根据用于指定月份,打印该月份所属的季节。
3,4,5春季 6,7,8夏季 9,10,11秋季 12,1,2冬季
int x=4;
if(x=3||x=4||x=5)
System.out.println(x+"春季");
else if(x=6||x=7||x=8)
System.out.println(x+"夏季");
else if(x=9||x=10||x=11)
System.out.println(x+"秋季");
else if(x=12||x=1||x=2)
System.out.println(x+"冬季");
else
System.out.println(x+"月份不存在");
或者这样写:
if(x>12||x<1)
System.out.println(x+"月份不存在");
else if(x>=3&&x<=5)
System.out.println(x+"春季");
else if(x>=6&&x<=8)
System.out.println(x+"夏季");
else if(x>=9&&x<=11)
System.out.println(x+"秋季");
else
System.out.println(x+"冬季");
19-语句(Switch)
这节讲选择结构。
int x=2;
switch(x)
{
case 4:
System.out.println("a");
break;
case 6:
System.out.println("b");
break;
case 8:
System.out.println("c");
break;
case 10:
System.out.println("d");
break;
default:
System.out.println("e");
break;//这个也可以省略,因为这里肯定结束啦
}
switch语句的四个特点:
a.switch语句选择的类型只有四种:byte,short,int,char
b.case之间与default没有顺序 ,先执行第一个case,没有匹配的case执行default
c.结束switch语句的两种情况:遇到break,执行到switch语句结束
d.如果匹配的case或者default没有对应的break,那么程序会继续向下执行,运行可以执行的语句,直到遇到break或者switch语句结尾结束。
20-语句(Switch练习)
还是季节那个例子:
if和switch的不同:
if除了判断具体数值,还可以判断区间,当区间很大的时候,switch很难把它们都列举出来。对于运算结果是布尔型的,if可以判断,switch不可以。
if和switch什么时候用才是我们重点要学的东西~
当要判断的数值不多且是那四种数据类型的时候,用switch,因为效率稍高。
其他情况:对区间判断,对结果为布尔类型判断,使用if,if的使用范围更广~