当前位置: 首页 > news >正文

Java基础知识

概念

请介绍全局变量和局部变量的区别

Java中的变量分为成员变量和局部变量,它们的区别如下:

成员变量:

1. 成员变量是在类的范围里定义的变量;

2. 成员变量有默认初始值;

3. 未被static修饰的成员变量也叫实例变量,它存储于对象所在的堆内存中,生命周期与对象相同;

4. 被static修饰的成员变量也叫类变量,它存储于方法区中,生命周期与当前类相同。

局部变量:

1. 局部变量是在方法里定义的变量;

2. 局部变量没有默认初始值;

3. 局部变量存储于栈内存中,作用的范围结束,变量空间会自动的释放

String可以被继承吗?

private final byte[] value

String类由final修饰,所以不能被继承。

在Java中,String类被设计为不可变类,主要表现在它保存字符串的成员变量是final的因为要保证String类的不可变,那么将这个类定义为final的就很容易理解了。如果没有final修饰,那么就会存在String的子类,这些子类可以重写String类的方法,强行改变字符串的值,这便违背了String类设计的初衷

使用字符串时,new和""推荐使用哪种方式?

先看看 "hello" 和 new String("hello") 的区别:

当Java程序直接使用 "hello" 的字符串直接量时,JVM将会使用常量池来管理这个字符串;

当使用 new String("hello") 时,JVM会先使用常量池来管理 "hello" 直接量,再调用String类的构造器来创建一个新的String对象,新创建的String对象被保存在堆内存中。 显然,采用new的方式会多创建一个对象出来,会占用更多的内存,所以一般建议使用直接量的方式创建字符串。

String a = "abc"; ,说一下这个过程会创建什么,放在哪里?

JVM会使用常量池来管理字符串直接量。

在执行这句话时,JVM会先检查常量池中是否已经存有"abc",

若没有则将"abc"存入常量池,否则就复用常量池中已有的"abc",将其引用赋值给变量a。

new String("abc") 是去了哪里,仅仅是在堆里面吗?

在执行这句话时,JVM会先使用常量池来管理字符串直接量,即将"abc"存入常量池。然后再创建一个新的String对象,这个对象会被保存在堆内存中。并且,堆中对象的数据会指向常量池中的直接量

说一下Java的特点

主要有以下的特点:

平台无关性:Java的“编写一次,运行无处不在”哲学是其最大的特点之一。Java编译器将源代码编译成字节码(bytecode),该字节码可以在任何安装了Java虚拟机(JVM)的系统上运行。

面向对象:Java是一门严格的面向对象编程语言,几乎一切都是对象。面向对象编程(OOP)特性使得代码更易于维护和重用,包括类(class)、对象(object)、继承(inheritance)、多态(polymorphism)、抽象(abstraction)和封装(encapsulation)。

内存管理:Java有自己的垃圾回收机制,自动管理内存和回收不再使用的对象。这样,开发者不需要手动管理内存,从而减少内存泄漏和其他内存相关的问题。

Java为什么是跨平台的?

Java 能支持跨平台,主要依赖于 JVM 关系比较大。

JVM也是一个软件,不同的平台有不同的版本。我们编写的Java源码,编译后会生成一种 .class 文件,称为字节码文件。Java虚拟机就是负责将字节码文件翻译成特定平台下的机器码然后运行。也就是说,只要在不同平台上安装对应的JVM,就可以运行字节码文件,运行我们编写的Java程序。

而这个过程中,我们编写的Java程序没有做任何改变,仅仅是通过JVM这一”中间层“,就能在不同平台上运行,真正实现了”一次编译,到处运行“的目的。

JVM是一个”桥梁“,是一个”中间件“,是实现跨平台的关键,Java代码首先被编译成字节码文件,再由JVM将字节码文件翻译成机器语言,从而达到运行Java程序的目的。

编译的结果不是生成机器码,而是生成字节码,字节码不能直接运行,必须通过JVM翻译成机器码才能运行。不同平台下编译生成的字节码是一样的,但是由JVM翻译成的机器码却不一样。

所以,运行Java程序必须有JVM的支持,因为编译的结果不是机器码,必须要经过JVM的再次翻译才能执行。即使你将Java程序打包成可执行文件(例如 .exe),仍然需要JVM的支持。

