halisi7

一个专注技术的组织

0%

Java面向对象2-向下转型

多态的补充:

  1. 有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。
  1. 如何才能调用子类特有的属性和方法? //向下转型:使用强制类型转换符。
  2. 多态是运行时行为。

类型转换:

Snipaste20220118134450

Snipaste20220118134518

强制转换出现的问题:

1
2
3
4
//使用强转时,可能出现ClassCastException的异常。
// Person p2 = new Man();
// Woman w1 = (Woman)p2;
// w1.goShopping();

解决方案——instanceof关键字的使用

1
2
3
4
5
6
7
8
9
10
11
12
/*
* instanceof关键字的使用
*
* a instanceof A : 判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false。
*
*
* 使用情境:为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先
* 进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。
*
* 如果 a instanceof A返回true,则 a instanceof B也返回true.
* 其中,类B是类A的父类。
*/

Demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
if(p2 instanceof Woman){
Woman w1 = (Woman)p2;
w1.goShopping();
System.out.println("******Woman******");
}

if(p2 instanceof Man){
Man m2 = (Man)p2;
m2.earnMoney();
System.out.println("******Man******");
}

if(p2 instanceof Person){
System.out.println("******Person******");
}
if(p2 instanceof Object){
System.out.println("******Object******");
}

// if(p2 instanceof String){
//
// }

//练习:
//问题一:编译时通过,运行时不通过
//举例一:
// Person p3 = new Woman();
// Man m3 = (Man)p3;
//举例二:
// Person p4 = new Person();
// Man m4 = (Man)p4;


//问题二:编译通过,运行时也通过
// Object obj = new Woman();
// Person p = (Person)obj;

//问题三:编译不通过
// Man m5 = new Woman();

// String str = new Date();

// Object o = new Date();
// String str1 = (String)o;




练习1:

Snipaste20220118141522

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Base {
int count = 10;

public void display() {
System.out.println(this.count);
}
}

class Sub extends Base {
int count = 20;

public void display() {
System.out.println(this.count);
}
}

public class FieldMethodTest {
public static void main(String[] args) {
Sub s = new Sub();
System.out.println(s.count);//20
s.display();//20

Base b = s;//多态性
//==:对于引用数据类型来讲,比较的是两个引用数据类型变量的地址值是否相同
System.out.println(b == s);//true
System.out.println(b.count);//10
b.display();//20
}
}

总结:

练习1:

  • 1.若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中:编译看左边,运行看右边
  • 2.对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量:编译运行都看左边

练习2:

Snipaste20220118141332

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
public class InstanceTest {

public static void main(String[] args) {

InstanceTest test = new InstanceTest();
test.method(new Student());
}


public void method(Person e){

//虚拟方法调用
String info = e.getInfo();
System.out.println(info);

//方式一
// if(e instanceof Graduate){
// System.out.println("a graduated student");
// System.out.println("a student");
// System.out.println("a person");
// }else if(e instanceof Student){
// System.out.println("a student");
// System.out.println("a person");
// }else{
// System.out.println("a person");
// }

//方式二
if(e instanceof Graduate){
System.out.println("a graduated student");
}

if(e instanceof Student){
System.out.println("a student");
}

if(e instanceof Person){
System.out.println("a person");
}


}
}

class Person {
protected String name = "person";
protected int age = 50;

public String getInfo() {
return "Name: " + name + "\n" + "age: " + age;
}
}

class Student extends Person {
protected String school = "pku";

public String getInfo() {
return "Name: " + name + "\nage: " + age + "\nschool: " + school;
}
}

class Graduate extends Student {
public String major = "IT";

public String getInfo() {
return "Name: " + name + "\nage: " + age + "\nschool: " + school + "\nmajor:" + major;
}
}

练习3:

Snipaste20220118152920

  • 对于多态,只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体 方法,这称为“晚绑定”或“动态绑定”。

练习4:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//考查多态的笔试题目:
public class InterviewTest1 {

public static void main(String[] args) {
Base1 base = new Sub1();
base.add(1, 2, 3);//sub_1

Sub1 s = (Sub1)base;
s.add(1,2,3);//sub_2
}
}

class Base1 {
public void add(int a, int... arr) {
System.out.println("base1");
}
}

class Sub1 extends Base1 {

public void add(int a, int[] arr) {
System.out.println("sub_1");
}

public void add(int a, int b, int c) {
System.out.println("sub_2");
}

}
  1. 形参中int[] arr=int… arr 所以构成重写。
  2. 编译时编译的是Base1的add方法然后执行时Sub1重写了add方法所以输出sub_1与sub_2无关(不构成重写)
  3. 方法的重载中确定个数的形参优先调用,所以输出sub_2。
打赏一下作者~ ฅ( ̳• ◡ • ̳)ฅ