栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

零基础学Java

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

零基础学Java

继承 1. 基本概念
  • 继承可以解决代码复用,让我们的编程更加靠近人类思维。
  • 当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,父类的所有子类不需要再重新定义这些属性和方法,只需要通过 extends 来声明继承父类即可。
  • 继承的示意图如下:
  • 继承的好处:
    • 代码的复用性提高了 ;
    • 代码的扩展性和维护性提高了;
2.基本用法
  • 基本语法:
3. 继承的细节(重要!)
  • 细节如下:

(1) 子类继承了父类所有的属性和方法,父类中的非私有属性和方法可以在子类直接访问, 但是父类中的私有属性和方法不能在子类直接访问,要通过父类提供的公共方法去访问 ;

(2) 子类调用构造器初始化时,必须调用父类的构造器, 完成父类的初始化 ;

(3) 当新创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类的无参构造器被覆盖了,则必须在子类的构造器中用 super 关键字 去指定使用父类另外的构造器完成对父类的初始化工作,否则,编译不会通过;

(4)当新创建子类对象时,如果想要指定调用父类的某个构造器,则需要在子类的构造器中显式的调用 : super(参数列表) ;

(5)super 关键字在子类构造器中使用时,必须放在其构造器第一行,并且super 只能在构造器中使用 ;

(6)由于super() 和 this() 都只能放在构造器的第一行,因此这两个方法不能同时存在于一个构造器中 ;

(7)java中的所有类都是 Object 类的子类, Object 是所有类的基类;

(8)父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类) ;

(9)子类最多只能继承一个父类(指直接继承),即 java 中是单继承机制; 思考:如何让 A 类继承 B 类和 C 类? 【答案:A 继承 B, B 继承 C】

(10)不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关系;

  • 代码举例:
public class ExtendsDetail {
    public static void main(String[] args) {
        System.out.println("====对象====");
        Sub sub3 = new Sub("king", 10); //创建了子类对象 sub2
        //sub.sayOk();
    }
}
//子类
public class Sub extends Base {
		
		
    //细节: super在使用时,必须放在构造器第一行;
    //细节: super() 和 this() 都只能放在构造器第一行,因此这两个方法不能同时存在于一个构造器; 
    public Sub() {// 子类的无参构造器
    	this(String name, int age);// 指定调用了自己的有参构造器,其实父类的构造器就不会调用了;
        System.out.println("子类Sub()构造器被调用....");
    }
	public Sub(String name) {
        // 什么都不写,隐式地存在 super();
        System.out.println("子类Sub(String name)构造器被调用....");
    }
	
    public Sub(String name, int age) {//子类的有参构造器
        //super(); // 默认调用父类的无参构造器;
        super("smith", 10);// 指定调用父类的 Base(String name) 构造器;
        System.out.println("子类Sub(String name, int age)构造器被调用....");
    }
	
	// 子类的普通方法
    public void sayOk() {
        //细节:父类的非私有的属性和方法可以在子类直接访问
        //但是父类的私有属性和方法不能在子类直接访问
        System.out.println(n1 + " " + n2 + " " + n3);
        test100();
        test200();
        test300();
        //test400(); 报错
        //要通过父类提供公共的方法去访问;
        System.out.println("n4=" + getN4());// 可以访问私有属性n4了
        callTest400();// 可以访问父类的私有方法 test400()
    }
}
//父类
public class Base { 
    //4个属性
    public int n1 = 100;
    protected int n2 = 200;
    int n3 = 300;
    private int n4 = 400;
	
	// 3个不同的构造器:
    public Base() { //无参构造器
        System.out.println("父类Base()构造器被调用....");
    }
    public Base(String name, int age) { //有参构造器
        //默认super()
        System.out.println("父类Base(String name, int age)构造器被调用....");
    }
    public Base(String name) { //有参构造器
        System.out.println("父类Base(String name)构造器被调用....");
    }
    
    //父类提供一个public的方法,返回了n4;
    public int getN4() {
        return n4;
    }

	// 父类的call方法,调用了私有的test400()方法;
    public void callTest400() {
        test400();
    }
    
    // 4种不同权限的普通方法:
    public void test100() { // 公有
        System.out.println("test100");
    }
    protected void test200() { // 受保护
        System.out.println("test200");
    }
    void test300() { // 默认
        System.out.println("test300");
    }
    private void test400() { // 私有
        System.out.println("test400");
    }
}

4. 继承的本质分析
  • 案例分析:

子类继承了父类,在创建子类对象时,内存中到底发生了什么?对象调用属性和成员方法时,顺序是什么样的(提示,按照查找的关系)?先看一段代码,看看主方法中会输出什么。

  • 代码如下:
public class ExtendsTheory {
    public static void main(String[] args) {
    
        Son son = new Son();
        System.out.println(son.name);// 返回就是子类的name= 大头儿子
        // System.out.println(son.age);// 会报错,访问受限
        System.out.println(son.getAge());// 使用父类的公共get方法,返回的就是父类的age= 39
        System.out.println(son.hobby);// 返回的就是爷类的hobby= 旅游
    }
}

// 爷类
class GrandPa { 
    String name = "大头爷爷";
    String hobby = "旅游";
}

// 父类
class Father extends GrandPa {
    String name = "大头爸爸";
    private int age = 39;

    public int getAge() {
        return age;
    }
}

// 子类
class Son extends Father { 
    String name = "大头儿子";
}

  • 内存流程示意图如下:
  • 内存布局解释:
  1. Son son = new Son(),首先在方法区中加载了Son 类和Son类继承的所有父类的信息,先查找Son 类的所有父类信息,从最顶层的父类开始加载,也就是Object -> GrandPa -> Father -> Son。
  2. 加载完类的信息后,其次在堆内存中开辟一个内存空间(地址),空间里面又划分了几个独立的类空间块(空间块个数由加载类的个数决定)。
  3. 接着给每个类空间块分配(初始化)属性,第一个是爷类空间块,分配爷类的属性;第二个是父类空间块,分配父类的属性;最后是子类空间块,分配子类的属性;由于各个类空间块是相互独立的,所以属性名相同也不会相互影响。
  4. 在分配完毕对象内存空间后,最后将内存地址返回给main 栈中的对象名 son,此时son 便指向了该对象内存,可以引用里面的信息。
  • 假设现在要用 son 输出某个属性,注意:要按照从下往上查找的关系来返回信息,如下:
  1. 首先看子类是否有该属性;
  2. 如果子类有这个属性,并且可以访问,则返回信息;
  3. 如果子类没有这个属性,接着看直接的父类有没有这个属性:
    (1)如果父类有该属性,并且可以访问,就返回信息;
    (2)如果父类有该属性,但是不可以访问(访问修饰符限制),则直接返回访问受限的错误信息(报错),而不会跳过父类接着访问上级的父类属性。
  4. 如果直接的父类没有这个属性,才可以按照 3 的规则,继续向上查找上级父类,直到 Object类 结束,或者最后找不到这个属性返回错误信息;
总结
  • 本文是小白博主在学习B站韩顺平老师的Java网课时整理总结的学习笔记,在这里感谢韩顺平老师的网课,如有有兴趣的小伙伴也可以去看看。
  • 本文详细解释了 继承 的概念与使用,并深入介绍了 继承 的注意事项和细节,继承是面向对象三大特征之一,非常重要,希望小伙伴们看后能有所收获!
  • 最后,如果本文有什么错漏的地方,欢迎大家批评指正!一起加油!!我们下一篇博文见吧!
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1009653.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号