导图社区 java基础学习思维导图
无数据
java基础学习思维导图,如编译型语言:如C语言,将源程序直接编译为机器能识别的二进制语言<br>。
编辑于2023-06-29 22:55:50 广东java基础
Java特点<br>
编程语言区分
概念区分
编译型语言:如C语言,将源程序直接编译为机器能识别的二进制语言<br>
解释型语言:典型代表Java,将源程序编译成.class文件后,由JVM虚拟机翻译成机器能识别的二进制语言<br>
优缺点
编译型语言执行速度快,但编译耗时;解释型语言编译快,执行慢
对Java而言,源代码首先需经过Java编译器编译成.class字节码文件,在由JVM将class文件加载进内存解释执行;但JVM支持JIT,能够以方法为单位将热点代码对应的class内容直接翻译成二进制语言(即时编译 / 解释执行)<br>
语言特性
面向对象
封装,继承,多态
异常机制
异常类
顶级类 Throwable<br>
只有Throwable的子类才能被捕获抛出,Error也是Throwable的子类,也是可以被捕获的
异常类 Exception<br>
异常会一直往上抛出,最终导致程序停止运行
运行时异常(非受检异常)代码逻辑错误导致<br>
运行时异常通常是由于代码出现了错误的逻辑导致的异常。如除零异常,空指针异常,数组下标越界异常。 非受检异常不要求必须处理才能编译。因为发生在运行时期
1. NullPointerException : 空指针异常,由于访问一个空对象而引起的异常<br>
2. ArrayIndexException : 数组越界异常,由于访问数组时下标越界而引发的异常<br>
3. ArthmeticException : 算数异常,由于进行除零等算术运算而引发的异常<br>
4. ClassCastException : 类型转换异常,由于进行类型转换时发送错误而引起的异常<br>
5. illegalArgumentException :非法参数异常,由于传递给对方的参数不合法而导致的异常<br>
6. NumberFormatException : 数字格式化异常,由于字符串无法转换成数字而出现的异常<br>
7. NoSuchElementException : 不存在的元素异常,由于访问一个不存在的元素而引发的异常<br>
8. UnSupportedOperatonException : 不支持操作异常,由于调用了不支持的方法或操作而引发的异常<br>
编译时异常(受检异常)外部影响导致<br>
受检异常通常表示程序无法处理的外部条件,例如文件不存在、网络连接中断等。这些异常需要在程序中进行处理,以确保程序的正确性和可靠性。如IOException 必须要处理编译时异常程序才能正常编译。处理方式如方法声明上throws 抛出或者try/finally 包裹
1. IOException : 输入/输出异常,由于读取或写入数据时出现的异常<br>
2. SQLException : SQL异常,操作数据库时出现的异常<br>
3. ClassNotFoundException : 类未找到异常,由于编译时找不到相关的字节码文件出现的异常<br>
4. InterruptedException : 线程中断异常,由于线程中断导致的异常<br>
5. NoSuchMethodExption : 方法未找到异常,由于无法找到所需的方法而引发的异常<br>
反射调用方法时,方法不存在抛出的异常
6. illegalAccessException : 非法访问异常,访问受保护或私有的方法或字段而引发的异常<br>
7. InstantiationException:实例化异常,由于无法实例化抽象类或接口或没有默认构造函数的类而引发的异常。<br>
8. ParseException : 转换异常,使用 SimpleDateFormat 将字符串转换日期类不符合格式时出现的异常<br>
异常处理原则
1. Throw eraly,catch later 早点抛出,方便定位具体错误信息,晚一点放到更上层处理,方便统一处理方式<br>
2. 抛出针对性的异常,不要直接抛出父类异常<br>
3. 不使用异常控制业务逻辑 ,异常需要记录堆栈信息损耗性能
4. 不要生吞异常<br>
Java异常处理机制<br>
Java每实例化一个异常,都会对当时的栈进行快照,并记录抛出异常的代码行数,是非常损耗性能的;<br>
如何创建一个不对栈快照的异常类
自定义异常类继承 Exception,调用父类的含参构造方法,参数 writableStackTrace 传值为false 即不对栈进行快照 <br>
final,finally, finalize的区别<br>
final
修饰class , 表示类不能被继承<br>修饰变量,表示不能被重新赋值(引用不可变)<br>修饰方法,表示方法不能被重写<br>
优点
1.安全性 :final修饰的变量一单被初始化就不能再重新被赋值,防止意外修改<br>
2.可读性 :final 修饰的变量是固定的,增加代码的可读性<br>
3.性能优化 : final 修饰的成员变量是固定的,编译器可以对其进行优化成常量。而final修饰的方法,JVM可以对此方法采用JIT(即时编译)进行方法内联(将被调用方法放入执行方法中,减少方法调用的损耗)<br>
缺点
如用final 修饰 集合,集合对象是可以添加修改元素的,如果想生成一个不可变的集合,需要使用List.of();<br>
finally
用于 try{}finally{} 代码块,用于执行必须要执行的代码<br>
注意如果调用System.exit(任意数字),则finally不会执行。如果需要释放资源,可以使用 try-with-resource语句。try(实现了AutoCloseable接口的类或实现了Closeable接口的类){}<br>
System.exit(0)表示正常退出,任意非0参数表示异常退出<br>
finalize
对方被回收时执行,属于Object类中的方法<br>
finalize 将会导致垃圾回收效率降低近50倍,并且finalize中的异常将会被生吞<br>
强引用,软引用,弱引用,虚引用的关系
强引用 : 不会回收<br>软引用: 内存不足时回收<br>弱引用: 垃圾回收时就回收<br>虚引用: 对象回收追踪<br>
引用队列的使用(备注)<br>
引用队列是Java中一种特殊的队列,它用于保存被垃圾回收器标记为“即将回收”的对象的引用,以便在对象被回收之前,进行一些必要的操作,例如资源释放、日志记录等。引用队列是通过java.lang.ref.ReferenceQueue类来实现的。 使用引用队列的步骤如下: 1. 创建一个引用队列对象:ReferenceQueue queue = new ReferenceQueue(); 2. 创建一个引用对象:SoftReference、WeakReference或PhantomReference,将要被回收的对象和引用队列对象作为参数传入。 3. 在程序中使用这个引用对象,当对象被垃圾回收器回收时,引用对象就会被加入到引用队列中。 4. 在程序中定期检查引用队列,如果队列中存在引用对象,则说明被引用的对象已经被回收,可以进行一些必要的操作。 需要注意的是,引用队列中保存的是引用对象,而不是被引用的对象本身,因此在使用引用队列时需要注意引用对象和被引用的对象之间的关系。另外,使用引用队列需要注意内存占用问题,因为引用队列中保存的对象可能会占用一定的内存空间。
String,StringBuilder,StringBuffer<br>
String
使用评率高,为了节省资源,引用了字符常量池,JDK8之前放在永久代中。由于永久代不会被回收,因此会导致OOM。JDK8及以后,放入堆中。如果是相同的字符串,将使用同一个引用。但如果显示的调用new 方法,那么引用将是不相同的。同时Java提供了inter()方法,能将字符串缓存起来。<br>
String s1 = new String("sz").intern(); String s2 = "sz"; System.out.println(s1==s2); 输出 true String s1 = new String("sz"); String s2 = "sz"; System.out.println(s1==s2); 输出 false
StringBuilder 是线程不安全的类,StringBuffer 是线程安全的 区别在与 StringBuffer 在每个方法上都添加了 synchronize 关键字<br>
动态代理与静态代理
区别
动态代理: 在程序运行时创建对象的代理类 缺点 : 编程复杂<br>
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; // 定义接口 public interface Subject { void request(); } // 目标类实现接口 public class RealSubject implements Subject { @Override public void request() { // 执行目标方法的具体逻辑 System.out.println("执行目标方法"); } } // 实现InvocationHandler接口的代理类 public class ProxyHandler implements InvocationHandler { private Object target; public ProxyHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 在调用目标方法之前可以添加一些额外的操作 System.out.println("调用目标方法之前的操作"); // 调用目标方法 Object result = method.invoke(target, args); // 在调用目标方法之后可以添加一些额外的操作 System.out.println("调用目标方法之后的操作"); return result; } } // 使用动态代理 public class Client { public static void main(String[] args) { // 创建目标对象 RealSubject realSubject = new RealSubject(); // 创建代理对象 Subject proxySubject = (Subject) Proxy.newProxyInstance( realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), new ProxyHandler(realSubject) ); // 通过代理对象调用目标方法 proxySubject.request(); } }
静态代理 : 在编译时期创建对象的代理类 缺点 : 每一个对象都需要创建一个代理类对象<br>
public interface Subject { void request(); } // 目标类实现接口 public class RealSubject implements Subject { @Override public void request() { // 执行目标方法的具体逻辑 System.out.println("执行目标方法"); } } // 代理类实现接口 public class ProxySubject implements Subject { private RealSubject realSubject; public ProxySubject(RealSubject realSubject) { this.realSubject = realSubject; } @Override public void request() { // 在调用目标方法之前可以添加一些额外的操作 System.out.println("调用目标方法之前的操作"); // 调用目标方法 realSubject.request(); // 在调用目标方法之后可以添加一些额外的操作 System.out.println("调用目标方法之后的操作"); } } // 使用代理类 public class Client { public static void main(String[] args) { // 创建目标对象 RealSubject realSubject = new RealSubject(); // 创建代理对象,并将目标对象传入代理类的构造方法 ProxySubject proxySubject = new ProxySubject(realSubject); // 通过代理对象调用目标方法 proxySubject.request(); } }
使用场景<br>
动态代理使用场景
日志
用户鉴权<br>
全局异常处理<br>
性能监控
事务处理
基本数据类型与包装类
八种基本数据类型
byte,short,char,int,long,doble,float,boolaen
包装类缓存(非 new的对象)<br>
Integer 缓存范围 -128 ~ 127<br>
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
<br>-XX:AutoBoxCacheMax=N 调整缓存值范围大小
String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } 如果 N 大于127 ,则使用 N,否则随时用 127 作为缓存上限。 下限则固定为 -128
线程安全性
原子类 AtomicInteger , AtomicLong<br>
原始数据类型不支持泛型,金额计算使用BigDecimal<br>
concurrentHashmap
1.7
put
分段锁segment,有多个segment,初始化16个,只能是2的倍数,一旦初始化则不能修改。每个segment中有多个桶bucket,每个桶上有k-v形式的链表。put元素时,首先hash计算所在的segment,对此segment加锁后再次hash计算所在桶,然后存放链表上
size
分段计算两次,结果相同则返回,对段加锁重新计算
1.8
put
首先判断容器是否为空,如果为空则利用cas初始化。接着hash计算所在桶,如果所在桶bucket为空,则利用cas创建新桶。如果桶不为空,则加锁遍历桶中链表,添加或修改删除元素
size
利用longadder分段计算
LongAdder是Java中的一个原子性的、线程安全的累加器类型,它可以高效地处理多个线程并发地对一个计数器进行累加操作。 下面是一个使用LongAdder的简单示例: ```java import java.util.concurrent.atomic.LongAdder; public class LongAdderExample { public static void main(String[] args) { // 创建LongAdder对象 LongAdder counter = new LongAdder(); // 创建10个线程并发地对计数器进行累加操作 for (int i = 0; i < 10; i++) { new Thread(() -> { for (int j = 0; j < 100000; j++) { counter.increment(); // 累加操作 } }).start(); } // 等待所有线程执行完毕 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // 输出最终的计数结果 System.out.println("Counter: " + counter.sum()); } } ``` 上述示例代码创建了一个LongAdder对象作为计数器,然后创建了10个线程来并发地对计数器进行累加操作。在每个线程中,我们使用`increment()`方法对计数器进行累加。 最后,我们等待所有线程执行完毕,并输出最终的计数结果。由于LongAdder是线程安全的,所以在多线程并发操作下,它可以高效地处理累加操作,而不需要使用锁来保护计数器。 使用LongAdder的好处是它比传统的AtomicLong在高并发情况下具有更好的性能,尤其是在写多读少的场景下。因为LongAdder内部使用了一种分段(分段累加器)的技术,将计数器的状态在多个单元之间进行分片,以减少并发操作的争用。 总结:LongAdder是Java中处理高并发累加操作的一种高效工具,特别适合于写多读少的场景。它可以在并发环境中保证计数器的原子性和线程安全性,同时具有更好的性能表现。
IO<br>
BIO
Socket编程
IO流
字节流
InputStream(字节输入流顶级接口)<br>
FileInputStream<br>
BufferInputStream<br>
ByteArrayInputstream<br>
ObjectInputstream<br>
OutputStream(字节输出流顶级接口)<br>
FileOutputStream<br>
BufferoutputStream<br>
ByteArrayOutputStream<br>
ObjectOutputstream<br>
字符流
Reader
FileReader
Writer
FileWriter<br>
转换流
InputstreamReader(字节输入转换流)<br>
OutputstreamWriter(字符输出转换流)<br>
NIO
三个组成部分
Channel
Selector
Buffer
AIO<br>