类的继承
- extends关键字标识继承关系
- super()语句调用父类的构造方法,也可以使用super关键字调用父类的成员方法,但是子类没有权限调用父类private成员方法
- 重写父类方法时,权限只能由小到大
- 重写父类方法修改返回值类型只能是父类返回值类型的子类(JDK5)
- 实例化子类对象时首先要实例化父类对象,无参数构造方法自动调用,有参数的构造方法不能被自动调用(需要传参数)
- 在继承的机制中,创建一个子类对象将包含一个父类子对象,这个父类子对象与父类创建的对象是一样的,后者来源于外部,前者来源于子类对象的内部(子类对象包含父类子对象)
- 如果使用finalize()方法对对象进行清理,需要确保子类的finalize()方法的最后一个动作是调用父类的finalize()方法,保证垃圾回收对象占用的内存时,对象的所有部分都能被正常终止
- static方法必须重写成static方法,final方法不可重写
package ex10_Interface;
class Parent {
public Parent() {
System.out.println("调用父类的Parent()构造方法");
}
protected void doSomething() { //父类protected方法
//do Something
}
protected Parent doIt() { //父类protected方法,返回Partent类型
return new Parent();
}
}
class SubParent extends Parent {
public SubParent() {
super(); //使用super()调用父类构造方法
super.doSomething(); //使用super关键字调用父类成员方法
System.out.println("调用子类的SubParent()构造方法");
}
public void doSomethingNew() { //子类新增方法
//do something new
}
public void doSomething() { //重写父类方法,修改权限为public
//do Something
}
public Subroutine doIt() { //重写父类方法,返回SubParent类型
return new Subroutine();
}
}
public class Subroutine extends SubParent {
public Subroutine() { //自动调用父类构造方法
System.out.println("调用子类的Subrountine()方法");
}
public static void main(String[] args) {
Subroutine s = new Subroutine();
}
}
Object类
- 所有类都继承与java.lang.Object类
- 任何类都可以重写Object类中的方法 clone(), finalize(), equals(), toString()等,getClass(), notify(), notifyAll(), wait()等方法不能被重写,因为这些方法被定义为final类型
- getClass()方法获取当前运行的类名(上下文中获得,包含class),返回值是一个Class实例,getClass().getName()返回类名
- toString()方法将一个对象返回字符串形式
- equals()方法默认实现的是==比较两个对象的引用,而不是比较内容,要想实现真正的比较对象的内容,需要在自定义类中重写equals()方法
package ex10_Interface;
public class Test {
public void myMethod(Test t) {
System.out.println(t);
}
public String toString() { //getClass()自动获取当前类名
return "在" + getClass().getName() + "中重写toString()方法";
}
public static void main(String[] args) {
Test t = new Test();
System.out.println(t); //自动调用toString方法
String s1 = "123";
String s2 = "123";
System.out.println(s1.equals(s2)); //返回true
Test t1 = new Test();
Test t2 = new Test();
System.out.println(t1.equals(t2)); //返回false,默认使用==比较引用
//对象类型转换
Test t3 = new Test2();
Test2 t4 = (Test2) t3; //向下转型
// System.out.println(t3 instanceof Anything); //t3不是Anthing的对象,报错
//多态
Test2 tt2 = new Test2();
Test3 tt3 = new Test3();
t1.myMethod(tt2); //不同子类的对象调用父类的方法,向上转型
t1.myMethod(tt3);
tt2.myMethod(tt2); //使用父类对象或者子类对象调用都可以
tt2.myMethod(tt3);
}
}
class Test2 extends Test {}
class Test3 extends Test {}
class Anything {
}
对象类型的转换
- 向上转型
- 子类实例化的对象可以调用父类的方法,传入子类对象,子类对象传入以父类对象为参数的方法为向上转型
- 子类实例化的对象可以赋值给父类类型的变量(向上转型)
- 向下转型
- 将子类实例化的对象赋值给父类类型的变量为向上转型,必须使用强制类型转换(告知编译器这个父类就是某个子类,显式类型转换)将父类类型的变量转换为子类类型,直接赋值会报错
- 越具体的对象具有的特性越多,越抽象的对象具有的特性越少,在做向下转型时,将特性范围小的对象转换为特性特性范围大的对象肯定会出问题,如果是父类new出来的对象赋值给子类对象,强制类型转换发生ClassCastException异常
- 使用instanceof判断对象类型
- 判断对象是否是子类的实例,如果是可以进行向下转型。a instanceof b; 返回布尔类型,不相关的类会报错
- 也可以判断是否有一个类实现了某个接口
方法的重载
参数个数不同、类型不同、类型顺序不同,不定长参数...(不定长参数作为数组)
多态
子类中的各类似方法的实现只需在父类中实现一次即可,所有继承父类的子类的对象都是父类的子对象,都可以调用父类中以父类对象为参数的方法,子类对象向上转型传入参数。
抽象类和接口
- 使用abstract关键字定义抽象类和抽象方法,抽象类不可以实例化对象,抽象方法没有方法体,因此抽象方法没有任何意义除非被重写,而承载这个抽象方法的抽象类必须被继承,因此不可能在非抽象类中定义抽象方法,抽象类除了被继承之外没有任何意义
- 由于继承抽象类必须要实现抽象类中的所有抽象方法,但是有些子类并不需要实现其中的抽象方法,Java不能同时继承多个父类,就有了接口的概念。接口是抽象类的延伸,接口中的所有方法都没有方法体。
- 使用interface关键字定义接口,可以像类一样使用权限修饰符,public关键字仅限用于与其同名的文件中被定义,接口中的方法必须被定义为public或abstract形式,即使不声明为public,它也是public
- 接口中定义的任何字段都自动式static和final的
- 实现接口时使用implements,多个接口使用逗号个卡尼
- 接口也可以被接口继承,使用extends
package ex10_Interface;
interface drawTest { //定义接口
void draw(); //定义方法,省略了public和abstract,其他不被编译器认可
}
interface drawTest2 extends drawTest {
void draw2(); //接口的继承
}
class A {
}
class B extends A implements drawTest { //多个接口使用逗号隔开
public void draw() { //由于该类实现了接口需要覆盖接口定义的方法
System.out.println("B类继承A类,实现接口drawTest,B.draw()");
}
}
class C extends A implements drawTest {
public void draw() {
System.out.println("C类继承A类,实现接口drawTest,C.draw()");
}
}
public class UseInterface {
public static void main(String[] args) {
System.out.println("----------------------------");
drawTest inf = new B(); //接口也可以进行向上转型
drawTest inf2 = new C();
inf.draw();
inf2.draw();
B b = new B(); //也可以直接使用对象调用成员方法
b.draw();
}
}