我们先简单回忆一下之前的一维数组:
一维数组也是一个引用变量。在Java中,数组属于引用数据类型,它们的变量存储的是数组对象的引用,而不是数组本身的值。
当我们声明一个一维数组时,实际上是在内存中开辟了一段连续的存储空间,用于存储数组元素的值。而数组变量本身存储的是指向该存储空间的引用,也就是数组对象的内存地址。
二维数组的定义
public static void main4(String[] args) {
//int[][] array1 = {1,2,3,4,5,6}; 这样写是不被允许的
int[][] array1 = {{1,2,3},{4,5,6}};
//int[2][3] array1 = {{1,2,3},{4,5,6}}; 这样写也是不被允许的
int[][] array2 = new int[][]{{1,2,3},{4,5,6}};
int[][] array3 = new int[2][3];//0
}
二维数组的打印
怎么遍历二维数组?
public static void main5(String[] args) {
int[][] array1 = {{1,2,3},{4,5,6}};
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
System.out.print(array1[i][j]+" ");
}
System.out.println();
}
}
可是,当行和列很多的时候,我们怎么确定它们的数量呢?靠数数吗?肯定是不行的。
二维数组是特殊的一维数组,
这样写:
System.out.println(array1[0]);
System.out.println(array1[1]);
这个时候应该输出的是地址:
那这样呢,是不是会把array1[0]和array1[1]的数组打印出来:
System.out.println(Arrays.toString(array1[0]));
System.out.println(Arrays.toString(array1[1]));
那长度呢?
System.out.println("==========");
System.out.println(array1[0].length);
System.out.println(array1[1].length);
System.out.println("==========");
System.out.println(array1.length);
结果都一一验证了我们的猜想。
所以我们可以这样写:
public static void main6(String[] args) {
int[][] array1 = {{1, 2, 3}, {4, 5, 6}};
for (int i = 0; i < array1.length; i++) {
for (int j = 0; j < array1[i].length; j++) {
System.out.print(array1[i][j] + " ");
}
System.out.println();
}
}
如果使用 System.out.println((array1)) 来打印二维数组,输出的是数组的地址,因为这里的 array1 是一个引用类型,它指向二维数组的内存地址。而且,如果使用 Arrays.toString() 来打印二维数组,也只会输出二维数组的地址。
那既然用
System.out.println(Arrays.toString(array1));
打印的是地址,怎么一次性地打印二维数组呢?
用深度打印:
public static void main(String[] args) {
int[][] array1 = {{1, 2, 3}, {4, 5, 6}};
System.out.println(Arrays.deepToString(array1));
}
因为 deepToString() 方法可以处理多维数组,而 toString() 方法只能处理一维数组。
不规则的二维数组
public static void main8(String[] args) {
//不规则的二维数组
int[][] array3 = new int[2][];
array3[0] = new int[]{1,2,3};
array3[1] = new int[]{4,5,6,7,8,9};
System.out.println(Arrays.deepToString(array3));
}
即省略列数,可以让某一行的长度是不规则的。
那么如果这样打印,会怎么样?
public static void main(String[] args) {
//不规则的二维数组
int[][] array3 = new int[2][];
/* array3[0] = new int[]{1,2,3};
array3[1] = new int[]{4,5,6,7,8,9};*/
System.out.println(Arrays.deepToString(array3));
}
或者这样:
public static void main(String[] args) {
//不规则的二维数组
int[][] array1 = new int[2][];
/*array3[0] = new int[]{1,2,3};
array3[1] = new int[]{4,5,6,7,8,9};*/
//System.out.println(Arrays.deepToString(array3));
for (int i = 0; i < array1.length; i++) {
for (int j = 0; j < array1[i].length; j++) {
System.out.print(array1[i][j]+" ");
}
System.out.println();
}
}
出现了一个空指针异常:
作为函数的参数:
1、参数传的是基本数据类型时,在方法中修改形参的值,不影响实参的值;
2、参数传数组类型(引用数据类型):在方法内部修改数组的内容,方法外部的数组内容也会发生改变。因为数组是引用类型,按照引用类型来进行传递,是可以修改其中存放的内容的。
总结:所谓的“引用“本质上只是存了一个地址,Java 将数组设定成引用类型,这样的话后续进行数组参数传参,其实只是将数组的地址传入到函数形参中,这样可以避免对整个数组的拷贝(数组可能比较长,那么拷贝开销就会很大)。
作为函数的返回值:
比如:获取斐波那契数列的前N项
public class TestArray {
public static int[] fib(int n){
if(n <= 0){
return null;
}
int[] array = new int[n];
array[0] = array[1] = 1;
for(int i = 2; i < n; ++i){
array[i] = array[i-1] + array[i-2];
}
return array;
}
类
注意事项:
1.一般一个文件当中只定义一个类
这样可以重命名一个类:
这样可以直接同时修改类的名字和文件名。但是!这只适用于一个文件一个类的情况!!!
这样是不行的。
2. main方法是程序的入口,它所在的类一般要使用public修饰(注意: Eipse默认会在public修饰的类中找main方法)
如上,每个类都可以有一个程序入口,它的左侧都有一个绿色三角,都可以run;
3.public修饰的类必须要和文件名相同(每个文件一个public)
4.不要轻易去修改public修饰的类的名称,如果要修改,通过开发工具修改。
public class Test {
public static void main(String[] args) {
System.out.println("1234");
//通过new关键字 实例化了一个Dog对象!
Dog dog = new Dog();
//dog就是一个引用 指向了Dog对象
dog.name = "初一";
dog.age = 10;
dog.color = "黄色";
System.out.println(dog.name);
System.out.println(dog.age);
System.out.println(dog.color);
dog.eat();
dog.bark();
System.out.println("===========");
Dog dog2 = new Dog();
//dog就是一个引用 指向了Dog对象
dog2.name = "初二";
dog2.age = 12;
dog2.color = "黄色2";
System.out.println(dog2.name);
System.out.println(dog2.age);
System.out.println(dog2.color);
dog2.eat();
dog2.bark();
}
}
class Dog {
public String name;
public int age;
public String color;
public void eat() {
System.out.println("吃饭!");
}
public void bark() {
System.out.println("汪汪叫!");
}
public static void main(String[] args) {
System.out.println("fdsafasad");
}
}
一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量。换句话说,就是实例化出的对象才可以实际存储数据、占用物理空间。
public class Date {
public int year;
public int month;
public int day;
public void setDate(int y,int m,int d) {
year = y;
month = m;
day = d;
}
public void printDate() {
System.out.println("年:"+ year+" 月:" +month+" 日:"+day);
}
public static void main(String[] args) {
Date date = new Date();
date.setDate(2008,8,8);
date.printDate();
}
}
这样是没有问题的,改一下:
public class Date {
public int year;
public int month;
public int day;
public void setDate(int year,int month,int day) {
year = year;
month = month;
day = day;
}
public void printDate() {
System.out.println("年:"+ year+" 月:" +month+" 日:"+day);
}
public static void main(String[] args) {
Date date = new Date();
date.setDate(2008,8,8);
date.printDate();
}
}
这样就出问题了,一打印,结果全是0,相当于局部变量自己给自己赋值,局部变量优先。
这个时候,要么别同名,要么+this
this引用的特性
1.this的类型;对应类类型引用,即哪个对象调用就是哪个对象的引用类型;
2this只能在”成员方法”中使用;
3.在“成员方法”中,this只能引用当前对象,不能再引用其他对象;
4.this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责调用成员方法;
对象的引用传递给该成员方法,this负责来接收。
//代表当前对象的引用,建议大家习惯使用 this 谁调用了当前的set方法 谁就是this
public void setDate(/*Date this,*/int year,int month,int day) {
this.year = year;
this.month = month;
this.day = day;
}
public void printDate() {
System.out.println("年:"+ year+" 月:" +month+" 日:"+day);
}
那现在,我们增加一个对象,this该如何抉择?
public static void main(String[] args) {
Date date = new Date();
date.setDate(2008,8,8);
date.printDate();
System.out.println("============");
Date date2 = new Date();
//setDate方法里面的this 就是谁调用过了这个方法
date2.setDate(2009,9,9);
date2.printDate();
}
不用担心!谁调用了当前的方法,谁就是this!
也就是说,其实下面的方法中都有一个隐藏的参数“ Date this ” :
public void setDate(/*Date this,*/int year,int month,int day) {
this.year = year;
this.month = month;
this.day = day;
}
public void printDate(Date this) {
System.out.println("年:"+ this.year+" 月:" +this.month+" 日:"+this.day);
}