JAVA扫盲笔记

前言

JAVA扫盲笔记,旨在对一些模糊的概念做出解释。

正文

基本数据类型和引用类型的区别

基本数据类型的访问是按值访问的,数据只存放在栈内,而引用类型的数据是栈指向堆。
八种基本数据类型:
整数型:byte short int long 8-16-32-64位 最大值为2的x-1次方,带正负号
浮点类型:float double 32-64位
float----符号位占用1位,指数位占用8位,小数位占用23位。
double:符号位占用1位,指数位占用11位,小数位占用52位。
字符类型char 16位char c='a';char c=97;
布尔型-true or false
基本数据类型组成的数组,使用new为数组分配内存:
一维数组int arr[]=new int[5];
二维数组int arr[][]=new int[2][3]
其他类型数组
List、ArrayList、HashMap

堆、栈、堆栈

栈包括:ring3用户栈,ring0内核栈(受操作系统级别保护)
堆向栈移动,栈向堆移动共同使用一块内存区域,直至用完。
一般只讨论用户栈stack、堆heap
栈:存放局部变量、函数调用时的寄存器信息 ESP栈顶指针、EBP栈底指针(先进后出)
堆:面向对象的new和C的malloc都是在堆上申请内存。(先进先出),堆空间远大于栈。
常见的“堆栈”多指栈。

final、finally、finalize的区别:

final:java关键字
修饰类(禁止继承)、方法(禁止重写)、变量(禁止赋值)
finally:java关键字
作为异常处理的一部分,关闭资源、释放锁
Finalize():Object类中的资源释放方法,可以重写。
定义在java.lang.Object中的方法,垃圾回收前调用,在对象回收前释放资源,每个对象的Finalize()只会被GC调用一次。

GC垃圾回收机制、System.gc()认定的垃圾有哪些:

1.对象引用超过其作用范围
2.对象置空Null

instanceof

java关键字,判断两个类的关系。
如果a继承于父类A,那么a instanceof A = true ,A instanceof A = true,A instanceof a = false
但是如果B instanceof A则会出现编译错误:不兼容的条件操作数类型(incompatible conditional operand types)

多态

官方解释是,利用多态可以使程序具有良好的扩展性,并可以对所有类对象进行通用的处理。
简单理解,多态是一种具体表现为利用面向对象思想以及重载、重写、继承、接口、向上转型等实现的一种概念。他的实现方法有很多种,但其实主要的是学习思想。

反射、注解

反射:通过Java反射机制,可以在程序中访问已经装载到JVM中的JAVA对象的描述,实现访问、检测和修改描述Java对象本身信息的功能。

注解:Annotation类型,用于类、构造方法、成员变量、方法、参数等的声明。该功能并不影响程序的运行,但是会对编译器警告等辅助工具产生影响。
定义Annotation类型的关键字为@interface,继承了Annotation接口。
@Target设置Annotation类型使用的程序元素种类。
@Retention设置Annotation的有效范围。

利用反射可以获得Annotation信息。
反射和注解常用于框架的开发,比如Spring、Mybatis 和JPA都有用到。

Unsafe类

Unsafe类,全限定名是sun.misc.Unsafe,他可以获得对象的内存地址,获得对象变量偏移量,从而对内存空间直接做操作,无视权限控制,甚至还可以直接在一个地址上读写。
获取unsafe对象:

Unsafe unsafe=Unsafe.getUnsafe();

volatile

java关键字
1.保证了变量的可见性(visibility)。被volatile关键字修饰的变量,如果值发生了变更volatile会保证修改的值立马被更新到主存,其他线程需要读取时会去内存中读取新值,避免出现脏读的现象。
2.防止指令重排序。在执行程序时,编译器和处理器会对指令做重排序。
分三个等级(
1.编译器优化重排序
2.指令级并行重排序
3.内存系统的重排序)

有如下一个问题:

a=b=x=y=0;
new Thread(()->{
            x=1;
            a=y;
        }).start();
new Thread(()->{
            y=1;
            b=x;
        }).start();

高并发的时候会出现a=0,b=0的情况。对a,b,x,y添加volatile保证读写操作的原子性,相当于加了一个读写锁。(但是不保证其他操作的原子性)

JMM

JAVA内存模型,定义了JVM只在计算机内存中的工作方式。
JAVA线程--->工作缓存(本地缓存)--->加载和保存操作--->主内存
MESI协议中,每个Cache line一共有4种状态,可用2个bit表示:
M: 被修改(Modified)
该缓存行只被缓存在该CPU的缓存中,并且是被修改过的(dirty),即与主存中的数据不一致,该缓存行中的内存需要在未来的某个时间点(允许其它CPU读取请主存中相应内存之前)写回(write back)主存。
当被写回主存之后,该缓存行的状态会变成独享(exclusive)状态。