JVM、JDK、JRE三者关系?

它们之间的关系如下:

JVM是Java虚拟机,是Java程序运行的环境。它负责将Java字节码(由Java编译器生成)解释或编译成机器码,并执行程序。JVM提供了内存管理、垃圾回收、安全性等功能,使得Java程序具备跨平台性。

JDK是Java开发工具包,是开发Java程序所需的工具集合。它包含了JVM、编译器(javac)、调试器(jdb)等开发工具,以及一系列的类库(如Java标准库和开发工具库)。JDK提供了开发、编译、调试和运行Java程序所需的全部工具和环境。

JRE是Java运行时环境,是Java程序运行所需的最小环境。它包含了JVM和一组Java类库,用于支持Java程序的执行。JRE不包含开发工具,只提供Java程序运行所需的运行环境。

为什么Java解释和编译都有?

编译性:

Java源代码首先被编译成字节码,JIT 会把编译过的机器码保存起来,以备下次使用。

解释性:

JVM中一个方法调用计数器,当累计计数大于一定值的时候,就使用JIT进行编译生成机器码文件。否则就是用解释器进行解释执行,然后字节码也是经过解释器进行解释运行的。

所以Java既是编译型也是解释性语言,默认采用的是解释器和编译器混合的模式。

jvm是什么

JVM是 java 虚拟机,主要工作是解释自己的指令集(即字节码)并映射到本地的CPU指令集和OS的系统调用。

JVM屏蔽了与操作系统平台相关的信息,使得Java程序只需要生成在Java虚拟机上运行的目标代码(字节码),就可在多种平台上不加修改的运行,这也是Java能够“一次编译,到处运行的”原因。

编译型语言和解释型语言的区别?

编译型语言和解释型语言的区别在于:

编译型语言:在程序执行之前,整个源代码会被编译成机器码或者字节码,生成可执行文件。执行时直接运行编译后的代码,速度快,但跨平台性较差。

解释型语言:在程序执行时,逐行解释执行源代码不生成独立的可执行文件。通常由解释器动态解释并执行代码,跨平台性好,但执行速度相对较慢。

典型的编译型语言如C、C++,典型的解释型语言如Python、JavaScript。

Python和Java区别是什么?

Java是一种已编译的编程语言,Java编译器将源代码编译为字节码,而字节码则由Java虚拟机执行

python是一种解释语言,翻译时会在执行程序的同时进行翻译。

数据类型

八种基本的数据类型

Java支持数据类型分为两类: 基本数据类型和引用数据类型。

基本数据类型共有8种,可以分为三类:

数值型:整数类型(byte、short、int、long)和浮点类型(float、double)

字符型:char

布尔型:boolean

long和int可以互转吗 ?

可以的,Java中的long和int可以相互转换。由于long类型的范围比int类型大,因此将int转换为long是安全的,而将long转换为int可能会导致数据丢失或溢出。

将int转换为long可以通过直接赋值或强制类型转换来实现。例如:

int intValue = 10;

long longValue = intValue; // 自动转换,安全的

将long转换为int需要使用强制类型转换,但需要注意潜在的数据丢失或溢出问题。

long longValue = 100L;

int intValue = (int) longValue; // 强制类型转换,可能会有数据丢失或溢出

数据类型转换方式你知道哪些?

自动类型转换(隐式转换):当目标类型的范围大于源类型时,Java会自动将源类型转换为目标类型,不需要显式的类型转换。例如,将int转换为long、将float转换为double等。

强制类型转换(显式转换):当目标类型的范围小于源类型时,需要使用强制类型转换将源类型转换为目标类型。这可能导致数据丢失或溢出。例如,将long转换为int、将double转换为int等。语法为:目标类型 变量名 = (目标类型) 源类型。

字符串转换:Java提供了将字符串表示的数据转换为其他类型数据的方法。例如,将字符串转换为整型int,可以使用Integer.parseInt()方法;将字符串转换为浮点型double,可以使用Double.parseDouble()方法等。

数值之间的转换:Java提供了一些数值类型之间的转换方法,如将整型转换为字符型、将字符型转换为整型等。这些转换方式可以通过类型的包装类来实现,例如Character类、Integer类等提供了相应的转换方法。

