方法覆盖与多态

目录

1、什么时候使用方法覆盖

2、怎么构成方法覆盖及其规则

3、方法覆盖的经典案例

4、覆盖toString方法

5、多态语法机制

6、为什么总要instanceof判断

6、多态在开发中的作用 

7、静态方法不存在方法覆盖详解

8、私有方法不能覆盖详解

9、关于覆盖后的返回值类型


1、什么时候使用方法覆盖

父类中的方法无法满足子类的业务需求,子类有必要对继承过来的方法进行覆盖

/*
	当前程序存在的问题(设计上的问题)????
		鸟儿在执行move()方法的时候,最好输出的结果是:“鸟儿在飞翔”
		但是当前的程序在执行move()方法的时候输出的结果是:"动物在移动!"
		很显然Bird子类从Animal父类中继承过来的move()方法已经无法满足子类的业务需求。

*/
public class OverrideTest01{
	public static void main(String[] args){
		// 创建鸟对象
		Bird b = new Bird();
		// 让鸟儿移动
		b.move();

		// 创建Cat类型对象
		Cat c = new Cat();
		c.move();
	}
}

// 父类 
class Animal{

	// 移动
	public void move(){
		System.out.println("动物在移动!");
	}

}

// 子类
class Bird extends Animal{

	// 子类继承父类中,有一些“行为”可能不需要改进,有一些“行为”可能面临着必须改进。
	// 因为父类中继承过来的方法已经无法满足子类的业务需求。

	// 鸟儿在移动的时候希望输出鸟儿在飞翔!!!!
}

class Cat extends Animal{
	// 猫在移动的时候,我希望输出:猫在走猫步!!!!!!
}

2、怎么构成方法覆盖及其规则

/*
	回顾一下方法重载!!!!
		什么时候考虑使用方法重载overload?
			当在一个类当中,如果功能相似的话,建议将名字定义的一样,这样
			代码美观,并且方便编程。
		
		什么条件满足之后能够构成方法重载overload?
			条件一:在同一个类当中
			条件二:方法名相同
			条件三:参数列表不同(个数、顺序、类型)

	--------------------------------------------------------------------------------

	什么时候我们会考虑使用“方法覆盖”呢?
		子类继承父类之后,当继承过来的方法无法满足当前子类的业务需求时,
		子类有权利对这个方法进行重新编写,有必要进行“方法的覆盖”。
	
	方法覆盖又叫做:方法重写(重新编写),英语单词叫做:Override、Overwrite,都可以。
	比较常见的:方法覆盖、方法重写、override

	重要结论:
		当子类对父类继承过来的方法进行“方法覆盖”之后,
		子类对象调用该方法的时候,一定执行覆盖之后的方法。

	当我们代码怎么编写的时候,在代码级别上构成了方法覆盖呢?
		条件一:两个类必须要有继承关系。
		条件二:重写之后的方法和之前的方法具有:
					相同的返回值类型、
                        (学习了多态机制之后:
			            “相同的返回值类型”可以修改一下吗?
				        对于返回值类型是基本数据类型来说,必须一致。
				        对于返回值类型是引用数据类型来说,重写之后返回值类型可以变的更小
                        (但意义不大,实际开发中没人这样写。)。)
					相同的方法名、
					相同的形式参数列表。
		条件三:访问权限不能更低,可以更高。(这个先记住。)
		条件四:重写之后的方法不能比之前的方法抛出更多的异常,可以更少。(这个先记住)
	
	这里还有几个注意事项:(这几个注意事项,当学习了多态语法之后自然就明白了!)
		注意1:方法覆盖只是针对于方法,和属性无关。
		注意2:私有方法无法覆盖。
		注意3:构造方法不能被继承,所以构造方法也不能被覆盖。
		注意4:方法覆盖只是针对于“实例方法”,“静态方法覆盖”没有意义。

*/
public class OverrideTest02{
	public static void main(String[] args){
		Bird b = new Bird();
		b.move();
		b.sing(1000); //Animal sing....

		Cat c = new Cat();
		c.move();
	}
}

