Java基础知识积累


【最后都落脚在内存中,着眼于内存的角度去分析】

JVM

  • synchronized ˈsɪŋkrənaɪzd和 volatile(直接操作内存别优化) 的区别:前者保证可见性和原子性,后者只保证可见性
    volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
    volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。
    volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性。
    volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
    volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。

  • StackOverflowError:线程请求的栈深度大于虚拟机所允许的深度。 OutOfMemoryError:虚拟机在动态扩展栈时无法申请到足够的内存空间

  • JVM是基于栈的(Android的JVM是基于寄存器的),优缺点在可移植性和执行速度

JMM

JMM在设计层面包括

  • 堆区(只存放对象实例,即new出来的)【只要是new的实例都在堆区,其引用变量都在线程区栈中,如:对象、数组,其声明】
  • 静态区又叫方法区(存放常量,全局变量,类型即class的结构)【存放永远只有一份儿的数据】
  • 线程区:程序计数器,虚拟机栈(局部变量,对象的引用变量),本地方法栈(native调用,C实现)

【一言蔽之:new出来的放堆里,声明的放栈里,static出来的放静态区】

  • GC发生在堆区
  • 对象诞生即新生代,在进行minor gc过程中,如果依旧存活,移动到from,变成Survivor,进行标记代数,如此检查一定次数后,晋升为老年代。

计算机系统对一块内存的使用分为四个区:

  • 栈区(stack segment):存放函数参数和局部变量;
  • 堆区(heap segment):存放全局变量和malloc;
  • 数据区(data segment):存放static、常量;
  • 代码区(code segment):存放执行代码;

数据区+代码区对应JMM中的静态区

JMM在虚拟机与物理机层面包括
主内存、工作内存,每条线程拥有各自的工作内存,工作内存中的变量是主内存中的一份拷贝。主内存中的变量需要通过工作内存来间接操作。有8个原子操作:主内存(lock上锁,unlock解锁,read读取,write写入),工作内存(use使用,assign复制,load载入,save存储)。变量–工作内存(use,assign)–主内存(read,write)

  • 主内存并非堆区,工作内存也非栈区

GC(Garbage Collection)原理

  • JAVA GC采用了分代思想,将java堆分成新生代,年老代。
  • 区满时才触发一次gc

新生代

  • 分为1个Eden(伊甸园)区和2个Survivor(幸存者)区(交替作为from和to区)。
  • 当创建对象,需要jvm分配内存时,会在新生代的eden区寻找合适的内存区域。
  • 当eden区内存满时,会触发minor GC(年龄+1)。未引用的对象被清除,eden区的存活对象和from区的存活对象将会被复制to区。对象会在两个Survivor区来回游荡,当对象年龄超过了晋升的年龄设置,对象将被提升到老年代。【新生代GC用的是复制算法

老年代

  • 年老代里存放的都是存活时间较久的,大小较大的对象。
  • 年老代内存满时,会触发一次Major GC(full GC),回收年老代和年轻代中不再被使用的对象资源。【年老代算法用的是标记-清除-整理

为什么要分代:绝大多数的对象存活时间都比较短,且标记-清除算法花费时间比较长

  • GC调优:

GC调优一般具体是通过GC日志的情况来分析。基本上发现minor gc频繁,新生代空间太小了。如果发现晋升的年龄很小,老年代迅速被填满,导致频繁的major gc,并且回收比率又很大,那说明对象的生命周期确实很短也需要调整新生代。如果看full gc很频繁,但是每次回收的内存就一点点,那目测就是内存泄露了。总体上就是根据分代的根本,也就是新生代朝生夕死的事实调整GC,避免分配大对象。具体还是得分析GC日志。

数据类型

  • 基本数据类型:数字型(整数型(byte,short,int,long),浮点型(float,double)),字符型(char),布尔型(boolean)【其实按所占空间记忆更舒服:bool,byte,char,short,int,long,float,double】

  • final修饰的事物不可更改。类不可被继承,方法不可被重写,变量不可被改变

  • 修饰符 public、private、protected、default 在应用设计中的作用

作用域当前类package内子类package外
public
protected×
default××
private×××

