类的继承
在java中,对于一些有相同特征和行为的类,我们通常将它们的相同内容提取出来组成新的类,然后让原来的类继承新类。举一个简单的例子:
class Person{
int age;
String name;
public void eat(){
System.out.println("eat...");
}
}
class Student{
int age;
String name;
public void eat(){
System.out.println("eat...");
}
}
class Teacher{
int age;
String name;
public void eat(){
System.out.println("eat...");
}
}
可以看到,Student类和Teacher类都有姓名、年龄以及eat这个特征。每一次创建一个具有相同属性的类都要写很多重复的东西,所以我们把它们的相同特征和属性拿出来放入一个Person类,我们用Student类和Teacher类继承Person类,继承使用extends关键字。如下:
class Person{
int age;
String name;
public void eat(){
System.out.println("eat...");
}
}
class Student extends Person{
}
class Teacher extends Person{
}
这样的定义跟以上是等价的,我们通过测试类来验证一下。
class Person{
int age;
String name;
public static void eat(){
System.out.println("eat...");
}
}
class Student extends Person{
}
class Teacher extends Person{
}
public class Test
{
public static void main(String[] args)
{
Student student = new Student();
student.age = 20;
student.name = "Tom";
student.eat();
System.out.println(student.age+" "+student.name);
Teacher teacher = new Teacher();
System.out.println(teacher.age+" "+teacher.name);
}
}
通过运行结果可以看出,Student类实例化后给继承的相关属性赋予了相应的值,而Teacher类的实例对象我们没有给它赋值,所以输出的是默认值。
注意:private修饰的属性和方法不能被直接访问,例如:
class Person{
private int age;
String name;
public static void eat(){
System.out.println("eat...");
}
}
此时Person类的age不能被直接访问。这里Person类叫做父类,Student类和Teacher类叫做子类,一个子类只能有一个父类,而一个父类可以有多个子类。
方法的覆盖
子类可以继承父类中所有可以被子类访问的成员方法,但是子类重新定义了从父类继承来的方法,那么父类的这个方法在子类中将不复存在,此时称子类覆盖了父类的方法,简称方法覆盖。例如,Student 类和 Teacher类都有eat方法,但它们的eat方法跟Person类的不一样,此时用方法的覆盖。
例如:
class Student extends Person{
public void eat(){
System.out.println("student eat...");
}
}
class Teacher extends Person{
public void eat(){
System.out.println("teacher eat...");
}
}
当然,子类中也可以加入自己的方法
例如:
class Person{
int age;
String name;
public static void eat(){
System.out.println("eat...");
}
}
class Student extends Person{
public static void eat(){
System.out.println("student eat...");
}
public void sleep(){
System.out.println("student sleep...");
}
}
class Teacher extends Person{
public static void eat(){
System.out.println("teacher eat...");
}
public void sleep(){
System.out.println("teacher sleep...");
}
}
public class Test
{
public static void main(String[] args)
{
Student student = new Student();
student.age = 20;
student.name = "Tom";
student.eat();
student.sleep();
System.out.println(student.age+" "+student.name);
Teacher teacher = new Teacher();
teacher.eat();
teacher.sleep();
System.out.println(teacher.age+" "+teacher.name);
}
}
输出结果如下:
构造方法在继承中的应用
构造方法遵循以下原则:
- 1、子类无条件地继承父类的构造方法。
- 2、如果子类没有定义构造方法,则它将继承父类的无参构造方法作为自己的构造方法,如果子类定义了构造方法,则在创建子类对象时,将先执行来自继承父类的无参构造方法,然后在执行自己的构造方法。
- 3、对于父类带参数的构造方法,子类可以通过自己的构造方法中使用super关键字来调用它,但这个调用语句必须是子类构造方法中第一条可执行语句。
这里我们用Student类来测试:
class Person{
int age;
String name;
public Person(){
System.out.println("父类无参构造调用");
}
public static void eat(){
System.out.println("eat...");
}
}
class Student extends Person{
public Student()
{
System.out.println("Student无参构造调用");
}
}
public class Test
{
public static void main(String[] args)
{
Student student = new Student();
}
}
运行结果如下:
可以看到,父类无参构造方法先被调用。
super关键字
Java中我们通常使用super关键字来调用父类中的构造方法,如上文运行结果,子类构造方法的第一行系统默认加上super(),所以先调用父类的无参构造,子类构造方法中,我们也可以调用父类的有参构造方法以及父类的成员方法和成员变量,如下;
class Person{
int age;
String name;
public Person()
{
System.out.println("父类无参构造调用");
}
public Person(int age){
System.out.println("person age:"+age);
}
public static void eat(){
System.out.println("eat...");
}
}
class Student extends Person{
public Student()
{
super(20);//调用父类有参构造
System.out.println("Student无参构造调用");
super.eat();//调用父类的成员方法
System.out.println(super.name);//调用父类成员变量
}
}
public class Test
{
public static void main(String[] args)
{
Student student = new Student();
}
}
由于父类中name没有赋值,所以输出默认值。
注意:若父类只有有参构造,则子类继承父类时会出错,要通过super关键字调用父类的有参构造方法来避免这种错误。