class Animal{
	public void move(){
		System.out.println("动物在移动!");
	}

	public void sing(int i){
		System.out.println("Animal sing....");
	}
}

class Bird extends Animal{

	// 对move方法进行方法覆盖,方法重写,override
	// 最好将父类中的方法原封不动的复制过来。(不建议手动编写)
	// 方法覆盖,就是将继承过来的那个方法给覆盖掉了。继承过来的方法没了。
	public void move(){
		System.out.println("鸟儿在飞翔!!!");
	}

	//protected表示受保护的。没有public开放。
	// 错误:正在尝试分配更低的访问权限; 以前为public
	/*
	protected void move(){
		System.out.println("鸟儿在飞翔!!!");
	}
	*/

	//错误:被覆盖的方法未抛出Exception
	/*
	public void move() throws Exception{
		System.out.println("鸟儿在飞翔!!!");
	}
	*/

	// 分析:这个sing()和父类中的sing(int i)有没有构成方法覆盖呢?
	// 没有,原因是,这两个方法根本就是两个完全不同的方法。
	// 可以说这两个方法构成了方法重载吗?可以。
	public void sing(){
		System.out.println("Bird sing.....");
	}
}

class Cat extends Animal{

	// 方法重写
	public void move(){
		System.out.println("猫在走猫步!!!");
	}
}

3、方法覆盖的经典案例

//方法覆盖比较经典的案例
//一定要注意:方法覆盖/重写的时候,建议将父类的方法复制粘贴,这样比较保险。
public class OverrideTest03{
	public static void main(String[] args){
		// 创建中国人对象
		// ChinaPeople p1 = new ChinaPeople("张三");// 错误原因:没有这样的构造方法
		ChinaPeople p1 = new ChinaPeople();
		p1.setName("张三");
		p1.speak();

		// 创建美国人对象
		// AmericPeople p2 = new AmericPeople("jack"); // 错误原因:没有这样的构造方法
		AmericPeople p2 = new AmericPeople();
		p2.setName("jack");
		p2.speak();
	}
}

// 人
class People{
	// 属性
	private String name;
	// 构造
	public People(){}
	public People(String name){
		this.name = name;
	}
	//setter and getter
	public void setName(String name){
		this.name = name;	
	}
	public String getName(){
		return name;
	}
	// 人都会说话
	public void speak(){
		System.out.println(name + "....");
	}
}

// 中国人
class ChinaPeople extends People{

	// 中国人说话是汉语
	// 所以子类需要对父类的speak()方法进行重写
	public void speak(){
		System.out.println(this.getName() + "正在说汉语");
	}
}


// 美国人
class AmericPeople extends People{
	// 美国人说话是英语
	// 所以子类需要对父类的speak()方法进行重写
	public void speak(){
		System.out.println(getName() + " speak english!");
	}
}

4、覆盖toString方法

/*
	关于Object类中的toString()方法
		1、toString()方法的作用是什么?
			作用:将“java对象”转换成“字符串的形式”。

		2、Object类中toString()方法的默认实现是什么?
			public String toString() {
				return getClass().getName() + "@" + Integer.toHexString(hashCode());
			}
			toString: 方法名的意思是转换成String
			含义:调用一个java对象的toString()方法就可以将该java对象转换成字符串的表示形式。

		3、那么toString()方法给的默认实现够用吗?
*/
public class OverrideTest04{
	public static void main(String[] args){
		// 创建一个日期对象
		MyDate t1 = new MyDate();
		// 调用toString()方法(将对象转换成字符串形式。)
		// 问:你对这个输出结果满意吗?不满意,希望输出:xxxx年xx月xx日
		// 重写MyDate的toString()方法之前的结果
		//System.out.println(t1.toString()); //MyDate@28a418fc 

		// 重写MyDate的toString()方法之后的结果
		System.out.println(t1.toString());

		// 大家是否还记得:当输出一个引用的时候,println方法会自动调用引用的toString方法。
		System.out.println(t1);

		MyDate t2 = new MyDate(2008, 8, 8);
		System.out.println(t2); //2008年8月8日

		//创建学生对象
		Student s = new Student(1111, "zhangsan");
		// 重写toString()方法之前
		//System.out.println(s); //Student@87aac27
		// 重写toString()方法之后
		// 输出一个学生对象的时候,可能更愿意看到学生的信息,不愿意看到对象的内存地址。
		System.out.println(s.toString());
		System.out.println(s);
	}
}

