JAVA整理总结

2023-10-26

文章目录

JavaSE

面向对象的特点是什么

继承

封装

  • 封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法

多态

  • 两种方法实现多态,基于接口、基于继承
  • 实现多态有三个必要条件:继承、重写、向上转型。

==和equals的区别

==的比较地址是否相等

  • equals在不重写的情况下,底层调用的就是==去比较地址

  • 在重写只会则是比较类中的数据是否相同

  • 重写了hashcode方法之后,一定要重写equals,

  • 因为hashcode的长度是固定的,当数据足够多时,便会出现数据不相同而,hashcode相同的情况

  • 此时便需要使用equals判断

String str="i"与 String str=new String(“i”)一样吗?

不一样,因为内存的分配方式不一样。

String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。

String 类的常用方法都有那些?

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

Integer a= 127 与 Integer b = 127相等吗

  • 对于对象引用类型:==比较的是对象的内存地址。
  • 对于基本数据类型:==比较的是值。

如果整型字面量的值在-128到127之间,那么自动装箱时不会new新的Integer对象,而是直接引用常量池中的Integer对象,超过范围 a1==b1的结果是false

Integer a = new Integer(3);
Integer b = 3;  // 将3自动装箱成Integer类型
int c = 3;
System.out.println(a == b); // false 两个引用没有引用同一对象
System.out.println(a == c); // true a自动拆箱成int类型再和c比较
System.out.println(b == c); // true
Integer a1 = 128;
Integer b1 = 128;
System.out.println(a1 == b1); // false

Integer a2 = 127;
Integer b2 = 127;
System.out.println(a2 == b2); // true

接口和抽象类的区别

  • 两个都无法实例出对象
  • 抽象类可以存在普通方法,而接口只能存在 public abstract 方法
  • 抽象类的属性可以是各种类型,但接口的的属性只能是 static final
  • 抽象类只能继承一个,而接口能继承多个

重写和重载的区别

重载:发生在一个类中,方法名必须相同,参数的类型不同、个数不同、顺序不同

重写:

  • 发生在父子类中
  • 方法名、参数列表必须相同
  • 子类的方法权限必须大于等于子类的方法权限
  • 抛出的异常范围小于等于父类

final的作用

final作用于类:该类无法被继承

final作用与方法:该方法无法被重写,但能被继承

final作用于属性:

  • 如果final引用一个基本数据类型,则值为常量,无法被修改
  • 如果final引用一个引用数据类型,则该对象或数组的地址无法被修改,其本身的值可以被修改
  • 如果final引用类的成员变量,则必须初始化时赋值

类的访问修饰符

img

静态代码块和构造代码块的区别

img

静态代码块:在虚拟机加载类的时候就会加载执行,而且只执行一次

构造代码块:每次创建对象的时候便会执行一次

执行顺序:(优先级从高到低。)静态代码块>mian方法>构造代码块>构造方法。

有哪些基本类型

int、long、short、float、double、byte、boolean、char

String、StringBuilder、StringBuffer的区别

  • String底层是不可变的char数组,每一次修改都是在new一个新的string对象

  • 而StringBuilder和StringBuffer是可变的char数组

  • StringBuilder是线程不安全的,性能高

  • StringBuffer是线程安全的,性能较低

基本数据类型和包装类型的区别

基本数据类型存放在栈中,包装类型存储在堆中

获取对象的方式有哪几种

  • new
  • 反射
  • 反序列化
  • clone 拷贝

什么是反射

(反射)是被视为动态语言的关键

  • 反射机制允许程序在执行期获得任何类的内部信息
  • 并能直接操作任意对象的内部属性及方法(操作字节码)。

创建Class的四种方式

//方式1  通过运行时类的属性
Class<User> userClass=User.class;
Class s = String.class;

//方式2  通过运行时类的对象,调用 getClass方法
User u=new User();
Class userClass2=u.getClass();


//方式3  通过forName静态方法
Class c1= Class.forName("java.lang.String");
Class userClass3 = Class.forName("com.jie.pojo.User");


//方式4  使用类的加载器 (了解即可)
ClassLoader classLoader=reflectionTest.class.getClassLoader();
Class userClass4=classLoader.loadClass("com.jie.pojo.User");
System.out.println(userClass4);
  • 无论是通过类还是对象创建的Class,都是指向的同一个字节码文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YIfbRfOE-1620218177125)(img\8.png)]

throw 和 throws 的区别?

  • throws是用来声明方法可能抛出的所有异常信息,throws是将异常声明但是不处理
  • throw则是指抛出的一个具体的异常类型。

集合

在这里插入图片描述

在这里插入图片描述

集合和数组的区别

  • 数组的固定长度,集合的可变长度
  • 数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。
  • 集合有很多内置方法

分别说一下list、set、map的区别

  • List和Set继承与collection接口,它们的子类都是能被迭代的
  • List:有序且重复,存储单元有下标
  • Set:无序不重复,无下标(使用迭代器、for each输出)
  • Map:采用KV对的形式存储,无序且不重复

ArrayList和LinkedList的区别

  • ArrayList底层采用数组,LinkedList底层采用链表
  • 它们都是线程不安全的
  • arraylist查询较快,增加、删较慢
  • linkedlist增删改较快,查询较慢

Arraylist和vector的区别

  • ArraylIst线程不安全,效率较快,初始容量为10扩容1.5倍
  • vector线程安全,效率较低,初始容量10,扩容2倍

