美文网首页
Java核心技术36讲

Java核心技术36讲

作者: governlee | 来源:发表于2019-02-28 10:52 被阅读0次

    第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

    image.png image.png image.png

    第2讲 | Exception和Error有什么区别?

    对比 Exception 和 Error,另外,运行时异常与一般异常有什么区别?

    1、理解 Throwable、Exception、Error 的设计和分类

    image.png

    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 变量,有利于减少额外的同步开销,也可以省去一些防御性拷贝的必要。

    image.png

    知识扩展

    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.png

    3. 有什么机制可以替换 finalize 吗?

    image.png
    public 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.png
    Object 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.png

    2. 字符串缓存

    image.png

    3.String 自身的演化

    image.png

    第6讲 | 动态代理是基于什么原理?

    image.png

    动态代理解决了什么问题?

    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: 被代理类不需要实现接口,代理对象是目标类的子类对象。

    image.png

    第7讲 | int和Integer有什么区别?

    image.png image.png image.png
    class 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

    第8讲 | 对比Vector、ArrayList、LinkedList有何区别?

    image.png image.png image.png image.png

    第9讲 | 对比Hashtable、HashMap、TreeMap有什么不同?

    image.png image.png image.png image.png image.png

    相关文章

      网友评论

          本文标题:Java核心技术36讲

          本文链接:https://www.haomeiwen.com/subject/pwrquqtx.html