// 日期类
class MyDate {
	private int year;
	private int month;
	private int day;
	public MyDate(){
		this(1970,1,1);
	}
	public MyDate(int year,int month,int day){
		this.year = year;
		this.month = month;
		this.day = day;
	}
	public void setYear(int year){
		this.year = year;
	}
	public int getYear(){
		return year;
	}
	public void setMonth(int month){
		this.month = month;
	}
	public int getMonth(){
		return month;
	}
	public void setDay(int day){
		this.day = day;
	}
	public int getDay(){
		return day;
	}

	// 从Object类中继承过来的那个toString()方法已经无法满足我业务需求了。
	// 我在子类MyDate中有必要对父类的toString()方法进行覆盖/重写。
	// 我的业务要求是:调用toString()方法进行字符串转换的时候,
	// 希望转换的结果是:xxxx年xx月xx日,这种格式。
	// 重写一定要复制粘贴,不要手动编写,会错的。
	public String toString() {
		return year + "年" + month + "月" + day + "日";
	}
}

class Student{
	int no;
	String name;
	public Student(int no, String name){
		this.no = no;
		this.name = name;
	}
	// 重写  方法覆盖
	public String toString() {
		return "学号:" + no + ",姓名:" + name;
	}
}

5、多态语法机制

    5.1、向上转型和向下转型的概念。

        向上转型:子--->父 (upcasting)
            又被称为自动类型转换:Animal a = new Cat();

        向下转型:父--->子 (downcasting)
            又被称为强制类型转换:Cat c = (Cat)a; 需要添加强制类型转换符。
            什么时候需要向下转型?
                需要调用或者执行子类对象中特有的方法。
                必须进行向下转型,才可以调用。
            向下转型有风险吗?
                容易出现ClassCastException(类型转换异常)
            怎么避免这个风险?
                instanceof运算符,可以在程序运行阶段动态的判断某个引用指向的对象
                是否为某一种类型。
                养成好习惯,向下转型之前一定要使用instanceof运算符进行判断。
        
        不管是向上转型还是向下转型,首先他们之间必须有继承关系,这样编译器就不会报错。

    5.2、什么是多态。
        多种形态,多种状态,编译和运行有两个不同的状态。
        编译期叫做静态绑定。
        运行期叫做动态绑定。
        Animal a = new Cat();
        // 编译的时候编译器发现a的类型是Animal,所以编译器会去Animal类中找move()方法
        // 找到了,绑定,编译通过。但是运行的时候和底层堆内存当中的实际对象有关
        // 真正执行的时候会自动调用“堆内存中真实对象”的相关方法。
        a.move();

        多态的典型代码:父类型的引用指向子类型的对象。(java中允许这样写代码!!!)

    5.3、什么时候必须进行向下转型?
        调用子类对象上特有的方法时。

// 动物类:父类
public class Animal{

	// 移动的方法
	public void move(){
		System.out.println("动物在移动!!!");
	}

}
// 鸟儿类,子类
public class Bird extends Animal{

	// 重写父类的move方法
	public void move(){
		System.out.println("鸟儿在飞翔!!!");
	}

	// 也有自己特有的方法
	public void sing(){
		System.out.println("鸟儿在歌唱!!!");
	}

}
// 猫类,子类
public class Cat extends Animal{

	// 对move方法进行重写
	public void move(){
		System.out.println("cat走猫步!");
	}