HashMap和HashTable的区别

  • hashmap线程不安全、效率高,hashtable线程安全、效率低
  • hashmap的kv都允许为空,hashtable的kv不允许为空
  • hashmap 初始容量16,hashtable是11,它俩的扩容因子都是0.75
  • hashmap的扩容变为2n,hashtable的扩容是2n+1

HashMap和HashSet的关系

  • HashSet的底层就是 实例了HashMap对象

  • 在添加时,将数据放在Map的key位置,value则是空object对象

  • TreeSet同样是实例了TreeMap

  • TreeMap底层是自平衡二叉树,实现了key按大小排列

Hash表的get和put原理

hashTable部分代码

/*
map.put(k,v)实现原理
	1. 先将k,v封装到Node对象中
	2. 底层会调用k的hashCode()方法得到hash值,然后通过哈希函数/哈希算法,将hash值转换成数组的下标
	3. 如果此时的下标位置上没有任何元素,将把Ndoe添加到这个位置上
	4. 如果说下标对应的位置上有链表,则判断是否存在key的hash相同,key之间的equals比较为true的节点
	5. 存在则替换该节点,不存在则在节点末尾添加
*/
	public synchronized V put(K key, V value) {
		// 判断value是否为空
        if (value == null) {
            throw new NullPointerException();
        }
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length; //通过hash确定下标
        
        Entry<K,V> entry = (Entry<K,V>)tab[index]; //获取该下标的链表
        for(; entry != null ; entry = entry.next) {
        	//如果该链表中有hash相同,并且key的equals也为true 则替换节点
            if ((entry.hash == hash) && entry.key.equals(key)) {
                V old = entry.value;
                entry.value = value;
                return old;
            }
        }
		//否则添加到链表的末尾
        addEntry(hash, key, value, index);
        return null;
    }

    

/*
map.get(k)实现原理
	1. 先调用k的hashCode()方法得出hash值,通过哈希算法将该哈希值转换为数组下标,通过数组下标快速定位到指定位置,如果这个位置是什么也没有,就返回null
	2. 如果此时这个位置上有单向链表,则判断此链表上是否存在key的hash相同且equals为true的节点 
	3. 有则返回其value 否则返回null
*/
    public synchronized V get(Object key) {
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length; //通过hash值确定数组下标
        for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {  //如果两个条件则输出该value
                return (V)e.value;
            }
        }
        return null;  //否则返回null
    }

map.put(k,v)实现原理

  • 先将k,v封装到 节点对象 中
  • 底层会调用k的hashCode()方法得到hash值
  • 然后通过哈希函数/哈希算法,将hash值转换成数组的下标
  • 如果此时的下标位置对应的链表上没有任何元素,将把节点添加到这个位置上
  • 如果说下标对应的位置上有链表,则判断是否存在key的hash相同,key之间的equals比较为true的节点
  • 存在则替换该节点,不存在则在节点末尾添加

map.get(k)实现原理

  • 先调用hashCode(key)方法得出hash值,
  • 通过哈希算法将该哈希值转换为数组下标,通过数组下标快速定位到指定位置,如果这个位置是什么也没有,就返回null
  • 如果此时这个位置上有单向链表,如何该链表上有 hash值相同 且 equals也为true的节点,则返回这个节点的value
  • 若该链表不满足上述条件,则返回null

多线程

何为进程和线程

  • 进程是程序的一次执行过程,是系统运行程序的基本单位
  • 线程是比进程更小的执行单位,一个线程在执行过程中,可以产生多个线程

创建线程有哪几种方式

  • 继承与Thread类,重写run方法

  • 实现ruannable接口,实现run方法

  • 实现Callable接口中的call方法

    • 将callable的实现类传给FutrueTask中
    • 将FutrueTask的实现类传给Thread类来启动

runnable 和 callable 有什么区别?

  • 可以抛异常

  • 可以返回值

    futureTask.get()  //获取返回值   但必须等待该线程执行完毕
    
  • 可以支持泛型

  • 需要借助FutrueTask工具类来实现

Thread类常用方法

yield(): 释放线程

  • 释放当前cpu线程的进程 (之后cpu进行的可能仍是该线程、也有可能是其他线程)

sleep():该线程进入堵塞状态 若干毫秒,不会释放锁

join():

  • 在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完以后,线程才结束阻塞状态

interrupt(): 打断线程

  • 打断 阻塞线程时 (sleep wait join…) 的线程时
    • 会抛出InterruptedException异常
  • 打断是正常运行的线程时,
    • 该线程不会停止,会继续执行,如果让线程被打断后停下来,需要使用被打断标记判断
    • 判断方法: isInterrupted()

setDaemon(true) 守护线程

  • java进程中有多个线程在执行时,当所有其他非守护线程都执行完毕后,无论守护线程是否执行完毕,也会一同结束线程

线程有哪几种状态

新建、就绪、运行、堵塞、终止

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jNnWP7uw-1618880935978)(img\3.png)]

线程是生命周期要经历五种状态:

  • 新建:当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态
  • 就绪:处于新建状态的线程被start()后,将进入线程队列等待CPU时间片,此时它已具备了运行的条件,只是没分配到CPU资源
  • 运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run()方法定义了线程的操作和功能
  • 阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出 CPU并临时中止自己的执行,进入阻塞状态
  • 死亡:线程完成了它的全部工作或线程被提前强制性地中止或出现异常导致结束

什么是守护线程

setDaemon(true) 守护线程

java进程中有多个线程在执行时,当所有其他非守护线程都执行完毕后,无论守护线程是否执行完毕,也会一同结束线程

同步代码块、同步方法

