Java基础(笔记)

本文详述了Java的基础知识,包括值传递、字符串不可变性、包装类的缓存机制、switch对String的支持、HashSet的工作原理以及Collection与Collections的区别。此外,还探讨了枚举在单例模式中的应用、序列化与反序列化、IO流、线程安全问题,以及Netty和API/SPI等高级主题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

根据链接 Java 工程师成神之路!的目录复习Java基础,并记录下一些笔记供以后翻阅。

 

  Part1

 

  • Java值传递

        无论是值传递还是引用传递,其实都是一种求值策略(Evaluation strategy)。在求值策略中,还有一种叫做按共享传递(call by sharing)。其实Java中的参数传递严格意义上说应该是按共享传递。Java值传递

        按共享传递,是指在调用函数时,传递给函数的是实参的地址的拷贝(如果实参在栈中,则直接拷贝该值)。在函数内部对参数进行操作时,需要先拷贝的地址寻找到具体的值,再进行操作。如果该值在栈中,那么因为是直接拷贝的值,所以函数内部对参数进行操作不会对外部变量产生影响。如果原来拷贝的是原值在堆中的地址,那么需要先根据该地址找到堆中对应的位置,再进行操作。因为传递的是地址的拷贝所以函数内对值的操作对外部变量是可见的。

        简单点说,Java中的传递,是值传递,而这个值,实际上是对象的引用。

  • 字符串不可变

        一个字符串在堆中开辟了空间,就是不可改变的,所有的方法都不可能改变它的值,但是我们可以返回一个新的字符串。

        String str1 = "abcd";String str2 = "abcd";两个字符串对象str1和str2其实指向的是同一个字符串对象,当修改一个时,另一个也会变,所以不可变;并且不变的hashcode值便于找到这个字符串。

        String 类底层是一个 final 修饰的 char 类型数组,意味着 String 类的对象是不可变的,所以 String 对象可以共享。

        String 类中的每一个看起来会修改 String 值的方法,实际上都是创建了一个全新的 String 对象,用来包含修改后的字符串内容,这也可以说明 String 对象具有只读的属性。

  • JDK 6 中的 substring 问题

        jdk6的问题是大字符串,会被一直引用而没办法被垃圾回收,jdk7解决了这个问题。

  • 包装类型自动拆装箱与Integer 的缓存机制

      Integer、Long等Interger类型缓存-128到128之间的数值,这个区间中的数值指向的都是同一个对象,当超出范围才新建对象。Double、Float则没有缓存。

  • switch 对 String 的支持

       将字符串的hash值代替int从而进行判断,本质上还是int。

  • HashSet保持元素不重复

       在向hashSet中add()元素时,判断元素是否存在的依据,不仅仅是hash码值就能够确定的,同时还要结合equles方法。使用的是HashMap的put方法,HashMap也不重复。

  • Collection 和 Collections 区别

        Collections是collection的工具类,用来操作collection,不能实例化。collection是集合类的顶级接口。

  • Arrays.asList使用避坑

        1、使用包装类数组,不能使用基本类型,基本类型没有class属性;2、Arrays.asList返回的List实际是Arrays的一个内部类,不是真正的util.ArrayList,使用如下代码

List<String> myList = new ArrayList<String>(Arrays.asList(myArray));

