Java学习记录
1、动态代理与反射
https://www.cnblogs.com/jacksontao/p/8552357.html
对于反射:讲的通俗一点的话就是,对于jvm来说,.java文件必须要先编译为.class文件才能够被jvm执行,所以在编译为.class文件的过程中,对象的类型都会被指定好,比如说 User user。那么如果说我想在代码运行的过程中获取到对象的类型呢?或者说程序在运行过程中如何载入一个特定的类呢?这就涉及到了java的反射机制了,反射提供了一套能够让我们在代码运行时也能获取到类型属性的方法。
而动态代理,利用java反射机制,动态的生成了一个代理类,直接调用代理方法即可。
2、int和Integer的区别
https://www.cnblogs.com/guodongdidi/p/6953217.html
自动装箱与自动拆箱
String a = “a”; String b = “a”; 这样定义的a和b指向的是字符串常量区变量,地址是一样的,即用equals为true,用" = = "也为true。
但是 String a =new String( “a”); String b = new String( “a”); 这样是定义了两个堆内存对象,只能equals,不能 " == "
(1)int与Integer、new Integer()进行= =比较时,结果永远为true
(2)Integer与new Integer()进行= =比较时,结果永远为false
(3)Integer与Integer进行==比较时,看范围;在大于等于-128小于等于127的范围内为true,在此范围外为false。
Java中的四类八种基本数据类型
第一类:整数类型 byte short int long
第二类:浮点型 float double
第三类:逻辑型 boolean(它只有两个值可取true false)
第四类:字符型 char
3、面向对象的四大特性
https://www.cnblogs.com/msn-z/p/7802576.html
4、数组、链表、红黑树
数组:
查询快: 数组的地址是连续的,通过首地址和索引可以快速查找某个元素
增删慢: 数组的长度是固定的,增删的时候其实是创建了一个新的数组,把仍然保存的元素复制到新数组中,原数组会在内存中被销毁(垃圾回收)
链表:
查询慢: 链表中的地址不是连续的,每次查询元素都必须从头开始查询
增删快: 链表的结构,增删某一元素对整体结构没有影响,所以增删快
链表还分为单向和双向,双向链表是有序的
红黑树:
5、List、Set、Collection、Map的区别和联系
https://blog.csdn.net/qq_44863974/article/details/95803762
https://blog.csdn.net/qq_36520235/article/details/82417949
Collection:Java.util下的一个接口,是各种集合结构的父接口,List和Set是继承自它的子接口,Collection是最基本的集合接口,Java SDK中不提供直接继承自Collection的类,而是提供继承自它子接口的类,如List和Set。所有的Collection类都支持一个Iterator()方法来遍历。
List:List接口是有序的,会精确的将元素插入到指定的位置(允许有相同元素)。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素。
ArrayList:List接口实现类,实现可变大小的数组,允许所有的元素,底层用数组实现,可以随机访问(访问效率高,插入和删除效率低),不是同步的,也就是没有同步方法,线程不安全。
LinkedList:List接口实现类,允许null元素,通常在首部或者尾部操作,所以常被使用做堆栈(Stack)、队列(Queue)和双向队列(Deque),底层用链表实现,插入删除效率高,访问效率低,不是同步的,也就是没有同步方法,线程不安全。
Vector:List接口实现类,类似于ArrayList,底层用数组实现,但Vector是同步的,线程安全(Stack继承自Vector)。
Set:是一种不包含重复元素的Collection接口,只关心元素是否属于Set(不允许有相同元素),而不关心它的顺序。
HashSet:Set接口实现类,不能有重复元素,底层使用HashMap实现,是为快速查找设计的Set,存入HashSet的对象必须定义HashCode()。
LinkedHashSet:继承自HashSet,具有HashSet的查询速度,底层使用链表实现(维护元素的插入次序),于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。
TreeSet:Set接口实现类,保存次序的Set,底层使用树结构实现,使用它可以从Set中提取有序的序列。
Map:是键值对映射集合,且为一一映射,键不能重复,值可以,所以是用键来索引值(即此接口实现Key到Value的映射,一个Map中不能包含相同的Key,但可以包含相同的Value,每个Key只能映射一个Value)。
HashTable:Map接口实现类,实现了一个Key-Value的哈希表,不能存储null值,每一个非null元素都可以作为Key或者Value,是同步的,也是线程安全的。
HashMap:可以存储null值,不是同步的,也不是线程安全的。
ConcurrentHashMap:线程安全。
JDK1.9以后(还没用过)List、Set、Map新增了一个静态方法of,但用of返回集合后就不能再添加新的元素,并且Set、Map不能有重复元素:
6、异常产生的过程解析
大致分成以下步骤:
1、JVM创建一个异常对象,里面包括异常产生的位置,异常内容,异常原因
2、在产生异常的方法中如果没有异常处理逻辑,就会把异常抛出到调用该方法的方法中,如果都没有异常处理逻辑,最后会抛出给JVM
3、JVM会把异常对象用红色字体打印在控制台,并终止当前正在进行的JAVA程序(中断处理)
7、try catch注意事项
1、如果有多个catch并且捕获的异常有子父类的关系,子类必须写在上面,否则会报错
2、如果finally中有return语句,运行时永远返回finally中的结果,避免该情况
3、子父类异常:
8、自定义异常:
9、多线程:
1、通过Thread扩展类实现多线程
public class MyThread extends Thread{
/*
这里面需要重写run方法
并且在main方法中new一个对象,调用该对象的start()方法
*/
}
2、通过Runnable接口实现多线程
public class RunnableImpl implements Runnable{
/*
这里面需要重写run方法
并且在main方法中new一个对象Runnable接口对象run
再new一个Thread类对象 Thread t = new Thread(run);
再调用t.start()方法
*/
}
3、实现Runnable接口创建多线程的好处:
4、通过匿名内部类实现线程创建:
匿名内部类的创建格式为: new 父类构造器(参数列表)|实现接口(){...}
使用匿名内部类时,必须继承一个类或实现一个接口
匿名内部类由于没有名字,因此不能定义构造函数
匿名内部类中不能含有静态成员变量和静态方法
示例:
//类中的main方法
public static void main(String[] args){
//1、用Thread
//线程的父类是Thread
new Thread(){
//重写run方法,设置线程任务
public void run(){...}.start();
}
//2、用Runnable接口
Runnable r = new Runnable(){
//重写run方法,设置线程任务
public void run(){...}.start();
}
new Thread(r).start();
//简化上面的方法,直接把 new... 传进去
new Thread(new Runnable(){
//重写run方法,设置线程任务
public void run(){...}.start();
}).start();
}
10、线程安全:
当同时有多个线程在执行时,如果不采取措施,很可能就会出现线程安全问题,解决线程安全问题有以下几种方法:
1、使用同步代码块
格式:
synchronized(锁对象){
可能会出现线程安全问题的代码(访问了共享资源的代码)
}
同步技术保证了只能有一个线程在同步中执行共享数据,保证了安全
但程序频繁的判断、获取、释放锁降低了程序执行的效率
2、使用同步方法
格式:
修饰符 synchronized 返回值 方法名(参数列表){
可能会出现线程安全问题的代码(访问了共享资源的代码)
}
3、使用Lock锁
Lock l = ...;
l.lock();
try { // access the resource protected by this lock }
...
finally { l.unlock(); }
当在不同范围内发生锁定和解锁时,必须注意确保在锁定时执行的所有代码由try-finally或try-catch保护,以确保在必要时释放锁。
11、等待与唤醒机制
void wait()
导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。
void wait(long timeout)
导致当前线程等待,直到另一个线程调用 notify()方法或该对象的 notifyAll()方法,或者指定的时间已过。
void notify()
唤醒正在等待对象监视器的单个线程。
void notifyAll()
唤醒正在等待对象监视器的所有线程。
多用于线程间的通信,使得多个线程可以符合我们的预期 有序的执行。
12、线程池
线程池:容器–>集合(ArrayList,Hashset,LinkedList,HashMap)
13、lambda表达式
面向对象思想:做一件事情,找一个可以做这个事情的对象,调用该对象的方法,完成事情
函数式编程思想:只要能获取到结果,谁去做的,怎么做的都不重要,重视结果 不看重过程
lambda标准格式:
lambda表达式省去了面向对象的条条框框,格式由3部分组成:
一些参数、一个箭头、一段代码
使用lambda表达式的前提:
14、File类
遍历目录:
15、递归
例1:
代码:
例2:
代码:
16、IO流
一个中文:GBK编码占用两个字节,UTF-8编码占用三个字节
字符输出流写入硬盘与字节输出流的一个区别是:
字节输出流直接使用write()方法把数据写入硬盘中
字符输出流使用write()方法是是把字符转换为字节,将字节写入内存缓冲区,需要再使用flush()方法 把内存缓冲区的数据刷新到文件中(colse方法使用时也会将内存缓冲区的数据刷新到文件中)
字节字符流的续写和换行:
在JDK7之前使用try catch处理流的异常:
JDK7的新特性:
JDK9的新特性: