一、你可以说它是编译型的:因为所有的Java代码都是要编译的,.java不经过编译就什么用都没有。 二、你可以说它是解释型的:因为java代码编译后不能直接运行,它是解释运行在JVM上的,所以它是解释运行的,那也就算是解释的了。 三、但是,现在的JVM为了效率,都有一些JIT优化。它又会把.class的二进制代码编译为本地的代码直接运行,所以,又是编译的。
一、浅拷贝clone()
如果对象中的所有数据域都是数值或者基本类型,使用clone()即可满足需求,如:
Person p = new Person();
Person p1 = p.clone();
这样p和p1分别指向不同的对象。
二、深度拷贝
如果在对象中包含子对象的引用,拷贝的结果是使得两个域引用同一个对象,默认的拷贝是浅拷贝,没有拷贝包含在对象中的内部对象。
如果子对象是不可变的,如String,这没有什么问题;如果对象是可变的,必须重新定义clone方法;
三、序列化可克隆(深拷贝)
四、BeanUtils.copyProperties()
1、使用new关键字;
2、使用Class类的newInstance方法,可调用无参的构造函数创建对象;
3、使用Constructor类的newInstance方法;
4、使用clone方法;
5、使用反序列化。
使用final的意义:
为方法上锁,防止任何继承类改变它的本来含义和实现。设计程序时,若希望一个方法的行为在继承期间保持不变,而且不可被覆盖或改写,就可以采取这种做法。
提高程序执行的效率,将一个方法设成final后,编译器就可以把对那个方法的所有调用都置入嵌入调用里(内嵌机制)。
static总结
static修饰成员函数:该成员函数不能使用this对象
static不能修饰构造函数
static不能修饰函数参数
static不能修饰局部成员变量
static修饰成员字段
当类被虚拟机加载时,首先按照字段声明的先后顺序对static成员字段进行初始化
static修饰语句块
当类被虚拟机加载时,按照声明顺序先后初始化static成员字段和static语句块
static所修饰的方法和字段是只属于类,所有对象共享。
在static所修饰的函数和语句块中不能使用非static成员字段。
在Java不能直接定义全局变量,是通过static来实现的
在Java中没有const,不能直接定义常量,通过static final来实现
https://www.cnblogs.com/binarylei/p/10987540.html
& 按位与操作:只有对应的两个二进制数位1时,结果位才为1
1&1=1;
|按位或操作:有一个为1时,结果位就为1
1|0=1
&& ||短路运算符 在逻辑判断中常见
将一个数左移,相当于乘以2的n次方,位运算是cpu直接支持的,所以效率高
2 << 3
hashmap的初始容量 1<< 4 //16
直接二进制操作,表示1左移4,变成10000,转为10进制就是16
a= a+b;
b=a-b;
a=a-b;
a=a^b;
b=b^a;
a=a^b;
基础数据类型
byte short int long
float double char boolean
引用数据类型:其他引用类型
string和enum分别是什么类型:引用类型
int i=5
return i++; 5
return ++i; 6
基本数据类型 比较要用==判断是否相等
引用数据类型 == 比较的就是内存地址是否一样,不同对象的内存地址不一样,equals比较的是具体的内容
三者都是final不允许被继承 本质上都是通过char[]数组实现的 string stringbuffer与stringbuilder中,string是不可变对象。另外两个都是可变的
四大特性 - 抽象 - 声明的类叫抽象类,抽象方法(只有一个声明没有方法体) - 封装 - 让代码更容易理解和维护,加强了安全性 - 继承 - 具有公共的方法和属性 - 多态
进程是操作系统的基本单位,是操作系统结构的基础 线程是cpu调度的最小单位。
存储Thread的局部变量, 从而达到各个Thread之间的隔离运行。它被广泛应用于框架之间的用户资源隔离、事务隔离等。
ThreadLocal操作不当会引发内存泄露,最主要的原因在于它的内部类ThreadLocalMap中的Entry的设计。 Entry继承了WeakReference<ThreadLocal<?>>,即Entry的key是弱引用,所以key’会在垃圾回收的时候被回收掉, 而key对应的value则不会被回收, 这样会导致一种现象:key为null,value有值。 久而久之,value累加就会导致内存泄漏。
java提供了基于Executor构建线程池的方式 ThreadPoolExecutor 中
int corePoolSize, //核心线程数
int maximumPoolSize,//最大线程数
BlockingQueue<Runnable> workQueue,任务队列/阻塞队列(array数组,like链表,优先级,delay延迟)
long keepAliveTime, //生存时间
TimeUnit unit,//生存时间的单位
RejectedExecutionHandler handler//拒绝策略
ThreadFactory threadFactory //线程工厂的名称
线程池中一个属性,本质 就是int类型的数值,高三位描述线程池的状态,低29位,描述工作线程的数量,线程池在执行任务时,需要多次判断线程池状态,来确定任务是否需要执行,低29位,表述线程池中现存的工作线程数量。
running :线程池正在正常工作,可以处理提交的任务
shutdown:调用线程池的shutdown方法,不接受新的任务,但是会处理现有的任务
stop:调用线程池的shutNow(),不接受新的任务,中断正在处理的任务,不管工作队列
ttdying:过度状态,会从shutdown(工作队列和线程位空)和stop转换成ttdying状态,要停止,但是没停止
terminated:当线程池达到了ttdying状态后,在源码中,会自动调用,进入到了terminated状态。线程池就没了。
worker对象继承aqs实现runable,线程池执行任务,其实就是调用了worker种的run方法内部的runworker方法 线程池中的工作线程是用worker对象表述的 worker - true 核心线程 - false 最大线程数
其实是为了添加标识来判断当前工作线程,是否可以被打断。
保存在线程池的hashset里面。
线程池一共有 4个拒绝策略
befareExecute(前置钩子)-默认空实现
afterExecute(后置钩子)-默认空实现
在分配线程池容量大小时,必须要根据业务类型来决定。 cpu密集 - 更多的是cpu在计算,一直在工作 - 线程数少一些(推荐:cpu内核数+1) io密集 - 更多的时候线程在等待io - 线程数多一些(推荐:cpu内核数*2)
hashmap,arraylist linkedlist
CopyOnWriteArrayList Vector ConcurrentHashMap
就是 比较和交换 完了再改。
aqs其实是并发包juc下面的类,实现了一个先进先出的队列,底层就是一个双向链表。使用Node实现队列,利用int类型标识状态。在AQS类中有一个叫做state的成员变量,线程会首先尝试获取锁,如果失败就将当前线程及等待状态等信息包装成一个node节点加入到同步队列sync queue里,接着会不断的循环尝试获取锁。
独占方式。 共享方式。
ReentrantLock(重入锁)是lock接口的实现类,,悲观锁,底层是aqs
arrayli - 数组 arraylist.get()是根据index下标查询的,时间复杂度是(0)1。
创建空的数组 给elementData,初始化并且没有容量,采用懒加载的形式, 当使用add方法的时候, 首先判断是否需要扩容 - 如果等于空的时候,直接10的大小的数组 - ArrayList 每次扩容之后容量都会变为原来的 1.5 倍左右。 完了通过index负值。
会先判段是否越界直接根据下标查询
相同点都是基于数组实现的,默认的初始容量都是10
底层基于链表【双向】实现的。
不允许,比较hashcode值和equest值
内存泄漏,key一直占用内存,不被回收 如果使用hashmap,自定义key对象,一定要重写hashcode值和equals。
使用entry对象存放健值对
不需要考虑hash膨胀,但是查询很慢
初始化大小是16 同一个链表中存放的都是hashCode值可能相同,但是内容值却不同
初始化大小是16(1<<4),当数组容量大于等于64()并且链表长度大于8的时候,就会把链表转红黑树存储(红黑树的个数小于6的时候转为链表),hash碰撞以后,链表长度就回很长。hashmap通过长度n-1 余hash,降低hash冲突。如果hashmap中元素超过阈值的时候会通过0.75扩展因子扩容,
存放在0个位置
对于HashSet而言,它是基于HashMap实现的,HashSet底层使用HashMap来保存所有元素,因此HashSet 的实现比较简单,相关HashSet的操作,基本上都是直接调用底层HashMap的相关方法来完成。