Java类加载顺序之一条日志引发的血案

目录

  • 为什么是null
  • 回顾类加载
  • 原因
  • 问题重现
  • 总结
    • 类加载顺序
    • 子类重写被父类构造函数调用的函数注意
    • 不能放过不起眼的日志

一条日志引发的案子

[11:12:58.505][D][Gen][RTLive][getIns ins = 4414717]
[11:12:58.774][I][Gen][null][updateShowMode]
[11:12:58.864][D][Gen][VideoCameraCapture][setOrientation ortation = 1]
[11:12:58.865][D][Gen][VideoCapture][setOrientation ortation = 1]
[11:12:58.865][D][Gen][VideoCapture][setHardEncode isHardEncode false]

为什么是null

第二行日志中的 “null” 引起了我的关注,正常情况下这里应该是该条日志所在的类的类名称,现出现了null,首先从日志阅读习惯上就不顺了。其次是TAG的值是给null,需要弄清楚。还存在TAG 没有初始化的嫌疑。

首先通过"updateShowMode"找到对应的代码位置。函数第一行就打了日志,而TAG是个成员变量,定义如下:

private String TAG = getClass().getSimpleName();public synchronized void updateShowMode() {GenLog.i(TAG,"updateShowMode");
}

这样的模型,TAG的值为什么是null。那就是类加载时机的问题了。

回顾类加载

先定义如下类

public class Person {private static String staticVar = staticVar(“def”);//目的是打日志,从日志上看顺序private String var = var();//目的是打日志,从日志上看顺序public Person(){System.out.println("Person init");}private String var() {System.out.println("Person var");return "var";}public static String (String param){System.out.println("Person staticVar" + param);return "staticVar";}static {System.out.println("Person static code");}
}

Person person = new Person(); 被执行时输出如下:

Person staticVar def
Person static code
Person var
Person init

加载顺序依次如下:

  • 静态变量
  • 静态代码块
  • 成员变量
  • 构造函数

Person.staticVar(“main”); 参数是为了区别外部与内部谁先调用,被执行时输出如下:

Person staticVar def
Person static code
Person staticVar main

执行顺序:
静态变量的初始化
静态代码块
外部调用的执行

加载顺序还是保持

  • 静态变量
  • 静态代码块

出现了上面的null,getClass().getSimpleName() 会有问题吗?我们将成员函数稍微变一下:

public class Person {private static String staticVar = staticVar("def");private String var = var();public Person(){System.out.println("Person init");}private String var() {//这里输出getClass().getSimpleName()的结果String name = getClass().getSimpleName();System.out.println("Person var name = " + name);return "var";}public static String staticVar(String param){System.out.println("Person staticVar " + param);return "staticVar";}static {System.out.println("Person static code");}
}

再次执行Person person = new Person(); 结果如下:

Person staticVar def
Person static code
Person var name = Person
Person init

说明getClass().getSimpleName()没有问题。

到底什么情况呢,经过一番折腾,发现还有一个继承关系,updateShowMode覆盖父类的函数,且updateShowMode是在父类构造函数中调用的。

我们再加一个类Any 作为person的父类

public class Any {private static String TAG = staticVar();private String var = var();private static String staticVar() {System.out.println("Any staticVar");return "Any staticVar";}public Any(){System.out.println("Any init");}public void test(){System.out.println("Any test");}private String var(){System.out.println("Any var");return "Any var";}static {System.out.println("Any static code");}
}//Person 类变化如下 继承Any
class Person extends Any

执行Person person = new Person(); 结果如下:

Any staticVar
Any static code
Person staticVar def
Person static code
Any var
Any init
Person var name = Person
Person init

执行顺序依次:

