Java语言基础

Java语言基础组成

1、关键字Java语言赋予了特殊含义的单词,关键字中所有字母都是小写

2、注释:单行注释,多行注释,文档注释。

3、标识符:在程序中自定义的一些名称。

                      26个英文字母大小写,数字:0-9符号:_ $组成

定义合法标识符规则

                    1,  数字不可以开头。

                    2,不可以使用关键字。

Java中严格区分大小写。

注意:在起名字的时,为了提高阅读性,要尽量有意义。

      main不是关键字,但是被JVM所识别。

      Java中严格区分大小写。

Java中的名称规范:

包名:多单词组成时所有字母都小写。xxxyyyzzz

类名接口名:多单词组成时,所有单词的首字母大写。XxxYyyZzz

变量名和函数名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写。xxxYyyZzz

常量名:所有字母都大写。多单词时每个单词用下划线连接。XXX_YYY_ZZZ

4、常量表示不能改变的数值。

(1)Java中常量的分类:

1,整数常量。所有整数

2,小数常量。所有小数

3,布尔型常量。较为特有,只有两个数值。true false

4,字符常量。将一个数字字母或者符号用单引号( ' ' )标识。

5,字符串常量。将一个或者多个字符用双引号标识。

6null常量。只有一个数值就是:null.

(2)整数常量表现形式:二进制,八进制,十进制,十六进制(要会进制间的转换)

(3)负数的二进制表现形式:对应的正数二进制取反加1

           如-6:

                               6:0000-0000 0000-0000 0000-0000 0000-0110

                         取反:1111-1111 1111-1111 1111-1111 1111-1001

                          加1 :1111-1111 1111-1111 1111-1111 1111-1010,即-6

            负数的最高位是1,正数的最高位是0.

 

拓展:关于补码、原码

1、在计算机系统中,数值一律用补码来表示(存储)。 主要原因:使用补码,可以将符号位和其它位统一处理;同时,减法也可按加法来处理。另外,两个用补 码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃。 2、补码与原码的转换过程几乎是相同的。

1)正数的补码与原码相同。

【例1】+9的补码是00001001。(备注:这个+9的补码说的是用8位的2进制来表示补码的,补码表示方式很多,还有16位二进制补码表示形式,以及32位二进制补码表示形式,64位进制补码表示形式等。)

2)负数的补码等于其绝对值的原码各位取反,然后整个数加1的数值。

同一个数字在不同的补码表示形式里头,是不同的。比方说-15的补码,在8位二进制里头是11110001,然而在16位二进制补码表示的情况下,就成了1111111111110001。在这篇补码概述里头涉及的补码转换默认把一个数转换成8位二进制的补码形式,每一种补码表示形式都只能表示有限的数字。

【例2】求-7的补码。

因为给定数是负数,则符号位为“1”。

后七位:-7的原码(10000111)→按位取反(11111000)(负数符号位不变)→加1(11111001)

所以-7的补码是11111001。

注:数0的补码表示是唯一的:

+0的补码=+0的反码=+0的原码=00000000

-0的补码=11111111+1=00000000(mod 2的8次方)

应用

已知一个数的补码,求原码的操作分两种情况:

⑴如果补码的符号位为“0”,表示是一个正数,其原码就是补码。

⑵如果补码的符号位为“1”,表示是一个负数,那么求给定的这个补码的补码就是要求的原码。

【例3】已知一个补码为11111001,则原码是10000111(-7)。

因为符号位为“1”,表示是一个负数,所以该位不变,仍为“1”。

其余七位1111001取反后为0000110;

再加1,所以是10000111。

 

5、变量:内存中的一个存储区域,该区域有自己的名称(变量名)和类型(数据类型),该区域的数据可以在同一类型范围内不断变化 。

         将不确定的数据进行存储,也就是在内存中开辟一个空间。

         开辟空间就是通过明确数据类型、变量名称、数据来完成。

(1)Java语言是强类型语言,对于每一种数据都定义了明确的具体数据类型,在内存总分配了不同大小的内存空间


(2)整数默认:int 小数默认:double

定义float类型数据时,后面要加f。

  一个汉字占16位,可以认为是char类型。

定义的基本数据类型在Java中都是带符号的,boolean和char不带符号。

(3)自动类型转换(也叫隐式类型转换)

 强制类型转换(也叫显式类型转换)