代替,否则Arrays.asList直接返回的是一个固定大小的List,不具备可扩容性,add和remove方法都会失败。

  • Enumeration 和 Iterator 区别

        Iterator 遍历时可以删除元素,Enumeration 不可以,但 Enumeration 比 Iterator 快2倍左右。

  • fail-fast 和 fail-safe

        Iterator 遍历集合的时候,我们对集合结构上(集合的插入和删除是结构改变,修改不是)做出了改变,报 fail-fast(快速失败)错误;fail-safe 在这种情况下,复制一份新的集合进行遍历,不会报错。

  • ConcurrentSkipListMap

        跳表SkipList,redis也在用这种数据结构,和红黑树效率相当,实现简单。

  • CopyOnWrite并发容器

        CopyOnWriteArrayList写时复制,当有新元素添加到List时,先从原有的数组中拷贝一份出来,然后在新的数组做写操作,写完之后,再将原来的数组引用指向到新数组,适用于读多写少。写操作多,或者数组很大的时候,拷贝的数组占用内存。

  • 枚举与单例模式

        枚举实现的单例,写法简单且线程安全,因为枚举类在被虚拟机加载的时候会保证线程安全的被初始化。并且Java中有明确规定,枚举的序列化和反序列化是有特殊定制的,这就可以避免反序列化过程中由于反射而导致的单例被破坏问题。

        类加载的loadClass方法使用了同步代码块,所以Java类的加载和初始化过程都是线程安全的。

        普通的Java类的反序列化过程中,会通过反射调用类的默认构造函数来初始化对象。

        枚举在序列化的时候Java仅仅是将枚举对象的name属性输出到结果中,反序列化的时候则是通过java.lang.Enum的valueOf方法来根据名字查找枚举对象。

  • 枚举的实例化

        枚举有严格的实例化控制,final确保不会被克隆,而且序列化机制保证不会因为反序列化而创造新的实例,枚举的反射实例化也是被禁止的。总之,除了定义的枚举常量之外。没有枚举类型实例。

  • 枚举的比较

        使用 ==,比equals快且能正常工作,运行时安全、编译器安全。

  • 字符和字节

        java中,一个字符(char),一个字节(byte),GBK编码格式下,一个char是2个字节。

  • IO流

        InputStream  -> OutputStream ;   Reader -> Writer 。

              字节输入 -> 字节输出            字符输入  -> 字符输出。

  • 同步、异步、阻塞、非阻塞、IO多路复用

       点击链接 Java|网络IO之同步、异步、阻塞、非阻塞

 

  Part2

 

  • Externalizable 和 Serializable

       序列化是针对Java对象的,反序列化(IO输入)与序列化(IO输出),序列化是对象转换成二进制字节码,反序列化相反。String、Array、Enum可以直接序列化。序列化不保存静态变量。序列化会破坏单例。

        Serializable接口只用来标识该类是否可序列化,没有其他含义。Externalizable继承了Serializable,当类实现了Externalizable接口时,可以自定义序列化和反序列化的方法。

  • 为什么需要序列化呢?

        第一种情况是:一般情况下Java对象的声明周期都比Java虚拟机的要短,实际应用中我们希望在JVM停止运行之后能够持久化指定的对象,这时候就需要把对象进行序列化之后保存。

        第二种情况是:需要把Java对象通过网络进行传输的时候。因为数据只能够以二进制的形式在网络中进行传输,因此当把对象通过网络发送出去之前需要先序列化成二进制数据,在接收端读到二进制数据之后反序列化成Java对象。

  • 外观/门面模式:简化调用 
  • Protobuf传输协议:PB数据保存小、传输快,结构比JSon复杂。
  • 反序列化的安全问题

        最常见的是通过修改序列化之后的数据字段,从而进行提权或越权操作,最严重可导致远程代码执行。防御方案是完整性校验,常见的是JWT。

  •  Java 消息服务

        同步消息rpc,异步消息jms/amqp。JMS是指两个应用程序之间的通信。activeMq用法和JMS相似,activeMq需要下载且有可视化界面。

JMS消息传递模型
消息传递模型生产者/消费者目的地    时间约束
点对点一对一队列Queue
发布/订阅一对多主题Topic订阅者在发布者之前
  • 泛型

        泛型的上限,? extends E,接受E或E的子类型;下限,? super E,接受E或E的父类型。

        泛型擦除,泛型只在编译器有用,运行时会将类型擦除。泛型可以在编译器指定类型,消除了用Obejct编写时的类转换错误(运行期错误),而且相比Object不用强制类型转换。

        泛型的定义可以参考链接 Java泛型中List、List<Object>、List<?>的区别

  •  泛型的KTVE

        E - Element (在集合中使用,因为集合中存放的是元素)

        T - Type(Java 类)

        K - Key(键)

        V - Value(值)

       ? -  表示不确定的java类型

  • List、List<Object>、List<?>的区别

        List:原生态类型

        List<Object>:参数化的类型,表明List中可以容纳任意类型的对象

        List<?>:无限定通配符类型,表示只能包含某一种未知对象类型

  • Netty

        Netty封装了JDK的NIO,Netty是一个异步事件驱动的网络应用框架,用于快速开发可维护的高性能服务器和客户端。

  • API 和 SPI 
  • 格林威治时间GMT,世界标准时间
  • SimpleDateFormat 的线程安全性

        SimpleDateFormat转换日期是通过同一个Calendar对象来操作的,线程不安全;解决方法是给每个线程一个新的SimpleDateFormat对象,也可以使用java8。java.util.DateSimpleDateFormatter都不是线程安全的,而LocalDateLocalTime和最基本的String一样,是不变类型,不但线程安全,而且不能修改。

 

说明:01基础篇已粗略复习完,由于内容太多,以后不写在本篇博客里了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值