JAVA自学教程之(继承及super使用)



JAVA自学教程之(继承及super使用)。继承:(extends)
很多类,但是有一些成员,都是重复的,所以为提供复用性,把重复的代码抽取出来,就应用了继承 1.提高了代码的复用性

2.让类与类之间产生了关系,继承给多态提供了前提,没继承就没多态

 

 

  1. class MAN
  2. {
  3.     String name;
  4.     int age;
  5. }
  6. class student extends MAN //MAN是student的基类,student是MAN的子类
  7. {
  8.     void study()
  9.     {
  10.         System.out.println(name+”正在学习”+age);
  11.     }
  12. }
  13. class teacher extends MAN
  14. {
  15.     void work()
  16.     {
  17.         System.out.println(name+”正在工作”+age);
  18.     }
  19. }
  20. public class Main
  21. {
  22.     public static void main (String[] args)
  23.     {
  24.         student BLF = new student();
  25.         BLF.name = “BLF2″;
  26.         BLF.age = 20;
  27.         BLF.study();
  28.     }
  29. }
class MAN
{
	String name;
	int age;
}
class student extends MAN //MAN是student的基类,student是MAN的子类
{
	void study()
	{
		System.out.println(name+"正在学习"+age);
	}
}
class teacher extends MAN
{
	void work()
	{
		System.out.println(name+"正在工作"+age);
	}
}
public class Main
{

	public static void main (String[] args) 
	{
		student BLF = new student();
		BLF.name = "BLF2";
		BLF.age = 20;
		BLF.study();
	}
}

 

 

概念理解图:

单继承和多继承
JAVA支持单继承,不直接支持多继承,但是在C++的多继承机制上进行了改良。
定义:

1、单继承:一个子类只能有一个直接父类。

class A extends B ,B extends C;

2、多继承:一个子类可以有多个直接父类,(java中不允许)进行了改良。

class A extends B;A extend C;

多继承的优点: 类A 中有一些变量,类B中有一些东西,如果C继承了A和B,那么C就同时拥有了A,B的东西 C++多继承的缺点:
见代码:

 

  1. #include <iostream>
  2. using namespace std;
  3. class A
  4. {
  5. public :
  6.     void show()
  7.     {
  8.     cout<<”sd”<<endl;
  9.     }
  10. }
  11. class B
  12. {
  13. public :
  14.     void show()
  15.     {
  16.     cout<<”sssd”<<endl;
  17.     }
  18. }
  19. class C :public A,public B//A,B的show都是同一个函数名
  20. {
  21. }
  22. C BLF;
  23. int main()
  24. {
  25.     BLF.show();//此处C++代码的多继承,就会出现混乱,必须让show,show1、show2,名字保证不一样,才可以
  26.     return 0;
  27. }
#include <iostream>
using namespace std;
class A
{
public :
	void show()
	{
	cout<<"sd"<<endl;
	}
}
class B
{
public :
	void show()
	{
	cout<<"sssd"<<endl;
	}
}
class C :public A,public B//A,B的show都是同一个函数名
{

}
C BLF;
int main()
{
	BLF.show();//此处C++代码的多继承,就会出现混乱,必须让show,show1、show2,名字保证不一样,才可以
	return 0;
}

java的多继承:不直接支持多继承,因为,一旦父类中出现了相同的成员,就会产生不确定性,java改良了C++这一缺陷

 

java的多继承,是通过“多实现”的方式来实现
java支持多层(多重)继承:D 继承 C,C 继承 B,B继承A,就会出现继承体系,
注意:当要使用一个继承体系时:

1.查看体系的最顶层,了解体系的基本功能

2.创建体系的最子类对象,完成功能的使用

继承体系图:

 

 