类型互转会出现什么问题吗?

数据丢失当将一个范围较大的数据类型转换为一个范围较小的数据类型时,可能会发生数据丢失。例如,将一个long类型的值转换为int类型时,如果long值超出了int类型的范围,转换结果将是截断后的低位部分,高位部分的数据将丢失。

数据溢出与数据丢失相反,当将一个范围较小的数据类型转换为一个范围较大的数据类型时,可能会发生数据溢出。例如,将一个int类型的值转换为long类型时,转换结果会填充额外的高位空间,但原始数据仍然保持不变。

精度损失:在进行浮点数类型的转换时,可能会发生精度损失。由于浮点数的表示方式不同,将一个单精度浮点数(float)转换为双精度浮点数(double)时,精度可能会损失。

类型不匹配导致的错误:在进行类型转换时,需要确保源类型和目标类型是兼容的。如果两者不兼容,会导致编译错误或运行时错误。

为什么用bigDecimal 不用double ?

double会出现精度丢失的问题

而 Decimal 是精确计算 , 所以一般牵扯到金钱的计算 , 都使用 Decimal。

装箱和拆箱是什么?

装箱(Boxing)和拆箱(Unboxing)是将基本数据类型和对应的包装类之间进行转换的过程。

Integer i = 10;  //装箱

int n = i;   //拆箱

自动装箱主要发生在两种情况,一种是赋值时,另一种是在方法调用的时候。

赋值时

这是最常见的一种情况,在Java 1.5以前我们需要手动地进行转换才行,而现在所有的转换都是由编译器来完成。

方法调用时

当我们在方法调用时,我们可以传入原始数据值或者对象,同样编译器会帮我们进行转换。

public static Integer show(Integer iParam){

   System.out.println("autoboxing example - method invocation i: " + iParam);

   return iParam;

}

自动装箱的弊端

自动装箱有一个问题,那就是在一个循环中进行自动装箱操作的情况,如下面的例子就会创建多余的对象,影响程序的性能。

Integer sum = 0; for(int i=1000; i<5000; i++){   sum+=i; }

上面的代码sum+=i可以看成sum = sum + i,但是+这个操作符不适用于Integer对象,首先sum进行自动拆箱操作,进行数值相加操作,最后发生自动装箱操作转换成Integer对象。其内部变化如下

int result = sum.intValue() + i; Integer sum = new Integer(result);

由于我们这里声明的sum为Integer类型,在上面的循环中会创建将近4000个无用的Integer对象,在这样庞大的循环中,会降低程序的性能并且加重了垃圾回收的工作量。因此在我们编程时,需要注意到这一点,正确地声明变量类型,避免因为自动装箱引起的性能问题。

Java为什么要有Integer?

Integer对应是int类型的包装类,就是把int类型包装成Object对象,对象封装有很多好处,可以把属性也就是数据跟处理这些数据的方法结合在一起,比如Integer就有parseInt()等方法来专门处理int型相关的数据。

另一个非常重要的原因就是在Java中绝大部分方法或类都是用来处理类类型对象的,如ArrayList集合类就只能以类作为他的存储对象,而这时如果想把一个int型的数据存入list是不可能的,必须把它包装成类,也就是Integer才能被List所接受。所以Integer的存在是很必要的。

Integer相比int有什么优点?

Integer和 int 的区别:

使用int来存储一个整数时,不需要任何额外的内存分配,而使用Integer时,必须为对象分配内存。在性能方面,基本数据类型的操作通常比相应的引用类型快。

那为什么还要保留int类型?

不管是读写效率,还是存储效率,基本类型都比包装类高效。

说一下 integer的缓存

Java的Integer类内部实现了一个静态缓存池,用于存储特定范围内的整数值对应的Integer对象。

默认情况下,这个范围是-128至127。当通过Integer.valueOf(int)方法创建一个在这个范围内的整数对象时,并不会每次都生成新的对象实例,而是复用缓存中的现有对象,会直接从内存中取出,不需要新建一个对象。

Integer a = 127;

Integer b = 127;

Integer c = 128;

Integer d = 128;