表达式的数据类型自动提升:

                             所有的byte型、short型和char的值将被提升到int型。

                             如果一个操作数是long型,计算结果就是long型;

                             如果一个操作数是float型,计算结果就是float型;

                             如果一个操作数是double型,计算结果就是double型。

                         (两个byte运算、两个short、两个char都会先提升成int型。)


/*拓展:关于Unicode编码
问题:char a='\U000d';为什么会编译失败
最佳答案:这是java编译器的一个缺陷,
你不能使用  Unicode的换行,斜杠等字符,至于为什么,举个例子:
public static void main(String[] args) {
        if ( false == true ) { //these characters are magic: \u000a\u007d\u007b
            System.out.println("false is true!");
        }
    }
你可以运行上面的方法,会输出  false is true!
java在编译时会先将Unicode字符进行 呈现(或翻译),然后再进行编译  ,上面的方法会变成  
public static void main(String[] args) {
        if ( false == true ) { //these characters are magic: 
}{
            System.out.println("false is true!");
        }
    }	

再来看你的代码 
char a='\U000d';
会变成:
char a='
';
这样就会产生语法错误。这就是原因了 

下面的代码是可以通过编译的
char c=' ';\u000d;
可以这样理解,代码中的 Unicode并不能理解为单纯的 字符或字符串,他们本身就是你的代码
如:
System.out.println("Unicode print ");  
这一行代码你可以写成
\u0053\u0079\u0073\u0074\u0065\u006d\u002e\u006f\u0075\u0074\u002e\u0070\u0072\u0069\u006e\u0074\u006c\u006e\u0028\u0022\u0055\u006e\u0069\u0063\u006f\u0064\u0065\u0020\u0070\u0072\u0069\u006e\u0074\u0020\u0022\u0029\u003b\u0020
其实都是一样的,只是书写和查看都很不方便 。
建议不要在代码中书写Unicode形式的字符,很容易产生奇怪的错误,而且不方便查看和修改
*/

6、运算符

  (1)算数运算符


算术运算符的注意问题:

如果对负数取模,可以把模数负号忽略不记,如:5%-2=1。但被模数是负数就另当别论。

对于除号“/”,它的整数除和小数除是有区别的:整数之间做除法时,只保留整数部分而舍弃小数部分。

  “+”除字符串相加功能外,还能把非字符串转换成字符串,字符串数据和任何数据

使用“+”号相连结果都是字符串。

  1%5=1;-1%5=-1;-1%-5=-1——就是说余数的符号只看被除数。

转义字符:通过\来转变后面字符的含义

 \n:转行

 \b:退格

\r:按下回车键

 \t:制表符,Tab键

 Linux里,换行由一个字符表示\n

Windows里,换行符由两个字符表示\r\n

(2)赋值符:= , +=,-=, *=, /=, %=

short s = 3;
s=s+2;//编译报错,两次运算,先加法再赋值
s+=2;//编译通过,一次运算,只有赋值。内部有自动转换动作,赋值时自动完成了强制转换操作。

//例子
byte a=123,b=0;
a+=134;//257 被强转为byte类型,为1.
b=a;
System.out.println(a); //结果为1.
System.out.println(b);

(3)比较运算符


注1:比较运算符的结果都是boolean型,也就是要么是true,要么是false。

注2:比较运算符“==”不能误写成“=”。

 

(4)逻辑运算符


逻辑运算符用于连接布尔型表达式,在Java中不可以写成3<x<6,应该写成x>3 & x<6 。

“&”和“&&”的区别:

单&时,左边无论真假,右边都进行运算;

双&时,如果左边为真,右边参与运算,如果左边为假,那么右边不参与运算。

“|”和“||”的区别同理,双或时,左边为真,右边不参与运算。

异或( ^ )与或( | )的不同之处是:当左右都为true时,结果为false。

                                      

(5)位运算符


位运算是直接对二进制进行运算。做运算时,位运算的运算速度最快。

<<:空位补0,被移除的高位丢弃,空缺位补0。

>>:被移位的二进制最高位是0,右移后,空缺位补0;最高位是1,空缺位补1。

>>>:被移位二进制最高位无论是0或者是1,空缺位都用0补。

&:二进制位进行&运算,只有1&1时结果是1,否则是0;

|:二进制位进行| 运算,只有0 | 0时结果是0,否则是1;

^:任何相同二进制位进行^ 运算,结果是0;1^1=0 , 0^0=0不相同二进制位^ 运算结果是1。1^0=1 , 0^1=1

反码:正数取反加1就是对应的负数,负数减1取反就是对应的正数。

      负数的原码是符号位不变,其他位取反加1.