synchronized(同步监视器){
	需要被同步的代码
}
  • 说明:操作共享数据的代码,即为需要被同步的代码
  • 共享数据:多个线程共同操作的变量。比如: ticket就是共享数据。
  • 同步监视器,俗称:锁。任何一个类的对象,都可以充当锁。

关于同步方法:

public synchronized void test() {
	
}
  • 同步方法仍然涉及到同步监视器

  • 同步方法上锁的对象

  • 加在成员方法上 (对象实例本身)

    加在静态方法上 (类本身)

死锁和活锁

死锁

  • 不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源就形成了线程的死锁
  • 出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续
public static void main(String[] args) {
        Object a=new Object();
        Object b=new Object();

        new Thread(() -> {
            synchronized (a) {
                System.out.println(Thread.currentThread().getName() + "我获取a锁,过会儿去获取b锁");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                synchronized (b) {
                    System.out.println(Thread.currentThread().getName() + "我获取了 a 和 b,方法执行结束");
                }
            }
        }).start();
        new Thread(() -> {
            synchronized (b) {
                System.out.println(Thread.currentThread().getName() + "我获取b锁,过会儿去获取b锁");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                synchronized (a) {
                    System.out.println(Thread.currentThread().getName() + "我获取了 a 和 b,方法执行结束");
                }
            }
        }).start();
    }

解决办法

  • 尽量减少同步资源的定义
  • 尽量避免嵌套同步

活锁

活锁出现在两个线程互相改变对方的结束条件,后谁也无法结束。

Lock锁

需要创建一个ReentrantLock对象

通过

  • 调用 lock.lock() 开启锁
  • 调用 **lock.unlock() **关闭锁

基本语法:

//获取ReentrantLock对象
private ReentrantLock lock = new ReentrantLock();
//加锁
lock.lock();
try {
	//需要执行的代码
}finally {
	//释放锁
	lock.unlock();
}

锁超时

使用lock.tryLock方法会返回获取锁是否成功。如果成功则返回true,反之则返回false。

设置等待时间

//判断获取锁是否成功,最多等待1秒
if(!lock.tryLock(1, TimeUnit.SECONDS)) {
    System.out.println("获取失败");
    //获取失败,不再向下执行,直接返回
    return;
}

synchronized 与Lock的异同?

  • 相同:

    • 二者都可以解决线程安全问题
    • 都是可重入锁:在执行对象中所有同步方法不用再次获得锁
  • 不同:

    • synchronized机制在执行完相应的同步代码以后,自动的释放同步监视

    • Lock需要手动的启动同步 Lock(),同时结束同步也需要手动的实现 unlock()

    • synchronized 是Java内置的关键字

    • Lock是java.util.concurrent.Locks 包下的一个接口

    • synchronized 是非公平锁,即不能保证等待锁线程的顺序

    • Lock的实现 ReentrantLock 可通过实例化true or false 的构造参数实现公平锁和非公平锁默认为非公平锁

    • synchronized无法判断是否获取锁的状,Lock可以判断是否获取到锁;

    • Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。

    • synchronized是一个悲观锁,Lock是一个乐观锁(底层基于volatile和cas实现)

线程通信 wait、notify

  • wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
  • notify():一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait 就唤醒优先级高的那个
  • notifyALL():一旦执行此方法,就会唤醒所有被wait的线程。

说明:

wait( ),notify(),notifyALl()

  • 三个方法必须使用在同步代码块或同步方法 而且由一个对象锁监控

  • 三个方法的调用者必须是同步代码块同步方法中同步监视器 否则,会出现ILLegaLMonitorStateException异常 (必须是一个对象)

sleep()和wait()的异同

相同点:一旦执行方法,都可以使得当前的线程进入阻塞状态。

不同点:

  1. 两个方法声明的位置不同: Thread类中声明sLeep() , object类中声明wait()

  2. 调用的要求不同: sleep()可以在任何需要的场景下调用。wait()必须使用在同步代码块或者同步方法

  3. 关于是否释放同步监视器:,如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁

park 暂停

park/unpark都是LockSupport类中的方法

//暂停线程运行
LockSupport.park;

//恢复线程运行
LockSupport.unpark(thread);
public static void main(String[] args) throws InterruptedException {
    Thread thread = new Thread(() -> {
        System.out.println("start");
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("park");
        //该线程 进入暂停
        LockSupport.park();
        System.out.println("return");
    });

    thread.start();
    Thread.sleep(100);
    LockSupport.unpark(thread);  //由主线程恢复thread线程的运行
}

区别

  • wait/notify必须要配合同步锁来执行 park/unpark不用
  • notify只能随机唤醒某一个线程,而unpark可以精准唤醒某线程
  • wait会释放锁,而park不会释放锁
  • park & unpark 可以先 unpark,而 wait & notify 不能先 notify
    • 可以提前调用unpark使该线程的参数+1(最多只能装下1),后续调用park也不会使该线程进入暂停

IO

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XNSeOpjW-1620217788901)(img\1.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fblBqz9z-1620217788903)(img\2.png)]

IO流分为哪几种

  • 按流的流向分为,输入流和输出流
  • 按流的操作分为,字节流和字符流
  • 按流的角色分为,节点流和处理流

Files的常用方法都有哪些?

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

序列化中如果有些字段不想进行序列化,怎么办?

  • 可以使用transient关键字
  • 阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被transient修饰的变量值不会被持久化和恢复。
  • transient只能修饰变量,不能修饰类和方法。

