------- android培训、java培训、期待与您交流! ----------
继承
继承,就是在已存在的类的基础上,进行扩展,从而产生新的类。已经定义好的类称为父类。在JAVA中,父类所拥有的一切,子类都可以继承。在父类中中定义的非私有的属性和方法,子类都可以继承。在子类继承父类后就自动获得了父类的非私有属性和非私有的方法。子类可以直接使用他们而不用自己再进行定义。
- 继承的特性:
- 直接使用继承的父类的属性和方法,提高了代码的复用性。
- 让类与类之间产生了关系,有了这个关系,才有了多态的特性。
- 在继承时需要注意:
- 不能为了获取其他类的功能,简化代码从而随便继承。
- 要继承,必须要有所属关系。比如学生继承人,学生所属于人,人的基本属性,学生都具有。
- JAVA中只支持单继承,不支持多继承。但是支持多实现。因为多继承可能出现安全问题。比如两个父类中都定义同名的方法,但方法的内容不同时。子类继承以后,需执行这个方法时,不知道应该执行哪一个方法。
- AVA虽然不支持多继承但是支持多层继承。
- 继承的方法的使用
- 想要使用体系,先查阅体系父类的描述。因为父类中定义的是该体系中共性的功能。通过了解共性功能就可以知道该体系的基本功能。
- 在具体调用时,要创建最子类的对象
- 因为可能父类不能创建对象。
- 二是创建子类对象可以使用更多的功能,不仅可以使用基本功能而且可以使用特有功能。
- 当子类创建对象时在内存中对象的建立过程:
- 主函数执行new Zi()——>加载Fu.class——>加载Zi.class——>分配属性空间(父类的属性不管是不是私有的和子类的属性都在子类对象里面)
- 方法区:
- Fu类中的方法加载——>子类的方法加载——>子类除了this引用(本类引用)外还有super引用(父类引用)
- 子父类中变量的特点:
- 类中的成员
- 变量:
- 如果子类出现非私有的同名变量时。子类如果要访问本类中的变量用this。子类如果要访问父类中的变量,用super。(this代表本类引用,super代表父类引用。)
- 函数:
- 当子类出现和父类一样的函数时。子类对象调用该函数,会运行子类的内容。如同父类的函数被覆盖一样。这种情况是函数的另一个特性——重写。
- 当子类继承父类,沿袭了父类的功能,到子类中,但是子类虽具备该功能,但是功能的内容却和父类不一致,这时,没有必要定义新的功能,而是使用覆盖特性,保留父类的功能定义并重写功能内容。
- 当子类覆盖父类,必须保证子类的权限大于等于父类的权限,才可以覆盖,否则编译失败。(但是如果父类中的方法被私有,此时子类不知道父类有那个方法,所以不能算是覆盖)
- 构造函数:
- 在对子类对象进行初始化事,父类的构造函数也会运行,那是因为子类的构造函数默认第一行有一条隐士的语句super();super();会访问父类中空参数的构造函数,而且子类中所有的构造函数默认第一行都是super();
- 如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。
- 当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定要访问父类中的构造函数。
- 子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。子类中至少会有一个构造函数会访问父类中的构造函数
- 注意:super语句一定定义在子类构造函数的第一行
- 子类为什么一定要访问父类中的构造函数?
- 答:因为父类中的数据子类可以直接获取。所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的。所以子类在对象初始化时,要先访问一下父类中的构造函数。
- 代码诠释:
class Person //定义Person类 { private String name; //定义Person类的两个属性name和age; private int age; Person(String name,int age)//构造函数初始化 { this.name = name; this.age = age; } void show() //show方法,说出自己的属性 { System.out.println("My name is:"+name+"\t"+"I am "+age+" years old"); } } class Student extends Person //Student继承了Person。 { private int studentid; //增加了一个特有属性学号 Student(String name,int age) //当未分配学号的时候,构造函数初始化 { super(name,age); //调用父类的构造函数初始化 } Student(String name,int age,int studentid)//当有name、age、studentid三个属性的构造函数 { this(name,age); //调用自己的另一个构造函数,在另一个构造函数中,访问到了父类的构 //造函数,相当于还是访问到了父类的构造函数。 this.id = studentid; } void show() //重写show()方法 { super.show(); System.out.println("My id is "+id); } } class ExtendsDemo3 //主函数 { public static void main(String[] args) { Student a = new Student("张三",23); a.show(); } } /* 执行结果 ================================= My name is:张三 I am 23 years old My id is 13 ================================= */
final关键字
Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类、非抽象类成员方法和变量。你可能出于两种理解而需要阻止改变:设计或效率。
- 被final修饰的特性:
- final类不能被继承,没有子类,final类中的方法默认是final的。
- final方法不能被子类的方法覆盖,但可以被继承。
- final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
- final不能用于修饰构造方法。
- 注意:父类的private成员方法是不能被子类方法覆盖的,因此private类型的方法默认是final类型的。
- final修饰对象:
- 类:final类不能被继承,因此final类的成员方法没有机会被覆盖,默认都是final的。在设计类时候,如果这个类不需要有子类,类的实现细节不允许改变,并且确信这个类不会载被扩展,那么就设计为final类。
- 方法:如果一个类不允许其子类覆盖某个方法,则可以把这个方法定义成final类型。
- 变量(常量):
- 用用final修饰的成员变量表示常量,值一旦给定就无法改变!
- final修饰的变量有三种:静态变量、实例变量和局部变量,分别表示三种类型的常量。
- 特别说明:final变量定义的时候,可以先声明,而不给初值,这中变量也称为final空白,无论什么情况,编译器都确保空白final在使用之前必须被初始化。但是,final空白在final关键字final的使用上提供了更大的灵活性,为此,一个类中的final数据成员就可以实现依对象而有所不同,却有保持其恒定不变的特征。
抽象类
抽象就是将对象的共同方法和属性提取出来,提取后,重新设计一个更加通用类,这个类被称为抽象类。
什么时候定义抽象类?
当多个类中出现相同功能,但是功能主题不同的时,就可以向上抽取,这时,只有抽取功能定义,而不抽取功能主体。 抽象类的定义:
在类和抽象的方法前面都必须家abstract声明。 抽象方法一定在抽象类中。 抽象方法和抽象类都要声明。 抽象类不可以用new创建对象,因为调用抽象方法没有意义。 抽象类中的方法要被使用,必须有子类复写所有的抽象方法后,建立子类对象调用。如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。 注意:
抽象类中既可以定义抽象方法,也可以定义普通方法(也可以不定义抽象方法,这样做的目的是为了防止建立该类的对象) 抽象类练习:
假如我们在开发一个系统时需要对员工进行建模,员工包含 3 个属性:姓名、工号以及工资。经理也是员工,除了含有员工的属性外,另为还有一个
奖金属性。请使用继承的思想设计出员工类和经理类。要求类中提供必要的方法进行属性访问。 代码:abstract class Employee { private String name; //定义员工的三个属性name、id、pay 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"); } } class AbstractDemo { public static void main(String[] args) { Pro p =new Pro("向天问","11415316",6000); Manager m = new Manager("向天问","11415316",6000,2000); p.work(); m.work(); } }
模版设计方法
模版方法:
在定义功能时,功能的一部分是确定的,一部分是不确定的,而确定的部分在使用不确定的部分,那么这时就将确定的部分用final修饰起来,表示本方法在本类中就是具备这个确定部分的功能,不可以被复写;将不确定的部分暴漏出去用abstract修饰,由该类的子类复写去完成接口
什么是接口?
接口是一种特殊的抽象类,接口中声明的所有方法都是抽象的。 使用interface关键字修饰(定义)一个接口。 接口定义时的格式特点:
接口中常见定义:常量,抽象方法。
常量:public static final 类型名 常量名
当接口中的常量赋值后,不可再进行第二次赋值操作 方法:public abstract返回值类型 方法名(); 以上定义常量和方法的格式中带颜色的部分如果省略,系统会自动帮你加上。 接口中的成员都是public的。 接口与接口的关系:继承关系。接口之间可以多继承。 接口的使用
类通过implements实现接口,并且类可以实现多个接口。
implements的用法和extends相似。 接口不可以创建对象,因为有抽象方法。
需要被子类实现,子类对接口中的抽象方法全部覆盖后,子类才可以实例话。否则子类仍然是一个抽象类。 接口的特点:
接口是对外暴露的规则。 接口可以用来多实现。 接口是程序的扩展功能。 接口与接口之间可有继承关系 接口降低了耦合性 类与接口之间是实现关系,且类可以继承一个类的同时实现多个接口。 继承抽象类和实现接口的选择:
抽象类是为继承而精心设计的,接口则更多以组合的方式使用。 如果你的业务中可以抽象出一个通用的处理过程,只是某些局部传递的状态或参数有所不同,这时可以考虑使用抽象类。 当只是拓展某个功能的时候,则可以实现接口的方式去实现。 基本功能定义在类中,拓展功能定义在接口中。 代码诠释:
abstract class Student //定义学生类的基本功能和属性。 { String name; int age; Student(String name,int age) { this.name = name; this.age = age; } abstract void study(); //将学习方法抽象。因为每个人学习的不一样 void sleep() { System.out.println("sleep"); } } interface Smoking //定义一个抽烟的接口,作为拓展功能。 { void smoke(); } class AStudent extends Student implements Smoking //定义一类学生,这类学生除了具备基本功能意外还具有抽烟的功能 { AStudent(String name,int age) { super(name,age); } void study() { System.out.println("我是"+name+"我学习基本技术"); } public void smoke() { System.out.println("抽烟"); } } class BStudent extends Student //定义一类学生,只有学生的基本功能,没有其他拓展功能 { BStudent(String name,int age) { super(name,age); } void study() { System.out.println("我是"+name+"我学习工商管理"); } } class InterfaceDemo //主函数 { public static void main(String[] args) { AStudent a = new AStudent("张三",33); BStudent b = new BStudent("李四",21); a.study(); a.smoke(); b.study(); } }