面向对象——继承
java中的继承,父类的成员,子类可以继承
要实现父子继承,使用extends实现
继承可以提高代码的复用性和维护性
但是也有不利性:
让类与类之间产生了父子关系,增加了耦合性。
耦合:完成一个功能,要去依赖别的类。
如果我们的软件大量的增加了耦合性,我们软件在后期的维护会很麻烦,
package demo2;
public class an {
String name;
int age;
public void sleep(){
System.out.println("睡觉");
}
public void eat(){
System.out.println("吃饭");
}
}
//父类
public class dog extends an{
public void lookdoor(){
System.out.println("看门");
}
}
//子类
public class cat extends an{
public void mouse(){
System.out.println("抓老鼠");
}
}
//子类
public class text {
public static void main(String[] args) {
cat cat = new cat();
cat.age=2;
cat.name="刘";
System.out.println(cat.age);
System.out.println(cat.name);
cat.mouse();//对父类的调用
cat.eat();
cat.sleep();
dog dog = new dog();
dog.age=1;
dog.name="吴";
System.out.println(dog.age);
System.out.println(dog.name);
dog.lookdoor();//对父类的调用
dog.eat();
dog.sleep();
}
}
//输出
继承的语法特点:
只支持单继承,一个类,只有一个父类,一个父类,可以有多个子类(联系生活)
也支持多层继承(爷—父—孙)
public class demo {
public static void main(String[] args) {
Grandson grandson = new Grandson();
System.out.println(grandson.g);
System.out.println(grandson.f);
grandson.show();
grandson.fuShow();
}
}
class Grandfather {
String g = "ggggg";
public void show() {
System.out.println("爷爷类中的show方法");
}
}
class Father extends Grandfather {
String f = "ffff";
public void fuShow() {
System.out.println("父亲的show方法");
}
}
class Grandson extends Father {
}
class Grandson2 extends Father {
}
注意:
1.父类的私有成员,子类不能继承
2.构造方法不参与继承
3.不要为了继承而继承
父子关系中的变量访问
public class demo{
public static void main(String[] args) {
Son son = new Son();
son.show(num:20);
}
}
class Father {
int num = 200;
}
class Son extends Father {
int num = 600;
public void show(int num) {
System.out.println(num); //20
System.out.println(this.num); //600
System.out.println(super.num);//200
}
}
变量访问的就近原则:当访问一个变量时,先在方法的局部范围找,找到使用,局部没找到,去本类成员范围找,找到使用,如果本类没找到,去父类找,找到使用,如果找不到,报错。
关键字 super
表示的是父类的空间标识,我们可以使用super关键字去访问父类数据。
super 和 this。
如果访问父类成员变量
super.成员变量名
如果访问本类的成员变量
this.成员变量名
如果访问父类的成员方法
super.成员方法名
本类的成员方法
this.成员方法名
父类的构造方法
super()
本类的构造方法
super();
package demo2;
public class demo{
public static void main(String[] args) {
Son son = new Son();
son.test();
}
}
class Father {
int fuNum = 200;
int f = 600;
public void fuShow() {
System.out.println("父类的show方法");
}
}
class Son extends Father {
int num = 20;
int f = 9000;
public void ziShow() {
System.out.println("子类的show方法");
}
public void test() {
System.out.println(super.fuNum);//200
System.out.println(super.f);//600
System.out.println(this.fuNum);//20
System.out.println(this.f); //9000
System.out.println("========================");
super.fuShow();
this.fuShow();
this.ziShow();
}
}
当我去创建子类对象时,为什么会先去调用父类的构造方法
因为:有了继承关系后,当我们初始化子的时候,子类要继承父类的数据,甚至还要去使用父类的数据,这时,我们先会完成父类的初始化。
在每个类的构造方法中的第一行有一行默认的super()这行代码去调用父类的空参构造
那么父类的父类呢?
在java中有一个顶层的父类 object,所有的类,都是直接或间接的继承它。
public class MyTest extends Object{
public static void main(String[] args) {
Zi zi = new Zi();
}
}
class Fu extends Object{
int fuNum=100;
public Fu() {
super();
System.out.println("父类的构造方法调用了");
}
}
class Zi extends Fu{
int ziNum=200;
public Zi() {
super();
System.out.println("子类的构造方法调用了");
}
}
那么,如果父类没有空参构造呢?
1.给父类构造空参
2.想办法调用父类的有参构造
package demo2;
public class demo {
public static void main(String[] args) {
Zi zi = new Zi();
Zi zi1 = new Zi(20);
}
}
class Fu extends Object{
public Fu(int num) {
super();
System.out.println("父类的有参构造");
}
}
class Zi extends Fu{
public Zi() {
super(10); //调用父类的有参构造
System.out.println("子类 构造执行了");
}
public Zi(int num){
this(); //间接的完成父类数句的初始化,调用本类空参构造
System.out.println("子类有参构造执行了");
}
}
方法重写
当子类和父类出现了一模一样的方法的时候(方法名,参数 返回值一样)就会发生方法覆盖现象,称之为方法重写。子类方法会覆盖父类方法。
为什么要有方法重写:子类对父类的功能实现,并不是很满意,子类想要改写掉父类的功能,或者说想要扩展父类的功能。那么子类都可以使用方法重写来完成。
package demo2;
public class fu {
public void fushow(){
System.out.println("fu类对show的调用");
}
public void eat(){
System.out.println("fu的eat功能实现");
}
}
package demo2;
public class zi extends fu{
public void zishow(){
System.out.println("zishow的重写");
}
public void eat(){
System.out.println("zi对eat的重写");
}
}
package demo2;
public class txet1 {
public static void main(String[] args) {
zi zi = new zi();
zi.fushow();
zi.eat();
zi.zishow();
}
}
重写的注意事项:
1.父类私有的方法,子类不能重写。
2.子类在重写父类方法时,方法前面的修饰符,不能比父类的低,可以等于和高,最好一样
3.静态方法,不参与重写
案例:
public class MyTest {
public static void main(String[] args) {
Zi zi = new Zi();
zi.fuStatic();
Zi.fuStatic();
Fu.fuStatic();
}
}
class Fu {
protected void fu() {
}
public static void fuStatic() {
System.out.println("父类的静态方法");
}
}
class Zi extends Fu {
@Override
protected void fu() {
}
// @Override
public static void fuStatic() {
System.out.println("子类的静态方法");
}
}
public class Iphone extends Phone{
//ctrl+O 重写父类的方法
@Override //注解 可以检测该方法,是否是重写父类的方法
public void call() {
System.out.println("视频打电话");
}
关键字final
final:最终的。可以修饰变量,可以修饰成员方法,以及类。
final修饰变量,变量改为常量。常量名一般大写。
final修饰类,此类不能被继承。
final修饰方法,此方法不能被重写了,子类只能继承使用
final修饰引用类型,指的是地址值不能再次改变。
package demo3;
public class text0 {
public static final boolean B=true;
public static void main(String[] args) {
final int num=100;
System.out.println(num);
final double A=3.14; //自定义常量
System.out.println(text0.B);
Son son = new Son();
son.show();
son.test();
System.out.println("========================");
final Son son1 = new Son();
}
}
final class Fu{
}
class Father{
public void show(){}
public final void test(){
System.out.println("最终的方法。子类继承下来使用,子类不能重写");
}
}
class Son extends Father{
@Override
public void show() {
super.show();
}
}
多态
运行时绑定
动态绑定:多态最重要的
静态绑定:代码在编译期时我们就知道他输出什么
指的是一种事物,在不同的时期,表现的不同的状态。
多态的继承:前提要有继承,没有继承无从谈起
多态要有重写,当然不重写,语法不报错,但是失去了多态的意义
父类引用指向子类对象
类的初始化过程:jvm加载的最后一步
顺序:
1.静态代码模块static,父子类顺序执行----->2.父类非静态代码块(父类静态代码块执行后,不会执行子类的非静态代码块,会执行父类的构造函数)-------->子类的非静态的代码块------>子类的构造函数
------->其他
成员方法会发生多态,成员变量不发生多态
多态中的成员访问方法
采用多态的形式,去访问成员变量,访问的是父类的成员变量。
访问构造方法,会访问父类的构造方法。
多态形式访问成员方法的特点,如果子类没有重写父类的方法,就以父类的方法为准,如果重写了,以子类重写之后的为准
A:多态中的成员访问特点
a:成员变量
编译看左边,运行看左边。
b:构造方法
创建子类对象的时候,会访问父类的构造方法,对父类的数据进行初始化。
c:成员方法
编译看左边,运行看右边。
d:静态方法
编译看左边,运行看左边。
(静态和类相关,算不上重写,所以,访问还是左边的)
B:案例演示
package demo3;
public class text0 {
public static void main(String[] args) {
Fu fu=new Zi();
System.out.println(fu.num);
fu.show();
System.out.println("=========================");
fu.fuJingTai();
Fu.fuJingTai();
}
}
class Fu{
int num=20;
public Fu() {
System.out.println("父类的构造方法执行了");
}
public void show(){
System.out.println("父类的show方法");
}
public static void fuJingTai() {
System.out.println("父类的静态方法");
}
}
class Zi extends Fu{
int num=200;
int aa=10;
public Zi() {
super();
System.out.println("子类的构造方法执行了");
}
@Override
public void show() {
System.out.println("zishow ");
}
}
多态的好处
提高代码的复用性,维护性,扩展性。
public class MyTest {
public static void main(String[] args) {
Fu fu = new Zi();
fu.show();
//fu.method();
//如果要调用子类特有的方法,我们可以向下转型。
Zi zi= (Zi) fu;
zi.method();
//向上转型:把子类型,转换成父类型。多态就是向上转型。
}
}
class Fu{
public void show(){
System.out.println("父类的show方法");
}
}
class Zi extends Fu{
@Override
public void show() {
System.out.println("我重写了父类的show方法");
}
public void method(){
System.out.println("这是子类特有的一个方法");
}
}
弊端:
不能使用子类的特有功能
多态中的内存图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SHNUXX5F-1587648676920)(C:\Users\LCH\Desktop\JAVA\DAY9\多态的内存图_wps图片.png)]
在Java中,实现多态的方式有两种,一种是编译时多态,另外一种是运行时多态,编译时的多态是通过方法的***重载***实现的,而运行时多态是通过方法的***重写***实现的。
方法的重载是指在同一个类中,有多个方法名相同的方法,但是这些方法有着不同的参数列表,在编译期我们就可以确定到底调用哪个方法。
方法的重写,子类重写父类中的方法(包括接口的实现),父类的引用不仅可以指向父类的对象,而且还可以指向子类的对象。当父类的引用指向子类的引用时,只有在运行时才能确定调用哪个方法。
rintln(“父类的show方法”);
}
}
class Zi extends Fu{
@Override
public void show() {
System.out.println(“我重写了父类的show方法”);
}
public void method(){
System.out.println("这是子类特有的一个方法");
}
}
弊端:
不能使用子类的特有功能
**多态中的内存图**
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200423213211605.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQ2NzY3MTgw,size_16,color_FFFFFF,t_70)
在Java中,实现多态的方式有两种,一种是编译时多态,另外一种是运行时多态,编译时的多态是通过方法的***重载***实现的,而运行时多态是通过方法的***重写***实现的。
方法的重载是指在同一个类中,有多个方法名相同的方法,但是这些方法有着不同的参数列表,在编译期我们就可以确定到底调用哪个方法。
方法的重写,子类重写父类中的方法(包括接口的实现),父类的引用不仅可以指向父类的对象,而且还可以指向子类的对象。当父类的引用指向子类的引用时,只有在运行时才能确定调用哪个方法。