序列号作用

  1. 当文件中的对象进行反序列化时,会先判断文件中类名和程序中类名是否一致

  2. 如果相同则再比较文件中对象的序列号,和项目中类的序列号是否相同

    • 如果不相同则会报异常

    • java.io.InvalidClassException: com.jie.io.Person; 
      local class incompatible: stream classdesc serialVersionUID = -7564189118422739644, local class serialVersionUID = -2265004783317520704
      

为什么会导致文件中类的序列号和项目中类的序列号不同呢

  • 当存储实现了Serializable接口的对象时,如果该对象没有设置序列号,Jvm会给这个对象分配一个默认的序列号
  • 但当该类的结构被改变时,该类的默认的序号也会发生改变
  • 如果不设置固定序列号,当类的结构改变时,就会出现磁盘和内存中类 序列号不同的情况
java.io.InvalidClassException: com.jie.io.Person; 
local class incompatible: stream classdesc serialVersionUID = -7564189118422739644, 
local class serialVersionUID = -2265004783317520704  //序列号不同

所以需要给可序列的类给定一个固定的序列号,使磁盘和内存中的类的序列号始终相同

JVM

JVM、JRE、JDK的关系

img](https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200608150422.png)

说一下JVM的内存模型分布

线程私有

  • 程序计数器
  • 虚拟机栈
  • 本地方法栈

线程共享

  • 方法区

程序计数器为什么是线程私有的

  • 程序计数器需要标记下一条jvm执行的指令
  • 每个线程拥有自己的程序计数器,便能保证程序在多线程下能够正确运行
  • 它是内存模型中唯一一个不会存在OOM的分区,它随着线程的创建而创建,随着线程的结束而销毁

JVM中堆、栈、方法区的作用是什么

虚拟机栈

  • 为Jvm虚拟机执行java方法,虚拟机栈由一个个栈帧组成
  • 每一次调用方法则代表,对应的栈帧被压入栈中,当方法结束或者抛异常是栈帧弹出
  • 栈不需要垃圾回收,因为栈帧结束后,会自动销毁空间

本地方法栈

  • 与虚拟栈类似,其执行的是native关键字的方法,需要JAVA去调用c/c++的方法

  • 堆的目的是存放对象的实例和数组,是垃圾回收的主要区域
  • 其被分为 新生代和永久代新生代又分为eden区、幸存区from、幸存区to

img

方法区

  • 方法区是各个线程共享的区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、编译后的代码等
  • 运行时常量池是方法区的一部分

方法区和元空间的关系

  • 元空间是方法区是实现(jdk1.8),在1.7时,方法区的实现还是永久代
  • 元空间存放在直接内存

字符串常量池在哪?

如何判断该对象是否可以被回收

  • 可达性分析算法:若没有被gc Root引用的对象则会被垃圾回收
  • 当进行垃圾回收时会调用该对象重写的析构方法finalize(),则判断是否被其他对象所掉调用
  • 如果其对象没有被其他调用,则将其删除,反正不会被删除
  • 析构方法只能执行一次

什么是gc root对象

  • gc root对象是作为垃圾回收时的根对象,如果没有被gc root所引用的对象,就将被进行垃圾回收

哪些能作为gc root对象

  • 中所引用的对象
  • 方法区中静态变量所引用的对象
  • 方法区中静态常量引用的对象

垃圾回收算法有哪些,它们的特点是什么

标记清理算法

img

  • 效率高,但容易产生大量的内存碎片

标记整理算法

  • 用于老年代的清除

img

可以有效的避免 碎片内存过多的问题

缺点:因为整体需要内存消耗时间,所以效率过低

复制算法


img

可以避免内存碎片的问题,但是会占用双倍的内存空间。

新生代和老年代空间默认比例

  • 新生代默认的空间占比总空间的 **1/3,**老生代的默认占比是 2/3。
  • 新生代内 eden区:幸存区From:幸存区To 的默认比列为 8:1:1
  • 新生代晋升老年代的阈值为15,若有大对象超过了新生代的空间,则会直接晋升老年代

四种引用是哪四种

强软弱虚

强引用:

  • 通过new出来的对象,为强引用 Object object=new Object();
  • 只有Gc root都不引用时,才会回收强引用对象

引用什么时候失效

生命周期结束 (作用域失效)

public void method(){
    Object o=new Object();
}//方法执行结束后,强引用指向的Object对象 就会被回收置为null之后
Object=null

除了上述两种情况外,其他情况Gc都不会回收强引用对象

软引用 (SoftReference)

当GC Root指向软引用对象时

  1. JVM内存不足时,会回收软引用所引用的对象
  2. 生命周期结束 (作用域失效)
  3. 置为null之后

弱引用 (WeakReference)

只要gc检测到弱引用就会回收

虚引用

  • 虚引用并不会决定对象的生命周期。
  • 如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。
  • 需要配合引用队列联合使用

有哪些垃圾回收器

img

  • 新生代回收器:Serial、ParNew、Parallel Scavenge
  • 老年代回收器:Serial Old、Parallel Old、CMS
  • 整堆回收器:G1

新生代垃圾回收器一般采用的是复制算法,复制算法的优点是效率高,缺点是内存利用率低;

老年代回收器一般采用的是标记-整理的算法进行垃圾回收。

类的加载

验证

验证类是否符合JVM规范,安全性检查

准备

为static变量分配空间,设置默认值

  • static变量在分配空间和赋值是在两个阶段完成的,分配空间在准备阶段完成,赋值在初始阶段完成
  • 如果static是final的基本类型,以及字符串常量,那准备阶段就确定赋值了
  • 如果static是final的引用类型,赋值仍然在初始化阶段
