一.覆盖与重载
重载:在同一个类中被声明的几个具有不同参数列(参数的类型,个数及其顺序不同)的同名函数,不关心其返回值.
覆盖:是指派生类中存在重新定义的函数,其函数名,参数列,返回值类型必须与父类中对应覆盖的函数严格一致,覆盖函数和被覆盖函数只有函数体不同.
注意:父类私有的方法与静态方法不能被覆盖,覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类
二.继承与组合
继承是指Child类的对象可以使用仅对Father类的对象有效的方法与属性,它使得这些方法与属性就好像是Child类自己定义一样.此时Father类内部的一些细节对于子类是可见的.所以继承的代码复用是一种"白盒式代码复用".
private Child extends Father{
...
}
组合是指通过对现有对象进行拼装产生新的更复杂的功能.因为在对象之间,各自的内部细节是不可见的,所以,我们也说这是一种"黑盒式代码复用".
private Child{
private Father father;
}
三.对象转型
package programming;
class Animal{
int age;//动物都有的年龄
public Animal() {
System.out.println("动物类");
}
public void play() {
System.out.println("动物在打闹");
}
}//定义一个动物类
public class Dog extends Animal{
public Dog() {
System.out.println("小狗");
}
public void play() {
System.out.println("小狗在打闹");
}
public void eat() {
System.out.println("小狗在吃骨头");
}
public static void main(String[] args) {
// Dog dog=(Dog) new Animal();//不可行,因为你new 出来的动物不一定是小狗
Animal animal=new Dog();//上转型
animal.play();//输出小狗
//animal.eat();获取不到子类独有的方法
Dog dog=(Dog) animal;//向下转型:只有先向上才能再向下
dog.play();
}
}
四.super与this关键字
package programming;
class Person1{
String name;
public Person1() {
System.out.println("person");
}
void value() {
name="人类";
}
}
public class Student extends Person1{
public Student() {
super();
System.out.println("student");
}
void print() {
super.value();
System.out.println(super.name);//在子类中引用父类中的成员变量与方法
//如果想要使用父类的构造函数,则应当使用super(参数列表)的形式
}
public static void main(String[] args) {
Student student=new Student();
student.print();//打印出person.student.人类
}
}
this代表子类自身的对象,而且this与super都必须放在第一行,所以两个不能同时使用
this也可以访问当前的对象,this.toString()
this还有一个用法就是构造函数的第一个语句,他的形式是this(参数列表),这个构造函数就会调用同一个类中的另一个构造函数.如下:
package programming;
public class User {
String name;
int age;
public User(int age) {
this("小明",21);
this.age=age;
}
public User(String name,int age) {
this.name=name;
this.age=age;
}
public static void main(String[] args) {
User user=new User(30);
System.out.println(user.name+user.age);
//输出小明,30
}
}
经典题目:
class Base {
int i;
Base() {
add(1);
System.out.println(i);
}
void add(int v) {
i+=v;
System.out.println(i);
}
void print() {
System.out.println(i);
}
}
class MyBase extends Base {
public MyBase() {
add(2);
}
void add(int v) {
i+=v*2;
System.out.println(i);
}
}
public class TestClu {
public static void main(String[] args) {
go(new MyBase());
}
static void go(Base b) {
b.add(8);
}
}
程序运行流程:
从主函数入口:先执行Base b=new MyBase()------>子类首先调用父类的构造函数,执行add(1),但是子类重写了父类的方法所以执行后的结果是i=2;-------->然后再执行子类的构造函数add(2)此时的i是i=2+2*2=6------->最后执行go()方法,add(8),i=8*2+6=22
五.不能继承的情况
匿名内部类是否可以继承其他类,是否可以实现接口?
匿名内部类是没有名字的内部类,不能继承其他类,但一个内部类可以作为一个接口,在另一个内部类实现
用final修饰的类也不能被继承
六.抽象类与接口
抽象类
1 如果将一个类声明为abstract,此类不能生成对象,只能被继承使用。
2 抽象方法必须存在于抽象类中。
3 抽象类中可以有一般的变量和一般的方法。
4 子类继承抽象类必须实现其中抽象方法,除非子类为抽象类。
接口
1 因为java不支持多重继承,所以有了接口,一个类只能继承一个父类,但可以实现多个接口,接口本身也可以继承多个接口。
2 接口里面的成员变量默认都是public static final类型的。必须被显示的初始化。
3 接口里面的方法默认都是public abstract类型的。隐式声明。
4 接口没有构造方法,不能被实例化。
5 接口不能实现另一个接口,但可以继承多个接口。
6 类如果实现了一个接口,那么必须实现接口里面的所有抽象方法,否则类要被定义为抽象类。
区别:
1 接口只能包含抽象方法,抽象类可以包含普通方法。
2 接口只能定义静态常量属性,抽象类既可以定义普通属性,也可以定义静态常量属性。
3 接口不包含构造方法,抽象类里可以包含构造方法。