对象数组
1.数组的定义:
数组是用来存储一组相同数据类型的数据,使用统一的名称来管理它,每一个元素使用编号进行区分,这个编号称为下标,每一个数据称呼为元素,元素的总个数称为数组的长度
2.数组元素的数据类型:
(1)基本数据类型:例如:int[]
(2)引用数据类型:例如:String[],Student[],Circle[],如果元素是引用数据类型,那么我们称为对象数组。因为每一个元素存储的是对象
3.数组可以分为:
(1)一维数组
(2)二维数组
二维数组可以堪称元素类型是以为数组的以为数组,例如int[][],可以看成元素是int[]的一维数组。
(3)三维数组等,理论上是可以的,但是几乎没有用过。
4.如何声明对象数组?
元素的数据类型[] 数组名;
5.对象数组的初始化
(1)静态初始化
元素的数据类型[] 数组名 = {........};
(2)动态初始化
数组名 = new 元素的数据类型[长度];
动态初始化后,元素还未赋值,此时还是默认值,引用数据类型默认是null。
//静态初始化
String[] strings = {"hello","java"};
Student[] students = {stu1,stu2,...};
//动态初始化
String[] strs = new String[5];
Student[] stus = new Student[5];
6.数组的使用
(1)获取数组的长度
数组名.length;
(2)获取某个元素的方式
数组名[下标];
//下标的范围[0,数组名.length-1];
//如果超过下标范围会报ArrayIndexOutOfBoundsException数组下标越界
(3)元素的赋值
数组名[下标] = 对象;
(4)遍历
for(int i = 0;i < strings.length;i++){
System.out.println(strings[i]);
}
7.通过对象数组的元素,访问对象的成员
public class TestPlus {
public static void main(String[] args) {
//声明并创建一个长度为5的矩形对象数组
Rectangle[] array = new Rectangle[5];
//创建5个矩形对象
/*array[0] = new Rectangle();
array[1] = new Rectangle();
...
*/
for (int i = 0; i < array.length; i++) {
array[i] = new Rectangle();
}
//为矩形对象的成员赋值
//5个矩形对象的长分别是10,20,30,40,50
//5个矩形对象的宽分别是5,15,25,35,45
//array[0]为什么可以.length?
// 因为array[0]是一个矩形类型的变量,对象,它能.出什么,看它类型
//array[0]现在是Rectangle类型,可以.出Rectangle中声明的成员。
// array[0].length = 10;
// array[0].width = 5;
for (int i=0; i<array.length; i++){
array[i].length = (i+1)*10;
array[i].width = (2*i+1)*5;
}
//遍历输出结果
for(int i=0; i<array.length; i++){
//System.out.println("长:" + array[i].length + ",宽:" + array[i].width +",面积:" + array[i].area() +",周长:" + array[i].perimeter());
System.out.println(array[i].getInfo());
}
}
}
class Rectangle{//矩形
double length;
double width;
public double area(){//面积
return length * width;
}
public double perimeter(){//周长
return 2 * (length + width);
}
public String getInfo(){
return "长:" + length + ",宽:" + width + ",面积:" + area() +",周长:" + perimeter();
}
}
8.对象数组的内存分析
![对象数组内存分析](F:\Typora File by Myself\对象数组内存分析.png)
封装
1.为什么要进行封装?
(1)考虑数据的安全性;
(2)隐藏细节;
(3)方便;
2.如何实现封装?(狭义,可见性范围的限制)
可以给属性加修饰符,例如:private
private:私有的,表示仅限于本类中使用
可见性修饰符:
本类 | 本包的其他类中 | 其他包的子类 | 其他包的非子类 | |
---|---|---|---|---|
private | 可见 | 不可见 | 不可见 | 不可见 |
default(缺省) | 可见 | 可见 | 不可见 | 不可见 |
protected | 可见 | 可见 | 可见 | 不可见 |
public | 可见 | 可见 | 可见 | 可见(同一个工程任意位置可见) |
对于类的成员(成员变量、成员方法等)来说,四种private,default(缺省),protected,public,但是对于外部的类来说,只能使用default(缺省)和public。
3.如果属性私有化,那么怎么对外提供方法来操作/访问它?
实际开发中,习惯上,属性(成员变量)都是私有化。然后提供get/set方法来访问它。
(1)set方法:用于给成员变量赋值的
//标准格式:
public void setXxx(数据类型 参数名){
成员变量 = 参数名;
}
(2)get方法:用于获取成员变量的值
//标准格式:public 数据类型 getXxx(){ return 成员变量;}
注意:
(1)set/get 方法名有标准,set/get单词 + 成员变量名(并且把成员变量首字母大写)
(2)对于get方法,如果成员变量是boolean类型,一般把get换成is
(3)开发中,get/set方法可以由idea生成,快捷键Alt + Insert(有的电脑可能需要同时按下Fn)
4.this的一个用法
当成员变量与方法的局部变量(例如:形参)同名时,可以在成员变量前面加this来区别。
为什么我们会出现局部变量(例如:形参)与成员变量同名呢?
因为变量是标识符,标识符有一个命名规范,见名知意。
例如public void setRadius(double radius)方法的形参的作用,就是给radius半径赋值,因此使用radius再好不过了。
5.当静态变量对应的set方法中出现了,局部变量与静态变量同名时,需要使用”类名.变量名“来进行区分,此时不能使用this来区分。
成员变量分两种:静态变量和实例变量。
为什么静态方法中不允许出现this?
因为我们调用静态方法,通常(也建议)使用”类名.“来使用
而this本质上指代的是当前对象,也就是”this.变量名“相当于”对象.变量名“。
return总结:
1.用法有两种:
(1)return 返回值; //仅用在方法的返回值不是void的方法体中
(2)return ; //仅用在方法的返回值是void的方法体中。
2.意义
(1)return 返回值; //表示返回结果并结束
(2)return ;//表示不返回结果,只是结束当前循环
3.注意:
(1)如果方法有返回值,即返回值类型不是void,那么方法体中必须有return 返回值; 而且要求无论当前方法从哪个分支结束,都必须有一个return 返回值;语句
(2)如果方法没有返回值,即返回值类型是void,那么方法体中return ;语句是可选的。
构造器
1.什么是构造器?
从名字来看,它是用来构造xxx的结构,它是类用来构造对象的结构。
在new后边调用的就是这个类的构造器。
作用:
(1)创建对象
(2)在创建对象时的成员变量初始化。
2.长什么样?如何自己定义/声明构造器?
【修饰符】 class 类名{//和一般的方法很像,但是它是没有返回值的,且构造器名和类名一致 【修饰符】 构造器名(){//无参的构造器} 【修饰符】 构造器名(形参列表){//有参的构造器}}
构造器与方法长得很像,又把构造器称为构造方法。
3.特点
(1)如果一个类没有声明任何构造器,那么编译器将会给这个类添加一个默认的无参(没有形参)构造方法。
(2)构造器的名称,必须与类名完全一致。
(3)构造器没有返回值类型,也不要写void,如果写上了,它就变成一个普通的方法。
(4)构造器是可以进行重载的。
构造器的形式越多,创建对象方式的可选性越多。
(5)如果一个类声明了构造器,那么编译器就不会给他添加默认的无参构造了。
(6)构造器的修饰符:只能是private,缺省,protected,public(权限修饰符),其他的都不可以使用(比如说static、final)。
(7)如果一个类没有声明构造器,会自动添加一个无参构造器,这个构造器的修饰符默认与class前的修饰符一致。
(8)子类不会继承父类的构造器,但是必须在子类构造器的首行调用父类的构造器。
默认调用的时父类的无参构造,也可以使用super();表示调用父类的无参构造器。
如果父类没有无参构造,那么在子类构造器中要指明调用的是父类的哪一个有参构造器。
4.idea生成构造器的快捷键:Alt+Insert
继承
1.什么是继承?为什么要继承?
(1)在编程中需要复用代码,需要继承原来一些类。
(2)表示类与类之间的关系,is a的关系
(3)对原来的类进行”扩展“。
2.如何实现继承?
extend关键字
子类:继承别人的类叫做子类,也称为派生类,SubClass
父类:被继承的类叫做父类,也称为基类,超类 ,SuperClass
【修饰符】 class 子类 extends 父类{}
3.继承的特点
(1)Java只支持单继承,每一个子类都只能有一个直接父类。
(2)Java支持多层继承,父类的父类也是父类
(3)当然,一个Java的父类可以同时有多个子类。
(4)子类继承父类时不会继承父类的构造器,但是在子类的构造器中一定会”调用“父类的构造器。默认情况下,调用父类的无参构造器。如果父类没有无参构造器,那么需要使用super(...)调用父类的有参构造器。
父类的构造器是创建父类对象用的,那么不能继承到子类中。但是父类的成员变量会继承到子类中,在创建子类对象时,需要借助父类的构造器为这些成员变量初始化。
(5)子类会继承构造器以外的其他成员,比如成员变量、成员方法。但是,如果成员变量、成员方法的修饰符是私有的,那么在子类中不能直接使用,需要间接使用。如果成员变量、成员方法的修饰符是缺省的,那么跨包的子类中也不能直接使用。
(6)父类的静态变量和静态方法可以被继承到子类中,即可以通过子类的对象访问到该静态变量,但是静态方法不能被子类重写。
4.继承的特点之成员方法
(1)方法的重写(override)
当子类继承了父类的成员方法后,如果父类的方法体实现不适合子类,那么子类可以选择重写。
(2)方法的重写有要求
①方法名必须相同
②形参列表必须相同
③返回值类型:
Ⅰ:父类方法的返回值类型是void和基本数据类型,那么子类方法必须与父类相同。
Ⅱ:父类方法的返回值类型是引用数据类型,那么子类方法的返回值类型可以是这个类,或者这个类的子类。
④权限修饰符:
Ⅰ:如果父类的方法的权限修饰符是private,那么子类是无法进行重写的,
如果父类是其他包的,并且方法的修饰符是缺省,那么子类也是无法进行重写的。
Ⅱ:其他情况下,重写方法的权限修饰符 可以大于等于被重写方法的权限修饰符
本包中,父类的方法的修饰符是缺省的,子类的重写方法的修饰符可以是缺省的,protected,public 其他包中,父类的方法的修饰符是protected,子类的重写方法的修饰符可以是protected,public 其他包中,父类的方法的修饰符是public,子类的重写方法的修饰符可以是public
⑤其他修饰符
父类的static,final方法是不能重写的
(3)抛出异常时的要求
①如果被重写方法没有throws编译时异常,那么重写方法时,就不能throws编译时异常
②如果被重写方法throws编译时异常,那么重写方法时,只能throws该异常类型或该异常类型的子类。<=
③如果被重写方法throws运行时异常,子类重写时,可以一样,可以不写。(无关)
④如果被重写方法没有throws运行时异常,子类重写时,可以一样,可以throws自己的运行时异常。(无关)
this和super
this关键字
1.this单词的意思:当前对象
2.this可以出现在哪里?
(1)构造器中:this表示正在new的对象。
(2)非静态方法中:this表示调用这个方法的对象。
(3)非静态代码块中
3.this不能出现在?
(1)静态方法中
(2)静态代码块中
因为这两个位置都没有对象
4.使用形式有三种
(1)this.成员变量
当成员变量与局部变量同名时,可以使用this.表示成员变量。
(2)this.成员方法
没有必须用的情况。
如果用的话,表示调用当前对象的xx方法。
如果不用this的话,一般这个方法是本类声明的,如果在本类中没有找到,会找从父类继承的可见的成员方法。
(不用this时,默认先找本类,在找父类)。
(3)this()或this(实参列表)//这里是没有点.的
this():表示调用本类的无参构造;
this(实参列表):表示调用本类的有参构造;
this()或this(实参列表)必须在构造器的首行,这两个只能使用其中一个。
例如:无论通过哪一个构造器,我都希望它能打印一句”hello“
super关键字
1.super单词的意思:表示父类的
2.可以出现在哪里?
(1)构造器中:super表示调用父类的xx。
(2)非静态方法中:super表示调用父类xx。
(3)非静态代码块中
3.super不能出现在?
(1)静态方法中
(2)静态代码块中
因为这两个位置都没有对象
this和super这两个关键字和静态无缘,即都不能出现在静态的xx结构中。
3.使用前提:super要引用到父类的xx(xx可以是父类的成员变量、成员方法、构造器),xx必须在子类是可见的。
4.使用形式
(1)super.成员变量
当子类声明了与父类同名的成员变量时,可以使用super.来区分父类成员变量和子类成员变量。
但是!在开发过程中,不要在子类中声明与父类同名的变量,会降低程序可读性。
(2)super.成员方法(重要)
当子类,重写了父类的方法时,又想要在子类中访问父类的这个方法时,可以使用super。
(3)super()或super(实参列表)
super():表示调用直接父类的无参构造,完全可以省略这句话,因为不写,默认也是找父类的无参构造。
super(实参列表):表示调用直接父类的有参构造函数。
super()或super(实参列表)也必须在构造器首行。
注意:
this()或this(实参列表)只在本类找,如果本类没有找到对应的就报错了。
super()或super(实参列表)只在父类找。父类找不到就报错了。
重写和重载
重载:发生在同一个类中,出现了方法名相同,形参列表不同的多个方法,和返回值类型无关。
重写:是子类对继承的父类的方法进行重写,
要求:方法名相同,形参列表,返回值类型(基本数据类型和void:相同,引用数据类型:小于等于),权限修饰符(大于等于,被重写的方法不能是private,跨包不能是缺省),其他修饰符(不能是final和static)