  1. 父类静态变量
  2. 父类静态代码块
  3. 子类静态变量
  4. 子类静态代码块
  5. 父类成员变量
  6. 父类构造函数
  7. 子类成员变量
  8. 子类构造函数

原因

出现null是因为没有把握好6和7的顺序。父类构造函数(6)调用了子类重载函数,重载函数又访问了子类的成员变量。此时还在执行父类的构造函数,子类的成员变量还没有被初始化(7),所以出现了null

问题重现

我们再次修改Any和Person 的test重载
Any 构造函数调用test()

public class Any {private static String TAG = staticVar();private String var = var();private static String staticVar() {System.out.println("Any staticVar");return "Any staticVar";}public Any(){System.out.println("Any init");//构造函数调用成员函数test();}public void test(){System.out.println("Any test");}private String var(){System.out.println("Any var");return "Any var";}static {System.out.println("Any static code");}
}

Person
覆盖Any的test(),并输出var

public class Person extends Any{private static String staticVar = staticVar("def");private String var = var();public Person(){System.out.println("Person init");}private String var() {String name = getClass().getSimpleName();System.out.println("Person var name = " + name);return "var";}public static String staticVar(String param){System.out.println("Person staticVar " + param);return "staticVar";}@Overridepublic void test() {//覆盖重写父类的test函数,并访问var 输出varSystem.out.println("Person test var= " + var);}static {System.out.println("Person static code");}
}

再次执行Person person = new Person(); 输出:

Any staticVar
Any static code
Person staticVar def
Person static code
Any var
Any init
Person test var= null
Person var name = Person
Person init

Person test var= null 得到应证。

总结

类加载顺序

  1. 父类静态变量
  2. 父类静态代码块
  3. 子类静态变量
  4. 子类静态代码块
  5. 父类成员变量
  6. 父类构造函数
  7. 子类成员变量
  8. 子类构造函数

没有继承关系的情况下

