Java总结

0、堆、栈、方法区

  堆:

  • 所有线程共享
  • 存储的是对象实例(Object)
  • 是垃圾回收(GC)的主要区域
  • 生命周期与对象一致,GC管理
  • 可以通过 -Xms 和 -Xmx 设置初始大小和最大大小

  栈:

  • 每个线程私有
  • 生命周期与方法调用一致
  • 方法调用产生栈帧,调用结束释放栈帧
  • 存储基本类型变量(如 intdouble)和对象引用(reference) 

  方法区:

   类结构、常量池、静态变量等

 类的加载顺序:

    父类静态变量,父类静态代码块,子类静态变量,子类静态代码块,父类实例变量赋值和实例代码块,父类构造函数,子类实例变量赋值和实例代码块,子类构造函数。

1、静态方法为什么不能调用非静态成员?

      静态方法是属于类的,在类加载的时候就会分配内存,可以通过类名直接访问。而非静态成员属于实例对象,只有在对象实例化之后才存在,需要通过类的实例对象去访问。
      在类的非静态成员不存在的时候静态方法就已经存在了,此时调用在内存中还不存在的非静态成员,属于非法操作。

2、接口和抽象类有什么共同点和区别?

     接口和抽象类的共同点

     实例化:接口和抽象类都不能直接实例化,只能被实现(接口)或继承(抽象类)后才能创建具体的对象。

     抽象方法:接口和抽象类都可以包含抽象方法。抽象方法没有方法体,必须在子类或实现类中实现。

     接口和抽象类的区别

     接口主要用于对类的行为进行约束,你实现了某个接口就具有了对应的行为。抽象类主要用于代码复用,强调的是所属关系。

    一个类只能继承一个类(包括抽象类),因为 Java 不支持多继承。但一个类可以实现多个接口,一个接口也可以继承多个其他接口。

     抽象类可以包含抽象方法和非抽象方法。抽象方法没有方法体,必须在子类中实现。非抽象方法有具体实现,可以直接在抽象类中使用或在子类中重写。

3、深拷贝和浅拷贝和引用拷贝

    浅拷贝,对于对象内部的引用类型的对象不拷贝,跟原对象使用同一个引用类型的对象。

  BeanUtils.copyProperties

    深拷贝,完全拷贝成新的对象。

    手动重新赋值

    json序列化 重新转成新对象

    引用拷贝,两个不同的引用指向同一个对象。

Person p1 = new Person("Tom", 20);
Person p2 = p1; // 引用拷贝

4、String   StringBuffer   StringBuilder 

String 中的对象是不可变的,也就可以理解为常量,线程安全。

  • 保存字符串的数组被 final 修饰且为私有的,并且String 类没有提供/暴露修改这个字符串的方法。
  • String 类被 final 修饰导致其不能被继承,进而避免了子类破坏 String 不可变。

StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。

5、try-catch-finally 如何使用?

try块:用于捕获异常。其后可接零个或多个 catch 块,如果没有 catch 块,则必须跟一个 finally 块。

catch块:用于处理 try 捕获到的异常。

finally 块:无论是否捕获或处理异常,finally 块里的语句都会被执行。当在 try 块或 catch 块中遇到 return 语句时,finally 语句块将在方法返回之前被执行。 finally里如果有return,则直接return了。不会执行 try 或 catch里的return了。

finally 之前虚拟机被终止运行,程序所在线程死亡,关闭cpu,finally 中的代码不会被执行。

6、Java反射

反射允许程序在运行时动态地加载类、创建对象、调用方法和访问字段。

许多现代 Java 框架(如 Spring、Hibernate、MyBatis)都大量使用反射来实现依赖注入(DI)、面向切面编程(AOP)、对象关系映射(ORM)、注解处理等核心功能。反射是实现这些“魔法”功能不可或缺的基础工具。控制反转IOC,注解@Service  @Controller @Mapper 等都依赖反射。

通过反射,可以编写更通用、可重用和高度解耦的代码,降低模块之间的依赖。例如,可以通过反射实现通用的对象拷贝、序列化、Bean 工具等。

7、BIO  NIO AIO

BIO  同步阻塞型IO模型。

NIO  同步非阻塞 IO 模型。 Netty框架

AIO 异步 IO 是基于事件和回调机制实现的

8、集合

List       

ArrayList  数组    

LinkedList 双向链表

Set

HashSet  (无序,唯一): 基于 HashMap 实现的,底层采用 HashMap 来保存元素。

LinkedHashSet   LinkedHashSet 是 HashSet 的子类,内部是通过 LinkedHashMap 来实现的。

TreeSet   (有序,唯一): 红黑树(自平衡的排序二叉树)。

Map

HashMap   1.8以前是数组+链表   1.8以后是红黑树   初始大小是16,每次扩容都是2倍。不保证任何顺序。

