Java后端_9

继承

一、继承性的好处:

1.减少代码的冗余,提高代码复用性
2.便于功能的扩展
3.为多态的使用提供前提

二、继承性的格式:

Class A extends B{}
A:子类、派生类、subclass
B:父类、基类、superclass
一旦A继承B之后,A就获取了B中的所有的属性和方法
特别的,父类中声明为private的属性和方法,子类继承父类后,仍然获取了父类中私有的结构,只是因为封装性的影响,使得子类不能直接调用父类的结构而已
子类继承父类以后,子类还可以声明自己特有的属性和方法:实现功能的扩展(extends:扩展)

三、Java中关于继承性的规定:

1.一个类可以被多个子类继承
2.一个类只能有一个父类:Java类的单继承性(和c++的多继承不一样)
3.子父类是相对的概念,如下图2,父类2是子类的直接父类,父类1是子类的间接父类
4.子类可以获取直接父类和所有间接父类的属性和方法
Java后端_9_第1张图片
Java后端_9_第2张图片
Java后端_9_第3张图片

四、所有自己声明的类都直接或间接继承于java.lang.Object类,意味着,所有java类都具有java.lang.Object类声明的功能。

Java后端_9_第4张图片

方法重写(override,overwrite)

1.重写

子类继承父类后,可以对父类中同名同参数的方法,进行覆盖操作(重写的参数列表也是相同的,重载的参数列表是不同的)

2.应用

重写以后,当创建子类对象后,通过子类对象调用子类中与父类同名同参数的方法时,实际执行的是子类重写父类的方法

3.重写的规定

权限修饰符 返回值类型 方法名(参数列表)throws 异常类型 {方法体}
1)子类重写的方法的方法名和形参列表和父类被重写的方法的相同
2)子类重写的方法的权限修饰符 >= 父类被重写的方法的权限修饰符
特殊情况:子类不能重写父类中声明为private权限的方法
3)返回值类型:
i.父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型也是void
ii.父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类
如父类中的一个方法:public Object eat(){},则子类中重写可以写成public String eat(){},因为String是Object的子类
iii.父类被重写的方法的返回值类型是基本数据类型,则子类重写的方法的返回值类型必须是相同的数据类型
4)子类重写的方法抛出的异常类型 <= 父类被重写的方法的抛出的异常类型(具体看异常处理的内容)
总结:权限大于父亲,返回和异常小于父亲
一般开发中都是直接把父类的方法粘贴到子类中再重写方法体的
子类和父类同名同参数的方法要么声明为非static的(这时要考虑重写的情况),要么都声明为static的(静态的就不是重写了)。

对于重写,指的是方法,方法重写之后,子类的方法覆盖父类的方法。而对于属性,子类的属性(如id)和父类的属性(如id)相同时,不能形成覆盖,即子类中既有子类的id又有父类的id。

不同包的子类只能调用父类的protected和public权限的结构(同一个包也是一样的)
不同包的普通类只能调用另一个包下面的类的public结构

super关键字

一、super:类似于this(此对象的…),super可以理解为父类的…

二、super可以用来调用属性、方法、构造器

三、super的使用

1.可以在子类的方法或构造器中,通过“super.属性”或“super.方法”的方式显式的调用父类中声明的属性或方法。但是通常情况下省略“super.”
2.特殊情况,当子类和父类定义同名的属性时,要想在子类调用父类中声明的属性,则必须显式的使用“super.属性”的方式,表明调用的是父类中的属性。

class Person{int id;}
class Student extends Person{int id;}
则直接在子类的方法或构造器中写id代表的是子类的id;this.id也代表子类的id;super.id代表是父类的id
3.当子类重写父类中的方法后,想在子类的方法中调用父类中被重写的方法时,则必须显式的使用“super.方法”的方式,表明调用的是父类中被重写的方法。
总结:在子类中想调子类的结构,啥都不加或加“this.”;想调父类的结构,加“super.”

四、super调用构造器

1.可以在子类的构造器中显式的使用“super(形参列表)”的方式,调用父类中指定的构造器

public class Person {
	Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
}
public class Student extends Person{
	Student(String name, int age, String major){
		super(name, age);//调用父类构造器
		this.major = major;
	}
}

2.“super(形参列表)”需声明在子类构造器的首行。所以在构造器中只能在“this(形参列表)”和“super(形参列表)”二选一,不能同时出现
3.在构造器首行没有显式的声明“this(形参列表)”和“super(形参列表)”,则默认调用的是父类中空参的构造器:super()

public class Student extends Person{
	Student(String major){
		this.major = major;//没有“this(形参列表)”和“super(形参列表)”,则默认在这个构造器中有一个super();
	}
}