关于String

  • String是final类,所以不能被继承和修改

  • 由char数组实现,最大长度为Integer.MAX_VALUE,线程安全

  • StringBuffer的很多方法用(写操作)synchronized修饰,所以线程安全,StringBuilder没有这个限制

  • String 类的常用方法
    indexOf():返回指定字符的索引。
    charAt():返回指定索引处的字符。
    replace():字符串替换。
    trim():去除字符串两端空白。
    split():分割字符串,返回一个分割后的字符串数组。
    getBytes():返回字符串的 byte 类型数组。
    length():返回字符串长度。
    toLowerCase():将字符串转成小写字母。
    toUpperCase():将字符串转成大写字符。
    substring():截取字符串。
    equals():字符串比较。

  • 基本类型和String互转:parseXXX(String)或valueOf(String)

OO三大特性【依靠JMM的堆区和方法区实现】

  • 多态:对象(父类引用子类的多态)、方法(重写和重载)。【实现多态的三种方式:父对子的引用,重写和重载方法】

  • 封装:将方法和属性打包进类,隐藏细节

  • 继承:

  • 面向对象的六原则:

    • 单一职责原则:一个类只做它该做的事情。【高内聚、低耦合】
    • 开闭原则:软件实体应当对扩展开放,对修改关闭。【宜新增、忌修改】
    • 依赖倒转原则:面向接口编程。
    • 里氏替换原则:任何时候都可以用子类型替换掉父类型。【子可替父】
    • 接口隔离原则:接口要小而专,绝不能大而全。
    • 合成聚合复用原则:优先使用聚合或合成关系复用代码。
    • 最少知识原则:最少知识原则又叫迪米特法则,一个对象应当对其他对象有尽可能少的了解。

数据结构

  • ArrayList和LinkedList。前者是数组实现,后者是节点实现
  • HashMap。哈希表(数组+链表,java又引入了红黑树(平衡二插搜索树))实现。ConcurrentHashMap有synchronized加持,LinkedHashMap有记录插入顺序

可以被序列化。
key-value都可以为null

  • HashTable

synchronized加持,线程安全
key-value都不可以为null

  • 数组存在(优:访问快,缺:不可变)中,链表存在(优:可变,缺:管理复杂)中。增删改查的时间空间都有别
  • List(有序,可重复)和Set(无序,不重复)

有序:分为插入顺序和排序顺序。list和set中所说的是插入顺序

  • Iterator 怎么使用hasNext()、next()、remove()

容器

简图容器简图
完整图
在这里插入图片描述

数组,String,java.util下的集合容器

  • Collection 元素序列
  • AbstractCollection: 对Collection接口的最小化抽象实现
  • List 有序集合
    • AbstractList 有序集合的最小化抽象实现
    • ArrayList 基于数组实现的有序集合
    • LinkedList 基于链表实现的有序集合
    • Vector 矢量队列【synchronized】
    • Stack 栈,先进后出
  • Set 不重复集合
    • AbstractSet 不重复集合的最小化抽象实现
    • HashSet 基于hash实现的不重复集合,无序
    • LinkedHashSet 基于hash实现的不重复集合,有序
    • SortedSet 可排序不重复集合
      • NavigableSet 可导航搜索的不重复集合
        • TreeSet 基于红黑树实现的可排序不重复集合
  • Queue 队列
    • AbstractQueue 队列的核心实现
    • BlockingQueue 阻塞队列
    • Deque 可两端操作线性集合
  • Map 元素键值对
  • AbstractMap 键值映射集合最小化抽象实现
  • Hashtable 基于哈希表实现的键值映射集合,key、value均不可为null
  • HashMap 类似Hashtable,但方法不同步,key、value可为null
    • LinkedHashMap 根据插入顺序实现的键值映射集合
  • SortedMap 可排序键值映射集合
  • 可以比较的点:
  • 有序、无序【指插入的顺序,非值大小的排序】
  • 可重复、不可重复
  • 键、值是否可为null
  • 底层实现的数据结构(数组、链表、哈希…)
  • 线程安全性
  • 有链表都是有序的(不是排序,是插入的顺序?)
  • Vector是线程安全的,ArrayList不是
  • List:有序、允许重复
  • HashSet:不重复

  • JVM中类的装载是由类加载器(ClassLoader)和它的子类来实现的,Java中的类加载器是一个重要的Java运行时系统组件,它负责在运行时查找和装入类文件中的类。类的加载是指把类的.class文件中的数据读入到内存中,通常是创建一个字节数组读入.class文件

  • 类的加载过程。装载(首次使用,查找)-连接(验证,准备、解析)-初始化(执行static区,放入JMM方法区),类只能被加载一次。

  • 类加载器实例化顺序。从父到子,从静到动,从变量到代码,最后是构造器

  • 反射是动态语言的一个特性,允许程序在运行时加载、探知、使用编译期间完全未知的classes。Class类的getDeclaredMethod可以获取指定方法名和参数的方法对象Method

  • 创建单例