异或:一个数异或同一个数偶数次,结果还是那个数。比如7^2^2=7。

拓展:关于移位

     1.<<:没有溢出时,相当于乘以2的移位数次方。

                       正数溢出就是指最高位的1移动到符号位开始。负数溢出就是指高位第一个0移动到符号位开始。

          比如4,二进制是0000-00000000-0000 0000-0000 0000-0100,移动29位之前都是符合以上规律

    2.>>:对于正整数而言,相当于除以2的移位次方取商。

          对于负数:负数能被2的右移的位数次方整除的话可能也是符合的,如果不能被其整除的话貌似就是负数除以2的右移位数次方再减1可以了

         注意:  如果对 char、byte 或者short 类型的数值进行移位处理,那么在移位进行之前,它们会自动转换为int,并且得到的结果也是一个int 类型的值。而右侧操作数,作为真正移位的位数,只有其二进制表示中的低5 位才有用。这样可防止我们移位超过int 型值所具有的位数。(译注:因为2 的5 次方为32,而int 型值只有32 位)。若对一个long 类型的数值进行处理,最后得到的结果也是long。此时只会用到右侧操作数的低6 位,以防止移位超过long 型数值具有的位数。

                 比如,1>>21,首先对21的低五位取模,得到21,再移位,移动21位

                       1>>32,首先对32的低五位取模,得0,即移动的位数为0位。

练习:

1.最有效率的方式算出2乘以8等于几?2<<3;

2.对两个整数变量的值进行互换

(6):三元运算符

      格式: (条件表达式)?表达式1:表达式2;

如果条件为true,运算后的结果是表达式1;

如果条件为false,运算后的结果是表达式2;

      拓展:

(1)假如表达式1和表达式2具有相同的类型,那么整个条件运算符结果的类型就是这个类型。

(2)假如一个表达式的类型是T,T是byte或short或char,另一个表达式的类型是int类型的常量表达式,而且这个常量表达式的值是可以用类型T表示的(也就是说,常量表达式的值是在类型T的取值范围之内),那么整个条件运算符结果的类型就是T。

(3)除以上情况外,假如表达式1和表达式2的类型不同,那么将进行类型提升,整个条件运算符结果的类型就是提升后的类型


7、流程控制语句

(1)判断语句

  If语句:条件表达式无论写成什么样子,只看最终的结构是否是true 或者false;

 If-else语句的简写格式:变量=(条件表达式)?表达式1:表达式2;即三运算符。三元运算符的好处就是能简写if-else代码,弊端就是因为是一个运算符,所以运算完必须要有一个结果。

(2)选择结构

  switch语句特点:

1、switch语句选择的类型只有四种:byte,short,int ,char。

2、case之间与default没有顺序。先执行第一个case,没有匹配的case执行default。

3、结束switch语句的两种情况:遇到break,执行到switch语句结束。

4、如果匹配的case或者default没有对应的break,那么程序会继续向下执行,运行可以执行的语句,直到遇到break或者switch结尾结束。case语句不能重复。

关于if和switch:两个语句很像,如果判断的具体数值不多,而且符合byte,short,int ,char这四种类型,虽然两个语句都可以用,建议使用switch语句,因为效率较高。对区间判断,结果是boolean类型的判断,使用if语句。If的适用范围更广。

//实例
int x=2;
	switch (x)
	{
	default:
	    System.out.println('a');
	case 3:
		System.out.println('b');
	case 4:
		System.out.println('c');
		break;
	case 5:
		System.out.println('d');
		break;
	}//结果为a b c
/*解析:执行顺序是 case 3—case 4—case 5—default(输出a,由于没有break或者大括号,所以继续向下执行)—case 3(输出 b)—case 4(输出c,此时遇到break,跳出switch语句)
*/

(3)循环结构

代表语句:while , do while , for

do while特点是条件无论是否满足,循环体至少被执行一次。

do
{//执行语句
}while(条件表达式);//do-while语句中while后面要加分号
	

while(条件表达式)//后不能加分号,否则可能是无限循环
{//执行语句
}

for循环的格式:
for(初始化表达式;循环条件表达式;循环后的操作表达式)
	{
		执行语句;
	}

注意

1,for里面的连个表达式运行的顺序,初始化表达式只读一次,判断循环条件,为假就立即跳出循环,为真就执行循环体,然后再执行循环后的操作表达式,接着继续判断循环条件,重复找个过程,直到条件不满足为止。

