- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Java编程—在测试中考虑多态由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
面向对象编程有三大特性:封装、继承、多态.
封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据。对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方法.
继承是为了重用父类代码。两个类若存在IS-A的关系就可以使用继承。,同时继承也为实现多态做了铺垫。那么什么是多态呢?多态的实现机制又是什么?请看我一一为你揭开:
所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。练习(1):创建一个Cycle类,它具有子类Unicycle,Bycycle,Tricycle.演示每一个类型的实例都可以经由ride()方法向上转型为Cycle. 。
向上转型就是允许将多种从同一基类的导出类看成同一类型.
多态方法调用就是允许一种类型表现出与其他相似类型之间的区别,只要他们是从同一基类导出而来的。这种区别由各个导出类型方法的具体不同实现而表现出来的,虽然这些方法都是由基类调用的.
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
|
public
class
Test1 {
public
static
void
main(String[] args){
Unicycle unicycle =
new
Unicycle(
"Unicycle"
);
Bicycle bicycle =
new
Bicycle(
"Bicycle"
);
Tricycle tricycle =
new
Tricycle(
"Tricycle"
);
Cycle.ride(unicycle);
Cycle.ride(bicycle);
Cycle.ride(tricycle);
}
}
class
Cycle{
private
String name;
public
Cycle(String str){
name = str;
}
public
static
void
ride(Cycle c){
System.out.println(c.name +
"is riding"
);
}
}
class
Unicycle
extends
Cycle{
private
String name;
public
Unicycle(String str) {
super
(str);
name = str;
}
}
class
Bicycle
extends
Cycle{
private
String name;
public
Bicycle(String str) {
super
(str);
name = str;
}
}
class
Tricycle
extends
Cycle {
private
String name;
public
Tricycle(String str) {
super
(str);
name = str;
}
}
|
输出:
Unicycleis riding 。
Bicycleis riding 。
Tricycleis riding 。
在以上示例中,三种子类能被视作Cycle传入到方法ride()中就是向上转型.
但向上转型只是看成,而不是强制转换,所以最后方法调用的结果不同,这就是多态.
多态又称之为动态绑定。什么是动态绑定?
与动态绑定相反的是静态绑定。c语言所有方法都是默认静态绑定。静态绑定也称为前期绑定,就是在程序运行前就绑定完成。也就是说,代码写了什么样,就是什么样.
而动态绑定是直到运行时才去决定该方法调用该绑定哪个实体.
java中的所有static和final方法都是静态绑定,其他的所有方法都是动态绑定.
练习(2):在几何图形示例中添加@Override注解.
练习(3):在基类Shape.java中添加一个新方法,用于打印一条消息,但导出类中不要覆盖这个方法。请解释发生了什么。现在,在其中一个导出类中覆盖该方法,而在其他的导出类中不予覆盖,观察又有什么发生。最后,在所有的导出类中覆盖这个方法.
练习(4):向Shapes.java中添加一个新的Shape类型,并在main()方法中验证:多态对新类型的作用是否与在旧类型中的一样.
以上三个练习在一份示例中完成.
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
public
class
Test234 {
private
static
RandonShapeGenerator gen =
new
RandonShapeGenerator();
public
static
void
main(String[] args){
Shape[] shapes =
new
Shape[
9
];
for
(
int
i =
0
; i < shapes.length; i++) {
shapes[i] = gen.next();
}
for
(Shape s :
shapes) {
s.draw();
s.newMethod();
//每个子类都调用了一次添加的新方法,
// 因为子类继承父类自然把所有方法都继承过去了,只不过没有显示出来,
// 其实是隐式的存在的,子类调用的其实是继承自父类的没有重写的方法,
// 看起来像是调用了父类的方法
}
Shape s =
new
Recf();
//这里是声明了一个Shape类型的引用,但实际的对象还是Recf.
s.draw();
//输出的是Recf类重写的方法,证明多态对新类的作用于在旧类中是一样的
}
}
class
Shape{
//基类
public
void
draw(){}
public
void
erase(){}
public
void
newMethod(){
System.out.println(
"new method"
);
//添加的新方法
}
}
class
Circle
extends
Shape{
@Override
//添加注解,一般IDE可以自动添加
public
void
draw() {
System.out.println(
"draw circle"
);
}
@Override
public
void
erase() {
System.out.println(
"erase circle"
);
}
}
class
Square
extends
Shape{
@Override
public
void
draw() {
System.out.println(
"draw Square"
);
}
@Override
public
void
erase() {
System.out.println(
"erase Square"
);
}
@Override
public
void
newMethod() {
System.out.println(
"Square new method"
);
//重写后该类输出内容就发生改变,没有重写时该类的该方法与父类运行结果相同
//无论重写与否,其实调用的都是自身的方法
//只是没有重写时方法调用结果与父类的相同
}
}
class
Triangle
extends
Shape{
@Override
public
void
draw() {
System.out.println(
"draw Triangle"
);
}
@Override
public
void
erase() {
System.out.println(
"erase Triangle"
);
}
}
class
Recf
extends
Shape{
//新添加的方法
@Override
public
void
draw() {
System.out.println(
"recf draw"
);
}
@Override
public
void
erase() {
System.out.println(
"recf erase"
);
}
}
class
RandonShapeGenerator{
//是一种工厂,用以随机获取一种Shape的子类
private
Random rand =
new
Random(
100
);
public
Shape next(){
switch
(rand.nextInt(
3
)){
default
:
case
0
:
return
new
Circle();
case
1
:
return
new
Square();
case
2
:
return
new
Triangle();
}
}
}
|
练习(5):以练习1为基础,才Cycle中添加wheels()方法,它将返回轮子的数量。修改ride()方法,让它调用wheels()方法,并验证多态起作用了.
在练习(1)的代码中给基类添加 。
1
2
3
|
public
void
wheels(){
System.out.println(
"轮子数量是"
+ num);
}
|
然后在main中:
1
2
3
|
unicycle.wheels();
bicycle.wheels();
tricycle.wheels();
|
最后输出结果都顺利输出了方法中的语句,证明多态确实起作用了.
练习(6):修改Music3.java,是what()方法成为根Object的toString()方法。试用System.out.pringtln()方法打印Instrument对象(不用向上转型). 。
练习(7):向Music3.java添加一个新的类型Instrument,并验证多态性是否作用于所添加的新类型. 。
练习(8):修改Music3.java,使其可以向Shapes.java中的方式那样随机创建Instrument对象.
三个练习将在一份代码完成.
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
public
class
Test678 {
public
static
void
main(String[] args){
Instrument[] orchestar = {
new
Wind(),
new
Percussion(),
new
Stringed(),
new
Brass(),
new
Woodwing()
};
tuneAll(orchestar);
newInstrument ni =
new
newInstrument();
ni.play(Note.B_FLAT);
//验证多态性是否适用于所添加的新类型,答案是确实适用。
}
public
static
void
tune(Instrument instrument){
instrument.play(Note.MIDDLE_C);
//无论传进声明子类,都播放MIDDLE_C
}
public
static
void
tuneAll(Instrument[] e){
for
(Instrument i :
e) {
tune(i);
System.out.println(i.toString());
}
}
}
class
RandomInsFactory{
//工厂类,用于随机生成一个Instrument的子类
private
Random ran =
new
Random(
47
);
public
Instrument next(){
switch
(ran.nextInt(
5
)){
default
:
case
0
:
return
new
Wind();
case
1
:
return
new
Percussion();
case
2
:
return
new
Stringed();
case
3
:
return
new
Brass();
case
4
:
return
new
Woodwing();
case
5
:
return
new
newInstrument();
}
}
}
enum
Note{
//枚举类,存放了哪些音乐
MIDDLE_C,C_HARPE,B_FLAT;
}
class
Instrument {
void
play(Note note){
System.out.println(
"Instrument.play() : "
+ note);
}
String what(){
return
"Instrument"
;
}
void
adjust(){
System.out.println(
"adjusting Instrument"
);
}
@Override
public
String toString() {
// /添加一个toString方法,调用当前what方法,
// 子类会自动继承该方法并分别返回给自what()里的内容
return
what();
}
}
class
Wind
extends
Instrument{
@Override
void
play(Note note) {
System.out.println(
"Wind.play() : "
+ note);
}
@Override
String what() {
return
"Wind"
;
}
@Override
void
adjust() {
System.out.println(
"adjusting Wind"
);
}
}
class
Percussion
extends
Instrument{
@Override
void
play(Note note) {
System.out.println(
"Percussion.play() : "
+ note);
}
@Override
String what() {
return
"Percussion"
;
}
@Override
void
adjust() {
System.out.println(
"adjusting Percussion"
);
}
}
class
Stringed
extends
Instrument{
@Override
void
play(Note note) {
System.out.println(
"Stringed.play() : "
+ note);
}
@Override
String what() {
return
"Stringed"
;
}
@Override
void
adjust() {
System.out.println(
"adjusting Stringed"
);
}
}
class
Brass
extends
Wind{
//继承自Wind
@Override
void
play(Note note) {
System.out.println(
"Brass.play() : "
+ note);
}
@Override
void
adjust() {
System.out.println(
"adjusting Brass"
);
}
}
class
Woodwing
extends
Wind{
@Override
void
play(Note note) {
System.out.println(
"Woodwing.play() : "
+ note);
}
@Override
String what() {
return
"Woodwing"
;
}
}
class
newInstrument
extends
Instrument{
//新添加的类型
@Override
void
play(Note note) {
System.out.println(
"newIns.play()"
+ note);
}
}
|
练习(9):创建Rodent(啮齿动物):Mouse(老鼠),Gerbil(鼹鼠),Hamster(大颊鼠),等等这样一个的继承层次结构。在基类中,提供对所有的Rodent都通用的方法,在导出类中,根据特定的Rodent类型覆盖这些方法,以便观察它们执行不同的行为。创建一个Rodent数组,填充不同的Rodent类型,然后调用基类方法,观察发生了什么情况.
这跟前面Instrument的例子相似,在Instrument中有what()这个对所有Instrument都通用的方法,而在每个子类中我们都覆盖了这个方法并赋予了不同的行为,最终在main中创建了Instrument数组,调用了基类方法,最后得到的结果是不同类调用基类方法得到的输出是该类重写后的结果。不再重复.
练习(10):创建一个包含两个方法的基类。在第一个方法中可以调用第二个方法。然后产生一个继承自该基类的导出类,且覆盖基类中的第二个方法。为该导出类创建一个对象,将它向上转型为基类并调用第一个方法,解释发生的情况.
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
|
public
class
Test10 {
public
static
void
main(String[] args){
jilei j =
new
daochulei();
//创建导出类的对象并转型为基类
j.first();
//调用第一个方法
//结果输出daochulei is running
//原因,就像前面提过的,导出类继承了基类的所有东西,没有重写的方法隐藏了起来
//其实在daochulei中还隐士的有void first()这个方法里调用了自身重写的second()
//当daochulei调用first()方法后,它就调用了自身重写的second()方法。
//导出类调用基类方法其实不是真的调用,而是调用自身继承自基类的方法,
// 只不过这个方法没重写时,内部形式与基类相同
}
}
class
jilei{
void
first(){
//调用第二个方法
second();
}
void
second(){
System.out.println(
"first is running"
);
}
}
class
daochulei
extends
jilei{
@Override
void
second() {
System.out.println(
"daochulei is running"
);
}
}
|
练习(11)跳过 。
练习(12):修改练习(9),使其能够演示基类和导出类的初始化顺序。然后向基类和导出类中添加成员对象,并说明构建期间初始化发生的顺序.
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
|
public
class
Test912 {
public
static
void
main(String[] args){
new
Hamster();
}
}
class
Rodent{
public
Rodent(){
shanghai =
100
;
System.out.println(
"Rodent"
);
}
private
int
shanghai;
public
void
bite(){
System.out.println(
"造成伤害"
+shanghai +
"点"
);
}
}
class
Mouse
extends
Rodent{
private
int
sh;
public
Mouse(){
sh =
1000
;
System.out.println(
"Mouse"
);
}
@Override
public
void
bite() {
System.out.println(
"造成伤害"
+sh +
"点"
);
}
}
class
Gerbil
extends
Mouse{
private
int
shang;
public
Gerbil(){
shang =
2000
;
System.out.println(
"Gerbil"
);
}
@Override
public
void
bite() {
System.out.println(
"造成伤害"
+shang +
"点"
);
}
}
class
Hamster
extends
Gerbil{
private
Mouse mouse =
new
Mouse();
//成员对象
//该类初始化输出结果
//Rodent
// Mouse
// Gerbil
// Rodent
// Mouse
// Hamster
//可以分析出,初始化时先调用基类的构造方法,
// 然后初始化成员变量,因为其中有Mouse这个成员对象,所有对Mouse进行初始化,
// 完成后再调用自身的构造方法
private
int
hai;
public
Hamster(){
hai =
3000
;
System.out.println(
"Hamster"
);
}
@Override
public
void
bite() {
System.out.println(
"造成伤害"
+ hai +
"点"
);
}
}
|
总结 。
以上就是本文关于Java编程—在测试中考虑多态的全部内容,希望对大家有所帮助。如有不足之处,欢迎留言指出。感谢朋友们对本站的支持! 。
原文链接:https://www.2cto.com/kf/201609/546918.html 。
最后此篇关于Java编程—在测试中考虑多态的文章就讲到这里了,如果你想了解更多关于Java编程—在测试中考虑多态的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我来自 Asp.Net 世界,试图理解 Angular State 的含义。 什么是 Angular 状态?它类似于Asp.Net中的ascx组件吗?是子页面吗?它类似于工作流程状态吗? 我听到很多人
我一直在寻找 3 态拨动开关,但运气不佳。 基本上我需要一个具有以下状态的开关: |开 |不适用 |关 | slider 默认从中间开始,一旦用户向左或向右滑动,就无法回到N/A(未回答)状态。 有人
我是一名优秀的程序员,十分优秀!