Java面向对象--继承

一、继承的概念

  1. 继承是类与类之间的关系,是一个很简单很直观的概念,与现实世界中的继承(例如儿子继承父亲财产)类似。
  2. 继承可以理解为一个类从另一个类获取方法和属性的过程。如果类B继承于类A,那么B就拥有A的方法和属性。
  3. 继承使用 extends 关键字。
例如:Son.java继承Person.java
public class Son extends Person {
}

二、父类与子类

父类:Person.java
public class Person {
	/**
	 * 姓名
	 */
	private String name;
	
	/**
	 * 性别 1:男;0:女
	 */
	private int gender;
	
	/**
	 * 年龄
	 */
	private int age = 18;
	
/**无参构造方法
*/
	public Person() {
	}
/**
* 有参构造方法
*/
	public Person(String name, int gender, int age) {
		super();
		this.name = name;
		this.gender = gender;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getGender() {
		return gender;
	}
	public void setGender(int gender) {
		this.gender = gender;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}
子类:Son.java
public class Son extends Person {
}

三、测试

public class SonTest {
	@Test
	public void tets01() {
		Son son01 = new Son();//此处继承的是无参构造方法;
		son01.setName("光小强");
		son01.setGender(1);
		son01.setAge(15);
		System.out.println("姓名:" + son01.getName() + "\n性别:" + (son01.getGender()==1?"男":"女") + "\n年龄:" + son01.getAge());
	}
}
运行结果:
姓名:光小强
性别:男
年龄:15

以上表明:

  1. 子类可以继承父类的属性和方法
  2. 子类无法直接继承父类的构造方法
  3. 子类在测试类中可以直接Son son01 = new Son();(看似继承了父类的无参构造),是因为子类在形成时自身创建了一个无参构造方法

四、子类继承父类构造方法并更改参数

public class Son extends Person {
	public Son() {
	}
	public Son(String name, int gender, int age) {
		this.setName(name);
		this.setGender(gender);
		this.setAge(age);
	}
}
                      或:
public class Son extends Person {
	public Son() {
	}
	public Son(String name, int gender, int age) {
		super.setName(name);
		super.setGender(gender);
		super.setAge(age);
	}
}

测试:

@Test
	public void test03() {
		Son son01 = new Son("熊大", 1, 2);
		System.out.println("姓名:" + son01.getName() + "\n性别:" + (son01.getGender()==1?"男":"女") + "\n年龄:" + son01.getAge());
	}

运行结果:

姓名:熊大
性别:男
年龄:2

五、实例化顺序

先实例化父类,再实例化子类
实例化子类时,先调用的是父类的构造方法
每实例化一个子类,都会先调用父类的构造方法
(注意:是构造方法,不是方法)

先在父类的无参构造方法中输入:
public Person() {
		System.out.println("父类的无参构造方法");
	}
再在两个子类的无参构造方法中分别输入:
public Son() {
		System.out.println("第一个子类的无参构造方法");
	}public Son01(){
		System.out.println("第二个子类的无参构造方法");
	}
测试:
@Test
	public void test04() {
		Son son = new Son();
		Son01 son01 = new Son01();
	}
运行结果:
父类的无参构造方法
第一个子类的无参构造方法
父类的无参构造方法
第二个子类的无参构造方法

六、子类可以有自己独有的方法

先在父类中新建一个方法
public void eat() {
		System.out.println("父类里的eat方法");
	}
在第一个子类中新建自己独有的方法:
public void work() {
		System.out.println("第一个子类中的work方法");
	}

在第二个子类中同样新建自己独有的方法:
public void money() {
		System.out.println("第二个子类中的money方法");
	}

测试:

@Test
	public void test05() {
		Son son = new Son();
		Son01 son01 = new Son01();
		son.work();
		son01.money();
		son.eat();
		son01.eat();
	}

运行结果:

父类的无参构造方法
第一个子类的无参构造方法
父类的无参构造方法
第二个子类的无参构造方法
第一个子类中的work方法
第二个子类中的money方法
父类里的eat方法
父类里的eat方法

七、方法重写

想在子类中重写父类中的一个或多个方法:
在子类中 右键—>source—>override—>选择想要重写的方法—>OK
测试:

父类中的eat方法
public void eat() {
		System.out.println("父类里的eat方法");
	}
子类中的eat方法(重写父类的eat方法)
@Override
	public void eat() {
		System.out.println("子类中的eat方法");
	}

测试:

@Test
	public void test06() {
		Son son = new Son();
		son.eat();
	}

运行结果:

父类的无参构造方法
第一个子类的无参构造方法
子类中的eat方法

八、父类的引用指向子类的实例化对象(向上转型)

将子类实例化对象类型换成父类,输出还是子类的方法

测试:
@Test
	public void test07() {
		Person son = new Son();
		son.eat();
	}
父类的无参构造方法
第一个子类的无参构造方法
子类中的eat方法
  1. 前提new的是子类:父类的引用指向子类的实例化对象
  2. 调用的还是子类中重写的方法
  3. 不能调用子类独有的方法

九、向下转型

父类直接转换成子类类型是没有办法调用子类方法的

错误转换:

@Test
	public void test08() {
		//只有引用类型对象的真实身份为子类对象才可以转换;
		Son person = (Son) new Person("熊二",1,12);
		person.eat();//父类直接转子类无法调用任何方法
		System.out.println("姓名:" + person.getName() + "\n性别:" + (person.getGender()==1?"男":"女") + "\n年龄:" + person.getAge());
	}

正确转换:

@Test
	public void test09() {
		//先向上转型
		Person person = new Son();
		//再向下转型,实际引用类型对象还是子类,所以不管person.eat还是son.eat调用的都是子类中的eat方法
		Son son = (Son) person;
		person.eat();
		son.eat();
		//person.work();无法调取,因为对象类型发生准便,不能调用子类独有的方法
		son.work();
		((Son)person).work();//这个其实还是将数据类型转换成子类的,就可以调用子类中的work方法,这是强制数据类型转换
	}

运行结果:

父类的无参构造方法
第一个子类的无参构造方法
子类中的eat方法
子类中的eat方法
第一个子类中的work方法
第一个子类中的work方法

十、方法重载和方法重写

重载看真实的数据类型,重写看真正的引用对象

public class InheritanceTest {
	public static void main(String[] args) {
		Super s = new Sub();
		Goo goo = new Goo();
		goo.g(s);//s的数据类型是Super,所以找数据类型g中是Super的obj;但s真正的引用对象是Sub,所以obj.f找的是Sub类,因此整体输出结果是g(Super) Sub.f
	}
}

class Super{
	public void f() {
		System.out.println("Super.f");
	}
}

class Sub extends Super{
	@Override
	public void f() {
		System.out.println("Sub.f");
	}
}

class Goo{
	public void g(Super obj) {//数据类型是个类,那它就是个对象,obj
	是个对象
		System.out.println("g(Super)");
		obj.f();
	}
	 
	public void g(Sub obj) {
		System.out.println("g(Sub)");
		obj.f();
	}
}

运行结果:

g(Super)
Sub.f

方法重载和方法重写的区别:

  1. 方法重载:
    在同一个类,参数列表不同的同名方法我们称之为方法重载;
  2. 方法重写:
    父类的方法满足不了子类需求,子类重写父类的方法我们称之为方法重写;
  3. 方法重载在同一个类中而方法重写必须存在子父类继承关系。

十一、this调用构造方法

需求:在一个类中限定属性中一个数组的长度:
方法一:在测试类中调用有参构造并进行赋值;

	private int[] capacity;
	
	public Son02(int[] capacity) {
		super();
		this.capacity = capacity;
	}

	public int[] getCapacity() {
		return capacity;
	}

	public void setCapacity(int[] capacity) {
		this.capacity = capacity;
	}

测试:

@Test
	//传参调用的是有参构造;
	public void test01() {
		Son02 son02 = new Son02(new int[10]);//给capacity这个数组传参,参数表示数组的长度
		System.out.println(son02.getCapacity().length);//输出这个数组的长度;
	}

方法二:使用使用无参构造赋值

private final int defaultCapacity = 10;//给一个变量赋值,final将这个变量定为常量,令数组的长度等于这个变量的值;这样就可以默认这个数组的长度;
	private int[] capacity;
		
	public Son02() {
		capacity = new int[defaultCapacity];//默认这个数组的长度是10;
	}
	public Son02(int[] capacity) {
		super();
		this.capacity = capacity;
	}

	public int[] getCapacity() {
		return capacity;
	}

	public void setCapacity(int[] capacity) {
		this.capacity = capacity;
	}

测试:

@Test
	//这个调用的是无参构造;
	public void test02() {
		Son02 son02 = new Son02();
		System.out.println(son02.getCapacity().length);
	}

方法三:使用this调用构造方法

private final static int defaultCapacity = 10;//想用this调用构造方法,这里必须是静态;
	private int[] capacity;
		
	public Son03() {
		//capacity = new int[defaultCapacity];//默认这个数组的长度是10;
		//可以改变为
		this(new int[defaultCapacity]);//this是用来调用本类中的构造方法的;
	}
	public Son03(int[] capacity) {
		super();
		this.capacity = capacity;
	}

	public int[] getCapacity() {
		return capacity;
	}

	public void setCapacity(int[] capacity) {
		this.capacity = capacity;
	}

测试:

@Test
	public void test02() {
		Son03 son03 = new Son03();
		System.out.println(son03.getCapacity().length);
	}

注意:

private final static int defaultCapacity = 10;
	private int[] capacity;
		
	public Son04() {
		//this(new int[defaultCapacity]);//this是用来调用本类中的构造方法的;
		this(10,20);//这个this和上一行的this不能同时存在
		//this在构造方法中调用其他构造方法只能放在第一行(一个构造方法中只能存在一个this去调用其他构造方法);注意使用this调用构造方法时不允许相互使用,造成死循环;
	}
	public Son04(int[] capacity) {
		super();
		this.capacity = capacity;
	}
	public Son04(int a, int b) {
		super();
	}

	public int[] getCapacity() {
		return capacity;
	}

	public void setCapacity(int[] capacity) {
		this.capacity = capacity;
	}

总结:

  1. this是在构造方法中使用的;
  2. this可以调用本类中的其他构造方法;
  3. this调用其他构造方法只能放在第一行(即一个构造方法中只允许有一个this去调用其他构造方法);
  4. 使用this调用构造方法时不允许相互使用,造成死循环;

十二、super调用父类构造方法

super可以调用父类里的构造方法;

public class Son extends Person {
	public Son() {
	super("熊二", 1, 13);//此处调用的是父类里的全参构造方法;要想传值,每个类都要有全参构造
	}	
}

测试:
测试类中不需要再进行赋值;

@Test
	public void test03() {
		Son son = new Son();
		System.out.println("姓名:" + son.getName() + "\n性别:" + (son.getGender()==1?"男":"女") + "\n年龄:" + son.getAge());
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值