public class HelloWorld {
    static int a;
    static final int b=1;
    static final Object o=new Object();  //仍然在初始化阶段才会赋值
}

解析

  • 将常量池中的符号引用解析为直接引用
  • 解析之前,符号未分配在具体的内中,解析之后才分配了具体的内存

初始化

初始化阶段就是在执行类构造器clinit()方法的过程,虚拟机会保证这个类的『构造方法』的线程安全

  • clinit()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的语句合并产生的

发生的时机

类的初始化是懒惰的,以下情况会初始化

  • main方法所在的类,总会被首先初始化
  • 首次访问这个类的静态变量或静态方法
  • 子类初始化,如果父类还没初始化,会引发父类的初始化
  • 子类访问父类的静态变量,只会触发父类的初始化
  • Class.forName
  • new 会导致初始化

不会导致初始化

  • 访问类的static final静态常量(基本类型和字符串)
  • 类对象.class不会触发初始化
  • 创建该类对象的数组
  • 类加载器的loadClass方法
  • Class.forNamed的参数2为false时

类加载器

启动类加载器

  • 优先级最高的类加载器
  • 负责加载 JAVA_HOME/jre/lib 下的类

扩展类加载器

  • 优先级第二的类加载器
  • 负责加载 JAVA_HOME/jre/lib/ext 下的类

应用程序类加载器

  • 优先级第三的类加载器
  • 负责加载 classpath 下的类 一般是自定义类型

双亲委派机制

所谓的双亲委派机制,就是指调用类加载器的loadClass方法时的规则

  • 首先查看这个类是否被加载过
  • 如果没有,就询问该类是否属于该加载器的上级加载(应用程序类加载器 ->扩展类加载器->启动类加载器)
  • 如果该类不属于于上级类加载器加载 则再由下级加载器加载

Mysql

内连接、左连接、右连接有什么区别?

  • 内连接关键字:inner join;
  • 左连接:left join;
  • 右连接:right join。

内连接是把匹配的关联数据显示出来;

左连接是左边的表全部显示出来,右边的表显示出符合条件的数据;右连接正好相反。

什么是索引

  • 索引是一种数据结构。数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。
  • 索引的实现通常使用B树及其变种B+树。

优点

  • 能够加快检索数据的速度,提高性能

    缺点

  • 创建索引和维护索引都需要耗费时间

  • 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,会降低增/改/删的执行效率;

索引适合建立在修改少,查多的列

索引的分类

  • ​ 单一索引:给单个字段添加索引
  • ​ 复合索引: 给多个字段联合起来添加1个索引
  • ​ 主键索引:主键上会自动添加索引
  • ​ 唯一索引:有unique约束的字段上会自动添加索引

索引什么时候失效
select ename from emp where ename like ‘%A%’;

模糊查询的时候,第一个通配符使用的是%,这个时候索引是失效的。

什么是视图

视图可以隐藏表的实现细节。保密级别较高的表,只对视图对象进行CRUD。

特点

  • 查询简单化。重用SQL语句
  • 保护数据。可以给用户授予表的特定部分的访问权限而不是整个表的访问权限;
  • 逻辑数据独立性。视图对重构数据库提供了一定程度的逻辑独立性

SQL 约束有哪几种?

  • NOT NULL: 用于控制字段的内容一定不能为空(NULL)。
  • UNIQUE: 控件字段内容不能重复,一个表允许有多个 Unique 约束。
  • PRIMARY KEY: 也是用于控件字段内容不能重复,但它在一个表只允许出现一个。
  • FOREIGN KEY: 用于预防破坏表之间连接的动作,也能防止非法数据插入外键列,因为它必须是它指向的那个表中的值之一。
  • CHECK: 用于控制字段的值范围。

事务的基本特性

​ 事务包括四大特性:ACID

  • A: 原子性:事务进行的操作 要么成功,要么失败
  • C: 一致性:事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。
  • I:隔离性:事务A与事务B之间具有隔离。
  • D:持久性:持久性说的是最终数据必须持久化到硬盘文件中,事务才算成功的结束。

事务的隔离级别

  • uncommitted; 读未提交

    两个客户端中,一个客户端在事务中操作数据,即使未提交,另一个客户端也能访问

  • committed; 读已提交

    一个客户端在事务中,未提交的数据,另一个客户端无妨访问

  • **repeatable read; ** 可重复读(Repeated Read):

    可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在事务中,读取的数据的始终不变

  • **Serializable **串行读

  • 完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞

Mysql三范式

  • 第一范式

数据表的每一列都要保持它的原子特性,也就是列不能再被分割。

  • 第二范式

表中的属性必须完全依赖于主键

  • 第三范式

所有的非主属性不依赖于其他的非主属性

JAVAEE

转发和重定向的区别

  • 转发forward:能共享请求数据,而redirect不能
  • 转发url不会变化,重定向url会变化
  • 转发效率比重定向高

Servlet的生命周期

void init(ServletConfig config) throws ServletException
void service(ServletRequest req, ServletResponse resp) 
void destroy()

生命周期: Web容器加载Servlet并将其实例化后,Servlet生命周期开始,容器运行其init()方法进行Servlet的初始化;请求到达时调用Servlet的service()方法,service()方法会根据需要调用与请求对应的doGet或doPost等方法;当服务器关闭或项目被卸载时服务器会将Servlet实例销毁,此时会调用Servlet的destroy()方法init方法和destroy方法只会执行一次,service方法客户端每次请求Servlet都会执行