2,while与for可以互换,区别在于for为了循环而定义的变量在for循环结束就是在内存中释放。而while循环使用的变量在循环结束后还可以继续使用。变量有自己的作用域,对于for而言,如果用于控制循环的变量定义在for语句中,那么该变量只在for语句中有效。for语句执行完毕,该变量在内存中被自动释放。

3,最简单无限循环格式:while(true), for(;;),无限循环存在的原因是并不知道循环多少次,而是根据某些条件,来控制循环。

4,for中的循环条件表达式必须是boolean类型,如果空着,就默认表达式恒为真。

//实例
int i=0;
for(System.out.print('a');i<2;System.out.print('c'))
		{
			System.out.print('d');
			i++;
		}//运行结果是adcdc

//用for嵌套循环打印乘法表:
public class Test {
	public static void main(String[] args)
	{
			chengFa(9);		
	}
	public static void chengFa(int a)
	{
		for(int i=1;i<=a;i++)//控制行数
		{
			for(int j=1;j<=i;j++)//控制列数
			System.out.print(j+"*"+i+"="+j*i+"\t");
			System.out.println();
		}
	}
}

注意:关于循环

  循环中的循环条件表达语句都可以用true。但是不能用false,因为没意义,执行不到下面的语句,会编译失败。而且也都不能用0和1,只能是boolean类型。

(4)break和continue语句

break(跳出), continue(继续)

break语句:应用范围:选择结构和循环结构。

continue语句:应用于循环结构。

注:

a,这两个语句离开应用范围,存在是没有意义的。

b,这个两个语句单独存在下面都不可以有语句,因为执行不到。如果有,就回编译失败。

c,continue语句是结束本次循环继续下次循环。

d,标号(只能用于循环,标号名称要符合标识符的格式,用冒号与循环隔开)的出现,可以让这两个语句作用于指定的范围。

//实例
//break用法:
for(int x=0;x<4;x++)
	{
		for(int y=0;y<4;y++)
			{System.out.print(y);
				break;//break用于跳出当前所在循环
			}
	}//执行结果为0000

one:for(int x=0;x<4;x++)
			{for(int y=0;y<4;)
				{y++;
					System.out.print(y);
					break one;//break跳出外层循环
				}
			}//执行结果为0
//Continue 用法:
for(int x=0;x<4;x++)
			{for(int y=0;y<9;y++)
				{if(y%2==0)
					continue;//当y是偶数时,继续执行内循环
					System.out.print(y);	
				}
			}//执行结果为1357135713571357

