Object类的toString方法
概述
Object类是所有类的祖宗类,它提供的方法是所有类都适用的,我们可以通过看它的源码来得知有什么方法。
其中的大部分都是以";"结尾的,中间带有native关键字的方法,表示的是底层调用C++写的dll程序(了解)。
其中有两个方法:`equals()`和`toString()`是可以调用的,这里重点了解`toString()`。
toString()方法
public static toString(){
return getClass().getName() + "@" + Integer.toHexString(hashCode);
}
这是一个实例方法,需要先创建对象再调用方法,得到的是`类名@对象在堆内存里的内存地址`。
这个地址是内存地址通过哈希算法得出的十六进制结果,了解就好~
但其实,直接输出引用对象,出来的地址也是这个显示格式,因为它默认调用了`toString()`方法。
覆盖toString()方法
toString()
是将对象转换为字符串,Java给定的默认方法在部分情况的调用是不尽如人意的,就比如说要输出年月日:
public class MyDate {
private int year;
private int month;
private int day;
public MyDate(){
this(2023,1,21);
}
public MyDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
}
public class test02 {
public static void main(String[] args) {
MyDate myDate = new MyDate();
System.out.println(myDate);
}
}
这个结果很明显不是我们想要的,我们希望的是它能直接输出日期,这时候就需要对该方法进行方法重写。
public String toString(){
return this.year+"年" +this.month+"月"+this.day+"日";
}
这样子就可以实现输出年月日了。
当然,实际开发中还存在着各种各样的需求,此时我们应该根据需求去对已有方法进行覆盖,使它服务于需求。
其实不覆盖也可以,但是由于多态的存在,使方法覆盖和多态联系在一起,所以说最好习惯方法覆盖
内部类
概述
定义:在一个类的内部定义的类,称为内部类。
分类:
1. 实例内部类:类似于实例变量。
2. 局部内部类: 类似于局部变量。
3. 静态内部类:类似于静态变量。
4. 匿名内部类: 内部类的一种。
使用内部类编写的代码可读性很差,实际开发中很少用,在这里只重点学习匿名内部类,便于之后能看懂这类代码。
匿名内部类
定义: 这个类没有名字,故称为匿名内部类。
public class MyMath {
public void mySum(Computer c ,int x,int y){
int retValue = c.sum(x,y);
System.out.println(x+"+"+y+"="+retValue);
}
}
interface Computer {
int sum(int a,int b);
}
public class classDemo {
public static void main(String[] args) {
MyMath mm = new MyMath();
mm.mySum(new Computer(),100,200);
}
}
很明显,对于这个接口,是不能直接创建一个对象去传入mySum方法中,需要创建一个实现类:
public class ComputerImpl implements Computer{
public int sum(int a,int b){
return a+b;
}
}
但是,我们可以通过匿名内部类来实现这个接口,这样的类是没有名字的!
public class classDemo {
public static void main(String[] args) {
MyMath mm = new MyMath();
mm.mySum(new Computer(){
public int sum(int a,int b){
return a+b;
}
},100,200);
}
}
这里表面上看好像是接口可以被创建对象了,实则不然,后面的`大括号{}`代表了对接口的实现!!!
不建议使用匿名内部类,因为这个类没有名字,不能重复使用,并且这么写太乱,可读性太差!
数组
之前学过数组,这里是接着之前的内容学的,跳过了前面的一维数组的基础知识
一维数组的扩容
在Java开发中,数组确定就无法改变,但是可以通过扩容来实现增长数组长度满足需求。
实质:重新创建一个新的更大的数组,将原有数组拷贝过去。
数组扩容效率较低,涉及数据拷贝问题,在以后的开发时候注意:尽可能少的进行数据扩容,在创建数组对象的时候就要估计数组的长度,避免进行数组扩容。
一维数组的数据拷贝
Java提供了一个用于数组拷贝的方法:System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
这里面五个参数从左往右分别代表:拷贝源,拷贝源起始下标,目标,目标起始下标,拷贝的数组长度。
基本数据类型和引用数据类型都是可以拷贝的~
二维数组
概述
二维数组其实是一个特殊的一维数组,特殊在这个一维数组中的每一个元素都是一个一维数组。
二位数组的静态初始化:int[][] array ={{1,2,3},{4,5},{6,7,8,9}};
三维数组就相当于是每个元素里都是一个二维数组。
二维数组的动态初始化:int[][] array = new[3][4]
length属性
一维数组有几个元素就长度就是多少,二维数组是有多少个一维数组,长度就是多少。与数组中的一维数组内的数据无关!
如果想要取得二维数组中的一维数组的长度,需要表明一维数组的下标(以上面静态初始化数组为例):我们想要取得第一个数组的长度,需要标下标:a[0].length
,其余类推即可。
元素访问&修改
案例:以上面静态初始化的二位数组为例,取出二维数组的第一个一维数组中的数据。
int[][] array ={{1,2,3},{4,5},{6,7,8,9}};
int[] a = array[0];//这是第一个一维数组!
int aa = a[0];//这是第一个一维数组里的第一个元素!
//也可以进行合并
int aa = array[0][0];
对于a[0][0]来说,前面两个是一个整体代表一维数组,之后再和后面的[0]结合为一个数组,代表着一维数组中的元素。
修改就是在访问二维数组的基础上进行一个赋值~
遍历
二维数组的遍历相比于一维数组的遍历,只需要多加一层循环,注意每一层循环的循环次数就可以了。
int[][] array ={{1,2,3},{4,5},{6,7,8,9}};
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
System.out.print(" "+array[i][j]);
}
System.out.println(" ");
}
动态初始化的二维数组的遍历也是一样的,只是给定了数组的长度,也可以通过直接方法得出数组的长度来实现,在没有赋予数据的时候默认值为0。
二维数组作为形参传递给方法
在传递的时候,只需要传递二维数组名就可以,如果不想新建一个变量,可以直接在传递的时候new一个数组,但是要保证该数组只使用一次!sum(new int[][] {{1,2,3},{4,5},{6,7,8,9}});
总的来说,Java的数组和C语言的数组差距不大,只有格式上的区别~
每日一练
案例: 使用一维数组,模拟栈数据结构
- 这个栈可以存储Java中任何引用数据类型的数据。
- 在栈中提供push方法模拟压栈(栈满了需要有信息提示)。
- 在栈中提供pop方法模拟弹栈(栈空了也要有信息提示)。
- 编写测试程序,new栈对象,调用push、pop方法来模拟。
- 栈的初始化内存为10。
public class test {
public static void main(String[] args) {
MyStack stack = new MyStack();
//压栈
for (int i = 0; i <11; i++) {
stack.push(new Object());
}
//弹栈
for (int i = 0; i <11; i++) {
stack.pop();
}
}
}
public class MyStack {
private Object[] elements;
//栈帧
private int index = 0;
public MyStack(Object[] elements) {
this.elements = elements;
}
public MyStack(){
//默认栈初始化容量是10
this.elements = new Object[10];
this.index = -1;
}
public void push(Object obj){
if(this.index>=this.elements.length-1){
System.out.println("压栈失败,栈已满!!!");
return;
}
this.index++;
this.elements[index]=obj;
System.out.println("元素"+obj+"压栈成功,栈帧指向"+index);
}
public void pop(){
if(index<0){
System.out.println("弹栈失败,栈已空!!!");
return;
}
System.out.print(elements[index]+"弹栈成功!!!");
index--;
System.out.println("栈帧指向"+index);
}
}