E: 独享的(Exclusive)
该缓存行只被缓存在该CPU的缓存中,它是未被修改过的(clean),与主存中数据一致。该状态可以在任何时刻当有其它CPU读取该内存时变成共享状态(shared)。
同样地,当CPU修改该缓存行中内容时,该状态可以变成Modified状态。

S: 共享的(Shared)
该状态意味着该缓存行可能被多个CPU缓存,并且各个缓存中的数据与主存数据一致(clean),当有一个CPU修改该缓存行中,其它CPU中该缓存行可以被作废(变成无效状态(Invalid))。

I: 无效的(Invalid)
该缓存是无效的(可能有其它CPU修改了该缓存行)。

当volatile write被触发后,其他的本地缓存状态被改为无效的。

线程安全

在多线程由于线程对资源的互相抢占,会导致资源访问冲突,我们称这种现象叫线程不安全的。i++在底层也是分步走的,不遵从原子性,所以也是线程不安全的。

synchronized同步锁

在多线程线程不安全时可以加锁,常见的同步机制有悲观锁(synchronized)、乐观锁(CAS)、手动加锁(LOCK指令)。

悲观锁、乐观锁:
synchronized关键字可以修饰同步块(临界区)或者定义同步方法从而解决线程安全问题。事实上synchronized就是一个悲观锁,采用独占的方式来访问这些变量,独占锁其实就是一种悲观锁。

相对悲观锁而言,乐观锁主要就是两个步骤:冲突检测和数据更新。假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。

常用的乐观锁解决方案Compare and Swap(比较和交换)CAS技术,非常直白一看就是一个乐观锁。
它有三个操作数分别为:V表示要更新的变量,E表示预估值,N表示新值。当且仅当V值等于E值时,才将V的值设置为N;如果V值和E值不同, 返回当前V的值。

悲观锁代码:

public class Safetest implements Runnable   {
    @Override
    public void run() {
        boolean isrun=true;
        while(isrun) {
            synchronized ("") {
                if(ticketpool.num>0) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    ticketpool.num--;
                    System.out.println("购票成功还剩下"+ticketpool.num+"张票" );
                }else {
                    isrun=false;
                }
            }
        }
    }
}

public class ticketpool {
    public static volatile int num=20;  
}

伪--乐观锁代码,执行效率比纯悲观锁好一点:

public class Safetest implements Runnable   {
    @Override
    public void run() {
        boolean isrun=true;
        while(isrun) {
            int version= ticketpool.version;
            int ttnum= ticketpool.num;
                if(ttnum>0) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    ttnum--;
                   if(CAS(version+1,ttnum)) {
                        System.out.println("购票成功还剩下"+ttnum+"张票" );
                    }else {
                        System.out.println("购票失败,请重试");
                    }
                }else {
                    isrun=false;
                }
        }
    }
    /**
     * 
     * @param E 期望值
     * @param N 新值
     * @param V 要更新的变量
     * @return boolean
     */
    public  synchronized boolean CAS(int N,int V) {
        if((ticketpool.version+1)==N) {
            ticketpool.version=N;
            ticketpool.num=V;
            return true;
        }else {
            return false;
        }
    }
}

真正的CAS乐观锁实现,使用Unsafe类的CAS或者使用AtomicIntger原子操作类。

public class Safetest implements Runnable   {
    @Override
    public void run() {
        boolean isrun=true;
        while(isrun) {
            AtomicInteger ttnum= ticketpool.NUM;
            int expect=ttnum.get();
                if(expect>0) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    int update=expect-1;
                    if( ttnum.compareAndSet(expect, update)) {
                        System.out.println("购票成功还剩下"+update+"张票" );
                    }else {
                        System.out.println("购票失败,请重试");
                    }
                }else {
                    isrun=false;
                }
        }
    }

ABA问题:A,B两个线程,A的期望值和新值确定后没有立即执行,B抢占资源进行一系列修改后把数据恢复成A进入等待之前的状态,结果A还可以顺利执行。

使用带印记(版本号)的原子操作类,AtomicStampedReference可以解决ABA问题:

public class Safetest implements Runnable   {
    @Override
    public void run() {
        boolean isrun=true;
        while(isrun) {
             AtomicStampedReference ato = ticketpool.atomicStampedRef;
             int[] stampHolder = new int[1];
             int expect=(int) ato.get(stampHolder);
             int version=ato.getStamp();
                if(expect>0) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    int update=expect-1;
                    if( ato.compareAndSet(expect, update, version, version+1)) {
                        System.out.println("购票成功还剩下"+update+"张票" );
                    }else {
                        System.out.println("购票失败,请重试");
                    }
                }else {
                    isrun=false;
                }
        }
    }