当链表长度大于等于阈值(默认为 8)(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间。

LinkedHashMap   继承自 HashMap,双向链表,保证有序。

TreeMap 红黑树  有序

Hashtable:这是 HashMap 的一个线程安全版本,所有方法都是同步的。与 HashMap 不同的是,Hashtable 不允许键或值为 null。

 ConcurrentHashMap:提供了一种高效且线程安全的哈希表实现。  

map遍历

0、Lambda

 map.forEach((key, value) -> {
            System.out.println(key);
            System.out.println(value);
        });

1、for each

for (Map.Entry<Integer, String> entry : map.entrySet()) {
            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
        }

2、迭代器

Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Integer, String> entry = iterator.next();
            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
        }

9、多线程

传统方式 继承 Thread 类和实现 Runnable 接口 重写run()

现在 使用 Executors 工具类来创建不同类型的线程池,如固定大小的线程池、缓存线程池等。

还可以使用线程池。通过 ThreadPoolExecutor 构造函数直接创建 (推荐)

Thread#sleep() 方法和 Object#wait()

  • sleep() 方法没有释放锁,而 wait() 方法释放了锁 。

  wait() 方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的 notify()或   者 notifyAll() 方法。

直接调用run()不会启动多线程,要调用start()才启动。

死锁:线程互相等待。  避免死锁:破坏循环等待条件

乐观锁和悲观锁

乐观锁 基于CAS算法实现。  悲观锁:每次访问都要上锁,synchronized

数据库

ACID  原子性 一致性 隔离性 持久性 

事务级别   读未提交 读已提交 可重复读(默认的隔离级别) 可串行化

mysql

创建数据库、表 删除数据库、表,索引、视图  create drop

-- 添加字段
ALTER TABLE users ADD COLUMN age INT AFTER name;

-- 删除字段
ALTER TABLE users DROP COLUMN age;

-- 修改字段类型或位置
ALTER TABLE users MODIFY COLUMN age VARCHAR(3);

当前默认的存储引擎是 InnoDB。并且,所有的存储引擎中只有 InnoDB 是事务性存储引擎,也就是说只有 InnoDB 支持事务。

三大范式

第一范式(1NF): 数据库表中的字段都是单一值。

第二范式(2NF):非主键字段需完全依赖于主键。

第三范式(3NF):一个非主键字段不能依赖另一个非主键字段。

索引

单表索引最好不超过5个。对于频繁的查询,优先考虑使用覆盖索引就是包含了所有查询字段 (where、select、order by、group by 包含的字段) 的索引

聚簇索引:索引和数据一起存放的索引,如主键索引。聚簇索引默认使用的是 B+Tree 索引。

非聚簇索引:索引结构和数据分开存放的索引,普通、唯一、复合、覆盖。

索引失效

  • 创建了组合索引,但查询条件未遵守最左匹配原则;
  • 在索引列上进行计算、函数、类型转换等操作;
  • 以 % 开头的 LIKE 查询比如 LIKE '%abc';
  • 查询条件中使用 OR,且 OR 的前后条件中有一个列没有索引,涉及的索引都不会被使用到;
  • IN 的取值范围较大时会导致索引失效,走全表扫描(NOT IN 和 IN 的失效场景相同);

最左索引

联合索引的最左匹配原则,在遇到范围查询(如 >、<)的时候,就会停止匹配,也就是范围查询的字段可以用到联合索引,但是在范围查询字段后面的字段无法用到联合索引。注意,对于 >=、<=、BETWEEN、like 前缀匹配的范围查询,并不会停止匹配。

Redis

缓存击穿:热点key失效,短时间大量请求数据库。   热点key提前预热或不过期

缓存穿透:无效的key 访问数据库。 缓存无效的key或者使用布隆过滤器

缓存雪崩:大量key集中失效。  redis集群或设置随机失效时间或提前预热

常见的缓存预热方式有两种:使用定时任务,比如 xxl-job,来定时触发缓存预热的逻辑,将数据库中的热点数据查询出来并存入缓存中。使用消息队列,比如 Kafka,来异步地进行缓存预热,将数据库中的热点数据的主键或者 ID 发送到消息队列中,然后由缓存服务消费消息队列中的数据,根据主键或者 ID 查询数据库并更新缓存。

Redis 中比较常见的数据类型有下面这些:

  • 5 种基础数据类型:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。
  • 3 种特殊数据类型:HyperLogLog(基数统计)、Bitmap (位图)、Geospatial (地理位置)。

Redis 采用的是那种删除策略呢

Redis 采用的是 定期删除+惰性/懒汉式删除 结合的策略。

    评论
    成就一亿技术人!
    拼手气红包6.0元
    还能输入1000个字符
     
    红包 添加红包
    表情包 插入表情
     条评论被折叠 查看
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值