Java中的继承与多态
继承和多态是Java语言面向对象程序设计的两个特点。下面主要讲述继承和多态的概念和用法,以及super关键字的使用。同时进一步接受构造函数的用法。
1、继承
由一个已定义的类中派生出一个新类,称为继承。利用继承可以先创建一个公共类,这个类具有多个项目的共同属性,然后一些具体的类继承该类,同时再加上自己特有的属性。
1)、超类和子类的关系
如果类A时从另一个类B中派生出来的,那么称A为子类或派生类、B为超类或父类。子类可以继承父类所有的成员变量和方法,同时自己还可以定义自己的成员变量和方法。
如果要创建一个类的子类,只需要在类声明中加入extends子句:
Class test02 extends test01{}
下面是子类test02继承了父类test01,并在测试类test03中调用父类的变量和方法:
public class test01{
String userName;
int userId;
int userAge;
String userAddress;
void print()
{
System.out.println("姓名:" + userName + "ID号:" + userId + "年龄:" + userAge + "住址:" + userAddress);
}
}
public class test02 extends test01{
boolean userSex;
void print1()
{
if (userSex) {
System.out.println("性别:" + "男");
}
else
{
System.out.println("性别:" + "女");
}
}
}
public class test03 {
public static void main(String[] args)
{
test01 t1 = new test01();
test02 t2 = new test02();
t1.userName = "小武灵灵";
t1.userId = 41009161;
t1.userAge = 22;
t1.userAddress = "陕西";
System.out.println("超类输出为:");
t1.print();
t2.userName = "灵灵小武";
t2.userId = 16190014;
t2.userAge = 22;
t2.userAddress = "西陕";
t2.userSex = true;
System.out.println("子类输出为:");
t2.print();
t2.print1();
}
}
2)、成员变量能否被继承
子类会继承其父类的所有的成员变量和成员方法,但是在其父类中被声明为private的成员变量和方法不能被继承。大家可以将上面的test01中的int userId;改为private int userId,可以看到test03中t2.userId = 16190014;这句会提示错误。
3)、对象在超类中与子类中的使用
假如有两个类:类A是类B的子类。C是类A的一个引用,它不但可以指向类A的对象,而且可以指向类B的对象。当C指向类B的对象时,它可以调用类B从类A中继承的方法或成员变量,但是不能调用类B中新增的成员变量或方法,下面是一个子类对象调用父类对象方法的实例:
public static void main(String[] args)
{
//父类的引用指向子类的对象
test01 t1 = new test02();
//创建类test02的一个对象
test02 t2 = new test02();
t1.userName = "小武灵灵";
t1.userId = 1001;
t1.userAge = 22;
t1.userAddress = "陕西";
System.out.println("这是一个父类的引用指向子类的对象");
t1.print();
System.out.println("这是子类特有的属性和方法:");
t2.userSex = true;
//调用子类特有的方法
t2.print1();
}
2、父类
在子类中经常使用父类的成员变量,或在重写的方法中使用父类中被重写的方法,这时就要访问父类的成员变量或调用父类的方法。Java中通过使用super关键字来实现对父类的访问。
Super的用途主要有二:调用父类的构造函数;用来访问被子类的成员隐藏(重定义)的超类成员。
1)、调用父类的构造函数
子类通过在方法中使用super(参数)调用父类的构造函数。其中参数指父类的构造函数所需的参数。同时在子类中super()作为第一句执行。下面是一个使用super方法调用父类的构造方法的实例:
public class test01{
String bookName;
int bookId;
int bookPrice;
public test01() { //设置默认值
bookName = "戏游记";
bookId = 1001;
bookPrice = 20;
}
public test01(test01 t)//对象作为构造函数的参数
{
bookName = t.bookName;
bookId = t.bookId;
bookPrice = t.bookPrice;
}
//初始化对象
public test01(String bookName, int bookId, int bookPrice) {
this.bookName = bookName;
this.bookId = bookId;
this.bookPrice = bookPrice;
}
public void print()
{
System.out.println("书名:" + bookName + " 序号: " + bookId + " 价格:" + bookPrice);
}
}
public class test02 extends test01{
String BookBadder;
public test02() {//设置默认值
super();
BookBadder = "科学出版社";
}
public test02(test02 t) { //对象作为构造函数的参数
super(t);
BookBadder = t.BookBadder;
}
//初始化对象
public test02(String bookName , int bookId , int bookPrice , String bookBadder) {
super(bookName , bookId , bookPrice);
BookBadder = bookBadder;
}
}
public class test03 {
public static void main(String[] args)
{
test02 t1 = new test02();//实例化一个对象
test02 t2 = new test02("三国演义", 1002, 10, "山东教育出版社");
test02 t3 = new test02(t2);
System.out.println(t1.BookBadder);
t1.print();
System.out.println(t2.BookBadder);
t2.print();
t3.print();
t3.BookBadder = "中国国际出版集团";
System.out.println(t3.BookBadder);
t3.print();
}
}
在Java中,有时还会遇到子类中的成员变量或方法与父类中的成员变量或方法同名。在下面会用一个默认的方法,当一个子类中没有使用super时,系统会自动调用父类中的默认的无参构造函数。下面是一个系统自动调用父类中的无参构造方法的实例:
class test01
{
public test01() {
System.out.println("这是一个父类");
}
}
class test02 extends test01
{
public test02() {
System.out.println("test02继承了父类test01");
}
}
public class test03 extends test02
{
public test03() {
System.out.println("test03继承了test02");
}
public static void main(String[] args) {
new test03();
}
}
子类不能继承父类的构造函数,只能使用super关键字在子类的构造函数中调用父类的构造函数。在Java中每一个构造函数都必须调用父类的构造函数作为第一条语句,当子类的构造函数中没有明确地使用super关键字时,那么系统会自动调用父类中默认的构造函数。
2)、访问超类的成员变量及方法
通过super()也可以访问超类的成员变量和方法,其今本格式为:
Super.[方法或成员变量];
这种形式多用于子类在隐藏了父类的构造函数或重写了父类的方法的情况。下面的实例将通过super变量给父类的变量赋值:
class test01
{
int a;
int b;
}
class test02 extends test01
{
int a , b;
public test02(int x, int y , int z , int q) {
//使用super调用父类中被子类隐藏的成员
super.a = x;
super.b = y;
//初始化子类中的成员
a = z;
b = q;
}
void print()
{
System.out.println(super.a + "");
System.out.println(super.b + "");
System.out.println(a + "");
System.out.println(b + "");
}
}
public class test03
{
public static void main(String[] args) {
test02 test02 = new test02(1, 2, 3, 4);
test02.print();
}
}
3)、多层次的继承
使用extends可以建立任意多层继承关系的类层次结构。我们已使用了由一个超类和子类组成的简单类层次结构。下面是一个多层次继承的实例,为了让大家更好地理解继承,我在关键位置加入了输出:
class test01
{
String bookName;
int bookId;
int bookPrice;
public test01() {
System.out.println("1");
bookName = "戏游记";
bookId = 1001;
bookPrice = 20;
System.out.println("2");
}
test01(test01 t)
{
System.out.println("3");
bookName = t.bookName;
bookId = t.bookId;
bookPrice = t.bookPrice;
System.out.println("4");
}
test01(String name , int id , int price)
{
System.out.println("5");
bookName = name;
bookId = id;
bookPrice = price;
System.out.println("6");
}
void print() {
System.out.println("书名:" + bookName + " 序号:" + bookId + "价格:" + bookPrice);
}
}
class test02 extends test01
{
String bookBadder;
public test02() {
super();
System.out.println("8");
bookBadder = "科学出版社";
}
test02(test02 t)
{
super(t);
System.out.println("9");
bookBadder = t.bookBadder;
}
test02(String x , int y , int z , String q)
{
super(x, y , z);
System.out.println("10");
bookBadder = q;
}
}
class Factory extends test02
{
String factory;
public Factory() {
super();
System.out.println("11");
factory = "达成印刷厂";
}
Factory(Factory f)
{
super(f);
System.out.println("12");
factory = f.factory;
}
Factory(String x , int y , int z , String q , String p)
{
super(x, y , z , q);
System.out.println("13");
factory = p;
}
}
public class test03
{
public static void main(String[] args) {
System.out.println("14");
Factory f1 = new Factory();
System.out.println("15");
Factory f2 = new Factory("三国演义" , 1002 , 42 , "希望出版社" , "曙光印刷厂");
System.out.println("16");
Factory f3 = new Factory(f2);
System.out.println("17");
System.out.println(f1.bookBadder);
System.out.println(f1.factory);
f1.print();
System.out.println(f2.bookBadder);
System.out.println(f2.factory);
f2.print();
f3.print();
}
}
3、重载
很多人认为重载是重写的“兄弟“,大部分书上也是将重写和重载放在一起讲解,不过大家一定要知道重写和重载是完全不同的两样东西。重载和重写有一个很相似的地方,就是他们都体现了Java的优越性。重载大大减轻了程序员的负担,让程序员不再需要记住那么多的方法名称。
1)、重载的定义:
同一个类中两个或多个方法可以共享一个相同的名称,只要它们的参数不同即可,这就是重载的概念。重载也是多态性的方法之一。下面是一个简单的print方法重载:
class Factory
{
String name;
int age;
void print()
{
System.out.println("姓名为:" + name + " 年龄为:" + age);
}
void print(String a , int b)//重载方法print
{
System.out.println("姓名为:" + a + " 年龄为" + b);
}
void print(String a , int b , int c)
{
System.out.println("姓名为:" + a + " 年龄为:" + b + "ID号为:" + c);
}
void print(String a , int b , double c)
{
System.out.println("姓名为:" + a + " 年龄为:" + b + " ID号为:" + c);
}
}
public class test03
{
public static void main(String[] args) {
Factory factory = new Factory();
factory.name = "小武灵灵";
factory.age = 22;
factory.print();
factory.print("小武", 22);
factory.print("小武灵", 22, 1001);
factory.print("灵灵小武" , 22 , 1002);
}
}
2)、重载规则
在调用重载方法时,确定要调用哪个参数是基于其参数的。如果是int参数调用该方法,则调用带int的重载方法。如果是double参数调用该方法,则调用带double的重载方法。总之参数决定重载方法的调用。
4、重写
1)、重写的定义
重写是体现Java优越性的地方之一。重写是建立在Java继承关系中的,它使得Java的语言结构更加丰富。由于父类的方法不能满足新的要求,因此需要在子类中修改从父类中继承的方法,同时还可以定义自己的方法,这就是重写的概念。通过下面的实例可以具体滴了解重写的过程:
class Factory
{
void print()
{
System.out.println("这是父类的方法");
}
}
public class test03 extends Factory
{
public static void main(String[] args) {
test03 test03 = new test03();
test03.print();
}
void print()
{
System.out.println("这是一个子类重写后的方法");
}
}
重写的目的有二:修改父类中的方法;对父类的方法进行扩展或在子类中定义具体的、特定的行为;下面的代码程序是以一个学校的名称、人数为例,编写了一个重写的类中的方法,子类重写父类中的方法主要就是为了可以修改父类中的方法:
class test01
{
String name;
int id , number;
void print()
{
System.out.println("学校名为:" + name + " 序号为:" + id + " 人数为:" + number);
}
public test01(String name , int id , int number) {
this.name = name;
this.id = id;
this.number = number;
}
}
class test02 extends test01
{
String adder;
public test02(String name, int id, int number , String adder) {
super(name, id, number);
this.adder = adder;
}
void print()
{
System.out.println("学校名为:" + name + " 学号为:" + id + "人数为:" + number
+ " 地址: " + adder);
}
}
public class test03 {
public static void main(String[] args)
{
test02 t = new test02("陕西师范大学", 1001, 1002, "师大路");
t.print();
}
}
2)、重写规则
超类中的方法并不是在任何情况下都可以重写的。当父类中的方法的访问控制修饰符为private时,该方法只能被自己的类所访问,不能被外部的类所访问,所以在子类中不能重写该方法。如果定义父类中的方法的访问控制修饰符为public,在子类中该方法被定义为private,在编译时仍然报错,因为在Java中规定重写方法不能比被重写方法有着更严格的访问权限。在子类中不可以重写父类中用private修饰的方法。具体实例可以将上面的代码test01中print()方法前加入private。
对于从父类继承的抽象方法,子类没有任何选择,必须设计该方法,除非该子类也是抽象的。父类的抽象方法必须被其非抽象的子类具体实现,因此抽象方法是必须重写的方法。下面是一个子类实现父类中未定义的抽象方法的实例:
abstract class test01
{
int a , b;
public test01(int x , int y) {
a = x;
b = y;
}
abstract void print();//定义了一个抽象方法
}
abstract class test02 extends test01
{
int c;
public test02(int x, int y , int z) {
super(x, y);
c = z;
}
abstract void print();
}
class test03 extends test02
{
int d;
public test03(int x, int y, int z , int h) {
super(x, y, z);
d = h;
}
void print()//重写抽象方法
{
System.out.println(a + b + c + d);
}
}
public class test {
public static void main(String[] args)
{
test03 t = new test03(1, 2, 3, 4);
t.print();
}
}
支持多态性是重写的另一个方面,多态性是面向对象程序设计的特性之一,一方面所有的子类继承了它们父类所有的元素,另一方面所有的子类也可以灵活定义自己的方法。重写是Java实现多态性的”一种接口,多种方法”的一种方法。下面是实例演示多个子类都可以对父类中的方法进行重写:
abstract class test01
{
int a , b;
public test01(int x , int y) {
a = x;
b = y;
}
abstract void print();//定义了一个抽象方法
}
class test02 extends test01
{
int c;
public test02(int x, int y , int z) {
super(x, y);
c = z;
}
void print() {
System.out.println(a + b + c);
}
}
class test03 extends test01
{
int d;
public test03(int x, int y, int z) {
super(x, y);
d = z;
}
void print()//重写抽象方法
{
System.out.println(a*b*d);
}
}
public class test {
public static void main(String[] args)
{
test02 t2 = new test02(1, 2, 3);
test03 t3 = new test03(1, 2, 3);
t2.print();
t3.print();
}
}
在一个代码中,有时会同时遇到重写和重载,重写是指在子类中修改从父类中继承的方法,同时还可以定义自己的方法。而重载是指在一个子类中具有相同方法名而参数却不同。由于两者都规定必须有相同的方法名,所以有时特别容易混淆。下面是一个重写与重载并存的实例:
class test01
{
int a , b;
public test01(int x , int y) {
a = x;
b = y;
}
int print()
{
return a + b;
}
int print(int x , int y)//方法重载
{
return x + y;
}
}
class test02 extends test01
{
public test02(int x, int y) {
super(x, y);
}
int print()//重写方法print()
{
return a;
}
double print(int a , double b) //test02定义了一个自己的方法
{
return a + b;
}
}
public class test {
public static void main(String[] args)
{
test01 t1 = new test01(1, 2);
test02 t2 = new test02(2, 4);
System.out.println(t1.print());
System.out.println(t1.print(2, 3));
System.out.println(t2.print());
System.out.println(t2.print(3, 4));
System.out.println(t2.print(5, 1.23234));
}
}