	// 猫除了move之外,应该有自己特有的行为,例如抓老鼠。
	// 这个行为是子类型对象特有的方法。
	public void catchMouse(){
		System.out.println("猫正在抓老鼠!!!!");
	}

}
// Dog并没有继承Animal
// Dog不是Animal的子类
public class Dog{

}
/*
	多态的基础语法:
		1、学习多态基础语法之前,我们需要普及两个概念:
			第一个:向上转型
				子 ---> 父(自动类型转换)
			第二个:向下转型
				父 ---> 子(强制类型转换,需要加强制类型转换符)

			注意:
				java中允许向上转型,也允许向下转型。

				*****(五颗星)无论是向上转型,还是向下转型,
						两种类型之间必须有继承关系,没有继承关系编译器报错。
				
				以后在工作过程中,和别人聊天的时候,要专业一些,说
				向上转型和向下转型,不要说自动类型转换,也不要说强制
				类型转换,因为自动类型转换和强制类型转换是使用在基本
				数据类型方面的,在引用类型转换这里只有向上和向下转型。
		
		2、多态指的是:
			父类型引用指向子类型对象。
			包括编译阶段和运行阶段。
			编译阶段:绑定父类的方法。
			运行阶段:动态绑定子类型对象的方法。
			多种形态。
		
		3、个别同学有点混乱了:
			java中只有“类名”或者“引用”才能去“点”
			类名.
			引用.
			万变不离其宗,只要你想“点”,“点”前面要么是一个类名,要么是一个引用。
		
		4、什么时候必须使用“向下转型”?
			不要随便做强制类型转换。
			当你需要访问的是子类对象中“特有”的方法。此时必须进行向下转型。
*/
public class Test01{