自旋问题:最好避免重操作和需要频繁修改的数据段使用乐观锁,以此规避自旋产生的问题。

Lock手动加锁代码:

private Lock lock = new ReentrantLock();
try{
lock.lock;
i--;
}finnally{
lock.unlcok;
}

Serializable

JDK自带的IO接口,一个类的对象要想序列化成功,必须满足两个条件:
该类必须实现 java.io.Serializable 接口。
该类的所有属性必须是可序列化的。如果有一个属性不是可序列化的,则该属性必须注明是短暂(transient)的。或如果有不想序列化的属性,也声明为transient,当对该类序列化时,会自动忽略被 transient 修饰的属性。
https://blog.csdn.net/wayne566/article/details/80292689
可以使对象数据序列化以二进制文本的方式被持久化到了磁盘文件中或在网络间传播,并通过反序列化得到对象。

双亲委派机制

ClassLoader负责将class文件加载到JVM中去执行,JVM中提供了三层的ClassLoader:

1.Bootstrap ClassLoader :最顶层的加载类,主要加载核心类库,也就是我们环境变量下面%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等。另外需要注意的是可以通过启动jvm时指定-Xbootclasspath和路径来改变Bootstrap ClassLoader的加载目录。比如java -Xbootclasspath/a:path被指定的文件追加到默认的bootstrap路径中。我们可以打开我的电脑,在上面的目录下查看,看看这些jar包是不是存在于这个目录。

2.Extention ClassLoader :扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。还可以加载-D java.ext.dirs选项指定的目录。

3.Appclass Loader:也称为SystemAppClass。 加载当前应用的classpath的所有类。

当一个类加载器收到类加载任务,会先交给其父类加载器去完成,因此最终加载任务都会传递到顶层的启动类加载器,只有当父类加载器无法完成加载任务时,才会尝试执行加载任务。

好处:
1.可以避免重复加载,父类已经加载了,子类就不需要再次加载
2.更加安全,很好的解决了各个类加载器的基础类的统一问题,如果不使用该种方式,那么用户可以随意定义类加载器来加载核心api,会带来相关隐患。

IOC

Spring框架的基本知识,中文名为控制反转,既获得依赖对象的过程被反转了。涉及的设计模式:
1.工厂设计模式 : Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。
2.单例设计模式 : Spring 中的 Bean 默认都是单例的。
3.模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
4.包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。

依赖注入DI和控制反转IOC就是从不同的角度描述同一件事情,是指通过引入IOC容器,利用依赖关系注入的方式实现对象之间的解耦。
其底层核心就是利用反射的方法动态生成JAVABEAN(Bean:在计算机英语中,有可重用组件的含义)对象,并把他们放到IOC容器里供程序使用。由于JAVA垃圾回收机制的存在,我们就需要一个容器来保护、管理实体类对象所以IOC容器的主要工作就是负责创建对象,管理对象,装配对象,配置对象,并且管理这些对象的整个生命周期。
bean对象的生命周期:
单例对象
出生:当容器创建时对象出生
活着:只要容器还在,对象一直活着
死亡:容器销毁,对象消亡
总结:单例对象的生命周期和容器相同
多例对象
出生:当我们使用对象时spring框架为我们创建
活着:对象只要是在使用过程中就一直活着。
死亡:当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收

我们可以通过XML文件或者使用注解的方式来配置进行依赖关系的维护,依赖注入。
注解配置和 xml 配置要实现的功能都是一样的,都是要降低程序间的耦合。只是配置的形式不一样。

AOP

Spring框架的基本知识,中文名为面向切面编程,通过配置的方法实现基于接口和基于子类的动态代理,具体实现也是分为XML文件配置和注解配置。
其目的就是为了使得减少重复代码、提高开发效率、维护方便。
一共有五种切面通知:
1.前置通知(before)
2.后置通知(after-returning)---try
3.异常通知(after-thorwing)---catch
4.最终通知(after)---finally
5.环绕通知(around)
同时Spring也内嵌了事物通知(transaction)

SpringMVC与五大核心组件

SpringMVC就是建立在Spring应用平台之上的MVC模型--[模型(model)-视图(view)-控制器(controller)]。可以说SpringMVC的核心组成就是这五大组件:
1.DispatcherServlet 前置控制器
2.HandlerMapping 处理器映射
3.Controller 控制器
4.ModelAndView 封装数据信息和视图信息的模型
5.ViewResolver 视图解析器

他们工作的流程图大概如下图:

组件工作流程图.PNG

我还是比较看好这个解释的:
五大组件