所以父类中一定要有空参构造器,否则创建子类的时候构造器会出错(出错提示:Implicit super constructor Person() is undefined. ),因为要调用spuer();
4.在类的多个构造器中,至少有一个类的构造器中使用了"super(形参列表)“。

子类对象实例化的全过程

结果上

子类继承父类后,就获取父类中的结构,即创建子类对象时,在堆空间就会加载所有父类的属性和方法

过程上

通过子类的构造器创建子类对象时,一定会调用其直接父类的构造器,进而调用间接父类的构造器…直到java.lang.Object类中空参的构造器为止。正因为调用super(形参列表)时会调用父类构造器(调用父类构造器类似于创建父类对象,所以会加载父类的结构),所以才能在内存中看到父类中的结构。

明确

虽然创建子类对象时调用了父类的构造器,但是自始至终就创建过一个对象,即new的子类对象。

多态(polymorphism):父类的引用指向子类的对象

一、理解:一个事物的多种形态

class Person {方法:eat(); walk();}
class Man extends Person{重写方法:eat(); walk(); 方法:earn();}
class Woman extends Person{重写方法:eat(); walk(); 方法:makeUp();}
则Person p = new Person();
或Person p = new Man();//多态
或Person p = new Woman();//多态

二、多态的使用:

虚拟方法调用(所谓虚拟方法:形成多态时,父类的方法被称为虚拟方法,父类根据赋给它不同的子类对象,动态的调用属于子类的该方法。这样的方法调用在编译阶段是无法确定的)
进行父类的引用指向子类的对象的多态以后,在编译阶段,只能调用父类中声明的方法(如p.eat();p.walk();),但在运行阶段,实际执行的是子类重写父类的方法(如子类中的eat()和walk())
总结:编译看左,运行看右(Person p = new Man()的左和右)
编译的时候是父类行为,运行时是子类行为

三、多态性的使用前提:

1.有类的继承
2.子类重写父类方法
3.父类的引用指向子类的对象

四、多态的作用:减少代码量,结构清晰,可扩展性强

public class AnimalTest {
	public static void main(String[] args) {
		AnimalTest aTest = new AnimalTest();
		aTest.func(new Dog());
		aTest.func(new Cat());
	}
	
	public void func(Animal animal) {//父类引用指向子类对象,形成多态
		animal.eat();
	}
}

class Animal{
	public void eat() {
		System.out.println("吃东西");
	}
}

class Dog extends Animal{
	@Override
	public void eat() {
		System.out.println("吃屎");
	}
}

class Cat extends Animal{
	@Override
	public void eat() {
		System.out.println("吃鱼");
	}
}

输出:
在这里插入图片描述
如果没有多态,需要把

	public void func(Animal animal) {
		animal.eat();
	}

改成

	public void func(Dog dog) {
		dog.eat();
	}
	public void func(Cat cat) {
		cat.eat();
	}

代码量增加了

五、多态性只适用于方法,不适用于属性。(对于属性,编译和运行都看左边)

class Person {属性:id=1}
class Man extends Person{属性:id=2}
Person p = new Man();
P.id;//输出的是Person的id,即id=1

重载:调用地址在编译阶段就绑定了,称为”静态绑定“
多态:运行的时候调用地址才绑定,称为”动态绑定“

常见的bug调试

方式一:硬看,必要的时候在代码中间添加输出语句,看看输出的中间结果和自己想的是否一样
方式二:debug调试

当代码过长时,在每个类、方法前加文档注释,之后调用时可以方便的知道每个类和方法是干什么用的

debug调试步骤

1.设置断点(注意:可以设置多个断点)
2.debug as java application
3.常用操作

操作 作用
step into 跳入(f5) 进入当前行所调用的方法中
step over 跳过(f6) 执行完当前行的语句,进入下一行
step return 跳回(f7) 执行完当前行所在方法,进入下一行
drop to frame 回到当前行所在方法的第一行
resume 恢复 执行完当前行所在断点的所有代码,进入下一个断点,如果没有就结束

按照例子进行debug

Java后端_9_第5张图片
这是所要debug的代码,输出如下
Java后端_9_第6张图片
所以代码有问题。现在开始debug

1.设置断点

在这里插入图片描述
在蓝色区域双击即可设置断点(再双击一次断点就会取消)
设置断点是为了使程序执行到断点停了一下,然后看看断点处的变量值和自己想的是否符合

2.debug as java application

Java后端_9_第7张图片
选择debug as进行debug调试,然后出现以下界面
Java后端_9_第8张图片

3.常用操作

在这里插入图片描述
Java后端_9_第9张图片
在这里插入图片描述
Java后端_9_第10张图片

你可能感兴趣的:(Java学习笔记,java,开发语言,java-ee)