1.整数类型:byte、short、int、long(默认类型是int、其余需要强转)
2.浮点数类型:float、double(默认类型是double,如果是float类型后面需要写F)
3.字符类型:char(默认值为空,字符类型用单引号表示字符)
4.布尔类型:boolean(默认值false true、false这两个不是关键字)
JDK : 开发工具包
JRE : 运行时环境
JVM : java虚拟机
&:符号的左右两边,无论真或假都要执行
&&:符号的左边如果为假,符号的右边不再执行,提高了代码的执行效率
int及以下整数包含 字符 char byte short int char String 枚举
访问修饰符 |
当前类 |
同一包下其他类 |
其它包内子类 |
其它包内非子类 |
private |
可以访问 |
|||
default(默认的修饰符) |
可以访问 |
可以访问 |
||
protected |
可以访问 |
可以访问 |
可以访问 |
|
public |
可以访问 |
可以访问 |
可以访问 |
可以访问 |
面向对象即OOP是一种编程思想,对象在我们生活中处处都存在,比如说一只小狗就是一个对象,在面向对象编程中,对象是有很多特征的,比如说品种、颜色、体型等等都是对象的属性,对象还会有一些能力,比如跑、跳、打滚,这就可以理解成对象所封装的方法,简单来说就是将功能封装到对象里,我们面向对象,让对象去完成这些功能,在java中万物皆对象
封装:将不同的功能抽取出来方便调用,减少大量代码的冗余
继承:减少了类的冗余代码,让子父类之间产生关系,为多态打下基础
多态:一个接口,多个方法。通过继承实现不同的对象调用相同的方法,进而有不同的行为
接口 |
抽象类 |
不能定义构造器 |
可以定义构造器 |
接口中所有成员都是public static final |
可以有抽象方法和具体方法 |
成员变量都是常量 |
抽象类中的成员可以是任何类型 |
接口可以多继承 |
类只能单继承 |
注意点:
抽象类如果是内部类可以使用static ,外部类不行
抽象类不能使用final修饰,因为使用后就不能被继承了,就失去了抽象类存在的意义了
注:抽象类中不一定有抽象方法,有抽象方法这个类一定是一个抽象类
成员变量: 类中方法外
局部变量: 方法中或方法定义的小括号里面
成员变量: 在堆内存中
局部变量: 在栈内存中
成员变量: 随着对象创建而产生,随着对象的消失而消失
局部变量: 随着方法的调用而产生,随着方法调用结束而消失
成员变量: 有默认值, 整数0,小数0.0 字符 ‘\u0000’ 布尔 false 引用数据类型 null
局部变量: 没有默认值,使用的时候,必须先赋值
1、修饰成员变量:叫静态变量 具有共享性,节省内存空间
2、修饰方法:静态方法: 可以直接使用类名.进行调用,
3、修饰代码块:静态代码块 ,给静态变量进行赋值
4、修饰类:静态内部类
this |
super |
可以区分成员变量与局部变量重名问题,如果本类没有这个成员变量,也可以调用父类的成员变量 |
可以区分本类成员变量与父类成员变量重名问题,只能调用父类的成员变量 |
可以调用本类的成员方法,如果本类没有这个成员方法,也可以调用父类的成员方法 |
只能调用父类的成员方法 |
可以通过this() 或 this(参数) 让其本类的构造方法直接相互调用 |
子类通过super() 或 super(参数) 调用父类的构造方法 |
抽象类:描述现实中具体的事务可以使用抽象类
接口:描述某些行为特征时可以使用接口
普通类 |
抽象类 |
不能包含抽象方法 |
可以包含抽象方法 |
能直接实例化(new) |
不能直接实例化(需要继承重写抽象方法) |
静态变量:被static修饰符修饰的变量,也被称为类变量,它是属于类的,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个拷贝
实例变量:必须依存于某一个实例,需要先创建对象然后通过对象才能访问到它。实例变量可以实现让多个对象共享内存
重写:发生在子类和父类之间,当子类继承父类时,子类中的方法与父类方法的名称,参数个数,参数类型完全一致时,称为子类重写父类方法,子类的访问修饰符必须大于等于父类的访问修饰符
重载:一个类中的多个方法的方法名称相同,参数个数或者形参类型不同,则称为方法重载,与返回值是无关的
补充:
1.final修饰的不能重写,但是能重载
2.无论重载重写,必须保证方法名相同
构造器Constructor是不能被继承的,因此不能被重写Overriding,但可以被重载Overloading
public 类名(){}
补充:
1、构造函数是不能被继承的,构造方法只能被隐式调用
2、构造函数是不能有返回值类型的
序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。
序 列 化 的 实 现 : 将 需 要 被 序 列 化 的 类 实 现 Serializable 接 口 , 该 接 口 没 有 需 要 实 现 的 方 法 , implements Serializable 只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用 ObjectOutputStream 对象的 writeObject(Object obj)方法就可以将参数为 obj 的对象写出(即保存其状态),要恢复的话则用输入流。
基本数据类型 |
包装类 |
short |
Short |
int |
Interger |
byte |
Byte |
long |
Long |
char |
Character |
double |
Double |
float |
Float |
boolean |
Boolean |
初始值不同:基本数据类型初始值int为0,boolean为false,double为0.0,包装类型的默认值都为null
使用方式不同:基本数据类型不能用于泛型,包装类可以作用于泛型
1、所有的POJO类属性必须使用包装数据类型
2、所有RPC方法的返回值和参数必须使用包装数据类型
3、所有的局部变量使用基本数据类型
说明:
POJO类属性没有初始值是提醒使用者在需要使用时,必须自己显示地进行赋值,任何NPE(NullPointerException)问题,或者入库检查,都由使用者来保证
数据查询的结果可能是null,因为自动拆箱,用基本数据类型接收有NPE风险
装箱:将基本类型转换成引用类型的过程叫做装箱(将栈中的基本数据类型放到堆里面去从而转换成一个引用类型)
int i1 =1; Integer i2 = new Integer(i1);
自动装箱
int t =11; Integer t2 =t;
拆箱:将包装类型转换成引用数据类型的过程叫拆箱(将栈中的基本数据类型放到堆里面去从而转换成一个引用类型)
Integer i=new Integer(1); int i2=i.intValue();
自动拆箱
int t =11; Integer t2 =t; int t3 =t2.intValue();
方法介绍:
intValue()是吧Integer对象类型变成int的基本数据类型
parseInt()是吧String转化成int类型
Valueof()是把String转化成Integer类型
String:不可变字符序列,底层是一个数组不可扩容
StringBuffer、StringBuilder:可变字符序列,底层是可扩容的数组,底层会有一个value 和 count,当需要追加数据时,底层的数组长度不够时,它会再创建一个扩容后的新数组,然后将原来的数据复制过去,然后再在新数组后面追加
StringBuffer:是JDK1.0的时候的,线程安全
StringBuilder:是JDK1.5的时候的,线程不安全
三者的效率区别:StringBuilder>StringBuffer>String
.equals() 比较
.substring() 截取
.length() 长度
.indexOf() 查找位置
.toUpperCase() 大写
......
equals()和==最大的区别一个是方法,一个是运算符
==:如果对象是基本数据类型,则比较的是数值是否相等;
如果是引用数据类型,比较的则是对象的地址值是否相等
equals():用来比较方法两个对象的内容是否相等
ArrayIndexOutOfBoundsException 数组下标越界
NullPointerException 空指针异常
ClassCastException 类转换异常
SQLException SQL异常
IllegalArgumentException 方法传参错误
try{
可能出现异常的代码
}catch{
捕获到的异常与catch中的异常类型进行匹配,执行里面的逻辑 可能有多重判断
}finally{
进行资源的关闭
}
1、在方法体内,表示抛出异常,由方法体内的语句处理
2、是具体向外抛出异常的动作,所以它抛出的是一个异常实例,执行 throw 一定是抛出了某种异常。
1、在方法签名后面,表示如果抛出异常,由该方法的调用者来进行异常处理
2、主要是声明这个方法会抛出某种类型的异常,让它的使用者要知道需要捕获的异常的类型
3、表示出现异常的一种可能性,并不一定会发生这种异常。
final:用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可被继承
finally:异常处理语句结构的一部分,表示不管抛不拋异常都执行
finalize:Object 类的一个方法,在垃圾回收器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。该方法无需我们调用
输入流,输出流
字节流,字符流
字符流 |
字节流 |
|
输入流 |
Reader |
inputStream |
输出流 |
writer |
outputStream |
节点流:可以直接从数据源或目的地读写数据,如FileInputStream、FileReader、DataInputStream等。
处理流:不直接连接到数据源或目的地,是”处理流的流”。通过对其他流的处理提高程序的性能,如BufferedInputStream、BufferedReader等。处理流也叫包装流。
1、字节流处理的数据类型:图片、MP3、视频文件、文本数据
2、字符流处理的数据类型:纯文本数据
3、如果是文本数据优先选择字符流,除此之外都是字节流
1、字节流主要操作的数据类型是byte类型数据,以byte数组为准
2、字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符、字符数组或字符串
3、字节流处理单元为 1 个字节,操作字节和字节数组
数组 |
集合 |
数组的大小在创建之初就规定了,后面不能更改 |
集合的大小是不固定的,底层会自动扩容 |
数组存放的类型在创建是就规定了,只能有一种 |
集合在不添加泛型时数据类型并不是一种,是Object类型 |
Set:Set继承Collection 集合 无序,不可重复的,元素进入集合的顺序是没有先后差别的
Queue:Queue继承Collection
List:List继承Cillection 有序的序列,允许插入重复的数据
1、Vector、Hashtable
2、核心代码使用synchronized修饰符
1、ArrayList、HashMap
2、线程不安全但是性能好,用来替代第一代
3、要变成线程安全,使用工具类Conllections,底层也是使用synchronized代码块锁,但是相比第一代性能稍有提升
1、List和Set都是继承Collection 接口的集合,是存储单列元素的集合,Map是存储k-v键值对双列数据的集合
2、List中存储的数据有序,允许重复 ;Set中存储的数据无序,不允许重复,但是元素的位置是由元素的hashCode决定的
Map接口 使用键值对存储(k-v),不能有重复的key,value可以重复,键要保证唯一性,键和值存在映射关系
集合名 |
存值 |
数据结构 |
使用 |
Hashtable |
不可以存入null键,null值 |
哈希表 |
如果需要保证键的唯一性需要覆写hashCode方法,和equals方法 |
HashMap |
允许null值和null键 |
JDK1.7 数组+链表 JDK1.8 数组+链表+红黑树 |
|
LinkedHashMap |
允许null值和null键 |
哈希表+双向链表 |
如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现 |
TreeMap |
key不可以为null,值可以为null |
红黑树 |
能够把它保存的记录根据键排序,默认是键值的升序排序 |
Map不能直接遍历,想要遍历有两种间接的方式
将map中的key 取出来,存到set集合里面,之后遍历set集合,通过map中的 get(key key) 方法取出每一个value值
将map中的key 和 value 存到 map的内部类 entry中,之后将entry对象存到set集合里面,之后通过遍历set集合,通过entry内部类中的 getKey, 和 getValue 获取每一个值
TreeSet
TreeSet底层实际使用的存储容器是TreeMap
对于TreeMap而言,它采用一种被称为红黑树的排序二叉树来保存Map中的每个Entry,每个Entry被当成红黑树的一个节点来对待
总结:
实现TreeMap
具有排序功能,有序
TreeSet中的元素必须实现comparable接口并重写compareTo(),TreeSet判断元素是否重复,以及确定元素的顺序,靠的就是这个方法
HashSet
HashSet的实现原理,封装了一个HashMap对象来存储所有的集合元素,不允许集合中有重复
的值,使用该方式时需要重写 equals()和 hashCode()方法
总结:
实现HashMap
没有排序功能,无序
重写 equals()和 hashCode()方法保证数据唯一性
根本区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位
1、一个进程可以包含多个线程
2、进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃,整个进程都死掉,所以多进程要比多线程健壮
接口/类 |
方法体 |
介绍 |
exteds Thread类 |
run() |
|
implement Runnable接口 |
run() |
|
implement callable接口 |
call() |
方法有返回值,能够抛出异常 |
新建:new创建一个线程
就绪:.start()后,该线程处于就绪状态,只是表示可以运行,等待jvm调用
运行:线程获得cpu开始执行run()方法体
阻塞:如果其他线程抢占CPU就会阻塞,或者调用sleep()
死亡:run()、call()执行完毕,线程正常结束,或者是抛出异常、调用stop()但是容易死锁
创建线程整个过程的浪费是比较大的,而线程池的意义在于先创建线程需要的数据,当要用的时候直接去线程池中取出线程,这样节省了创建连接和关闭资源的开销
ExecutorService executorService=new ThreadPoolExecutor(
3,//核心线程数
6,//最大线程数
1L,//存活时间(多余的空闲线程的存活时间)
TimeUnit.SECONDS,//时间单位(线程池维护线程所允许的空闲时间的单位)
new ArrayBlockingQueue<>(3),//任务队列
Executors.defaultThreadFactory(),//线程工厂
new ThreadPoolExecutor.AbortPolicy());//拒绝策略
任务队列:任务队列是基于阻塞队列实现的,即采用生产者消费者模式
AbortPolicy(默认):丢弃任务并抛出 RejectedExecutionException 异常。
CallerRunsPolicy:由调用线程处理该任务。
DiscardPolicy:丢弃任务,但是不抛出异常。可以配合这种模式进行自定义的处理方式。
DiscardOldestPolicy:丢弃队列最早的未处理任务,然后重新尝试执行任务。
通过Exeutors(jdk1.5)提供的四种线程池
名称 |
||
可缓存线程池 |
newCachedThreadPool |
如果线程池长度超过处理需要,可以灵活的回收线程,若无可回收,则新建线程 |
定长线程池 |
newFixedThreadPool |
可控制线程最大并发数,超出的线程会在队列中等待 |
定长线程池,定时 |
newScheduledThreadPool |
支持定时及周期任务执行 |
单线程化的线程池 |
newSingleThreadExecutor |
它会用唯一的工作线程来执行任务,保证所有的任务按照指定顺序执行 |
1、Lock是接口,synchronized是关键字
2、Lock可以选择性的获取锁,如果一段时间获取不到,可以放弃。Synchronized会一直获取,借助这个特性可以规避死锁
3、synchronized在发生异常和同步代码块结束的时候,会自动释放锁,Lock必须手动释放,所以如果忘记释放锁,也会造成死锁
1.对象锁钥匙只能有一把才能互斥,才能保证共享变量的唯一性
2.在静态方法上的锁,和实例方法上的锁,默认不是同样的,如果同步需要制定两把锁一样。
static synchronized是类锁
synchronized是对象锁
若类对象被lock,则类对象的所有同步方法(static synchronized func)全被lock。
若实例对象被lock,则该实例对象的所有同步方法(synchronized func)全被lock。
同步块(或方法)和volatile变量
互斥和可见性
volatile关键字是一种轻量级的同步机制,只保证数据的可见性,而不保证数据的原子性。
非原子操作都会存在线程安全问题,需要我们使用同步技术(sychronized)来让它变成一个原子操作
synchronized 是由“一个变量在同一个时刻只允许一条线程对其进行 lock 操作”这条规则获得的,此规则决定了持有同一个对象锁的两个同步块只能串行执行
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
在传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁、写锁等,都是在操作之前先上锁(效率低)
在数据上会为其加一个版本号,在操作后数据版本号会更新,如果使用数据版本号不一致,后面就不能操作了,乐观锁适用于多读的应用类型,这样可以提高吞吐量。
List接口是Collection接口的子接口定义一个允许重复项的有序集合,可以动态的增长,最重要的是它保证维护元素特定的顺序
ArrayList 优点是随机访问元素,但插入和删除速度很慢
LinkedList 对顺序访问进行了优化,插入和删除的开销并不大,随机访问则相对较慢
是指在多线程环境下,每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的
反射就是在程序运行时期,动态的获取类中成员信息(构造方法,成员变量,成员方法)的过程
所谓的反射机制就是java语言在运行时拥有一项直观的能力。通过这种能力可以彻底地了解自身的情况为下一步的动作做准备。
Java的反射机制的实现要借助于4个类:Class,Constructor,Field,Method;
其中Class代表的是类对 象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象。通过这四个对象我们可以粗略地看到一个类的各个组 成部分。
在Java运行时环境中,对于任意一个类,可以知道这个类有哪些属性和方法。对于任意一个对象,可以调用它的任意一个方法。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射(Reflection)机制。
在运行时判断任意一个对象所属的类。
在运行时构造任意一个类的对象。
在运行时判断任意一个类所具有的成员变量和方法。
在运行时调用任意一个对象的方法
sleep方法是Thread类的静态方法
调用sleep方法可以让当前正在运行的线程进入睡眠状态,即暂时停止运行指定的单位时间。并且该线程在睡眠期间不会释放对象锁。
wait是Object提供的一个方法
调用wait方法可以让当前线程进入等待唤醒状态,并释放锁。该线程会处于等待唤醒状态直到另一个线程调用了object对象的notify方法或者notifyAll方法。
notify也是Object提供的一个方法
当其它线程调用该对象的notifyAll()方法(唤醒所有wait线程)或notify()方法(只随机唤醒一个wait线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去公平竞争该对象锁。