一、Java基础

1.1Java中基本数据类型有哪些?

byte:8位,最大存储数据量是255,存放的数据范围是-128~127之间。

short:16位,

int:32位,最大数据存储容量是2的32次方减1,数据范围是负的2的31次方到正的2的31次方减1。

long:64位,最大数据存储容量是2的64次方减1,数据范围为负的2的63次方到正的2的63次方减1。

float:32位,

double:64位,

boolean:只有true和false两个取值。

char:16位,存储Unicode码,用单引号赋值。

1.2Integer 和 int的区别

int是基本数据类型,变量中直接存放数值,变量初始化时值是0

Integer是引用数据类型,变量中存放的是该对象的引用,变量初始化时值时null

Integer是int类型的包装类,将int封装成Integer,符合java面向对象的特性,可以使用各种方法比如和其他数据类型间的转换

Integer和int的深入对比:

1.两个通过new生成的Integer对象,由于在堆中地址不同,所以永远不相等

2.int和Integer比较时,只要数值相等,结果就相等,因为包装类和基本数据类型比较时,会自动拆箱,将Integer转化为int

3.通过new生成的Integer对象和非通过new生成的Integer对象相比较时,由于前者存放在堆中,后者存放在Java常量池中,所以永远不相等

4.两个非通过new生成的Integer对象比较时,如果两个变量的数值相等且在-128到127之间,结果就相等。这是因为给Integer对象赋一个int值,java在编译时,会自动调用静态方法valueOf(),根据java api中对Integer类型的valueOf的定义,对于-128到127之间的整数,会进行缓存,如果下次再赋相同的值会直接从缓存中取,即享元模式

1.3String和StringBuilder和StringBuffer区别

在 Java 中,String、StringBuilder 和 StringBuffer 分别代表不同的字符串类型,三者底层都是字符数组来存储数据,JDK1.9之后使用的是byte[] ,因为往往我们存储都是短字符串,使用byte[]这样更节约空间。

String类型是一个只读字符串。一旦创建了一个 String 对象,它的内容是不能被修改的,任何的操作都会导致一个新的字符串对象的创建。可以通过 + 运算符或者 concat() 方法来连接两个 String 对象。

StringBuilder 类和 StringBuffer 类都是可变字符串类型,两个类的主要区别是 StringBuffer 是线程安全的,而 StringBuilder 不是。它们都支持在字符串的末尾添加新的字符或字符串,也支持在指定位置插入、删除或替换字符串中的某个子串。

因此,选择哪种字符串类型取决于实际需求:

如果字符串只需要被读取且不需要修改,那么使用 String 类型。
如果需要对字符串进行频繁的插入、删除或替换操作,并且不需要考虑线程安全问题,那么可以使用 StringBuilder,因为这样可以避免频繁地创建新的字符串对象,节省内存空间,提高运行速度。
如果需要同时满足线程安全和可变性的需求,那么可以使用 StringBuffer,但要注意,由于 StringBuffer 的线程安全是通过锁机制实现的,因此它的运行速度会受到一定的影响。

下面是 StringBuilder 和 StringBuffer 类的一些常用方法:

append():将指定的字符串或字符序列添加到当前字符串的末尾。
insert():将指定的字符串或字符序列插入到当前字符串的指定位置处。
delete():删除当前字符串中指定位置的子串。
replace():替换当前字符串中指定位置的子串。
charAt():返回当前字符串中指定位置的字符。
substring():返回当前字符串中指定位置开始到结束位置的子串。

1.4== 和 equals的区别?

解释一:
== 和 equals 是 Java 中用来比较两个对象是否相等的两个方法。

== 是比较两个对象的引用是否相等,即它们是否指向同一个对象。如果两个对象的引用相等,那么它们是相等的;反之,它们不相等。例如:

String str1 = "hello";
String str2 = "hello";
String str3 = new String("hello");System.out.println(str1 == str2);  // true,因为 str1 和 str2 指向同一个对象,都是 "hello" 字符串的常量池实例
System.out.println(str1 == str3);  // false,因为 str1 和 str3 指向不同的对象,一个是常量池实例,一个是堆内存实例

equals 是比较两个对象的内容是否相等。默认情况下,equals 方法与 == 方法作用相同,即比较两个对象的引用。但是,你可以在自己定义的类中重写 equals 方法,来根据实际情况定义比较是否相等。例如