	public static void main(String[] args){

		Animal a1 = new Animal();
		a1.move(); //动物在移动!!!

		Cat c1 = new Cat();
		c1.move(); //cat走猫步!

		Bird b1 = new Bird();
		b1.move(); //鸟儿在飞翔!!!

		// 代码可以这样写吗?
		/*
			1、Animal和Cat之间有继承关系吗?有的。
			2、Animal是父类,Cat是子类。
			3、Cat is a Animal,这句话能不能说通?能。
			4、经过测试得知java中支持这样的一个语法:
				父类型的引用允许指向子类型的对象。
				Animal a2 = new Cat();
				a2就是父类型的引用。
				new Cat()是一个子类型的对象。
				允许a2这个父类型引用指向子类型的对象。
		*/
		Animal a2 = new Cat();
		Animal a3 = new Bird();

		// 没有继承关系的两个类型之间存在转型吗?
		// 错误: 不兼容的类型: Dog无法转换为Animal
		// Animal a4 = new Dog();

		// 调用a2的move()方法
		/*
			什么是多态?
				多种形态,多种状态。
			分析:a2.move();
				java程序分为编译阶段和运行阶段。
				先来分析编译阶段(不会new对象):
					对于编译器来说,编译器只知道a2的类型是Animal,
					所以编译器在检查语法的时候,会去Animal.class
					字节码文件中找move()方法,找到了,绑定上move()
					方法,编译通过,静态绑定成功。(编译阶段属于静态绑定。)
				再来分析运行阶段:
					运行阶段的时候,实际上在堆内存中创建的java对象是
					Cat对象,所以move的时候,真正参与move的对象是一只猫,
					所以运行阶段会动态执行Cat对象的move()方法。这个过程
					属于运行阶段绑定。(运行阶段绑定属于动态绑定。)

			多态表示多种形态:
				编译的时候一种形态。
				运行的时候另一种形态。
		*/
		a2.move(); //cat走猫步!
		
		// 调用a3的move()方法
		a3.move(); //鸟儿在飞翔!!!

		// ======================================================================
		Animal a5 = new Cat(); // 底层对象是一只猫。

		// 分析这个程序能否编译和运行呢?
		// 分析程序一定要分析编译阶段的静态绑定和运行阶段的动态绑定。
		// 只有编译通过的代码才能运行。没有编译,根本轮不到运行。
		// 错误: 找不到符号
		// why??? 因为编译器只知道a5的类型是Animal,去Animal.class文件中找catchMouse()方法
		// 结果没有找到,所以静态绑定失败,编译报错。无法运行。(语法不合法。)
		//a5.catchMouse(); 
		
		// 假设代码写到了这里,我非要调用catchMouse()方法怎么办?
		// 这个时候就必须使用“向下转型”了。(强制类型转换)
		// 以下这行代码为啥没报错????
		// 因为a5是Animal类型,转成Cat,Animal和Cat之间存在继承关系。所以没报错。
		Cat x = (Cat)a5;
		x.catchMouse(); //猫正在抓老鼠!!!!

		// 向下转型有风险吗?
		Animal a6 = new Bird(); //表面上a6是一个Animal,运行的时候实际上是一只鸟儿。
		/*
			分析以下程序,编译报错还是运行报错???
				编译器检测到a6这个引用是Animal类型,
				而Animal和Cat之间存在继承关系,所以可以向下转型。
				编译没毛病。

				运行阶段,堆内存实际创建的对象是:Bird对象。
				在实际运行过程中,拿着Bird对象转换成Cat对象
				就不行了。因为Bird和Cat之间没有继承关系。
			
			运行是出现异常,这个异常和空指针异常一样非常重要,也非常经典:
				java.lang.ClassCastException:类型转换异常。
			
			java.lang.NullPointerException:空指针异常。这个也非常重要。
		*/
		//Cat y = (Cat)a6;
		//y.catchMouse();

		// 怎么避免ClassCastException异常的发生???
		/*	
			新的内容,运算符:
				instanceof (运行阶段动态判断)
			第一:instanceof可以在运行阶段动态判断引用指向的对象的类型。
			第二:instanceof的语法:
				(引用 instanceof 类型)
			第三:instanceof运算符的运算结果只能是:true/false
			第四:c是一个引用,c变量保存了内存地址指向了堆中的对象。
				假设(c instanceof Cat)为true表示:
					c引用指向的堆内存中的java对象是一个Cat。
				假设(c instanceof Cat)为false表示:
					c引用指向的堆内存中的java对象不是一个Cat。
			
			程序员要养成一个好习惯:
				任何时候,任何地点,对类型进行向下转型时,一定要使用
				instanceof 运算符进行判断。(java规范中要求的。)
				这样可以很好的避免:ClassCastException
		*/
		System.out.println(a6 instanceof Cat); //false

		if(a6 instanceof Cat){ // 如果a6是一只Cat
			Cat y = (Cat)a6;  // 再进行强制类型转换
			y.catchMouse();
		}
	}
}

6、为什么总要instanceof判断

/*
	这个代码的疑问?
		肉眼可以观察到底层到底是new Bird()还是new Cat()!!
		我们为什么还要进行instanceof的判断呢!!!!

		原因是:
			你以后可能肉眼看不到。
*/
public class Test02{
	public static void main(String[] args){
		Animal x = new Bird();
		Animal y = new Cat();

		if(x instanceof Bird){
			Bird b = (Bird)x;
			b.sing();
		} else if(x instanceof Cat){
			Cat c = (Cat)x;
			c.catchMouse();
		}


		if(y instanceof Bird){
			Bird b = (Bird)y;
			b.sing();
		} else if(y instanceof Cat){
			Cat c = (Cat)y;
			c.catchMouse();
		}
	}
}

如:

public class AnimalTest{
	
	// test方法是程序员B负责编写。
	// 这个test()方法的参数是一个Animal
	public void test(Animal a){ // 实例方法
		// 你写的这个方法别人会去调用。
		// 别人调用的时候可能给你test()方法传过来一个Bird
		// 当然也可能传过来一个Cat
		// 对于我来说,我不知道你调用的时候给我传过来一个啥。
		if(a instanceof Cat){
			Cat c = (Cat)a;
			c.catchMouse();
		}else if(a instanceof Bird){
			Bird b = (Bird)a;
			b.sing();
		}
	}

}
public class Test03{
	public static void main(String[] args){
		// main方法是程序员A负责编写。
		AnimalTest at = new AnimalTest();
		at.test(new Cat());
		at.test(new Bird());
	}
}

