记录一些Java知识点
- Java基础知识
- Java一次编译,到处运行
- Java特性
- Java创建对象的集中方式
- JAVA数据类型
- 数组
- String字符串
- 一些常见的比较
- Java中四种修饰符的区别
- Static,final作用
- Java集合
- 反射
- IO流
- 线程
Java基础知识
你好!这里是Java一些基础的知识点。
Java一次编译,到处运行
java是一门计算机程序设计语言,可以实现一次编译,到处运行,原理就是因为有JVM(Java虚拟机),Java程序编译成.class文件,运行在JVM里面,而JVM有针对不同系统(Windows,linux,mac)的特定实现,所以说,Java语言是跨平台的,而JVM不是:
Java特性
Java是面向对象的,面向对象有三大特征
- 继承 :子类继承父类;
- 封装:把该隐藏的隐藏,该暴露的暴露,比如类的私有方法,私有属性等,再比如把类封装成接口,只对外提供公有接口,隐藏具体的实现逻辑(如factory);
- 多态:事物的多种形态,比如方法的重载和重写;
- 用作: 我理解的这些都是为了提高程序的安全性,保护数据,隐藏底层实现逻辑,增强系统的可维护性等;
Java创建对象的集中方式
- 构造方法:调用类的构造方法(无参构造,有参构造),new对象;
- 反射方法: 通过反射获取对象,Class.forName(“类名”);
- clone方法: 使用克隆方法clone();
- 使用反序列化方法: 使用反序列化获取对象;
JAVA数据类型
Java数据类型分为两大类,基本数据类型和引用数据类型,基本数据类型分为四类八种
- byte:8位,范围: -2^7 - 2^7-1,默认值为0,包装类型为:Byte;
- short: 16位,范围:–2^15 - 2^15-1,默认值为0,包装类型为:Integer;
- int: 32位,范围:-2^31 - -2^31-1,默认值为0,包装类型为:Integer;
- long: 64位,范围:-2^63 - -2^63-1,默认值为0,包装类型为:Long;
- float:单精度,浮点型,默认值为0.0f,包装类型为:Float;
- double:双精度,默认值为0.0d,包装类型为:Double;
- char:字符型,char 为2个字节;
- boolean:布尔型,默认值为false,包装类为:Boolean;
数组
- 概述: 大小固定的(new的时候已经把数组的size确定好了),用来存放相同类型的元素;
- 一维数组:初始化方式int[] a = new int[10] / int[] a = {1,2,3,4,5},属性(a.length());
- 二维数组: int[][] a = new int[10][5];int[][] a = {1,2,3},{5,3,4,},{2,3,4};
String字符串
不可变的,底层是数组,使用final修饰的
- 创建: String str = “hellow” ,str引用的是静态区的字符串常量;String str = new String(“hellow”),str引用堆上的字符串对象;
- 一些常用方法: length(),charAt(),equals(),concat(),startWith(),endWith(),replace(),subString(),indexof(),trim(),replaceAll(),contains()等;
- StringBuffer,StringBuild
StringBuffer 线程安全,效率低(synchronize加锁,所以线程安全,效率低);
StringBuild 线程不安全,效率高(没有加锁,所以效率高,线程不安全);
一些常见的比较
- i++ 和 ++i
i++: i = i + 1,i先不加,等语句执行完之后再加1;
++i:i先加1,再执行语句;- equals 与 ==
比较基本数据类型时,两者意思一样,都是比较的值;
比较引用数据类型时,== 比较的是地址值(变量(栈)内存中存放的对象(堆)的内存地址),判断是否指向同一个地址,如果是,返回true,如果否,返回false,是真正意义上的指针操作;
equals比较的是两个对象的内容,equals底层源码用的也是==,所以一般需要重写equals方法(比如String类就重写了equals方法);
equals没有 == 运行速度快,因为equals比较的是内容,需要一个个字符比较,== 比较的是地址值- 方法的重写和重载
重写:方法名相同,返回值相同,参数类型和个数一样,子类重写父类的方法,运行时的多态;
重载:方法名相同,参数类型,参数顺序和个数不同,发生在同一个类中,编译时的多态;- 值传递和引用传递
值传递:形式参数为基本数据类型,传递的就是值;
引用传递:形式参数为引用数据类型,传递的是地址值;- &和&&
&:位运算符,也是逻辑运算;
&&: 逻辑运算符,短路与;- 接口和抽象类
接口可以多实现,类只能单继承;
接口里面只能有抽象方法,默认方法,静态方法,抽象类里面可以有具体的方法实现;
接口不能有构造方法,抽象类可以;
接口不能包含初始化块,抽象类可以;
Java中四种修饰符的区别
- 四中修饰符分别为:public,protect,default,private;
- 作用范围 (访问权限):
public 当前类,子类,同一个包,其他包;
protect 当前类,子类,同一个包;
default 当前类, 同一个包;
private 当前类;
Static,final作用
- 方便在没有创建对象的情况下 调用类的方法,变量;
- 调用规则
静态不能访问非静态,非静态可以访问静态;
static修饰方法,此方法为静态方法,不能被重写;
static修饰变量,此变量为静态成员变量,在类初始化的时候被加载,不能被更改(常量,不能再次被赋值);
static修饰类,此类不能被继承;
- final修饰词,表示不可更改的(比如String类)
final,finally ,finalize 区别
final:修饰词;
finally:捕获异常时,try-catch-finally 使用,finally里面的代码一定会执行,如果try里面代码和finally里面代码都有return,则返回finally里面的;
finalize:被GC回收的对象如果想再活一次,可以使用finalize关键字;
Java集合
- 链表: 一种链式存取的数据结构,链表中的数据是以节点的形式存在的
单链表:每个节点存放数据源+下一个节点的地址;
双向链表:每个节点存放数据源+上一个节点的地址+下一个节点的地址; - 链表和数组的区别
数组:存放在内存中的数据 空间地址是连续的,所以可以通过索引操作数组;
链表:存放在内存中的数据 空间地址是不连续的,无法直接根据索引查询元素; - 集合: 集合分为 Collect集合,Map集合
- 集合和数组的区别
集合:长度是可变的,存储的是对象,而且对象的类型可以不一致,有的集合可以存储null元素;
数组;长度是固定的,存的是基本数据类型值,存储的是同一类型的元素; - Collection集合
Collection集合有:List,Set,Queue - List集合
List集合分为:ArrayList,LIinkedList,Vector,常用的为ArrayList,可以有重复数据,如果需要确保List的线程安全,通常可以用synchronize;
ArrayList:底层为数组,增删慢,查询快(数组有索引,新增的时候得在最后加),效率高,线程不安全(查询没关系,增删的时候都是操作原Arraylist),可以存储多个null,初始值为10,每次扩容为原来的1.5倍
LinkedList:底层为链表,增删快,查询慢,效率高,线程不安全;
Vector:底层为数组,查询快,增删慢,效率低,线程安全;
- Set集合
Set集合分为: HashSet,sortSet,TreeSet,LinkedHashSet,常用的为HashSet;
HashSet:底层为HashMap,采用hashCode来确定key的位置,通过equals来比较元素是否相等,无序,不可重复,效率高,线程不安全,可以存储null元素,初始容量为16,默认扩容因子为 0.75,如果数据量大于 set容量*0.75,则扩容;
linkedHashSet:底层为双向链表 + hashCode,有序,不可重复,效率高,线程不安全;
TreeSet:底层为红黑树,有序不可重复,不能放null元素,支持两种排序方式,自然排序(实现comparable接口,通过comparable接口的compareTo()方法)和定制排序(通过Comparator接口)
HashSet性能最好,是最常用的Set,如果需要排序,那就用TreeSet,LinkedHashSet效率比HashSet低,如果要确保线程安全,通常可以用synchronize;
- Map集合
map集合分为:HashMap,HashTable,TreeMap,ConcurrentHashMap,以key-value方式存储数据;
HashMap: 底层为数组+链表+红黑树,不能重复,效率高,线程不安全;
jdk1.7 HashMap底层为数组+链表(单向链表);
jdk1.8 HashMap 底层为数组+链表(单向链表)+红黑树,即当数组长度<64且链表的长度>8时会树化,当树的node减少到6时会恢复成链表,当数组长度>64时,不会树化,会继续扩容;
可以有null值和null键;
扩容机制为: 初始大小为16,以2的次方来扩容;
可以通过synchronize来保证hashMap的线程安全,使用synchronize后锁的是整个map;
- put()方法:
(1):把key-value封装到节点node中;
(2):调用key的hashCode()获取key的hash值;
(3):把key的hash值转换成数组的下标,通过key的hash值来查找在数组中的位置,如果该位置没有任何元素,就把node添加到这个位置上,如果该位置有链表,则key跟链表上的每个节点的key对比,如果有相同的key,就把值覆盖,如果没有相同的key,则把这个key-value节点添加到链表的尾部,key的比较都是通过equals来比较的;
get()方法:
(1):通过key的hashCode方法获取key的hash值,并转换成数组下标;
(2):通过下标找到对应的数组位置,如果该位置上什么都没有,则返回null;
(3):如果该位置上有链表,则拿key跟链表上的每个节点的key进行equals比较,如果相等,则返回该key的value;
hashMap内部结构图: - put操作图:
- 扩容图:
- 树化图:
HashTable: 效率低,线程安全(类中的方法加了synchronize),不可以有null值null键;
LinkedHashMap: 底层为双向链表,维护了元素的插入顺序,迭代性能好;
TreeMap: 底层为红黑树(实现了sortMap接口),可以排序,有两种排序方式,自然排序和选择排序;
ConcurrentHashMap:效率高,线程安全,为了解决多线程下HahsMap线程不安全问题可以使用concurrentHashMaop; jdk1.7 为:Segment + HashEntry,使用segment作为ReentrantLoak重入锁,tryLoak()来控制线程安全,HashEntry存储键值对数据; jdk1.8 为:Node数组+链表+红黑树,使用synchronize + CAS来控制线程安全
反射
- 解释:动态获取对象信息和调用对象方法,即在任何状态下,对于任何一个类,我们都能通过反射机制来获取对象的信息,也可以通过反射调用这个类的方法和属性;
正常情况下,被private封装的资源只能类内部访问,但反射机制能直接操作类的私有属性,获取类的所有信息(包括成员变量,成员方法,构造器等),并且操纵类的字段,方法,构造器等部分。 - 反射API
通过 类名.class() 获取 对象的class;
Class clazz = Person.class;Class.forName(“类的全路径”),此方法 最安全,性能最好;
Class clazz = Class.forName(“类的全路径”);实例化一个类,然后通过getClass()方法;
Person person = new Person();
Class clazz = person.getClass();其他API
clazz.getPackage().getName();//获取包名;
clazz.getName();//获取类的完整类名;
clazz.getSimpleName();//获取类名;
getFields();//获取所有公开的成员变量,包括继承变量;
getDeclareFields();//获取本类定义的成员变量,不包括继承的变量;
getConstructors();//获取类的所有可见的方法,包括继承的方法;
getConstructor(参数类型列表);//获取本类定义的方法,不包括继承的方法;
getDeclaredMethods();//获取本类的所有定义方法,包括私有,但不包括继承的方法;
getDeclaredMethod(方法名,int.class,String.class);
//反射创建实例
clazz.newInstance();//通过类的无参构造创建对象;
clazz.setAccessible(true);//允许访问私有成员;反射应用
springIOC getBean(“user”) 底层就是通过反射机制来获取对象
IO流
- 分类:输入流,输出流,字节流,字符流,缓冲流;
输入流,输出流;
输入流只能读取数据,不能写入数据(把文件读取到内存中)InputStream,read()方法;
输出流只能写数据,不能读数据(把内存中的流输出到文件中)OutputStream,write()方法;
NIO
线程
- 线程和进程的区别
进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程(如后台进程);
线程是进程中的一条执行流程,是程序执行流的最小单元;
- 线程的五种状态
五种状态分别为:新建,就绪,运行,堵塞,死亡;
- 阻塞的三种情况
等待阻塞:运行的线程执行了wait()方法,在该状态下,线程是不会自动唤醒的,必须依靠其他线程调用nodify()或者nodifyAll()方法来唤醒;
同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被其他线程占用,则JVM会把该线程放入到"锁池"当中;
其他阻塞:运行的线程执行sleep()方法或者join()方法,或者发出I/O请求;
- sleep(),wait(),join() 方法解释
sleep()方法:为线程Thread的方法,执行sleep()方法之后,线程不会释放资源(执行sleep方法之后,该线程会主动让出CPU,等CPU执行完其他任务之后,又会回到该线程继续往下执行,即不释放资源);
wait()方法:Object类的方法,调用wait()方法之后,CPU会释放资源,等待其他线程执行完任务之后,执行nodify()方法,让执行了wait方法的线程重新进入等待状态,与其他线程一起争抢CPU资源;
join()方法:调用线程等待被调用线程执行完之后,继续往下执行(比如A,B,C三个线程,在B线程里面调用a线程的join方法,在C线程里面调用b线程的join方法,则线程执行顺序为:A-B-C);
- 线程的创建方式
继承thread类,重写run()方法,通过start()方法来启动线程;
实现runable接口,重写run()方法,通过start()方法来启动线程;
实现callable接口start() 方法和 run() 方法的区别:
start()方法:Thread类里面的方法,调用start方法启动一个线程,表示该线程处于就绪状态(线程还没有运行);
run()方法: 线程要执行的操作(线程具体干的事情);
- ThreadLocal
ThreadLocal叫做线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量相对于其他线程来说是隔离的,是当前线程独有的,ThreadLocal为变量在每个线程中都创建了一个副本,每个线程都是操作自己内部的副本变量;
ThreadLocal不存在多线程之间共享的问题;
ThreadLocal 变量通常被private static 修饰,当一个线程结束时,它所使用的的所有ThreadLocal相对的实例副本都可以被回收;
ThreadLocal类里面有个ThreadLoalMap,当ThreadLocal使用get/set方法时,会创建这个map(Entry),key为弱引用ThreadLocal对象,value为对应设置的Object对象;
ThreadLocal的remove方法直接是将ThreadlLocal对应的值从map中删除,为什么要删除,因为这里涉及到内存泄漏的问题(因为map中的key是弱引用,弱引用就是垃圾回收的时候一定会被清理,而map中的value是强引用,垃圾回收的时候不会被清理,这样就会出现 key为null的value,所以需要删除map中的value);
- synchronize作用
实现线程同步的同步锁;
乐观锁:线程独占锁(synchronize原始采用的锁);
悲观锁:每次不加锁,假设没有冲突则取完成某项操作,如果有冲突而失败就重试,一直到成功为止(lock采取的方式);synchronize 与 lock区别
synchronize:在完成方法或者出现异常之后会释放锁资源(CPU);
lock:只有在调用unlock() 方法才会释放锁,否则一直霸占锁,而且Lock接口可以通过很多方式来尝试获取锁;
- 线程池
维护管理线程的池子,一种线程使用模式(thread pool);
作用:降低线程创建的资源消耗,提高响应速度(不用再重新创建线程),提高线程的可管理性;
常用场景:多线程下跑定时任务,异步处理业务逻辑时,备份数据库时等等都可以使用到线程池(Tomcat内部采用的就是多线程);