public class Singleton implements java.io.Serializable {   
   public static Singleton INSTANCE = new Singleton();   
    
   protected Singleton() {   
      
   }   
   private Object readResolve() {   
            return INSTANCE;   
      }  
}
  • equals与hashcode(非物理地址,一种设计被用于hashmap把对象相对分开的散列值)的关系。equals相等两个对象,则hashcode一定要相等。但是hashcode相等的两个对象不一定equals相等。

  • == 和 equals 的区别是什么。equals本质上是==,只是有的类重写了equals

  • 构造器不能被继承,因此不能被重写,但可以被重载

Exception

  • CheckedException:ClassNotFoundException、NoSuchMetodException、IOException
  • RuntimeException:ArithmeticException,ArrayStoreExcetpion,ClassCastException,IndexOutOfBoundsException,NullPointerException

输入输出

  • IO 流:
    按功能来分:输入流(input)、输出流(output)。
    按类型来分:字节流(8bit)和字符流(16bit)。

  • Files的常用方法:
    Files.exists():检测文件路径是否存在。
    Files.createFile():创建文件。
    Files.createDirectory():创建文件夹。
    Files.delete():删除一个文件或目录。
    Files.copy():复制文件。
    Files.move():移动文件。
    Files.size():查看文件个数。
    Files.read():读取文件。
    Files.write():写入文件。

Collection接口

  • Collection是最基本的集合接口,一个Collection代表一组Object。子接口如:List和Set
  • Collections是个一个工具类,提供了一系列的静态方法来辅助容器操作,这些方法包括对容器的搜索、排序、线程安全化等等

线程

  • 线程5状态:
    java线程五大状态

    • 新建状态(New):
      当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();
    • 就绪状态(Runnable):
      当调用线程对象的start()方法,线程即进入就绪状态。处于就绪状态的线程,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
    • 运行状态(Running):
      当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。就绪状态是进入到运行状态的唯一入口。
    • 阻塞状态(Blocked):
      处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态。阻塞状态又可以分为三种:
      • 等待阻塞:执行wait()方法进入,notify()或notifyAll()方法来退出
      • 同步阻塞:线程在获取synchronized同步锁失败(因为锁被其它线程所占用)
      • 其他阻塞:通过调用线程的sleep()或join()或发出了I/O请求。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
    • 死亡状态(Dead):
      线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
  • Thread类的sleep()方法和对象的wait()方法都可以让线程暂停执行,它们有什么区别?
    答:sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复。wait()是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lock pool),如果线程重新获得对象的锁就可以进入就绪状态【资源由持锁者占有】

  • 创建线程:继承Thread类和实现Runnable接口。都要重写run()方法来定义线程的行为,推荐使用接口方式

  • 线程池:

corePoolSize:线程池的常驻核心线程数
maximumPoolSize:最大线程数
keepAliveTime:存活时间。
workQueue:任务队列。

  • ThreadLocal

ThreadLocal和Synchronized都是为了解决多线程中相同变量的访问冲突问题
Synchronized是通过线程等待,牺牲时间来解决访问冲突
ThreadLocal是通过每个线程单独一份存储空间,牺牲空间来解决冲突,并且相比于Synchronized,ThreadLocal具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问到想要的值。
当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候,可以考虑采用ThreadLocal

  • 锁:

互斥锁:使用sleep()来等待,线程被挂起
自旋锁:使用while()来等待,线程忙
信号量:计数器。主要用来线程同步

  • Object的wait()和notify()内部的monitor由lock+synchronized实现

synchronized和锁

  • 每个java对象都有一个内置的锁,synchronized只是一个内置锁的加锁机制。当加上synchronized修饰后,就表明要获得该内置锁才能执行。
  • 修饰方法和代码块:synchronized void func(){}、synchronized (this)
  • synchronized修饰,称为对象锁,使用static修饰synchronized,称为静态锁、全局锁、类锁。
  • 对象锁和类锁是互补干扰的两个锁,各自锁定着自己的区域,一个在堆区的对象中存放,一个在静态区中存放【两把锁】

Object中的方法

hashCode():用户获取对象的hash值,用于检索  
queals():用于确认两个对象是否相等;补充,哈希值相同的对象不一定equals(),但equals()的两个对象,hash值一定相等  
toString():返回一个String对象,用来标识自己  
getClass():返回一个class对象,打印的格式一般为 class http://package.name.xxx,经常用于java的反射机制  
clone():用来另存一个当前存在的对象  
finalize():垃圾回收的时候回用到,匿名对象回收之前会调用到  
wait():用于让当前线程失去操作权限,当前线程进入等待序列  
wait(long)、wait(long,int):用户设定下一次获取锁的距离当前释放锁的间隔时间  
notify():用于随机通知一个持有对象锁的线程获取操作的权限  
notifyAll():用于通知所有持有对象锁的线程获取操作权限

作者:淡定的蜗牛
链接:https://www.zhihu.com/question/333684160/answer/752557741
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

设计模式

  • 一套被反复使用的代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性
  • 几个常用的设计模式:
    • 工厂模式:工厂类可以根据条件生成不同的子类实例,这些子类有一个公共的抽象父类并且实现了相同的方法,但是这些方法针对不同的数据进行了不同的操作(多态方法)。当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。【对象多态】
    • 代理模式:给一个对象提供一个代理对象,并由代理对象控制原对象的引用。【对象保护】
    • 适配器模式:把一个类的接口变换成客户端所期待的另一种接口。【对象转化】
    • 单例模式:一个类只有一个实例,即一个类只有一个对象实例。【资源保护】
    • 发布订阅模式:【资源传递】

其他

  • bio是同步的,面向流。nio是异步的,面向缓冲区。nio避免了在 Java 堆和 Native 堆中来回复制数据。

  • switch不能作用于long,所有类型都会被转为int来实现(包括String,转hashCode),long转int会损失精度。

  • try{}里有个return。会记录下返回值待finally代码块执行后返回

  • Integer 中的-128到127在缓存表中不用new

  • Servlet的生命周期init(Web容器加载Servlet并将其实例化后) -> service(请求到达时调用doGet或doPost) -> destroy(服务器关闭或项目被卸载将Servlet实例销毁)

  • 转发(forward)【服务器帮你拿】和重定向(redirect)【服务器告诉你自己拿】

  • JSP有9个内置对象:

    • request:封装客户端的请求,其中包含来自GET或POST请求的参数;
    • response:封装服务器对客户端的响应;
    • pageContext:通过该对象可以获取其他对象;
    • session:封装用户会话的对象;
    • application:封装服务器运行环境的对象;
    • out:输出服务器响应的输出流对象;
    • config:Web应用的配置对象;
    • page:JSP页面本身(相当于Java程序中的this);
    • exception:封装页面抛出异常的对象。
  • AOP:面向切面编程(aspect-oriented programming)

  • TPS:Transactions Per Second,意思是每秒事务数,具体事务的定义,都是人为的,可以一个接口、多个接口、一个业务流程等等。一个事务是指事务内第一个请求发送到接收到最后一个请求的响应的过程,以此来计算使用的时间和完成的事务个数。(向服务器发请求,服务器内部处理,服务器返回结果,如果每秒能够完成N次这三个过程,tps就是N)

  • LRU:(Least Recently Used,最少最近使用)。用链表实现。被使用的节点从链表中取出并放到开头,链表满了就删掉最后一个

web

https://www.hollischuang.com/archives/4859
ThreadLocal

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值