6、多态在开发中的作用 

// 主人类
public class Master{

	/*
	// 假设主人起初的时候只是喜欢养宠物狗狗
	// 喂养宠物狗狗
	public void feed(Dog d){
		d.eat();
	}

	// 由于新的需求产生,导致我们“不得不”去修改Master这个类的代码
	public void feed(Cat c){
		c.eat();
	}
	*/
	
	// 能不能让Master主人这个类以后不再修改了。
	// 即使主人又喜欢养其它宠物了,Master也不需要修改。
	// 这个时候就需要使用:多态机制。
	// 最好不要写具体的宠物类型,这样会影响程序的扩展性。
	public void feed(Pet pet){ 
		// 编译的时候,编译器发现pet是Pet类,会去Pet类中找eat()方法,结果找到了,编译通过
		// 运行的时候,底层实际的对象是什么,就自动调用到该实际对象对应的eat()方法上。
		// 这就是多态的使用。
		pet.eat();
	}

}

/*

	注意这里的分析:
		主人起初的时候只喜欢养宠物狗狗
		随着时间的推移,主人又喜欢上养“猫咪”
		在实际的开发中这就表示客户产生了新的需求。
		作为软件的开发人员来说,必须满足客户的需求。
		我们怎么去满足客户的需求呢?
			在不使用多态机制的前提下,目前我们只能在Master类中添加一个新的方法。
	
	思考:软件在扩展新需求过程当中,修改Master这个类有什么问题?
		一定要记住:软件在扩展过程当中,修改的越少越好。
		修改的越多,你的系统当前的稳定性就越差,未知的风险就越多。

		其实这里涉及到一个软件的开发原则:
			软件开发原则有七大原则(不属于java,这个开发原则属于整个软件业):
				其中有一条最基本的原则:OCP(开闭原则)

		什么是开闭原则?
			对扩展开放(你可以额外添加,没问题),对修改关闭(最好很少的修改现有程序)。
			在软件的扩展过程当中,修改的越少越好。
	

	高手开发项目不是仅仅为了实现客户的需求,还需要考虑软件的扩展性。

	什么是软件扩展性?
		假设电脑中的内存条部件坏了,我们可以买一个新的插上,直接使用。
		这个电脑的设计就考虑了“扩展性”。内存条的扩展性很好。
	
	面向父类型编程,面向更加抽象进行编程,不建议面向具体编程。
	因为面向具体编程会让软件的扩展力很差。

*/
// 宠物狗狗类
public class Dog extends Pet{
	// 吃
	public void eat(){
		System.out.println("狗狗喜欢啃骨头,吃的很香。");
	}
}
public class Cat extends Pet{

	// 吃
	public void eat(){
		System.out.println("猫咪喜欢吃鱼,吃的很香!!!");
	}
}
// 所有宠物的父类
public class Pet{

	// 吃的行为(这个方法可以不给具体的实现。)
	public void eat(){
	
	}


}
/*
	测试多态在开发中的作用
*/
public class Test{
	public static void main(String[] args){
		// 创建主人对象
		Master zhangsan = new Master();
		// 创建宠物对象
		Dog zangAo = new Dog();
		// 主人喂
		zhangsan.feed(zangAo);
		// 创建宠物对象
		Cat xiaoHua = new Cat();
		// 主人喂
		zhangsan.feed(xiaoHua);
		// 创建宠物对象
		YingWu yingWu = new YingWu();
		// 主人喂
		zhangsan.feed(yingWu);
	}
}

7、静态方法不存在方法覆盖详解

