多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:
多态性是对象多种表现形式的体现。
现实中,比如我们按下 F1 键这个动作:
同一个事件发生在不同的对象上会产生不同的结果。
下面代码中,创建了人的类,也创建了男人和女人的类,男人和女人都继承了人的类。
class Person {
void testPerson() {
System.out.println("test person...");
}
}
class Boy extends Person {
void testBoy() {
System.out.println("test boy...");
}
}
class Girl extends Person {
void testGirl() {
System.out.println("test girl...");
}
我们可以看见使用多态时,p1和p2无法调用boy和girl的方法,这说明,多态语法其实就是对对象的使用场景进行了约束,比如说蜘蛛侠在不变身的情况下,一般不能使用蜘蛛侠的能力,但当变身后就可以使用能力了。
一个对象可以使用的功能取决于引用变量的类型。
多态的实现方式大致有三种:重写、接口、抽象类和抽象方法;接下来我们对重写和重载进行详细的介绍,抽象类会在后面的章节学习。
重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
public class Java14_Object {
public static void main(String[] args) {
user.login(1111);
user.login("123123");
user.login("zhangsan", "123123");
}
}
class User14 {
void login( String account, String password ) {
System.out.println("账号,密码登录");
}
void login(int tel) {
System.out.println("手机验证码登录");
}
void login(String wx) {
System.out.println("微信,支付宝登录");
}
}
当然,构造方法也有重载的功能。
public class Java14_Object {
public static void main(String[] args) {
User14 user = new User14("zhangsan");
}
}
class User14 {
User14() {
System.out.println("user...");
}
User14(String name) {
System.out.println("user..." + name);
}
}
如果在一个构造方法中。想要调用其他的构造方法,那么需要使用特殊的关键字:this
public class Java14_Object_1 {
public static void main(String[] args) {
User141 user1 = new User141();
}
}
class User141 {
User141() {
this("zhangsan");
}
User141( String name ) {
this(name, "男");
}
User141( String name, String sex ) {
System.out.println(name + "," + sex);
}
}
下面再看一个重载的例子:
public class chapter10 {
public static void main(String[] args) {
byte b = 10;
test(b);
}
// static void test( byte b ) {
// System.out.println("bbb");
// }
static void test( short s ) {
System.out.println("sss");
}
static void test( char c ) {
System.out.println("ccc");
}
static void test( int i ) {
System.out.println("iii");
}
}
从上面来看,如果是调用test (byte b),那毫无疑问是打印出bbb,但现在我们将test (byte b)进行注释,这个时候test (b)又会调用哪个呢?
结果是sss,说明调用了test (short s),可是为什么呢?
原因是基本数据类型在匹配方法时,可以在数值不变的情况下,扩大数据的精度
byte 8位
short 16位
char 16位
int 32位
所以,在没有byte的情况下,会默认匹配short。
现在我们又注释了test (short s),可以发现结果打印出iii,说明调用的是 test( int i )。
原因是,byte类型无法和char类型做转换,char没有负数,但是byte存在负数
我们再来看一个多态与重载相关的例子。
// 多态其实就是约束了对象的使用场景
// 方法的重载:方法名相同,参数列表不同(个数,顺序,类型)
// AAA -> Object
// BBB -> AAA -> Object
public class Java14_Object_3 {
public static void main(String[] args) {
AAA aaa = new BBB();
test(aaa);
}
static void test( Object aaa ) {
System.out.println("aaa");
}
static void test( BBB bbb ) {
System.out.println("bbb");
}
}
class AAA {
}
class BBB extends AAA {
}
以上运行结果是:aaa,说明方法的重载和调用的是类型。
如果现在将 static void test( Object aaa ) 注释掉呢?
结果test(aaa)报错了,原因是AAA 会向上一级父类Object类进行查找,看父类有没有这个方法,如果有,那么久调用父类的方法,如果没有就会提升报错。
现在修改aaa的类型为BBB,将 static void test( Object bbb ) 注释掉。
重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
public class Java15_Object {
public static void main(String[] args) {
Child15 child = new Child15();
child.test();
}
}
class Parent15 {
void test() {
System.out.println("parent test...");
}
}
class Child15 extends Parent15 {
void test() {
super.test();
System.out.println("child test...");
}
}
这里的重写,并不意味着父类的方法被覆盖掉,只是在当前场合不使用。如果使用super关键字还是可以访问。
下面来看这串代码:
public class Java15_Object_1 {
public static void main(String[] args) {
CCC ddd = new DDD();
System.out.println(ddd.sum());
}
}
class CCC {
int i = 10;
int sum() {
return i + 10;
}
}
class DDD extends CCC {
int i = 20;
int sum() {
return i + 20;
}
}
一个对象能使用什么方法,取决于引用变量的类型
一个对象能使用什么属性,取决于引用变量的类型
一个对象的方法具体的使用(直接,间接)是需要看具体的对象的
一个对象的属性具体的使用是不需要看具体的对象的,属性在哪里声明在哪里使用
现在,我们对象的类型是CCC,那么是可以使用CCC中的sum,但具体的使用是DDD当中的sum,原因是new DDD()。
下面我们将DDD当中的sum进行注释
public class Java15_Object_1 {
public static void main(String[] args) {
CCC ddd = new DDD();
System.out.println(ddd.sum());
}
}
class CCC {
int i = 10;
int sum() {
return i + 10;
}
}
class DDD extends CCC {
int i = 20;
// int sum() {
// return i + 20;
// }
}
故而,这个时候的运行结果是20,使用的是CCC当中的sum。
我们再将代码进行更改:
public class Java15_Object_1 {
public static void main(String[] args) {
CCC ddd = new DDD();
System.out.println(ddd.sum());
}
}
class CCC {
int i = 10;
int sum() {
return getI() + 10;
}
int getI() {
return i;
}
}
class DDD extends CCC {
int i = 20;
// int sum() {
// return i + 20;
// }
int getI() {
return i;
}
}