知识点复习0701 java基础04
Java String类为什么是final的?
答:1.为了实现字符串池
2.为了线程安全
3.为了实现String可以创建HashCode不可变性
首先你要理解final的用途,在分析String为什么要用final修饰,final可以修饰类,方法和变量,并且被修饰的类或方法,被final修饰的类不能被继承,即它不能拥有自己的子类,被final修饰的方法不能被重写, final修饰的变量,无论是类属性、对象属性、形参还是局部变量,都需要进行初始化操作。
在了解final的用途后,在看String为什么要被final修饰:主要是为了”安全性“和”效率“的缘故
final也可以将数组本身改变的,这个时候,起作用的还有private,正是因为两者保证了String的不可变性。
那么为什么保证String不可变呢,因为只有当字符串是不可变的,字符串池才有可能实现。字符串池的实现可以在运行时节约很多heap空间,因为不同的字符串变量都指向池中的同一个字符串。但如果字符串是可变的,那么String interning将不能实现,因为这样的话,如果变量改变了它的值,那么其它指向这个值的变量的值也会一起改变。
如果字符串是可变的,那么会引起很严重的安全问题。譬如,数据库的用户名、密码都是以字符串的形式传入来获得数据库的连接,或者在socket编程中,主机名和端口都是以字符串的形式传入。因为字符串是不可变的,所以它的值是不可改变的,否则黑客们可以钻到空子,改变字符串指向的对象的值,造成安全漏洞。
因为字符串是不可变的,所以是多线程安全的,同一个字符串实例可以被多个线程共享。这样便不用因为线程安全问题而使用同步。字符串自己便是线程安全的。
因为字符串是不可变的,所以在它创建的时候HashCode就被缓存了,不需要重新计算。这就使得字符串很适合作为Map中的键,字符串的处理速度要快过其它的键对象。这就是HashMap中的键往往都使用字符串。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
反射中Class.forName()和ClassLoader.loadClass()的区别
根据运行结果得出Class.forName加载类是将类进了初始化,而ClassLoader的loadClass并没有对类进行初始化,只是把类加载到了虚拟机中。
应用场景:
Spring框架中的IOC的实现就是使用的ClassLoader。
在使用JDBC驱动的时候,通常是使用Class.ForName()方法来加载数据库连接驱动。只是因为在JDBC规范中明确要求Driver(数据库驱动)向Drivermanger中注册自己。
1. 类加载:Bootstrap Loader ——》Extended Loader——》System Loader
2. 静态代码块初始化
3. 链接:
a) 验证:是否符合java规范
b) 准备:默认初始值
c) 解析:符号引用转为直接引用,解析地址
4. 初始化
a) 赋值:java代码中的初始值
b) 构造:构造函数
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
java线程启动线程有两种方式:Thread、Runnable两种方式
在Java线程当中,线程通常都有五种状态,新建(创建)、就绪、运行、阻塞和死亡。
1、新建状态。在生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态。
2、就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。
3、运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码。
4、阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞。
5、死亡状态。如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪。
然而:run()方法:在本线程内调用该Runnable对象的run()方法,可以重复多次调用, start()方法:启动一个线程,调用该Runnable对象的run()方法,不能多次启动一个线程。
换句话说:start()是告诉线程准备完毕,可以运行了,然后run()就是运行状态方法,当thread.start()的时候会走thread(new Runnable(){public void run(){})异步去调用,但thread.run()方式可以直接调用匿名内部类run(),不需要start();
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Java-五种线程池,四种拒绝策略,三种阻塞队列
三种阻塞队列:
BlockingQueue<Runnable> workQueue = null;
workQueue = new ArrayBlockingQueue<>(5);//基于数组的先进先出队列,有界
workQueue = new LinkedBlockingQueue<>();//基于链表的先进先出队列,无界
workQueue = new SynchronousQueue<>();//无缓冲的等待队列,无界
四种拒绝策略:
RejectedExecutionHandler rejected = null;
rejected = new ThreadPoolExecutor.AbortPolicy();//默认,队列满了丢任务抛出异常
rejected = new ThreadPoolExecutor.DiscardPolicy();//队列满了丢任务不异常
rejected = new ThreadPoolExecutor.DiscardOldestPolicy();//将最早进入队列的任务删,之后再尝试加入队列
rejected = new ThreadPoolExecutor.CallerRunsPolicy();//如果添加到线程池失败,那么主线程会自己去执行该任务
五种线程池:
ExecutorService threadPool = null;
threadPool = Executors.newCachedThreadPool();//有缓冲的线程池,线程数 JVM 控制
threadPool = Executors.newFixedThreadPool(3);//固定大小的线程池
threadPool = Executors.newScheduledThreadPool(2);
threadPool = Executors.newSingleThreadExecutor();//单线程的线程池,只有一个线程在工作
threadPool = new ThreadPoolExecutor();//默认线程池,可控制参数比较多
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 总结
- LinkedHashMap是继承于HashMap,是基于HashMap和双向链表来实现的。
- HashMap无序;LinkedHashMap有序,可分为插入顺序和访问顺序两种。如果是访问顺序,那put和get操作已存在的Entry时,都会把Entry移动到双向链表的表尾(其实是先删除再插入)。
- LinkedHashMap存取数据,还是跟HashMap一样使用的Entry[]的方式,双向链表只是为了保证顺序。
- LinkedHashMap是线程不安全的。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
反射机制:
所谓的反射机制就是java语言在运行时拥有一项自观的能力。通过这种能力可以彻底的了解自身的情况为下一步的动作做准备。下面具体介绍一下java的反射机制。这里你将颠覆原来对java的理解。 Java的反射机制的实现要借助于4个类:class,Constructor,Field,Method;其中class代表的时类对 象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象。通过这四个对象我们可以粗略的看到一个类的各个组 成部分。
Java反射之类的实例对象的三种表示方式