Java面向对象 (二) 引用类型数组 继承 super 向上造型 方法的重写

第三天:
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的用法:

  1. this.成员变量名-----------访问成员变量
  2. this.方法名()-------------调用方法(一般不用)
  3. 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个元素,给元素赋值,遍历输出名字并问好
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值