精华内容
下载资源
问答
  • 1.数组1.0 一开始就错了 int a[8]; //没有像C在内存中开辟了8个区域改:int a[] = {1,2,3} ;System.out.println(a.length);...//引用array[2] 就是0数组特点:大小固定 , 按下标进行取值2.arraylist工作原理就是:1...

    1.数组

    1.0   一开始就错了 int a[8];    //没有像C在内存中开辟了8个区域

    改:

    int a[] = {1,2,3} ;

    System.out.println(a.length); //3

    1.1用java专用的new运算符

    int[] array = new int[8];

    //引用array[2] 就是0

    4fe105e46677636fe4466f5de1ddf959.png

    数组特点:大小固定  ,  按下标进行取值

    2.arraylist

    工作原理就是:1.  new一个的时候得到10个元素的数组

    add超过10个元素的时候,也就是当添加第11个数据的时候,Arraylist继续扩容变为10*1.5=15

    2. new一个新数组(15元素),然后把老的数组元素copy过来

    增 删 都会移动元素的大量移动

    对比《数据结构》的顺序表

    顺序表定义:用一组地址连续的存储单元依次存储线性表的数据元素的表

    相当于能够动态增加删除数组里面的元素。

    构造器

    ArrayList提供了三个构造器:

    public   ArrayList();

    默认的构造器,将会以默认(16)的大小来初始化内部的数组

    在做实验实现顺序表的时候,int a[100] ,然后用一个变量L来标识这个表的长度

    List list = new ArrayList();

    list.add(1);

    72fee52474b4b71360ed0ac76e148bf6.png

    首先,ArrayList有一个初始的默认大小,为10.

    private static final int DEFAULT_CAPACITY = 10;

    从add方法为入口

    public boolean add(E e) {

    ensureCapacityInternal(size + 1); // 确保不超出内部的容量

    elementData[size++] = e; // 标准的数组啊

    return true;

    }

    ArrayList的扩容会产生一个新的数组,将原来数组的值复制到新的数组中。会消耗一定的资源

    e9e22400aa728316e9db25173f2f392f.png

    16744c0be326565a3cedf78f2884e44c.png

    将java中数组转换为ArrayList的方法实例(包括ArrayList转数组)

    方法一:使用Arrays.asList()方法   1 2 String[] asset = {"equity", "stocks", "gold&q ...

    JAVA 用数组实现 ArrayList

    我们知道 ArrayList 是一个集合,它能存放各种不同类型的数据,而且其容量是自动增长的.那么它是怎么实现的呢? 其实 ArrayList 的底层是用 数组实现的.我们查看 JDK 源码也可以发现 ...

    Java中Array与ArrayList的10个区别

    Array和ArrayList都是Java中两个重要的数据结构,在Java程序中经常使用.并且ArrayList在内部由Array支持,了解Java中的Array和ArrayList之间的差异对于成为 ...

    在Java中怎样把数组转换为ArrayList?

    翻译自:How to Convert Array to ArrayList in Java? 本文分析了Stack Overflow上最热门的的一个问题的答案,提问者获得了很多声望点,使得他得到了在S ...

    [转]Java中怎样把数组转换为ArrayList

    方法汇总: Element[] array = {new Element(1),new Element(2),new Element(3)}; ArrayList arr ...

    Java基础(七)泛型数组列表ArrayList与枚举类Enum

    一.泛型数组列表ArrayList 1.在Java中,ArrayList类可以解决运行时动态更改数组的问题.ArrayList使用起来有点像数组,但是在添加或删除元素时,具有自动调节数组容量的功能,而 ...

    Java学习笔记51:数组转ArrayList和ArrayList转数组技巧

    ArrayList转数组: public class Test { public static void main(String[] args) { List list = ...

    Java中List,ArrayList、Vector,map,HashTable,HashMap区别用法

    Java中List,ArrayList.Vector,map,HashTable,HashMap区别用法 标签: vectorhashmaplistjavaiteratorinteger ArrayL ...

    Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

    随机推荐

    Java中常用集合操作

    一.Map 名值对存储的. 常用派生类HashMap类 添加: put(key,value)往集合里添加数据 删除: clear()删除所有 remove(key)清除单个,根据k来找 获取: siz ...

    【POJ 1269】判断两直线相交

    题 利用叉积解方程 #include #define MAX 1<<31 #define dd double int xmult(dd x1,dd y1,dd ...

    JavaScript封装Ajax(类JQuery中&dollar;&period;ajax&lpar;&rpar;方法)

    ajax.js (function(exports, document, undefined){ "use strict"; function Ajax(){ if(!(this ...

    solrnet的使用

    solr与.net系列课程(五)solrnet的使用    solr与.net系列课程(五)solrnet的使用 最近因项目比较忙,所以这篇文章出的比较晚,离上一篇文章已经有半个月的时间了,这节课我们 ...

    Souvenir Shop 解题报告

    Souvenir Shop 魔幻题目,这谁搞得到啊... 考场上完全sb了写了个线段树合并,想必我是个复杂度分析都没学过的入门级选手 发现这个网格图dag它的出度最多只有2 如果按照先走朝上的一条边进 ...

    聊聊React的路由React-Router、react-router-dom

    关于二者的区别 参见:https://github.com/mrdulin/blog/issues/42 直接使用react-router-dom好了,react-router-dom封装了react ...

    Redis之无序集合类型命令

    Redis 集合(Set) Redis 的 Set 是 String 类型的无序集合.集合成员是唯一的,这就意味着集合中不能出现重复的数据. Redis 中集合是通过哈希表实现的,所以添加,删除,查找 ...

    &period;net core 自制错误日志

    前言 之前.net framework用的ErrorLog帮助类,对于监控错误形成日志,内容非常清晰,想在.net core2.2中继续用,但是有很多不一样的地方,所以想总结一下. 首先需要HttpC ...

    Appstate的几种状态及在android 和ios触发

    AppState能告诉你当前应用是在前台还是在后台,或者处于切换应用的状态,并且能在状态变化的时候通知你. AppState 通常在处理推送通知的时候用来决定内容和对应的行为 一: App State ...

    IOS-Quartz2D(Paths元素)

    Paths中的几个重要元素 Points void CGContextMoveToPoint (    CGContextRef c,    CGFloat x,    CGFloat y ); 指定 ...

    展开全文
  • 1./*二维数组:就是一个数组元素是一维数组数组格式1:每一个一维数组的长度都一样 数据... 表示声明一个可以存放3个一维数组的二维数组,每个一维数组的长度是2 取值数组名[m][n],表示获取第m+1个一维数组的...

    1.

    /*

    二维数组:就是一个数组元素是一维数组的数组
    格式1:每一个一维数组的长度都一样
    数据类型[][] 数组名 = new 数据类型[m][n];
    m:表示这个二维数组有m个一维数组
    n:表示每个一维数组有n个元素

    int[][] arr = new int[3][2];
    表示声明一个可以存放3个一维数组的二维数组,每个一维数组的长度是2

    取值:数组名[m][n],表示获取第m+1个一维数组的第n+1个元素
    赋值:数组名[m][n] = value,表示给数组的第m+1个一维数组的第n+1个元素赋值为value
    */
    class ArrayDemo{
    public static void main(String[] args){
    int[][] arr = new int[3][2];
    System.out.println(arr);//整个二维数组的首地址:[[I@15db9742
    System.out.println(arr[0]);//第一个一维数组的首地址:[I@6d06d69c
    System.out.println(arr[1]);//第二个一维数组的首地址:[I@7852e922
    System.out.println(arr[2]);//第三个一维数组的首地址:[I@4e25154f
    System.out.println(arr[0][0]);//0
    System.out.println(arr[1][1]);//0
    System.out.println(arr[2][1]);//0
    arr[0][0] = 100;
    arr[1][1] = 200;
    System.out.println(arr[0][0]);//100
    System.out.println(arr[1][1]);//200
    }

    }

    2.

    /*
    格式2:可以动态指定每个一维数组的长度
    数据类型[][] 数组名 = new 数据类型[m][];
    m:这个二维数组有m个一维数组,但是每个一维数组的长度可以动态的指定
    */
    class ArrayDemo2{
    public static void main(String[] args){
    //创建了一个二维数组,这个二维数组有3个一维数组
    int[][] arr = new int[3][];
    System.out.println(arr);//[[I@15db9742
    System.out.println(arr[0]);//null
    System.out.println(arr[1]);//null
    System.out.println(arr[2]);//null
    arr[0] = new int[1];
    arr[1] = new int[2];
    arr[2] = new int[3];
    System.out.println(arr[0]);//[I@6d06d69c
    System.out.println(arr[1]);//[I@7852e922
    System.out.println(arr[2]);//[I@4e25154f
    arr[0][0] = 10;
    arr[1][1] = 20;
    arr[2][2] = 30;
    System.out.println(arr[0][0]);//10
    System.out.println(arr[1][1]);//20
    System.out.println(arr[2][2]);//30
    }
    }

    3.

    /*

    二维数组格式3:可以直接给每个一维数组的元素赋值
    数据类型[][] 数组名 = new 数据类型[][]{{值1,值2...},{值1,值2...},{值1,值2...}};
    简化格式:
    数据类型[][] 数组名 = {{值1,值2...},{值1,值2...},{值1,值2...}};
    */
    class ArrayDemo3{
    public static void main(String[] args){
    //int[][] arr = {{1,2,3},{11,22,33,44},{111,222}};
    int[][] arr = new int[][]{{1,2,3},{11,22,33,44},{111,222}};
    System.out.println(arr);//[[I@15db9742
    System.out.println(arr[0]);//[I@6d06d69c
    System.out.println(arr[1]);//[I@7852e922
    System.out.println(arr[2]);//[I@4e25154f
    System.out.println(arr.length);//二维数组的长度:3
    System.out.println(arr[0].length);//第一个一维数组的长度:3
    System.out.println(arr[1].length);//第二个一维数组的长度:4
    System.out.println(arr[2].length);//第三个一维数组的长度:2

    System.out.println(arr[0][2]);//3
    System.out.println(arr[1][2]);//33
    System.out.println(arr[2][0]);//111
    }

    }

    4.面试必考题之冒泡排序

    class ArraySort{
    public static void main(String[] args){
    int[] arr = {-1,2,55,12,6,-5};
    //排序之前的遍历:
    showArray(arr);

    bubbleSort(arr,false);

    //排序之后的遍历:
    showArray(arr);
    }

    //使用冒泡排序对数组进行排序,isDesc如果是true就表示降序,反之表示升序
    public static void bubbleSort(int[] arr,boolean isDesc){
    //总共遍历比较次数:数组长度-1
    for(int i=1; i<arr.length; i++){
    //每一次遍历比较的次数:数组长度-当前遍历比较的次数
    for(int j=0; j<arr.length-i; j++){
    //拿着j和j+1对应的值进行比较
    if(isDesc){
    //降序:如果发现前面的值比后面的值小的话,就把前面的值往后方法
    if(arr[j]<arr[j+1]){
    int temp = arr[j];
    arr[j] = arr[j+1];
    arr[j+1] = temp;
    }
    }else{
    //升序:如果发现前面的值比后面的值大的话,就把前面的值往后方法
    if(arr[j]>arr[j+1]){
    int temp = arr[j];
    arr[j] = arr[j+1];
    arr[j+1] = temp;
    }
    }
    }
    }
    }

    //遍历一维数组的方法
    public static void showArray(int[] temp){
    //遍历一维数组
    for(int j=0; j<temp.length; j++){
    if(temp.length==1){//判断数组长度是否等于1
    System.out.println("["+temp[j]+"]");
    }else if(j==0){//第一个元素
    System.out.print("["+temp[j]+",");
    }else if(j==temp.length-1){//最后一个元素
    System.out.println(temp[j]+"]");
    }else{//剩余的元素
    System.out.print(temp[j]+",");
    }
    }
    }

    }

    5.遍历二维数组

    /*
    二维数组:就是一个数组元素为一维数组的数组
    */
    class ArrayTest{
    public static void main(String[] args){
    int[][] arr = {{666},{1,2,3},{11,22,33,44,55},{111,222,333}};
    showArray(arr);
    }

    //遍历二维数组的方法
    public static void showArray(int[][] arr){
    /*
    [1,2,3]
    [11,22,33,44,55]
    [111,222,333]
    */
    //先遍历二维数组
    for(int i=0; i<arr.length; i++){
    //取出来的是一维数组
    int[] temp = arr[i];
    //遍历一维数组
    showArray(temp);
    }
    }

    //遍历一维数组的方法
    public static void showArray(int[] temp){
    //遍历一维数组
    for(int j=0; j<temp.length; j++){
    if(temp.length==1){//判断数组长度是否等于1
    System.out.println("["+temp[j]+"]");
    }else if(j==0){//第一个元素
    System.out.print("["+temp[j]+",");
    }else if(j==temp.length-1){//最后一个元素
    System.out.println(temp[j]+"]");
    }else{//剩余的元素
    System.out.print(temp[j]+",");
    }
    }
    }

    }

    冒泡原理图:


    原理图:





    展开全文
  • 作者 陈本布衣转载自https://www.cnblogs.com/chenbenbuyi/p/11407158.html我们都知道,Java中有8中基本数据类型,每种类型都有取值范围,比如 1 个字节的 byte 取值范围是【-128~127】,4 个字节的 int 取值范围是 ...

    d19450bd7a39eb0ec63922078e5b952f.png

    码农每日一题长按关注,工作日每天分享一个技术知识点。8d81bbb6c6b5f140260b4970a36c3735.png

    作者 陈本布衣

    转载自 https://www.cnblogs.com/chenbenbuyi/p/11407158.html

    我们都知道,Java中有8中基本数据类型,每种类型都有取值范围,比如 1 个字节的 byte 取值范围是【-128~127】,4 个字节的 int 取值范围是 【-231~231-1】。因为能表示的值的范围不同,如果我们将 int 类型强转为 byte 类型的话,是很可能损失精度的,比如:

    byte a = (byte127;  // a = 127
    byte b = (byte128;  // b = -128
    byte c = (byte256;  // c = 0

    以人脑的主观意识,128 只比 byte 范围上限多 1 而已,如果损失精度,把多的 1 舍去变 127 就好了啊,怎么就变成了 -128?也曾看到一些园友说,这种强转造成的精度损失后的结果是毫无意义的,博主不以为然;稍微深究一下,你会发现,这结果并不是编译器随便给的数字,而是经过逻辑运算后的结果——虽然,表面上你看不出这种结果有什么运算逻辑,但你不要忘了,计算机的逻辑都是二进制逻辑,不是你我的人脑逻辑啊。

    二进制

      二进制,是计算机唯一能识别、存储的数,用0和1两个数码来表示,基数为2,“逢二进一”,”借一当二”。  要搞清楚上面 Java 代码的运算逻辑,我们首先要做的是将对我们人脑直观的十进制数字转换成对计算机直观的二进制,这里就用到了一个概念叫比特位(bit),这是计算机最小的存储单元了,表示二进制的存储位。而我们说 一个字节占用 8 个长度位,就是指一个字节占用了八个比特位的长度,也就是八个二进制位。布衣博主画了一份草图,来将上文中的十进制数转换成二进制比特存储位,这里先以十进制的 256 为例:bd1484ba7b237713d63f3f02e08a15c6.png

    将4字节的int类型数据转换成单字节的byte,最高位的三个字节的存储单元将被舍弃掉,这才是损失精度的要义所在!所以,根据上图高位舍弃的强转后,你自己也可以看出来,最后得到的 byte 十进制表示数字 0 。嗯,似乎也就那么回事,还是很好理解,但是,沿用上面的图,我们换成 128 试试?

    7626898168f93b2970bc9427aa7f0118.png

    看草图,似乎也很简单,128强转后,按照高位舍弃理论,无非是舍弃掉了高字节位无意义的 24 个 0 而已,最后的 byte 字节表示的还是原来那么大,还应该是 128 才对啊,为什么实际程序运行的结果却变成了 -128 ?咳咳!老师有没有告诉过你,Java的数据是带符号的?你知道二进制中如何表示一个数的正负的吗?所以,上诉理论中,我们还遗漏了一个很重要的知识点,那就是符号位的表示。对于有符号二进制来说,为了区分数的正负,约定以最高位作为符号位,0表示正数,1 表示负数,除去符号位剩下的就是这个数的绝对值部分:

    f29eef64c990d42fa4e85022c0848889.png

    我们带上符号位,回过头来重新分析上面对 128 的强转:当高位的三个字节被舍弃掉之后,连同舍弃的还有它的符号位 0 ,最终的结果就是强转成单字节后,原来表示数值部分的 1 变成了符号位,表示为负,除去符号位,能表示值的就只有后7位的 0000000 了。这样表示的十进制值为  -0,在带符号的二进制中,-0 被规定用来指代 -128,+0 才表示 0 。看来,只要带上符号位,本文最开始的输出结果是很好分析的。至此,我们引出了二进制中的符号位,并用此解答了本文一开始的疑惑。但是,有了符号位,这里又有疑问了,如果符号位占据了字节高位(第一位),当我们在进行算数运算的时候,符号位又该如何处理呢?

    原码、反码和补码

      虽然人类用计算器算账的时候,是按十进制的思维来进行加减乘除的,但是对于计算机来说,它最终会将人类的输入转化成底层的二进制来操作。如果我们的二进制操作都是带符号的,这就会有上面提到的符号位该如何处理的问题。比如 5-3,21-25,21+15,-3-8 等等,两个数字相加减,结果可能是正数也可能是负数,如果将符号位加入运算,如何进行进位和借位操作?如果符号位不加入运算,单独区分符号位肯定会增加计算机底层设计的复杂度。不管怎样,有一点可以肯定,那就是带符号的二进制数是不能直接拿来运算的!肿么办呢?为了不增加计算机底层设计的复杂度,人类还是决定在符号位上下功夫,于是有了我们熟知的二进制领域中的 原码,反码以及补码等等概念,下面是三种码基本的表示的方法:
    • 原码:符号位(字节序列的最高位)加上原数值绝对值的二进制表示;
    • 反码:正数的反码是其本身,负数的反码为保持符号位不变其余位置按位取反;
    • 补码:正数补码依旧是其本身,负数补码为反码加1;
      其实,引入反码,我么已经可以将减法统一变作加法【 1-1=1+(-1)】进行正确的计算了,已经解决了符号位的问题了,但会产生 -0 和 +0 的问题,也就是 0 被带上了符号。虽然在人脑看来是正负 0 一样的,但是计算机可不那么认为,而且按照定义 0 会有两种原码表示,即 000 0000 和 1000 0000,这显然是有问题的。于是在反码的基础之上加 1 变补码,彻底解决了正负 0 的问题,以前表示 -0 的1000 0000 现在可以用来表示 -128,因为 -128 = -1-127=(-1)+(-127)=(1111 1111)补+(1000 0001)补=1000 0000。——这也是带符号位二进制能够多表示一个数的原因。下面是博主探究二进制运算的过程中画的原码和补码计算的结果差异图:76519b8527930efad99be8cad67720ba.png

    上图至少说明了两点:

    第一,带符号二进制直接用原码进行加减运算特别不靠谱,而通过补码进行加法(减也看作加)运算很靠谱;

    第二,如果运算结果是正数,由于正数的原码和补码相同,所以结果和十进制数是正确匹配的,如果结果是负数,需要将补码转成原码方能匹配正确的十进制结果;

    虽然补码解决了问题,但是博主还是有疑问——难道计算机科学家是先知,他们怎么知道将原码求反码后再加 1 得到的补码就能够解决符号位的运算问题?感觉像是碰巧一样,毫无道理嘛!但正确无比的结果又似乎在告诉我,补码的产生背后,肯定有某种隐含的逻辑。(思考ing)。补码补码,为什么叫补码,没学过计算机的我只听过补数啊?咦,会不会和补数有关系呢,不然为什么都姓 补 呢?一番琢磨,卧槽,还真的有关系。在十进制中,如果两个数相加能凑成十或成百的整数,我们就可以把其中一个数叫另一个数的补数,因此可以说 4 和 6 互为补数;同样的对于二进制来说,我们也是可以凑个整数的,凑整就有补数,而补数对于运算往往大有帮助!这里拿一个 4 位二进制来说,若不考虑符号位,其能表示的最大数为 1111,包含 0 在内总共能表示 16 个数,那么这个 16 就是一个 整数。如果要计算 7-3,我们可以尝试带入补数的思想,先用 7 加 3 的补数 13 看会有什么发现。这是很简单的算术问题, 7+13 等于 20,和 7-3 的结果 4 差的有点远。但是,差的是什么呢?恰好就是我们前面提到的那个整数啊,如果我们用 20 减掉整数 16,恰恰就是我们要的结果 4 !巧合吗?这可不是巧合,这是因为 20 已经超出了4 位二进制所能表示的最大数,产生进位溢出,这个溢出的数刚好就是那个整数 16。换成二进制表示你一定就了然了:

    7-3 = 0111-0011=0111+1101=0100(10100进位溢出舍弃高位的1)

    如果你还是不太理解,那么,博主将上面表述中特意强调的整数换成计算机术语中更常用的 模 你应该就恍然有感了。为什么上述中的整数也可以表述成模呢?因为二进制的进位溢出其实同模运算中遇整舍弃只留余数是一样的道理。具体到生活中我们可以用时钟来作比。时针在表盘上走一圈是12个点,因此 12 这个整就是一个模长,如果现在时针停在 12 点处,要让它指向 10 点,可以怎么做?顺时针(+)走10个点也行,逆时针(-)回 2 个点也行,而恰好 10 和 2 之间是互补的,于是,根据模长和补数的关系,我们就成功的将减法转换成了加法运算,这就是为什么上面的 7-3 可以换成 7+13的原因,由此可见,在带符号二进制的算数运算中,引入补码,其意思很明确,就是为了统一运算符。

    回过头来可以解答开头的问题——为什么科学家先知一样的就知道负数的补码是其反码加 1 呢?根据博主对补数和模的粗浅解释,我们可以自己来算下。带符号的 4 位 二进制能表示的最大数是 7,最小数是 -8,模长依然是 16。在这个单字节范围内的负数,比如 -3 ,二进制表示为 1011 。以上面博主说过减法变加法的方式,取 3 的补数 13,二进制表示为 1101,这不正是 -3 的补数嘛!所以,负数的补码真不是科学家先知一般知道就是反码加 1,只不过运算出来恰好就是反码加 1 ,这也是算出补码最简单的方法了,于是也就那样去表述,并不是理论基础。

    位运算

    二进制的运算其实还不止于上面看到的基本的算数运算,还有一种运算叫逻辑运算——直接操作二进制中的位,而不涉及算术运算中的进位和借位,所以也叫位运算。面试你可能遇到过诸如 "写出 2*8 最有效率的运算方法"之类的问题,无非就是考你对于底层二进制的熟悉程度。不用说,当然是用位运算效率最高咯。所以,掌握一点位运算,在一些问题解决上,常常会有一些巧技。博主简述一下常见的逻辑运算,为最后的阐述做铺垫。

    按位与(&)

    相对应的二进制位同为 1 结果才为 1,否则都是 0,形如:0&0=0,0&1=0,1&0=0,1&1=1 。 利用这个特性,我们判断奇偶数就可以不用再传统的 n%2的方式了,直接用 n&1,结果为 1 就是奇数,为 0 就是偶数。why? 因为 0或正数,补码和原码相同,由于 1 的前 n 位都是 0 ,与 1 相与,结果肯定是 0 ,我们只关心最后一位,奇数肯定是 1,1与1相与结果为1;若为负数,原码转反码时,奇数最后一位由 1 变 0,但转补码后有加 1 操作,末尾为 1 ,判定同理。

    按位或(|)

    相对应的二进制位只要有一个为 1 ,结果即为 1,形如:0|0=0,0|1=1,1|0=1,1|1=1。 

    按位异或(^)

    相对应的二进制位数字不同,结果为 1 ,否则都是 0 ,形如:0^0=0,0^1=1,1^0=1,1^1=0。异或有个特性就是,任何数与 0 异或,结果都是其本身。利用这个特性,可用于数的交换,以此可以解决一些面试刁难:如何在不采用临时变量的情况下实现两个数的交换?当然,不用位运算也是可以实现的,只是不那么高级。常见写法奉上:

    int a = 2int b = 3;
    //方式一
    a=a+b; b=a-b; a=a-b;
    // 方式二
    a=a^b;  b=a^b; a=a^b;    

    取反(~)

    二进制位按位取反,0 变 1 ,1 变 0 。

    左移(<

    形如 a<

    右移(>>)

    形如 a>>b ,原理同左移,只不过由于符号位在最高位,所以,如果右移的是负数,会在高位补 1 ,如果为正数,高位补 0 。

    无符号右移(>>>)

    与右移唯一的不同在于,不论原来最左边是什么数,移动后都在高位补 0。注意,没有无符号左移, 因为左移始终是在右边补 0 ,而符号位在左边,不存在补符号位的问题。

    终章

    哔哔了这么多,还是回到开始吧。看了博主上面无头无脑的分析,相信你早已明白,长字节的数要往短了转,直接强来,肯定是不行的。那就不转呗,反正也很少遇到。NO,NO,NO!只需要翻看一下Java的IO包中的各种输入输出流的读写方法,就可以发现,很多参数都是字节数组,因为字节可以说是计算机中能表示信息含义的最小单位了,尤其在网络编程中,为了不同通讯终端的数据兼容,发送和接受的数据基本都是字节序列,所以,知道如何将长字节数变短,也是很有必要滴。

    那么,在Java中,我们怎么将一个int类型,转换成byte 还能成功的还原呢?直接强转,超过范围的部分,肯定是装不下的,不过我们知道,一个 int 占用 4个 byte,换句话说,我们可以用一个长度为 4 的 byte数组来装:

    25d2ef30ca10d54b793fc6f7e0358662.png

    看图就知道,装进byte数组是容易的(这里的装法也可以反序来,即byte[0]装低8位,以此类推,还原相应调整顺序,只要明白原理,都OK),主要的问题在于如何将 int 拆分成单个字节放进数组。看图就知道,其实也比较简单,就是进行位运算中的右移(>>)操作,不然博主上面位运算铺垫个铲铲啊,不多说,代码一目了然:

    public static byte[] int2Bytes(int i) {
            byte[] bytes = new byte[4];
            bytes[0] = (byte) (i >> 24);
            bytes[1] = (byte) (i >> 16);
            bytes[2] = (byte) (i >> 8);
            bytes[3] = (byte) i;
            return bytes;
    }
    装是装进去了,怎么还原呢?我们刚刚是进行了进行了右移操作,要还原的话,很自然的我们想到要左移(<
    public static int bytes2Int(byte[] bytes) {
            // 左移将原来的数先还原到对应的位置,再 按位或 将几个数进行合并
            return   bytes[3]
                    | bytes[2] <8
                    | bytes[1] <16
                    | bytes[0] <24;
    }
    如果你真这样搞,那就等着大大的bug吧!如上图博主画图是 256 的二进制存储位序列图,用上面的方法还原出来倒是没问题,你多换几个数试试,比如-258, 245677,-2677等等?这都是博主随便举的数字,没有啥特殊,但结果会让你大跌眼镜。为什么通过右移装进数组再按照同样的思维方式左移还原就不行了呢?那是因为计算机对二进制的运算和存储都是以补码方式来进行的啊,亲。-258 在 int 中存的样子不是你以为的这个样子:

    49c2a9fe1b8c089cb5a1ae89a17355c8.png

    而应该是下面这个样子:

    0a5fabed8b4730416adfd02b0fbd75f8.png

    因此,我们装到字节数组中的就是第二份草图中存储位序列中的每一个字节段。而当我们用左移想进行还原的时候,byte 数组中每个byte左移后的结果其实是下面这样的:

    dea1ec58049043608fec37f24035a183.png

    对于上面的草图,博主解释一下。在进行移位运算时,byte,short,char 的类型会提升为 4 字节 32 位的 int 型,就需要用 0 或 1 进行补位,如果是负数,会在前面补 1 ,如果是正数则补 0 。从上图左移补齐后的存储序列来看,如果此时将得到的 4 个 int 值进行 按位或(|)操作(未移位的byte[3]此时也会补位到 32 位),结果就是下面这样:

    13e14c8a78022003399837eee9c7b935.png

    哇,这个结果,看起来这个数好大的样子,其实不大,因为博主早就说过了计算机是以补码的形式存储二进制的,将该补码转回原码你会发现,才等于 -2 ,挺小的,不过和原来的 -258相差太多了。分析下来,其实你已经发现了,还是因为符号位在捣乱:当还原前字节数组中有负数的时候,在提升为 int 补位的时候补1 就补出了问题。如何解决呢,很简单,将负数本来补的 1 置为 0 。通常的做法是采取将字节数先和 0xff(00000000 00000000 00000000 11111111)进行 按位与(&)操作,在电计算机补 1 之前,我们自己先给补 0 到32位,形如布衣草图:

    75731e63f7d12b27d4ae8b51be821abf.png

    所以,上面还原 int 的方法该这样写:
    public static int bytes2Int(byte[] bytes) {
            return    bytes[3] & 0xff
                    | (bytes[2] & 0xff) <8
                    | (bytes[1] & 0xff) <16
                    | (bytes[0] & 0xff) <24;
    }
    好了,结尾勿煽情,哔完收工!若博主阐述有不恰当的地方,欢迎留言指正;推不推荐的,随缘随便随你吧。

    867e54adcfbe4806dd4e62f9b80039df.gif

    7a3b039918a02eb771b3ace4fbd9148e.png看完顺手 Option 咯~

    ▼往期精彩回顾▼当程序员当了爸爸,你也会有如下经历!10个艰难的 Java 技术问题与答案

    6cd2ad37d44d98ee94f00f412265d032.png本号主打短小精干,点击左下角阅读原文查看历史经典题目汇总~

    展开全文
  • 在堆中产生了一个数组或者对象后,还可以在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存中的首地址,在栈中的这个特殊的变量就变成了数组或者对象的引用变量,以后就可以在程序中使用栈内存中的...

    Java堆

    堆内存用于存放由new创建的对象和数组在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。在堆中产生了一个数组或者对象后,还可以在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存中的首地址,在栈中的这个特殊的变量就变成了数组或者对象的引用变量,以后就可以在程序中使用栈内存中的引用变量来访问堆中的数组或者对象,引用变量相当于为数组或者对象起的一个别名,或者代号。

    根据垃圾回收机制的不同,Java堆有可能拥有不同的结构,最为常见的就是将整个Java堆分为

    新生代和老年代。其中新声带存放新生的对象或者年龄不大的对象,老年代则存放老年对象。

    新生代分为eden区、s0区、s1区,s0和s1也被称为from和to区域,他们是两块大小相等并且可以互相角色的空间

    绝大多数情况下,对象首先分配在eden区,在新生代回收后,如果对象还存活,则进入s0或s1区,之后每经过一次

    新生代回收,如果对象存活则它的年龄就加1,对象达到一定的年龄后,则进入老年代。

    Java栈

    Java栈是一块线程私有的空间所以不会产生线程安全问题,栈代码运行完毕自动释放内存,一个栈,一般由三部分组成:局部变量表、操作数据栈和帧数据区

    局部变量表:用于报错函数的参数及局部变量

    操作数栈:主要保存计算过程的中间结果,同时作为计算过程中的变量临时的存储空间。

    帧数据区:除了局部变量表和操作数据栈以外,栈还需要一些数据来支持常量池的解析,这里帧数据区保存着

    访问常量池的指针,方便计程序访问常量池,另外当函数返回或出现异常时卖虚拟机子必须有一个异常处理表,方便发送异常

    的时候找到异常的代码,因此异常处理表也是帧数据区的一部分。

    Java方法区

    Java方法区和堆一样,方法区是一块所有线程共享的内存区域,他保存系统的类信息。

    比如类的字段、方法、常量池等。方法区的大小决定系统可以保存多少个类。如果系统

    定义太多的类,导致方法区溢出。虚拟机同样会抛出内存溢出的错误。方法区可以理解

    为永久区。

    转载于:https://www.cnblogs.com/easyLog/p/10848572.html

    展开全文
  • 目录命名规范基本数据类型...a++,其中第一个输出为2,第二个输出为3,原理就是(变量++),先进行取值,后进行相加,所以第一次输出会先取值,取到2,接着第二次输出是在第一次,已经相加的情况下输出,所以输出三。
  • 在堆中产生了一个数组或者对象后,还可以在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存中的首地址,在栈中的这个特殊的变量就变成了数组或者对象的引用变量,以后就可以在程序中使用栈内存中的...
  • java不像c语言,没有指针,所以没办法通过指针取值进行排序。那么java的二维数组是怎么排序的呢? 解决方法如下: 方法一: 思路:新建一个一维数组将二维数组的数据按行存入,然后对一维数组排序,最后将排过序...
  • 零基础Java入门课程

    2020-12-06 18:54:17
    Java开发环境搭建、编写Java入门练习 虚拟机的运行机制、Java的平台无关性、虚拟机垃圾回收机制 基础语法 关键字、标识符、Java数据类型分类、基础数据类型、取值范围 变量、常量、三种注释、生成doc文档、运算符、...
  • Java开发环境搭建、编写Java入门练习 虚拟机的运行机制、Java的平台无关性、虚拟机垃圾回收机制 基础语法 关键字、标识符、Java数据类型分类、基础数据类型、取值范围 变量、常量、三种注释、生成doc文档、运算符、...
  • Java开发环境搭建、编写Java入门练习 虚拟机的运行机制、Java的平台无关性、虚拟机垃圾回收机制 基础语法 关键字、标识符、Java数据类型分类、基础数据类型、取值范围 变量、常量、三种注释、生成doc文档、运算符、...
  • Java基础语法

    2020-08-03 17:48:12
    Java基础语法 1.二进制(计算机组成原理课程的内容) 二进制:逢二进一,二进制中只含有0和1 原码:用二进制表示数值的大小(第一位为符号位,0表示正数,1表示负数) 反码:由原码取反得到(1变成0,0变成1,符号位...
  • Java堆和栈的基本理解

    2020-11-23 20:50:24
    堆存放的原因:由于在堆中创建对象(或数组)后,可在栈中定义一个特殊变量,让其取值为对象(或数组)在堆内中的首地址,即为其原理; 栈存放的原因:由于追求速度的原因,基本类型放置于栈中; 补充:堆中分配...
  • 本文主要写了有关在Java里面用数组实现栈的表达式,通过写有关简单表达例如:2-5*1-3的取值来对比数栈和符号栈,实现计算器原理,然后拓展到多位数表达里面给出结果分析思路,并给出实现代码
  • Java的数据类型分为两大类: 基本数据类型:包括 整数 、 浮点数 、 字符 、 布尔 。 引用数据类型:包括 类 、 数组 、 接口 。 long类型:建议数据后加L表示。 float类型:建议数据后加F表示。 数据类型转换 自动...
  • Java类型--集合

    2021-04-05 00:33:57
    迭代器和for循环(下标取值)对比 List ...虽然Java中有些底层通过链接存储原理实现的集合也可以通过下标获取指定的记录,但是其每次都必须从链表头开始查找记录,这样会影响查找的效率 Map ...
  • Java程序员面试宝典pdf

    热门讨论 2013-02-21 13:06:13
    面试题047 如何理解数组Java中作为一个类 75 面试题048 new Object[5]语句是否创建了5个对象 77 面试题049 如何拷贝数组的数据 78 面试题050 二维数组的长度是否固定 79 5.2 集合框架 80 面试题051 什么是集合 80 ...
  • 在堆中产生了一个数组或者对象后,还可以在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存中的首地址,在栈中的这个特殊的变量就变成了数组或者对象的引用变量,以后就可以在程序中使用栈内存中的...
  • 比如我们有取值范围为1-50的的元素数组,设置50个桶,那就是值相等的元素放到同一个桶里,然后按顺序取出每个桶里的元素,就可以得到一个有序数组了。 来看个例子,这有个无序数组 arr={8,4,5,7,1,4,3,6,7,9,7,2},...
  • Java数据结构-Hashmap

    2016-11-02 21:59:16
    内部结构图实现原理HashMap内部维护着一个Entry类型的数组,默认大小16:Entry,V>[] table,这个Entry对象包含key,value,next,hash四个属性,key和value即是你map.put(Key,Value)的key和value,hash是使用key经过...
  • 所谓排序就是将数组中各元素的值按从大到小的顺序或者从小到大的顺序重新排列。 排序过程一般都要进行元素值的比较和元素值的交换。 ... a[j+1],则交换a[j]与a[j+1],j的取值0,1,2,3,4,…...
  • 面试题047 如何理解数组Java中作为一个类 75 面试题048 new Object[5]语句是否创建了5个对象 77 面试题049 如何拷贝数组的数据 78 面试题050 二维数组的长度是否固定 79 5.2 集合框架 80 面试题051 什么是...
  • Java图像处理基础基本原理显示原图马赛克效果二值化边缘检测融合旋转缩放 基本原理 电脑中的图片,都是由像素点构成的,我们可以将图片理解为由像素组成的矩阵或二维数组,每个像素在矩阵中的位置,则表示了像素的...
  • MD5加密算法(Java版) 可以运行 原理  对MD5算法简要的叙述可以为:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位...
  • HashMap源码分析

    2020-11-23 17:00:22
    :无符号右移HashMap数据结构默认容量最大容量扩容阈值默认加载因子加载因子由Node转为TreeNode的阈值由TreeNode转为Node的阈值数据存储:使用数组存储Node节点hash 计算原理get 取值原理put 存值原理resize 扩容...
  • 你真的懂HashMap吗?

    2020-10-27 14:50:12
    1.HashMap的结构和底层原理 HashMap是由数组和链表组合构成的数据结构,它的存储是key-value键值对的形式存储的。跟据key的Hash去计算index...Java8之后采用的是尾插(因为头插,多线程插入可能会出现循环链表,取值
  • 类加载与字节码技术类结构文件magic版本常量池javap工具图解方法执行流程条件判断指令构造方法cinit 构造方法init 构造方法方法调用多态的原理synchronized编译期处理默认构造器自动拆装箱泛型集合取值可变参数...
  • KMP算法

    2021-01-21 01:38:11
    适合曾经学过KMP算法,理解大概原理但是写不出或者不太理解代码的同学,不适合KMP小白。 1. 理论 2. java代码实现 2.1 求解next数组 假设已经知道next[y]的取值为len,求next[y+1]的值。 若P[len] == P[y],则...
  • 3.4.8 找出数组中出现次数超过一半的数,现在有一个数组,已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数。 3.4.9 找出被修改过的数字 3.5.0 设计DNS服务器中cache的数据结构。要求设计一个...
  • EL表达式的详细使用

    2011-04-01 11:12:51
    4、例如,原理如上例3。 ${ sessionScope.userlist } 1 ${ sessionScope.userlist } 2 ${ applicationScope.userlist } 3 ${ pageScope.userlist } 4 ${uselist} 含义:执行顺序为4 1 2 3。 “.”后面的只是一个...

空空如也

空空如也

1 2
收藏数 37
精华内容 14
关键字:

java数组取值原理

java 订阅