你的位置:首页 > Java教程

[Java教程]Java: 面向对象程序设计(下)


1. 类的继承

继承的意义:

当一个类A继承了一个已存在的类B后,类A就用于了类B所有的非private的属性和方法,但同时类A还可以根据需要,添加新的方法和属性。

在Java语言中,一个类可以拥有多个子类,但是一个子类只能拥有一个父类。

 

如何定义子类:

class 子类名 extends 父类名

{}

public class ExtendsDemo1 {  Employee e;  Manager m;    public ExtendsDemo1()  {    e=new Employee("Wnag Xiao Yue", 3000.00, "2005/05/20");    System.out.println("Name: "+ e.getName() + "; Salary: "+ e.getSalary()+ "; Hireday: "+e.getHireDay()+"\n");        m=new Manager("Zhao XS", 8000.00, "2004/6/2", 4000.00, 20);    System.out.println("Name: "+ m.getName() + "; Salary: "+ m.getSalary()+ "; Hireday: "+m.getHireDay() + "; Bonus: "+m.getBonus()+"; Holidays: "+m.getHolidays());      }  public static void main(String[] args) {    new ExtendsDemo1();  }}class Employee{  String name;  double salary;  String hireDay;    public Employee(String name, double salary, String hireDay)  {    this.name=name;    this.salary=salary;    this.hireDay=hireDay;    System.out.println("I'm Employee");  }    public String getName()  {    return name;  }  public String getHireDay()  {    return hireDay;  }  public double getSalary()  {    return salary;  }}class Manager extends Employee{  private double bonus;  private int holidays;    public Manager(String name, double salary, String hireDay, double bonus, int holidays)  {    super(name, salary, hireDay);  //调用父类构造方法    this.bonus=bonus;    this.holidays=holidays;    System.out.println("I'm Manager");  }    public double getBonus()  {    return bonus;  }    public int getHolidays()  {    return holidays;  }}

I'm Employee
Name: Wnag Xiao Yue; Salary: 3000.0; Hireday: 2005/05/20

I'm Employee
I'm Manager
Name: Zhao XS; Salary: 8000.0; Hireday: 2004/6/2; Bonus: 4000.0; Holidays: 20

 

覆盖父类中的方法(重载:方法名、参数、返回值均不变, 只有方法体发生了变化):

public class ExtendsDemo1 {  Employee e;  Manager m;    public ExtendsDemo1()  {    e=new Employee("Wnag Xiao Yue", 3000.00, "2005/05/20");    e.getInfo();    System.out.println("Name: "+ e.getName() + "; Salary: "+ e.getSalary()+ "; Hireday: "+e.getHireDay()+"\n");        m=new Manager("Zhao XS", 8000.00, "2004/6/2", 4000.00, 20);    m.getInfo();    System.out.println(m.getSalary());    System.out.println("Name: "+ m.getName() + "; Hireday: "+m.getHireDay() + "; Bonus: "+m.getBonus()+"; Holidays: "+m.getHolidays());      }  public static void main(String[] args) {    new ExtendsDemo1();  }}class Employee{  String name;  double salary;  String hireDay;    public Employee(String name, double salary, String hireDay)  {    this.name=name;    this.salary=salary;    this.hireDay=hireDay;  }    public void getInfo()  {    System.out.println("I'm Eployee");  }  public String getName()  {    return name;  }  public String getHireDay()  {    return hireDay;  }  public double getSalary()  {    return salary;  }}class Manager extends Employee{  private double bonus;  private int holidays;    public Manager(String name, double salary, String hireDay, double bonus, int holidays)  {    super(name, salary, hireDay);  //调用父类构造方法    this.bonus=bonus;    this.holidays=holidays;  }    public void getInfo()  {    System.out.println("I'm Manager");  }  public double getSalary()  {    System.out.print("Manager Salary is: ");    return salary;  }  public double getBonus()  {    return bonus;  }    public int getHolidays()  {    return holidays;  }}

I'm Eployee
Name: Wnag Xiao Yue; Salary: 3000.0; Hireday: 2005/05/20

I'm Manager
Manager Salary is: 8000.0
Name: Zhao XS; Hireday: 2004/6/2; Bonus: 4000.0; Holidays: 20

 

this关键字的使用:

this关键字就好像创建一个虚拟的类对象实例,在定义类的时候,就提前使用其对象实例。

注意:由于this是指向当前类实例的一个引用,因此只能在实例方法的定义中使用。而在类方法(static型静态方法)中,不能使用this关键字。

public class ThisDemo {  private String name;    public ThisDemo(String name)  {    this.name=name;  }    public String getName()  {    return name;  }    public void show()  {    String str=this.getName();    System.out.println(str);  }    public Object getObject()  {    return this;  }}

 

super的使用:

子类继承父类后,若要在子类中直接调用父类的构造方法,就必须使用super(...)语句,注意一下两点:

