继承
- 继承是是什么?
生物学中的界门纲目科属种就是继承关系,也是包含的关系,继承就是被包含,例如,草食动物继承了所有动物的特性例如:吃喝拉撒。
在代码中的体现就是,学生类和老师类都属于人类,所以我们可以讲学生类和老师类继承人这个大类,java中只有单继承没有多个类,不能继承多个类,但是可以连着继承,例如学生类继承人类,人类继承生物类
继承的好处是:提升代码的复用性,继承是多态的前提(使类与类之间产生了关系)
编写生物类:变量:姓名和年龄,方法:吃饭睡觉
//生物类
public class LivingThings {
String name;
int age;
public void eat() {
System.out.println("吃饭");
}
public void sleep() {
System.out.println("睡觉");
}
}
人类:继承生物,但是比生物多的方法:会说话
public class Human extends LivingThings {
public void speak() {
System.out.println("说人话");
}
}
老师类:除了会说话,变量多了个工资,方法多了会讲课
public class Teacher extends Human {
int salary;
public void teach() {
System.out.println("讲java");
}
}
学生类:继承人类,除了人类有的属性还有独特的方法:写作业
public class Student extends Human {
public void writeHomework(){
System.out.println("写作业");
}
}
使用main函数调用学生类,可以访问到生物类,人类,还有本类所有的方法
- 了解完继承的含义接下来来了解其中的奥秘吧
从一个简单的继承来看,就是父与子两个类,
父类代码:定义了私有的变量(get&set方法)和普通变量,还有父类专属的方法,以及无参构造方法中加入了输出语句。
public class Fu {
private int num = 10;
int numA = 100;
public Fu() {
System.out.println("父类的无参构造方法");
}
public void show() {
}
public void showA() {
System.out.println("父类中的showA方法");
}
public void showB() {
System.out.println("父类中的showB方法");
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}
子类代码:继承了父类,与父同名的变量名,无参构造方法中也加入了输出语句,
public class Zi extends Fu{
int numA = 1000;
int numC = 6666;
public Zi1() {
System.out.println("子类构造方法");
}
public void showA() {
System.out.println("子类中的showA方法");
}
public void showC() {
System.out.println("子类中的showC方法");
}
那么在main方法中调用子类的时候会输出什么呢?
public static void main(String[] args) {
Zi1 zi = new Zi1();
int numA = zi.numA;
System.out.println(numA);
int num = zi.getNum();
System.out.println(num);
}
解析:继承中有个原则:就近原则,当需要访问变量或者方法时,会先查询子类有无其定义,若有则将其赋值为子类中的定义,若没有则向上查询,父类有则直接使用,如果没有就报编译异常。
当new新的子类时,如果其有父类,会先调用其无参的构造方法,再调用本类的构造方法可以将子类构造方法看成如下代码:
public Zi() {
super();
System.out.println("子类的无参构造方法");
输出:
- this关键字和super关键字用法一样就写一起了
this关键字最常用的地方就是在get&set方法中,其总共有三种使用方法:
this关键字的使用
- 就近原则
变量在使用的时候,优先使用定义的近的变量,谁离得近就指向哪个变量 - this作用
表示存储“当前对象”的引用
this指向的内容,可以理解为访问本类中的内容。 - 三种格式
this.成员变量 访问本类成员变量
this.成员方法名() 访问本类成员方法
this(…) 访问本类构造方法
我们定义一个类,里面有无参构造方法和全参构造方法,再提供一个其他方法来讲解this关键字。
super关键字的使用
- super作用
表示“父类”的引用
super指向的内容,可以理解为访问父类中的内容。 - 三种格式
super.成员变量 访问父类成员变量
super.成员方法名(…) 访问父类成员方法
super(…) 访问父类构造方法
public class Zi {
int num = 666;
public Zi() {
this(6666);//要写在首行 其意思就是先访问其全参构造方法,将6666赋值到this.num中
System.out.println("子类的无参构造方法");
}
public Zi(int num) {
System.out.println("子类的有参构造");
this.num = num;
}
public void method() {
System.out.println("子类中的method方法");
}
public void show() {
int num = 999;
System.out.println("访问局部的num:" + num);
System.out.println("访问本类成员位置的num:" + this.num);
//访问本类的成员方法
method();
this.method();//一般不用加
}
}
输出:
- 继承体系的内存图 涉及知识点:jvm
在此之间,我们先了解简单的jvm知识,我们会有问题,栈内存是干嘛的?堆内存又是什么?方法区是啥?
在我们访问一个对象时,JAVA虚拟机内部是通过栈上的reference数据来操作堆上的具体对象,同时方法区又存储着这个对象的类型数据即对象所属的类的信息。JAVA虚拟机规范中只规定了一个指向对象的引用,并没有定义这个引用应该通过哪种方式去定位、去找到对象所在堆中的具体位置,所以对象的方法方法是取决于虚拟机实现而定的。
- 栈:每个线程都会有一个栈内存,由栈帧组成栈,一个栈帧等于一次方法的调用,我们用一个很简单的代码来演示栈的压栈和出栈
public class Demo4 {
public static void main(String[] args) {
a();//在这里设置断点
}
public static void a(){
b();
}
public static void b(){}
}
当我们将断点设在main方法函数中,用debug运行,我们很容易看出压栈和出栈的过程
下图可以看出来,main方法a方法b方法都已经入栈了,main方法在栈底,栈是先进后出的一种数据结构
b方法执行完就进行出栈操作
将所有方法出栈后结束程序,另外补充一个知识点:垃圾回收不涉及栈内存,因为栈内的是一次性的方法调用,每次调用后,都会被弹出栈,会自动回收,垃圾回收是回收堆内存中的无用对象
堆和方法区后续补充。。。
- 抽象方法的使用
当我们写动物类之后,在写猫类和狗类的时候,我们我们可以将其继承动物类,在猫类和狗类中补充他们的叫声,但是他们还是有很多不同的,我们有时候怕忘记在具体类中写在这里插入代码片
他们的不同时会采用抽象方法先定义出他们会叫,至于怎么叫在子类中实现,不实现就会报编译错误,所以不怕忘记写
我们先编写动物类(为了简化代码,就写了他们的不同)他们吃的东西不同
public abstract class Animal {
public abstract void eat();
}
猫类(猫吃鱼)
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
编写狗类
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃骨头");
}
}
我们的main方法如下:
public static void main(String[] args) {
Cat c = new Cat();
c.eat();
Dog d = new Dog();
d.eat();
}
注意事项:
1.抽象类只能通过子类创建对象。
2.抽象类可以有构造器,供子类初始化父类成员。
3.抽象类中,不一定包含抽象方法。
4.抽象类的子类,必须重写抽象父类中"所有的"抽象方法,否则子类也必须定义成抽象类
5.抽象类存在的意义是为了被子类继承,体现的是模板思想。
- 最后来介绍final类
概述
1.作用
Java提供了final 关键字,用于修饰不可改变内容。
2.应用
修饰类:被修饰的类,不能被继承(例如:String类、Math类、Scanner类…)。
修饰方法:被修饰的方法,不能被重写。
修饰变量:被修饰的变量,一旦赋值,不能被重新赋值。
final的使用
1.修饰类:
格式:public final public class 类名 { //类中成员 }
2.修饰方法:
格式:public final 返回值类型 方法名(){}
3.修饰变量
格式:final 数据类型 变量名=值; 或 final 数据类型 变量名; 变量名=值;
注意事项:
被final修饰的常量,被称为自定义常量(所有字母都大写)。
修饰的如果是成员变量,可以不直接赋值,但需要保证所有构造方法有赋值操作