Get请求和Post请求的区别

  • Get的请求参数都会显示在地址栏中,post不会
  • get传输的数据受url长度的限制,而post请求可以传输大量的数据
  • get请求不安全,但速度快,post请求安全,但速度较低

Jsp的四大作用域

  • page:代表当前页面的对象和数据
  • request:发出的一个请求相关的对象和属性
  • session:和服务器建立的一次会话的对象和属性,相关数据存放在session中
  • application:代表服务器全局的对象和数据

Cookie和Session的区别

  • Cookie的数据保存在客户端,Session的数据保存在服务端
  • cookie没有session安全
  • 单个cooke保存的数据不能超过4k,很多浏览器限制20个cookie,session会占据服务器的资源

谈谈你对Spring的理解

核心:IOC AOP

IOC

  • 管理对象的创建和依赖关系的维护
  • 解耦,由容器去维护具体的对象
  • IOC 或 依赖注入把应用的代码量降到最低。

AOP

  • 面向切面编程,作为面向对象的一种补充
  • 用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,
  • 这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。
  • 可用于权限认证、日志、事务处理等。

AOP有哪些通知类型

  • @Before — 前置通知,在连接点方法前调用;
  • @Around — 环绕通知,它将覆盖原有方法,但是允许你通过反射调用原有方法;
  • @After — 后置通知,在连接点方法后调用;
  • @AfterReturning — 返回通知,在连接点方法执行并正常返回后调用,要求连接点方法在执行过程中没有发生异常;
  • @AfterThrowing — 异常通知,当连接点方法异常时调用。

@Autowired和@Resource注解的区别是什么

  • @Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false),它是Spring依赖中的注解

  • @Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入,它是javax依赖中的注解

@Component 和 @Bean 的区别

  • @Component 注解作用于类,而 @Bean 注解作用于方法、
  • @Bean的自定义性更强,当我们引用第三方库到容器时,只能通过 @Bean 来实现。
  • @Bean需要在**@Configuration注解类**中使用

@Qualifier 注解有什么作用

当您创建多个相同类型的 bean 并希望仅使用属性装配其中一个 bean 时,可以使用@Qualifier 注解和 @Autowired 通过指定应该装配哪个确切的 bean 来消除歧义。

Redis

redis有哪些数据类型

简单类型

  • String(字符串) :字符串
  • List(列表): 字符串列表,可头插法和尾插法
  • Set(集合) : 字符串无序集合,并且值不重复
  • Zset(有序集合): 字符串有序集合,并且值不重复
  • Hash(哈希表):一个hash里面 可以存储多个Map键值对

复杂类型

  • Geospatial(地理位置)
  • Hyperloglog(基数统计)
  • BitMaps(位图)

说一下redis的持久化

RDB 全称Redis DataBase。

  • 将某一时刻的内存快照,以二进制的方式写入磁盘

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wAseLKNY-1634278848244)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20211003204101823.png)]

AOF: 全名为Append Only File

  • 它用日志的形式来记录每一个写操作,将Redis执行过的命令进行记录(读操作不记录)
  • 数据安全,准确

AOF的文件比RDB大,并且恢复速度慢

AOF运行效率比RDB低

缓存穿透、缓存击穿、缓存雪崩是什么

缓存穿透

  • 缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。

缓存击穿

  • 缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力

缓存雪崩

  • 是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。

常返回后调用,要求连接点方法在执行过程中没有发生异常;

  • @AfterThrowing — 异常通知,当连接点方法异常时调用。

@Autowired和@Resource注解的区别是什么

  • @Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false),它是Spring依赖中的注解

  • @Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入,它是javax依赖中的注解

@Component 和 @Bean 的区别

  • @Component 注解作用于类,而 @Bean 注解作用于方法、
  • @Bean的自定义性更强,当我们引用第三方库到容器时,只能通过 @Bean 来实现。
  • @Bean需要在**@Configuration注解类**中使用

@Qualifier 注解有什么作用

当您创建多个相同类型的 bean 并希望仅使用属性装配其中一个 bean 时,可以使用@Qualifier 注解和 @Autowired 通过指定应该装配哪个确切的 bean 来消除歧义。

Redis

redis有哪些数据类型

简单类型

  • String(字符串) :字符串
  • List(列表): 字符串列表,可头插法和尾插法
  • Set(集合) : 字符串无序集合,并且值不重复
  • Zset(有序集合): 字符串有序集合,并且值不重复
  • Hash(哈希表):一个hash里面 可以存储多个Map键值对

复杂类型

  • Geospatial(地理位置)
  • Hyperloglog(基数统计)
  • BitMaps(位图)

说一下redis的持久化

RDB 全称Redis DataBase。

  • 将某一时刻的内存快照,以二进制的方式写入磁盘

在这里插入图片描述

AOF: 全名为Append Only File

  • 它用日志的形式来记录每一个写操作,将Redis执行过的命令进行记录(读操作不记录)
  • 数据安全,准确

AOF的文件比RDB大,并且恢复速度慢

AOF运行效率比RDB低

缓存穿透、缓存击穿、缓存雪崩是什么

缓存穿透

  • 缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。

缓存击穿

  • 缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力

