基本类型
1byte = 8 bit
基本类型 | 大小(字节) | 取值范围 | 装箱基本类型 |
---|---|---|---|
byte(整) | 1 | -2^7 ~ 2^7-1 | Byte |
boolean(布尔) | 1 | true ~ false | Boolean |
short(整) | 2 | -2^15 ~ 2^15-1 | Short |
char(字符) | 2 | Character | |
float(浮点) | 4 | Float | |
int(整) | 4 | -2^31 ~ 2^31-1 | Integer |
double(浮点) | 8 | Double | |
long(整) | 8 | -2^63 ~ 2^63-1 | Long |
包装类–默认为null
基本类型 | 数值 | 包装类 |
---|---|---|
byte | 0 | Byte |
short | 0 | Short |
int | 0 | Integer |
long | 0 | Long |
float | 0.0 | Float |
double | 0.0 | Double |
char | 空格 | Character |
boolean | false | Boolean |
基本类型和包装类的区别
基本类型是 值,放在栈里,高效,值传递,
包装类是 对象,放在堆里,低效,引用传递
map,list及其变化类型全部放Object(对象)类型,也就是包装类,(String不是基本类型)
HashMap
,HashTable
,ConCurrentHashMap
,ArrayMap
,ArrayList
和LinkedList
(1)null key
HashMap支持null Key和null Value;HashTable不允许。这是因为HashMap对null进行了特殊处理,将null的hashCode值定为了0,从而将其存放在哈希表的第0个bucket。
(2)线程安全
HashMap是线程不安全,HashMap是非synchronized;HashTable是线程安全,ConCurrentHashMap安全
(3)默认长度
HashMap默认长度是16,扩容是原先的2倍负载因子(0.75,此时如果数组空间使用数>数组大小的0.75时会进行扩容,0.75的碰撞概率比较合适,空间换时间);
HashTable默认长度是11,扩容是原先的2n+1
(4)父类
HashMap继承AbstractMap;HashTable继承了Dictionary
(5)存储效率
HashMap为了提高计算效率,将哈希表的大小固定为了2的幂**,这样在取模预算时,不需要做除法,只需要做位运算。位运算比除法的效率要高很多。Hashtable在计算元素的位置时需要进行一次除法运算,而除法运算是比较耗时的。
比如说,我们有1000个元素new HashMap(1000), 但是理论上来讲new HashMap(1024)更合适,不过上面annegu已经说过,即使是1000,hashmap也自动会将其设置为1024。
但是new HashMap(1024)还不是更合适的,因为0.75*1000 < 1000, 也就是说为了让0.75 * size > 1000, 我们必须这样new HashMap(2048)才最合适,既考虑了&的问题,也避免了resize的问题。
(6)ConCurrentHashMap,
JDK1.7 采用Segment数组加锁–table–HashEntry
JDK1.8的实现已经抛弃了Segment分段锁机制,利用CAS+Synchronized来保证并发更新的安全。数据结构采用:数组+链表+红黑树。
java.util.concurrent包中借助CAS实现了区别于synchronouse同步锁的一种乐观锁,使用这些类在多核CPU的机器上会有比较好的性能.
CAS算法的过程是这样:它包含三个参数CAS(V,E,N)。V表示要更新的变量,E表示预期值,N表示新值。仅当V值等于E值时,才会将V的值设为N,如果V值和E值不同,则说明已经有其他线程做了更新,则当前线程什么都不做。
(1)存储方式
hashmap(数组+链表),ArrayMap(数组+数组)
(2) 扩容处理
hashmap(new,开销大),Arraymap(copy,效率高)
(3)ArrayMap有收缩功能,在clear和remove之后,会重新收缩数组,节约空间
(4)ArrayMap 采用二分法查找,比较慢,当你删除或者添加数据时,会对空间重新调整
(1)结构
ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
(2)访问
对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
(3)线程安全性
都不安全。
线程安全解决办法 :
方法1: Collections.synchronizedList(new LinkedList())
方法2: LinkedList和ArrayList换成线程安全的集合,如CopyOnWriteArrayList,ConcurrentLinkedQueue…
方法3:Vector(内部主要使用synchronized关键字实现同步)
List 和set都是Collection的子类
List, 有序,存储顺序等于取出顺序,可重复
set 无序 集合 值不重复,
子类:HashSet 和TreeSet
方法,判断hashcode在进行equals值判断
set.add,
set.delete,返回是否删除,没有值的话就返回false
set.has 判断有没有值
set.size,返回大小
set.foreach 遍历
map 地图(key–value)可以重复
Map是接口,Android中需要用他的子类
子类:HashMap、Hashtable(哈希地图),LinkedHashMap(链式哈希地图),TreeMap(树地图)、EnumMap(枚举地图)
map.add添加 map.add(“”,string/int/boolean…)
map.get("")
map.size
mao.has("")
map.set("","")添加重复的key的操作会更新原来的值
map.delete
String StringBuilder
和 StringBuffer
的作用和区别StringBuilder > StringBuffer > String
StringBuilder是线程不安全的,而StringBuffer是线程安全的
String为字符串常量,StringBuilder和StringBuffer均为字符串变量
总结一下
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
能修饰:变量,方法,类
修饰基本数据变量:不可改变
修饰引用类型变量:初始化后不会指向其他对象
修饰类:不能被继承,类中所有成员方法都是隐士的final
使用原因:1.锁定方法,防止继承修改其含义,2.内嵌调用,提升性能
(1)进程 : 一段程序的执行过程。
(2)进程状态 :就绪、运行和阻塞
(3)程序 : 指令和数据的有序集合
(4)线程 : 通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程可以利用进程所拥有的资源,在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统多个程序间并发执行的程度。
(5)多线程 : 在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理”。多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的。
(1)并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。其中两种并发关系分别是同步和互斥
(2)互斥:进程间相互排斥的使用临界资源的现象,就叫互斥。
同步:进程之间的关系不是相互排斥临界资源的关系,而是相互依赖的关系。进一步的说明:就是前一个进程的输出作为后一个进程的输入,当第一个进程没有输出时第二个进程必须等待。具有同步关系的一组并发进程相互发送的信息称为消息或事件。
(3)并行:并行是针对多处理器而言的。并行是同时发生的多个并发事件,具有并发的含义,但并发不一定并行,也亦是说并发事件之间不一定要同一时刻发生。
(4)异步:异步和同步是相对的,同步就是顺序执行,执行完一个再执行下一个,需要等待、协调运行。异步就是彼此独立,线程就是实现异步的一个方式。实现异步可以采用多线程技术或则交给另外的进程来处理。
(1)简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
(2)线程的划分尺度小于进程,使得多线程程序的并发性高。
(3)进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
(4)从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
(5)总结:线程执行开销小,但不利于资源的管理和保护;而进程正相反。同时,线程适合于在SMP(多核处理机)机器上运行,而进程则可以跨机器迁移。
(1)死锁的定义:多线程以及多进程改善了系统资源的利用率并提高了系统的处理能力。然而,并发执行也带来了新的问题——死锁。所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。
(2)如何避免死锁?
A. 分时调度: 所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。
B. 抢占式调度:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。
C. 在有些情况下死锁是可以避免的。三种用于避免死锁的技术:
C1. 加锁顺序(线程按照一定的顺序加锁)
C2. 加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)
C3. 死锁检测
synchronized具有同步功能,是一种互斥锁,锁的是对象,synchronized修饰普通方法时,锁对象是this对象。修饰静态方法时,锁对象是字节码文件对象。
synchronized可以用来修饰代码块和方法。
synchronized可以保证原子性,有序性,可见性。
synchronized的缺点:
1、synchronized底层是由jvm实现,因此不能手动控制锁的释放,不如lock锁灵活,synchronized修饰的方法一旦出现异常,jvm保证锁会被释放(lock锁需要在finally中释放)。
2、synchronized是非公平锁,不保证公平性。
原文链接:https://blog.csdn.net/ROAOR1/article/details/88845700
主内存就是硬件内存,本地内存是抽象内存:缓存,写缓存区,寄存器
用volatile修饰之后,本地内存可以达到互相可见,原理是会把本地内存刷新到主内存上。
作用于主内存(Main Memory):
lock,unlock,read(主–》工作,之后进行load),write(store之前的操作,工作–》主)
作用于工作内存:
load(read之后的操作,主–》工作的变量副本),use(工作–》执行),assign(执行–》工作变量),store(工作–》主,之后进行write)
https://blog.csdn.net/woainimax/article/details/75560973?ops_request_misc=%7B%22request%5Fid%22%3A%22158322800019724845059314%22%2C%22scm%22%3A%2220140713.130056874…%22%7D&request_id=158322800019724845059314&biz_id=0&utm_source=distribute.pc_search_result.none-task
原理:没有引用的对象,内存将变为垃圾
对象的回收:1.没有引用,引用为null,引用对象转移,2. 弱引用
方法区的垃圾回收:1. 废弃常量。2. 无用的类。
强制系统垃圾回收方式
5. System.gc();
6. Runtime.getRuntime().gc();
7. 备注:并不是立刻回收,也会做一些算法进行加权,使垃圾回收容易发生,提早发生,回收较多
finalize
是方法名,在Object类中定义,所以所有的类都继承了他
在垃圾回收机制清除内存前做必要的清理工作
只能运行一次
用于一些不容易控制,而且非常重要的资源释放
程序本身释放为主,finalize函数释放为辅,双保险管理
判定回收(jvm怎么确定哪些对象应该进行回收)
9. 引用计数,来判断一个对象是否可以被回收,但是循环指向就不会回收
10. 可达性分析,关系图,节点,引用链,判定是否可达
jvm会在什么时候进行回收
11. 会在cpu空闲的时候自动进行回收
12. 在堆内存存储满了之后
13. 主动调用System.gc()后尝试进行回收
垃圾回收算法(如何回收)–四个算法
14. Mark-Sweep(标记-清除)算法:最基础,容易实现,会产生大量的不连续内存
15. Copying(复制)算法:平均分为两块内存,只使用一块,然后用完之后把依旧存活的对象转移到另一块,原来区域清理。特点,简单不会产生碎片,但是牺牲内存
16. Mark-Compact(标记-整理)算法:在标记清除算法上添加了整理,使其没有内存碎片,
17. Generational Collection(分代收集)算法:目前大部分JVM的垃圾收集器采用的算法,核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域,一般情况下将堆区划分为老年代(Tenured Generation)和新生代(Young Generation)
新生代,频繁大量回收,通常使用时间占优的GC,需要复制的操作较少,所以Copying算法。
老年代,少量被回收,通常使用善于处理大空间的GC,因为老年代的空间大,GC频率低引用,使用Mark-Compact算法。
引用分为强引用、软引用、弱引用、虚引用4种,这4种引用强度依次减弱。
1、强引用
代码中普遍存在的类似"Object obj = new Object()"这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。
2、软引用
描述有些还有用但并非必需的对象。在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围,进行二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。Java中的类SoftReference表示软引用。(网站缓存)
3、弱引用
描述非必需对象。被弱引用关联的对象只能生存到下一次垃圾回收之前,垃圾收集器工作之后,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。Java中的类WeakReference表示弱引用。(handler内存泄露,bitmap缓存)
4、虚引用
这个引用存在的唯一目的就是在这个对象被收集器回收时收到一个系统通知,被虚引用关联的对象,和其生存时间完全没关系。Java中的类PhantomReference表示虚引用。
9.1、两者创建对象的方式不同,前者是实用类的加载机制,后者则是直接创建一个类:
9.2、newInstance创建类是这个类必须已经加载过且已经连接,new创建类是则不需要这个类加载过
9.3、newInstance: 弱类型(GC是回收对象的限制条件很低,容易被回收)、低效率、只能调用无参构造,new 强类型(GC不会自动回收,只有所有的指向对象的引用被移除是才会被回收,若对象生命周期已经结束,但引用没有被移除,经常会出现内存溢出)
public class Student {
private int id;
String name;
protected boolean sex;
public float score;
}
public class Get {
//获取反射机制三种方式
public static void main(String[] args) throws ClassNotFoundException {
//方式一(通过建立对象)
Student stu = new Student();
Class classobj1 = stu.getClass();
System.out.println(classobj1.getName());
//方式二(所在通过路径-相对路径)
Class classobj2 = Class.forName("fanshe.Student");
System.out.println(classobj2.getName());
//方式三(通过类名)
Class classobj3 = Student.class;
System.out.println(classobj3.getName());
}
}
作用是使一个类的实例能够将自身拷贝到另一个新的实例中
这里所说的“拷贝”拷的是对象实例,而不是类的定义,进一步说,拷贝的是一个类的实例中各字段的值。
(在开发过程中,拷贝实例是常见的一种操作,如果一个类中的字段较多,而我们又采用在客户端中逐字段复制的方
法进行拷贝操作的话,将不可避免的造成客户端代码繁杂冗长,而且也无法对类中的私有成员进行复制,而如果让需要
具备拷贝功能的类实现Cloneable接口,并重写clone()方法,就可以通过调用clone()方法的方式简洁地实现实例 拷贝功能)
浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。
深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象
1、 sleep 来自 Thread 类,和 wait 来自 Object 类。
2、最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
3、wait,notify和 notifyAll 只能在同步控制方法或者同步控制块里面使用,而 sleep 可以在任何地方使用(使用范围)
4、 sleep 必须捕获异常,而 wait , notify 和 notifyAll 不需要捕获异常
(1) sleep 方法属于 Thread 类中方法,表示让一个线程进入睡眠状态,等待一定的时间之后,自动醒来进入到可运行状态,不会马上进入运行状态,因为线程调度机制恢复线程的运行也需要时间,一个线程对象调用了 sleep方法之后,并不会释放他所持有的所有对象锁,所以也就不会影响其他进程对象的运行。但在 sleep 的过程中过程中有可能被其他对象调用它的 interrupt() ,产生 InterruptedException 异常,如果你的程序不捕获这个异常,线程就会异常终止,进入 TERMINATED 状态,如果你的程序捕获了这个异常,那么程序就会继续执行catch语句块(可能还有 finally 语句块)以及以后的代码。注意 sleep() 方法是一个静态方法,也就是说他只对当前对象有效,通过 t.sleep() 让t对象进入 sleep ,这样的做法是错误的,它只会是使当前线程被 sleep 而不是 t 线程
(2) wait 属于 Object 的成员方法,一旦一个对象调用了wait方法,必须要采用 notify() 和 notifyAll() 方法唤醒该进程;如果线程拥有某个或某些对象的同步锁,那么在调用了 wait() 后,这个线程就会释放它持有的所有同步资源,而不限于这个被调用了 wait() 方法的对象。 wait() 方法也同样会在wait 的过程中有可能被其他对象调用 interrupt() 方法而产生 。
https://www.iteye.com/blog/welcome66-2216572
JVM就是虚拟出来的计算机,有自己完善的架构,处理器,堆栈,寄存器,指令系统。使用jvm就是为了支持与操作系统无关,java跨平台的原理,因为java代码都在这上运行,.java文件通过javac命令编译后生成.class字节码文件,JVM的java解释器负责把.class字节码文件转化为特定的机器码文件运行。
设置守护线程:public final void setDaemon(boolean on)
判断守护线程:public final boolean isDaemon()
生命周期:
启动:启动java是开启,起点是public static void main
运行:main起点,两种线程:守护线程(JVM),非守护线程(JAVA),java也可以创建自己的守护线程
消亡:程序终止则退出,也可以用System.exit或Runtime类来退出
体系结构
类装载器(ClassLoader)–用来装载.class文件
执行引擎(执行字节码,执行本地文件)
运行时数据区(方法区,堆,java栈,PC寄存器,本地方法栈)
https://blog.csdn.net/poorcoder_/article/details/80258725
1 JVM整个类加载过程的步骤:
①.装载:二进制字节码加载到JVM,通过三个标识:类名,类所在的包名和ClassLoader实例ID
②.链接:1.对二进制字节码的格式进行校验,初始化装载类中的静态变量以及解析类中调用的接口、类; 2.完成校验后,初始化静态变量赋默认值;3.最后对所用的属性,方法进行验证,确保存在,具有应有的权限。
③.初始化
执行静态代码块,构造器代码,静态属性初始化,类变量(static)会分配在方法区中,而实例变量是会随着对象一起分配到Java堆中。
四纵情况会被触发执行:new,反射,子类调用初始化,jvm指定初始化类
4.2. JVM整个类加载顺序:
①java类装载器包括:启动类装载器(JVM的一部分) 和 用户自定义装载器(JAVA的一部分,必须是ClassLoader的子类)
②装载顺序:JVM启动时,由bootstrap 向User-Defined方向加载类;应用进行ClassLoader时,由User-Defined向Bootstrap方向查找并加载类
背景:判定两个类是否为同一个类,判定原则是是否由一个类加载器加载;所以导致多个类加载器可能会导致有多个不同的类,比如Object类如果有其他类加载器加载,就会导致有多个Object类,无法保证java的行为执行,会混乱。所以引入双亲委派:加载类的时候,先去让父类加载(顶层父类是启动类加载器,所以顶层都会走加载的方法)。如果父类不能加载,则传给子类加载,父子关系不是继承,而是组合(Composition)。带有优先级。
类加载器命名空间
不同的类加载器在虚拟机中处于不同的命名空间下,他们不可见
但是,例子:自己写的A类有AppClassLoader加载器加载,List由Bootstrap加载器加载,A访问List,先去自己的AppClassLoader,找不到,再去找父类,一直到顶层Bootstrap 找到List类
背景,可以对class文件进行加密和解密。
实现方式
重写findClass方法,
面试官:Java中是否可以覆盖(override)一个 private 或者是 static 的方法?
答:Java 中 static 方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而 static 方法是编译时静态绑定的。static 方法跟类的任何实例都不相关,所以概念上不适用。
Java 中也不可以覆盖 private 的方法,因为 private 修饰的变量和方法只能在当前类中使用,如果是其他的类继承当前类是不能访问到 private 变量或方法的,当然也不能覆盖。
4. RXjava
5. 切面编程,IOC,AOP
6. 注解模式
7. MVP,MVC,MVVM
8. 多态
重写式多态和重载式多态
多态,简而言之就是同一个行为具有多个不同表现形式或形态的能力。
多态的分类:运行时多态和编译时多态。
运行时多态的前提:继承(实现),重写,向上转型
9. 重载和重写
覆盖(Override)是指子类对父类方法的一种重写,只能比父类抛出更少的异常,访问权限不能比父类的小,被覆盖的方法不能是 private 的,否则只是在子类中重新定义了一个新方法。
重载(Overload)表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同。
面试官: 那么构成重载的条件有哪些?
答:参数类型不同、参数个数不同、参数顺序不同。
面试官: 函数的返回值不同可以构成重载吗?为什么?
答:不可以,因为 Java 中调用函数并不需要强制赋值。举例如下:
抽象类和接口
包装类
final,finally,finalize
回收机制,什么情况下回收,调用回收机制会全部回收吗?
!是逻辑取反,只涉及到0和非0(非0并没有统一的数值)
~是按位取反,就是数值写成2进制,然后0改成1,1改成0