System.out.println(a == b);

System.out.println(c == d);

面向对象

怎么理解面向对象?简单说说封装继承多态

洗衣服: 人(把衣服放进洗衣机),洗衣机(洗衣服)

面向对象是一种编程范式,它将现实世界中的事物抽象为对象,对象具有属性(称为字段或属性)和行为(称为方法)。面向对象编程的设计思想是以对象为中心,通过对象之间的交互来完成程序的功能,具有灵活性和可扩展性,通过封装和继承可以更好地应对需求变化。

Java面向对象的三大特性包括:封装、继承、多态:

封装:通过关键字private,对外隐藏对象的内部细节,仅通过对象提供的接口与外界交互。

继承:对共性进行抽取,达到代码的复用

多态:相同类型的对象调用同一个方法会产生不同的状态

多态体现在哪几个方面?

多态在面向对象编程中可以体现在以下几个方面:

方法重载:

方法名相同,参数列表不同,返回值不做要求

方法重写:

方法名相同,参数列表相同,返回值相同或者具有父子关系

向上转型

在Java中,可以使用父类类型的引用指向子类对象,这是向上转型。直接赋值,方法传参,返回值

多态解决了什么问题?

多态是指子类可以替换父类,在实际的代码运行过程中,调用子类的方法实现。多态这种特性也需要编程语言提供特殊的语法机制来实现,比如继承、接口类。

多态可以提高代码的扩展性和复用性,是很多设计模式、设计原则、编程技巧的代码实现基础。比如策略模式、基于接口而非实现编程、依赖倒置原则、里式替换原则、利用多态去掉冗长的 if-else 语句等等

重载与重写有什么区别?

方法重载:

方法名相同,参数列表不同,返回值不做要求

方法重写:

方法名相同,参数列表相同,返回值相同或者具有父子关系

Java抽象类和接口的区别是什么?

从使用方式上来说,二者有如下的区别:

接口里只能包含抽象方法、静态方法、默认方法和私有方法,不能为普通方法提供方法实现;抽象类则完全可以包含普通方法。

接口里只能定义静态常量,不能定义普通成员变量;抽象类里则既可以定义普通成员变量,也可以定义静态常量。

接口里不包含构造器;抽象类里可以包含构造器,抽象类里的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。

接口里不能包含初始化块;但抽象类则完全可以包含初始化块。

一个类最多只能有一个直接父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java单继承的不足。

接口和抽象类很像,它们都具有如下共同的特征:

接口和抽象类都不能被实例化,它们都位于继承树的顶端,用于被其他类实现和继承。

接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法。

抽象类能加final修饰吗?

不能,Java中的抽象类是用来被继承的,而final修饰符用于禁止类被继承或方法被重写,因此,抽象类和final修饰符是互斥的,不能同时使用。

解释Java中的静态变量和静态方法

在Java中,静态变量和静态方法是与类本身关联的,而不是与类的实例(对象)关联。它们在内存中只存在一份,可以被类的所有实例共享。

静态变量

静态变量(也称为类变量)是在类中使用static关键字声明的变量。它们属于类而不是任何具体的对象。主要的特点:

共享性:所有该类的实例共享同一个静态变量。如果一个实例修改了静态变量的值,其他实例也会看到这个更改。

初始化:静态变量在类被加载时初始化,只会对其进行一次分配内存。

访问方式:静态变量可以直接通过类名访问,也可以通过实例访问,但推荐使用类名。

静态方法

静态方法是在类中使用static关键字声明的方法。类似于静态变量,静态方法也属于类,而不是任何具体的对象。主要的特点:

无实例依赖:静态方法可以在没有创建类实例的情况下调用。对于静态方法来说,不能直接访问非静态的成员变量或方法,因为静态方法没有上下文的实例。

访问静态成员:静态方法可以直接调用其他静态变量和静态方法,但不能直接访问非静态成员。

多态性:静态方法不支持重写(Override),但可以被隐藏(Hide)。

使用场景

静态变量:常用于需要在所有对象间共享的数据,如计数器、常量等。

静态方法:常用于助手方法(utility methods)、获取类级别的信息或者是没有依赖于实例的数据处理。

非静态内部类和静态内部类的区别?

