java基础三(继承)

java面向对象三大特性,封装、继承、多态。上一节中我们已经学习了有关封装的知识,接下来我们来学习继承。

1.概念
  1.1一种类与类之间的关系
  1.2使用已存在的类的定义作为基础建立新类
  1.3新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。
  1.4满足"A is a B"的关系
2.特点:
  2.1利于代码复用
  2.2缩短开发周期
3.语法:
  3.1 使用extends实现继承
  3.2 单一继承,只能有一个父类。(如:狗继承动物,动物称作父类或基类,狗称作子类或派生类)

  3.3子类只能继承自父类的非私有成员,父类不可以访问子类的特有成员

  3.4语法规则:返回值类型、方法名、参数类型、顺序、个数都要与父类继承的方法相同。

4.继承后的初始化顺序:

父类静态成员——>子类静态成员——>父类对象构造——>子类对象构造


5.学习方法重写的知识,并比较:方法重载与方法重写

* 方法重写
      * 1) 有继承关系的子类中
      * 2) 方法名相同,参数列表相同(参数顺序、个数、类型),方法返回值相同
      * 3) 访问修饰符,访问范围需要大于等于父类的访问范围
      * 4) 与方法的参数名无关
* 方法重载:
      * 1) 同一个类中
      * 2) 方法名相同,参数列表不同(参数顺序、个数、类型)
      * 3) 方法返回值、访问修饰符任意
      * 4) 与方法的参数名无关

注:方法重写存在,属性重写不存在。

       虽然重写仅限于方法上面,但是在子类中,可以定义与父类重名的属性的。


6.访问修饰符

公有的:public  允许在任意位置访问
私有的:private  只允许在本类中进行访问
受保护的:protected  允许在当前类、同包子类/非子类、跨包子类调用。跨包非子类不允许
默认: 允许在当前类,同包子类/非子类调用。跨包子类/非子类不允许调用。

即满足这样的关系

访问修饰符 本类 同包 子类 其他
private      
默认    
protected  
public

7.如何区分调用的是父类的继承父类的方法,还是子类自己重写的方法?

——接下来我们学习和使用super关键字

7.1 super:父类对象的引用

注:1.父类的构造不允许被继承、不允许被重写,但是会影响子类对象的实例化过程。

       2.继承后的初始化顺序:
         父类静态成员——>子类静态成员——>父类对象构造(属性(赋值)、构造代码块、构造方法)——>子类对象构造(属性(赋值)、构造代码块、构造方法)

7.2 super的使用:
1)子类构造默认调用的父类的无参构造方法;

  除了父类和子类的无参构造方法,我们也拥有一个父类和子类的双参构造,但是即使是这样,在我们进行调用的时候,默认的顺序仍然是:父类的静态代码块、子类的静态代码块、父类的构造代码块、父类的无参构造方法、子类的构造代码块、子类的带参构造方法

(注:具体的执行流程,可以在断点调试中详细观察。下面直接贴出运行结果)

package com.susu.animal;

//父类
public class Animal {

	private String name = "妮妮";// 昵称
	protected int month;// 月份
	String species = "动物";// 品种

	static {
		System.out.println("我是父类的静态代码块");
	}

	public static int st2 = 23;
	private static int st1 = 22;

	{
		System.out.println("我是父类的构造代码块");
	}

	// 父类的构造不允许被继承、不允许被重写,但是会影响子类对象的实例化
	 public Animal() {
		System.out.println("我是父类的无参构造方法");
	}

	public Animal(String name, int month) {
		this.name = name;
		this.month = month;
		System.out.println("我是父类的带参构造方法");
	}
package com.susu.animal;
//子类
public class Cat extends Animal{
	private double weight;//体重
	public static int st3=44;
	
	static{
		System.out.println("我是子类的静态代码块");
	}
	
	{
		System.out.println("我是子类的构造代码块");
	}
	
	public Cat(){

		System.out.println("我是子类的无参构造方法");
	}
	
	public Cat(String name,int month){
		System.out.println("我是子类的带参构造方法");
	}
package com.susu.animal;
//测试类
public class Test {

	public static void main(String[] args) {
		Cat one = new Cat();
		/*
		 *  我是父类的静态代码块
			我是子类的静态代码块
			我是父类的构造代码块
			我是父类的无参构造方法
			我是子类的构造代码块
			我是子类的无参构造方法
		 */

		Cat two = new Cat("xinxin",12);
		/*我是父类的静态代码块
		我是子类的静态代码块
		我是父类的构造代码块
		我是父类的无参构造方法
		我是子类的构造代码块
		我是子类的带参构造方法*/
	}
}

 通过以上代码的运行结果,我们可以清楚的看到,不管是子类调用是带参还是无参,都会默认调用父类的无参构造,而不是带参构造。那么如果我们非要调用父类的带参构造呢?下面我们来看第二点。

2)我们可以通过super()调用父类允许被访问的其他构造方法;

  我们写一个父类和子类的双参构造,如果想要调用双参构造方法,我们只需要把参数传进来就好。如:super(name,month),当进入子类双参构造时,由于super(name,month)的存在,会进入父类的双参构造,完成我们期待的指定构造方法的调用。

  即顺序:父类的静态代码块、子类的静态代码块、父类的构造代码块、父类的带参构造方法、子类的构造代码块、子类的带参构造方法

为了更好的证明这一点,我们把修改后的代码,以及运行结果贴出来:

package com.susu.animal;

//父类
public class Animal {

	private String name = "妮妮";// 昵称
	protected int month;// 月份
	String species = "动物";// 品种

	static {
		System.out.println("我是父类的静态代码块");
	}

	public static int st2 = 23;
	private static int st1 = 22;

	{
		System.out.println("我是父类的构造代码块");
	}

	// 父类的构造不允许被继承、不允许被重写,但是会影响子类对象的实例化
	 public Animal() {
		System.out.println("我是父类的无参构造方法");
	}

	public Animal(String name, int month) {
		this.name = name;
		this.month = month;
		System.out.println("我是父类的带参构造方法");
	}
package com.susu.animal;
//子类
public class Cat extends Animal{
	private double weight;//体重
	public static int st3=44;
	
	static{
		System.out.println("我是子类的静态代码块");
	}
	
	{
		System.out.println("我是子类的构造代码块");
	}
	
	public Cat(){

		System.out.println("我是子类的无参构造方法");
	}
	
	public Cat(String name,int month){
        /* 子类构造默认调用父类无参构造方法
		 * 可以通过super()调用父类允许被访问的其他构造方法
		 * super()必须放在子类构造方法有效代码第一行
		 */
		super(name,month); //this
		System.out.println("我是子类的带参构造方法");
	}
package com.susu.animal;
//测试类
public class Test {

	public static void main(String[] args) {
		Cat three = new Cat("xinxin",12);
		/**
		 * 	我是父类的静态代码块
			我是子类的静态代码块
		 * 	我是父类的构造代码块
			我是父类的带参构造方法
			我是子类的构造代码块
			我是子类的带参构造方法
		 */
	}
}

 以上代码只是在原有代码的基础上,做了一点点的修改,就产生了我们预期的效果。实际上,我只在Cat类的双参构造中,添加了一行语句,super(name,month),从而调用父类允许被访问的其他构造方法。

3)super()必须放在子类构造方法有效代码第一行。

public Cat(String name,int month){
		/* 子类构造默认调用父类无参构造方法
		 * 可以通过super()调用父类允许被访问的其他构造方法
		 * super()必须放在子类构造方法有效代码第一行
		 */
		super(name,month);  //放在了第一行。如果放在其他行,如打印语句的下面,会报错。
		System.out.println("我是子类的带参构造方法");
	}

7.3 super知识的总结:
super:代表父类引用

子类访问父类成员:
    -访问父类成员方法   super.print()
    -访问父类属性    super.name;
    -访问父类构造方法  super();
   注:1.子类的构造的过程中必须调用其父类的构造方法
        2.如果子类的构造方法中没有显示标注,则系统是默认调用父类无参的构造方法
        3.如果子类构造方法中既没有显示标注,且父类中没有无参的构造方法,则编译出错。
        4.-使用super调用父类指定构造方法,必须在子类的构造方法的第一行       
7.4 比较this和super

this: 当前类对象的引用 super:父类对象的引用
-访问当前类的成员方法
-访问当前类的成员属性
-访问当前类的构造方法
-不能在静态方法中使用
-访问父类的成员方法
-访问父类的成员属性
-访问父类的构造方法
-不能在静态方法中使用
public Cat(String name,int month){
        /* 子类构造默认调用父类无参构造方法
         * 可以通过super()调用父类允许被访问的其他构造方法
         * super()必须放在子类构造方法有效代码第一行
         */
         //this();
        super(name,month); //this
        System.out.println("我是子类的带参构造方法");
    }

注: 构造方法调用时,super和this不能同时出现。因为super和this有很多的相似之处,二者都要抢占Cat带参构造中的第一行有效代码,因此放一块时,会产生矛盾。如果强制写上去,不管谁在上面,程序都会报错。


 

猜你喜欢

转载自blog.csdn.net/Wang_susu/article/details/86636533