什么时候定义继承?
当类与类之间有所属关系时,使用继承,如:xxx是yyy的一种,那么xxx继承于yyy,谁是谁中的一种 所属关系:A is a B;A继承于B
子父类中成员变量的特点: 1.成员变量  2.成员函数  3.构造函数
一、成员变量

  1. class father
  2. {
  3.     int num = 5;
  4. }
  5. class son extends father
  6. {
  7.     int num = 6;
  8.     void show()
  9.     {
  10.         System.out.print(num+” : “+num);//6 : 6
  11.     }
  12. }
  13. public class Main
  14. {
  15.     public static void main(String[] args)
  16.     {
  17.         son zSon = new son();
  18.         zSon.show();
  19.     }
  20. }
class father
{
	int num = 5;
}
class son extends father
{
	int num = 6;
	void show()
	{
		System.out.print(num+" : "+num);//6 : 6
	}
}

public class Main
{
	public static void main(String[] args)
	{
		son zSon = new son();
		zSon.show();
	}
}

子类中的有,坚决不找父类
当本类的成员和局部变量重名,用this来区分,当子父类中的成员重名,用super区分。

super的用法和this相似。

 

  1. class father
  2. {
  3.     int num = 5;
  4. }
  5. class son extends father
  6. {
  7.     int num= 6;
  8.     void show()
  9.     {
  10.         System.out.print(this.num+” : “+super.num);// 6 :5
  11.     }
  12. }
  13. public class Main
  14. {
  15.     public static void main(String[] args)
  16.     {
  17.         son zSon = new son();
  18.         zSon.show();
  19.     }
  20. }
class father
{
	int num = 5;
}
class son extends father
{
	int num= 6;
	void show()
	{
		System.out.print(this.num+" : "+super.num);// 6 :5
	}
}

public class Main
{
	public static void main(String[] args)
	{
		son zSon = new son();
		zSon.show();
	}
}

上述代码,作为了解,父类有num,子类继承于父类自然也有num
两者区别: this:代表一个类的引用 super:代表一个父类的空间
子父类内存图:

 

 

子类不能直接访问,父类中的私有内容,但是可以间接访问,开发时不常见,面试多见

 

  1. class father
  2. {
  3.     private int num = 5;
  4.     public int getnum()
  5.     {
  6.         return num;
  7.     }
  8. }
  9. class son extends father
  10. {
  11.     int num= 6;
  12.     void show()
  13.     {
  14.         System.out.print(this.num+” : “+super.getnum());
  15.     }
  16. }
  17. public class Main
  18. {
  19.     public static void main(String[] args)
  20.     {
  21.         son zSon = new son();
  22.         zSon.show();
  23.     }
  24. }
class father
{
	private int num = 5;
	public int getnum()
	{
		return num;
	}
}
class son extends father
{
	int num= 6;
	void show()
	{
		System.out.print(this.num+" : "+super.getnum());
	}
}

public class Main
{
	public static void main(String[] args)
	{
		son zSon = new son();
		zSon.show();
	}
}

 

 

二、成员函数

 

  1. class father
  2. {
  3.     void show1()
  4.     {
  5.         System.out.println(“father”);
  6.     }
  7. }
  8. class son extends father
  9. {
  10.     void show2()
  11.     {
  12.         System.out.println(“son”);
  13.     }
  14. }
  15. public class Main
  16. {
  17.     public static void main(String[] args)
  18.     {
  19.         son zSon = new son();
  20.         zSon.show1();
  21.         zSon.show2();
  22.     }
  23. }


class father
{
	void show1()
	{
		System.out.println("father");
	}
}
class son extends father
{
	void show2()
	{
		System.out.println("son");
	}
}

public class Main
{
	public static void main(String[] args)
	{
		son zSon = new son();
		zSon.show1();
		zSon.show2();
	}
}

当子父类中出现成员函数一样(函数名一样,返回类型一致,函数参数列表相同)时,会运行子类的函数,成为覆盖操作,父类的操作被覆盖了,这是函数在子父类中的特性

 

 

 

 

 

  1. class father
  2. {
  3.     void show()
  4.     {
  5.         System.out.println(“father”);
  6.     }
  7. }
  8. class son extends father
  9. {
  10.     void show()
  11.     {
  12.         System.out.println(“son”);
  13.     }
  14. }
  15. public class Main
  16. {
  17.     public static void main(String[] args)
  18.     {
  19.         son zSon = new son();
  20.         zSon.show();
  21.         zSon.show();
  22.     }
  23. }
