• springboot项目面试题


    1.简述什么事springboot?

    Spring Boot是一个用于构建独立的、基于Spring Framework的生产级别的应用程序的框架。它提供了一种简化的方式来创建和配置Spring应用程序,使开发者能够更快速、更轻松地构建Spring应用程序。

    Spring Boot的主要目标是简化Spring应用程序的开发过程,通过提供默认的配置和自动化的配置方式,减少了繁琐的XML配置,并提供了一种约定优于配置的方式来快速开发应用程序。它还提供了一套强大且易于使用的命令行工具,可以用于创建、运行和管理Spring Boot应用程序。

    Spring Boot具有以下特点:

    1. 简化配置:Spring Boot通过提供默认的配置和自动配置来简化应用程序的配置过程,开发者只需关注业务逻辑,无需手动配置底层的框架和组件。

    2. 内嵌服务器:Spring Boot内置了多个常用的Web服务器,如Tomcat、Jetty等,开发者无需手动配置,即可快速启动和运行Web应用程序。

    3. 自动装配:Spring Boot提供了自动装配机制,根据类路径中的依赖自动配置应用程序,简化了依赖包管理和配置文件的编写工作。

    4. 组件集成:Spring Boot集成了多个常用的组件和框架,如Spring Data、Spring Security、Spring MVC等,使开发者能够更方便地使用这些组件来构建应用程序。

    5. 健康监测:Spring Boot提供了健康监测的功能,可以通过HTTP端点实时监测应用程序的运行状态。

    总之,Spring Boot通过简化配置、提供默认设置和自动化配置等方式,使得开发者能够更加快速、高效地构建和部署Spring应用程序。它的设计目标是提高开发效率、减少样板代码,并提供一种简单的方式来创建和管理Spring应用程序。

    1.2Spring Boot、Spring MVC和Spring的区别?

    Spring Boot、Spring MVC和Spring是Spring Framework的三个不同的部分,它们之间有以下区别:

    1. Spring:Spring是一个开源的Java应用程序开发框架。它提供了一种轻量级的解决方案,用于构建企业级Java应用程序。Spring提供了一个容器来管理应用程序中的对象,并提供了一系列的模块来处理不同的功能,如数据访问、事务管理、Web开发等。

    2. Spring MVC:Spring MVC是Spring Framework的一个模块,用于构建Web应用程序。它采用了经典的MVC(Model-View-Controller)设计模式,将应用程序的逻辑分成三个部分:模型(Model),视图(View)和控制器(Controller)。Spring MVC提供了一套强大的API,用于处理Web请求、渲染视图、处理表单提交等。

    3. Spring Boot:Spring Boot是一个用于构建独立的、基于Spring Framework的生产级别的应用程序的框架。它提供了一种简化的方式来创建和配置Spring应用程序,使开发者能够更快速、更轻松地构建Spring应用程序。Spring Boot通过提供默认配置和自动配置,减少了繁琐的XML配置,并提供了一种约定优于配置的方式来快速开发应用程序。

    总结起来,Spring是整个框架,提供了基础的IoC(控制反转)和AOP(面向切面编程)功能;Spring MVC是Spring Framework的一个模块,用于构建Web应用程序,处理Web请求和渲染视图;Spring Boot是基于Spring Framework的一个框架,提供了一种简化的方式来创建和配置Spring应用程序,加速开发过程。

    1.3java问什么不直接实现iterator接口,而是实现iterable?

    Java中为了增加代码的灵活性和易用性,设计了迭代器模式。迭代器模式允许我们对集合进行遍历,而无需暴露底层集合的细节。Java中的Iterable接口是用来支持迭代器模式的关键接口,而Iterator接口是Iterable接口的一部分。

    Java中的集合类实现Iterable接口的主要原因如下:

    1. 提供可迭代性:通过实现Iterable接口,类可以告诉**编译器和其他开发者,它是一个可迭代的类,**可以使用增强的for循环来遍历其元素。这使得代码更加易读和简洁。

    2. 支持多次迭代:Iterable接口要求类能够返回一个新的Iterator对象,该对象可以用于多次迭代。这样可以方便地对集合进行多次遍历,而不需要重新创建集合的副本。

    3. 隐藏底层实现:Iterable接口允许类隐藏其底层集合的实现细节。这样可以提高代码的封装性和安全性,同时也使得代码更加模块化和可维护。

    总的来说,通过实现Iterable接口,Java的集合类可以提供更好的可迭代性和灵活性,同时隐藏底层实现细节,使代码更加易读和模块化。这样可以提高代码的可维护性和可扩展性。

    1.4面试题:hashCode()和equals()方法的重要性体现在什么地方?

    简介:

    hashCode与equals这一对看似作用相同但细品却有着很大的区别,都是值比较而你我却有着不同的衡量标准。不如我们一起约定一个规则,来更好的为程序服务吧

    有这么两个结论:

    1、equals相等的两个对象他们的hashCode肯定相等,因此equals是绝对可靠的。

    2、hashCode相等的两个对象他们的equals不一定相等,因此hashCode不是绝对可靠的。

    什么是HashCode(哈希码)

    hashCode()的作用就是获取哈希码,它是一个int整数。这个哈希码的作用是确定该对象在散列表中的索引位置。hashCode定义在java.Object中,意味着每个类都有hashCode函数。

    public class Demo{
    public static void main (String []args){
    String str = “aa”;
    System.out,println(str.hashCode())
    }
    }

    3104
    什么是equals

    判断两个对象是否相等,就是“==”,两个对象的地址是否相同;如果对象重写了equals()的方法,则比较对象的内容是否相等。同样的equals定义在java.Object中,Java中任何类都有equals方法。

    下图是不重写equals()的方法

    那么由于两个对象的地址不同,所以得到的hashCode不同,即使他们的name一样,但是“==”与“equals()”都不相等,返回为false.

       如果我们想要两个name相等的两个对象让它被系统认为是同一个,即调用equals()方法或者“==”时返回true,那么就需要重写equals方法了。而且在很多的情景下,我们判断两者是不是同一个name时,不需要判断其他信息,比如地址。怎么重写呢?
    
    • 1

    重写equals()方法还需要满足几个条件

    自反性:对于任意的非空引用x, x.equals(x)返回为true。

    对称性:对于任意引用x和y, x.equals(y)返回true,则y.equals(x)返回也应该为true。

    传递性:对于任意引用x,y和z,如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)也应该返回true。

    一致性:如果x和y引用的对象没有发生变化,那么反复调用x.equals(y)得到的结果不变。

    非空性:对于任意非空引用x, x.equals(null)的结果应该为false。

    重写equals方法就必须重写hashCode方法,因为你返回true那么地址值也要相等这样的条件才能保证equals相等

    1.4Hashtable、HashMap、LinkedHashMap 的区别和不同

    Hashtable、HashMap和LinkedHashMap都是Java集合框架中用于存储键值对的类,它们的主要区别和不同点如下:

    1. 线程安全性:

      • Hashtable:Hashtable是线程安全的,它的方法都是同步的,适用于多线程环境。多个线程可以同时访问同一个Hashtable实例而不会导致数据不一致的问题。
      • HashMap:HashMap是非线程安全的,它的方法都不是同步的,不适用于多线程环境。如果多个线程同时访问同一个HashMap实例,可能会导致数据不一致的问题。
      • LinkedHashMap:LinkedHashMap是非线程安全的,与HashMap的线程安全性相同。
    2. 插入顺序:

      • Hashtable和HashMap:Hashtable和HashMap不保证元素的插入顺序,即元素的迭代顺序可能与插入顺序不一致。
      • LinkedHashMap:LinkedHashMap保持元素的插入顺序,即元素的迭代顺序与插入顺序一致。
    3. 底层实现:

      • Hashtable:Hashtable使用链表数组实现,通过哈希函数将键映射到链表数组的索引位置。
      • HashMap:HashMap也使用链表数组实现,但它引入了"拉链法"和"红黑树"的概念,当链表长度超过一定阈值时,链表会转换为红黑树,以提高查找效率。
      • LinkedHashMap:LinkedHashMap继承自HashMap,底层实现与HashMap相同,但它使用链表维护元素的插入顺序。
    4. 允许键和值为null:

      • Hashtable:Hashtable不允许键或值为null。
      • HashMap和LinkedHashMap:HashMap和LinkedHashMap允许键和值为null。

    综上所述,Hashtable是线程安全的、不保证元素插入顺序的类;HashMap是非线程安全的、不保证元素插入顺序的类;LinkedHashMap是非线程安全的、保持元素插入顺序的类。根据具体的需求,选择合适的类使用。

    Hashtable和HashMap是Java集合框架中用于存储键值对的类,它们的区别如下:

    1. 线程安全性:
      • Hashtable:Hashtable是线程安全的,它的方法都是同步的,适用于多线程环境。多个线程可以同时访问同一个Hashtable实例而不会导致数据不一致的问题。
      • HashMap:HashMap是非线程安全的,它的方法都不是同步的,不适用于多线程环境。如果多个线程同时访问同一个HashMap实例,可能会导致数据不一致的问题。

    下面举例说明Hashtable和HashMap的区别:

    import java.util.Hashtable;
    import java.util.HashMap;
    import java.util.Map;
    
    public class HashTableVsHashMapExample {
        public static void main(String[] args) {
            // Hashtable例子
            Hashtable<String, String> hashtable = new Hashtable<>();
            hashtable.put("key1", "value1");
            hashtable.put("key2", "value2");
            
            System.out.println(hashtable.get("key1")); // 输出: value1
            
            // HashMap例子
            HashMap<String, String> hashMap = new HashMap<>();
            hashMap.put("key1", "value1");
            hashMap.put("key2", "value2");
            
            System.out.println(hashMap.get("key1")); // 输出: value1
            
            // 多线程环境下的Hashtable例子
            Runnable runnable1 = new Runnable() {
                @Override
                public void run() {
                    System.out.println(hashtable.get("key1")); // 输出: value1
                }
            };
            
            Runnable runnable2 = new Runnable() {
                @Override
                public void run() {
                    System.out.println(hashtable.get("key2")); // 输出: value2
                }
            };
            
            Thread thread1 = new Thread(runnable1);
            Thread thread2 = new Thread(runnable2);
            
            thread1.start();
            thread2.start();
            
            // 多线程环境下的HashMap例子
            Runnable runnable3 = new Runnable() {
                @Override
                public void run() {
                    System.out.println(hashMap.get("key1")); // 输出: value1 或者 null
                }
            };
            
            Runnable runnable4 = new Runnable() {
                @Override
                public void run() {
                    System.out.println(hashMap.get("key2")); // 输出: value2 或者 null
                }
            };
            
            Thread thread3 = new Thread(runnable3);
            Thread thread4 = new Thread(runnable4);
            
            thread3.start();
            thread4.start();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    在上述例子中,Hashtable和HashMap都能够成功存储键值对,并且通过键获取值。然而,在多线程环境下,**Hashtable能够保证数据的一致性,两个线程同时访问Hashtable实例时,**得到的值都是正确的。而HashMap则可能出现数据不一致的情况,两个线程同时访问HashMap实例时,有可能得到的值是正确的,也有可能是null,这取决于线程之间的竞争情况。

    因此,在多线程环境下,如果需要保证数据一致性,可以选择使用Hashtable;如果不需要考虑线程安全性,可以选择使用HashMap。

    1.5 基本数据类型和Object的关系

    基本数据类型和Object是Java中两种不同的数据类型,它们之间存在着一定的关系。具体如下:

    1. 基本数据类型是Java语言中的原始数据类型,包括boolean、byte、short、int、long、float、double和char。这些基本数据类型是直接存储值的,它们不是对象,没有方法和属性。

    2. Object是Java中的根类,是所有类的直接或间接父类。它是一个通用的引用类型,可以引用任何类型的对象,包括基本数据类型的包装类。

    3. 基本数据类型的包装类是由Java为每个基本数据类型提供的对应类,用于将基本数据类型转换为对象以便操作。包装类包括Boolean、Byte、Short、Integer、Long、Float、Double和Character。

    4. 基本数据类型的包装类都继承自Object类,因此它们都可以被当作Object来使用。这意味着可以将基本数据类型的包装类作为方法的参数或返回值,也可以将其存储在集合类中。

    5. 在需要将基本数据类型作为对象处理的时候,可以使用基本数据类型的包装类来封装成对象。这样就可以使用一些Object类提供的方法,比如toString()、equals()等。

    下面是一个示例代码,展示了基本数据类型和Object之间的关系:

    public class BasicTypeAndObjectExample {
        public static void main(String[] args) {
            // 基本数据类型
            int num = 10;
            
            // 基本数据类型的包装类
            Integer numObject = new Integer(num);
            
            // 基本数据类型的包装类作为Object使用
            Object obj = numObject;
            
            System.out.println(obj.toString()); // 输出: 10
            System.out.println(obj.equals(new Integer(10))); // 输出: true
            
            // 将基本数据类型封装成对象
            Integer numObject2 = Integer.valueOf(20);
            
            // 基本数据类型的包装类作为方法参数
            printNumber(numObject2);
        }
        
        public static void printNumber(Object obj) {
            System.out.println(obj.toString());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在上述示例中,首先使用基本数据类型int来存储一个整数,并通过Integer类将其封装为对象。然后,将该对象赋值给Object类型的变量,通过Object类提供的方法来操作该对象。最后,将基本数据类型的包装类作为方法的参数传递给printNumber()方法,并在方法内部将其当作Object来使用。

    通过包装类,我们可以将基本数据类型转换为对象,从而可以使用Object类的方法和特性。这种转换在某些需要对象操作的场景中非常有用。

    1.6byte基本数据类型有没有getclass 方法

    基本数据类型byte本身是一个基本数据类型,不是对象,因此没有getClass()方法。getClass()方法是Object类定义的方法,用于返回一个对象的运行时类。只有引用类型(即对象)才可以调用该方法,基本数据类型没有这个方法可供调用。

    然而,byte有对应的包装类Byte,它是byte的包装类。Byte类是Object类的子类,因此可以调用getClass()方法。该方法返回一个Class对象,表示包装类的运行时类。

    以下是一个示例代码,展示了基本数据类型byte和包装类Byte的getClass()方法的不同使用方式:

    public class ByteExample {
        public static void main(String[] args) {
            byte num = 10;
            Byte byteObj = new Byte(num);
            
            // 基本数据类型调用getClass()方法,会编译错误
            // byte类没有getClass()方法
            // System.out.println(num.getClass());
            
            // 包装类调用getClass()方法,返回运行时类
            System.out.println(byteObj.getClass()); // 输出: class java.lang.Byte
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在上述示例中,首先定义了一个基本数据类型byte并初始化为10。由于基本数据类型byte没有getClass()方法,所以在尝试调用num.getClass()时会导致编译错误。然后,创建了一个Byte对象byteObj,通过byteObj.getClass()调用getClass()方法,返回一个Class对象,表示包装类Byte的运行时类。最后,将结果打印出来,输出为"class java.lang.Byte"。

    1.7java中的堆栈的理解举例说明

    在Java中,堆(Heap)和栈(Stack)是两种常用的内存管理方式。它们用于存储不同类型的数据或者对象,并且在内存中的分配和回收方式也有所不同。

    1. 堆(Heap):

      • 堆是用于存储对象实例的内存区域,也被称为动态内存分配区。
      • 在堆中分配的内存需要手动进行释放,在对象不再被引用或者程序执行结束时,由垃圾回收器进行回收。
      • 堆中存储的对象可以被多个线程共享,因此适合存放多个线程共享的对象。
      • 堆的大小是动态可变的,可以根据程序的需要进行扩展。
    2. 栈(Stack):

      • 栈是用于存储局部变量和方法调用的内存区域,也被称为自动内存分配区。
      • 栈的大小是固定的,由编译器预先分配。
      • 栈中的内存会在方法执行结束后自动释放,不需要手动进行回收。
      • 栈中存储的局部变量和方法调用的上下文信息是私有的,每个线程都有自己独立的栈空间。

    下面是一个简单的示例,用来说明堆和栈的使用方式和区别:

    public class StackHeapExample {
        public static void main(String[] args) {
            // 栈中分配的内存
            int a = 10;
            int b = 20;
            int c = a + b;
            
            // 堆中分配的对象
            String str1 = new String("Hello");
            String str2 = new String("World");
            String str3 = str1 + str2;
            
            System.out.println(c);  // 输出: 30
            System.out.println(str3);  // 输出: HelloWorld
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在上述示例中,首先在栈中分配了三个整型变量a、b和c,并对其进行运算。在栈中,这些变量的内存会被自动分配和释放。然后,在堆中分配了三个字符串对象str1、str2和str3,并对其进行字符串拼接操作。在堆中,这些对象的内存需要手动进行释放。

    总结起来,堆和栈的区别在于存储的内容、分配方式和内存管理方式不同。堆主要用于存储对象实例,需要手动进行内存管理;栈主要用于存储局部变量和方法调用,内存管理由编译器自动处理。#

    1.8简述什么是Java反射? 并举例说明

    Java反射是指在程序运行过程中,通过反射机制动态获取、操作和修改类的属性、方法和构造函数等信息的能力。它使得程序能够在运行时动态地调用类的方法、访问和修改类的属性,甚至可以在运行时创建对象和调用私有方法。

    Java反射主要通过以下几个类和接口来实现:

    • Class类:代表类的实体,可以用来获取类的属性、方法、构造函数等信息。
    • Constructor类:代表类的构造函数。
    • Method类:代表类的方法。
    • Field类:代表类的属性。

    下面是一个简单的示例,用来说明Java反射的使用方式:

    public class ReflectionExample {
        private String message;
        
        public ReflectionExample() {
            message = "Hello, Reflection!";
        }
        
        public void printMessage() {
            System.out.println(message);
        }
        
        private void privateMethod() {
            System.out.println("This is a private method.");
        }
        
        public static void main(String[] args) throws Exception {
            // 获取类的Class对象
            Class<?> clazz = ReflectionExample.class;
            
            // 创建对象
            Object obj = clazz.getDeclaredConstructor().newInstance();
            
            // 调用方法
            Method printMessageMethod = clazz.getMethod("printMessage");
            printMessageMethod.invoke(obj);
            
            // 访问私有属性
            Field messageField = clazz.getDeclaredField("message");
            messageField.setAccessible(true);
            String messageValue = (String) messageField.get(obj);
            System.out.println(messageValue);
            
            // 调用私有方法
            Method privateMethod = clazz.getDeclaredMethod("privateMethod");
            privateMethod.setAccessible(true);
            privateMethod.invoke(obj);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    在上述示例中,首先通过Class.forName()方法或者直接使用类名获取了ReflectionExample类的Class对象。然后,通过Class对象可以获取类的构造函数(getDeclaredConstructor())、方法(getMethod())和属性(getDeclaredField())。接着,通过newInstance()方法创建了ReflectionExample对象,并使用getMethod()方法获取printMessage方法的Method对象,然后通过invoke()方法调用了该方法。再通过getDeclaredField()方法获取了message属性的Field对象,并使用setAccessible()方法设置为可访问,然后使用get()方法获取属性的值。最后,通过getDeclaredMethod()方法获取了privateMethod方法的Method对象,并同样设置为可访问,然后使用invoke()方法调用了该方法。

    这个示例展示了Java反射的基本用法,通过反射可以在运行时动态地获取、操作和修改类的属性、方法和构造函数等信息,增加了程序的灵活性和可扩展性。但是,

    过度使用反射可能会导致性能下降和安全问题,因此在使用时需要谨慎考虑。

    反射机制是 Java 语言的一个重要特性。在学习 Java 反射机制前,大家应该先了解两个概念,编译期和运行期。

    编译期是指把源码交给编译器编译成计算机可以执行的文件的过程。在 Java 中也就是把 Java 代码编成 class 文件的过程。

    编译期只是做了一些翻译功能,并没有把代码放在内存中运行起来,而只是把代码当成文本进行操作,比如检查错误。

    运行期是把编译后的文件交给计算机执行,直到程序运行结束。所谓运行期就把在磁盘中的代码放到内存中执行起来。

    Java 反射机制是在运行状态中,

    对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为
    Java 语言的反射机制。简单来说,反射机制指的是程序在运行时能够获取自身的信息。在 Java
    中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。

    Java 反射机制在服务器程序和中间件程序中得到了广泛运用。在服务器端,往往需要根据客户的请求,动态调用某一个对象的特定方法。此外,在
    ORM 中间件的实现中,运用 Java 反射机制可以读取任意一个 JavaBean 的所有属性,或者给这些属性赋值。

    1.9 简述两个对象值相同(x.equals(y)== true)但却可有不同的hash code 这句话对不对?

    这句话是正确的。在Java中,

    Object类中的equals方法用于比较两个对象是否相等,**而hashCode方法用于计算对象的哈希码值。**根据Java规范,如果两个对象使用equals方法比较返回true,则它们的hashCode值应该相等。但是,反之则不一定成立,即两个对象的hashCode值相等并不意味着它们一定相等。

    这是因为hashCode方法是根据对象的内部状态计算出来的,而equals方法是根据业务逻辑来判断对象是否相等。即使两个对象的值(内部状态)相同,但它们的hashCode值可能是根据不同的计算方式得出的,因此可能不同。

    为了遵循Java规范,当重写equals方法时,必须同时重写hashCode方法,以确保对象的相等性和哈希码的一致性。

    1.10简述当一个对象被单做参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化的结果,那么这里到底是值传递,还是引用传递?

    在Java中,当一个对象被作为参数传递给一个方法时,

    实际上是将对象的引用(内存地址)传递给了方法,而不是对象本身。因此,这里可以说是引用传递。

    在方法中,可以通过引用来访问和修改对象的属性,因为方法中使用的是对象的引用,指向的是同一个对象。所以,如果方法修改了对象的属性,这些修改会在方法执行完后仍然保持。

    然而,需要注意的是,当方法返回一个结果时

    ,实际上返回的是一个新的对象或基本数据类型的拷贝,而不是原始对象本身。所以,返回结果不会影响原始对象的引用。

    综上所述,虽然对象通过引用传递给方法,方法可以修改对象的属性,但方法返回的结果不会影响原始对象本身。因此,在这种情况下,可以认为是值传递。

    1.11 简述char型变量中不能存储一个中文汉字?

    在Java中,char类型是用来表示单个字符的数据类型,它使用16位Unicode编码来表示字符。Unicode编码可以表示世界上几乎所有的字符,包括中文汉字。

    因此,char类型的变量是可以存储一个中文汉字的。例如,可以使用以下方式来声明和初始化一个char类型的变量来存储一个中文汉字:

    char chineseChar = '中';
    
    • 1

    在上面的例子中,chineseChar变量存储了一个中文汉字’中’,这是完全合法的。

    需要注意的是

    ,由于Java使用的是UTF-16编码,在某些特殊情况下,一个字符可能需要占用两个char类型的变量。例如

    ,一些特殊的中文字符或表情符号可能需要两个char类型的变量来表示。

    综上所述,char类型的变量完全可以存储一个中文汉字,只需要注意特殊情况下可能需要使用多个char类型的变量来表示一个字符。

    1.12简述instanceOf关键字的作用

    instanceof关键字是Java中的一个运算符,用于判断一个对象是否是某个类的实例或者实现了某个接口。

    其作用如下:

    1. 判断对象是否是某个类的实例:可以使用instanceof关键字来判断一个对象是否属于某个类的实例。例如,可以使用obj instanceof MyClass来判断obj对象是否是MyClass类的实例。

    2. 判断对象是否实现了某个接口:可以使用instanceof关键字来判断一个对象是否实现了某个接口。例如,可以使用obj instanceof MyInterface来判断obj对象是否实现了MyInterface接口。

    3. 多态性中的类型转换:instanceof关键字可以在多态性中进行类型转换的判断。在进行类型转换之前,可以使用instanceof关键字来判断对象是否是某个类的实例,以避免出现ClassCastException异常。

    示例代码如下:

    class Animal {
    }
    
    class Dog extends Animal {
    }
    
    class Cat extends Animal {
    }
    
    public class Example {
        public static void main(String[] args) {
            Animal animal = new Dog();
            if (animal instanceof Dog) {
                Dog dog = (Dog) animal;
                dog.bark();
            } else if (animal instanceof Cat) {
                Cat cat = (Cat) animal;
                cat.meow();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在上述示例中,animal对象被实例化为一个Dog对象,并使用instanceof关键字判断animal对象是否是Dog类的实例。根据判断结果的不同,可以进行相应的类型转换和方法调用。

    101 简述a = a+b 和a += b有什么区别?

    a = a + b 和 a += b 在功能上是相同的,都是将变量b的值加到变量a上,并将结果赋值给变量a。

    然而,它们在底层实现和使用时有一些细微的差别:

    1. 表达式的类型不同:a = a + b 是一个赋值表达式,右边的 a + b 是一个新的表达式,

    它的结果是一个新创建的对象。而 a += b 是一个复合赋值表达式,会直接在原有的对象上进行修改。

    1. 对象引用的不同:在 a = a + b 中,右边的表达式会创建一个新的对象,然后将新的对象的引用赋给变量a。而在 a += b 中,不会创建新的对象,直接在原有的对象上进行修改。

    2. 适用类型的不同:a += b 只能用于某些特定的基本数据类型(如int、long等)和一些特定的类(如String),而 a = a + b 可以适用于更多的数据类型。

    3. 可读性和代码简洁性:a += b 相对于 a = a + b 更加简洁和易读,可以减少代码量。

    需要注意的是,虽然 a += b 的实现可能在底层上效率更高,但在大多数情况下,这两种写法的性能差异并不明显,因此选择哪种写法主要取决于个人的编码风格和偏好。

    103 简述Excption 与 Error 包结构?

    Exception 和 Error 是 Java 中的两个不同的异常类层次结构。

    1. Exception:
      Exception 是程序运行过程中可能出现的异常情况的基类。它是由应用程序或者 API 引起的,表示程序可以处理的异常。Exception 可以被捕获并进行处理,或者在方法签名中声明并交由调用者处理。

    Exception 类下还有两个子类:RuntimeException 和 IOException。

    • RuntimeException: RuntimeException 是一种非受检异常,即在编译时不会强制要求处理的异常。它通常表示程序的逻辑错误或者运行时错误,如空指针异常、数组越界异常等。这些异常往往可以通过代码的改进避免。
    • IOException: IOException 是一种受检异常,即在编译时要求必须处理的异常。它表示输入输出操作可能失败或中断的情况,如文件读取异常、网络连接异常等。
    1. Error:
      Error 是一种严重的错误,通常表示虚拟机运行时的系统级别错误或者资源耗尽错误。Error 一般无法被应用程序捕获和处理,而是由 JVM 来处理。如果出现 Error,一般意味着程序无法继续正常运行,并可能导致 JVM 终止运行。

    Error 类下有一些子类,如 OutOfMemoryError、StackOverflowError 等,这些错误通常是由于系统资源耗尽或者 JVM 内部错误引起的,无法通过代码进行处理和修复。

    总结:
    Exception 和 Error 都是继承自 Throwable 类,表示在程序执行过程中的异常情况,但它们在处理方式和出现场景上有所不同。

    • Exception 用于表示程序运行过程中的可处理异常,它的子类 RuntimeException 和 IOException 可以被捕获并处理,或者在方法签名中声明并交由调用者处理。
    • Error 用于表示严重的系统级别错误或者资源耗尽错误,一般无法被应用程序直接处理,而是由 JVM 处理。

    106 简述Object有哪些常用方法?大致说一下么一个方法的含义?

    Object类是Java中所有类的父类,它定义了一些常用的方法,下面对其中几个常用方法进行简要说明:

    1. equals(Object obj):用于判断当前对象是否与给定的对象相等。默认情况下,该方法使用的是引用比较,即只有两个对象的引用指向同一个内存地址时才认为它们相等。如果子类希望根据实际需求重写该方法,可以修改比较的逻辑。

    2. **hashCode():**返回当前对象的哈希码值。哈希码是一个整型值,用于快速查找对象在哈希表中的位置。通常情况下,如果两个对象通过equals()方法比较相等,它们的哈希码应该相等。

    3. toString():返回当前对象的字符串表示。默认情况下,该方法返回类名和对象的哈希码。可以根据实际需求重写该方法,使其返回更有意义的信息。

    4. getClass():返回当前对象的运行时类对象。该方法可以用来获取对象所属的类,以便

    109 简述常用的java并发工具类有哪些?

    常用的Java并发工具类包括以下几个:

    1. CountDownLatch:用于控制一个或多个线程等待其他线程完成操作后再继续执行。它通过一个计数器来实现,初始化时设置计数器的值,每当一个线程完成操作时,计数器的值减一。当计数器的值变为0时,所有等待的线程将被释放。

    2. CyclicBarrier:与CountDownLatch类似,也是用于控制线程的执行顺序。不同之处在于,CyclicBarrier设置了一个屏障,当指定数量的线程都到达屏障时,所有线程才能继续执行。与CountDownLatch不同,CyclicBarrier的计数器可以重置,可以用于循环执行的场景。

    3. Semaphore

    用于控制同一时间并发访问的线程数量。它通过设置许可数量来限制同时访问的线程数量。每当一个线程访问结束后,释放一个许可,使其他等待的线程可以继续执行。

    1. Exchanger

    用于两个线程之间交换数据。每个线程通过调用exchanger方法交换数据,当两个线程都调用了exchanger方法后,它们可以获取彼此交换的数据。

    1. Phaser:类似于CyclicBarrier,也是用于控制线程的协同执行。不同之处在于,Phaser可以动态地注册和注销参与者,并根据参与者的数量来决定是否继续执行。它可以用于分阶段执行任务的场景。

    2. LockCondition:Lock是一个可重入的互斥锁,

    它比synchronized关键字更加灵活,可以手动控制锁的获取和释放。Condition是与Lock配合使用的条件变量,可以用于线程间的等待和通知机制。

    111.简述如何通过反射调用对象的方法

    这些并发工具类在多线程编程中起到了重要的作用,能够提高线程的效率和安全性。在具体

    通过反射调用对象的方法可以使用Java中的java.lang.reflect包中的相关类和方法。下面是通过反射调用对象方法的简要步骤:

    1. 获取要调用方法的对象的Class对象。可以通过对象的getClass()方法或者使用Class.forName()方法获取。

    2. 使用Class对象的getMethod()方法获取要调用的方法。

    需要传入方法的名称和参数类型

    1. 使用Method对象的invoke()方法调用方法。需要传入要调用方法的对象实例和方法的参数(如果有参数的话)。

    下面是一个示例代码,演示了如何通过反射调用对象的方法:

    import java.lang.reflect.Method;
    
    public class ReflectExample {
        public static void main(String[] args) throws Exception {
            // 创建一个字符串对象
            String str = "Hello, World!";
            
            // 获取String类的Class对象
            Class<?> cls = str.getClass();
            
            // 获取String的substring方法
            Method method = cls.getMethod("substring", int.class, int.class);
            
            // 调用substring方法
            String result = (String) method.invoke(str, 0, 5);
            
            // 输出结果
            System.out.println(result); // 输出:Hello
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在上述示例中**,首先获取了字符串对象的Class对象,然后使用getMethod()方法获取了substring方法的Method对象。最后使用invoke()方法调用了substring方法,并传入了参数0和5,得到了调用结果**。

    113. 什么事bit 什么事byte ,什么是字符(char),他的长度是多少,各有什么区别?

    bit是计算机中最小的数据单位,表示二进制位,取值为0或1。它是计算机存储和处理信息的基础。

    byte是计算机中常用的数据存储单位,由8个bit组成,可以表示256个不同的值(从0到255)。在计算机中,通常使用byte来表示字符、整数和其他数据类型。

    字符(char)是Java中的数据类型,用于表示单个字符。它是16位的无符号整数类型,可以用来存储Unicode字符。字符类型的长度是2个字节。

    区别如下:

    • bit是计算机最小的数据单位,只能表示0或1;byte是8个bit组成的数据单位,可以表示更大的范围。
    • byte可以用来表示整数、字符等多种数据类型,而bit主要用于位运算。
    • 字符是一种特殊的数据类型,用于表示单个字符,而byte可以表示更多的数据类型。
    • 字符类型的长度是2个字节,而byte类型的长度是1个字节。
  • 相关阅读:
    SpringAOP底层原理
    吃瓜教程第一二章学习记录
    人脑能否重启?
    20【访问者设计模式】
    基于 Linux 的 web 服务器
    Map集合继承结构
    hadoop_概念
    docker入门加实战—docker常见命令
    JS中的set集合和map映射
    windows docker desktop配置国内镜像仓库
  • 原文地址:https://blog.csdn.net/weixin_42655650/article/details/133855333