1.方法的重载
1)方法的重载(编译时多态),重载是指同一类中有多个同名的方法,但这些方法有着不同的参数(参数类型或个数不同),因此在编译时就可以确定到底调用哪些方法。
- 返回类型可以不同:可以任意改变重载方法的返回类型,只要所有的覆盖使用不同的参数即可。
- 不能只改变返回类型
- 可以更改存取权限:可以任意设定子类版的存取权限
- 父类方法的访问权限是private,那么就不能在子类中对其重载:
示例:最常见的重载(类中的参数不同):
class Monster
{
boolean frighten(int d)
{
System.out.println("arrrgh");
return true;
}
boolean frighten(int d,int t)//参数的个数不同
{
System.out.println("a bit");
return true;
}
boolean frighten(double d)//参数的类型不同
{
System.out.println("breath fire");
return true;
}
}
class HelloWorld
{
public static void main(String[] args)
{
Monster monster = new Monster();
monster.frighten(1, 2);
monster.frighten(1);
monster.frighten(1.1);
}
}
输出:a bitarrrgh
breath fire
子类继承父类方法后在子类中的重载:
子类继承了父类的方法frighten(int d)与子类的方法frighten(int x,int y)构成重载,如下例所示:
class Monster
{
boolean frighten(int d)
{
System.out.println("arrrgh");
return true;
}
}
class Vampire extends Monster
{
boolean frighten(int x,int y)
{
System.out.println("a bit");
return true;
}
}
class HelloWorld
{
public static void main(String[] args)
{
Vampire v = new Vampire();
v.frighten(1, 2);
v.frighten(1);
}
}
输出:a bitarrrgh
父类方法的访问权限是private,那么就不能在子类中对其重载:class Monster
{
private boolean frighten(int d)
{
System.out.println("arrrgh");
return true;
}
}
class Vampire extends Monster
{
boolean frighten(int x,int y)//父类的方法为private,不能在子类中对其重载
{ //子类中是一个新方法,不会达到重载效果
System.out.println("a bit");
return true;
}
}
class HelloWorld
{
public static void main(String[] args)
{
Vampire v = new Vampire();
v.frighten(1, 2);
//v.frighten(1); //这边报错,无法调用
}
}
2.方法的覆盖:
- 子类中的覆盖方法必须和父类中方法有相同的函数名和参数
- 子类中的覆盖方法的返回类型必须与父类中被覆盖的方法的返回类型相同
- 不能降低方法的存取权限:子类的存取权限必须相同或者更开放
- 子类中被覆盖的方法不能为private,否则子类只是定义了一个方法,并没有对其覆盖
示例:
class Monster
{
boolean frighten(int d)
{
System.out.println("arrrgh");
return true;
}
}
class Vampire extends Monster
{
int frighten(int x)
{
System.out.println("a bite");
return 1;
}
}
这个既不是重载也不是覆盖,因为首先参数相同,所以不同重载,同时返回类型也不满足覆盖的条件,但函数名相同编译器会报错。
3.多态可以理解为事物存在的多种体现形态:
Java语言中,父类的引用变量不仅可以指向父类的实例对象,也可以指向其子类的实例对象。同样接口的引用变量也可以指向其实现类的实例对象。而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存中正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。
1)第一张情况 调用非继承父类的方法和成员
class Base
{
public Base()
{
g();
}
public void f()
{
System.out.println("Base f()");
}
public void g()
{
System.out.println("Base g()");
}
}
class Derived extends Base
{
public void f()
{
System.out.println("Derived f()");
}
public void g()
{
System.out.println("Derived g()");
}
public void p()
{
System.out.println("Derived g()");
}
}
class HelloWorld
{
public static void main(String[] args)
{
Base b = new Derived(); //子类引用可以指向父类对象
Derived d = (Derived)b; //不能用父类引用访问子类非继承父类的成员和方法,要先强制转换
d.p();
}
}
弊端:只能使用父类的引用访问父类的成员和方法,不能使用父类的引用s1访问子类非继承的的成员和方法,上例中p()方法不是继承与父类的,所以不可用子类的引用直接调,即b.p()是错误的,要先进行强制转换。
2)第二种情况 运行多态时,引用类型可以是实际对象类型的父类
示例
class Base
{
public Base()
{
g();
}
public void f()
{
System.out.println("Base f()");
}
public void g()
{
System.out.println("Base g()");
}
}
class Derived extends Base
{
public void f()
{
System.out.println("Derived f()");
}
public void g()
{
System.out.println("Derived g()");
}
public void p()
{
System.out.println("Derived g()");
}
}
class HelloWorld
{
public static void main(String[] args)
{
Base b = new Derived(); //子类引用可以指向父类对象
b.f();
b.g();
}
}
输出:Derived g()
Derived f()
Derived g()
说明:Base b = new Derived()时会调用Base类的构造函数,在Base的构造函数中,执行了go()方法,由于Java的多态特性此时或调用子类的g()方法,而非父类的go()方法,因此会输出Derived g()。因为创建的是Derived类对象,后面的方法都会调用子类Derived的方法。
3)参数和返回类型也可以多态
public class HelloWorld {
public static void main(String[] args) {
Student s1 = new Student();
function(s1);
}
public static void function(Person c) //传入参数可以是多态
{
if (c instanceof Student)
{
Student s = (Student)c;
s.study();
s.sleep();
}
}
}
class Person{
String name;
int age;
void sleep()
{
System.out.println("Person sleep");
}
}
class Student extends Person{
void sleep()
{
System.out.println("Student sleep");
}
void study(){
System.out.println("good study");
}
}
总结:存取权限,返回类型,方法名,参数(类型,个数,顺序)
方法的重载:要求:方法名相同,参数不同(类型,个数,顺序有一个不同)
方法的覆盖:要求:方法名相同,参数相同,权限不能降低,返回类型返回一样的类型或该类型的子类