第5节:Java基础 - 必知必会(下)
第5节:Java基础 - 必知必会(下)
本小节是Java基础篇章的第三小节,主要讲述Java中的Exception与Error,JIT编译器以及值传递与引用传递的知识点。
一、Java中的Exception和Error有什么区别
Exception和Error的主要区别可以概括如下:
Exception是程序正常运行中预料到可能出现的错误,并且应该被捕获并进行相应处理,是一种异常现象。
Error是正常情况下不可能发生的错误,Error会导致JVM处于已追踪不可恢复的状态,不需要捕获处理,比如说OutOfMemoryError
解析:
Exception又分为了运行时异常和编译异常。
编译异常(受检异常)表示当前调用的方法体内部抛出了一个异常,所以编译器检测到这段代码在运行时可能会出现异常,所以我们必须对异常进行相应处理,可以捕获异常或者抛给上层调用方。
运行时异常(非受检异常)表示在运行时出现的异常,常见的运行异常包括:空指针异常,数组越界异常,数字转换异常以及算数异常等。
前面说到了异常Exception应该被捕获,我们可以使用try-catch-finally来处理异常,并且使得程序恢复正常。
那么我们捕获异常应该遵循哪些基本原则呢?
尽可能捕获比较详细的异常,而不是使用Exception一起捕获。
当本模块不知道捕获之后该怎么处理异常时,可以将其抛给上层模块。上层模块拥有更多的业务逻辑,可以进行更好的处理。
捕获异常后至少应该有日志记录,方便之后的排查。
不要使用一个很大的try-catch包住整段代码,不利于问题的排查。
NoClassDefFoundError 和 ClassNotFoundException 有什么区别?
从名字中,我们可以看出前者是一个错误,后者是一个异常。我们先来看下JDK中对ClassNotFoundException异常的阐述:
大概意思就是在说,当我们使用例如Class.forName方法来动态的加载该类的时候,传入了一个类名,但是其并没有在类路径中被找到的时候,就会报ClassNotFoundException异常。出现这种情况,一般都是类名字传入有误导致的。
我们再来看下JDK中对该错误NoClassDefFoundError的阐述:
大概意思是这样的,如果JVM或者ClassLoader实例尝试加载(可以通过正常的方法调用,也可能是使用new来创建新的对象)类的时候却找不到类的定义。但是要查找的类在编译的时候是存在的,运行的时候却找不到了。这个时候就会导致NoClassDefFoundError。出现这种情况,一般是由于打包的时候漏掉了部分类或者Jar包被篡改已经损坏。
二、JIT编译器
前面我们谈到了Java是一种先编译,后解释执行的语言。那么我们就来说下何为JIT编译器吧。
JIT编译器全名叫Just In Time Compile 也就是即时编译器,把经常运行的代码作为"热点代码"编译成与本地平台相关的机器码,并进行各种层次的优化。JIT编译除了具有缓存的功能外,还会对代码做各种优化,包括逃逸分析、锁消除、 锁膨胀、方法内联、空值检查消除、类型检测消除以及公共子表达式消除等。
解释:
JIT编译器属于Java基础中的比较有深度的题目了,回答出来算是一个亮点了。既然说到了JIT编译器,我们来看下JIT对代码优化使用到的逃逸分析技术吧。
逃逸分析:
逃逸分析的基本行为就是分析对象动态作用域,当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他地方中,称为方法逃逸。JIT编译器的优化包括如下:
同布省略:也就是锁消除,当JIT编译器判断不会产生并发问题,那么会将同步synchronized去掉
标量替换
我们先来解释下标量和聚合量的基本概念。
标量(Scalar)是指一个无法再分解成更小的数据的数据。Java中的原始数据类型就是标量。
聚合量(Aggregate)是还可以分解的数据。Java中的对象就是聚合量,因为他可以分解成其他聚合量和标量。
在JIT阶段,如果经过逃逸分析,发现一个对象不会被外界访问的话,那么经过JIT优化,就会把这个对象拆解成若干个其中包含的若干个成员变量来代替。这个过程就是标量替换。标量替换的好处就是对象可以不在堆内存进行分配,为栈上分配提供了良好的基础。
那么逃逸分析技术存在哪些缺点呢?
技术不是特别成熟,分析的过程也很耗时,如果没有一个对象是不逃逸的,那么就得不偿失了。
三、Java中的值传递和引用传递
值传递和引用传递的解释可以概括如下。
值传递,意味着传递了对象的一个副本,即使副本被改变,也不会影响源对象。
引用传递,意味着传递的并不是实际的对象,而是对象的引用。因此,外部对引用对象的改变会反映到所有的对象上。
我们先看一个值传递的例子:
public class Test {
public static void main(String[] args) {
int x=0;
change(x);
System.out.println(x);
}
static void change(int i){
i=7;
}
}
毫无疑问,上边的代码会输出0。因为如果参数是基本数据类型,那么是属于值传递的范畴,传递的其实是源对象的一个copy副本,不会影响源对象的值。
我们再来分析一个引用传递的例子:
public class Test {
public static void main(String[] args) {
StringBuffer x = new StringBuffer("Hello");
change(x);
System.out.println(x);
}
static void change(StringBuffer i) {
i.append(" world!");
}
}
通过运行程序,输出为Hello world!接下来我们通过图片来分析下程序执行过程种的内存变化吧。
由图中我们可以看出x和i指向了同样的内存地址,那么i.append操作将直接修改了内存地址里边的值,所以当方法结束,局部变量i消失,先前变量x所指向的内存值已经发生了变化,所以输出为Hello world!
接着,我们修改下change方法,代码如下所示:
public class Test {
public static void main(String[] args) {
StringBuffer x = new StringBuffer("Hello");
change2(x);
System.out.println(x);
}
static void change2(StringBuffer i) {
i = new StringBuffer("hi");
i.append(" world!");
}
}
先给出答案,上边Demo的输出为Hello,我们依然来画图分析内存变化。
由图中我们可以看出来,在函数change2中将引用变量i重新指向了堆内存中另一块区域,下边都是对另一块区域进行修改,所以输出是Hello。
最后,我们继续升级该题目代码如下:
public class Test {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("Hello ");
System.out.println("Before change, sb = " + sb);
changeData(sb);
System.out.println("After change, sb = " + sb);
}
public static void changeData(StringBuffer strBuf) {
StringBuffer sb2 = new StringBuffer("Hi,I am ");
strBuf = sb2;
sb2.append("World!");
}
}
输出为:
Before change, sb = Hello
After change, sb = Hello
第5节:Java基础 - 必知必会(下)的更多相关文章
- 第4节:Java基础 - 必知必会(中)
第4节:Java基础 - 必知必会(中) 本小节是Java基础篇章的第二小节,主要讲述抽象类与接口的区别,注解以及反射等知识点. 一.抽象类和接口有什么区别 抽象类和接口的主要区别可以总结如下: 抽象 ...
- 第3节:Java基础 - 必知必会(上)
第3节:Java基础 - 必知必会(上) 本篇是基础篇的第一小节,我们从最基础的java知识点开始学习.本节涉及的知识点包括面向对象的三大特征:封装,继承和多态,并且对常见且容易混淆的重要概念覆盖和重 ...
- Java面试必知必会(扩展)——Java基础
float f=3.4;是否正确? 不正确 3.4是双精度,将双精度赋值给浮点型属于向下转型,会造成精度损失: 因此需要强制类型转换: 方式一:float f=(float)3.4 方式二:float ...
- Java面试必知必会:基础
面试考察的知识点多而杂,要完全掌握需要花费大量的时间和精力.但是面试中经常被问到的知识点却没有多少,你完全可以用 20% 的时间去掌握 80% 常问的知识点. 一.基础 包括: 杂七杂八 面向对象 数 ...
- 迈向高阶:优秀Android程序员必知必会的网络基础
1.前言 网络通信一直是Android项目里比较重要的一个模块,Android开源项目上出现过很多优秀的网络框架,从一开始只是一些对HttpClient和HttpUrlConnection简易封装使用 ...
- 【SQL必知必会笔记(1)】数据库基础、SQL、MySQL8.0.16下数据库、表的创建及数据插入
文章目录 1.数据库基础 1.1 数据库(database) 1.2 表(table) 1.3 列和数据类型 1.4 行 1.5 主键 2.什么是SQL 3.创建后续练习所需数据库.表(MySQL8. ...
- Java并发必知必会第三弹:用积木讲解ABA原理
Java并发必知必会第三弹:用积木讲解ABA原理 可落地的 Spring Cloud项目:PassJava 本篇主要内容如下 一.背景 上一节我们讲了程序员深夜惨遭老婆鄙视,原因竟是CAS原理太简单? ...
- 必知必会之 Java
必知必会之 Java 目录 不定期更新中-- 基础知识 数据计量单位 面向对象三大特性 基础数据类型 注释格式 访问修饰符 运算符 算数运算符 关系运算符 位运算符 逻辑运算符 赋值运算符 三目表达式 ...
- .NET零基础入门09:SQL必知必会
一:前言 仿佛到了更进一步的时候了,每一个程序员迟早都会遇到数据存储的问题.我们拿什么来存储程序产生的数据?举例来说,用什么来存储我们的打老鼠游戏每次的成绩呢?选择如下: 1:内存中.缺点,退出游戏, ...
随机推荐
- Python 基础之re 模块
Python 基础之大话 re 在使用re模块中主要会用到一下几个方法: re.match() #从头匹配一个字符串 re.search() #浏览全部字符串,匹配第一个符合规则的字符串 re.fin ...
- jdk 错误1316 指定账户已存在 与 jdk1.7安装和配置环境变量 与 jdk1.8与1.7版本的切换使用
问题: 安装JDK,提示错误信息:,指定的账号已存在. 原因: 安装JDK,相当于安装了一个软件,要使用系统的软件卸载功能卸载,不能只删除安装目录文件夹下的文件,如果只 ...
- Java枚举——枚举的作用、使用方法、使用场景
枚举的定义 枚举关键字enum 枚举类是一种特殊类,它和普通类一样可以使用构造器.定义成员变量和方法,也可以实现多个接口,但不能继承类. 枚举的使用 enum Color { RED, BLUE, G ...
- 为什么Python类语法应该不同?
做过python的人你会发现想要的东西跟它原有的是不同的.Python对我来说是真的是这样.如果可以的话,对于Python中很多的我想要改的东西,我有很多的想法.现在我向您讲述其中一个:类定义的语法. ...
- chrome中安装Vue调试工具vue-devtools
一.前言 vue-devtools是一款基于浏览器的插件,用来调试vue应用.本篇文章将要总结的是如何在chrome中安装Vue的调试工具vue-devtools. 首先能想到的第一种方法就是直接在c ...
- nyoj 290 动物统计加强版 (字典树 (Trie) PS:map<TLE>)
动物统计加强版 时间限制:3000 ms | 内存限制:150000 KB 难度:4 描述 在美丽大兴安岭原始森林中存在数量繁多的物种,在勘察员带来的各种动物资料中有未统计数量的原始动物的名单 ...
- java操作RabbitMQ添加队列、消费队列和三个交换机
假设已经在服务器上安装完RabbitMQ.我写的教程 一.发送消息到队列(生产者) 新建一个maven项目,在pom.xml文件加入以下依赖 <dependencies> <depe ...
- 2C 还是 2B,跟找工作有什么关系?
通常,我们会把公司的业务类型分成以下几种: 2C,to Customer,指面向个人客户的业务,即将公司的产品或服务销售给个人,通常做出购买决策的个人也是使用产品或服务的用户.举例说明,像 BAT 发 ...
- NTP服务搭建详解一条龙
说在前面:ntp和ntpdate区别 ①两个服务都是centos自带的(centos7中不自带ntp).ntp的安装包名是ntp,ntpdate的安装包是ntpdate.他们并非由一个安装包提供. ② ...
- spring日志体系浅析(spring 5.x)
日志是进行软件开发必不可少的一项功能,目前流行着很多开源日志库,比如log4j.log4j2.logback.JDK Logging.commons-logging.slf4j等. 几种日志产品的介绍 ...