【 java 基础问题 第二篇 】

06-02 165阅读

目录

1.深拷贝和浅拷贝

1.1.区别

定义

定义

1.2.实现深拷贝的方式

2.泛型

2.1.定义

2.2.作用

 3.对象

3.1.创建对象的方式

3.2.对象回收

3.3. 获取私有成员

4.反射

4.1.定义

4.2.特性

4.3.原理

5.异常

5.1.异常的种类

5.2.处理异常的方法

6.Object

6.1.等于与equals()区别

6.2.hashcode()与equals()关系

6.3String、StringBuffer、StringBuilder的区别

 7.序列化

7.1.JVM之间的传递对象

 8.设计模式

9.I/O

9.1.实现网络IO高并发编程

9.2.BIO、NIO、AIO区别


1.深拷贝和浅拷贝

1.1.区别

例子:你需要将一个对象拷贝到一个新的对象里(类型相同),你选择浅拷贝,那么它就是将对原先的对象原封不动的拷贝过去(引用类型共享内存地址),而深拷贝就是基本类型复制,引用类型是先创建一个新的对象再将值复制过来

区别:引用类型拷贝区别:浅拷贝将地址拷过来(地址复用),深拷贝将值拷过来(创建一个新的对象,地址不复用)

浅拷贝

定义
  • 基本类型字段:直接复制值。

  • 引用类型字段:仅复制内存地址(新旧对象共享同一引用对象)。

  • 特点:修改原对象或拷贝对象中的引用字段时,另一方会同步变化。

    深拷贝

    定义
    • 基本类型字段:直接复制值。

    • 引用类型字段:递归创建新对象并复制所有层级数据(新旧对象引用独立对象)。

    • 特点:修改原对象或拷贝对象中的引用字段时,另一方不受影响。

      【 java 基础问题 第二篇 】

      1.2.实现深拷贝的方式

      • 实现 Cloneable 接口并重写 clone() 方法
        class Person implements Cloneable {
            String name;
            Address address;
            @Override
            public Person clone() {
                try {
                    Person cloned = (Person) super.clone();
                    // 深拷贝:递归克隆引用字段
                    cloned.address = this.address.clone();
                    return cloned;
                } catch (CloneNotSupportedException e) {
                    throw new AssertionError(); // 不会发生
                }
            }
        }
        class Address implements Cloneable {
            String city;
            @Override
            public Address clone() {
                try {
                    return (Address) super.clone();
                } catch (CloneNotSupportedException e) {
                    throw new AssertionError();
                }
            }
        }class Person implements Cloneable {
            String name;
            Address address;
            @Override
            public Person clone() {
                try {
                    Person cloned = (Person) super.clone();
                    // 深拷贝:递归克隆引用字段
                    cloned.address = this.address.clone();
                    return cloned;
                } catch (CloneNotSupportedException e) {
                    throw new AssertionError(); // 不会发生
                }
            }
        }
        class Address implements Cloneable {
            String city;
            @Override
            public Address clone() {
                try {
                    return (Address) super.clone();
                } catch (CloneNotSupportedException e) {
                    throw new AssertionError();
                }
            }
        }
        • 使用序列化和反序列化
          import java.io.*;
          class Person implements Serializable {
              String name;
              Address address; // Address 也需实现 Serializable
          }
          public class DeepCopyUtils {
              public static  T deepCopy(T obj) {
                  try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
                       ObjectOutputStream oos = new ObjectOutputStream(bos)) {
                      oos.writeObject(obj);
                      try (ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
                           ObjectInputStream ois = new ObjectInputStream(bis)) {
                          return (T) ois.readObject();
                      }
                  } catch (IOException | ClassNotFoundException e) {
                      throw new RuntimeException("Deep copy failed", e);
                  }
              }
          }
          // 使用示例
          Person original = new Person();
          Person deepCopy = DeepCopyUtils.deepCopy(original);
          • 手动递归复制
            class Person {
                String name;
                Address address;
                public Person deepCopy() {
                    Person copy = new Person();
                    copy.name = this.name;
                    copy.address = this.address.deepCopy(); // 手动递归复制
                    return copy;
                }
            }
            class Address {
                String city;
                public Address deepCopy() {
                    Address copy = new Address();
                    copy.city = this.city;
                    return copy;
                }
            }
            // 使用示例
            Person original = new Person();
            Person deepCopy = original.deepCopy();

            对比总结

            方法性能代码复杂度适用场景限制条件
            Cloneable 接口中等简单对象、可控的深拷贝需递归处理引用字段
            序列化/反序列化复杂对象图、完全深拷贝必须实现 Serializable
            手动递归复制精细控制拷贝逻辑、排除特定字段代码维护成本高

            2.泛型

            2.1.定义

            泛型是java中的一个特性,它允许在定义类和方法和接口时只需要指定一个或者多个类型参数(泛型符号)就行,在使用时再指定具体的类型

            2.2.作用

            当多个类需要共享相同代码逻辑时,可以通过定义泛型来实现。泛型允许在使用时指定具体类型,使不同类都能复用相同的代码逻辑。

            --------

            由于泛型在定义时使用类型参数而非具体类型,它可以接收任何类型参数而无需强制类型转换,从而避免了类型安全问题

             3.对象

            3.1.创建对象的方式

            • 通过new关键字创建对象
            • 通过克隆创建对象
            • 通过反射创建对象
            • 通过反序列化创建对象

              3.2.对象回收

              对象是由垃圾回收器回收,垃圾回收器会在程序运行时自动运行,周期性去检查对象是否被引用,没有就直接回收,释放内存

              垃圾回收器实现的主要的机制:

              ----

              1.引用计数法:它会根据该对象的引用计数,如果为0,代表没有被引用直接回收释放

              ---

              2.可达性分析算法:它会从根对象出发,根据根对象的属性和方法的引用链来判断,如果这个对象没有一个引用链那么代表没有被引用,直接回收释放内存

              ---

              3.终结器:在对象里面你可以重写finalize()方法,如果重写了该方法,那么垃圾回收器在回收该对象之前会先执行该方法,但是会出现一个问题,你清楚你的这个对象什么时候被回收吗?不确定时间,那么该方法执行的时间也不确定,因此会出现一些可能会出现的问题( 可能导致性能问题、死锁和资源争用),就比如性能问题,如果你在finalize()方法中释放了某些资源,但是由于不确定时间释放,就会导致一些性能问题(可能都不会释放)

              3.3. 获取私有成员

              由于定义的私有成员,那么只能该类内部访问,如果外部需要访问

              • 你对外提供方法来访问(比getter方法)
              • 你通过反射直接获取该成员

                4.反射

                4.1.定义

                反射就是可以获取任何一个类里面的全部信息(父类,实现的接口都可以),并且反射可以调用任何一个类里面的成员

                4.2.特性

                运行时类信息全知只要程序运行,那么通过反射就可以知道类里面全部信息
                动态的创建对象由于你知道信息,那么你通过反射也可以创建对象
                动态的调用方法也是因为知道全部信息,因此可以调用
                访问和修改字段值一样

                4.3.原理

                编译器会将源代码先编译成字节码,然后JVM根据字节码翻译成机器码,而反射就是通过字节码从而知道类的全部信息

                5.异常

                5.1.异常的种类

                【 java 基础问题 第二篇 】

                5.2.处理异常的方法

                • 使用try-catch-fianlly(包裹可能会出现异常的代码)

                • 手动抛出异常(throw)

                • 方法或类抛出异常(throws)

                  如果你使用try-catch-fianlly那么你需要注意:

                  当 try 代码块中的语句发生异常时,后续代码将不会执行,异常会立即传递给 catch 块。如果 catch 块未能捕获对应类型的异常,该异常会继续向上层抛出(例如方法b抛出的异常可被调用它的方法a捕获)。

                  ----

                  catch接收到异常那么就会执行catch里面的对应代码

                  ----

                  如果定义了fianlly,不管有没有异常,fianlly都会执行(常用于释放锁)

                  ----

                  执行顺序规则(fianlly,如果return在前,fianlly在后)

                  1. return 语句计算返回值:先将返回值存储到临时变量中。

                  2. 执行 finally 块:无论是否有 return 或异常,finally 都会执行。

                  3. 方法返回临时变量中的值:如果 finally 中没有新的 return,则返回最初的值;如果 finally 中有 return,则会覆盖原值。

                  6.Object

                  6.1.等于与equals()区别

                  等于就是:比较基本类型比值,比较引用类型比地址(比表面的)

                  而equals():你如果重写了该方法,那么比较引用类型时比较里面的属性值,没有重写与等于一样

                  6.2.hashcode()与equals()关系

                  前提:你如果要重写这其中的一个方法,那么另外一个也需要重写(约定)

                  一致性:当equals()比较对象相等时,那么hashcode也一定相等(本质就是根据内部值计算出哈希值,而内部值都相等了,你的哈希值肯定相等)

                  不一致性:当hasjcode相等时,equals()不一定相等,因为你不同的对象计算出来的哈希值可能相同(哈希冲突)

                  6.3String、StringBuffer、StringBuilder的区别

                  1.可变性

                  -----

                  解释:在Java中,String对象一旦创建就不可修改,具有不可变性。每次对String进行修改时,实际上都会创建一个新的String对象(数组也有类似特性)。

                  而StringBuffer、StringBuilder可变

                  2.线程安全性

                  ---

                  解释:由于String不可变,因此天然的线程安全, 而StringBuilder是线程不安全的(单线程来访问最好),StringBuffer是线程安全的,其内部方法(在StringBuilder方法上)实现了悲观锁synchronized

                  3.性能

                  ----

                  解释:由于String每次修改就需要创建一个新的对象,因此性能低, StringBuffer由于内部方法实现了锁(而锁本身就会影响性能),因此性能一般,StringBuilder性能最好

                   7.序列化

                  7.1.JVM之间的传递对象

                  1.使用序列化和反序列化

                  ---

                  解释:你先通过序列化将对象序列化成字节流存入文件中,再将文件传输,接收到文件后再将文件反序列化成对象即可

                  2.使用消息队列

                  ---

                  解释:使用消息队列( RabbitMQ、Kafka)来传递消息,另一边接收消息即可 

                  3.使用远程方法(RPC)

                  4.使用数据库(MYSQL)或缓存(Redis)

                  ---

                  解释:比如将对象之间存入数据库或缓存中,直接访问数据即可 

                   8.设计模式

                  代理模式:

                  • 目的:控制对象的访问或增加一些新的方法
                  • 内容:抽象主题,真实主题,代理三个角色

                    适配器模式:

                    • 目的:转换接口,是不兼容的类可以并行执行
                    • 内容:目标接口,适配器,被适配对象

                      9.I/O

                      9.1.实现网络IO高并发编程

                      使用NIO,NIO是同步非阻塞执行的,NIO 是基于I/O多路复用实现的,它可以只用一个线程处理多个客户端I/O,如果你需要同时管理成千上万的连接,但是每个连接只发送少量数据,例如一个聊天服务器,用NIO实现会更好一些。

                      9.2.BIO、NIO、AIO区别

                      BIO同步阻塞式执行
                      NIO同步非阻塞执行
                      AIO异步非阻塞执行

                      解释:

                      • 同步阻塞式执行:就是说你发完一个消息后,你会一直等待别人回你消息,并且在等待的过程中不会干任何事情
                      • 同步非阻塞执行:就是说你发完一个消息后,你会一直等待别人回你消息,但是在等待的过程中你可以做一些自己的事情
                      • 异步非阻塞执行:就是说你发完一个消息后,你不会等待别人回你消息
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码