class father
{
	void show()
	{
		System.out.println("father");
	}
}
class son extends father
{
	void show()
	{
		System.out.println("son");
	}
}

public class Main
{
	public static void main(String[] args)
	{
		son zSon = new son();
		zSon.show();
		zSon.show();
	}
}

函数的两个特性:1.重载 2.覆盖(重写/复写)
重载是同一个类中,覆盖是在子类中
覆盖注意 :
1.子类方法覆盖父类方法时,子类权限必须 >= 父类的权限,才能覆盖(上述代码父类show前加public就无法覆盖,son的show也加public就行,不能用static修饰其中一个,必须两个都static才行)
2.静态只能覆盖静态,或被静态覆盖
什么时候使用覆盖?
当对一个类,进行子类的扩展时,子类需要保留父类的功能声明,但是在定义子类中功能的特有功能时,就使用覆盖操作完成
比如电话:来电显示功能,后期想添加 号码来自地区

 

 

  1. class phone
  2. {
  3.      void show()
  4.     {
  5.         System.out.println(“number”);
  6.     }
  7.      void call()
  8.      {}
  9.      void memssage()
  10.      {}
  11.      //….
  12. }
  13. class phone2 extends phone//phone中有一些功能不需要改,所以采用继承
  14. {
  15.      void show()//只需修改show的功能
  16.     {
  17.         System.out.println(“from”);
  18.         super.show();//保留父类的功能
  19.     }
  20. }
  21. public class Main
  22. {
  23.     public static void main(String[] args)
  24.     {
  25.         phone2 zSon = new phone2();
  26.         zSon.show();
  27.     }
  28. }
class phone
{
	 void show()
	{
		System.out.println("number");
	}
	 void call()
	 {}
	 void memssage()
	 {}
	 //....
}
class phone2 extends phone//phone中有一些功能不需要改,所以采用继承
{
	 void show()//只需修改show的功能
	{
		System.out.println("from");
		super.show();//保留父类的功能
	}
}

public class Main
{
	public static void main(String[] args)
	{
		phone2 zSon = new phone2();
		zSon.show();

	}
}

 

子父类中的构造函数的特点:

 

  1. class father
  2. {
  3.     father() {
  4.         System.out.println(“fu”);
  5.     }
  6. }
  7. class son extends father
  8. {
  9.     son() {
  10.         System.out.println(“so”);
  11.     }
  12. }
  13. public class Main
  14. {
  15.     public static void main(String[] args)
  16.     {
  17.         //super();
  18.         new son();
  19.     }
  20. }
class father
{
	father() {
		System.out.println("fu");
	}
}
class son extends father
{
	son() {
		System.out.println("so");
	}
}
public class Main
{
	public static void main(String[] args)
	{
		//super();
		new son();
	}
}

打印 fu      so
在子类构造对象时,发现,访问子类构造函数时,父类构造函数也运行了?
在子类构造函数的第一行有一个默认的隐式语句 super();有super() ,表示正在调用父类中的空参数的构造函数。 (父类构造函数如果有参的话,那么super就要自己写了)

 

 

  1. class father
  2. {
  3.     father()
  4.     {
  5.         System.out.println(“A”);
  6.     }
  7.     father(int x)
  8.     {
  9.         System.out.println(“B”);
  10.     }
  11. }
  12. class son extends father
  13. {
  14.     son()
  15.     {
  16.         //super();
  17.         System.out.println(“C”);
  18.     }
  19.     son(int x)
  20.     {
  21.         super(x);
  22.         System.out.println(“D”+x);
  23.     }
  24. }
  25. public class Main
  26. {
  27.     public static void main(String[] args)
  28.     {
  29.         new son(6);
  30.     }
  31. }
