2、继承
①、基本概念
- 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
- extends的意思是“扩展”,子类是父类的扩展。
- Java中类只有单继承,没有多继承。一个儿子只能有一个爸爸,但一个爸爸可以有多个儿子。
package 面向对象OOP.继承;
//人类
public class Person {
}
package 面向对象OOP.继承;
//老师是人,作为子类(派生类),继承人类
public class Teacher extends Person {
}
package 面向对象OOP.继承;
//学生是人,继承人类。
public class Student extends Person {
}
- 继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合和聚合。
- 继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。
- 子类和父类之间,从意义上讲应该具有"is a"关系,因为子类只有一个父类。
//子类继承了父类,就会拥有父类的全部方法
package 面向对象OOP.继承;
//人类
public class Person {
public void say(){
System.out.println("人类会说话");
}
}
package 面向对象OOP.继承;
//学生是人,继承人类。
public class Student extends Person {
}//虽然学生类是空的,但还是能够点出say方法,也就是说student类继承了Person类的say方法。
package 面向对象OOP.继承;
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.say();
}
}
执行结果:
人类会说话
- private修饰的属性和方法是无法继承的。
- 不写就是default修饰。
- protected
- public,保密性由上之下,由高到低。
②、Object类
- 快捷键Ctrl+H打开继承树。
- 发现父类Person上面还有个Object类
- 再用Application类调用Person类,发现Person类不止由say()方法可以调用。
- 在java中,所有的类都默认继承Object。
③、super关键字
- super关键字可以在子类中调用父类的方法
package 面向对象OOP.继承;
//父类
//人类
public class Person {
protected String name = "狂神";
}
package 面向对象OOP.继承;
//学生是人,继承人类。
public class Student extends Person {
public String name = "秦疆";
public void test(String name){
System.out.println(name);//打印输出的是test的实际参数name。
System.out.println(this.name);//打印输出的是本类中的属性name。
System.out.println(super.name);//打印出的是其父类Person中的属性name。
}
}
package 面向对象OOP.继承;
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.test("张三");//给Student类中的test属性传递了一个实参张三,会输出什么呢?
}
}
执行结果:
张三
秦疆
狂神
- super关键字也会在子类中调用父类的属性
//super不仅可以调用父类的属性,也可以调用父类的方法
package 面向对象OOP.继承;
//父类
//人类
public class Person {
//定义了一个print()方法,输出person。
public void print(){
System.out.println("Person");
}
}
package 面向对象OOP.继承;
//学生是人,继承人类。
public class Student extends Person {
//在子类中也定义了一个print方法。
public void print(){
System.out.println("Student");
}
public void test1(){
print();//调用本类中的print()方法
this.print();//依然是调用本类中的print()方法,这是this关键字的作用。
super.print();//调用了父类的方法
}
}
package 面向对象OOP.继承;
public class Application {
//执行一下
public static void main(String[] args) {
Student student = new Student();
student.test1();
}
}
执行结果:
Student
Student
Person
④、关于super的默认情况
//先在父类Person中创建一个显式无参构造方法
package 面向对象OOP.继承;
//人类
public class Person {
public Person() {
System.out.println("Person的无参执行了");//方便确认无参方法是否执行
}
}
//再在子类Student中建立一个显式无参构造方法
package 面向对象OOP.继承;
//学生是人,继承人类。
public class Student extends Person {
public Student() {
System.out.println("Student的无参执行了");
}
}
//在主方法中实例化一个Student变量
//运行并得出结构
package 面向对象OOP.继承;
public class Application {
public static void main(String[] args) {
Student student = new Student();
}
}
执行结果:
Person的无参执行了
Student的无参执行了
- 为什么主方法中明明调用的是Student类的无参构造方法,却先输出了Person的无参构造方法呢?
//答案:
package 面向对象OOP.继承;
//学生是人,继承人类。
public class Student extends Person {
public Student() {
super();//正常来说,这个地方应该有个super(),才会使得上面的执行结果成立。
//这个super()就是被隐藏的代码,它存在,并且必须是在构造器的第一行,放在其他行就会报错。
System.out.println("Student的无参执行了");
}
}
⑤、super注意点
- super调用父类的构造方法,必须在构造方法的第一个。
- super必须只能出现在子类的方法或者构造方法中。
- super和this不能同时调用构造方法,因为它们两个都必须放在第一行。
- super和this的不同点
- 代表对象不同:this代表本身调用者对象。super代表父类的引用。
- 前提不同:没有继承也可以使用,super只能在继承条件下才可以使用。
- 调用构造方法不同:this是调用本类的构造,super是调用父类的构造方法。
⑥、方法重写
- 子类有和它父类相似的却不同的东西,好比基因突变,青出于蓝而胜于蓝。
package 面向对象OOP.方法重写;
//重写都是方法的重写,和属性无关。
public class B {
public static void test(){
System.out.println("B=>test()");
}
}
package 面向对象OOP.方法重写;
//A类继承B类
public class A extends B{
public static void test(){
System.out.println("A=>test()");
}
}
package 面向对象OOP.方法重写;
public class Application {
public static void main(String[] args) {
//方法的调用只和左边定义的数据类型有关
A a = new A();
a.test();
//发现父类B类型的实例b,可以通过A实例化。
//父类的引用指向了子类。
B b = new A();//这句没有报错
b.test();
}
}
执行结果:
A=>test()
B=>test()
- 快捷键Alt+insert
- 非静态(无static)的方法的方法重写
//父类B
package 面向对象OOP.方法重写;
//重写都是方法的重写,和属性无关。
public class B {
public void test(){
System.out.println("B=>test()");
}
}
//子类A继承父类
package 面向对象OOP.方法重写;
public class A extends B{
//@Override 重写
@Override//注解:有功能的注释
public void test() {
System.out.println("A=>test");
}
}
//主类:Application
package 面向对象OOP.方法重写;
public class Application {
//静态方法和非静态方法区别很大!
//静态方法:方法的调用只和左边有关,是A的就调用A,是B的就调用B。
//非静态:方法重写。
public static void main(String[] args) {
//方法的调用只和左边定义的数据类型有关
A a = new A();
a.test(); //A=>test
//发现父类B类型的实例b,可以通过A实例化。
//父类的引用指向了子类。
B b = new A(); //A=>test,子类重写了父类的方法。
b.test();
}
}
执行结果:
A=>test
A=>test
- 总结:
- 需要有继承关系,子类重写父类的方法。
- 方法名必须相同。
- 参数列表必须相同。
- 修饰符范围可以扩大,但不能缩小:public>protected>default>private
- 抛出的异常:范围可以被缩小,但不能扩大。ClassNotFoundException(小)->Exception(大),可以。
- 重写:子类的方法和父类的必须要一致,方法体不同!
- 为什么需要重写?
- 1、父类的功能,子类不一定需要或者不一定满足!
- Alt+insert ->override;