one:for(int x=0;x<4;x++)
		{for(int y=0;y<2;y++)
			{
			if(x%2!=0)
			{System.out.print("x"+x);
continue one;//x是偶数时,结束内循环继续执行外循环	   }}
			}//执行结果为x1x3

8、函数

   函数就是定义在类中的具有特定功能的一段独立小程序。函数也称为方法。(把代码中相同的部分抽取出来封装成一个独立的功能,Java中对功能的定义是通过函数的形式来体现的,函数只有被调用时才会执行,函数放在类里。)

函数的格式:


返回值类型:函数运行后的结果的数据类型。

参数类型:是形式参数的数据类型。

形式参数:是一个变量,用于存储调用函数时传递给函数的实际参数。

实际参数:传递给形式参数的具体数值。

return:用于结束函数。

返回值:该值会返回给调用者。

函数的特点:

1.定义函数可以将功能代码进行封装

2.便于对该功能进行复用

3.函数只有被调用才会被执行

4.函数的出现提高了代码的复用性

5.对于函数没有具体返回值的情况,返回值类型用关键 字void表示,那么该函数中的return语句如果在最后一行可以省略不写。

 注意:

函数中只能调用函数,不可以在函数内部定义函数。

定义函数时,函数的结果应该返回给调用者,交由调用者处理。

函数之间是平级,不可以哪个函数包含哪个函数,只能调用,放在类中,各函数间定义无顺序之分,系统会自动执行main函数

定义函数:明确要定义的功能最后的结果是什么,即明确返回值类型。

明确在定义该功能的过程中,是否需要未知内容参与运算,即明确参数列表

 

函数的重载(overload):在同一个类中,允许存在一个以上的同名函数,只要它们的参数个数或者参数类型不同即可。(与返回值类型无关,只看参数列表。)

                                       当定义的功能相同,但参与运算的位置内容不同(即参数列表),那么这时就可以定义相同的函数名称以表示其功能,方便于阅读,优化了程序设计。

void show(int a,int b,int c)
	{}
boolean show(int a,int b,int c)
	{return false;}
/*上述二者没有重载,而且不允许二者在同一个类中出现,因为假如调用show函数,系统将不知道调用哪一个。编译出错。
*/

9、数组

   同一种类型数据的集合。其实数组就是一个容器。可以自动给数组中的元素从0开始编号,方便操作这些元素。

   格式1:

元素类型[] 数组名= new 元素类型[元素个数或数组长度(必须写)];

示例:int[] arr = newint[5];

格式2:

元素类型[] 数组名= new 元素类型[]{元素,元素,……};

int[] arr = newint[]{3,5,1,7};

int[] arr ={3,5,1,7};

数组操作常见问题

1.数组脚标越界异常(ArrayIndexOutOfBoundsException)

int[] arr = new int[2];

System.out.println(arr[3]);

访问到了数组中的不存在的脚标时发生。

该代码在编译时没有错误,运行时出现错误提示:数组角标越界异常。所以,只有在运行时才会建立数组,编译只检查语法错误。

2.空指针异常(NullPointerException)

int[] arr = null;

System.out.println(arr[0]);

arr引用没有指向实体,却在操作实体中的元素时。

该代码在编译时没有错误,运行时出现错误提示:空指针异常

 

内存结构

Java程序在运行时,需要在内存中的分配空间。为了提高运算效率,有对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。

*栈内存

用于存储局部变量,当数据使用完,所占空间会自动释放。

*堆内存

数组和对象,通过new建立的实例都存放在堆内存中。

每一个实体都有内存地址值

实体中的变量都有默认初始化值

实体不再被使用,会在不确定的时间内被垃圾回收器回收

*还有方法区,本地方法区,寄存器

 

内存实例:

1.栈内存


解释:有主函数main函数和show函数,两个函数中都有变量x,主函数运行时,会在栈中开辟一个空间,当调用show函数时,也会在栈中开辟一个空间,当show函数执行完毕,为show开辟的空间就会自动消失

局部变量都在栈中(定义在方法中的变量,方法的参数,for循环中的变量)

2,堆内存            

  (1) int[] x=newint[3]; 

   首先,当读到赋值号左边时,栈内存会定义一个x,开辟一个空间。如图:


然后,new出来的东西都存放在堆内存中,是实体。因此,读赋值号右边时会在堆内存开辟一个空间,用于存放数组,这个空间有存放位置,假设该数组的起始位置为0X0078,即地址值。数组定义了长度,所以会分为三个小区域。如图:


再然后,这个地址值会赋给栈中的x,因此x指向了该数组。如图:



(2)

int[]x=newint[3];
      int[]y=x;
      y[1]=89;
     x=null;

     首先,执行第一行代码,定义了一个长度为3的数组。

     然后执行第二行代码,在栈内存中开辟了一个空间存放y,将x的值赋给了y,即数组地址值赋给了y,于是,y也指向了该数组。如图:

然后执行第三行代码,堆里的实体都有默认初始化值,该数组的初始化值都是0.当执行代码时x[1]变成了89。当执行第四行代码时,x指向空,即x不再指向该数组。此时,该数组还没有变成垃圾,因为变量y还指向该数组。假如,还有一行代码为y=null,那么该数组彻底没有被引用了,就变成了垃圾,会被Java的垃圾回收机制不定时被清除,释放堆内存的空间。如图:




综上所述:

1,new出来的实体(数组和对象)在堆内存中,堆内存中存放的就是实体。

 2,堆内存中的每个实体都有一个存放位置,用地址标识数据存放的位置,数组存放时有一个起始位置,将这个值赋给x(x在栈中),此时x指向了该数组,或引用了该数组。

 3,堆内存中的实体是用于封装数据的,而堆内存中的实体中的数据都有默认初始化值,如:int—0,double—0.0,boolean—false。

 4,若不想x指向这个数组,那就用x=null。只有引用数据类型才能用null.

5,int[]x=newint[3];

      System.out.println(x);

                      这个代码的运行结果是[I@60e128([代表一维数组,I代表int类型,60e128代表内存地址)

 

数组的操作

   1、获取最值(通常用到遍历)

int[]x={99,2,-1,0,34,3,87};
		int max=x[0];//max是数组中的数值
		for(int i=1;i<x.length;i++)//遍历
		{if(max<x[i])
			max=x[i];
		}
        System.out.println(max);
//或者:
int[]x={99,2,-1,0,34,3,87};
		int max=0;//max是角标
		for(int i=1;i<x.length;i++)
		{if(x[max]<x[i])
			max=i;
		}
        System.out.println(x[max]);

2、排序

   选择排序:选择一个固定的位置跟其他位置比



就是先拿0角标位跟其他位置比较换位,再是1角标位跟1之后的角标位比较换位,再是2角标位跟2之后的角标位比较换位。。。依次下去。。。

for(int i=0;i<x.length-1;i++)
	{for(int j=i+1;j<x.length;j++)
		{if(x[i]>x[j])
		{//换位;
		}}}

冒泡排序:相邻的两个元素进行比较,符合条件就换位


0角标和1角标比;1和2比;2和3比。。这就这样循环,每次都减少一次比较

for(int i=0;i<x.length-1;i++)
	{for(int j=0;j<x.length-1-i;j++)
		{if(x[j]>x[j+1])
		{//换位;
		}}}

选择排序特点:内循环结束一次,最值出现在0角标位

冒泡排序特点:内循环结束一次,最值出现在末角标位

排序中换位功能代码抽取:

public staticvoidchenge(int[]arr,inta,intb)
    {int temp=arr[a];
     arr[a]=arr[b];
     arr[b]=temp;}
因为数组在堆内存中,所以置换位置肯定要置换堆内存中的元素。栈内存中的置换对数组不起作用。

3,折半查找:能提高效率,但必须是有序数组

//法一:
public static int halfSearch(int[] arr,int key)
	{
		int min,max,mid;
		min = 0;
		max = arr.length-1;
		mid = (max+min)/2;
while(arr[mid]!=key)
		{if(key>arr[mid])
			    min = mid + 1;
			else if(key<arr[mid])
				max = mid - 1;
	if(min>max)
				return -1;
			mid = (max+min)/2;
		}
		return mid;
	}
//法二:
public static int halfSearch_2(int[] arr,int key)
	{int min = 0,max = arr.length-1,mid;
while(min<=max)
		{mid = (max+min)>>1;
if(key>arr[mid])
				min = mid + 1;
			else if(key<arr[mid])
				max = mid - 1;
			else
				return mid;
		}return -1;
	}

//将一个元素插入到一个有序数组中,求插入位置
public static int getIndex_2(int[] arr,int key)
	{int min = 0,max = arr.length-1,mid;
while(min<=max)
		{mid = (max+min)>>1;
if(key>arr[mid])
				min = mid + 1;
			else if(key<arr[mid])
				max = mid - 1;
			else
				return mid;
		}
		return min;

二维数组

格式1:int[][] arr = new int[3][2];

定义了名称为arr的二维数组,二维数组中有3个一维数组,每一个一维数组中有2个元素,一维数组的名称分别为arr[0], arr[1], arr[2],给第一个一维数组1脚标位赋值为78写法是:arr[0][1] =78;

格式2:int[][] arr = new int[3][];

二维数组中有3个一维数组,每个一维数组都是默认初始化值null,可以对这个三个一维数组分别进行初始化

arr[0] = new int[3];
arr[1] = new int[1];
arr[2] = new int[2];

格式3:int[][] arr= {{3,8,2},{2,7},{9,0,1,6}};

定义一个名称为arr的二维数组,二维数组中的有三个一维数组,每一个一维数组中具体元素也都已初始化

第一个一维数组arr[0] = {3,8,2};

第二个一维数组arr[1] = {2,7};

第三个一维数组arr[2] = {9,0,1,6};

第三个一维数组的长度表示方式:arr[2].length;

 Java中多维数组的声明和初始化应按照从高维到地维的顺序进行。

 

int[][] arr =newint[3][2];
System.out.println(arr);
System.out.println(arr[0]);//结果为[[I@60e128 [I@5e1077(一个二维和一个一维)


二维数组内存:

int[][] arr = new int[3][];
arr[0] = new int[3];
arr[1] = new int[1];
arr[2] = new int[2];

当运行第一行代码时,可以认为是数据类型为一维数组的一维数组。在栈内存中开辟了一个空间,用来存储变量arr,在堆内存中开辟了一个空间,用来存储数组,因为没有初始化所以默认初始化为null。数组的地址值赋给arr,arr指向该数组,如图:


当执行到第二行代码时,会在堆内存中再开辟一个空间,分为3个区域,默认初始化值为0,并将首地址值赋给二维数组中的第一个数组[0],数组中第一个引用就指向了这个长度为3的数组。第三、四行代码同理。如图:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值