class father
{
	father() 
	{
		System.out.println("A");
	}
	father(int x) 
	{
		System.out.println("B");
	}
}
class son extends father
{
	son() 
	{
		//super();
		System.out.println("C");
	}
	son(int x) 
	{
		super(x);
		System.out.println("D"+x);
	}
}
public class Main
{
	public static void main(String[] args)
	{
		new son(6);
	}
}

子类的实例化过程,子类中所有的构造函数都会访问父类中空参数的构造函数
为什么实例化的时候,要访问父类的构造函数?
子类继承了父类,拥有了父类的内容(属性和行为)所以在使用父类内容之前,要知道父类是如何进行初始化的,所以子类在构造对象时,就必须访问父类中的构造函数,为了完成这个必须的动作,就在子类的构造函数中加入默认的super()。 如果父类中,没有定义空参数的构造函数,那么子类的构造函数必须用super明确的调用父类中对应构造函数

 

 

  1. class father
  2. {
  3.     int num;
  4.     father()
  5.     {
  6.         num = 8;
  7.         System.out.println(“A”);
  8.     }
  9. }
  10. class son extends father
  11. {
  12.     son()
  13.     {
  14.         System.out.println(“C”+num);
  15.     }
  16. }
class father
{
	int num;

	father() 
	{
		num = 8;
		System.out.println("A");
	}

}
class son extends father
{
	son() 
	{
		System.out.println("C"+num);
	}

}

 

如果子类不访问父类的构造函数的话,那么打印 C 0,所以访问父类构造函数成为了必须。 内存空间一建立,父类中的num会在子类的num都会在内存中展现出来,所以子类必须知道父类怎么初始化的
注意:super语句必须在子类构造函数的第一行。因为父类的初始化的动作在子类前,必须先完成。
this和super:

this 和super 在构造函数都必须在一行,那是不是就引起冲突呢。 子类函数中,如果使用了this调用了本来的构造函数,但是this和super都必须房子本类构造函数的第一行,所以只能有一个 但是,子类中肯定有其他的构造函数访问父类的构造函数。
代码如下:

 

  1. class father
  2. {
  3.     int num;
  4.     father()
  5.     {
  6.         num = 8;
  7.         System.out.println(“A”);
  8.     }
  9. }
  10. class son extends father
  11. {
  12.     son()
  13.     {
  14.     }
  15.     son(int x)
  16.     {
  17.         this();//使用this,省掉super,原因:使用this调用本类的son(),而son(){} 继承于father,son(){}中有默认          //的super();肯定至少有一个访问父类的构造函数
  18.         System.out.println(“C”+num);
  19.     }
  20. }
  21. public class Main
  22. {
  23.     public static void main(String[] args)
  24.     {
  25.         new son(6);
  26.     }
  27. }
class father
{
	int num;

	father() 
	{
		num = 8;
		System.out.println("A");
	}

}
class son extends father
{
	son()
	{

	}
	son(int x) 
	{
		this();//使用this,省掉super,原因:使用this调用本类的son(),而son(){} 继承于father,son(){}中有默认			//的super();肯定至少有一个访问父类的构造函数
		System.out.println("C"+num);
	}

}
public class Main
{
	public static void main(String[] args)
	{
		new son(6);
	}
}

 

 

子类的实例化过程:

 

  1. class father
  2. {
  3.     father()
  4.     {
  5.         show();
  6.     }
  7.     void show()
  8.     {
  9.         System.out.println(“asdf”);
  10.     }
  11. }
  12. class son extends father
  13. {
  14.     int num = 8;
  15.     son()
  16.     {
  17.         super();
  18.         //System.out.println(“dfsdf”);
  19.     }
  20.     void show()
  21.     {
  22.         System.out.println(“num is “+num);
  23.     }
  24. }
  25. public class Main
  26. {
  27.     public static void main(String[] args)
  28.     {
  29.         son s = new son();
  30.         s.show();
  31.     }
  32. }