区别包括:

非静态内部类依赖于外部类的实例,而静态内部类不依赖于外部类的实例。

非静态内部类可以访问外部类的实例变量和方法,而静态内部类只能访问外部类的静态成员。

非静态内部类不能定义静态成员,而静态内部类可以定义静态成员。

非静态内部类可以直接访问外部方法,编译器是怎么做到的?

非静态内部类可以直接访问外部方法是因为编译器在生成字节码时会为非静态内部类维护一个指向外部类实例的引用。

有一个父类和子类,都有静态的成员变量、静态构造方法和静态方法,在我new一个子类对象的时候,加载顺序是怎么样的?

当你实例化一个子类对象时,静态成员变量、静态构造方法和静态方法的加载顺序遵循以下步骤:

父类静态成员变量、静态代码块(如果有)

子类静态成员变量、静态代码块(如果有)

父类构造方法(实例化对象时)

子类构造方法(实例化对象时)

深拷贝和浅拷贝

深拷贝和浅拷贝的区别?

浅拷贝是指只复制对象本身和其内部的值类型字段,但不会复制对象内部的引用类型字段。换句话说,浅拷贝只是创建一个新的对象,然后将原对象的字段值复制到新对象中,但如果原对象内部有引用类型的字段,只是将引用复制到新对象中,两个对象指向的是同一个引用对象。

深拷贝是指在复制对象的同时,将对象内部的所有引用类型字段的内容也复制一份,而不是共享引用。换句话说,深拷贝会递归复制对象内部所有引用类型的字段,生成一个全新的对象以及其内部的所有对象。

实现深拷贝的三种方法是什么?

在 Java 中,实现对象深拷贝的方法有以下几种主要方式:

实现 Cloneable 接口并重写 clone() 方法

这种方法要求对象及其所有引用类型字段都实现 Cloneable 接口,并且重写 clone() 方法。在 clone() 方法中,通过递归克隆引用类型字段来实现深拷贝。

使用序列化和反序列化

通过将对象序列化为字节流,再从字节流反序列化为对象来实现深拷贝。要求对象及其所有引用类型字段都实现 Serializable 接口。

泛型

什么是泛型?

泛型是 Java 编程语言中的一个重要特性,它允许类、接口和方法在定义时使用一个或多个类型参数,这些类型参数在使用时可以被指定为具体的类型

泛型的主要目的是在编译时提供更强的类型检查,并且在编译后能够保留类型信息,避免了在运行时出现类型转换异常。

为什么需要泛型?

适用于多种数据类型执行相同的代码

泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型)

对象

java创建对象有哪些方式?

在Java中,创建对象的方式有多种,常见的包括:

使用new关键字:通过new关键字直接调用类的构造方法来创建对象。

MyClass obj = new MyClass();

使用Class类的newInstance()方法:通过反射机制,可以使用Class类的newInstance()方法创建对象。

MyClass obj = (MyClass) Class.forName("com.example.MyClass").newInstance();

使用Constructor类的newInstance()方法:同样是通过反射机制,可以使用Constructor类的newInstance()方法创建对象。

Constructor<MyClass> constructor = MyClass.class.getConstructor();

MyClass obj = constructor.newInstance();

使用clone()方法:如果类实现了Cloneable接口,可以使用clone()方法复制对象。

New出的对象什么时候回收?

通过过关键字new创建的对象,由Java的垃圾回收器(Garbage Collector)负责回收。垃圾回收器的工作是在程序运行过程中自动进行的,它会周期性地检测不再被引用的对象,并将其回收释放内存。

具体来说,Java对象的回收时机是由垃圾回收器根据一些算法来决定的,主要有以下几种情况:

引用计数法:某个对象的引用计数为0时,表示该对象不再被引用,可以被回收。

可达性分析算法:从根对象(如方法区中的类静态属性、方法中的局部变量等)出发,通过对象之间的引用链进行遍历,如果存在一条引用链到达某个对象,则说明该对象是可达的,反之不可达,不可达的对象将被回收。

反射

什么是反射?

Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 Java 语言的反射机制。

反射具有以下特性:

运行时类信息访问:反射机制允许程序在运行时获取类的完整结构信息,包括类名、包名、父类、实现的接口、构造函数、方法和字段等。

