黑马程序员——Java基础—面向对象(二)
2015-04-02 20:37
162 查看
———Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ———
一继承
二final关键字
三抽象类
四接口
面向对象(二)
将多个类的共性抽取出来,形成一个父类。让所有具备这些共性属性的类,继承这个父类,成为其子类。这样做的好处在于:
1)这样可以避免重复代码,提高代码复用性;
2)继承是面向对象另一特点多态的基础之一,有了继承,才有多态;
3)同时可以使子类的功能更加强大灵活,便于扩展
注意:
1)不要仅为了获取其他类的功能,而使用继承;必须在类与类之间有所属关系的情况下,才使用继承;
2)Java中只支持单继承。因为多继承容易带来安全隐患。如果支持多继承,多个父类当中有相同名字的不同功能的方法,子类在调用同名方法的时候,虚拟机不能确定要运行哪个;
3)Java中保留了多继承的机制,用多实现的方式来体现(implements);
4)Java支持多层继承,C继承B,B继承A,以此类推,形成一个继承体系。继承体系相对复杂,想要良好运用该体系,先查阅体系中父类的描述,通过了解父类中的共性功能,就能了解该继承体系的基本功能。在具体调用时,应创建最小子类的对象。由于:
1> 父类不能创建对象,如抽象类;
2> 子类对象有更多的功能,包括父类和自由的功能
2.继承的表现形式
类与类之间不止有A属于B这一种关系,还有聚集的关系。聚集关系分为:
1)聚合关系:A由B组成,B是A中的一个,但是缺少一个B,不影响A的整体功能;例如:球队由球员组成,一个球员是球队的一员;
2)组合关系:A由B组成,B是A的一部分,缺少B,A的功能将受到极大影响;例如:心脏是人的一部分
3.继承的应用
1)super关键字
1>
2>
2)这一小节探讨继承关系出现后,类中成员的变化
1> 变量的变化
示例代码:
继承状态下,成员变量内存加载图示:
继承状态下,成员变量的变化如下:
如果子类和父类中出现非私有同名变量,子类要访问本类中的同名变量,用
小扩展:
继承的时候,子类继承父类的成员变量,同时继承该成员变量的值。
示例代码:
2> 方法的变化
示例代码:
继承状态下,成员方法的变化如下:
当子类出现和父类一模一样的方法时,子类对象调用同名方法,会运行子类方法的内容。由于子类继承了父类的方法,但是子类在具体实现的时候需要有不同的功能,这个时候,只需要用到方法的另一个特性:复写。在子类中定义一个和父类完全相同的方法,在方法体中实现子类的特有功能即可。如果要在子类的复写方法中,调用父类的方法,只需要加上
小扩展:
super关键字的使用
示例代码:
子类对象调用
复写注意事项:
a. 复写成功必须保证子类方法权限大于等于父类方法权限;
b. 静态方法只能复写静态方法;
c. 复写和重载的区别在与,复写要求子类父类方法一模一样,重载要求同名函数的参数列表不一样
3> 构造方法的变化
示例代码:
子类对象进行初始化时,父类的构造方法也会执行。因为子类的构造方法第一行默认写有隐式语句
子类一定要访问父类构造方法的原因:
由于子类继承了父类的成员,子类对象在被创建时,应该先知道父类是如何对其成员进行初始化的,以避免代码功能的重复。
注意:
构造函数中,this和super只能存在一个,因为两者都必须写在构造方法第一行。
final作为一个修饰符:
1)可以修饰类,变量以及方法;
2)被
3)被
4)被
5)内部类定义在类中的局部位置上时,只能访问该局部被final修饰的局部变量
示例代码:
抽象就是将多个事物的共性的、本质的内容进行抽取和概括。例如:老虎,猫,狮子都是猫科动物,猫科就是一个抽象的概念。
2.抽象类
抽象类是包含抽象方法的类。抽象方法只有方法的定义,没有方法体。抽象方法的具体实现,有子类复写完成。抽象方法只负责抽象出不同对象的共性,但是不涉及具体实现的细节。例如:猫和狗都会叫,但是叫的内容不同。抽象方法定义一个叫的功能,具体叫的内容则有子类对象来实现。
3.抽象类的特点
1)抽象方法一定定义在抽象类中;
2)抽象方法和抽象类都被
3)抽象类不可以实例化;
4)抽象类中的抽象方法要被使用,必须由子类复写其所有抽象方法,由子类对象进行调用;如果子类中只覆盖了部分抽象方法,那么该子类还是一个抽象类;
5)抽象类中可以不定义抽象方法,仅为了让该类不被实例化
代码示例:
4.抽象类练习
1)练习1:
开发一个系统需要对员工进行建模,员工包含3个属性:姓名,工号以及工资;经理也是员工,除了含有员工的属性外,另外还有一个奖金属性。请使用继承的思想设计出员工类和经理类。
示例代码:
2)练习2:模版方法模式
使用
示例代码:
如果
示例代码:
现在想运行另外一段代码,直接修改源代码的方式操作性极差。那么可以运用一个类,继承
示例代码:
进一步,在
示例代码:
这是模版方法设计模式。在定义功能时,功能的一部分是确定的,有一部分不确定;而确定的部分在使用不确定的部分。这时,就将不确定的部分暴露出去,由该类的子类来实现不确定的部分。
在Java中,用
其他类可以通过
2.接口的特点
1)接口中通常定义常量和抽象方法
2)接口中的成员有固定的修饰符
常量:
方法:
示例代码:
3)接口中的成员都是public权限
4)接口不能实例化
5)子类必须复写接口中的所有抽象方法才能实例化
6)一个类可以实现多个接口
示例代码:
7)一个类可以在继承之后继续实现一个或多个接口
示例代码:
8)接口和接口之间可以继承
示例代码:
9)接口之间可以多继承 原因是抽象方法没有方法体,具体方法,具体实现即可
示例代码:
3.接口的应用
在描述问题的时候,如果是类的基本功能,就可以提取到抽象类类当中,将功能定义为方法或抽象方法。如果是类可以具备,但是不是必要的扩展功能,可以定义在接口中,作为类的功能扩展。
示例代码:
示例代码中,编程和睡觉,可以作为IT男的基本功能被提取到
———Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ———
一继承
二final关键字
三抽象类
四接口
面向对象(二)
一、继承
1.继承概述将多个类的共性抽取出来,形成一个父类。让所有具备这些共性属性的类,继承这个父类,成为其子类。这样做的好处在于:
1)这样可以避免重复代码,提高代码复用性;
2)继承是面向对象另一特点多态的基础之一,有了继承,才有多态;
3)同时可以使子类的功能更加强大灵活,便于扩展
注意:
1)不要仅为了获取其他类的功能,而使用继承;必须在类与类之间有所属关系的情况下,才使用继承;
2)Java中只支持单继承。因为多继承容易带来安全隐患。如果支持多继承,多个父类当中有相同名字的不同功能的方法,子类在调用同名方法的时候,虚拟机不能确定要运行哪个;
3)Java中保留了多继承的机制,用多实现的方式来体现(implements);
4)Java支持多层继承,C继承B,B继承A,以此类推,形成一个继承体系。继承体系相对复杂,想要良好运用该体系,先查阅体系中父类的描述,通过了解父类中的共性功能,就能了解该继承体系的基本功能。在具体调用时,应创建最小子类的对象。由于:
1> 父类不能创建对象,如抽象类;
2> 子类对象有更多的功能,包括父类和自由的功能
2.继承的表现形式
类与类之间不止有A属于B这一种关系,还有聚集的关系。聚集关系分为:
1)聚合关系:A由B组成,B是A中的一个,但是缺少一个B,不影响A的整体功能;例如:球队由球员组成,一个球员是球队的一员;
2)组合关系:A由B组成,B是A的一部分,缺少B,A的功能将受到极大影响;例如:心脏是人的一部分
3.继承的应用
1)super关键字
1>
super关键字和this关键字的用法基本一致;
2>
this代表本类对象的引用,
super代表父类对象的引用
2)这一小节探讨继承关系出现后,类中成员的变化
1> 变量的变化
示例代码:
class Parent { int num = 4; } class Sub extends Parent { int num = 5; void show() { System.out.println(super.num); } } class Test { public static void main(String[] args) { Sub s = new Sub(); s.show(); } }
继承状态下,成员变量内存加载图示:
继承状态下,成员变量的变化如下:
如果子类和父类中出现非私有同名变量,子类要访问本类中的同名变量,用
this关键字;子类要访问父类中的同名变量,用
super关键字。
小扩展:
继承的时候,子类继承父类的成员变量,同时继承该成员变量的值。
示例代码:
class Parent { private int num = 4; } class Sub extends Parent { void show() { System.out.println(num); System.out.println(this.num); } } class Test { public static void main(String[] args) { Sub s = new Sub(); s.show(); } }
2> 方法的变化
示例代码:
class Parent { void show() { System.out.println("Parent show"); } } class Sub extends Parent { void show() { System.out.println("Sub show"); } } class Test { public static void main(String[] args) { Sub s = new Sub(); s.show(); } }
继承状态下,成员方法的变化如下:
当子类出现和父类一模一样的方法时,子类对象调用同名方法,会运行子类方法的内容。由于子类继承了父类的方法,但是子类在具体实现的时候需要有不同的功能,这个时候,只需要用到方法的另一个特性:复写。在子类中定义一个和父类完全相同的方法,在方法体中实现子类的特有功能即可。如果要在子类的复写方法中,调用父类的方法,只需要加上
super.方法名即可。
小扩展:
super关键字的使用
示例代码:
class Parent { void show() { System.out.println("Parent show"); } } class Sub extends Parent { void show() { super.show(); System.out.println("Sub show"); } }
子类对象调用
show()方法时,上述代码既输出
"Parent show",也输出
"Sub show"。
复写注意事项:
a. 复写成功必须保证子类方法权限大于等于父类方法权限;
b. 静态方法只能复写静态方法;
c. 复写和重载的区别在与,复写要求子类父类方法一模一样,重载要求同名函数的参数列表不一样
3> 构造方法的变化
示例代码:
class Parent { Parent() { System.out.println("Parent construct..."); } } class Sub extends Parent { Sub() { //super(); System.out.println("Sub construct..."); } Sub(int x) { //super(); System.out.println("4"); } } class Test { public static void main(String[] args) { Sub s = new Sub(); } }
子类对象进行初始化时,父类的构造方法也会执行。因为子类的构造方法第一行默认写有隐式语句
super();
super()会访问父类中空参数的构造方法。
super();存在于所有子类的所有构造方法的第一行。如果访问父类中指定的构造方法,只需通过手动定义
super语句。
子类一定要访问父类构造方法的原因:
由于子类继承了父类的成员,子类对象在被创建时,应该先知道父类是如何对其成员进行初始化的,以避免代码功能的重复。
注意:
构造函数中,this和super只能存在一个,因为两者都必须写在构造方法第一行。
二、final关键字
1.final的定义及特点final作为一个修饰符:
1)可以修饰类,变量以及方法;
2)被
final修饰的类不能被继承;
3)被
final修饰的方法不能被复写;
4)被
final修饰的变量是常量,值不能被改变;既可以修饰成员变量,也可以修饰局部变量;
5)内部类定义在类中的局部位置上时,只能访问该局部被final修饰的局部变量
示例代码:
//TestFinal被final关键字修饰,不能被继承 final class TestFinal { //PI被final修饰,为常量,值不能修改 private final int PI = 3.14; } class TestFinal { //method1被final关键字修饰,不能被复写 final void method1() { } void method2() { } }
三、抽象类
1.抽象的定义抽象就是将多个事物的共性的、本质的内容进行抽取和概括。例如:老虎,猫,狮子都是猫科动物,猫科就是一个抽象的概念。
2.抽象类
抽象类是包含抽象方法的类。抽象方法只有方法的定义,没有方法体。抽象方法的具体实现,有子类复写完成。抽象方法只负责抽象出不同对象的共性,但是不涉及具体实现的细节。例如:猫和狗都会叫,但是叫的内容不同。抽象方法定义一个叫的功能,具体叫的内容则有子类对象来实现。
3.抽象类的特点
1)抽象方法一定定义在抽象类中;
2)抽象方法和抽象类都被
abstract关键字修饰;
3)抽象类不可以实例化;
4)抽象类中的抽象方法要被使用,必须由子类复写其所有抽象方法,由子类对象进行调用;如果子类中只覆盖了部分抽象方法,那么该子类还是一个抽象类;
5)抽象类中可以不定义抽象方法,仅为了让该类不被实例化
代码示例:
abstract class Employee { abstract void work(); } class Programmer extends Employee { void work() { System.out.println("Program..."); } } class Janitor extends Employee { void work() { System.out.println("Clean..."); } }
4.抽象类练习
1)练习1:
开发一个系统需要对员工进行建模,员工包含3个属性:姓名,工号以及工资;经理也是员工,除了含有员工的属性外,另外还有一个奖金属性。请使用继承的思想设计出员工类和经理类。
示例代码:
package test; public abstract class Employee { /** * 声明员工的三个属性 */ private String name; private String id; private double pay; /** * 声明员工的构造方法,对三个属性进行初始化 * @param name 员工姓名 * @param id 员工工号 * @param pay 员工工资 */ Employee(String name, String id, double pay) { this.name = name; this.id = id; this.pay = pay; } /** * 声明员工的抽象方法;由于每个员工都需要工作,而具体的工作内容不明确,所以声明为抽象方法 */ public abstract void work(); } class Programmer extends Employee { /** * 声明程序员的构造方法,调用父类的构造方法对程序员属性进行初始化 * @param name 程序员姓名 * @param id 程序员工号 * @param pay 程序员工资 */ Programmer(String name, String id, double pay) { super(name, id, pay); } /** * 复写父类的work方法,具体实现程序员的工作 */ public void work() { System.out.println("Programming..."); } } class Manager extends Employee { /** * 声明经理独有的属性 */ private int bonus; /** * 声明经理的构造方法,调用父类的构造方法对经理属性进行初始化 * @param name 经理姓名 * @param id 经理工号 * @param pay 经理工资 * @param bonus 经理奖金 */ Manager(String name, String id, double pay, int bonus) { super(name, id, pay); this.bonus = bonus; } /** * 复写父类的work方法,具体实现经理的工作 */ public void work() { System.out.println("Managing..."); } }
2)练习2:模版方法模式
使用
System类中的
currentTimeMillis()方法获取一段程序运行的时间。
示例代码:
package test; class GetTime { public static void getTime() { /** * 获取程序开始时间 */ long start = System.currentTimeMillis(); /** * 程序执行 */ for(int x = 0; x < 1000; x ++) { System.out.print(x); } /** * 获取程序结束时间 */ long end = System.currentTimeMillis(); /** * 打印程序运行时间 */ System.out.println("Time elapse: " + (end = start)); } } class UpTime { public static void main(String[] args) { GetTime.getTime(); } }
如果
GetTime类要被其他程序使用,来获取程序运行时间,那么该类中所要运行的程序代码是不确定的。因此,首先将要运行的代码提取出来,封装在一个方法中。
示例代码:
package test; class GetTime { public static void getTime() { /** * 获取程序开始时间 */ long start = System.currentTimeMillis(); /** * 程序执行 */ runCode(); /** * 获取程序结束时间 */ long end = System.currentTimeMillis(); /** * 打印程序运行时间 */ System.out.println("Time elapse: " + (end = start)); } /** * 封装要运行的代码块 */ public void runCode() { for(int x = 0; x < 1000; x ++) { System.out.print(x); } } } class UpTime { public static void main(String[] args) { GetTime.getTime(); } }
现在想运行另外一段代码,直接修改源代码的方式操作性极差。那么可以运用一个类,继承
GetTime类,然后以复写
runCode()方法的方式更改要运行的代码,并在主函数中创建子类的对象,调用
getTime()方法即可。
示例代码:
package test; class GetTime { public void getTime() { /** * 获取程序开始时间 */ long start = System.currentTimeMillis(); /** * 程序执行 */ runCode(); /** * 获取程序结束时间 */ long end = System.currentTimeMillis(); /** * 打印程序运行时间 */ System.out.println("Time elapse: " + (end = start)); } /** * 封装要运行的代码块 */ public void runCode() { for(int x = 0; x < 1000; x ++) { System.out.print(x); } } } /** * 声明Sub类,继承GetTime类,复写runCode()方法 */ class Sub extends GetTime { public void runCode() { for(int x = 0; x < 2000; x ++) { System.out.print(x); } } } class UpTime { public static void main(String[] args) { Sub s = new Sub(); s.getTime(); } }
进一步,在
GetTime类中定义一段代码,并没有意义。
GetTime类的作用是计算时间,至于要运行的代码,需要使用
GetTime类的程序来确定。同时,
GetTime类是用来计算时间的,计算时间的方法不需要其他程序来改变,否则该类将失去意义。因此,最好的方式是,将
GetTime类声明为抽象类,将
runCode()方法声明为抽象方法,将
getTime()方法声明为
final方法。子类继承
GetTime类,复写
runCode()抽象方法,写入要运行的代码,再用子类对象调用
getTime()方法计算运行时间。
示例代码:
package test; abstract class GetTime { public final void getTime() { /** * 获取程序开始时间 */ long start = System.currentTimeMillis(); /** * 程序执行 */ runCode(); /** * 获取程序结束时间 */ long end = System.currentTimeMillis(); /** * 打印程序运行时间 */ System.out.println("Time elapse: " + (end = start)); } /** * 声明抽象方法 */ public abstract void runCode(); } /** * 声明Sub类,继承GetTime类,复写runCode()方法 */ class Sub extends GetTime { public void runCode() { for(int x = 0; x < 2000; x ++) { System.out.print(x); } } } class UpTime { public static void main(String[] args) { Sub s = new Sub(); s.getTime(); } }
这是模版方法设计模式。在定义功能时,功能的一部分是确定的,有一部分不确定;而确定的部分在使用不确定的部分。这时,就将不确定的部分暴露出去,由该类的子类来实现不确定的部分。
四、接口
1.定义在Java中,用
interface关键字定义接口。格式为:
interface { }
其他类可以通过
implements关键字实现接口,并复写其功能。接口可以实现”多继承”的机制,即一个类,可以实现多个接口。
2.接口的特点
1)接口中通常定义常量和抽象方法
2)接口中的成员有固定的修饰符
常量:
public static final
方法:
public abstract
示例代码:
interface Inter { public static final int x = 1; public abstract void run(); }
3)接口中的成员都是public权限
4)接口不能实例化
5)子类必须复写接口中的所有抽象方法才能实例化
6)一个类可以实现多个接口
示例代码:
interface A { } interface B { } class C implements A, B { }
7)一个类可以在继承之后继续实现一个或多个接口
示例代码:
interface A { } interface B { } class C { } class D extends C implements A, B { }
8)接口和接口之间可以继承
示例代码:
interface A { } interface B extends A { }
9)接口之间可以多继承 原因是抽象方法没有方法体,具体方法,具体实现即可
示例代码:
interface A { } interface B { } interface C extends A, B { }
3.接口的应用
在描述问题的时候,如果是类的基本功能,就可以提取到抽象类类当中,将功能定义为方法或抽象方法。如果是类可以具备,但是不是必要的扩展功能,可以定义在接口中,作为类的功能扩展。
示例代码:
package test; public class TestInterface { } class ITWorker { public static void program() { System.out.println("Programming..."); } public static void sleep() { System.out.println("Sleeping..."); } } interface FixComputer { abstract void fix(); } class Programmer extends ITWorker implements FixComputer { @Override public void fix() { System.out.println("Reinstall OS..."); } }
示例代码中,编程和睡觉,可以作为IT男的基本功能被提取到
ITWorker类当中;而修电脑,则作为扩展功能,定义成接口,让有修电脑能力的程序员,实现这个接口即可,而没有修电脑功能的程序员,只用继承IT男的基本功能。
———Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ———
相关文章推荐
- 黑马程序员——Java基础之面向对象(3)——第九篇
- 黑马程序员---Java基础--08天(面向对象之三多态)
- 黑马程序员_Java基础_面向对象(概述、类与对象关系、成员变量、封装private、构造函数和构造代码块、this关键字)
- 黑马程序员:java基础学习——面向对象
- 黑马程序员_Java基础_面向对象(内部类、异常1)
- 黑马程序员——Java基础之面向对象(4)——第十篇
- 黑马程序员_Java基础_面向对象(异常2、练习题、导包)
- 黑马程序员____基础____java的面向对象
- 黑马程序员_Java基础_面向对象(Static的使用、对象初始化和调用成员过程、单例设计模式)
- 黑马程序员-----笔记整理(java基础五-------面向对象--多态)
- 黑马程序员-Java语言基础–面向对象 第9天
- 黑马程序员-Java语言基础–面向对象 第5天
- 黑马程序员_Java基础_面向对象(继承、子父类变量和函数以及构造函数特点、final关键字、抽象类、模版方法模式、接口)
- 黑马程序员——Java基础之面向对象(1)——第七篇
- 黑马程序员---Java基础--07天(面向对象之三)
- 黑马程序员-Java语言基础 –面向对象 第7天
- 黑马程序员-Java语言基础–面向对象 第8天
- 黑马程序员-----java基础三(之面向对象)
- 黑马程序员_Java基础_面向对象(多态、Object类相关方法)
- 黑马程序员_java编程基础10面向对象