Java基础
Posted 一路晨光
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java基础相关的知识,希望对你有一定的参考价值。
一、Scanner的next()方法和nextLine()方法
1、next()一定要读取到有效字符后才可以结束输入,对输入有效字符之前遇到的空格键、Tab键或Enter键等结束符,next()方法会自动将其去掉,只有在输入有效字符之后,next()方法才将其后输入的空格键、Tab键或Enter键等视为分隔符或结束符。next方法不能得到带空格的字符串。
2、nextLine()方法的结束符只是Enter键,即nextLine()方法返回的是Enter键之前的所有字符,它是可以得到带空格的字符串的。
3、Scanner.nextInt()是从(流,控制台)中读取一个整数到空格和回车结束,如果输入的不是数字会抛出异常。nextInt()在顺序读取流的时候会把回车留在流中。这样先用nextInt() 和nextLine()连用时,nextLine()会读到空字符串。
4、在实际工作中很少使用 Scanner在控制台编程!一般控制台只是用来调试软件的输出目标。
二、java应用开发步骤
1、编写Java 源文件(文本文件)(记事本,Eclipse)
2、编译为.class 字节码文件
3、使用Java 虚拟机执行 .class字节码文件
c c++是直接翻译成机械码,java要先编译再解释。所以java比较慢,cc++比较快。java源文件是人能够看懂的程序脚本,经过变编译器编译为计算机能够处理的 2进制数据和指令,在进一步有计算机执行和处理!
计算机只能处理数据,任何软件的功能最终都要转换为数据计算!.metadata 是eclipse的配置信息保存目录。
三、Java的开发环境-JDK
JDK java 开发工具包
|--bin 包含一些用于开发Java程序的工具,例如:编译工具 (javac.exe)、运行工具 (java.exe) 、打包工具 (jar.exe)等。
|-- lib 包含开发Java程序所使用的类库文件。 (tools.java)
|-- src.zip: API的源文件 System.java
|-- jre JRE Java运行环境
|-- lib Java运行时环境所使用的核心类库。(rt.java)
|-- bin (java_vm)JVM Java虚拟机
JDK JRE JVM三者的联系与区别
JDK
Java Development ToolKit(Java开发工具包)。JDK是整个JAVA的核心,包括了Java运行环境,一堆Java工具(javac/java/jdb等)和Java基础的类库(即Java API包括rt.jar)。
JRE
Java Runtime Enviromental(java运行时环境)。所有的Java程序都要在JRE下才能运行。包括JVM和JAVA核心类库和支持文件。与JDK相比,它不包含开发工具——编译器、调试器和其它工具。
JVM
Java Virtual Mechinal(JAVA虚拟机)。JVM是JRE的一部分,运行java字节码文件。JVM 对上层的Java 源文件是不关心的,它关注的只是由源文件生成的类文件(class file )。
J2SE J2EE J2ME
java2平台包括:标准版(J2SE)、企业版(J2EE)和微缩版(J2ME) 三个版本。
J2SE就是Java2的标准版,主要用于桌面应用软件的编程;Standard Edition(标准版) J2SE 包含那些构成Java语言核心的类。比如:数据库连接、接口定义、输入/输出、网络编程
J2EE是Java2的企业版,主要用于分布式的网络程序的开发,如电子商务网站。Enterprise Edition(企业版) J2EE 包含J2SE 中的类,并且还包含用于开发企业级应用的类。比如:EJB、servlet、JSP、XML、事务控制。
J2ME主要应用于嵌入式系统开发,如手机和PDA 的编程;Micro Edition(微缩版) J2ME 包含J2SE中一部分类,用于消费类电子产品的软件开发。 比如:呼机、智能卡、手机、PDA、机顶盒。
简单讲就是
j2se java 2 simple edition 小型程序用
j2ee java 2 enterprise edition 大型程序用
j2me java 2 micro edition 手机上用
他们的范围是J2SE包含于J2EE中,J2ME包含了J2SE的核心类,但新添加了一些专有类。
四、环境变量
linux环境下
PATH 是Linux操作系统的环境变量
$PATH 是读取变量的值
echo $PATH 命令就是将$PATH 取回的变量值显示到屏幕
简单说就是看看PATH变量的值
PATH 变量的作用: 操作系统可执行命令的搜索路径,操作系统在执行命令时候,
逐一搜索PATH指定的路径,找到命令执行如果找不到就报错
误:command not found
export 导出命令,可以用来修改环境变量
export PATH=/bin
在终端窗口中的环境变量设置,只在当前窗口中生效。关闭就取消了
安装 JDK 以后要配置环境变量
1) 配置PATH,目的是将 Java 开发工具命令,扩展为系统命令
PATH=/opt/jdk/bin:$PATH
export PATH
2) JAVA_HOME
是Java的环境变量,作用是指示java应用软件找到 Java的安装目录 (/opt/jdk)
JAVA_HOME=/opt/jdk
exoprt JAVA_HOME
3) CLASSPATH
是Java的环境变量,作用是指示Java在 运行期间Java class文件的搜索位置
CLASSPATH=.
exoprt CLASSPATH
(2)windows环境下
1)path
path环境变量是定义操作系统查找和运行的可执行文件的路径。在java中,假设我
的java安装在C:\Program Files\Java\jdk1.5.0_02下。那么,path环境变量的值应设
为:C:\Program Files\Java\jdk1.5.0_02\bin,即把bin目录下的java.exe,javac.exe等可
执行文件设进path环境变量中.
2)classpath
classpath环境变量是定义java虚拟机查找和运行的源文件的路径。在java中就要
把C:\Program Files\Java\jdk1.5.0_02\lib下的java源文件(.class文件)的路径设进
classpath中,即把lib目录下的.jar文件(将.class文件打包后的文件)的路径设进去,
例如:把classpath的值设为C:\Program
Files\Java\jdk1.5.0_02\lib\dt.jar,classpath可
设多个,用 "; "分隔就行了.
3)java_home
指的就是java的安装目录即C:\Program Files\Java\jdk1.5.0_02;如果把java_home
设为C:\Program Files\Java\jdk1.5.0_02,那么在path和classpath路径中可用
%java_home%替换C:\Program Files\Java\jdk1.5.0_02。
5、变量
1)逻辑上类似于人类语言中的代词
2)本质上是内存中的数据
Person she;
Person he;
she.love(he);
变量的语法 规定
1) 变量必须有明确的类型
2) 变量必须声明,且初始化以后才能使用
3) 变量有作用域, 超过作用域就释放
变量的作用域:声明位置开始,到块结束
语句块:{}
4)变量不能重复定义!
如果违反了语法规定 将发生编译错误!
编译错误:在代码编译期间发生的错误。如果有编错误,就不能生成.class 更不可能运行!
编译错误的处理:
1)查看编译错误消息!
2)根据提示修改代码,解决问题
6、进制
进制基础, 目的:理解计算机只能处理2进制的数据和指令
(1)10进制计数规律
数字: 0 1 2 3 4 5 6 7 8 9
基数:10
权: 1000 100 10 1
权是基数的n次幂
(2)2进制计数规律
数字: 0 1
基数:2
权: 128 64 32 16 8 4 2 1
权是基数的n次幂
(10) (2)
0 0
1 1
2 10
3 11
4 100
5 101
6 110
7 111
8 1000
9 1001
10 1010
11 1011
12 1100
13 1101
14 1110
15 1111
展开式:
11001010(2) = 128+64+8+2 = 202(10)
234(10) = ?(2)
128 64 32 16 8 4 2 1
234(10) = 1 1 1 0 1 0 1 0 (2)
106 42 10 2 0
二进制补码! 成本考虑, 为省钱!
以4位补码为例
1) 将高位为1的大数, 作为负数使用! 最高位称为符号位.
2) 计算时候如果超过4位数, 多出数位自动溢出舍弃.
3) 在不超过范围情况下, 补码运算满足数学规则
4) 缺点 数字有范围, 不能进行超范围计算
补码的取反对称现象: -n = ~n + 1
符号位扩展现象: 低位数补码扩展为高位数补码: 正数补0 负数补1
(10) 4位补 8位补 32位补码
min -------- 10000000 00000000 00000000 00000000
8 0 0 0 0 0 0 0
...
-129 -------- 11111111 11111111 11111111 01111111
-128 ---- 10000000 11111111 11111111 11111111 10000000
-127 ---- 10000001
-126 ---- 10000010
....
-10 ---- 11110110
-9 ---- 11110111
-8 1000 11111000
-7 1001 11111001
-6 1010 11111010
-5 1011 11111011
-4 1100 11111100
-3 1101 11111101 11111111 11111111 11111111 11111101
-2 1110 11111110 11111111 11111111 11111111 11111110
-1 1111 11111111 11111111 11111111 11111111 11111111
0 0000 00000000 00000000 00000000 00000000 00000000
1 0001 00000001 00000000 00000000 00000000 00000001
2 0010 00000010 00000000 00000000 00000000 00000010
3 0011 00000011 00000000 00000000 00000000 00000011
4 0100 00000100
5 0101 00000101
6 0110 00000110
7 0111 00000111
8 ---- 00001000
9 ---- 00001001
10 ---- 00001010
...
126 ---- 01111110
127 ---- 01111111 00000000 00000000 00000000 01111111
128 ---- -------- 00000000 00000000 00000000 10000000
129 ---- -------- 00000000 00000000 00000000 10000001
....
max ---- -------- 01111111 11111111 11111111 11111111
7 f f f f f f f
代码实现 输出-128到127的二进制:
for(int i=-128;i<=127;i++){
String bin=Integer.toBinaryString(i);
int n=32-bin.length();
for(int j=0;j<n;j++){
System.out.print("0");
}
System.out.println(bin);
}
-3 1101
-3 1101
+ 11 1
-------------
-6 1010
-5 的补码: -5 = ~5 + 1
0101
1010
1011
16 进制计数规律
数字: 0 1 2 3 4 5 6 7 8 9 a b c d e f
基数:16
权: 256 16 1
权是基数的n次幂
16进制用于简化2进制的书写!
每4位2进制数据 可以简写为1位16进制数
16进制就是2进制!
10 16 2
0 00 0000 0000
1 01 0000 0001
2 02 0000 0010
3 03 0000 0011
4 04 0000 0100
5 05 0000 0101
6 06 0000 0110
7 07 0000 0111
8 08 0000 1000
9 09 0000 1001
10 0a 0000 1010
11 0b 0000 1011
12 0c 0000 1100
13 0d 0000 1101
14 0e 0000 1110
15 0f 0000 1111
16 10 0001 0000
17 11 0001 0001
18 12 0001 0010
...
65 41 0100 0001
66 42 0100 0010
...
192 c0 1100 0000
193 c1 1100 0001
...
255 ff 1111 1111
System.out.println(010+2);//10
进制的总结:
1) 计算机只能处理 2 进制数据(经常是补码)!
2) 计算机内部没有 10 进制 和 16进制
3) 10进制是人类 处理数据的习惯,Java 利用API 提供算法(方法)实现 10进制的处理!
4) 16 进制 是便捷的 2进制书写格式!
5) 一切交给计算机的处理的数据,都要转换为2进制!
原码 反码 补码
1)原码是指将最高位作为符号位(0表示正,1表示负),其它数字位代表数值本身的绝对值的数字表示方式。
例如:数字6在计算机中原码表示为:0000
0110
用带符号位的原码进行乘除运算时结果正确,而在加减运算的时候就出现了问题,如下:
( 1 ) 10- ( 1 )10 = ( 1 )10 + ( -1 )10
= ( 0 )10
(00000001)原 + (10000001)原 = (10000010)原 = ( -2 ) 显然不正确.
2)反码表示规则为:如果是正数,则表示方法和原码一样;如果是负数,则保留符号位1,
然后将这个数字的原码按照每位取反,则得到这个数字的反码表示形式。
例如,数字6在8位计算机中的反码就是它的原码:0000 0110
数字(-6)在8位计算机中的反码为:1111 1001
因为在两个整数的加法运算中是没有问题的,于是就发现问题出现在带符号位的负数上,
对除符号位外的其余各位逐位取反就产生了反码.反码的取值空间和原码相同且一一对应. 下面是反码的减法运算:
( 1 )10 - ( 1 ) 10= ( 1 ) 10+ ( -1 ) 10=
( 0 )10
(00000001) 反+
(11111110)反 = (11111111)反 = ( -0 ) 有问题.
( 1 )10 - ( 2)10 = ( 1 )10 + ( -2 )10
= ( -1 )10
(00000001) 反+ (11111101)反 = (11111110)反 = ( -1 ) 正确
问题出现在(+0)和(-0)上,在人们的计算概念中零是没有正负之分的.于是就引入了补码概念. 负数的补码就是对反码加一,而正数不变,正数的原码反码补码是一样的.在补码中用(-128)代替了(-0),所以补码的表示范围为:(-128~0~127)共256个。
3)所以补码的设计目的是:
⑴使符号位能与有效值部分一起参加运算,从而简化运算规则.
⑵使减法运算转换为加法运算,进一步简化计算机中运算器的线路设计
7、八种基本类型
数据类型分为两大类:基本类型,引用类型
基本类型有8种,除了基本类型(8种)以外任何类型都是引用类型。
如: String 是引用类型
基本类型有8种(首字母是小写):
整数:byte, short, int, long
浮点数(小数):float,double
布尔类型:boolean
字符类型: char
(1)整数,都是有符号数(补码):
byte 8位补码 -128 ~ 127
short 16位补码 -32768 ~ 32767
int 32位补码 约-21亿 ~ 21亿 -2^31 ~ 2^31-1 -2G ~ 2G-1
long 64位补码 -2^63 ~ 2^63-1
注意点:
1)任何整数“字面量”都是 int 类型! 字面量就是直接写出的常数,如:5
2)“整数字面量”在不超过范围情况下可以给“小类型变量”赋值
3)以0x为前缀的是16进制,0前缀的是8进制
4)整数超范围运算会溢出
最常用int,但是要注意范围
short很少使用
byte用于表示文件等底层数据
int a=0x7fffffff; a*2=-2
long 类型
1) 使用L后缀的字面量(直接量) 是long类型
2) 计算机时间规定: long类型 从GMT 1970年元旦开始 累计的
毫秒数作为时间, 这个规定:将时间转换为整数long
3) 使用 System.currentTimeMillis() 获得系统时间
4) 时间是一个long整数!
(2)浮点数
详细的float double 的计算规则参考 IEEE 754 标准
1) 由于float 精度比较差,很少使用,大多使用double
精度:尾数长度决定 大小范围:指数(小数点位置)决定
float 的精度 没有 int 高,但是float的大小范围比int大!
double的精度比float高,double的范围也比float大
int a = 0x7fffffff;
int b = 0x7ffffff0;
System.out.println(a-b);//15
System.out.println(a+b);//超过int范围发生溢出了
float fa = a;//损失精度,舍入误差
float fb = b;
System.out.println(fa-fb);//0.0 说明float精度不高,有误差
System.out.println(fa-fb);//正确 float 范围比int大
double da = a;
double db = b;
System.out.println(da-db);//15.0 double精度比int高
System.out.println(da-db);//正确 double比int范围大,比float范围大
2) 浮点数字面量默认是double 类型
D为后缀是double f 后缀是float
3) 浮点数运算的不精确性, 避免使用浮点数进行精确计算。
2.6-2.0不精确 因为底层是将2.6 2.0转换成二进制运算的,2.6不能精确转换成
(无限循环),2.0可以精确转换成二进制。所以结果不精确。小数只有.0和.5才能
精确转换成二进制。
Java 中精确小数计算的解决方案 ,BigDecimal API类实现了精确的定点小数计算
BigDecimal x = new BigDecimal("2.6");
BigDecimal y = new BigDecimal("2");
BigDecimal z = x.subtract(y);//subtract 减法
z = x.add(y);//加
z = x.multiply(y).multiply(y);//乘法
z = x.divide(y); //除
4) float和double
float:1bit(符号位) 8bits(指数位) 23bits(尾数位)
double:1bit(符号位) 11bits(指数位) 52bits(尾数位)
范围:float的指数范围为-127~+128,而double的指数范围为-1023~+1024
float的范围为-2^128 ~ +2^128,也即-3.40E+38 ~ +3.40E+38;
double的范围为-2^1024 ~ +2^1024,也即-1.79E+308 ~ +1.79E+308。
精度:float和double的精度是由尾数的位数来决定的。
float的精度为6~7位有效数字;double的精度为15~16位。
float精度由尾数位决定,二进制23位转成十进制约为 7到8位
(3)boolean 类型
1) 只有两个值:true 真, false 假
2) 用来表示判断结果状态的
(4)字符类型
1)字符是一个16位无符号"整数"! 字符的数值是unicode编码值
char是16位无符号整数,最高位不是符号位,也是数值。范围是0~2的16次方-1
即整数范围:0 ~ 65535
2) unicode编码 8万多字
规定:‘中‘ 编码数字 20013
‘田‘ 编码数字 30000
‘A‘ 编码数值 65
unicode英文编码与ASCII编码一致
3) Java char 类型支持了 i18n(国际化), 就是支持全球文字
4) 在中文本地系统中,字库(字模)只能显示20000+文字!
5) 字符字面量 就是一个char整数字面量 ‘中‘
6) 字符可以参与数学运算
‘A‘ 的编码 65
‘B‘ 66
...
‘Z‘ 90
‘0‘ 48
‘1‘ 49
...
7) 特殊字符,可以使用转义字符书写
‘\n‘ new line 换行
‘\r‘ return 回车
‘\t‘ tab 字符
‘\\‘ \ 字符
‘\‘‘ 单引号
‘\"‘ 双引号
‘\u4e2d‘ unicode 16进制编码
8) 控制字符也是字符,如:回车,换行,退格等,
但是控制字符输出显示效果不明显
8、类型转换
(1)自动类型转换 也称为 隐式类型转换
从小类型向大类型转换 , 发生符号位扩展现象。
负数扩展为1 ,正数扩展为0
int i = -1;//i 是32位数
long l = i;//l 是64位数, 发生符号位扩展现象
System.out.println(l);//-1
System.out.println(Integer.toBinaryString(i));
System.out.println(Long.toBinaryString(l));
//Long.toBinaryString方法的参数是long类型
//在i向long 类型参数传递时候发生了自动类型转换!
System.out.println(Long.toBinaryString(i));
(2)强制类型转换
强制类型转换: 大类型到小类型的转换
在范围之内的情形,强制转换没有问题。
超过小类型范围,发生高位溢出现象。
强制类型转换也会发生精度损失。
l = (long)(pi+0.5);//利用强制类型转换实现 4舍5入
System.out.println(l); //4舍5入
(3)注意点
1) java 中 字面量(直接量)之间的运算,在编译期间,优化为运算结果了。
2) Java 中int类型的“字面量”,在不超过小类型范围情况下可以给小类型变量赋值
3)由于Java编译器,不能确定变量表达式的结果,
不允许直接将大类型变量给小类型赋值 。
int n = 2;
char c;
c = ‘A‘+2;// int 67 没有编译错误
//c = ‘A‘+n;//编译错误,不能转换int到char
c = (char)(‘A‘+n);
9、运算符及表达式
算数运算
加(+) 减(-) 乘(*) 除(/) 取余(%)
自增(++)
自减(- -)
注意点
(1)同种类型参与运算(可能需要自动类型转换),返回同种类型
(2)整数的除法是整数
(3)0对其他数的余数是0
(4)%获取除法结果中的余数
负数取余的结果: 负数和0,工作很少使用,考试可能有!
正数方向,n的余数是周期函数,并且小于n。在工作中, 周期性的运算经常采用 % 实现。
(5)i++后++
i++,后++,先将i的值作为整个表达式的值,然后将i增加1
++i前++
++i,先++,先将i增加1,然后将i的值作为整个表达式的值
注意: int a=1;
a+=a+++a;-->a=a+(a++)+a;-->a=1+1+2=4
关系运算
java关系运算用于判断数据之间的大小关系
“>” “<” “>=” “<=” “==” “!=”
关系表达式的值为boolean类型(“true” 或者”false”)
逻辑运算
逻辑运算的操作数均为boolean表达式
&&(与) ||(或) !(非)
b1 b2 b1&&b2 b1||b2 !b1
false false false false true
false true false true true
true false false true false
true true true true false
短路逻辑运算 与 非短路逻辑运算
&& || 具备“短路“的特性;
如果通过第一个表达式的值即可得出最后的结果,则不计算第二个表达式。
&& 是短路逻辑运算当第一个表达式是false时候,就直接得结果
& 非短路逻辑运算
建议:工作中大多使用 && 实现短路逻辑
条件运算符
条件运算符又称”三目运算符“,其结构为:
boolean表达式?表达式1:表达式2
先计算boolean表达式的值,如果为true,则整个表达式的值为表达式1的值;
如果为false,则整个表达式的值为表达式2的值。
数据分页:
int rows = 55;//总共55条数据
int size = 10;//每页10条数据
int pages;
pages = rows%size == 0 ? rows/size : rows/size+1;//总共的页数
闰年的判断公式为:
1)年份能被4整除,且不能被100整除的是闰年。
2)年份能被400整除的是闰年。
isLeapYear = ( year%4==0 && !(year%100==0)) || (year%400 == 0);
求三个数中的最大值:
int max = a>b ? a : b;
max = max > c ? max : c;
赋值运算符
”=“称为赋值运算符,用于对变量赋值。
赋值表达式本身也有值,其本身之值即为所赋之值
扩展的赋值表达式(+= -= *= /=)
注意:int a=1;
a+=1.0/5; 不会报错
a=a+1.0/5; 会报错
字符串连接运算 +
Java 中唯一"重载"的运算符是“+”:同名,但实际是两种功能
类似于: 打车 打酱油 打扑克
+ 两端数值,就进行 加法运算
+ 两端是字符串,就进行 字符串连接
System.out.println(1 + ‘0‘);//49 int
System.out.println(1 + "0");//"10"
System.out.println(1 + ‘0‘ + "0"); //"490"
System.out.println(1 + ‘0‘ + "0"+‘0‘); //"4900"
位运算符
(1)按位与运算符(&)
参加运算的两个数据,按二进制位进行“与”运算。
运算规则:0&0=0; 0&1=0; 1&0=0; 1&1=1;
即:两位同时为“1”,结果才为“1”,否则为0
例如:3&5 即 0000 0011 & 0000 0101 = 0000 0001 因此,3&5的值得1。
“与运算”的特殊用途:清零。如果想将一个单元清零,
即使其全部二进制位为0,只要与一个各位都为零的数值相与,结果为零。
(2)按位或运算符(|)
参加运算的两个对象,按二进制位进行“或”运算。
运算规则:0|0=0; 0|1=1; 1|0=1; 1|1=1;
即 :参加运算的两个对象只要有一个为1,其值为1。
例如:3|5 即 0000 0011 | 0000 0101 = 0000 0111 因此,3|5的值得7。
(3)异或运算符(^)
参加运算的两个数据,按二进制位进行“异或”运算。
运算规则:0^0=0; 0^1=1; 1^0=1; 1^1=0;
即:参加运算的两个对象,如果两个相应位为“异”(值不同),
则该位结果为1,否则为0。
(4)取反运算符(~)
参加运算的一个数据,按二进制位进行“取反”运算。
运算规则:~1=0; ~0=1;
即:对一个二进制数按位取反,即将0变1,1变0。
(5)左移运算符(<<)
将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。
例:a = a << 2 将a的二进制位左移2位,右补0,(正数负数左移都补0)
左移1位后a = a * 2;
若左移时舍弃的高位不包含1,则每左移一位,相当于该数乘以2。
(6)右移运算符(>>)
将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。
正数时:操作数每右移一位,相当于该数除以2。
负数时:操作数每右移一位,相当于该数除以2,再减一
例如:a = a >> 2 将a的二进制位右移2位,
左补0 or 补1 得看被移数是正还是负。
(7)无符号右移运算符(>>>)
>>> 运算符把 expression1 的各个位向右移 expression2 指定的位数。
右移后左边空出的位用0来填充。移出右边的位被丢弃。
例如:var temp = -14 >>> 2
变量 temp 的值为 -14 (即二进制的 11111111 11111111 11111111 11110010),
向右移两位后等于(即二进制的 00111111 11111111 11111111 11111100)。
案列:
(1)最快速的实现 n * 8(2 的 n次幂)
int n=5;
int a=n<<3;
System.out.println(a);
最快速的实现 n / 8(2 的 n次幂)
(2)ip: 192.168.10.23
d1 = 192 d2 = 168 d3 = 10 d4 = 23
将 d1 d2 d3 d4 拼接为 1个 32位数 IP地址
int d1 = 192;//00000000 00000000 00000000 11000000
int d2 = 168;//00000000 00000000 00000000 10101000
int d3 = 10; //00000000 00000000 00000000 00001010
int d4 = 23; //00000000 00000000 00000000 00010111
int ip;// 11000000 10101000 00001010 00010111
//ip = (d1<<24)+(d2<<16)+(d3<<8)+(d4<<0);
ip = (d1<<24)|(d2<<16)|(d3<<8)|(d4<<0);
System.out.println(Integer.toBinaryString(ip));
(3)将一个int数据拆分为 4个byte数据
int a=-4;// 0xff ff ff fc
int d1=a>>24&0xff;
int d2=a>>16&0xff;
int d3=a>>8&0xff;
int d4=a&0xff;
运算符的优先级
算术运算符>关系运算符>逻辑运算符>赋值运算符
优先级 |
运算符 |
结合性 |
1 |
() [] . |
从左到右 |
2 |
! +(正) -(负) ~ ++ -- |
从右向左 |
3 |
* / % |
从左向右 |
4 |
+(加) -(减) |
从左向右 |
5 |
<< >> >>> |
从左向右 |
6 |
< <= > >= instanceof |
从左向右 |
7 |
== != |
从左向右 |
8 |
&(按位与) |
从左向右 |
9 |
^ |
从左向右 |
10 |
| |
从左向右 |
11 |
&& |
从左向右 |
12 |
|| |
从左向右 |
13 |
?: |
从右向左 |
14 |
= += -= *= /= %= &= |= ^= ~= <<= >>=>>>= |
从右向左 |
注意运算符的优先级: 1>>2+6>>2==>1>>(2+6)>>2==0
10、流程控制结构
if结构
if(关系表达式){
//语句块
}
当关系表达式为true时,执行语句
if-else结构
if(关系表达式){
//语句块1
}else{
//语句块2
}
当关系表达式为true时,执行语句块1,否则执行语句块2
if-else嵌套
if(表达式1){
//语句块1
}else if(表达式2){
//语句块2
}else if(表达式3){
//语句块3
}else….
switch结构
switch(整数表达式){
case 条件1:...;break;
case 条件2:...;break;
default:...;break;
}
使用switch时有如下注意点:
(1)switch(表达式)
只能是整数表达式(int byte char short),switch不能处理long或其他类型。
(2)case条件只能是整数常量(int byte char short),不能是变量或者表达式。
(3)case条件的内容可以为空,如果为空,则继续执行之下代码。
(4)default表示如果没有满足case的条件的其它一切情况。
(5)别忘记写break,会出现”渗透”\
(一直执行接下来的代码,直到遇到break或者本代码块执行错误)
for 循环
处理周期性,重复处理的功能。for 大多用于处理 与 次数有关的循环
for(表达式1;表达式2;表达式3){
语句块;
}
while结构
while(boolean表达式){
语句块;
}
当boolean表达式为true时,执行语句块;否则退出循环。
while与for结构可以互换。
while(true)等价于for(;;){}
do-while结构
do{
语句块;
}while(boolean表达式);
当boolean表达式为true时,执行语句块。否则退出循环。
do-while与while结构的区别在于:如果循环条件一开始就不满足时,while结构不会执行循环体;而d-while结构会执行一次循环体。
注意点
分支流程 if else
使用建议:
1)尽量使用肯定条件,减少使用否定条件,目的是避免思考误区,减少逻辑错误。
2)减少嵌套层次,一般不要超过。目的是避免思考误区,减少逻辑错误。
3)注意缩进和括号配对!成对写括号,对齐格式以后,在括号中间添代码,如果要删除(注释掉)一定成对的括号删除。
4)适当的减少使用else(否则的情形)
总之:要保持代码的简洁,和很好的可读性。理想的代码要接近自然语言。
多路分支
if else if else
switch case
1)if else if else 判断条件灵活适应广泛。
2)switch case 条件必须是整数(byte short char int)。使用限制多,但性能好于if else
3)在工作中 if else使用的更多些。
循环流程
for while do--while
for:“经典的用法”是与次数有关的循环
如下循环:循环时候:i=0 1 2 ... n-1 共计 n 次循环
for(int i=0; i<n; i++){
}
其中 i 是 index(序号)的缩写
while: “经常”处理与次数无关的循环
for 和 while 可以相互替换
1) while 可以处理 次数 循环,但是没有 for方便
2) for(; 循环条件 ;) 与 while(循环条件) 等价
3) for(;;) 与 while(true) 等价,都是死循环
4) 只使用for循环可以处理任何循环逻辑
5) 在不能明确循环结束条件时候,可以先使用死循环。在适当的时候 使用 break 结束循环。
6) do while 循环 适合循环结束条件在循环体最后的循环流程
continue
continue语句在循环体中,用于结束本次循环而开始下次循环。
break
break用于退出当前语句块。break用在循环体中用于退出循环。
案列:
(1)字符串对齐
public static void print(String str){
int count = 8 - str.length();
for(int i=0; i<count; i++){
System.out.print(" ");
}
System.out.println(str);
}
(2)输出 1000 以内的所有质数 (素数)
素数:一个数(>=2)只能被自身和1整除的数
如何判断一个数是否是质数!
如果一个数除了1 和自身以外,有“约数”就不是质数了!
如 6 = 3 * 2, 6 就不是 质数
如何查找:24 的约数,如果有约数范围一定是:2 ~ <=24/2
for(int n=2;n<=1000;n++){
boolean isPrime=true;
for(int i=2;i<=n/2;i++){
if(n%i==0){
isPrime=false;
break;
}
}
if(isPrime){
System.out.println(n+"是质数");
}
}
(3)输出一个数的全部约数,1 和自身除外
public static void get(int n){
for(int i=2;i<n/2;i++){
if(n%i==0){
System.out.println(i);
}
}
}
(4)反转一个整数 num = 37195 结果:59173
int num=37195;
int sum=0;
while(num!=0){
int last=num%10;
sum=sum*10+last;
num=num/10;
}
System.out.println(sum);
(5)求PI = 4 * (1/1-1/3 + 1/5-1/7 + 1/9-1/11 ... ) 值
double sum = 0;
for(long i=1; i<500000000L; i+=4){
sum += 1.0/i - 1.0/(i+2);
}
double pi = sum*4;
System.out.println(pi);
(6)找到 100 ~ 999 之间的全部水仙花数(3位自幂数)
如153=1*1*1+5*5*5+3*3*3; 153是首先花数
for(int n=100; n<=999; n++){
int num = n;
int sum = 0;
do{
int last = num%10;
sum += last*last*last;//3次方和
num /= 10;
}while(num!=0);
if(sum == n){
System.out.println(n+"是水仙花数");
}
}
(7)猜数字游戏
数据分析的前提是业务规则
数据分析:
num 是被猜测数字
answer 是用户猜的答案
count 猜测的次数
计算方法(计算过程):
1) 随机生成 num 范围 1~100
(如果要生成100-200之间的数可以这样写:nextInt(100)+100)
2) 提示用户猜测数据
3) 得到猜测答案 answer
4) 比较用户answer 和 num
4.1 计分 count++
4.2 如果相等就结束 游戏
4.3 提示大/小
5) 返回 (2)
public static void main(String[] args) {
int num;
int answer;
int count = 0;
Scanner in = new Scanner(System.in);
Random random = new Random();
num = random.nextInt(100)+1;
System.out.println("亲,欢迎使用猜数字游戏!(*_^)");
for(;;){
System.out.print("猜吧:");
answer = in.nextInt();
count++;
if(num==answer){
System.out.println("(@[email protected])对了!分"+count); break;
}
if(answer > num){
System.out.println("猜大了!次数:"+count);
}else{
System.out.println("猜小了!次数:"+count);
}
}
}
11、数组
1)什么是数组?
数组是相同数据类型的元素组成的集合。
这些元素按线性顺序排列。
所谓线性顺序是指除第一个元素外,每一个元素都有唯一的前驱元素;除最后 一个元素外,每一个元素都有唯一的后继元素。(“一个跟着一个”)。
2)数组变量数组对象 数组元素
数组变量:是引用数组的变量,是引用变量。
数组(数组对象):数组整体对象
数组元素:数组中每个元素
羊村的全体羊,他们打败了灰太狼。
他们 和 羊村的全体羊 之间是引用的关系,他们是变量
他们:相当于 数组变量
羊村的全体羊: 相当于 数组(数组对象)
喜洋洋:数组元素
3)数组的声明: int[] arr;
int arr[]; 不常用,很少使用
int[] 是数组类型,是引用类型。int[]表示数组中的每一个元素都是int类型。
arr是变量(引用变量),类型是数组类型int[]。
int[] arr=new int[10];
new int[10]是创建数组对象,将对象的引用赋值给ary变量。
ary变量就引用了数组对象,这个对象有10个元素。
10表示数组的长度,即数组中元素的个数。
java数组元素是自动初始化的,初始化为零值。有: 0 0.0 \u0000 null false
int[] arr=new int[10],创建数组对象,有10个元素,每个元素的初始值是0;
double[] arr=new double[3],数组对象有3个元素,每个元素的初始值是0.0;
char[] arr=new char[3],每个元素的初始值是\u0000;
\u0000--\ufffff,\u开头的是一个Unicode码的字符,
\u0000字符是数值0对应的字符
boolean[] arr=new boolean[3],,每个元素的初始值是false;
4)数组对象的创建和初始化
(1)动态初始化
new 类型[长度]; new int[4]
类型是任何类型:基本类型、类类型(String,Integer)
长度:变量或常量 值:0 ~ Integer.MAX_VALUE
(2)动态初始化
new 类型[]{元素0,元素1,元素2}
直接给出元素,元素直接初始化,元素的长度就是长度。
(3)静态初始化
类型[] 变量={元素0,元素1,元素2}。
这种方式可以看做是 new int[]{4,5,6} 的简化版。
只能用于声明时的初始化,不能用于赋值。
(4)注意
new int[length] 适合创建不知道具体的元素,数量很多
new int[]{2,3,4} 适合已经知道具体元素了,元素比较少
{4,5,6} 只是适合知道元素,并只能使用在声明变量直接初始化。
5)数组的访问
数组一旦创建后,数组的长度是不可以改变的。
调用数组的length属性可以获取数组的长度;int len=arr.length
可以通过下标的方式访问数组中的每一个元素。
注意:数组的下标从0开始,对于长度为n的数组,下标的范围是0~n-1。
数组不能越界访问,会出现运行异常。
迭代数组元素,迭代数组,也称为遍历数组,就是逐一处理元素
for(int i=0; i<ary.length; i++){
// i = 0 1 ... ary.length-1
System.out.println(ary[i]);、
}
案列
学生成绩管理
数据模型设计
names = { "Tom", "Jerry", "Andy", "John" }
score = { 85 , 67, 66, 98 }
0 1 2 3
算法设计,业务功能实现
1 成绩输入
迭代显示每个人名,从控制台读取数据填充到对应的分数数组
2 成绩列表, 并计算平均成绩
迭代每个人名,并且显示对应的成绩,统计总分。最后计算显示平均分。
3 查询某人的成绩
等待输入查询人名,根据人名迭代找人名,如果找到就显示人名和对应的成绩。
public static void main(String[] args) {
String[] names = {"Tom","Jerry","Andy","John"};
int[] score = new int[names.length];
//处理控制台命令
Scanner in = new Scanner(System.in);
System.out.println("\t欢迎使用成绩管理");
while(true){
System.out.print(
"1.成绩录入 2.成绩单 3.查询 0.离开, 选择:");
String cmd = in.nextLine();//从控制台读取一行字符串
//比较字符串必须使用equals()方法!
//最后是字符串字面量与对象比较
if("0".equals(cmd)){
System.out.println("亲,再见了(T_T)!"); break;
}else if("1".equals(cmd)){//cmd command 命令
//输入
System.out.println("开始输入成绩");
for(int i=0; i<names.length; i++){
String name = names[i];//name 代表每个人名
System.out.print((i+1)+" 输入 "+name+" 的成绩:");
String str = in.nextLine();//"95"
//parseInt 将10进制的字符串转换为整数
score[i]=Integer.parseInt(str);//"95" -> 95(int)
}
}else if("2".equals(cmd)){
//成绩单
int sum = 0;
for(int i=0; i<names.length; i++){
String name = names[i];
System.out.println(
(i+1) + "." + name +"的成绩:"+score[i]);
sum += score[i];
}
System.out.println("平均成绩:"+(sum/names.length));
}else if("3".equals(cmd)){
// 3.查询
System.out.print("输入查询人名:");
String name = in.nextLine();
for(int i=0; i<names.length; i++){
if(name.equals(names[i])){
System.out.println(
(i+1) + "." + name +"的成绩:"+score[i]);
break;
}
}
}else{
System.out.println("命令错啦!");
}
}
}
12、方法
Math.sqrt() 取平方
Math.pow(2,3) 2的3次方
方法(Method),就是数学函数(Function)
业务方面: 是功能,是动作,一般采用动词命名
数据层面:是利用算法操作数据模型,实现业务功能
方法就是数据算法。
1)方法的声明
方法用于封装特定的逻辑功能。方法的主要要素有:方法名、参数列表和返回值。
语法结构: 修饰符 返回值类型 方法名(参数列表){ 方法体}
方法在类中定义,不能在方法中定义。
2)方法要素--返回值
方法调用结束后可以返回一个数据,称之为返回值。
方法在声明时必须指定返回值类型。
如果方法没有返回值(即方法不需要返回数据),需将返回值类型声明为void
通过return语句返回,return语句的作用在于结束方法并且将数据返回。
return a+b; return语句返回该表达式的值
return; 对于返回值为void的方法也可以使用return语句,
此时该语句的作用在于结束方法调用。
如果方法声明的返回值,必须在方法体使用return 语句返回数据!
3)方法要素--参数列表
方法的参数是指:在调用时传递给方法,需要被方法处理的数据。
在定义方法时,需要声明该方法所需要 参数变量。
在方法调用时,会将实际的参数值传递给方法的参数变量。
必须保证传递参数的类型和个数符合方法的声明。
4)方法的调用过程
public static int max(int a, int b){....}
int a=5; int b=6;
int max=max(5 , 6);
(1)为main方法中的便利a b max 分配空间并赋值
(2)调用方法max,为max方法的参数变量a, b分配空间
(3)将调用值传入参数变量中
(4)max方法运行完返回,参数变量空间释放。
(5)main方法中的max变量得到返回值。
案列:求斐波那契(Fibonacci) 数列(第n项 等于前两项的和)
public static long f(long n){
long f1 = 1; long f2 = 1; long fn = 2;
for(int i=3; i<=n; i++){
fn = f1 + f2; f1 = f2; f2 = fn;
}
return fn;}
13、Arrays中常用的方法
JDK中的java.utils.Arrays类提供对数组操作的一系列使用方法。
使用API方法:API方法封装了常用算法功能,使用这些功能简化开发过程, 提高开发效率。
如:使用toString可以便捷输出数组内容
使用equals可以便捷比较 数组内容
API 封装的算法也是 for if 实现的!也可以不用。
数组类型是引用类型,但是没有覆盖object中的toString ,equals方法。所以要输出比较用Arrays工具类的toString方法,equals方法
(1)Arrays.toString方法
用于字符串表示数组的元素。将数组的内容连接成一个字符串。
String[] str={"Tom", "Andy", "Jerry", "John"};
Arrays.toString(str);--->"[Tom, Andy, Jerry, John]"
(2)Arrays.equals方法
用于比较两个数组的各个元素是否相等。
char[] answer = {‘A‘, ‘C‘, ‘D‘};
char[] input = {‘A‘, ‘C‘, ‘D‘};
boolean match = Arrays.equals(answer, input);//true
(3)Arrays.sort方法
用于实现数组的排序。
int[] score = {67, 49, 88, 69, 95};
Arrays.sort(score);//小 -> 大 [49 67 69 88 95]
String[] names = {"Tom", "Jerry", "Andy", "John"};
Arrays.sort(names);//按字典顺序排序 [Andy Jerry John Tom]
(4)Arrays.fill();
填充数组
String[] names=new String[3];
Arrays.fill(names,”liuyueqin”);
Arrays.toString(names)//[liuyueqin, liuyueqin, liuyueqin]
(5)Arrays.binarySearch方法
用于实现有序数组的二分法查找。二分查找,在未排序的数组上二分查找结果
是不稳定的。在查找之前必须先排序。
String[] names={"Tom","Andy","Jerry","John","Wang",”Andy”};
Arrays.sort(names);// 先排序
int index = Arrays.binarySearch(names,"Jerry");返回下标值
index = Arrays.binarySearch(names,"Lee");// 找不到时,返回负数
index = Arrays.binarySearch(names,"Andy");
//有多个相等元素时不确定返回的是哪一个。
(6)数组的复制和赋值
数组的赋值
int[] ary1 = {4,5,6};
int[] ary2 = ary1;
ary2[1]++;
ary1和ary2都指向同一个数组对象,ary1和ary2相互影响。
数组的复制
就是将一个数组(源数组)中的各个元素值复制到另外一个数组(目标数组)中。
1)使用for循环实现
int[] ary3 = new int[ary1.length];
for(int i=0; i<ary1.length; i++){
ary3[i] = ary1[i];
}
ary3[1]++;
2)使用API System.arraycopy().
System.arraycopy 是用C代码实现。
System.arraycopy(src, srcPos, dest, destPos, length)
src-----要复制的源数组
srcPos--从源数组复制的起始位置
dest----复制到的目标数组
destPos-复制到目标数组的起始位置
length--要复制的元素的个数
int[] ary4 = new int[ary1.length];
System.arraycopy(ary1, 0, ary4, 0, ary1.length);
3)使用Array.copyOf()
Arrays.copyOf() 方法,底层就是arraycopy
int[] ary5 = Arrays.copyOf(ary1, ary1.length);
ary5:复制后的数组
ary1:原数组
ary1.length复制后的长度
(7)数组的扩展
数组的长度在创建后不可改变的。
所谓的扩展是指创建一个更大新数组并将原有数组的内容复制到其中。
利用复制并更换数组对象,实现数组的变长计算。
1)System.arraycopy
String[] names={"Tom","Andy","Jerry","John","Wang"};
String[] names1=new String[names.length+1];
System.arraycopy(names, 0, names1, 0, names.length);
names1[names1.length-1]="liuyueqin";
System.out.println(Arrays.toString(names1));
2)Arrays.copyOf
String[] names={"Tom","Andy","Jerry","John","Wang"};
String[] names1=Arrays.copyOf(names, names.length+1);
names1[names1.length-1]="liuyueqin";
System.out.println(Arrays.toString(names1));
14、数组排序算法
(1)选择排序
选择排序原理:
1)将数组中的每个元素与第一个元素比较,如果这个元素小于第一个元素,
则交换这两个元素。
2)循环第一条规则,找出最小元素,放于第一个位置。
3)经过n-1轮比较完成排序。
简单而言,每轮都找到最小的放到前面。
代码:
for(int i=0;i<ary.length-1;i++){
for(int j=i;j<ary.length;j++){
if(ary[i]>ary[j]){
int temp=ary[i];
ary[i]=ary[j];
ary[j]=temp;
}
}
}
(2)冒泡排序
冒泡排序原理:
1)逐一比较数组中相邻的两个元素, 如果后面的数字小于前面的数字,
就交换先后元素。
2)经过一个轮次的比较, 一定有一个最大的排在最后的位置.
3)每次比较剩下的元素, 经过n-1次比较, 可以实现排序
简单说: 比较相邻元素,大的向后交换。
代码:
for(int i=0;i<ary.length;i++){
for(int j=0;j<ary.length-i-1;j++){
if(ary[j]>ary[j+1]){
int temp=ary[j];
ary[j]=ary[j+1];
ary[j+1]=temp;
}
}
}
(3)插入排序
选择排序原理:
1)将数组分为两部分, 将后部分的第一张逐一与前部分每一张比较。
2)找到合理位置插入.
代码:
int i,k,j;
for(i=1;i<ary.length;i++){
k=ary[i];
for(j=i-1;j>0;j--){
f(k<ary[j]){
ary[j+1]=ary[j];
}else{
break;
}
}
ary[j+1]=k;
}
(4)系统排序
JDK提供的排序方法Arrays.sort(ary)的效率要比上面三种排序方法高。 测试:
int[] ary1=new int[100000];
Random random=new Random();
for(int i=0;i<ary1.length;i++){
ary1[i]=random.nextInt();
}
long tim1=System.currentTimeMillis();
Arrays.sort(ary1);
long time2=System.currentTimeMillis();
System.out.println(time2-time1);
15、方法的递归调用
(1) java 的栈
是Java进程启动时候在内存中开辟的存储空间。
栈内存的利用方式LIFO(后进先出)。
Java所有局部变量都在栈中分配(压入), 方法的参数也是局部变量,
局部变量在离开作用域时候回收 就是从栈中弹出(删除).
(2) Java方法调用使用栈实现, 递归调用就是栈实现的
(3) 递归时候要按照递归深度分配全部临时变量, 栈开销很大, 性能不好,
要注意不要超过栈的大小, 并且一定要给出结束条件, 否则会造成栈溢出错误。
递归的优点与缺点
优点: 业务问题解决的很优雅 只需要解决一个层次,其他层次问题就递归解决了。
缺点:1) 大量消耗栈内存空间,不能进行过深层次的递归。否则可能出现栈溢出错误。
使用递归的要点
1)不能过深的递归
2)不能发散递归
3)必须有结束条件
案列:
(1)递归实现1+2+...+1000=? fn(n)=f(n-1)+n
public static int f(int n){
if(n==1){
return 1;
}
return n + f(n-1);
}
(2)斐波那契
public static long f1(long n){
if(n==1 || n==2){
return 1;
}
return f1(n-1) + f1(n-2);
}
public static long f(long n){
long f1 = 1;
long f2 = 1;
long fn = 1;
for(int i=3; i<=n; i++){
fn = f1+f2;
f1 = f2;
f2 = fn;
}
return fn;
}
以上是关于Java基础的主要内容,如果未能解决你的问题,请参考以下文章