动态对象创建:可以使用反射API动态地创建对象实例,即使在编译时不知道具体的类名。这是通过Class类的newInstance()方法或Constructor对象的newInstance()方法实现的。

动态方法调用:可以在运行时动态地调用对象的方法,包括私有方法。这通过Method类的invoke()方法实现,允许你传入对象实例和参数值来执行方法。

访问和修改字段值:反射还允许程序在运行时访问和修改对象的字段值,即使是私有的。这是通过Field类的get()和set()方法完成的。

反射在你平时写代码或者框架中的应用场景有哪些?

加载数据库驱动

我们的项目底层数据库有时是用mysql,有时用oracle,需要动态地根据实际情况加载驱动类,这个时候反射就有用了,假设 com.mikechen.java.myqlConnection,com.mikechen.java.oracleConnection这两个类我们要用。

这时候我们在使用 JDBC 连接数据库时使用 Class.forName()通过反射加载数据库的驱动程序,如果是mysql则传入mysql的驱动类,而如果是oracle则传入的参数就变成另一个了。

配置文件加载

Spring 框架的 IOC(动态加载管理 Bean),Spring通过配置文件配置各种各样的bean,你需要用到哪些bean就配哪些,spring容器就会根据你的需求去动态加载,你的程序就能健壮地运行。

注解

能讲一讲Java注解的原理吗?

注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。

我们通过反射获取注解时,返回的是Java运行时生成的动态代理对象。通过代理对象调用自定义注解的方法,会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。而memberValues的来源是Java常量池。

Java注解的作用域呢?

注解的作用域(Scope)指的是注解可以应用在哪些程序元素上,例如类、方法、字段等。Java注解的作用域可以分为三种:

类级别作用域:用于描述类的注解,通常放置在类定义的上面,可以用来指定类的一些属性,如类的访问级别、继承关系、注释等。

方法级别作用域:用于描述方法的注解,通常放置在方法定义的上面,可以用来指定方法的一些属性,如方法的访问级别、返回值类型、异常类型、注释等。

字段级别作用域:用于描述字段的注解,通常放置在字段定义的上面,可以用来指定字段的一些属性,如字段的访问级别、默认值、注释等。

除了这三种作用域,Java还提供了其他一些注解作用域,例如构造函数作用域和局部变量作用域。这些注解作用域可以用来对构造函数和局部变量进行描述和注释。

异常

介绍一下Java异常

Java异常类层次结构图:Java的异常体系主要基于两大类:Throwable类及其子类。Throwable有两个重要的子类:Error和Exception,它们分别代表了不同类型的异常情况。

Error(错误):表示运行时环境的错误。错误是程序无法处理的严重问题,如系统崩溃、虚拟机错误、动态链接失败等。通常,程序不应该尝试捕获这类错误。例如,OutOfMemoryError、StackOverflowError等。

Exception(异常):表示程序本身可以处理的异常条件。异常分为两大类:

非运行时异常:这类异常在编译时期就必须被捕获或者声明抛出。它们通常是外部错误,如文件不存在(FileNotFoundException)、类未找到(ClassNotFoundException)等。非运行时异常强制程序员处理这些可能出现的问题,增强了程序的健壮性。

运行时异常:这类异常包括运行时异常(RuntimeException)和错误(Error)。运行时异常由程序错误导致,如空指针访问(NullPointerException)、数组越界(ArrayIndexOutOfBoundsException)等。运行时异常是不需要在编译时强制捕获或声明的。

编译时异常/受查异常

   程序员手动捕获或者throws进行处理

运行时异常/非受查异常

   不需要程序员手动处理,jvm会帮助处理

Java异常处理有哪些?

异常处理是通过使用try-catch语句块来捕获和处理异常。以下是Java中常用的异常处理方式:

try-catch语句块:用于捕获并处理可能抛出的异常。try块中包含可能抛出异常的代码,catch块用于捕获并处理特定类型的异常。可以有多个catch块来处理不同类型的异常。

throw语句:用于手动抛出异常。可以根据需要在代码中使用throw语句主动抛出特定类型的异常。

throw new ExceptionType("Exception message");