  • 若要在子类构造方法中调用父类构造方法,super()语句必须放在子类构造方法中的第一行;
  • 不能在子类构造方法中同时调用this(...)和super(...)语句,因为这两条语句都必须位于子类构造方法中的第一行

 

2. 抽象类与接口

抽象类和抽象方法:

abstract关键字是抽象修饰符,只能用于修饰类和方法。

  • 抽象类:没有具体实例对象的类。简单的说,抽象类就是一种经过优化的概念组织方式,把所要描述的事物的共性抽象出来,使得所有的概念层次分明、简洁
  • 抽象方法:在定义的时候只有方法的声明,而没有方法体的实现部分。也就是说,抽象方法仅包含访问修饰符、返回类型、方法名及参数表,而不包含方法体“{}”中的内容。至于方法的实现部分,需要在继承该抽象方法的子类中,进行定义。

归纳总结后,使用抽象类和抽象方法要注意一下4点:

  • abstract抽象类不能创建对象,必须通过子类继承后,有子类来创建对象
  • abstract抽象方法只允许方法声明,不允许方法实现
  • abstract抽象类中,可以没有抽象方法,也可以有一个或多个抽象方法
  • 若一个类中含有abstract抽象方法,那么这个类必须被声明为抽象类
public class AbstractDemo {  Employee1 e;    public AbstractDemo()  {    e=new Employee1("Wnag Xiao Yue", 3000.00, "2005/05/20", 24);    e.getInfo();    System.out.println("Age: "+e.getAge());    System.out.println("Name: "+ e.getName() + "; Salary: "+ e.getSalary()+ "; Hireday: "+e.getHireDay()+"\n");  }  public static void main(String[] args) {    new AbstractDemo();  }}abstract class People{  String name;  int age;    abstract String getName();  abstract int getAge();}class Employee1 extends People{  double salary;  String hireDay;    public Employee1(String name, double salary, String hireDay, int age)  {    this.name=name;    this.salary=salary;    this.hireDay=hireDay;    this.age=age;  }    public void getInfo()  {    System.out.println("I'm Eployee");  }  public String getName()  {    return name;  }  public int getAge()  {    return age;  }  public String getHireDay()  {    return hireDay;  }  public double getSalary()  {    return salary;  }}

I'm Eployee
Age: 24
Name: Wnag Xiao Yue; Salary: 3000.0; Hireday: 2005/05/20

 

什么是接口:

Java语言中的接口不同于一般的类,通常称为接口类,是用来描述类的功能的。在接口类中,定义了抽象的方法和常量,形成一个属性集合,该属性集合代表了一组功能的实现。在Java语言中,一个类只能继承自一个父类;但是一个类可以实现多个接口,因此使用接口主要是为了实现类的多重继承功能。

 

如何定义接口:

[public] interface 接口名 [extends 父类接口]

{

  //借口体

  //常量声明

  [public] [static] [final] 常量类型 常量名 =  常量值;

 

  //抽象方法声明

  [public] [abstract] 返回类型 方法名(参数列表) [throw 异常列表]

}

 

在定义接口类的时候需要注意一下几点:

  • 与定义类相似,定义的接口类也具有继承性。定义一个接口的时候,可以通过extends关键字来让定义的接口继承自一个已经存在的父类接口
  • 接口体由两部分组成,一部分是对接口属性的声明,另一部分是对接口中方法的声明。接口中的属性都是用final修饰的常量;而接口中的方法都是用abstract修饰的抽象方法,在接口类中,只能给出这些抽象方法的方法名、返回值、参数列表,而不能定义方法体
  • 根据编程的习惯,接口类的名字,一般都已大写字母“I”开头
public interface IEmployee{  public static final double prize=1000.00;  public abstract void addSalary();}

 

实现接口:

在定义好接口后,就可以创建一个类来实现该接口类,同时在实现类中,完成接口类中抽象方法的定义。

public class UseIEmployee {  Employee2 e;    public UseIEmployee()  {    e=new Employee2("Wnag Xiao Yue", 3000.00, "2005/05/20");    e.addSalary(2);    e.getInfo();    System.out.println("Name: "+ e.getName() + "; Salary: "+ e.getSalary()+ "; Hireday: "+e.getHireDay()+"\n");  }    public static void main(String[] args) {    new UseIEmployee();  }}class Employee2 implements IEmplyee1{  private String name;  private double salary;  private String hireDay;    public Employee2(String name, double salary, String hireDay)  {    this.name=name;    this.salary=salary;    this.hireDay=hireDay;  }    public String getName()  {return name;}    public void getInfo()  {System.out.println("I'm Employee");}    public double getSalary()  {return salary;}    public String getHireDay()  {    return hireDay;  }    public void addSalary(int n)  {    salary+=prize*n;  }}interface IEmplyee1 {    public static final double prize = 1000.00;  public abstract void addSalary(int n);}

I'm Employee
Name: Wnag Xiao Yue; Salary: 5000.0; Hireday: 2005/05/20

 

3. 内部类和匿名类

什么是内部类:

内部类就是定义在其他类内部的类,而内部类所在的类一般称为外部类。根据内部类在外部类中所处的位置,一般又分为定义在方法体的内部类以及定义在方法体外的成员内部类。同时,定义在方法体内的内部类又可以分为两种,分别是有实例名称的内部类和无实例名称的匿名内部类。

 

如何使用内部类:

(1)对于定义在方法体外的内部类(成员内部类)

又可以分为以下两种情况:

  • 定义在方法体外的成员内部类:如同其他类成员一样,也是附属于类的,可以通过外部类的实例来引用,即先创建一个外部类的实例,再通过该外部类的对象实例来创建内部类实例。语法格式有以下两种

new 外部类构造方法().内部类构造方法();

外部类对象实例.new 内部类构造方法();

public class InnerClassDemo1 {    private String s="World";    class InnerClass{     public InnerClass()     {       System.out.println("This is Inner Class constructor");     }         //内部类对象能够访问其所在外部类的全部属性,包括私有属性     public void showMessage(String str)     {       System.out.println("Hello "+s+","+str);     }  }  public static void main(String[] args) {    InnerClass i1=new InnerClassDemo1().new InnerClass();    i1.showMessage("Lilian");    System.out.println();        InnerClassDemo1 demo=new InnerClassDemo1();    InnerClass i2=demo.new InnerClass();    i2.showMessage("Kira");  }}

This is Inner Class constructor
Hello World,Lilian

This is Inner Class constructor
Hello World,Kira

  • 对于静态内部类的引用:静态内部类的附属于外部类的,而不附属于外部类的实例,因此不需要通过外部类的对象实例来创建内部类对象,直接通过外部类名就可以实现。语法格式如下:

new 外部类名.内部构造方法();

 

public class InnerClassDemo2 {    private static String s= "World";    static class InnerClass{    public InnerClass()    {      System.out.println("This is inner class constructor");    }        public void showMessage(String str)    {      System.out.println("Hello "+ s +","+str);    }  }  public static void main(String[] args) {    InnerClass i=new InnerClassDemo2.InnerClass();    i.showMessage("Lilian");  }}

This is inner class constructor
Hello World,Lilian

 

(2)对于定义在方法体内的内部类

由于附属于方法体,所以只能在方法体中创建对象实例,并且创建的实例也只能在方法体中被访问。所创建的对象实例的生命周期与方法体相同,当方法结束后,对象也就随之消失。

public class InnerClassDemo3 {  private String str="World";    public InnerClassDemo3()  {    showMessage();  }    public void showMessage()  {    System.out.println("Now you are in method!");        class InnerClass{      public InnerClass()      {        System.out.println("This is inner class constructor");      }            public void showMesage()      {        System.out.println("Hello "+ str+"!");      }    }        InnerClass i=new InnerClass();    i.showMesage();        System.out.println("Method end!");  }  public static void main(String[] args) {    new InnerClassDemo3();  }}

Now you are in method!
This is inner class constructor
Hello World!
Method end!

 

什么是匿名类

在创建类的对象的时候,会有两种方式,第一种方式是创建对象后,将该对象保存在一个对象变量中,如下所示。

类名 对象名 = new 类构造方法();

另一种方式就是所谓的匿名类方式创建对象。使用匿名类方式创建对象时,并不将创建的对象保存在对象变量中,程序会根据创建对象的构造方法中的操作,来运行程序,当程序运行结束后,该对象的生命周期也就结束了。

new 类构造方法();

 

使用内部类需要注意的问题:

  • Java程序中,对于内部类的继承没有限制,与普通的类一致,满足单继承。同时对内部类的嵌套层次也没有限制
  • 同一般类一样,可以实现接口
  • 非静态的内部类可以看作是外部类中的普通方法,对整个类具有访问权限,可以访问其所在外部类的所有属性。包括private私有属性。但是非静态的内部类中不能包含static类型的属性。非静态的内部类可以被不同访问修饰符修饰,也可以被其他外部类的成员函数访问。
  • 静态内部类可以看作是外部类中的static方法,只能访问声明为static的变量,以及调用static的方法
  • 定义在方法体中的内部类,可以看作是方法中的局部变量,可以访问外部类中的所有属性,包括private私有属性
  • 定义在方法体中的内部类,可以访问许哦在方法中被声明为final型的局部变量
  • 定义在方法体中的内部类,不能用认可访问修饰符修饰,同时也不能使用static修饰符修饰

 

实战练习:

简单模拟一个雇员工资管理的程序系统。整个系统由5个源文件组成:

  • IEmployee.java接口类,在其中定义常量prize,用来保存员工加薪的基本值,同时在接口类中声明addSalary()抽象方法,用来声明给员工加薪的方法
public interface IEmployee {    public static final double prize=1000.00;  public abstract void addSalary(); }

  • People.java抽象类,用来描述人的属性
abstract class People {  String name;  int age;    abstract String getName();  abstract int getAge();}

  • Employee.java雇员类,用来表示一个特定的员工。该类继承了People抽象类,同时实现了IEmployee接口,并在类方法体中定义了三个成员方法,用来获取雇员属性
public class Employee extends People implements IEmployee{  double salary;  String hireDay;    public Employee(String name, double salary, String hireDay, int age)  {    this.name=name;    this.salary=salary;    this.hireDay=hireDay;    this.age=age;  }    public void getInfo()  {    System.out.println("I'm Employee");  }  public double getSalary()  {    return salary;  }  public String getHireDay()  {    return hireDay;  }    //实现父类中的方法  public String getName()  {return name;}    public int getAge()  {return age;}    //实现接口中的方法  public void addSalary()  {    salary+=prize;  }}

  • Manager.jave经理类,该类继承了Employee雇员类,同时在Manager类中,使用方法重载重新定义getInfo(), getSalary(), addSalary()方法
public class Manager extends Employee{  private double bonus;  private int holidays;    public Manager(String name, double salary, String hireDay, int age, int holidays)  {    super(name, salary, hireDay, age);    this.holidays=holidays;  }    public void getInfo()  {    System.out.println("I'm Manager");  }  public double getSalary()  {    return salary;  }    public int getHolidays()  {return holidays;}    public void addSalary()  {    salary+=prize*2;  }}

  • ManageEmployeeSalary.java程序主类,包含main方法,是本系统中所有程序的入口点,用来全局控制和运行整个系统
public class ManageEmployeeSalary {  Employee e1, e2;  Manager m;    public ManageEmployeeSalary()  {    e1=new Employee("Wang Xiao Yue", 3000.00, "2005/05/20", 24);    e2=new Employee("Xu Guang Yang", 2000.00, "2006/06/02", 22);    m=new Manager("Zhao XS", 8000.00, "2004/6/2", 26, 20);        System.out.println("name:"+e1.getName());    e1.getInfo();    System.out.println("Age:"+e1.getAge());    System.out.println("Salary:"+e1.getSalary());    System.out.println("Hireday:"+e1.getHireDay()+"\n");        System.out.println("name:"+e2.getName());    e2.getInfo();    System.out.println("Age:"+e2.getAge());    System.out.println("Salary:"+e2.getSalary());    System.out.println("Hireday:"+e2.getHireDay()+"\n");        System.out.println("name:"+m.getName());    m.getInfo();    System.out.println("Age:"+m.getAge());    System.out.println("Salary:"+m.getSalary());    System.out.println("Hireday:"+m.getHireDay()+"\n");        e1.addSalary();    e2.addSalary();    m.addSalary();    System.out.println("\nAfter adding salary:");    System.out.println(e1.getName()+"'s salary is:"+e1.getSalary());    System.out.println(e2.getName()+"'s salary is:"+e2.getSalary());    System.out.println(m.getName()+"'s salary is:"+m.getSalary());      }  public static void main(String[] args) {    new ManageEmployeeSalary();      }}

name:Wang Xiao Yue
I'm Employee
Age:24
Salary:3000.0
Hireday:2005/05/20

name:Xu Guang Yang
I'm Employee
Age:22
Salary:2000.0
Hireday:2006/06/02

name:Zhao XS
I'm Manager
Age:26
Salary:8000.0
Hireday:2004/6/2


After adding salary:
Wang Xiao Yue's salary is:4000.0
Xu Guang Yang's salary is:3000.0
Zhao XS's salary is:10000.0