JavaSE学习笔记——继承、方法重写、多态

面向对象特征之二:继承

概念

在这里插入图片描述

  • 为什么要有继承?
    多个类中存在相同属性和行为时,将这些内容抽象到单独一个类中,多个类无需再定义这些属性和行为,只要继承那个类即可。
    此处的多个类称为子类,单独的这个类称为父类(基类或超类)。

继承

  1. 类继承语法规则:
    class Subclass extends Superclass{ }

  2. 子类继承了父类,就继承了父类的方法和属性(分情况)。
    在子类中,可以使用父类中定义的方法和属性,也可以创建新的数据和方法。
    在Java 中,继承的关键字用的是“extends”,即子类不是父类的子集,而是对父类的“扩展”。

  3. 继承的规则:
    子类不能直接访问父类中私有的(private)的成员变量和方法。
    在这里插入图片描述

  4. Java中,子类继承父类什么?

  • 继承 public 和 protected 修饰的属性和方法,不论子类和父类是否在同一个包;
  • 继承缺省的属性和方法,前提是子类和父类必须在同一个包。
  1. 注意:
  • Java只支持单继承,不允许多重继承
  • 一个子类只能有一个父类
  • 一个父类可以派生出多个子类
  • class SubDemo extends Demo{ } //ok
    class SubDemo extends Demo1,Demo2…//error

    在这里插入图片描述
  1. 单继承举例
    在这里插入图片描述

练习

  • 定义一个ManKind类,包括成员变量int sex和int salary;
  • 方法void manOrWorman():根据sex的值显示“man”(sex== 1)或者“women”(sex==0);
  • 方法void employeed():根据salary的值显示“no job”(salary==0)或者“ job”(salary!=0);
  • 定义类Kids继承ManKind,并包括成员变量int yearsOld;方法printAge()打印yearsOld的值;
  • 在Kids类的main方法中实例化Kids的对象someKid,用该对象访问其父类的成员变量及方法。
package practice2;

public class ManKind {
	int sex;
	double salary;
	
	public ManKind(int sex, double salary) {
		this.sex = sex;
		this.salary = salary;
	}
	
	public void manOrWoman() {
		if(this.sex == 0) {
			System.out.println("man");
		}else {
			System.out.println("woman");
		}
	}
	
	public void employeed() {
		if(this.salary == 0) {
			System.out.println("no job");
		}else {
			System.out.println("job");
		}
	}
	
}
package practice2;

public class Kids extends ManKind{
	int yearsold;
	
	public Kids(int sex, double salary, int yearsold) {
		super(sex, salary);
		this.yearsold = yearsold;
	}
	
	public void printAge() {
		System.out.println(this.yearsold);
	}
	
	public static void main(String[] args) {
		Kids somekid = new Kids(0, 150000, 27);
		
		somekid.manOrWoman();
		somekid.employeed();
		somekid.printAge();
	}
	
}

方法的重写

  1. 概念
    在子类中可以根据需要对从父类中继承来的方法进行改造,也称方法的重置、覆盖。在程序执行时,子类的方法将覆盖父类的方法。

  2. 要求:
    (1)重写方法必须和被重写方法具有相同的方法名称、参数列表和返回值类型,即只改变方法体内容。
    (2)重写方法不能使用比被重写方法更严格的访问权限。
    (3)重写和被重写的方法须同时为static的,或同时为非static的
    (4)子类方法抛出的异常不能大于父类被重写方法的异常

  3. 与重载的区别:
    (1)重载时,不关注返回值类型,参数列表必须不同(参数个数、参数顺序、参数类型(构造方法重载除外));
    (2)重写时,除了方法体中的内容不同以外,其他部分都相同;
    (3)方法重载,指一个类可以有多个同名方法,发生在同一个类内部;
    (4)方法重写,指子类可以重写父类的方法,覆盖父类的方法,发生的父子类中。

  4. 注意:
    重写不代表父类被重写的方法不可使用,例如父类Person的showInfo()方法被子类Student重写,此时p.showInfo();调用的是父类中的showInfo()方法,s.showInfo();调用的是子类重写的showInfo()方法。

  5. 举例1:

public class Person {
	public String name;
    public int age;
    public String getInfo() {
		return "Name: "+ name + "\n" +"age: "+ age;
    }
}
public class Student extends Person {
	public String school;
	public String getInfo() {//重写方法
		return  "Name: "+ name + "\nage: "+ age + "\nschool: "+ school;
	}
	public static void main(String args[]){
		Student s1=new Student();
		s1.name="Bob";
		s1.age=20;
		s1.school="school2";
		System.out.println(s1.getInfo());   //Name:Bob  age:20  school:school2
	}
}
  1. 举例2:
class Parent {
	public void method1() {}
}

class Child extends Parent {
	private void method1() {}  
//非法,子类中的method1()的访问权限private比被覆盖方法的访问权限public弱
}
  1. 四种访问权限修饰符:
修饰符类内部同一个包子类其他
private
(缺省)
protected
public

结论:

  • 如果子类和父类在同一个包下,则子类可以访问和调用父类中除了 private 以外的任何属性和方法;
  • 如果子类和父类不在同一个包下,则子类只可以访问和调用父类中的 public 和 protected 修饰的属性和方法。

super关键字

  1. 作用:
    (1)访问父类中的属性;
    (2)调用父类中的方法:
    (3)在子类构造方法中调用父类的构造方法。

  2. 注意:
    (1)当子父类出现同名成员时,可以用super进行区分;
    (2)super的追溯不仅限于直接父类(C继承B,B继承A,在C中使用super可以引用A的属性和方法);
    (3)super和this的用法相似,this代表本类对象的引用,super代表父类对象的引用。

  3. 举例:

package test;

public class TestStudent {
	public static void main(String[] args){
		Student st = new Student();
		System.out.println(st.getInfo());
	} 
}

class Person {
	protected String name="张三";
    protected int age;
    
	public String getInfo() {
          return "Name: " + name + "\nage: " + age;
    }
}

class Student extends Person {
    protected String name = "李四";
	private String school = "New Oriental";
	
	public String getSchool(){ 
	      return school; 
	}
    public String getInfo() {
          return super.getInfo() +"\nschool: " +school;//调用的是父类方法, 父类中的Name是张三
    } 
}
/*Name: 张三
age: 0
school: New Oriental*/
  1. 调用父类构造器
    (1)子类中所有的构造器默认都会访问父类中的无参构造器; 即所有子类构造器的第一行包含一条隐式语句super();。
    (2)当父类中没有无参构造器时,子类的所有构造器都必须通过 super() 或 this() 语句指定调用父类或子类中的构造器,且必须放在构造器的第一行,super() 或 this() 只能包含其中一个; 注意,使用 this() 调用本类构造器时,要保证至少有一个子类构造器调用了父类构造器。
    (3)若使用 super() 或 this() 显示的调用了父类或子类中的构造器,则该构造器内不会再添加默认 super()。
    (4)如果子类构造器中未显式调用父类或本类的构造器,且父类中又没有无参构造器,则编译出错。
public class Person {	
 	private String name;
 	private int age;
	private Date birthDate;	

 	public Person(String name, int age, Date d) {
 	        this.name = name;
 	        this.age = age;
 	        this.birthDate = d;
    }
 	public Person(String name, int age) {
 	        this(name, age, null);
 	}
 	public Person(String name, Date d) {
 	        this(name, 30, d);
	 }
 	public Person(String name) {
 	        this(name, 30);
	}
}
public class Student extends Person {
 	private String school;
 	
 	public Student(String name, int age, String s) {
 	          super(name, age);
 	          school = s;
    }
 	public Student(String name, String s) {
 	          super(name);
	          school = s;
 	}
 	public Student(String s) { // 编译出错: no super(),
 	          school = s;      //系统将调用父类的无参构造器,但父类中并无无参构造器 
 	}
}

this 和 super的区别

\区别thissuper
1访问属性访问本类中的属性,如果本类没有此属性则从父类中继续查找访问父类中的属性
2调用方法访问本类中的方法直接访问父类中的方法
3调用构造器调用本类构造器,必须放在构造器的首行调用父类构造器,必须放在子类构造器的首行
4特殊表示当前对象\

一般对象的实例化过程

在这里插入图片描述