throws关键字:用于在方法声明中声明可能抛出的异常类型。如果一个方法可能抛出异常,但不想在方法内部进行处理,可以使用throws关键字将异常传递给调用者来处理。

抛出异常为什么不用throws?

如果异常是未检查异常或者在方法内部被捕获和处理了,那么就不需要使用throws。

Unchecked Exceptions:未检查异常(unchecked exceptions)是继承自RuntimeException类或Error类的异常,编译器不强制要求进行异常处理。因此,对于这些异常,不需要在方法签名中使用throws来声明。示例包括NullPointerException、ArrayIndexOutOfBoundsException等。

捕获和处理异常:另一种常见情况是,在方法内部捕获了可能抛出的异常,并在方法内部处理它们,而不是通过throws子句将它们传递到调用者。这种情况下,方法可以处理异常而无需在方法签名中使用throws。

try catch中的语句运行情况

try块中的代码将按顺序执行,如果抛出异常,将在catch块中进行匹配和处理,然后程序将继续执行catch块之后的代码。如果没有匹配的catch块,异常将被传递给上一层调用的方法。

try{return “a”} fianlly{return “b”}这条语句返回啥

finally块中的return语句会覆盖try块中的return返回,因此,该语句将返回"b"。

object

== 与 equals 有什么区别?

对于字符串变量来说,使用"=="和"equals"比较字符串时,其比较方法不同。"=="比较两个变量本身的值,即两个对象在内存中的首地址,"equals"比较字符串包含内容是否相同。

对于非字符串变量来说,如果没有对equals()进行重写的话,"==" 和 "equals"方法的作用是相同的,都是用来比较对象在堆内存中的首地址,即用来比较两个引用变量是否指向同一个对象。

==:比较的是两个字符串内存地址(堆内存)的数值是否相等,属于数值比较;

equals():比较的是两个字符串的内容,属于内容比较。

StringBuffer和StringBuild区别是什么?

区别:

线程安全:

StringBuffer:线程安全

StringBuilder:线程不安全

速度:

一般情况下,速度从快到慢为 StringBuilder > StringBuffer > String,当然这是相对的,不是绝对的。

使用场景:

操作少量的数据使用 String。

单线程操作大量数据使用 StringBuilder。

多线程操作大量数据使用 StringBuffer。

有一个学生类,想按照分数排序,再按学号排序,应该怎么做?

可以使用Comparable接口来实现按照分数排序,再按照学号排序。首先在学生类中实现Comparable接口,并重写compareTo方法,然后在compareTo方法中实现按照分数排序和按照学号排序的逻辑

相关文章:

  • SQL 语句基础(增删改查)
  • 电流互感器的两相星形接线的建模与仿真
  • 撰写学位论文Word图表目录的自动生成
  • 基于单片机的病房呼叫系统设计
  • 【MCAL】AUTOSAR架构下基于SPI通信的驱动模块详解-以TJA1145为例
  • [网鼎杯 2022 青龙组]fakeshell
  • 开启深度学习之旅
  • 机器学习中的数学(PartⅡ)——线性代数:2.1线性方程组
  • 【随行付-注册安全分析报告-无验证方式导致隐患】
  • 从零开始的C++编程 2(类和对象下)
  • 【Python] pip制作离线包
  • TcxCustomCheckComboBoxProperties.EditValueFormat 值说明
  • 第三篇:Python数据结构深度解析与工程实践
  • Node.js中net模块详解
  • 网络5 TCP/IP 虚拟机桥接模式、NAT、仅主机模式
  • Android7 Input(四)InputReader
  • vue3中,element-plus中el-select隐藏下拉箭头
  • DAY 42 leetcode 151--哈希表.反转字符串中的单词
  • 危化品安全员岗位注意事项有哪些?
  • Downlink Sensing in 5G-Advanced and 6G: SIB1-assisted SSB Approach
  • 西安专业网站开发公司/查指数
  • 网站代码如何优化/郑州网站建设方案
  • 做互联网一个月挣多少钱/广东网站营销seo方案
  • 素颜网站建设/北大青鸟培训机构官网
  • 实验设计方案怎么写模板/网站seo设计方案案例
  • 福州建设厅网站/百度知道推广软件