今天学习Java中的抽象类和接口,接口是Java中一个非常重要的技术,可以实现一个类继承多个抽象方法(多继承)。
在Java中,一个文件只能有一个public类,但非public类可以有多个,而且该文件的文件名要与public类文件名相同。比如下面这个例子中,文件名应为TextDemo.java。
*对子类对象实例化过程的探究
package day3;
class Person
{
String name;
int age;
//父类的构造方法
Person()
{
System.out.println("1.public Person{}调用了");
}
}
class Student extends Person
{
String school;
//子类的构造方法
public Student()
{
System.out.println("2.public Student{}调用了");
}
}
public class TextDemo {
public static void main(String[] args)
{
Student s=new Student();
}
}
结果:
1.public Person{}调用了
2.public Student{}调用了
可以看出子类对象在实例化时会默认先去调用父类中的无参构造方法,之后再调用本类中的相应构造方法。
*super关键字的使用(很像C++中的冒号语法)
package day3;
class Person
{
String name;
int age;
//父类的构造方法,给出有参构造
Person(String name,int age)
{
this.name=name;
this.age=age;
}
}
class Student extends Person
{
String school;
//子类的构造方法,只给出无参构造
public Student()
{
//在这里用super调用父类中的构造方法
super("lzh",20);
}
}
public class TestDemo {
public static void main(String[] args) {
Student s=new Student();
//为Student对象s的school域赋值
s.school="SHU";
System.out.println("姓名:"+s.name+",年龄:"+s.age+",学校:"+s.school);
}
}
super的主要功能是完成子类调用父类(也称超类)中的内容,也就是调用父类中的属性和方法。在这里调用了超类中的构造方法,与冒号语法非常相像,在今天的第一个例子中super();是缺省的。
*通过super调用父类的属性和方法
package day3;
class Person
{
String name;
int age;
//父类的构造方法
Person()
{
}
public String talk()
{
return "我是:"+this.name+",今年:"+this.age+"岁";
}
}
class Student extends Person
{
String school;
//子类的构造方法
public Student(String name,int age,String school)
{
//在这里用super调用父类中的属性
this.name=name;//用this其实也可以
super.age=age;
//调用父类中的talk()方法
System.out.print(super.talk());
//调用本类中的school属性
this.school=school;
}
}
public class TestDemo {
public static void main(String[] args) {
Student s=new Student("x",19,"SHU");
System.out.println(",学校"+s.school);
}
}
上例说明了super关键字不仅可以用于调用父类中的构造方法,也可用于调用父类中的属性或方法。注意:this也可以调用父类的属性,但this不能像super那样还能调用父类的方法。
有时候,超类不希望子类可以访问自己类中全部的属性或方法,所以需要将一些属性与方法隐藏起来,不让子类去使用,为此可以在声明属性或方法时加上private关键字表示私有。
覆写:与重载相似,所谓重载即是在不同的场合做不同的事。覆写是指子类中的某个方法与父类中的方法的名称、参数个数、类型都完全一致。这时子类的对象调用该方法时将采用子类的方法,覆盖了父类的方法。
*多态性
package day3;
class Person
{
public void fun1()
{
System.out.println("调用了父类的fun1()");
}
public void fun2()
{
System.out.println("调用了父类的fun2()");
}
}
class Student extends Person
{
//在这里覆写了Person类中的fun1()方法
public void fun1()
{
System.out.println("调用了子类的fun1()");
}
public void fun3()
{
System.out.println("调用了子类的fun3()");
}
}
public class TestDemo {
public static void main(String[] args) {
//此处,父类对象由子类实例化
Person p=new Student();
//调用fun1()方法,观察此处调用的是哪个类里面的fun1()方法
p.fun1();
p.fun2();
//p.fun3();报错:不能调用fun3()说明p仍然是父类对象
}
}
运行结果:
调用了子类的fun1()
调用了父类的fun2()
从结果可以看到,p是父类的对象,但调用fun1()方法的时候并没有调用其本身的fun1()方法,而是调用了子类中被覆写了的fun1()方法。这是因为父类对象并非由其本身的类实例化,而是通过子类实例化,这就是对象的多态性,即子类实例化对象可以转换为父类实例化对象(向上转型)。
还有一种向下转型,即是父类对象可转换为子类对象,这个时候需要强制类型转换,并且在父类对象实例化时就应该用这个子类对象对其实例化,如下。
Person p=new Student();
Student s=(Student)p;//强制转换
抽象类(abstract class):一种专门的父类,只是与普通的类相比其中多了抽象方法(abstract 返回值 方法名称(形参表))。
抽象类定义规则:
①抽象类和抽象方法必须用abstract关键字修饰。
②抽象类不能被直接实例化,也就是不能直接用new关键字去产生对象。
③抽象方法只需要声明,而不需要实现。
④含有抽象方法的类必须被声明为抽象类,抽象类的子类必须覆写所有的抽象方法后才能被实例化,否则这个子类还是个抽象类。
*抽象类的使用
package day3;
abstract class Person
{
String name;
int age;
String occupation;
//抽象类中也可以拥有构造方法
public Person(String name,int age,String occupation)
{
this.name=name;
this.age=age;
this.occupation=occupation;
}
public abstract String talk();//抽象方法只声明不实现
}
class Student extends Person
{
public Student(String name,int age,String occupation)
{
//抽象类中的构造方法必须在子类中被明确调用
super(name,age,occupation);
}
public String talk()
{
return "学生->姓名:"+this.name+",年龄:"+this.age+",职业:"+this.occupation;
}
}
class TestDemo {
public static void main(String[] args) {
Student s=new Student("lzh",20,"学生");
System.out.println(s.talk());
}
}
抽象类的唯一作用就是用来被继承的。
接口(interface):接口和抽象类非常相似,也具有数据成员与抽象方法,但它与抽象类又以下两点不同。
①接口里的数据成员必须初始化,且数据成员均为常量(final)。
②接口里的方法必须全部声明为abstract,也就是说,接口不能像抽象类一样保有一般的方法,必须全部是“抽象方法”。
接口定义的语法如下:
interface 接口名称 //定义抽象类
{
final 数据类型 成员名称=常量; //数据成员必须赋值
abstract 返回值的数据类型 方法名称(参数...);
}
接口的方法必须全部是抽象方法,而没有一般的方法,所以如上格式中,abstract是可以省略的。接口中的数据成员必须赋值,且此值不能再被更改,所以声明数据成员的关键字final也可以省略。
接口实现的语法如下:
class 类名称 implements 接口A,接口B
{
...
}
一个类只可以继承一个父类,但却可以实现多个接口。
接口扩展的语法如下:
interface 子接口名称 extends 父接口1,父接口2
{
...
}
*接口的继承使用
package day3;
interface A
{
int a=10;
public void sayA();
}
interface E
{
int e=40;
public void sayE();
}
//B同时继承了A、E两个接口
interface B extends A,E
{
int b=20;
public void sayB();
}
//C继承实现B接口,也就意味着要实现A、B、E等三个接口的抽象方法
class C implements B
{
public void sayA()
{
System.out.println("a="+a);
}
public void sayE()
{
System.out.println("e="+e);
}
public void sayB()
{
System.out.println("b="+b);
}
}
class TestDemo {
public static void main(String[] args) {
C c=new C();
c.sayA();
c.sayE();
c.sayB();
}
}
运行结果:
a=10
e=40
b=20
参考书籍是人民邮电的《Java从入门到精通》,笔记中的多数例子和释义也是基于这本书。
收工。