第1讲 | 谈谈你对Java平台的理解?
Java两大特性
1、跨平台能力:书写一次,到处运行(Write once, run anywhere)
2、垃圾收集
Java 通过字节码和 Java 虚拟机(JVM)这种跨平台的抽象,屏蔽了操作系统和硬件的细节,这也是实现“一次编译,到处执行" 的基础。
JRE,也就是 Java 运行环境,包含了 JVM 和 Java 类库,以及一些模块等。
JDK 可以看作是 JRE 的一个超集,提供了更多工具,比如编译器、各种诊断工具等。
JDK8是解释和编译混合执行的模式
1、解释执行
源代码编译成字节码(bytecode),JVM解释器将字节码转换为机器码执行。
2、编译执行
JIT在运行时把热点代码编译成机器码
类加载机制
Class-Loader
Bootstrap、 Extension Class-Loader 、 Application
类加载过程
加载、验证、链接、初始化
常见的垃圾收集器
SerialGC、Parallel GC、 CMS、 G1
第2讲 | Exception和Error有什么区别?
对比 Exception 和 Error,另外,运行时异常与一般异常有什么区别?
1、理解 Throwable、Exception、Error 的设计和分类
NoClassDefFoundError与ClassNotFoundException之间的区别
https://blog.csdn.net/u012208784/article/details/79564414
2、理解 Java 语言中操作 Throwable 的元素和实践
try-with-resource & multiple catch
https://www.cnblogs.com/itZhy/p/7636615.html
try (BufferedReader br = new BufferedReader(…);
BufferedWriter writer = new BufferedWriter(…)) {// Try-with-resources
// do something
catch ( IOException | XEception e) {// Multiple catch
// Handle it
}
下面代码有哪些不当之处?
try {
// 业务代码
// …
Thread.sleep(1000L);
} catch (Exception e) {
// Ignore it
}
1、尽量不要捕获类似 Exception 这样的通用异常,而是应该捕获特定的异常.
- 隐藏了真正目的
- RuntimeException也被捕获
- 不要捕获Throwable, 否则OOM无法处理
2、不要生吞异常
再看看第二段代码
try {
// 业务代码
// …
} catch (IOException e) {
e.printStackTrace();
}
printStackTrace:Prints this throwable and its backtrace to the **standard error stream".
在稍微复杂一点的生产系统中,标准出错(STERR)不是个合适的输出选项,很难判断出到底输出到哪里。
Throw early, catch late 原则
public void readPreferences(String fileName){
//...perform operations...
InputStream in = new FileInputStream(fileName);
//...read the preferences file...
}
如果 fileName 是 null,那么程序就会抛出 NPE,但是由于没有第一时间暴露出问题,堆栈信息可能非常令人费解,往往需要相对复杂的定位。
让问题“throw early”,对应的异常信息就非常直观了。
public void readPreferences(String filename) {
Objects. requireNonNull(filename);
//...perform other operations...
InputStream in = new FileInputStream(filename);
//...read the preferences file...
}
image.png
自定义异常,这个时候除了保证提供足够的信息,还有两点需要考虑:
1、是否需要定义成 Checked Exception,因为这种类型设计的初衷更是为了从异常情况恢复。
2、在保证诊断信息足够的同时,也要考虑避免包含敏感信息,因为那样可能导致潜在的安全问题。
从性能角度来审视一下 Java 的异常处理机制,这里有两个可能相对昂贵的地方:
-
try-catch 代码段会产生额外的性能开销,会影响 JVM 对代码进行优化。除了必要代码段,不要try一大段代码。不要使用try-catch控制流程。
-
Java 每实例化一个 Exception,都会对当时的栈进行快照,这是一个比较重的操作
当我们的服务出现反应变慢、吞吐量下降的时候,检查发生最频繁的Exception也是一种思路。
第3讲 | 谈谈final、finally、 finalize有什么不同?
image.png推荐使用 final 关键字来明确表示我们代码的语义、逻辑意图,这已经被证明在很多场景下是非常好的实践,比如:
-
我们可以将方法或者类声明为 final,这样就可以明确告知别人,这些行为是不许修改的。
-
使用 final 修饰参数或者变量,也可以清楚地避免意外赋值导致的编程错误,甚至,有人明确推荐将所有方法参数、本地变量、成员变量声明为final。
-
final 变量产生了某种程度的不可变(immutable)的效果,所以,可以用于保护只读数据,尤其是在并发编程中,因为明确地不能再赋值 final 变量,有利于减少额外的同步开销,也可以省去一些防御性拷贝的必要。
知识扩展
1. final 并不等同于 immutable
final List<String> strList = new ArrayList<>();
strList.add("Hello");
strList.add("world");
// java 9支持
List<String> unmodifiableStrList = List.of("hello", "world");
unmodifiableStrList.add("again");
image.png
关于 setter/getter 方法,很多人喜欢直接用 IDE 一次全部生成,建议最好是你确定有需要时再实现。
2.finalize 真的那么不堪?
image.png3. 有什么机制可以替换 finalize 吗?
image.pngpublic class CleaningExample implements AutoCloseable {
// A cleaner, preferably one shared within a library
private static final Cleaner cleaner = <cleaner>;
static class State implements Runnable {
State(...) {
// initialize State needed for cleaning action
}
public void run() {
// cleanup action accessing State, executed at most once
}
}
private final State;
private final Cleaner.Cleanable cleanable
public CleaningExample() {
this.state = new State(...);
this.cleanable = cleaner.register(this, state);
}
public void close() {
cleanable.clean();
}
}
image.png
第4讲 | 强引用、软引用、弱引用、幻象引用有什么区别?
不同的引用类型,主要体现的是对象不同的可达性(reachable)状态和对垃圾收集的影响。
image.png image.png image.png所有引用类型,都是抽象类 java.lang.ref.Reference的子类,你可能注意到它提供了 get() 方法:
image.png image.png
引用队列(ReferenceQueue)使用
image.pngObject counter = new Object();
ReferenceQueue refQueue = new ReferenceQueue<>();
PhantomReference<Object> p = new PhantomReference<>(counter, refQueue);
counter = null;
System.gc();
try {
// Remove 是一个阻塞方法,可以指定 timeout,或者选择一直阻塞
Reference<Object> ref = refQueue.remove(1000L);
if (ref != null) {
// do something
}
} catch (InterruptedException e) {
// Handle it
}
第5讲 | String、StringBuffer、StringBuilder有什么区别?
image.png你要知道 String 是 Immutable 的,字符串操作不当可能会产生大量临时字符串,以及线程安全方面的区别。
image.png image.png2. 字符串缓存
image.png3.String 自身的演化
image.png第6讲 | 动态代理是基于什么原理?
image.png动态代理解决了什么问题?
JDK Proxy实现动态代理
public class MyDynamicProxy {
public static void main (String[] args) {
HelloImpl hello = new HelloImpl();
MyInvocationHandler handler = new MyInvocationHandler(hello);
// 构造代码实例
Hello proxyHello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), HelloImpl.class.getInterfaces(), handler);
// 调用代理方法
proxyHello.sayHello();
}
}
interface Hello {
void sayHello();
}
class HelloImpl implements Hello {
@Override
public void sayHello() {
System.out.println("Hello World");
}
}
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("Invoking sayHello");
Object result = method.invoke(target, args);
return result;
}
}
image.png
image.png
image.png
JDKProxy: 被代理类要实现接口,代理对象基于接口生成。
cglib: 被代理类不需要实现接口,代理对象是目标类的子类对象。
第7讲 | int和Integer有什么区别?
image.png image.png image.pngclass Counter {
private final AtomicLong counter = new AtomicLong();
public void increase() {
counter.incrementAndGet();
}
}
如果利用原始数据类型,可以将其修改为
class CompactCounter {
private volatile long counter;
private static final AtomicLongFieldUpdater<CompactCounter> updater = AtomicLongFieldUpdater.newUpdater(CompactCounter.class, "counter");
public void increase() {
updater.incrementAndGet(this);
}
}
image.png
image.png
网友评论