面向对象--继承、多态
1、继承
继承的格式class 子类名 extends 父类名{}
1.1 继承的利处
a、提高了代码的复用性。b、让类与类之间产生了关系。有了这个关系,才有了多态的特性。
必须是类与类之间有所属关系才可以继承。所属关系 is a。
其他关系:
聚集:has a
组合:contains a
java只支持单继承,不支持多继承。支持多实现。
可以多层继承。
1.2 Object类是所用类的父类
常见方法:boolean equals(Object obj):用于比较两个对象是否相同。
String toString():获取对象的字符串表现形式 类名@哈希值
getClass().getName()+"@"+Integer.toHexString(hashCode());
Class getClass():获取正在运行的对象所属的字节码文件的对象。
1.3 super关键字
super和this的用法相同。super代表父类引用。
子类调用父类的构造函数时,可以使用super语句。
当子父类出现同名成员时,可以用super进行区分。
子类要访问本类中的变量,用this
子类要访问父类中的同名变量,用super
2、重载(Overload)和覆写(Override)
覆盖:子类中出现与父类一模一样的方法,会出现覆盖操作,也称为重写或者复写。注意:
a、在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int,float),但是不能为fun(int,int);
b、不能通过访问权限、返回类型、抛出的异常进行重载;
c、方法的异常类型和数目不会对重载造成影响;
d、对于继承来说,如果某一方法在父类中是访问权限是priavte,那么就不能在子类对其进行重载,
如果定义的话,也只是定义了一个新方法,而不会达到重载的效果。
a、子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败。
b、静态只能覆盖静态。
重载表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不同)
覆盖表示子类中的方法可以和父类中的某个方法的名称和参数列表完全相同,通过子类创建的实例对象调用这个方法时,
将调用子类中定义的方法,这相当于把父类中定义的那个完全相同的方法给覆盖了,这也是面向对象编程的多态性的一种表现。
子类覆盖父类的方法时,只能比父类抛出更少的异常,或者是抛出父类抛出的异常的子异常,因为子类可以解决父类的一些问题,
不能比父类有更多的问题。子类方法的访问权限只能比父类的更大,不能更小。如果父类的方法是private类型,
那么,子类则不存在覆盖的限制,相当于子类中增加了一个全新的方法。
构造器不能被继承,因为不能被重写,但可以被重载。
接口可以继承接口。抽象类可以实现(implements)接口,抽象类可继承具体类。抽象类中可以有静态的main方法。
抽象类不能创建实例。
子父类中的构造函数。
在对子类对象进行初始化时,父类的构造函数也会运行。
这是由于子类的构造函数默认第一行有一条隐式的语句super();
如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。
当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定要访问父类中的构造函数。
注意:
子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。
子类中至少会有一个构造函数会访问父类中的构造函数。
final:最终,作为一个修饰符。
1、可以修饰类、函数、变量。
2、被final修饰的类不可以被继承。为了避免被继承。被子类复写功能。
3、被final修饰的变量时一个常量只能赋值一次,既可以修饰成员变量,又可以修饰局部变量。
常量:书写规范所有字母都大写,如果由多个单词组成,通过_连接。
4、内部类定义在类中的局部位置上,只能访问该局部被final修饰的局部变量。
2、抽象类
抽象类的特定:
1、抽象方法一定在抽象类中。
2、抽象方法和抽象类都必须被abstract关键字修饰。
3、抽象类不可以用new创建对象。
4、抽象类中的抽象方法要被使用,必须由子类复写起所有的抽象方法后,建立子类对象调用。
如果子类只覆盖了部分抽象方法,那么子类还是一个抽象类。
2.1 抽象关键字不可以和private/static/final共存。
final:被final修饰的类不能有子类。而被abstract修饰的类一定是一个父类。private:抽象类中的私有的抽象方法,不被子类所知,就无法被复写。
static:如果static可以修饰抽象方法,那么连对象都省了,直接类名调用就可以了。可是抽象方法运行没意义。
抽象类中有构造方法,作为父类,需要给子类提供实例的初始化。
/* 假如我们在开发一个系统时需要对员工进行建模,员工包含 3 个属性: 姓名、工号以及工资。经理也是员工,除了含有员工的属性外,另为还有一个 奖金属性。请使用继承的思想设计出员工类和经理类。要求类中提供必要的方 法进行属性访问。 员工类:name id pay 经理类:继承了员工,并有自己特有的bonus。 */ class Employee { private String name; private String id; private double pay; Employee(String name,String id,double pay) { this.name = name; this.id = id; this.pay = pay; } public abstract void work(); } class Manager extends Employee { private int bonus; Manager(String name,String id,double pay,int bonus) { super(name,id,pay); this.bonus = bonus; } public void work() { System.out.println("manager work"); } } class Pro extends Employee { Pro(String name,String id,double pay) { super(name,id,pay); } public void work() { System.out.println("pro work"); } }
2.2 接口:是一个特殊的抽象类
class用于定义类。interface用于定义接口。
格式如下:
固定修饰符:
常量:public static final
方法:public abstract
接口不可以创建对象,需要被子类实现,子类对接口中的抽象方法全覆盖后,子类才可以实例化。否则子类是一个抽象类。
接口可以被类多实现,java支持多实现。一个类可以继承一个类的同时,实现多个接口。
应用特点:
1、接口是对外曝露的规则。
2、接口是功能的扩展。
3、接口的出现降低了耦合性。
2.3 抽象类和接口异同
相同:1、都可以在内部定义抽象方法。
2、通常都在顶层。
3、都不可以实例化,都需要子类来实现。
不同点:
1、抽象类中可以定义抽象方法和非抽象方法,而接口中只能定义抽象方法。
2、接口的出现可以多实现,抽象类只能单继承。
3、继承和实现的关系不一致。继承:is a,实现 like a.
interface Inter { public static final int NUM = 3; public abstract void show(); } interface InterA { public abstract void show(); } class Demo { public void function(){} } class Test extends Demo implements Inter,InterA { public void show(){} } interface A { void methodA(); } interface B //extends A { void methodB(); } interface C extends B,A { void methodC(); } class D implements C { public void methodA(){} public void methodC(){} public void methodB(){} } class InterfaceDemo { public static void main(String[] args) { Test t = new Test(); System.out.println(t.NUM); System.out.println(Test.NUM); System.out.println(Inter.NUM); } }
3、模板方法设计模式
/* 需求:获取一段程序运行的时间。 原理:获取程序开始和结束的时间并相减即可。 获取时间:System.currentTimeMillis(); 当代码完成优化后,就可以解决这类问题。 这种方式,模版方法设计模式。 什么是模版方法呢? 在定义功能时,功能的一部分是确定的,但是有一部分是不确定,而确定的部分在使用不确定的部分, 那么这时就将不确定的部分暴露出去。由该类的子类去完成。 */ abstract class GetTime { public final void getTime() { long start = System.currentTimeMillis(); runcode(); long end = System.currentTimeMillis(); System.out.println("毫秒:"+(end-start)); } public abstract void runcode(); } class SubTime extends GetTime { public void runcode() { for(int x=0; x<4000; x++) { System.out.print(x); } } } class TemplateDemo { public static void main(String[] args) { //GetTime gt = new GetTime(); SubTime gt = new SubTime(); gt.getTime(); } }
4、多态
多态:可以理解为事物存在的多种体现形态。多态的出现大大的提高程序的扩展性。多态的前提必须是类与类之间有关系。要么继承,要么实现,而且存在覆盖。
Animal a = new Cat();//自动类型提升,作用就是限制对特有功能的访问。向上转型。将子类型隐藏。就不用使用子类的特有方法。
Cat c = (Cat)a;//向下转型的目的是为了使用子类中的特有方法。
4.1 多态时,成员的特点
1、成员变量。编译时:参考引用型变量所属的类中是否有调用的成员变量,有,编译通过,没有,编译失败。
运行时:参考引用型变量所属的类中是否有调用的成员变量,并运行该所属类中的成员变量。
简单讲:编译和运行都参考左边。
2、成员函数(非静态)
编译时:参考引用型变量所属的类中是否有调用的函数,有,编译通过,没有,编译失败。
运行时:参考的对象所属的类中是否有调用的函数。
简单讲:编译看左边,运行看右边。
因为成员函数存在覆盖特性。
3、静态函数。
编译时:参考引用型变量所属的类是否有调用的静态方法。
运行时:参考应用型变量所属的类中是否有调用的静态方法。
简单讲:编译和运行都看左边。
其实对于静态方法,是不需要对象的。直接用类名调用即可。
5、内部类
如:
class Outer { class Inner //实例内部类 { void show(){} } static class Inner1 //静态内部类 { static void function2(){} } public void fun() { final int a = 2; class Inner2(){} //局部内部类 } } Outer out = new Outer(); //直接访问外部类中的实例内部类中的成员。 Outer.Inner in = new Outer().new Inner(); in.show(); //如果内部类是静态的。 Outer.Inner in = new Outer.Inner(); in.show(); //如果内部类是静态的,成员是静态的。 Outer.Inner.function();
5.1 内部类的访问特点
1、内部类可以直接访问外部类中的成员。2、外部类要访问内部类,必须建立内部类的对象。
内部类能直接访问外部类中成员,是因为内部类持有了外部类的引用,即外部类名.this。
内部类也可以存放在局部位置上,但是内部类在局部位置上只能访问局部中被final修饰的局部变量。
内部类定义在局部时:
1、不可以被成员修饰符修饰。
2、可以直接访问外部类中的成员,因为还持有外部类中的引用。但是不可以访问它所在的局部中的变量。只能访问被final修饰的局部变量。
匿名内部类:就是内部类的简写格式。
前提:内部类必须继承或者实现一个外部类或者接口。
其实就是一个匿名子类对象。
格式:new 父类or接口(){子类内容}
通常的使用场景一:
当函数参数是接口类型时,而且接口中的方法不超过三个。
可以用匿名内部类作为实际参数进行传递。
------- android培训、 java培训、 java学习型技术博客、期待与您交流! ----------