关于SpringMVC的说法也很多有人就提出了九大组件也可以当当扩展看看:
九大组件
因为它没有前端控制器所以不好理解暂且就不学习了,以后深入的时候应该会接触到。

Servlet

Servlet是sun公司提供的一门用于开发动态web资源的技术。
Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
  1、编写一个Java类,实现servlet接口。
  2、把开发好的Java类部署到web服务器中。
  按照一种约定俗成的称呼习惯,通常我们也把实现了servlet接口的java程序,称之为Servlet
其中Tomcat服务器不同版本就是对JAVA EE Servlet不同版本规范的实现,Servlet是一个接口,而Tomcat就是对其进行底层实现的一套解决方案。
比如说:Apache Tomcat 9.X 就是遵循Servlet4.0,JSP2.3,EL3.0规范的一Servlet服务器,支持jdk8.0及以上的版本的开发。
Servlet程序、Filter过滤器、Listener监听器并成为JavaWeb三大组件。
Servlet的生命周期从第一次访问时开始创建、初始化,并且他是一个单例对象,接下来请求此Servlet都是使用同一对象,直到Web工程停止时对对象进行销毁。

过滤器在请求进入服务前进行过滤,可以对其进行身份校验选择是否进行重定向。

监听器可以对三大域(request、session、ServletContext)进行监听,其提供了八种监听器接口。这八种监听器可以分为四大种类:
1.监听对象的创建:
ServletContext:主要监听servletContext的创建,需要实现ServeltContextListener接口。
ServletRequest:主要监听request的创建, 需要实现ServletRequestListener接口
HttpSession:主要监听session的创建,需要实现HttpSessionListener接口
2.监听属性的改变:
ServletContext:主要监听servletContext属性的更改、添加、删除,需要实现ServeltContextAttrbuteListener接口。
ServletRequest:主要监听request属性的更改、添加、删除, 需要实现ServletRequestAttrbuteListener接口
HttpSession:主要监听session属性的更改、添加、删除,需要实现HttpSessionAttrbuteListener接口
3.监听session的活化与钝化:
httpSessionActivationListener主要监听了session的活化与钝化
4.监听session与对象的绑定:
httpSessionBindingListener监听了session与对象的绑定

在学习的时候应当着重于各种监听器的触发条件。
活化与钝化其实就是对反应序列化与序列化,可以对session进行保存和恢复需要实现Serializable接口。

学习链接:
https://www.cnblogs.com/lukelook/p/11079113.html
https://blog.csdn.net/csdn19970806/article/details/80707271

JavaWeb四大域
以上说到监听三大域的监听器,那么现在就来聊聊四大域。
依照pageContext->request->session->servletContext的顺序由小到大。
pageContext是JSP中特有的,如果使用静态页面则没有,封装了8大隐式对象。
servletContext则涵盖了整个web应用。
https://www.jianshu.com/p/6c02951267d8

EL表达式
EL是JSP内置的表达式语言,EL可以输出的东西都在11个内置对象中,11个内置对象,其中10个是Map,只有pageContext不是(如上所述是四大域之一)。
https://blog.csdn.net/qq_17045385/article/details/54799998

HTTP协议

HTTP协议下属于TPC/IP协议簇(TCP/IP协议不仅仅指的是TCP 和IP两个协议,而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇, 只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以被称为TCP/IP协议)中的应用层协议。
协议就是指:网络协议是通信计算机双方必须共同遵从的一组约定。一般由Servlet提供规范接口。

HTTP包括GET,POST,PUT,DELETE,OPTIONS等请求方式,主流开发中一般使用GET,POST两种请求方式。

get.PNG
post.PNG
文件上传

他们都包含请求行、请求头,但是POST请求参数放在了请求体内。
一般来说纯参数的请求使用GET也可以达到和POST一样的效果但是由于浏览器和服务器对URL长度(8208字节)的限制导致传图像和文件时只能使用POST请求。

MIME.PNG

https://www.cnblogs.com/xianlei/p/tcpip_http.html
HTTPS协议

HTTPS协议可以理解为HTTP协议的升级,就是在HTTP的基础上增加了数据加密。在数据进行传输之前,对数据进行加密,然后再发送到服务器。这样,就算数据被第三者所截获,但是由于数据是加密的,所以你的个人信息让然是安全的。这就是HTTP和HTTPS的最大区别。
2021.4.14补充:
HTTPS实际上就是利用了CA(也可能是自己)颁发的SSL证书利用其中的公钥、私钥,进而通过一系列加密算法实现对称、非对称加密等过程,实现对信息加密防止了信息传输过程中的偷窥以及中间人攻击等可能危害信息安全的事件发生。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352