class father
{

	father() 
	{
		show();
	}
	void show()
	{
		System.out.println("asdf");
	}
}
class son extends father
{
	int num = 8;
	son()
	{
		super();
		//System.out.println("dfsdf");
	}
	void show()
	{
		System.out.println("num is "+num);
	}

}
public class Main
{
	public static void main(String[] args)
	{
		son s = new son();
		s.show();
	}
}

打印: num is 0 num is 8
再看把上述代码注释部分打开 打印: num is 0 dfsdf num is 8

 

 

 

  1. class father
  2. {
  3.     father()
  4.     {
  5.         show();
  6.     }
  7.     void show()
  8.     {
  9.         System.out.println(“asdf”);
  10.     }
  11. }
  12. class son extends father
  13. {
  14.     int num = 8;
  15.     son()
  16.     {
  17.         super();//通过super初始化父类内容时,子类并未进行初始化,等super()父类初始化
  18.                 //完毕后,才进行子类的成员变量,显示初始化->分水岭
  19.     }
  20.     void show()
  21.     {
  22.         System.out.println(“num is “+num);
  23.     }
  24. }
  25. public class Main
  26. {
  27.     public static void main(String[] args)
  28.     {
  29.         son s = new son();
  30.         s.show();
  31.     }
  32. }
class father
{

	father() 
	{
		show();
	}
	void show()
	{
		System.out.println("asdf");
	}
}
class son extends father
{
	int num = 8;
	son()
	{
		super();//通过super初始化父类内容时,子类并未进行初始化,等super()父类初始化
		        //完毕后,才进行子类的成员变量,显示初始化->分水岭
	}
	void show()
	{
		System.out.println("num is "+num);
	}
}
public class Main
{
	public static void main(String[] args)
	{
		son s = new son();
		s.show();
	}
}
  1. /*
  2. * 一个对象实例化过程
  3. * son s = new son();
  4. * 1.JVM会读取指定路径下的son.class文见,并加载进内存,如果有直接父类,先加载父类
  5. * 2.在堆内存中开辟空间,分配地址
  6. * 3.并在对象空间中,对对象中的属性进行默认初始化
  7. * 4.调用对应的构造函数进行初始化
  8. * 5.在构造函数中第一行,会先调用父类的构造函数,进行初始化
  9. * 6.父类初始完毕,再对子类的属性进行显示初始化,
  10. * 7.再进行子类构造函数的特定初始化
  11. * 8.子类初始化完毕后将地址值给引用变量
  12. * */
/*
 * 一个对象实例化过程
 * son s = new son();
 * 1.JVM会读取指定路径下的son.class文见,并加载进内存,如果有直接父类,先加载父类
 * 2.在堆内存中开辟空间,分配地址
 * 3.并在对象空间中,对对象中的属性进行默认初始化
 * 4.调用对应的构造函数进行初始化
 * 5.在构造函数中第一行,会先调用父类的构造函数,进行初始化
 * 6.父类初始完毕,再对子类的属性进行显示初始化,
 * 7.再进行子类构造函数的特定初始化
 * 8.子类初始化完毕后将地址值给引用变量
 * */

 

PS:C++针对多继承体系重复继承相同基类的同一成员多次继承的弊端,改用虚基类来改良,但是,子类的必须要写他的每一个直接基类的构造函数,代码冗杂,java利用super,来代替原来的基类的构造函数,且是单继承,每一个类的构造函数都含指向有他的直接基类的空间地址

  1. class FU{
  2.     public int num;
  3.     public String name;
  4.     public FU(int num,String name) {
  5.         this.num = num;
  6.         this.name = name;
  7.         System.out.println(“FU.FU()”);
  8.     }
  9. class ZI extends FU{
  10.     private int age;
  11.     ZI(int age,int num,String name){
  12.         super(num,name);this.age = age;
  13.     }