/*
	1、方法覆盖需要和多态机制联合起来使用才有意义。
		Animal a = new Cat();
		a.move();
		要的是什么效果?
			编译的时候move()方法是Animal的。
			运行的时候自动调用到子类重写move()方法上。
		
		假设没有多态机制,只有方法覆盖机制,你觉得有意义吗?
			没有多态机制的话,方法覆盖可有可无。

			没有多态机制,方法覆盖也可以没有,如果父类的方法无法满足
			子类业务需求的时候,子类完全可以定义一个全新的方法。
		
		方法覆盖和多态不能分开。

	2、静态方法存在方法覆盖吗?
		多态自然就和对象有关系了。
		而静态方法的执行不需要对象。
		所以,一般情况下,我们会说静态方法“不存在”方法覆盖。
		不探讨静态方法的覆盖。

*/
public class OverrideTest05{
	public static void main(String[] args){
		// 静态方法可以使用“引用.”来调用吗?可以
		// 虽然使用“引用.”来调用,但是和对象无关。
		Animal a = new Cat(); //多态
		// 静态方法和对象无关。
		// 虽然使用“引用.”来调用。但是实际运行的时候还是:Animal.doSome()
		a.doSome();
		
		Animal.doSome();
		Cat.doSome();
	}
}

class Animal{
	// 父类的静态方法
	public static void doSome(){
		System.out.println("Animal的doSome方法执行!");
	}
}

class Cat extends Animal{
	// 尝试在子类当中对父类的静态方法进行重写
	public static void doSome(){
		System.out.println("Cat的doSome方法执行!");
	}
}

8、私有方法不能覆盖详解

// 经过测试,你记住就行。
// 私有方法不能覆盖。
public class OverrideTest06{

	// 私有方法
	private void doSome(){
		System.out.println("OverrideTest06's private method doSome execute!");
	}

	// 入口
	public static void main(String[] args){
		// 多态
		OverrideTest06 ot = new T();
		ot.doSome(); //OverrideTest06's private method doSome execute!
	}
}

/*
// 在外部类中无法访问私有的。
class MyMain{
	public static void main(String[] args){
		OverrideTest06 ot = new T();
		//错误: doSome() 在 OverrideTest06 中是 private 访问控制
		//ot.doSome();
	}
}
*/

// 子类
class T extends OverrideTest06{
	// 尝试重写父类中的doSome()方法
	// 访问权限不能更低,可以更高。
	public void doSome(){
		System.out.println("T's public doSome method execute!");
	}
}

9、关于覆盖后的返回值类型

学习了多态机制之后:
            “相同的返回值类型”可以修改一下吗?
                对于返回值类型是基本数据类型来说,必须一致。
                对于返回值类型是引用数据类型来说,重写之后返回值类型可以变的更小(但意义不大,实际开发中没人这样写。)。

public class OverrideTest07{
	public static void main(String[] args){
		// 一般重写的时候都是复制粘贴。不要动。不要改。	
	}
}

class Animal{
	/*
	public double sum(int a, int b){
		return a + b;
	}
	*/
	
	/*
	public long sum(int a, int b){
		return a + b;
	}
	*/

	/*
	public int sum(int a, int b){
		return a + b;
	}
	*/
}

class Cat extends Animal{
	// 重写
	// 错误: Cat中的sum(int,int)无法覆盖Animal中的sum(int,int)
	/*
	public int sum(int a, int b){
		return a + b;
	}
	*/
	
	/*
	public double sum(int a, int b){
		return a + b;
	}
	*/

	//错误: Cat中的sum(int,int)无法覆盖Animal中的sum(int,int)
	/*
	public long sum(int a, int b){
		return a + b;
	}
	*/
}

// 父类
class MyClass1{
	
	public Animal getAnimal(){
		return null;
	}
}

// 子类
class MyClass2 extends MyClass1{

	// 重写父类的方法
	/*
	public Animal getAnimal(){
		return null;
	}
	*/

	// 重写的时候返回值类型由Animal变成了Cat,变小了。(可以,java中允许)
	/*
	public Cat getAnimal(){
		return null;
	}
	*/

	// 重写的时候返回值类型由Animal变成了Object。变大了。(不行,java中不允许)
	/*
	public Object getAnimal(){
		return null;
	}
	*/
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值