public class Person {private String name;private int age;// ... 此处省略构造器和 getter/setter 方法@Overridepublic boolean equals(Object obj) {if (this == obj) {  // 如果两个对象的引用相等,则它们一定相等return true;}if (obj == null || obj.getClass() != this.getClass()) {  // 如果 obj 为空或者它与本对象的类型不同,则它们不相等return false;}Person other = (Person) obj;  // 把 obj 转换成 Person 类型return this.name.equals(other.name) && this.age == other.age;  // 比较两个对象的 name 和 age 是否相等}
Person p1 = new Person("Tom", 25);
Person p2 = new Person("Tom", 25);
Person p3 = new Person("Jerry", 18);System.out.println(p1.equals(p2));  // true,因为 p1 和 p2 的 name 和 age 都相等
System.out.println(p1.equals(p3));  // false,因为 p1 和 p3 的 name 和 age 不相等

总之,== 比较的是两个对象的引用,而 equals 比较的是两个对象的内容(可以重写这个方法来定义比较的具体操作)。在使用时,要注意不要混淆它们的作用。
解释二:
对于“==”
如果作用于基本数据类型的变量,则直接比较其存储的值是否相等,
如果作用于引用类型的变量,比的是指向的是不是同一个对象,即比较的是所指向的对象的地址是否相等。

对于equals方法,equals方法不能作用于基本数据类型的变量,因为基本数据类型是特殊的,没有集成equals方法.
另外,equals()方法存在于Object类中,而Object类是所有类的直接或间接父类,所以说所有类中的equals()方法都继承自Object类。
在没有重写equals方法的类中,调用equals方法其实和使用==的效果一样,比较的是引用类型的变量所指向的对象的地址;
在重写了equals()方法的类中,调用equals方法比较的是所指向的对象的内容,比如String、Date类,

举例:

Public static void main(String[] args) {//基本数据类型的比较int num1 = 10;int num2 = 10;System.out.println(num1 == num2);  //true//引用数据类型的比较 //String类(重写了equals方法)中==与equals的比较String s1 = "hello";String s2 = "hello";System.out.println(s1 == s2);   //true,比较地址值:内容相同,因为常量池中只有一个“hello”,所以它们的地址值相同System.out.println(s1.equals(s2));//true,比较内容:内容相同,因为常量池中只有一个“hello”,所以它们的地址值相同System.out.println(s1.equals("hello")); //trueString s3 = new String("hello");String s4 = new String("hello");System.out.println(s3 == s4);     //false,比较地址值:s3和s4在堆内存中的地址值不同System.out.println(s3.equals(s4)); //true,比较内容:内容相同//没有重写equals方法的类中==与equals的比较 People p1 = new People();People p2 = new People();People p = p2;System.out.println(p1);//People@135fbaa4System.out.println(p2);//People@45ee12a7System.out.println(p); //People@45ee12a7System.out.println(p1.equals(p2)); //false,p1和p2的地址值不同System.out.println(p.equals(p2)); //true,p和p2的地址值相同}

1.5equals()和hashCode()的联系

hashCode()是Object类的一个方法,用来获取对象的哈希码。,它代表了对象的地址或者是其它任何原始信息的转换值,这个值可以用来在哈希表中查找、插入或删除元素。
而 equals() 方法则是用来比较两个对象是否相等。
由于 hashCode() 和 equals() 通常一起使用(比如在集合类中),因此当你重写了 equals() 方法后也需要同时重写 hashCode() 方法。
具体来说,hashCode() 方法必须遵守以下规则:
如果两个对象使用 equals() 方法比较返回 true,那么这两个对象的 hashCode() 方法也必须返回相同的值。
如果两个对象的 hashCode() 方法返回相同的值,它们并不一定相同,也就是说,hashCode() 方法不能用来判断两个对象是否相等,只能用来优化哈希表等数据结构的查找速度。
如果两个对象使用 equals() 方法比较返回 false,这两个对象的 hashCode() 方法可以返回相同的值,也可以返回不同的值;但是不同的值能够更好地优化哈希表等数据结构的性能。

1.6&和&&的区别

&和&&都是逻辑运算符,但是它们的功能有所不同。

&表示按位与运算符,把运算符两侧都转换成二进制数然后再进行与的运算,只有两个二进制位都为1时,结果才为1,否则为0。

例如:3 & 5

3的二进制表示为11,5的二进制表示为101,进行按位与运算,得到结果为1。

&&表示逻辑与运算符,当两侧的表达式的结果均为 true时,其结果才为 true,只要有一个为false,结果就为false。
&&具有短路功能,即左侧的表达式的结果为false,整个的结果就为false,不再计算右侧的表达式。而&不具有短路功能。
例如:3>2 && 5>6

表达式左边和右边的结果都为true,因此整个表达式的结果为false。

总之,“&”是位运算符,“&&”是逻辑运算符。在大多数情况下,推荐使用“&&”运算符。

1.7final、finally和finalize的区别

1.final 关键字语义是不可改变的,可以修饰类、方法、变量。
用来修饰变量时,表示该变量是一个常量,即变量的值在编译时确定,并且在运行时不能修改。
用来修饰方法时,表示该方法不能被子类重写或继承,只能直接使用。
用来修饰类时,表示该类不能被继承。
功能:用来增加代码的可读性和可维护性,以及避免代码中不合理的修改。

2.finally 关键字通常与 try-catch 语句结合使用,表示不论 try 块中代码是否发生异常,都会执行 finally 块中的代码。finally 块通常用来释放资源、关闭文件等操作。

3.finalize 方法是 Object 类中的一个方法,在对象被垃圾回收器回收之前自动调用。子类可以重写该方法来释放一些非 Java 资源,比如文件句柄、网络连接等。

需要注意的是,虽然 finalize 方法可以用来释放资源,但是它已经被标记为不推荐使用,因为它的调用是由垃圾回收过程控制的,而垃圾回收器的运行不是确定的,不能保证在对象被回收之前一定会执行 finalize 方法。因此,建议使用其它方式来释放资源,比如 try-with-resources 语句块。

1.8JDK 和 JRE 有什么区别?

JDK(Java Development Kit)和 JRE(Java Runtime Environment)是两个不同的 Java 包,它们之间的区别如下:

JDK 包含 JRE。JDK 是 Java 开发工具包,包含了 JRE 以及一些开发工具(比如编译器)和库文件(比如 API 文档)。因此,如果你需要使用 Java 进行开发,需要安装 JDK;如果只是为了运行 Java 应用程序,那么只需要安装 JRE 就可以了。

JRE 只包含 Java 运行时环境,即 Java 虚拟机(JVM),以及 Java 库文件和支持文件。Java 应用程序需要 JRE 才能在计算机上运行。

总之,JDK 包含了 JRE,而 JRE 则只包含 Java 运行时环境。安装 JDK 可以让你进行 Java 开发,而安装 JRE 可以让你运行 Java 应用程序。

1.9switch中能否使用string作为参数

在jdk 1.7之前,switch只能支持byte, short, int,char或者其对应的封装类以及Enum类型作为参数。从jdk 1.7之后switch开始支持String作为参数。

2.0面向对象四大特性

面向对象编程有四大特性,它们分别是:封装、继承、多态和抽象。

封装(Encapsulation):指隐藏对象的属性和实现细节,仅对外暴露接口来实现与外界的交互。封装可以增强代码的可读性和可维护性,因为它将数据保护起来,不容易被错误的使用,还可以避免属性被误修改等问题。

继承(Inheritance):指一个类可以共享另一个类的属性和方法,使得代码可以被复用和扩展。子类继承了父类的所有属性和方法,但是子类也可以重写父类的方法来实现自己的功能,这样就可以实现多态。继承可以减少代码的重复编写,也可以提高代码的可读性。

多态(Polymorphism):指同一个类型的对象,在不同的情况下会表现出不同的行为。在 Java 中,多态包括静态多态和动态多态。静态多态是指重载(Overload),即同一个方法名称可以有多个不同的参数列表和实现,Java 根据方法的参数和返回值指定哪个方法会被调用。动态多态是指重写(Override),即子类可以重写父类的方法,实现自己的逻辑,当父类引用指向子类的对象时,调用的方法就是子类重写后的方法。

抽象(Abstraction):指描述一类事物的共同特征和行为,抽象类是不能被实例化的类,只能被继承。抽象类不能实现自己的方法,只能定义抽象方法,由子类实现具体细节。在实际开发中,抽象类可以用于框架中,定义一些公共的方法,由具体的子类实现细节逻辑。

这四大特性是面向对象编程的重要概念,在实际开发中需要灵活应用,以实现代码的可读性、可扩展性和可维护性。

2.1多态的好处

多态是面向对象编程十分重要的概念,它可以带来以下好处:

增强可扩展性:由于多态允许多个对象响应同一方法,所以可以更方便地添加和修改代码,不需要大量修改原有的代码,从而增强了程序的可扩展性。

代码复用:多态性可以通过定义抽象类或接口来实现,这样可以通过继承和实现,来轻松地复用代码。

简化代码:由于多态可以隐藏实际的对象类型,因此通过多态可以达到一种简化代码的目的,更好的降低代码的复杂度。

提高可维护性:多态具有高内聚低耦合的特性,使得代码的逻辑更清晰,功能更独立,从而提高了代码的可维护性。

2.2代码中如何实现多态

三种方式:

  1. 接口实现

  2. 继承父类重写方法

  3. 同一类中进行方法重载

2.3虚拟机是如何实现多态的

动态绑定技术(dynamic binding),执行期间判断所引用对象的实际类型,根据实际类型调用对应的方法。

2.4方法覆盖和重载

方法的覆盖是子类和父类之间的关系,方法的重载是同一个类中方法之间的关系。 覆盖只能由一个方法,或只能由一对方法产生关系;方法的重载是多个方法之间的关系。 覆盖要求参数列表相同;重载要求参数列表不同。

2.5接口和抽象类的区别

接口和抽象类都是面向对象编程中常用的工具,它们之间的区别在于以下方面:

定义方式:抽象类是通过使用关键字"abstract"来定义的,可以包含抽象方法和普通方法,而接口则是通过使用关键字"interface"来定义的,只能包含抽象方法和常量。

实现:抽象类可以使用继承来实现,子类可以继承抽象类并实现其中的抽象方法,也可以继承普通方法,而接口则是使用实现(implements)来实现的,一个类可以实现多个接口,并实现每个接口中的所有抽象方法。

构造函数:抽象类可以包含构造函数,而接口不可以。

访问修饰符:抽象类可以使用访问修饰符来限制方法和属性的访问权限,而接口中的方法默认为public,属性默认为final static,不能使用任何访问修饰符。

对继承的限制:一个类只能继承一个抽象类,但是可以实现多个接口,这也是接口可以实现多重继承的原因之一。

总的来说,抽象类更适合用于定义一些有共同特性的类之间的关系,而接口则更适合用于定义行为的标准,在多个类中重复使用。

2.6父类的静态方法能否被子类重写

不能。重写只适用于实例方法,不能用于静态方法,而子类当中含有和父类相同签名的静态方法,我们一般称之为隐藏。

2.7什么是不可变对象

不可变对象是指创建后其状态不可被修改的对象。任何修改都会创建一个新的对象,如 String、Integer及其它包装类。

2.8静态变量和实例变量的区别?

存储位置:静态变量属于类,只会被实例化一次,而实例变量属于类的每个实例,每个实例都会有一份实例变量的副本。

生命周期:静态变量的生命周期和类相同,在类被加载时初始化,在整个程序运行期间都存在,而实例变量的生命周期与具体的实例对象相关,在对象创建时初始化,在对象被回收时销毁。

使用方式:静态变量适用于存储类级别的信息,例如类的属性、常量等,可以被所有实例共享,可以直接通过类名访问;而实例变量适用于存储对象的属性信息,每个实例都拥有自己的属性值,需要通过实例对象来访问。

默认值:如果静态变量没有显式初始化,它会被初始化为默认值(通常为0或者null);如果实例变量没有显式初始化,它会被初始化为默认的数据类型值(例如int类型变量默认值为0,String类型变量默认值为null)。

综上所述,静态变量适用于存储类级别的信息,实例变量适用于存储对象属性的信息。

解释二:

静态变量存储在方法区,实例变量存储在堆内存中。

静态变量前要加static关键字,而实例变量前则不加。

静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,给静态变量分配空间,就可以被使用。

实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。

//静态变量
public static int a = 1;
//实例变量
public int b = 1;

2.9java创建对象的几种方式

通过new
通过反射

通过clone
通过序列化机制
前2者都需要显式地调用构造方法。造成耦合性最高的是第一种,因此你发现无论什么框架,只要涉及到解耦必先减少new的使用

3.0什么是克隆

克隆就是根据已有的数据,拷贝出一份完全一样的数据。

实现克隆的方式:

1.可以手工的new出一个新的对象,然后将原来的对象信息一个一个的set到新的对象中。

2.实现Cloneable接口并重写Object类中的clone()方法

3.实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆

在Java中对象的克隆有深克隆和浅克隆之分。有这种区分的原因是Java中分为基本数据类型和引用数据类型,对于不同的数据类型在内存中的存储的区域是不同的。基本数据类型存储在栈中,引用数据类型存储在堆中。

3.1浅克隆和深克隆的区别

1、浅克隆:对当前对象进行克隆,并克隆该对象所包含的8种基本数据类型和String类型属性(拷贝一份该对象并重新分配内存,即产生了新的对象);但如果被克隆的对象中包含除8中数据类型和String类型外的其他类型的属性,浅克隆并不会克隆这些属性(即不会为这些属性分配内存,而是引用原来对象中的属性)

2、深克隆:深拷贝会完全复制整个对象,包括这个对象所包含的内部对象

浅克隆中由于除8中数据类型和String类型外的其他类型的属性不会被克隆,因此当通过新对象对这些属性进行修改时,原对象的属性也会同时改变。而深克隆则已经对这些属性重新分配内存,所以当通过新对象对这些属性进行修改时,原对象的属性不会改变。

举例:现有Employee类,其中有成员属性为Person类对象

public class Employee implements Cloneable{private String name;private int age;private Person person;}

例如将e1 克隆给 e2;浅克隆时, e2和e1中的person对象指向了同一个地址;也就是说我们修改了e1中的person属性,那么e2中的person属性也会被修改;而深克隆实现后e1,和e2就是完全独立的两个对象,不会相互干扰。

3.2你知道BIO,NIO,AIO么?讲一下你的理解

AIO ( Asynchronous I/O):异步非阻塞I/O 模型,适用于连接数目多且连接比较长(重操作)的架构

BIO (Blocking I/O):同步阻塞I/O 模式,以流的方式处理数据,数据的读取写入必须阻塞在一个线程内等待其完成。适用于连接数目比较小且固定的架构

NIO (New I/O):同时支持阻塞与非阻塞模式,以块的方式处理数据,适用于连接数目多且连接比较短(轻操作)的架构,比如聊天器

3.3java 中四大基础流

InputStream : 输入字节流, 也就是说它既属于输入流, 也属于字节流 ,

OutputStream: 输出字节流, 既属于输出流, 也属于字节流

Reader: 输入字符流, 既属于输入流, 又属于字符流

Writer: 输出字符流, 既属于输出流, 又属于字符流

读文本用什么流,读图片用什么流

文本用字符输入流,读图片用字节输入流

3.4字符流和字节流有什么区别

字符流适用于读文本,字节流适用于读图片,视频,文件等。

字节流操作的基本单元为字节;字符流操作的基本单元为Unicode码元。

字节流默认不使用缓冲区;字符流使用缓冲区。

字节流通常用于处理二进制数据,实际上它可以处理任意类型的数据,但它不支持直接写入或读取Unicode码元;字符流通常处理文本数据,它支持写入及读取Unicode码元

BufferedInputStream 用到什么设计模式

主要运用了俩个设计模式,适配器和装饰者模式

带缓冲区的流

BufferedInputStream 带缓冲区的字节输入

BufferedOutputStream 带缓冲区的输出流

BufferedReader : 带缓冲区的字符输入流

BufferedWriter : 带缓冲区的字符输出流

3.5.java当中的四种引用

强引用,软引用,弱引用,虚引用。不同的引用类型主要体现在GC上:

强引用:普通变量赋值即为强引用, 如Aa = new A(); 如果一个对象具有强引用,它就不会被垃圾回收器回收。即使当前内存空间不足,JVM也不会回收它,而是抛出 OutOfMemoryError 错误,使程序异常终止。如果想中断强引用和某个对象之间的关联,可以显式地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。

软引用:在使用软引用时,首次垃圾回收不会回收该对象,如果内存仍不足,再次回收时才会释放对象,软引用自身需要配合引用队列来释放,典型例子是反射数据.

弱引用:弱引用引用该对象时,只要发生垃圾回收,就会释放该对象,弱引用自身需要配合引用队列来释放,典型例子 是ThreadLocalMap中的Entry对象

虚引用:必须配合引用队列一起使用,如果一个对象仅持有虚引用,那么它相当于没有引用,在任何时候都可能被垃圾回收器回收。

3.6如何正确退出多层嵌套循环?

1.使用标号和break;

2.通过在外层循环中添加标识符

3.7Java异常Error和Exception的区别

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oVJccs2h-1666779046477)(file:///C:\Users\浮心尘\AppData\Local\Temp\ksohtml17960\wps1.jpg)]

异常:

检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。

运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。

错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

Error:Error类对象由 Java虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关。例如,Java虚拟机运行错误(VirtualMachineError),当JVM不再有继续执行操作所需的内存资源时,将出现OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止;还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError)、链接错误(LinkageError)。这些错误是不可查的,因为它们在应用程序的控制和处理能力之
外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在Java中,错误通常是使用Error的子类描述。

Exception:在Exception分支中有一个重要的子类RuntimeException(运行时异常),该类型的异常为你所编写的程序出现ArrayIndexOutOfBoundsException(数组下标越界)、NullPointerException(空指针异常)、ArithmeticException(算术异常)、MissingResourceException(丢失资源)、ClassNotFoundException(找不到类)等异常,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生;而RuntimeException之外的异常我们统称为非运行时异常,类型上属于Exception类及其子类,从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Al4Xpa4g-1666779046478)(file:///C:\Users\浮心尘\AppData\Local\Temp\ksohtml17960\wps2.jpg)]

3.8获得一个类的类对象有哪些方式

方式一:调用运行时类的属性:.class(适用于编译期间已知的类型)

Class clazz1 = Person.class;

System.out.println(clazz1);

方式二:通过运行时类的对象,调用getClass()

Person p1 = new Person();

Class clazz2 = p1.getClass();

System.out.println(clazz2);

这个方法在 java.lang.Object 类型中声明的,可以获取该对象的运行时类型的 Class 对象;

适用情况:必须先有对象,才能获取 Class 对象

方式三:调用Class的静态方法:forName(String classPath)

Class clazz3 = Class.forName(“com.java.Person”);

clazz3 = Class.forName(“java.lang.String”);

System.out.println(clazz3);

该方法需要传入一个字符串参数,该值是某个类的全限定名(即完整的包.类型名),该方法适用于除了数组以外的任意引用数据类型;

已知一个类的全类名,且该类在类路径下, 可通过Class类的静态方 法forName()获取,可能抛出ClassNotFoundException。

多用于配置文件,将类名定义在配置文件中,读取文件,加载类。

优点:这个类型可以在编译期间未知,这个类名称可以在代码中出现,也可以配置在配置文件中,或键盘输入等方式来指定

3.9JDBC操作数据库的基本步骤

· 加载(注册)数据库驱动(到JVM)。

· 建立(获取)数据库连接。

· 创建(获取)数据库操作对象。

· 定义操作的SQL语句。

· 执行数据库操作。

· 获取并操作结果集。

· 关闭对象,回收数据库资源(关闭结果集–>关闭数据库操作对象–>关闭连接)

4.0Statement和PreparedStatement的区别

操作数据库具体步骤

首先导入java.sql.*;这个包。

然后加载驱动,创建连接,得到Connection接口的的实现对象,比如对象名叫做conn。

然后再用conn对象去创建Statement的实例,方法是:Statement stmt = conn.creatStatement(“SQL语句字符串”);

Statement 对象用于将 SQL 语句发送到数据库中。

Statement每次执行sql语句,数据库都要执行sql语句的编译,最好用于仅执行一次查询并返回结果的情形,效率高于PreparedStatement,但存在sql注入风险。

PreparedStatement是预编译执行的。在执行可变参数的一条SQL时,PreparedStatement要比Statement的效率高,因为DBMS预编译一条SQL当然会比多次编译一条SQL的效率高。安全性更好,有效防止SQL注入的问题。对于多次重复执行的语句,使用PreparedStatement效率会更高一点。执行SQL语句是可以带参数的,并支持批量执行SQL。

4.1数据库连接池的基本原理与作用

基本原理:

在内部对象池中,维护一定数量的数据库连接,并对外暴露数据库连接的获取和返回方法。

如外部使用者可通过getConnection方法获取数据库连接,使用完毕后再通过releaseConnection方法将连接返回,注意此时的连接并没有关闭,而是由连接池管理器回收,并为下一次使用做好准备

作用:

1.资源重用

  1. 更快的系统响应速度

  2. 新的资源分配手段

  3. 统一的连接管理,避免数据库连接泄露

4.2什么是DAO模式

DAO(Data Access Object)顾名思义是一个为数据库提供了抽象接口的对象,在不暴露底层持久化方案实现细节的前提下提供了各种数据访问操作。在实际的开发中,应该将所有对数据源的访问操作进行抽象化后封装在一个公共API中。用程序设计语言来说,就是建立一个接口,接口中定义了此应用程序中将会用到的所有事务方法。在这个应用程序中,当需要和数据源进行交互的时候则使用这个接口,并且编写一个单独的类来实现这个接口,在逻辑上该类对应一个特定的数据存储。

DAO模式实际上包含了两个模式,一是Data Accessor(数据访问器),二是Data Object(数据对象),前者要解决如何访问数据的问题,而后者要解决的是如何用对象封装数据

4.3Java实现单例模式

java中的单例模式是一种常见的设计模式,主要介绍懒汉式单例、饿汉式单例、
单例模式:通俗地说,就是一个类只能创建一个对象,并且在程序的任何地方都能够访问到该对象。

单例模式的五种实现方式:

1饿汉式

饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。

public class Singleton1 {private static final Singleton1 instance = new Singleton1();//私有化构造方法private Singleton1() {}public static Singleton1 getInstance() {return instance;}
}

测试:

public class SingletonTest {public static void main(String[] args)  {System.out.println(Singleton1.getInstance());}}
2.枚举-饿汉式:

线程安全的,能防止反序列化导致重新创建新的对象保证只有一个实例

/*** 枚举--饿汉式*/
public enum  Singleton2 {instance;private Singleton2(){System.out.println("private singleton2");}@Overridepublic String toString() {return getClass().getName()+"@"+Integer.toHexString(hashCode());}public static Singleton2 getInstance(){return instance;}public static void otherMethod(){System.out.println("otherMethod");}}
3懒汉式—在第一次调用的时候进行实例化
//懒汉式单例类.在第一次调用的时候实例化对象
public class Singleton3 {//私有化构造方法private Singleton() {}private static Singleton instance=null;//静态工厂方法 public static Singleton getInstance() {if (instance == null) {  instance = new Singleton();}  return instance;}
}

它是线程不安全的,并发环境下很可能出现多个Singleton实例。

/*** 解决方法1.在getInstance方法上加同步锁*/
public class Singleton3 implements Serializable {//私有化构造方法private Singleton3(){};private static Singleton3 instance=null;//如果没有synchronized,则线程不安全public static synchronized Singleton3 getInstance(){if (instance==null){instance=new Singleton3();}return instance;}
}
4.双检索懒汉式

解决方法2:双重检查锁定

public class Singleton4 implements Serializable {//私有化构造方法private Singleton4(){};private static volatile Singleton4 instance=null;//可见性、有序性//先判断实例是否存在,若不存在再对类对象进行加锁处理public static Singleton4 getInstance(){if (instance==null){synchronized (Singleton4.class){if (instance==null){instance=new Singleton4();}}}return instance;}
}
5. 内部类懒汉式(推荐):

解决方法3:既实现了线程安全,又避免了同步带来的性能影响。

public class Singleton5 implements Serializable {//私有化构造方法private  Singleton5(){};//一个私有的静态内部类,用于初始化一个静态final实例private static class Holder{private static final Singleton5 instance=new Singleton5();}public static Singleton5 getInstance(){return Holder.instance;}
}

就我个人而言,一般情况下直接使用饿汉式就好了,如果明确要求要懒加载(lazy initialization)会倾向于使用静态内部类,如果涉及到反序列化创建对象时会试着使用枚举方式来实现单例。

4.4finally一定会执行吗

在执行try语句块之前直接return,我们发现finally块是不会执行的。

在执行try语句块之前制造一个错误,直接爆红。

不管是在try语句块中造了个异常,还是在try语句块中进行return,我们发现finally块还是会执行的。

4.5动态代理

动态:在这里指Java运行时生成的

代理:在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。

静态代理指的是我们预先编码好一个代理类,而动态代理指的是运行时生成代理类。

动态代理在 Java 中有着广泛的应用,比如 AOP 的实现原理、RPC远程调用、Java 注解对象获取、日志框架、全局性异常处理、事务处理等。

静态代理,是硬编码到代码中,功能在运行时之前就有;动态代理,不是硬编码,必须在运行时才能生成。

4.6JDK 动态代理与 CGLIB 区别

JDK 动态代理是基于接口的,所以要求代理类一定是有定义接口的。

CGLIB 基于ASM字节码生成工具,它是通过继承的方式来实现代理类,所以要注意 final 方法

JDK 动态代理实现原理:

首先通过实现 InvocationHandler 接口得到一个切面类。

然后利用 Proxy 根据目标类的类加载器、接口和切面类得到一个代理类。

代理类的逻辑就是把所有接口方法的调用转发到切面类的 invoke() 方法上,然后根据反射调用目标类的方法。

4.7反射

在java中,反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。本质就是得到class对象后,反向获取类对象的各种信息。

Java反射机制的主要功能:

1、在运行时判断任意一个对象所属的类;

2、在运行时构造任意一个类的对象;

3、在运行时调用任意一个对象的方法等

4.8类加载

类加载过程:加载——>链接——>初始化——>使用——>卸载,链接部分又可以分为三步:验证——>准备——>解析

类加载过程主要分为三个阶段

加载

①将类的字节码载入方法区, 并创建类.class对象

②如果此类的父类没有加载, 先加载父类

③加载是懒惰执行

链接

①验证-验证类是否符合Class规范,合法性、安全性检查

验证包含类数据信息的格式验证、语义检查、字节码验证,以及符号引用验证等

②准备- 为类的静态变量分配空间,设置默认值

③解析- 将常量池(类、接口、字段和方法)的符号引用解析为直接引用

初始化

①执行执行初始化方法、静态代码块;为类的静态变量赋予正确的初始值

②初始化是懒惰执行

4.9双亲委派

Java 自身提供了 3 种类加载器:

1、启动类加载器 bootstrap classloader :加载jre/lib/rt.jar

2、扩展类加载器 extension classloader :加载jre/lib/ext/*.jar

3、应用程序类加载器 application classloader:加载classpath上指定的类库

双亲委派机制

双亲委派机制是指当一个类加载器收到一个类加载请求时,该类加载器首先会把请求委派给父类加载器。每个类加载器都是如此,只有当父类加载器在自己的搜索范围内找不到指定类时,子类加载器才会尝试自己去加载。

双亲委派的目的有两点

①让上级类加载器中的类对下级共享(反之不行),即能让你的类能依赖到jdk提供的核心类

②让类的加载有优先次序, 保证核心类优先加载

自己编写类加载器就能加载一个假冒的java.lang.System吗?

①假设你自己的类加载器用双亲委派,那么优先由启动类加载器加载真正java.lang.System,自然不会加载假冒的

②假设你自己的类加载器不用双亲委派,那么你的类加载器加载假冒的java.lang.System时,它需要先加载父类java.lang.Object,而你没有用委派,找不到java.lang.0bject所以加载会失败

③以上也仅仅是假设。实际操作你就会发现自定义类加载器加载以java.打头的类时,会抛安全异常,在jdk9以上版本这些特殊包名都与模块进行了绑定,更连编译都过不了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0f9hhIWt-1666779046478)(file:///C:\Users\浮心尘\AppData\Local\Temp\ksohtml17960\wps3.jpg)]

5.0什么是序列化?什么是反序列化

序列化其实就是将对象转化成可传输的字节序列格式,以便于存储和传输。

反序列化就是将字节序列格式转换成对象的过程。

序列化的实现:将需要被序列化的类实现serializable接口

什么时候使用序列化:

1、对象序列化可以实现分布式对象

2、java对象序列化不仅保留一个对象的数据,而且递归保存对象引用的每个对象的数据

3、序列化可以将内存中的类写入文件或数据库中

4、对象、文件、数据有许多不同的格式,很难统一传输和保存

5.1什么是事务?

事务是逻辑上的一组操作,要么都执行,要么都不执行。
事务最经典也经常被拿出来说例子就是转账了。

假如小明要给小红转账100元,这个转账会涉及到两个关键操作就是:小明的余额减少1000元,将小红的余额增加1000元。如果这两个操作之间突然出现错误比如银行系统崩溃,导致小明余额减少而小红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败。

1.事务的ACID是什么

(1).原子性(Atomicity):一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即事务不可分割,不可约简。
(2). 一致性(Consistency):事务开始之前和事务结束以后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。
(3). 隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账
(4).持久性(Durability):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

2.事务的并发问题

脏读:(读取未提交数据)
A事务读取B事务尚未提交的数据,此时如果B事务发生错误并执行回滚操作,那么A事务读取到的数据就是脏数据。
不可重复读:(前后多次读取,数据内容不一致)
事务A多次读取同一数据,事务B在事务A多次读取的过程中,对数据作了修改并提交,导致事务A多次读取同一数据时,结果不一致。
幻读:(前后多次读取,数据总量不一致)
事务A在执行读取操作,需要两次统计数据的总量,前一次查询数据总量后,此时事务B执行了新增数据的操作并提交后,这个时候事务A读取的数据总量和之前统计的不一样,就像产生了幻觉一样,平白无故的多了几条数据,成为幻读。

3.事务隔离级别

事务的隔离级别分为:读未提交(read uncommitted)、读已提交(read committed)、可重复读(repeatable read)、串行化(serializable)。

read uncommitted(读未提交): 即一个事务可以读取另一个未提交事务的数据;并发操作时会导致脏读,不能解决脏读、不可重复读、幻读。
read committed(读已提交): 允许读取并发事务已经提交的数据,解决脏读问题,并发操作会导致幻读或不可重复读。
repeatable read(可重复读): 对同一字段的多次读取结果都是一致的,不再允许修改操作,可以阻止脏读和不可重复读,但仍有可能发生幻读。
serializable(可串行化): 最高的隔离级别,所有的事务顺序执行,事务之间就完全不可能产生干扰,该级别可以防止脏读、不可重复读以及幻读。但是该级别效率低下,会导致大量的操作超时和锁竞争,从而大大降低数据库的性能,一般不使用这样事务隔离级别

4.如何解决事务的并发问题(脏读,幻读)

要想解决脏读、不可重复读、幻读等读现象,那么就需要提高事务的隔离级别。但与此同时,事务的隔离级别越高,并发能力也就越低。

为了解决上述问题,数据库通过锁机制解决并发访问的问题。

根据锁定对象不同:分为行级锁和表级锁;
根据并发事务锁定的关系上看:分为共享锁定和独占锁定,共享锁定会防止独占锁定但允许其他的共享锁定。而独占锁定既防止共享锁定也防止其他独占锁定。为了更改数据,数据库必须在进行更改的行上施加行独占锁定,insert、update、delete和select for update语句都会隐式采用必要的行锁定。

但是直接使用锁机制管理是很复杂的,基于锁机制,数据库给用户提供了不同的事务隔离级别。

脏读的表现和具体解决并发问题

脏读就是指:A事务读取B事务尚未提交的数据,此时如果B事务发生错误并执行回滚操作,那么A事务读取到的数据就是脏数据。

解决:

修改时加排他锁,直到事务提交后才释放;

读取时加共享锁,读取完释放事务1读取数据时加上共享锁后(这样在事务1读取数据的过程中,其他事务就不会修改该数据),不允许任何事物操作该数据,只能读取,之后1如果有更新操作,那么会转换为排他锁,其他事务更无权参与进来读写,这样就防止了脏读问题。

但是当事务1读取数据过程中,有可能其他事务也读取了该数据,读取完毕后共享锁释放,此时事务1修改数据,修改完毕提交事务,其他事务再次读取数据时候发现数据不一致,就会出现不可重复读问题,所以这样不能够避免不可重复读问题。

不可重复读/ 幻读 的表现和具体解决并发问题

不可重复读:在同一事务中,前后多次读取,得到的数据内容不同
幻读:同一事务中,前后多次读取,数据总量不一致

解决:

读取数据时加共享锁,写数据时加排他锁,都是事务提交才释放锁。读取时候不允许其他事物修改该数据,不管数据在事务过程中读取多少次,数据都是一致的,避免了不可重复读问题

5.mysql怎么保证原子性?

为了保证事务的原子性,就需要在异常发生时,对已经执行的操作进行回滚,在 MySQL 中,恢复机制是通过 回滚日志(undo log) 实现的,所有事务进行的修改都会先记录到这个回滚日志中,然后再执行相关的操作。如果执行过程中遇到异常的话,我们直接利用回滚日志中的信息将数据回滚到修改之前的样子即可。并且回滚日志会先于数据持久化到磁盘上,这样就保证了即使遇到数据库突然宕机等情况,当用户再次启动数据库的时候,数据库还能够通过查询回滚日志,将之前未完成的事务重新执行。

5.2说说MySQL索引,以及它们的好处和坏处

索引主要分为普通索引、唯一索引、主键索引、全文索引、组合索引几种;

好处:在大数据量的查询中,创建索引可以大幅提高系统性能,提高数据查找的效率,降低查询中分组和排序的时间,加速表与表之间的链接。

坏处:索引的存储需要占用磁盘空间,消耗存储资源;同时也增大了增删改操作的维护成本,因为每个增删改操作后相应列的索引都必须被更新

只要创建了索引,就一定会走索引吗? 不一定。 比如,在使用组合索引的时候,如果没有遵从“最左前缀”的原则进行搜索,则索引是不起作用的。

5.3Java 支持多继承么?

不支持,java中的一个类只能继承一个类,但可以实现多个接口。

1.面试题--Java基础相关推荐

  1. java面试题——java基础(四),java初级面试笔试题

    我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家. 扫描二维码或搜索下图红色VX号,加VX好友,拉你进[程序员面试学习交流群]免费领取.也欢迎各位一起 ...

  2. Android面试题Java基础篇

    Android面试题Java基础篇,由本人整理汇总,后续将继续推出系列篇,如果喜欢请持续关注和推荐,更多精彩内容可以关注微信公众号(Android高级编程):android-tech 系列文章目录: ...

  3. java实体类转map_十五道经典面试题-JAVA基础篇

    十五道JAVA基础面试题送给有需要的童鞋,但是不得不多提醒一句,打铁还需自身硬,计算机软件这个行业,技术和学历才是王道.好了,废话不多说,上菜: 一:面向对象的特征有哪些方面 1. 抽象:抽象就是忽略 ...

  4. Java校招笔试题-Java基础部分(七)

    导语   Java 面试题集2021版 Java基础部分七 73.Set 和List的区别? 74.集合框架中Collection 和Arrays 类的作用 75.TreeSet 里面放对象,如果同时 ...

  5. Java校招笔试题-Java基础部分(六)

    导语   Java 面试题集2021版 Java基础部分六 62.ArrayList和LinkedList 有什么异同之处? 63.HashMap和HashTable的区别 64.List和Map的区 ...

  6. Java校招笔试题-Java基础部分(五)

    导语   Java 面试题集2021版 Java基础部分五 47.String 和String Buffer的区别 48.StringBuffer和StringBuilder的区别 49.数组有没有l ...

  7. Java校招笔试题-Java基础部分(四)

    导语   Java 面试题集2021版 Java基础部分三 37.abstract 的method 是否可同时是static,是否可同时是native,是否可同时是synchronized? 38.什 ...

  8. Java校招笔试题-Java基础部分(三)

    导语   Java 面试题集2021版 Java基础部分三 26.说说has a 与is a的区别 27.一个房间里有一把椅子,椅子有四条腿,房子和椅子是什么关系,椅子和椅子腿是什么关系? 28.什么 ...

  9. Java校招笔试题-Java基础部分(二)

    导语   Java面试题集2021版 Java基础部分二 14.hashCode方法的作用? 15.写clone()方法时,通常都有一行代码,这行代码是什么? 16.静态变量和实例变量的区别? 17. ...

  10. Java校招笔试题-Java基础部分(一)

    导语   Java面试题集2021版 Java基础部分 1.一个.java 源文件中是否可以包括多个类(不是内部类)?有什么限制? 2.Java中有没有goto? 3.说说& 和 && ...

最新文章

  1. linux dump用法,Linux命令之tcpdump命令用法介绍
  2. H3C交换机常用巡检命令
  3. 【深度学习】用于小目标检测的一个简单高效的网络
  4. C++、python、CUDA性能分析--矩阵乘法
  5. vuepress build提示YAMLException: end of the stream or a document separator is expected at line 7, colu
  6. python flask 上传下载 api_python – 使用Flask上传和下载文件
  7. 基于matlab的信号与系统实例,华南理工大学信号与系统实验基于Matlab的信号处理实例...
  8. imread函数_不知道这 7 大 OpenCV 函数怎么向计算机视觉专家进阶?
  9. nodejs 密码加盐
  10. 约瑟夫环c语言不用链表,C语言基于循环链表解决约瑟夫环问题的方法示例
  11. 什么是xserver和xclient
  12. Python获取对象所占内存大小方法
  13. 重启计算机可以使用什么组合键,win10系统重启电脑的快捷键是什么呢?
  14. Apple自动化利器AppleScript
  15. ir-keytable + lirc 红外控制开关机及程序运行 armbian搞机篇
  16. Pyton入门的歪路
  17. 【转载】如何从win8/8.1中文版(核心版)升级到win8/8.1专业版
  18. Android终端实现个人中心界面
  19. 游戏中人工智能的优化
  20. UVA之11549 - Calculator Conundrum

热门文章

  1. VUE 项目落地页使用 LinkedME 深度链接服务跳回App
  2. python迭代器和for循环区别_python迭代器和for循环区别,
  3. vivo全球商城:库存系统架构设计与实践
  4. Oracle instant clinet 连接数据库注意
  5. 生鲜商超行业如何通过微信做增长?
  6. 3天时间,给你一个完整的APP设计模型
  7. 故障特效AE视频模板 Modern Glitch Intro
  8. 再谈NAND 【转】 关于SSD的二三事,NAND闪存的一些常识
  9. 获取手机号码/判断Sim卡状态
  10. ant design图片hover蒙层