封装、继承、多态是面向对象的三大特征,“继承”最主要的目的是为了实现代码的可复用性。通过父类与子类的继承关系,子类继承了父类的成员函数和成员变量,提高了代码的重复利用率。同时,子类也可以扩展自己特有的成员,丰富功能。
在Java中,类与类之间通过extends 关键字来定义继承关系。Java规定,类之间只能是单继承的关系,子类只能继承一个父类,但是可以实现多个接口。
public class Base {private String name="base";public String getName(){return this.name;}public Base(){}public Base(String name){this.name=name}
}public class Child extends Base{public String getName(){return "child";}}
Object
Object是Java中规定的一切类的起源,任何类都需要继承Object,在object 中规定了以下11个方法:
- toString()
- equals(Object object)
- hashCode()
- getClass()
- notify ()
- notifyAll()
- wait()
- wait(long timeout)
- wait(long timeout,int nanos)
这11个方法是所有对象都拥有的成员,我们可以继承并进行重写,以实现自己的机制。对这上述11个类,其着重功能点不同,可以按照功能点进行分组如下。
输出字符串
toString()方法的作用是返回该对象的文本描述,默认实现是使用类名@16进制哈希码的形式。比如声明了Point 类,实例化该类的一个对象Point pt=new Point() pt.toString()输出的就为 Point@76f9aa66。
对象间相等性的判断
equals()
hashCode()
在java 中,存在两种不同的变量类型,基本数据类型和对象类型。联系到底层的存储机制,二者的区别在于,基本类型都存储在栈中,对象类型存储到堆中。Java提供了8中基础类型,而同时对于每种基础类型,又以对象的方式提供相应的包装类型。具体如下:
- byte----Byte
- short----Short
- int----Integer
- long----Long
- double----Double
- float----Float
- char----Char
- boolean----Boolean
在判断这两种类型的变量是否相等的问题上,我们应该使用的机制也不同。通常情况下,我们使用 === 来进行比较,在基础类型中,这没有问题,比较的依据是内容相等,则变量等价。但是对于对象类型的变量,这比较的是变量的内存地址,这就意味着,除非是同一个对象,否则不可能相等。在object中,equals 的本质就是==,但是例如Integer、String等类型重写了equals方法,变成了内容的比较。
继承下的一些机制
变量初始化
子类初始化的过程中,先进行父类的初始化,可通过super来调用父类相应的构造方法,没有使用super的情况下,将调用父类的默认构造方法。如果声明了一个子类变量,其实例化顺序如下:
- 类初始化
- 父类初始化
- 开辟类变量内存空间并赋值
- 执行静态代码段
- 子类初始化
- 开辟类变量内存空间并赋值
- 执行静态代码段
- 变量初始化
- 父类变量开辟空间并赋值
- 执行父类构造函数
- 子类变量开辟空间并赋值
- 子类构造函数
注意,在父类构造方法中不要调用可重写的方法,因为一旦子类进行了重写,调用父类构造方法的时候就会调用子类的方法。而且,此时子类构造方法中,如果引用了子类变量,此时子类变量还未进行赋值操作,为null。
public class Base {private String name="base";public String getName(){return this.name;}public Base(){printName();}public void printName(){System.out.println(name);}public Base(String name){this.name=name;}
}public class Child extends Base{private String name="child";public String getName(){return "child";}@Overridepublic void printName() {System.out.println(name);}}public class main extends GeodataApplicationTest {@Testpublic void extendTest() {Child child = new Child();}}
上述代码输出结果为:
开始测试-----------------
null
测试结束-----------------
静态绑定与动态绑定
子类对象可以赋值给父类引用变量,这叫多态,实际执行的调用的是子类的方法,这叫动态绑定。与之相对的是静态绑定,变量绑定到变量的类型。静态绑定在程序编译阶段即可决定,动态绑定需要在运行时决定。
重载和重写
子类继承父类的public方法,如果在子类中同时对该方法进行了重载,在调用时,会同等看待这两种不同来源的重载方法,依据参数类型进行比较,调用符合度较高的方法。
父子类型转换
子类对象可以赋值给父类型的变量,这样称之为向上转换,但是父类对象不可赋值给子类对象的变量,通过强制转换也不行,也就是不可进行向下转换。
继承实现的机制
Java是静态语言,需要经过编译的过程,经过编译后将原来.java格式的源代码文件转换为.class的文件。JVM通过类加载机制,将.class文件加载到内存中,形成类的数据结构。
在类的数据结构中,会记录父类与子类的关系。