子类对象的实例化过程

在这里插入图片描述

面向对象特征之三:多态

Java中的体现

  1. 方法的重载(overload)和重写(overwrite)。
  2. 对象的多态性 ——可以直接应用在抽象类和接口上。

对象的多态性

.在Java中,父类引用的实例可以是它的子类(形参是Person类,传入的实参可以是Student类)。

1. 普通成员方法的调用:

  • Person p = new Student(); // Person类型的变量p,指向Student类型的对象。 可以理解为所有的学生都是人,因此可以用Person类接收Student对象,但是人不一定都是学生,因此不能用Student类接收Person对象。
  • 使用这种声明方式后,由于引用变量是Person类型,因此p只能调用父类中的方法(若已被子类重写,则调用子类中重写的方法),而不能调用子类特有的方法,如需调用子类特有的方法,要进行强制类型转换。
  • 原因:编译时检查父类中是否有被调用的方法,若没有则编译失败;运行时检查子类是否重写方法,若重写则调用重写方法。简单一句话,编译时看左边,运行时看右边。

2. 静态方法的调用:

  • Person p = new Student(); 若子类重写了父类的静态方法,则使用p调用该静态方法时,执行的依然是父类中的静态方法,即编译和运行都看左边。

3. 成员属性的访问:

  • Person p = new Student(); 无论要访问的属性是否为静态,p只能访问父类中的成员属性,即编译和运行都看左边。

举例

package test;

public class TestAnimal {
	public static void main(String[] args) {
		Animal a = new Cat();
		Function.eatFunc(a);
		Function.speakFunc(a);
	}
}

abstract class Animal{
	//动物叫声
	public abstract void speak();
	//动物食物
	public abstract void eat();
	//动物进食
}

class Cat extends Animal{
	
	@Override
	public void speak() {
		System.out.println("cat miaomiaomiao");
	}
	
	@Override
	public void eat() {
		System.out.println("cat eat fish");
	}
	
}

class Dog extends Animal{

	@Override
	public void speak() {
		System.out.println("dog wangwangwang");
	}

	@Override
	public void eat() {
		System.out.println("dog eat rice");
	}
	
}

class Function{
	public static void speakFunc(Animal a) {
		a.speak();
	}
	public static void eatFunc(Animal a) {
		a.eat();
	}
}

instanceof 操作符

  1. 语法格式:
    x instanceof A:检验x是否为类A(或A的子类B)的对象,返回值为boolean型。

  2. 注意:
    (1)要求x所属的类与类A必须是子类和父类的关系,否则编译错误。
    (2)如果x属于类A的子类B,x instanceof A值也为true。
    (3)判断的是引用x所指代的堆内存是否是类A的对象(关注new后面的内容)。

  3. 举例:

public class Person {}
public class Student extends Person {}
public class Graduate extends Person {}

public void method1(Person e) {
	if (e instanceof Person) {
		// 处理Person类及其子类对象(Person,Student,Graduate)
	}
	if (e instanceof Student) {
		//处理Student类及其子类对象(Student,Graduate)
	}
	if (e instanceof Graduate){
		//处理Graduate类及其子类对象(Graduate)
	}
}
  1. 判断:
Person p = new Student();
System.out.println(p instanceof Person);
System.out.println(p instanceof Student);

结果:true true
原因:p中存放的堆内存是Student类的,故结果都为true。

Object类

概念

  • Object类是所有Java类的根父类
  • 如果在类的声明中未使用extends关键字指明其父类,则默认父类为Object类
    public class Person {

    }
    等价于:
    public class Person extends Object {

    }
  • 例:
method(Object obj){}//可以接收任何类作为其参数
    Person o=new Person();  
    method(o);

Object类中的主要方法

\方法名称类型描述
1public Object()构造构造方法
2public boolean equals(Object obj)普通对象比较
3public int hashCode()普通获取Hash码
4public String toString()普通打印对象的堆内存地址

注意:关于equals()方法,后面有详细介绍。

Person p = new Person();
Person e = new Person();
System.out.println(p.equals(e));

结果:false,p与e的堆内存地址不同,不管p与e存放的内容是否相同,只比较堆内存地址,故返回false。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值