1详细二进制
(主要是用于基本i/o流)
#二进制:
1、计算机内部都是2进制
2、数组和ArrayList的区别:ArrayLlsit里面有算法(通用算法,只有当通用算法不行的时候,可以自己写专门算法),数组没有相应的算法,但就底层而言都是数组数组结构。
#什么是二进制
1、逢2进1的计数规则
数字:0 1
权:256 128 64 32 16 8 4 2 1
基数:2
#为什么使用2进制
>______________________________________________________________________________________________________________________________
进制的在计算机运行计算成本最低, 可以支持任何的数学运算,在进行下面方法的时候:
int i=56;
System.ou.prinln(i);
实际上程序暗自调度了下面的方法:(下面的两个函数十分重要,他们的性能影响java的性能)
--->Integer.parseIne();--->将 56---> 2 进制
--->Integer.toString();--->将2进制--->转换为10进制
我们可以对上面程序进行设置断点,单步调试(F5),依次进入到方法之中:
<
public static String toString(int i) {
if (i == Integer.MIN_VALUE)
return "-2147483648";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
getChars(i, size, buf);
return new String(0, size, buf);
}
static int stringSize(int x) {
for (int i=0; ; i++)
if (x <= sizeTable[i])
return i+1;
}
static void getChars(int i, int index, char[] buf) {
int q, r;
int charPos = index;
char sign = 0;
if (i < 0) {
sign = '-';
i = -i;
}
// Generate two digits per iteration
while (i >= 65536) {
q = i / 100;
// really: r = i - (q * 100);
r = i - ((q << 6) + (q << 5) + (q << 2));
i = q;
buf [--charPos] = DigitOnes[r];
buf [--charPos] = DigitTens[r];
}
// Fall thru to fast mode for smaller numbers
// assert(i <= 65536, i);
for (;;) {
q = (i * 52429) >>> (16+3);
r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
buf [--charPos] = digits [r];
i = q;
if (i == 0) break;
}
if (sign != 0) {
buf [--charPos] = sign;
}
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
>
>__________________________________________________________________________________________________________________________
###2进制与10进制的转换
> 因为10 进制用于计数,2进制也可以用于计数,转换是指,当前相同个数的时候,10 进制的数字和2进制数字是相同的数字
> 计算机类不处理是2进制的。编程语言是将10值的转换为2机制的交给计算机处理,编程语言给使用者留下错觉:计算机能够直接处理10进制巍数据
2进制--->10进制方法:
1101(2)=8+4+1=13(10)
总结:各个位数跟权乘后相加
10进制-->2进制的转换方法
1、短除法
2、或者根据权值来计算
<
程序实现:
public class Demo{
public static void mian (args[] String){
int n =234;
// Integer.toBinaryString(int n)转换为二进制
System.out.println(Integer.toBinaryString(n));
}
// 可以验证你的计算转换是否正确。
}
>
##16进制
1、16进制是2进制的简写形式
2、2进制书写过于冗长不便
3、16进制的一位数可以简写二进制的四位数
16进制计数规则:
数字:0 1 2 3 4 5 6 7 8 9 A B C D E F
权值:256 16 1
基数:16
##补码:因为计算机底层无法放负数,所以将2^32,其中2^31表示负数(最高位1表示负数,但是从计算机角度来说,是一个很大的正数),剩下的2^31表示正数,
>___________________________________________________________________________________________________________________________________
> 是一种算法 已经封成为方法了:
Integer.toString()
Integer.paraInt()
补码:32位的最大值:0x7fffffff
的最小值:0x80000000
补码特点:
补码的最大值:
int max=0f7fffffff
System.out.println(Integer.toBinaryString(max))
补码的最小值:
int min=0x80000000
System.out.printlin(Integer.toBinaryString(min))
程序实现:求-1 的补码:
public class Demo {
public static void main(String[] args) {
// TODO 自动生成的方法存根
int n=-1;
System.out.println(n);
System.out.println(Integer.toBinaryString(n));
}
}
输出:111....(32个1)
>_________________________________________________________________________________________________________________________
经典例题:
<
public class Demo {
public static void main(String[] args) {
// TODO 自动生成的方法存根
int n=Integer.MAX_VALUE;
System.out.println(n);
System.out.println(Integer.toBinaryString(n));
}
}
输出:1111111111111111111111111111111(请看清楚31个1,尽管内存中是01111111111111111111111111111111,但是控制台输出时会不是最前面的0省略!!!)
>
>_________________________________________________________________________________________________________________________________
1、溢出结果不是无规律!
2、正数溢出不一定负数
3、负数溢出也不一定正数
4、n=(max+1)*2+n
5、min=max+1
>____________________
相反数:
补码的对称现象:-n=~n+1(取反+1)---->但是这个规律不适合两头极值(最大值和最小值)
经典面试题
System.outprintln(~8+1);//-8
System.outprintln(+1)
>
按照2进制的每个位进行计算的运算符 ~ & | >>> >> <<
### ~ 取反运算(略)
### >>> 逻辑右移位运算
规则:将数据的每一个位向有移动
n:0000 0000 0000 0000 0000 0000 0011 0010
m=n>>>1
m:0000 0000 0000 0000 0000 0000 0001 1001
m=n>>>2
m:0000 0000 0000 0000 0000 0000 0000 1100
测试代码:
public class Demo {
public static void main(String[] args) {
int x=0x5d8c8;
int n=50;
int m=n >>> 2;
System.out.println(Integer.toBinaryString());
}
}
### << 逻辑左移位运算
规则:将数据的每一个位向有移动
代码测试:
public class Demo {
public static void main(String[] args) {
int n=50;
int m=n << 2;
System.out.println(m);
}
}
###移动运算的数学意义
> 引子:移动小数点运算
347720. 小数点向右移动一次
347720. 数据*10
假设小数点不动,则数字向右移动,数字向左移动一次,原数据向左移动一次。原数据*10
如上规律 --->二进制依然成立
经典例题:
--->如何优化将n*8运算?答案:移位运算(n<<3)
运算规则:
---当正数的情况下,左侧补0;
---当负数的情况下,左侧补1,保存符号不变
例子:
n=11111111 11111111 11110111 11110100
int n=0xfffff7f4;
int m1=n>>>1;(在前面添加0 无论正负)
//m1:01111111 111111111 11110111 1111010
int m2=n>>1;(按正负号在前面添加0或1)
//m2:11111111 11111111 11111011 11111010
########将两个数据对其的位置进行“与&”以及“或||”运算
运算规则:
1&1=1 1||1=1
1&0=0 1||0=1
0&1=0 0||1=1
0&0=0 0||0=0
测试代码:
int n=0x6db7b65
int mask=0xffffffd5;
int x=a&mask
int y=a||mask
######### 掩码
1 用于将数据的一部分截取出来。
2 掩码运算2的整次幂的余数
!(掩码的运算性能是比除法的强----->面试:如何优化是除法 n%8 的性能:答案 :n&0x7)
0000%4=00 0000&0011=00
0011%4=11 0011&0011=11
0010%4=10 ...
0001%4=01 ...
0100%4=00 ...
3 掩码的运算用途:将整数进行拆分
测试代码:
public class Demo {
public static void main(String[] args) {
int n=0x6d64c311;
System.out.println(Integer.toBinaryString(n));
int b1=(n>>>24)&0xff;
int b2=(n>>>16)&0xff;
int b3=(n>>>8)&0xff;
int b4=(n>>>0)&0xff;
//合并操作
int m=(b1<<24)|(b2<<16)|(b3<<8)|b4;//可以将|换为+ ,但是注意一点,+会有进位。
System.out.println(Integer.toBinaryString(m));
}
}
############认识read()方法
文件:
11101011 01110111 11011011 11011101 EOF
0 1 2 3 4
^
int b=readInt();
b1=00000000 00000000 00000000 11101011
11101011 01110111 11011011 11011101 EOF
0 1 2 3 4
^
int b1=readInt();
b2=00000000 00000000 00000000 01110111
................
int b4=readInt();//读到文件末尾,返回-1,
b4=11111111 1111111 11111111 11111111
读取后然后将通过移位和与运算
int n=(b1<<24)|(b2<<16)|(b3<<8)|b4
-------->读取n的值
(原因:文件在读取操作时,每次只能读取文件的低八位的字节数,也就是1个byte,所以就造成了上述的现象)
#########认识write();
认识读写RandomAccessFile
write(int b) 向文件中写出一个byte
int b=read() 向中读取一个byte
write(byte[] buf) 向文件中写出一批 byte
read(byte[] buf)从文件中添加一批文件
控制文件的读写位置:getFilePoint seek()
#########
测试代码:
import java.io.IOException;
import java.io.UnsupportedEncodingException;
public class Demo2 {
/**
*UTF-8 是国际化的最优国际编码
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
String str="今天你吃了吗?";
for(int i=0;i<str.length();i++){
char c=str.charAt(i);
System.out.println(Integer.toBinaryString(c));
}
/*getBytes()
*将字符串序列化为byte数据的方法
*(字符串序列化=字符串的编码,字符串编码的方案之一“UTF-16BE”)
*如果添加一些字母,会浪费了8个字节的空间,因为中文16个字节,而字母的只需8个字节表示造成的
*/
byte[] buf=str.getBytes("UTF-16BE");
for(int b:buf){
System.out.println(Integer.toBinaryString(b&0xff));
}
}
}
##########
测试代码UTF-8
import java.io.IOException;
import java.io.UnsupportedEncodingException;
public class Demo2 {
public static void main(String[] args) throws IOException {
String str="今天你吃了吗?www";
for(int i=0;i<str.length();i++){
char c=str.charAt(i);
System.out.println(Integer.toBinaryString(c));
}
System.out.println("UTF-8方案如下:");
byte[] buf=str.getBytes("UTF-8");
for(int b:buf){
System.out.println(Integer.toBinaryString(b&0xff));
}
}
}
输出:
100111011001010
101100100101001
100111101100000
101010000000011
100111010000110
101010000010111
1111111100011111
1110111
1110111
1110111
UTF-8方案如下:
11100100
10111011 今 (111 是标识, 10也是标识 今---------> 00100111011001010)
10001010
11100101 天
10100100 .
10101001 .
.
11100100
10111101
10100000
11100101
10010000
10000011
11100100
10111010
10000110
11100101
10010000
10010111
11101111
10111100
10011111
1110111
1110111
1110111
经典案例:将字符串写到文件:
RandomAccessFile raf=new ...?
String str="你今天吃了吗?";
byte[] buf=str.getByte("UTF-8");
raf.write(buf);
raf.close();
##############
RandomAccessFile raf=new ...?
byte[] buf=new buty[200];
//从文件raf中读取多个byte填充到buf数组中,返回值m表示填充个数
int n=raf.read(buf);
SYSTEM.OUT.PRITBLN(n);
String str=new String(buf,0,n,"utf-8");
//n 表示,200个字节中前n个是有效的。
System.our.pritnln(str);
raf.close();
编码测试:
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Random;
public class Demo1 {
public static void main(String[] args) throws IOException {
RandomAccessFile raf=new RandomAccessFile("demo", "rw");
byte[] buf=new byte[200];
int n=raf.read(buf);
String str=new String(buf,0,n,"utf-8");
System.out.println(str);
raf.close();
}
}
############控制文件读写位置
getFilePointer seek
############总结:
RandomAccessFile 总结
1 可操作文件内容
2 可以任意移动文件指针 读写文件
3 每次读写1个byte
4 提供了基本数据类型 读写方法
测试代码:
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Random;
public class Demo1 {
public static void main(String[] args) throws IOException, Exception {
RandomAccessFile raf=new RandomAccessFile("aa", "rw");
raf.write(25);
System.out.println(raf.getFilePointer());//跳到1
raf.writeInt(12345678);
System.out.println(raf.getFilePointer());//跳到5
//
raf.seek(1);//跳到int 数据开始的位置
int m=raf.readInt();
System.out.println(m);
System.out.println(raf.getFilePointer());
raf.close();
}
}
缺点:没有提供更复杂的读写方法