第三天:
1、 引用类型数组:
int[] arr = new arr[3]; //基本类型数组
double[] ds = new double[10]; Student[] stus = new Student[3]; //引用类型数组
//Student 首字母大写了,为类,类也是一种数据类型(引用类型)
Airplane[] as = new Airplane[45];
基本类型数组内存图:
引用类型数组内存图:注意:是引用类型stus里装的是地址,不是栈 中装的是地址
1) Student[] stus = new Student[3]; //创建Student数组对象
stus[0] = new Student("zhangsan",25,"LF"); //创建Student对象
stus[1] = new Student("lisi",26,"JMS");
stus[2] = new Student("wangwu",28,"SD");
System.out.println(stus[0].address); //输出第1个学生的地址
System.out.println(stus[0].name); //输出第1个学生的名字
stus[1].age = 28; //修改第2个学生的年龄为28
stus[2].sayHi(); //第3个学生跟大家问好
for(int i=0;i<stus.length;i++){ //遍历所有学生
System.out.println(stus[i].name); //输出每个学生的名字
stus[i].sayHi(); //每个学生跟大家问好
}
2) Student[] stus = new Student[]{ //{}大括号直接赋值
new Student("zhangsan",25,"LF"),
new Student("lisi",26,"JMS"),
new Student("wangwu",28,"SD")
}; //1) 2)代码效果是一样的
int[] arr = new int[]{2,5,8}
int[] arr = new int[]{
2,
5,
8
};
--------------------------------------------------------------------
3) int[][] arr = new int[3][]; -----------数组的数组
arr[0] = new int[2];
arr[1] = new int[3];
arr[2] = new int[2];
arr[1][0] = 100;
4) int[][] arr = new int[3][4]; //3行4列 -----------数组的数组
for(int i=0;i<arr.length;i++){ 3为arr的长度,4为arr中每个元素的长度
for(int j=0;j<arr[i].length;j++){
arr[i][j] = 100; //给每个元素赋值为100
}
}
区别:
① int[] arr = new int[3]; //1)声明整型数组arr,包含3个元素
2)每个元素都是int型,默认值为0
int型数组为基本类型
Student[] stus = new Student[3]; //1)声明Student型数组stus,包含3个元素
2)每个元素都是Student型,默认值为null
Student型数组为引用类型
Student 首字母大写了,为类,类也是一种数据类型(引用类型)
② 赋值:
int[] arr = new int[3];
arr[0] = 100; //基本类型直接赋值
System.out.println(arr[0]); //100 基本类型 直接输出一个数
Student[] stus = new Student[3]; //创建Student数组对象
stus[0] = new Student("zhangsan",25,"LF"); //创建Student对象
stus[1] = new Student("lisi",26,"JMS"),
//引用类型赋值要new,[]前面是谁就new谁,调构造方法
stus[0]是Student类型,Student型数组为引用类型
System.out.println(stus[0]); //引用类型 输出的是 地址
//所以想访问引用类型数组里的元素 打.访问 stus[0].address
---------------------------------------------------------------------
③ int [] arr = new [3];
Student [] stus = new Student[3];
//[]前是数据类型
int[] [] arr = new int[3][]; //声明int[]型数组arr,包含3个元素,每个元素都是int[]型,默认值为null
//int[]型是引用类型 (因为是数组)
int[][] arr = new int[3][];
arr[0] = new int[2]; //arr里包含了3个元素,这三个元素都是数组,
//第一个元素里包含了两个元素,第二个元素里包含了3个元素…
arr[1] = new int[3];
arr[2] = new int[2];
//给arr中第2个元素中的第1个元素赋值为100
arr[1][0] = 100;
arr ---------------------int[][]型 二维数组
arr[0] ------------------int[]型 一维数组
arr[0][0] ---------------int型 元素
2、继承:泛化
1)作用:代码复用
2)通过extends来实现继承
3) 超类/父类:是派生类所共有的属性和行为
派生类/子类:是派生类所特有的属性和行为
4)派生类继承超类后,派生类可以访问:派生类的+超类的,而超类只能访问超类的
5) 一个超类可以有多个派生类,
一个派生类只能有一个超类---------单一继承
6)继承具有传递性
7) java规定:构造派生类之前必须先构造超类
7.1)在派生类的构造方法中,若自己没有调用超类构造方法,
----则默认super() 来调用超类的 无参构造方法
7.2)在派生类的构造方法中,若自己调用了超类的构造方法,
----则不再默认提供
package oo.day03;
//super的演示
public class SuperDemo {
public static void main(String[] args) {
Boo o = new Boo();
}
}
class Aoo{
Aoo(){
System.out.println("超类构造方法");
}
}
class Boo extends Aoo{
Boo(){
//super(); //默认的---调用超类的无参构造 (写不写 这句话都在)
System.out.println("派生类构造方法");
}
}
注意:super()调用超类(父类)构造方法必须 位于派生类(子类)构造方法的第一行
控制台输出:
先: 超类构造方法
后: 派生类构造方法
-----------------------------------------------------------------------
class Coo{
Coo(int a){ //超类的 有参构造
}
}
class Doo extends Coo{
Doo(){
super(5); //调用超类的有参构造
}
/*
//如下代码为默认的:(只不过 没显示出来)
Doo(){
super(); //调用超类的无参构造, 但是上面超类是有参构造
}
*/
}
派生类继承了超类的什么东西 ?
----继承的是 成员变量+方法,而不包括构造方法
----超类的构造方法不是被派生类继承的,而是被派生类通过super();来调用的
上面三个 重复的代码太多了,复用性差,把三个都有的放到Person类中
class Person{ //------------------------超类/父类
String name;
int age;
String address;
void eat(){}
void sleep(){}
}
class Student extends Person{-----------派生类/子类
String stuId;
void study(){}
}
class Teacher extends Person{-----------派生类/子类
double salary;
void teach(){}
}
class Doctor extends Person{------------派生类/子类
String level;
void cut(){}
}
Student zs = new Student();
zs.stuId/study();
zs.name/age/address/eat()/sleep();
Teacher ls = new Teacher();
ls.salary/teach();
ls.name/age/address/eat()/sleep();
Doctor ww = new Doctor();
ww.level/cut();
ww.name/age/address/eat()/sleep();
继承具有传递性: 继承---------代码 虽然我没有写,但也属于我
class Aoo{-----------------------a
int a;
}
class Boo extends Aoo{-----------b+a
int b;
}
class Coo extends Boo{-----------c+b+a
int c;
}
3、 super: 指代当前对象的超类对象 与this有点像,指代当前对象
super的用法:
1)super. 成员变量名-------------访问超类的成员变量
2)super. 方法名()---------------调用超类的方法(想在超类基础之上加东西时使用)
3)super()----------------------调用超类的构造方法
1)的举例: 一般super.省略
Hero里面 /** 构造方法 */
Hero(){ //this指的是派生类对象,super指的是超类对象
super.width = 97; //this. 也可以 第四条
super.height = 139;
super.x = 140;
super.y = 400;
this.life = 3;
this.fire = 0;
}
3)的举例: 与第七条有关
/** 构造方法 */
Hero(){
super(); //在调用超类的无参构造,不管写不写都在这,类似构造方法
width = 97;
height = 139;
x = 140;
y = 400;
life = 3;
fire = 0;
}
2)的举例:
class Aoo{
void show(){
System.out.println(111);
}
}
class Boo extends Aoo{
void show(){
super.show(); //调用超类的show方法---想在超类的基础之上做操作
System.out.println(222);
}
}
this:指代当前对象,哪个对象调用方法指的就是哪个对象
this的用法:
- this.成员变量名-----------访问成员变量
- this.方法名()-------------调用方法(一般不用)
- this()--------------------调用构造方法(应用率低)
练习:
1.创建Person类,包含:
1)成员变量:name,age,address
2)构造方法:Person(3个参数){ 赋值 }
3)方法:sayHi(){ 输出3个数据 }
2.创建学生类Student,继承Person,包含:
1)成员变量:学号stuId(String)
2)构造方法:Student(4个参数){ super调超类3参构造、赋值stuId }
3.创建老师类Teacher,继承Person,包含:
1)成员变量:工资salary(double)
2)构造方法:Teacher(4个参数){ super调超类3参构造、赋值salary }
4.创建医生类Doctor,继承Person,包含:
1)成员变量:职称level(String)
2)构造方法:Doctor(4个参数){ super调超类3参构造、赋值level }
5.创建测试类Test,main中:
1)创建学生数组stus,包含3个元素,给元素赋值,遍历输出名字并问好
2)创建老师数组tes,包含3个元素,给元素赋值,遍历输出名字并问好
3)创建医生数组docs,包含2个元素,给元素赋值,遍历输出名字并问好
package oo.day04;
//练习 把类分开写,这里写在一起 是为了方便看
public class Test {
public static void main(String[] args) {
Student[] stus = new Student[3];
stus[0] = new Student("aaa",25,"LF","111");
stus[1] = new Student("bbb",24,"JMS","222");
stus[2] = new Student("ccc",25,"SD","333");
for(int i=0;i<stus.length;i++){
System.out.println(stus[i].name);
stus[i].sayHi();
}
Teacher[] tes = new Teacher[3];
tes[0] = new Teacher("ddd",35,"LF",8000.0);
tes[1] = new Teacher("eee",44,"JMS",12000.0);
tes[2] = new Teacher("fff",55,"SD",22000.0);
for(int i=0;i<tes.length;i++){
System.out.println(tes[i].name);
tes[i].sayHi();
}
Doctor[] docs = new Doctor[2];
docs[0] = new Doctor("ggg",35,"SD","副主任医师");
docs[1] = new Doctor("hhh",54,"SX","主任医师");
for(int i=0;i<docs.length;i++){
System.out.println(docs[i].name);
docs[i].sayHi();
}
}
}
class Person{
String name;
int age;
String address;
Person(String name,int age,String address){
this.name = name;
this.age = age;
this.address = address;
}
void sayHi(){
System.out.println("大家好,我叫"+name+",今年"+age+"岁了,家住"+address);
}
}
class Student extends Person{
String stuId; //学号
Student(String name,int age,String address,String stuId){
super(name,age,address);
this.stuId = stuId;
}
}
class Teacher extends Person{
double salary; //工资
Teacher(String name,int age,String address,double salary){
super(name,age,address);
this.salary = salary;
}
}
class Doctor extends Person{
String level; //职称
Doctor(String name,int age,String address,String level){
super(name,age,address);
this.level = level;
}
}
第四天:
1、 向上造型: (应用率特别高)
1)超类型的引用指向派生类的对象
2)能点出来什么,看引用的类型--------这是规定,记住就OK
举例:
①
class Animal{ //动物
}
class Tiger extends Animal{ //老虎
}
继承要符合is a(是一个)的关系
//动物是动物 (一个动物对象是动物类型) 从后往前读
Animal o = new Animal();
//老虎是老虎 (一个老虎对象是老虎类型)
Tiger o = new Tiger();
//老虎是动物 (一个老虎对象是动物类型) 从后往前读,赋值也是
Animal o = new Tiger();
//动物是老虎----语义不通 (一个动物对象是老虎类型)
Tiger o = new Animal(); //编译错误
//老虎是动物
Animal o = new Tiger(); //向上造型 , 超类型的引用o指向派生类的对象
②
超类 派生类
Animal o = new Tiger();
o.只能点出Animal类中的
Person p1 = new Student();
Person p2 = new Teacher();
Person p3 = new Doctor();
p1/p2/p3.只能点出Person类中的
FlyingObject o1 = new Airplane();
FlyingObject o2 = new BigAirplane();
FlyingObject o3 = new Bee();
FlyingObject o4 = new Hero();
FlyingObject o5 = new Sky();
FlyingObject o6 = new Bullet(100,200);
o1/o2/o3/o4/o5/o6.只能点出FlyingObject类中的
---------------------------------------------------
package oo.day04;
//向上造型的演示
public class UploadDemo {
public static void main(String[] args) {
Aoo o1 = new Aoo();
o1.a=1;
o1.show();
//o1.b=2; //编译错误,超类不能访问派生类的
//o1.test();
Boo o2 = new Boo();
o2.b=10;
o2.test();
o2.a=11; //正确,派生类可以访问超类的
o2.show();
Aoo o3 = new Boo(); //向上造型
o3.a =2;
o3.show();
//o3.b=2; //编译错误,能点出来什么,看引用的类型
//o3.test();
}
}
昨天的 练习 代码,为什么for循环在重复?
-----因为将数据分装在了三个不同的数组中
package oo.day04;
//练习
public class Test {
public static void main(String[] args) {
Person[] ps = new Person[5]; //做一个Person的数组
ps[0] = new Student("zhangsan",25,"LF","111");
ps[1] = new Student("lisi",26,"JMS","222");
ps[2] = new Teacher("zhaoliu",45,"SX",8000.0);
ps[3] = new Teacher("sunqi",35,"LF",10000.0);
ps[4] = new Doctor("zhangba",25,"JMS","主治医师");
for(int i=0;i<ps.length;i++){
ps[i].sayHi();
}
//重写方法被调用时,看对象的类型 (举例:方法的重写 )
Student zs = new Student("zhangsan",25,"LF","111");
Person p = new Student("zhangsan",25,"LF","111");
zs.sayHi(); //调用的是Student的sayHi()
p.sayHi(); //调用的是Student的sayHi()
}
}
class Person{
String name;
int age;
String address;
Person(String name,int age,String address){
this.name = name;
this.age = age;
this.address = address;
}
void sayHi(){
System.out.println("大家好,我叫"+name+",今年"+age+"岁了,家住"+address);
}
}
class Student extends Person{
String stuId; //学号
Student(String name,int age,String address,String stuId){
super(name,age,address);
this.stuId = stuId;
}
void sayHi(){
System.out.println("大家好,我叫"+name+",今年"+age+"岁了,家住"+address+",学号为:"+stuId);
}
}
class Teacher extends Person{
double salary; //工资
Teacher(String name,int age,String address,double salary){
super(name,age,address);
this.salary = salary;
}
void sayHi(){
System.out.println("大家好,我叫"+name+",今年"+age+"岁了,家住"+address+",工资为:"+salary);
}
}
class Doctor extends Person{
String level; //职称
Doctor(String name,int age,String address,String level){
super(name,age,address);
this.level = level;
}
}
2、 方法的重写 (Override/Overriding):重新写、覆盖
1)发生在父子类中,方法名称相同,参数列表相同,方法体不同
2)重写方法被调用时,看对象的类型 ------- new出来的是对象,new谁调谁
为什么要重写?
觉得超类的方法不好,不能满足派生类的需求了,就重写
3)重写需遵循"两同两小一大"原则:-------了解即可,一般都是一模一样的
3.1)两同:
1)方法名称相同
2)参数列表相同
3.2)两小:
1) 派生类方法的返回值类型小于或等于超类方法的
3.2.1.1) void时,必须相等
3.2.1.2) 基本类型时,必须相等
3.2.1.3) 引用类型时,小于或等于
2) 派生类方法抛出的异常小于或等于超类方法的---------API时讲
3.3)一大:
1)派生类(子类)方法的访问权限大于或等于超类方法的访问权限
eg:
接口那里用到了:
接口的实现类 必须重写接口中的所有抽象方法,超类接口 已经是public 公开了(因为接口里默认访问权限是public),派生类什么都不写 就是小于超类方法的,要大于或等于,所以实现类重写接口中的抽象方法时必须写 public
抽象类:
如果是抽象类的子类 重写抽象方法,就不是必须写成public了,只要大于或等于就行
super. 方法名()---------------调用超类的方法(想在超类基础之上加东西时使用)
我继承了一个中餐馆:
1):我还是想做中餐---------------不用重写
2):我想改做西餐-----------------需要重写
3):我想在中餐之上加西餐---------需要重写(先super中餐,再加西餐)
class Aoo{
void show(){
中餐
}
}
// 3)号举例
class Boo extends Aoo{
void show(){
super.show(); //调上面的 中餐
西餐
}
}
// 2)号举例
class Boo extends Aoo{
void show(){
西餐
}
}
3、 重写与重载的区别:----------常见面试题
1)重写(Override):
1.1)发生在父子类中,方法名称相同,参数列表相同,方法体不同
2)重载(Overload):
2.1)发生在同一类中,方法名称相同,参数列表不同,方法体不同
重写看对象类型 来调用方法
重载看参数类型/引用类型 来绑定方法
class Doo{
void show(){ }
}
class Eoo extends Doo{
void show(String name){ //此处show重载了
}
Eoo o = new Eoo();
o.show();
o.show("zhangsan");
继承: 代码虽然我没有写,但也属于我
----------------------------------------------------------
射击游戏World类中:
class World{
FlyingObject[] enemies;
FlyingObject[] enemies = null; //---输出enemies的长度,会报空指针异常
FlyingObject[] enemies = new FlyingObject[0];
FlyingObject[] enemies = {}; //---输出enemie的长度,没有异常,会输出0(长度为0/元素数为0)
} //前两句话效果相同,后两句话效果相同
void action(){ //测试代码
system.out.println(enemies.length);
}
结论:类中的成员变量如果是引用类型,要赋值(先赋值为空) 为null,容易发生空指针异常
练习:
1.创建Person类,包含:
1)成员变量:name,age,address
2)构造方法:Person(3个参数){ 赋值 }
3)方法:sayHi(){ 输出3个数据 }
2.创建学生类Student,继承Person,包含:
1)成员变量:学号stuId(String)
2)构造方法:Student(4个参数){ super调超类3参构造、赋值stuId }
3)方法:重写sayHi(){ 输出4个数据 }
3.创建老师类Teacher,继承Person,包含:
1)成员变量:工资salary(double)
2)构造方法:Teacher(4个参数){ super调超类3参构造、赋值salary }
3)方法:重写sayHi(){ 输出4个数据 }
4.创建医生类Doctor,继承Person,包含:
1)成员变量:职称level(String)
2)构造方法:Doctor(4个参数){ super调超类3参构造、赋值level }
5.创建测试类Test,main中:
1)创建Person数组ps,包含7个元素,给元素赋值,遍历输出名字并问好