缓存雪崩

  • 是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JAVA整理总结 的相关文章

  • Java中RandomAccessFile的并发

    我正在创建一个RandomAccessFile对象通过多个线程写入文件 在 SSD 上 每个线程都尝试在文件中的特定位置写入直接字节缓冲区 并且我确保线程写入的位置不会与另一个线程重叠 file getChannel write buffe
  • 检查发送到网页的请求数

    我正在编写一个 Java 多线程应用程序 它可以访问不同 Web 服务器的数百万个 有时甚至数十亿个 URL 这个想法是检查这些 URL 是否给出有效的 200OK 响应或 404 其他代码 我如何知道我的程序是否不会在他们的服务器上造成高
  • 通过 html tidy 提供渲染 jsp 页面

    我有一个在 Glassfish 上运行的 Java 项目 它会呈现一些难看的 HTML 这是使用各种内部和外部 JSP 库的副作用 我想设置某种渲染后过滤器 通过 HTMLTidy 提供最终的 HTML 这样源代码就很好且整洁 有助于调试
  • EL 通过 Scriptlet

    在 JSP 中使用 EL 相对于 scriptlet 的优势是什么 EL 被认为是无脚本语言 EL 使 JSP 免受容易出错原始 Java 代码并强制您根据 MVC 思想编写 JSP EL 或像 JSTL 这样的标签库 不可能实现的任何事情
  • 使用 Hibernate Dialect 设置表字符集/排序规则?

    我使用 Hibernate MySQLInnoDB Dialect 来生成 DDL hibernate cfg xml
  • SwingWorker 在另一个 SwingWorker 的 did 方法中

    首先 我需要通知您 我正在尽最大努力学习如何用 Java 编写代码 虽然有点困难 但我相信我能做到 我过去提交了几个有关 SwingWorkers 等的问题 每一个我都以为我已经做到了 但后来发现我仍然需要学习 希望这一次不是那样的一次 话
  • 为什么我要使用责任链而不是 switch 语句

    考虑一下您已经获得了多次验证 仅当要检查的对象属于某种类型时 这些验证才应生效 为什么我要使用责任链而不是 switch 语句 责任链示例 public class Executor Inject private ValidatorFact
  • 反应式 Spring Webflux REST 控制器内部重定向

    我正在为 spring 反应项目创建简单的控制器服务器 在设置重定向到另一个位置时 我在调用时发现错误http localhost 8080 There was an unexpected error type Internal Serve
  • 无法自动装配 org.springframework.mail.javamail.JavaMailSender

    尝试运行我的应用程序时遇到以下问题 所有的东西都调试过了 还是一无所获 IDE 毫无问题地找到了 bean 所以我对这里发生的情况感到非常困惑 SEVERE Exception sending context initialized eve
  • 两条腿的 OAuth 和 Gmail Atom feed

    我们正在尝试让 2 legged OAuth 与 Gmail Atom feed 一起使用 我们使用 John Kristian Praveen Alavilli 和 Dirk Ba lfanz 贡献的 Java 库 http oauth
  • 使用 JNI 从 Java 代码中检索 String 值的内存泄漏

    我使用 GetStringUTFChars 从使用 JNI 的 java 代码中检索字符串的值 并使用 ReleaseStringUTFChars 释放该字符串 当代码在 JRE 1 4 上运行时 不会出现内存泄漏 但如果相同的代码在 JR
  • java中日期转换dd-MMM-yyyy到dd-MM-yyyy

    在Java中将23 Mar 2011转换为23 03 2011的最简单方法是什么 感谢大家 这似乎解决了这个问题 try Calendar cal Calendar getInstance cal setTime new SimpleDat
  • Java LRU 缓存使用 LinkedList

    堆栈溢出的新手 所以请不要介意我以菜鸟的方式问这个问题 我正在尝试使用链表实现 LRU 缓存 我在这里看到了使用 linkedHashMap 和其他数据结构的其他实现 但对于这种情况 我正在尝试使用链表创建最佳优化版本 正如我在技术期间被问
  • 在 REST Web 服务中接受逗号分隔值

    我正在尝试接收 REST URI 中以逗号分隔值形式的字符串列表 示例 http localhost 8080 com vogella jersey first rest todo test 1 abc test 其中 abc 和 test
  • 如何使 JScrollPane 与嵌套 JPanel 一起正常工作?

    我正在使用 NetBeans 在 Java 中构建 Swing 应用程序 但我遇到布局问题 我的主框架包含一个JScrollPane其中包含一个JPanel called contentPanel其中又包含一个JPanel called l
  • 如何在 Log4j2 - JSON 布局中自定义或删除默认属性

    In Spring Boot 2我已配置的应用程序Log4j2 with JsonLayout像下面这样
  • Lucene/Hibernate 搜索锁定异常

    我使用 Hibernate Search 在 Web 应用程序上索引和全文搜索项目 没有问题 来自我的 pom xml
  • AndroidAnnotations 和 Dagger

    我正在尝试使用 Dagger 注入 Android 带注释的 Activity java lang IllegalArgumentException No inject registered for members com app serv
  • 获取Java中ResultSet返回的行数

    我用过一个ResultSet返回一定数量的行 我的代码是这样的 ResultSet res getData if res next System out println No Data Found while res next code t
  • 使用 PDFBox 在 Android 中创建 PDF

    我正在尝试通过我的 Android 应用程序创建 PDFPDFBoxapi 但出现以下错误 java lang NoClassDefFoundError org apache pdfbox pdmodel PDDocument 我已经将以下