  1. 静态变量
  2. 静态代码块
  3. 成员变量
  4. 构造函数

子类重写被父类构造函数调用的函数注意

重载函数被调用的过程中,成员变量是没有被初始化的。

不能放过不起眼的日志

我们要多看日志,养成日志规范,并充分利用日志解决问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/558204.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java错误:找不到或无法加载主类

目录前言javac xxx.java 编译需要相对物理路径java xxx 执行需要虚拟路径总结前言 一般情况下,我们都使用工具进行代码的编辑和调试,例如eclipse 、Manven、Android Studio、sublime、vim、notepad、记事本等。 当我们用eclipse android studio等创建的p…

vue取通过key取value_如何通过获取map中的key来获得与key对应的value值,进行运算...

展开全部获取map的key和value的方法分为以下62616964757a686964616fe4b893e5b19e31333366306439两种形式:1、map.keySet():先获取map的key,然后根据key获取对应的value;2、map.entrySet():同时查询map的key和value&…

Android坑点-ByteBuffer.array() 入过坑吗

目录1、坑点介绍2、正确使用姿势(入坑了怎么办)3、坑坑详解3.1HeapByteBuffer可以用buffer.array()3.2DirectByteBuffer的坑在哪里1、坑点介绍 如下代码: ByteBuffer buffer ByteBuffer.allocateDirect(int capacity) byte[] array buf…

php四则运算出题器_php实现简单四则运算器

本文实例为大家分享了php实现简单四则运算器的具体代码,供大家参考,具体内容如下前端代码 :php计算器请输入num1:请选择运算符:-*/%请输入num2:后台:php计算器$num1$_post["num1"];$n…

步苹果iOS的后尘,谷歌Android12“翻车”,更新需谨慎?

苹果不论电脑还是移动设备,都是一如既往的“强硬”。说实话,忽视“兼容”,体验极低。 有小伙伴调侃:人家就是要你买新机器。也有小伙伴(包括我在内),直接关闭系统自动更新。 开发者&#xff1a…

word把选择答案弄到题目里_word中把选择题的正确答案自动填到括号里技巧

为了适应各类复习迎考,大家都会利用一些题目来练习。当面对题目与答案分离的现状(两个文档或一个文档的两个部分)时,怎样将题目和答案合二为一,使答案自动填充到题目后的括号中是颇让大家头疼的一件事情。经过实践探索多步骤的组合操作可以实…

Android Studio无线连接设备调试,比数据线更方便

前言 一般情况下,多数移动开发者使用的是数据线连接电脑,进行各种移动设备的调试,更有胜者,非常迷恋模拟器,模拟器它好不好,答案是好,因为直接运行在电脑上,直接操作,调试…

机器学习里面的基函数_神经网络与机器学习 笔记—核方法和径向基函数网络(上)...

对于神经网络的监督学习有多种不同方法。之前一直总结整理的多层感知器反向传播算法,可以看做是递归技术的应用,这种技术在统计学中通称为随机逼近。这次是采用不同的途径,通过包含如下两个阶段的混合方式解决非线性可分模式的分类问题&#…

AndroidJava List与equals的微妙关系,小心掉坑里

前言 List 有多个实现,本文以ArrayList(LinkedList也一样)作为说明,equals是Object的一个成员函数,例子中的bean重写实现它。 一、Bean 类定义并重写equals函数 public class Book {private String id;private String name;public String ge…

apache缺省banner_http服务器缺省banner

HTTP协议详解(真的很经典)HTTP协议详解(真的很经典)Author :清晨引言HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。目…

GenseeSDK 使用Kotlin要注意TODOAndroid Studio关闭TODO

目录一、Kotlin的TODO二、GenseeSDK与TODO 请注意三、Android studio关闭TODO一、Kotlin的TODO 在实现一些接口时候,工具自动将所有的接口函数"空"实现,并在函数体中增加一行代码: TODO或TODO(“not implemented”) 作为提醒催促…

如何启动netcat_Netcat用法

Netcat用法--服务泄漏内部信息要得到某些端口号的详细信息,可以连接到某个端口,对应的服务会告知它的版本号、结构甚至其工作的操作系统。所以,可以使用Netcat来扫描一个特定范围内的端口并报告在这些端口上运行的服务。要使Netcat自动工作&a…

AndroidJava try-catch-finally正确用法

目录一、try-catch-finally的用途二、try-catch的正确使用三、奇怪的try-finally (错误的用法)四、关于try-catch-finally的面试考察1、try、catch、finally 考察,请指出下面程序的运行结果。2、try、catch、finally 考察2,请指出…

python tcp服务器并发_python tcp并发服务器

{"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],"search_count":[{"count_phone":6,"count":6}]},"card":[{"des":"云服务器 ECS(Elastic Compute Service)是一…

OpenCV Mat基础认知感

OpenCV是一个开源的供开发的计算机视觉处理库,涵盖的内容包括图像处理,机器学习。由c到c ,再到各平台的跨平台框架。 Mat - 图像容器 Mat类用于表示一个多维的单通道或者多通道的稠密数组。能够用来保存实数或复数的向量、矩阵,…

layui多文件上传讲解_Layui 多文件上传 SSH

jsp 页面pageEncoding"UTF-8"%>Insert title here选择多文件文件名大小状态操作开始上传layui.use(upload, function(){var $ layui.jquery,upload layui.upload;//多文件列表示例var demoListView $(#demoList),uploadListIns upload.render({elem: #testLis…

OpenCV:H1.type() == H2.type() H1.depth() == CV_32F

如题: E/cv::error(): OpenCV(4.1.0) Error: Assertion failed (H1.type() H2.type() && H1.depth() CV_32F) in compareHist, file /build/master_pack-android/opencv/modules/imgproc/src/histogram.cpp, line 1936 E/org.opencv.imgproc: imgproc::co…

css 外弧_css 伪类实现弧形

在实现页面五花八门的有特色的ui时,我们有时会遇到要用实现一个弧形,而这样的弧形要怎么实现呢?用图片?不太优雅,这样就要无故多加载一张图片了,这里来说说怎么用css的after伪类来实现弧形。总思路&#xf…

C++期末实践程序设计与数组作为参数的注意事项

目录小表弟发来的求助信号要点代码文件头文件Student.h源文件Student.cppmain.c执行结果c数组特性以及数组做形参的特点数组试验数组特殊性质不允许拷贝和赋值数组是通常被转化成指针使用数组形参多种写法代理模式MVC模式小表弟发来的求助信号 并补充说要5种写法才算过关。 要…

sgm3157功能_SGM3157_SGM3157供应商_价格_Datasheet_pdf资料-IC资料网

SGM31574.5惟 Low Voltage SPDT Analog SwitchSGMICROSG Micro CorpLow Voltage SPDT Analog Switch in 6-Pin SC70SGMICROSG Micro Corp4.5惟 Low Voltage SPDT Analog SwitchSGMICROSG Micro CorpFLAT WASHERS NYLON FIBREetc2List of Unclassifed Manufacturers70 MHz Bandp…