6、类间关系
在⾯向对象的系统中,通常不会存在孤⽴的类,类之间、对象之间总是存在各种各样的关系,按照UML(Unified Modeling Language,统⼀建模语⾔)规范,类之间存在六种关系:继承 、实现 、依赖 、关联 、聚合 、组成 。
UML的六种关系中,继承和实现是⼀种纵向的关系,⽽其余四种是横向关系。其中关联、聚合、组成关系在代码上是⽆法区分的,更多的是⼀种语义上的区别。
继承
在Java中,被继承的类叫⽗类(parent class)或超类(super class),继承⽗类的类叫⼦类(subclass)或派⽣类(derived class)。
在Java中,关键字“extends”表⽰继承,后⾯紧跟⽗类的类名,如下 :
public class Person {
private String name;// 姓名
private int age;// 年龄
private String gender;// 性别
……//省略get和set⽅法
}
class Teacher extends Person {
private float salary;// 薪酬
private String department;// 部门
……//省略get和set⽅法
}
class Student extends Person {
private int[] score;// 成绩
private String grade;// 年级
……//省略get和set⽅法
}
重写
当⼀个⼦类继承了⼀个⽗类时,可以在⼦类中直接使⽤⽗类的属性和⽅法。如果⽗类的⽅法⽆法满⾜⼦类的需求,则可以在⼦类中对⽗类的⽅法进⾏改造,也称作重写(override)。重写是Java多态性的另⼀种体现。
重写的原则
重写的⽅法的签名必须要和被重写的⽅法的签名完全匹配
重写的⽅法的返回值必须和被重写的⽅法的返回⼀致或者是其⼦类;
重写的⽅法所抛出的异常必须和被重写⽅法的所抛出的异常⼀致,或者是其⼦类;
私有⽅法不能被重写
⼦类重写⽗类⽅法的过程中,可访问性只能⼀样或变的更公开。
public class Base {
public void print(){
System.out.println("In Base ");
}
public static void main(String[] args){
Son obj =new Son();
obj.print();
}
}
class Son extends Base {
// 覆盖⽗类的print()⽅法
public void print(){
System.out.println("In Son ");
}
}
//执⾏结果如下:
In Son
依赖关系
在⼀个类的⽅法中操作另外⼀个类的对象,则称其依赖于第⼆个类。
public class Person {
void travel( Car car ){
car.run("北京");
}
public static void main(String[] args){
new Person().travel(new Car());
}
}
class Car {
void run(String city){
System.out.println("汽车开到"+ city);
}
}
关联关系
体现为⼀个类中使⽤另⼀个类的对象作为属性。(⼦对象)
public class Person {
Car car;
Person(Car car){
this.car = car;
}
void travel(){
car.run("北京");
}
public static void main(String[] args){
new Person(new Car()).travel();
}
}
class Car {
void run(String city){
System.out.println("汽车开到"+ city);
}
}
聚合关系
聚合关系体现的是整体与部分的关系,即⼀个类(整体)由其它类类型的属性(部分)构成。聚合关系中的各个部分可以具有独⽴的⽣命周期,部分可以属于多个整体。
public class Department {
Employee[] employees;
public static void main(String[] args){
Employee e1 =new Employee();
Employee e2 =new Employee();
Employee e3 =new Employee();
Department dept1 =new Department();
dept1.employees =new Employee[]{ e1, e3 };
Department dept2 =new Department();
dept2.employees =new Employee[]{ e2, e3 };
}
}
class Employee {}
super
“super”关键字代表⽗类对象。通过使⽤super关键字,可以访问⽗类的属性或⽅法,也可以在⼦类构造⽅法中调⽤⽗类的构造⽅法,以便初始化从⽗类继承的属性。
⽤来修饰类、⽅法和变量,其含义是“不可改变的、最终的” 。
修饰类:声明为final的类不能被继承,⼀个final类中的所有⽅法都隐式地指定为final。
修饰变量:声明为final的变量是⼀个常量,在定义时必须给予初始值,变量⼀旦初始化,将不能改变。
修饰⽅法:声明为final的⽅法不能被⼦类重写。
7、Object类
概述
Object类是所有类的顶级⽗类,在Java体系中,所有类都是直接或间接的继承了Object类,Object类包含了所有Java类的公共属性和⽅法,这些属性和⽅法在任何类中均可以直接使⽤,其中较为重要的⽅法如下表所⽰:
⽅法名功能说明
boolean equals(Object obj)⽐较两个类变量所指向的是否为同⼀个对象,是则返true
Class getClass()获取当前对象所属类的信息,返回Class对象
String toString()将调⽤toString()⽅法的对象转换成字符串
Object clone()⽣成当前对象的⼀个备份,并返回这个副本
int hashCode()返回该对象的哈希代码值
注意:
继承是⾯向对象编程技术的基础,它允许创建分等级层次的类
任何类只能有⼀个⽗类,即Java只允许单继承
除构造⽅法,⼦类继承⽗类的所有⽅法和属性
overload(重载)是多态性的静态展⽰,override(重写)是多态性的动态展⽰
super有两种通⽤形式:调⽤⽗类的构造⽅法、⽤来访问被⼦类的成员覆盖的⽗类成员
final修饰符可应⽤于类、⽅法和变量
Object是所有类的最终⽗类,是Java类结构的基础
类之间有依赖、关联、聚合、组成四种关系
8、抽象类
定义
在⾯向对象的概念中,所有的对象都是通过类来表述,但并不是所有的类都是⽤来描绘对象的,如果⼀个类中没有包含⾜够的信息来描绘⼀类具体的对象,这样的类就是抽象类。抽象类虽然具备类的形式,但由于其“抽象”性,不能定义抽象类的实例,即不能为抽象类分配具体空间 ;
抽象类需要注意以下⼏点:
abstract放在class前,指明该类是抽象类;
abstract放在⽅法声明中,则该⽅法是抽象⽅法,抽象⽅法没有⽅法体;
⼀个抽象类可以含有多个抽象⽅法,也可以含有已实现的⽅法。
抽象类不能实例化,但可以指向⼀个实现它的⼦类对象;
abstract不能与final同时修饰⼀个类;
abstract不能和static、private、final或native并列修饰同⼀⽅法。
public abstract class Shape {
double dim;
public Shape(double dim){
this.dim = dim;
}
// 抽象⽅法,获得⾯积
public abstract double callArea();
// 抽象⽅法,获得周长
public abstract double callPerimeter();
}
//可以通过如下⽅式来实例⼀个抽象类
Shape someShape;
//引⽤Circle类的实例对象
someShape =new Circle(5);
someShape.callArea();
9、接⼝
概述
Java是单继承的语⾔,利⽤接⼝可以模拟多继承;
接⼝是对抽象类的进⼀步抽象,是⽅法声明和常量的定义集合;
接⼝是⼀种⾏为规范,是⼀种契约;
定义
//定义接⼝格式
<;访问符>interface接⼝名{
[访问符]<;返回类型>⽅法名([参数列表]);
......
}
注意:在定义接⼝的时候,接⼝中的所有⽅法和常量⾃动定义为public。接⼝中定义的变量默认是public static final型,且必须赋初值
从JDK8.0开始可以使⽤default关键字来定义⼀个默认的⽅法来扩展接⼝,default关键字修饰的默认⽅法可以直接调⽤,不⽤⼦类去实现。
使⽤
//接⼝的使⽤通过“implements”关键字来实现
public class MyClass implements MyInterface {
public void add(int x,int y){
// do something
}
public void volume(int x,int y,int z){
// do something
}
}
//多重继承
public class MyClass2 implements MyInterface, MultiInterface{
......//实现多个接⼝中的所有⽅法
}
10、抽象类与接⼝区别
抽象类中可以有⾮抽象⽅法。JDK8.0之前接⼝中则不能有实现⽅法,之后可以使⽤default关键字来定义⼀个默认的⽅法;
接⼝中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值;
接⼝中的⽅法默认都是public abstract类型的。
11、instanceof运算符
声明为同种类型的两个引⽤变量调⽤同⼀个⽅法时也可能会有不同的⾏为。为更准确的鉴别⼀个对象的真正类型,Java语⾔引⼊了instanceof操作符,其使⽤格式如下:
<;引⽤类型变量> instanceof <;引⽤类型>
当 instanceof 左侧的引⽤类型变量所引⽤对象的实际类型是其右侧给出的类型或其⼦类类型时,整个表达式的结果为true,否则为false。
12、对象类型转换
⾃动转换
⼦类转换成⽗类时(或者实现类转换成接⼝)可以⾃动完成。例如,Teacher是Person的⼦类,将⼀个Teacher对象赋给⼀个Person类型的变量时,转换⾃动完成。
强制转换
⽗类转换成⼦类时(或者接⼝转换成实现类),必须使⽤强制转换。例如,Teacher类是Person的⼦类,如果将⼀个Person对象赋给⼀个Teacher类型变量的时候,必须使⽤强制转换。
//创建⼀个Teacher对象,把引⽤赋予Person类型的变量p,该过程⾃动转换
Person p =new Teacher();
//把变量p强制转换成Teacher类型的变量
Teacher t =(Teacher)p;