随机推荐

  • 时序预测

    时序预测 MATLAB实现AR时间序列预测 目录 时序预测 MATLAB实现AR时间序列预测 基本介绍 程序设计 学习总结 参考资料 基本介绍 如果某个时间序列的任意数值可以表示自回归方程 那么该时间序列服从p阶的自回归过程 可以表示为AR
  • stable diffusion实践操作-常见lora模型介绍

    系列文章目录 本文专门开一节写Lora相关的内容 在看之前 可以同步关注 stable diffusion实践操作 文章目录 系列文章目录 前言 一 什么是lora 1 1 lora 定义 1 2 lora的基本原理 1 2 通过分层控制l
  • 面向对象(带参实例)——加减乘除运算

    实现加减乘除运算 代码如下 public class Daican int num1 int num2 public double cal String opr public double cal String opr int num1 i
  • 《信号与系统学习笔记》—信号与系统的时域和频域特性(二)

    注 本博客是基于奥本海姆 信号与系统 第二版编写 主要是为了自己学习的复习与加深 一 一阶与二阶连续时间系统 一 一阶连续时间系统 1 对于一个一阶系统 其微分方程往往表示成下列形式 区中t是一个系数 相应的一阶系统的频率响应是 其单位冲激
  • 锁的升级过程

    再此之前我们需要先了解一下什么是cas和aba 一 CAS 我们使用多线程来访问一个变量的时候 会出现相应的并发的情况 所以我们需要对这个变量进行加锁操作 但是我们也可以不进行加锁 我们先将查询到了的变量值放到内存中 然后将相应的然后我们要
  • ROS的ros_canopen调试

    Ros canopen是ros支持can通信的package 链接 http wiki ros org ros canopen distro indigo Ros canopen包结构如下 SocketCAN是一组开源的CAN驱动程序和网络
  • Linux内核中网络数据包的接收, 涉及到select/poll/epoll

    转自 https blog csdn net dog250 article details 50528280 与网络数据包的发送不同 网络收包是异步的的 因为你不确定谁会在什么时候突然发一个网络包给你 因此这个网络收包逻辑其实包含两件事 1
  • mysql 登录hang_MySQL客户端连接登入hang住原因分析

    作者 八怪 高鹏 中亦科技数据库专家 原文 https www jianshu com p 93b69955344b 一 问题来源 问题来自一位朋友 如下 mysql客户端无法登陆 查看服务器负载没有发现高负载信息 通过pstack查看线程
  • 普通人是否能从ChatGPT中分一杯羹?

    ChatGPT3 0刚刚推出 最开始的时候 人们只是将ChatGPT看作一个很会聊天的机器人 无论问题多么天马行空 它的答案看上去都有理有据 后来 像打开潘多拉魔盒一样 很多人开始拿它编大纲 撰写文案 编代码 创作剧本 写法律文书 还可以出
  • 服务器数据库怎么导入数据库文件路径,服务器数据库导入sql文件路径

    服务器数据库导入sql文件路径 内容精选 换一换 下载MySQL源码包 includes Boost Headers cd home wget https dev mysql com get Downloads MySQL 5 7 mysq
  • 多个线程访问共享对象和数据的方式

    一 如果每个线程执行的代码相同 可以使用同一个Runnable 对象 这个Runnable对象中有那个共享的数据 例如买票系统就可以这样做 代码如下 package com thread class ShareDataTest1 publi
  • 编译器架构的王者LLVM——(9)栈式符号表的构建

    LLVM平台 短短几年间 改变了众多编程语言的走向 也催生了一大批具有特色的编程语言的出现 不愧为编译器架构的王者 也荣获2012年ACM软件系统奖 题记 版权声明 本文为 西风逍遥游 原创文章 转载请注明出处 西风世界 http blog
  • Centos升级openssh的正确方式

    准备工作 升级ssh可能会造成服务器无法连接 如果不能直接操作服务器 请开启telnet或者vnc 查看openssl版本 openssl version 在这里下载1 0 2版本 https www openssl org source
  • Spring的AOP五大通知注解

    通知注解 声明方法 在方法前加入通知注解 指定要拦截的对象信息 注意 代表任意修饰符号 任意值 AOP五大通知注解 Before 前置通知 在方法执行之前执行 After 后置通知 在方法执行之后执行 无论是否发生异常 还不能访问目标方法执
  • C++复合模式:Compound Pattern

    模式通常被一起使用 并被组合在同一个设计解决方案中 复合模式在一个解决方案中结合两个或多个模式 以解决一般或重复发生的问题 注 是为了解决一般或重复发生的问题 而不是简单的认为使用了多个模式就是复合模式 绝不要为了使用模式而使用模式 具体问
  • 基于 Flask 的简易 Mock 平台

    https testerhome com topics 14753
  • Linux——md5命令

    文章目录 介绍 选项 使用案例 生成文件md5值 文本模式或二进制模式 md5值重定向 重定向追加 md5校验 实际开发场景 介绍 md5sum命令用于生成和校验文件的md5值 它会逐位对文件的内容进行校验 是文件的内容 与文件名无关 也就
  • KEIL软件中编译时出现的Error L6200E: symbol multiply defined ...的解决方法

    今天在编程的时候遇到了这个问题 在网上查找了好多办法 都没有什么效果通过ctrl f 发现自己并没有重新定义 而且这两个 c文件都是移植且可以用的 然后我就准备一点一点的删mian c中的内容 看看是哪的问题 当我删掉 include lc
  • 前后端时间比较大小

    前端 this createdTime response createdTime 获取到时间的值 const onLineDate 2023 04 11 23 00 00 if moment this createdTime gt mome
  • JAVA整理总结

    文章目录 JavaSE 面向对象的特点是什么 和equals的区别 String str i 与 String str new String i 一样吗 String 类的常用方法都有那些 Integer a 127 与 Integer b