JavaSE_面向对象(封装、继承、多态)
2015-06-23 11:37
513 查看
面向对象的三大特性:封装、继承、多态
一、封装
是指对象应对外部环境隐藏它内部的工作方式,通过封装增加数据的访问权限从而增强了程序的可维护性。
涉及到4中权限:private、public、protected、缺省(default)。
这四个修饰符修饰类中属性和方法对应的权限
---------------------------------------------------------------------------------
类内部 package内 子类 其他
public 允许 允许 允许 允许
protected 允许 允许 允许 不允许
default 允许 允许 不允许 不允许
private 允许 不允许 不允许 不允许
---------------------------------------------------------------------------------
二、继承
通过类Father派生出一个类Son: class Son extends Father;我们就说Son继承了Father。
1)Father类称为父类、超类、基类,最常说的是父类或者基类。
2)Son类称为子类、派生类,常说子类。
3)一个子类只能继承于一个父类,但是一个父类可以被多个子类继承。
4)实际上,子类是对父类的扩充,它不仅继承了父类中的构造器、属性、方法,还可以定义自己特有的属性方法。
5)当子类要定义一个和父类同名的方法时,子类的方法会覆盖或重写父类方法。
6)当一个子类继承于一个父类,它拥有父类所有的public/protected方法,当父类的这些方法不满足子类需求我们可以定义接口或者写子类自己的方法。
举例:
[java] view
plaincopy
package test;
class Test {
public static void main(String[] args) {
Man m = new Man("张三", 23);
System.out.println(m.getName());
}
}
public class Person {
private String name;
private int age;
Person(String name, int age){
this.name = name;
this.age = age;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return this.age;
}
}
class Man extends Person{
public Man(String name, int age){
super(name, age);
}
}
三、多态
class S extends F;
1. 什么是多态性?
1)可以理解为同一个事物多种不同的表现形式,一个接口多个方法。
2)一个S变量既可以引用一个S类对象,也可以引用S类的任意一个子类的对象。
3)方法的重写和重载是Java多态性的不同体现。方法的重写是父类和子类之间多态性的体现,而方法重载是一个类中一种多态性的表现。
2.多态存在的三个必要条件?
1)要有继承 ---> class S extends F;
2)要有方法的重写
3)父类引用指向子类对象 ---> F f = new S();
3.多态的好处
1)
2)
3)
4)
下面放一个头疼的例子帮助自己理解,花了近半个小时才理解...坑:
[java] view
plaincopy
package test;
public class test{
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println(a1.show(b)); //1
System.out.println(a1.show(c)); //2
System.out.println(a1.show(d)); //3
System.out.println(a2.show(b)); //4
System.out.println(a2.show(c)); //5
System.out.println(a2.show(d)); //6
System.out.println(b.show(b)); //7
System.out.println(b.show(c)); //8
System.out.println(b.show(d)); //9
}
}
class A {
public String show(D obj){
return ("A and D");
}
public String show(A obj){
return ("A and A");
}
}
class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
class C extends B{}
class D extends B{}
正确答案在这里:
1.A and A
2.A and A
3.A and D
4.B and A
5.B and A
6.A and D
7.B and B
8.B and B
9.A and D
相信很多初学者和我一样得出的答案和正确答案大相径庭,那么接下来让我们好好分析一下:
首先,这里涉及到一个方法调用的优先级,由高到低:this.show(0),super.show(0),this.show(super0),super.show(super0);this代表的是引用类型,0是被引用对象。
有个技巧,编译时看左边,运行时看右边。
1. a1.show(b): A a1 = new A(); B b = new B(); this.show(0)-->a1.show(B),类A中并无此方法super.show(0)-->类A无父类this.show(super0)-->a1.show(superB)-->a1.show(A)-->得到答案AA;
2. 原理和1相同。
3. 原理和1、2相同。
4. a2.show(b):a2是一个类型为A的引用变量,在类A中没有show(B)方法。同样的类A没有父类。this.show(super0)-->a2.show(superB)-->a2.show(A),在类A中可以找到方法show(A),那么答案就是AA?显然是不对的,因为a2是指向其
子类B的,在类B中我们重写了方法show(A),所以父类中的show(A)方法被子类的show(A)覆盖了,因此应该执行的是类B中的show(A)得到答案BA。
5. a2.show(c):a2是一个类型为A的引用变量,在类A中没有show(C)方法。同样的类A没有父类。this.show(super0)-->a2.show(superC)-->a2.show(B)仍然没有道理参考4。得到答案BA
6. a2.show(d): a2是一个类型为A的引用变量,在类A中有show(D)方法,且在子类B中此方法并未重写,所以得答案AD。
7. b.show(b): b是类型为B的引用,类B中有方法show(B),直接得到答案BB。
8. b.show(c): 根据方法调用的优先级。1)类B中没有show(C)方法 2)A.show(C)方法也不存在 3)b.show(B)存在得到答案BB
9. b.show(d): 根据方法调用的优先级。1)类B中没有show(D)方法 2)A中有show(D)方法没有在子类B中重写,所以执行A.show(D)得到答案AD。
总结:
当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。还拿a2.show(b)来说吧。
a2是一个引用变量,类型为A,它引用的是B的一个对象,因此这句话的意思是由B来决定调用的是哪个方法。因此应该调用B的show(B obj)从而输出"B and B”才对。但是为什么跟前面的分析得到的结果不相符呢?!
问题在于:这个被调用的方法必须是在超类中定义过的,也就是被子类覆盖的方法。B里面的show(B obj)在超类A中有定义吗?没有!那就更谈不上被覆盖了。
实际上这句话隐藏了一条信息:它仍然是按照方法调用的优先级来确定的。它在类A中找到了show(A obj),如果子类B没有覆盖show(A obj)方法,那么它就调用A的show(A obj)(由于B继承A,虽然没有覆盖这个方法,
但从超类A那里继承了这个方法,从某种意义上说,还是由B确定调用的方法,只是方法是在A中实现而已);现在子类B覆盖了show(A obj),因此它最终锁定到B的show(A obj)。这就是那句话的意义所在,到这里,
我们可以清晰的理解Java的多态性了。
PS:从网上搜到了一个很好的面试回答再加以巩固多态的概念:
简述多态概念、作用?
1)多态有编译时多态、运行时多态。
2)多态体现在两个方面:
函数的重载,在同一类中根据不同类型的参数执行不同的方法。比如程序中做加法操作两个int相加和两个double相加,方法名可以相同但是执行的方法却不同。
函数的重写,即动态绑定。使用父类引用指向子类对象,在调用父类的同一方法时不同子类结果不尽相同。这样的好处就是互不干涉且具有良好的扩展性。一个例子:在DNF(游戏)中,人物角色是个父类,鬼剑士、神枪手等具体的角色
都是人物角色的子类,它们都可以进行普通攻击但是表现出来的形式却不同,鬼剑士是挥刀,神枪手是射子弹。这就是多态的体现,比如以后我想修改鬼剑士的普通攻击效果只需要对鬼剑士类进行修改即可。如果以后再要扩展角色,只要
新建角色类重写父类中相应的方法而不需要对之前的代码进行任何改动。
3)降低代码的耦合度。
一、封装
是指对象应对外部环境隐藏它内部的工作方式,通过封装增加数据的访问权限从而增强了程序的可维护性。
涉及到4中权限:private、public、protected、缺省(default)。
这四个修饰符修饰类中属性和方法对应的权限
---------------------------------------------------------------------------------
类内部 package内 子类 其他
public 允许 允许 允许 允许
protected 允许 允许 允许 不允许
default 允许 允许 不允许 不允许
private 允许 不允许 不允许 不允许
---------------------------------------------------------------------------------
二、继承
通过类Father派生出一个类Son: class Son extends Father;我们就说Son继承了Father。
1)Father类称为父类、超类、基类,最常说的是父类或者基类。
2)Son类称为子类、派生类,常说子类。
3)一个子类只能继承于一个父类,但是一个父类可以被多个子类继承。
4)实际上,子类是对父类的扩充,它不仅继承了父类中的构造器、属性、方法,还可以定义自己特有的属性方法。
5)当子类要定义一个和父类同名的方法时,子类的方法会覆盖或重写父类方法。
6)当一个子类继承于一个父类,它拥有父类所有的public/protected方法,当父类的这些方法不满足子类需求我们可以定义接口或者写子类自己的方法。
举例:
[java] view
plaincopy
package test;
class Test {
public static void main(String[] args) {
Man m = new Man("张三", 23);
System.out.println(m.getName());
}
}
public class Person {
private String name;
private int age;
Person(String name, int age){
this.name = name;
this.age = age;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return this.age;
}
}
class Man extends Person{
public Man(String name, int age){
super(name, age);
}
}
三、多态
class S extends F;
1. 什么是多态性?
1)可以理解为同一个事物多种不同的表现形式,一个接口多个方法。
2)一个S变量既可以引用一个S类对象,也可以引用S类的任意一个子类的对象。
3)方法的重写和重载是Java多态性的不同体现。方法的重写是父类和子类之间多态性的体现,而方法重载是一个类中一种多态性的表现。
2.多态存在的三个必要条件?
1)要有继承 ---> class S extends F;
2)要有方法的重写
3)父类引用指向子类对象 ---> F f = new S();
3.多态的好处
1)
2)
3)
4)
下面放一个头疼的例子帮助自己理解,花了近半个小时才理解...坑:
[java] view
plaincopy
package test;
public class test{
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println(a1.show(b)); //1
System.out.println(a1.show(c)); //2
System.out.println(a1.show(d)); //3
System.out.println(a2.show(b)); //4
System.out.println(a2.show(c)); //5
System.out.println(a2.show(d)); //6
System.out.println(b.show(b)); //7
System.out.println(b.show(c)); //8
System.out.println(b.show(d)); //9
}
}
class A {
public String show(D obj){
return ("A and D");
}
public String show(A obj){
return ("A and A");
}
}
class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
class C extends B{}
class D extends B{}
正确答案在这里:
1.A and A
2.A and A
3.A and D
4.B and A
5.B and A
6.A and D
7.B and B
8.B and B
9.A and D
相信很多初学者和我一样得出的答案和正确答案大相径庭,那么接下来让我们好好分析一下:
首先,这里涉及到一个方法调用的优先级,由高到低:this.show(0),super.show(0),this.show(super0),super.show(super0);this代表的是引用类型,0是被引用对象。
有个技巧,编译时看左边,运行时看右边。
1. a1.show(b): A a1 = new A(); B b = new B(); this.show(0)-->a1.show(B),类A中并无此方法super.show(0)-->类A无父类this.show(super0)-->a1.show(superB)-->a1.show(A)-->得到答案AA;
2. 原理和1相同。
3. 原理和1、2相同。
4. a2.show(b):a2是一个类型为A的引用变量,在类A中没有show(B)方法。同样的类A没有父类。this.show(super0)-->a2.show(superB)-->a2.show(A),在类A中可以找到方法show(A),那么答案就是AA?显然是不对的,因为a2是指向其
子类B的,在类B中我们重写了方法show(A),所以父类中的show(A)方法被子类的show(A)覆盖了,因此应该执行的是类B中的show(A)得到答案BA。
5. a2.show(c):a2是一个类型为A的引用变量,在类A中没有show(C)方法。同样的类A没有父类。this.show(super0)-->a2.show(superC)-->a2.show(B)仍然没有道理参考4。得到答案BA
6. a2.show(d): a2是一个类型为A的引用变量,在类A中有show(D)方法,且在子类B中此方法并未重写,所以得答案AD。
7. b.show(b): b是类型为B的引用,类B中有方法show(B),直接得到答案BB。
8. b.show(c): 根据方法调用的优先级。1)类B中没有show(C)方法 2)A.show(C)方法也不存在 3)b.show(B)存在得到答案BB
9. b.show(d): 根据方法调用的优先级。1)类B中没有show(D)方法 2)A中有show(D)方法没有在子类B中重写,所以执行A.show(D)得到答案AD。
总结:
当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。还拿a2.show(b)来说吧。
a2是一个引用变量,类型为A,它引用的是B的一个对象,因此这句话的意思是由B来决定调用的是哪个方法。因此应该调用B的show(B obj)从而输出"B and B”才对。但是为什么跟前面的分析得到的结果不相符呢?!
问题在于:这个被调用的方法必须是在超类中定义过的,也就是被子类覆盖的方法。B里面的show(B obj)在超类A中有定义吗?没有!那就更谈不上被覆盖了。
实际上这句话隐藏了一条信息:它仍然是按照方法调用的优先级来确定的。它在类A中找到了show(A obj),如果子类B没有覆盖show(A obj)方法,那么它就调用A的show(A obj)(由于B继承A,虽然没有覆盖这个方法,
但从超类A那里继承了这个方法,从某种意义上说,还是由B确定调用的方法,只是方法是在A中实现而已);现在子类B覆盖了show(A obj),因此它最终锁定到B的show(A obj)。这就是那句话的意义所在,到这里,
我们可以清晰的理解Java的多态性了。
PS:从网上搜到了一个很好的面试回答再加以巩固多态的概念:
简述多态概念、作用?
1)多态有编译时多态、运行时多态。
2)多态体现在两个方面:
函数的重载,在同一类中根据不同类型的参数执行不同的方法。比如程序中做加法操作两个int相加和两个double相加,方法名可以相同但是执行的方法却不同。
函数的重写,即动态绑定。使用父类引用指向子类对象,在调用父类的同一方法时不同子类结果不尽相同。这样的好处就是互不干涉且具有良好的扩展性。一个例子:在DNF(游戏)中,人物角色是个父类,鬼剑士、神枪手等具体的角色
都是人物角色的子类,它们都可以进行普通攻击但是表现出来的形式却不同,鬼剑士是挥刀,神枪手是射子弹。这就是多态的体现,比如以后我想修改鬼剑士的普通攻击效果只需要对鬼剑士类进行修改即可。如果以后再要扩展角色,只要
新建角色类重写父类中相应的方法而不需要对之前的代码进行任何改动。
3)降低代码的耦合度。
相关文章推荐
- java mail
- java1.5新增Enum(枚举类)
- 【j2ee spring】37、巴巴运动网的产品品牌修改和查询
- Java培训Java序列化与static
- Java编程基础抽象类
- java中读取文件以及向文件中追加数据的总结
- Java面向对象的三大特征
- Java 读取数据流的几种情况总结
- Java编程基础抽象类
- stackoverflow中关于数组方法
- 浅析Java线程的三种实现
- 使用Spring2.5的Autowired实现注释型的IOC
- 第二个Spring冲刺周期团队进展报告
- Java类的继承总结
- Maven中央仓库信息速查 网址,java 源码下载地址
- java自带定时器 ScheduledExecutor
- Java高质量代码之面向对象
- JAVA使用POI如何导出百万级别数据
- Java类集框架
- Java内部类学习笔记