面试-Java
面试-Java
基础
Java八大基本类型
问:Java八大基本类型
答:Byte(1) Short(2) Int(4) Long(8) Float(4) Double(8) Char(2) Boolean(1)
String类中常用的方法
问:String类中常用的方法
答:indexof()从指定字符提取索引位置
replace()替换
subString()截取字符串
equals()比较
split()把字符串分割成字符串数组
为什么要同时重写HashCode和Equals方法
问:为什么要同时重写HashCode和Equals方法
答:官方规定如果两个对象通过equals()方法比较是相等的,那么它们的hashCode()方法必须返回相同的整数值。反之hashCode相同的对象,equals不一定相等。hashCode不同的对象,equals一定不相等。如果只重写一个就会违反这个约定,导致HashMap或HashSet出现重复数据等情况。
String中 == 和equals的区别
问:String中的 == 和equals的区别
答:对于八大基本类型 == 比较的是值,对于引用类型==比较内存地址。
对于引用类型equals默认比较内存地址。
对于String来说 == 比较的是内存地址,equals重写了比较的是内容。
说说Final关键字
问:说说Final关键字
答:Final是一个安全修饰符,Final修饰的类不能被继承,Final声明的方法不能被重写。Final声明的变量不能被修改。
说五个开发中常见的异常
问:说五个开发中常见的异常
答:IO异常
null异常
SQL异常
数组下标越界异常
文件未找到异常
什么是重载和重写
问:什么是重载和重写
答:Java里面方法的重写和重载就是指Java的多态。重写就是父类和子类之间的多态,方法名和参数都一样。重载是一个类中方法的多态,方法名相同而参数不同。
接口和抽象类的异同
问:接口和抽象类的异同
答:
相同点:
接口和抽象类都是抽象的,不能直接实例化,只能被子类实现或继承,并且可以包含抽象方法(没有具体实现),接口和抽象类都用于定义一种规范或者协议,描述类应该具备的行为和功能。
不同点:
接口中的方法都是抽象的,不能有具体的实现;而抽象类中可以包含具体的方法实现,也可以包含抽象方法。Java中一个类只能继承一个父类,但是可以实现多个接口。因此,接口支持多继承,而抽象类不支持多继承。接口中的变量默认是public static final类型的常量,不能被修改;抽象类中可以定义实例变量,并且可以有各种访问控制修饰符。接口中不能包含构造方法;抽象类可以包含构造方法,用于被子类调用。接口主要用于实现类之间的解耦,描述类应该具备的行为,强调规范和契约;而抽象类主要用于作为其他类的基类,提取共性的方法和属性,强调类的继承关系和代码复用。
创建对象的几种方法
问:创建对象的几种方法
答:
第一种:使用new关键字
第二种:通过反射,可以根据类名来创建对象。Class.forName("com.example.MyClass");然后使用Class类的newInstance()方法:该方法会调用类的无参构造方法来创建对象,要求类必须有无参构造函数
第三种:使用clone()方法:通过复制一个现有对象来创建一个新对象,要求被复制的类必须实现Cloneable接口,并且重写clone()方法。
package com.tensoflow;
public class test {
public static void main(String[] args) throws Exception {
// 方式一使用new关键字
A a = new A();
System.out.println(a.name);
// 方式二使用反射
Class<?> aClass = Class.forName("com.tensoflow.A");
// 调用无参构造创建实例(JDK9+不推荐)
Object instance = aClass.newInstance();
// 若需要调用类的方法,需向下转型
if (instance instanceof A) {
A aInstance = (A) instance;
System.out.println(aInstance.name);
}
// 方式三使用Clone克隆, A类需要实现CloneAble接口然后重写clone方法
A clone = (A) a.clone();
System.out.println(clone.name);
}
}
package com.tensoflow;
public class A implements Cloneable{
String name = "TenSoFlow";
// 重写 clone() 方法
@Override
public Object clone() throws CloneNotSupportedException {
// 调用父类Object的 clone() 方法,完成浅拷贝
return super.clone();
}
}
什么是反射,能干嘛
问:什么是反射,能干嘛
答:反射就是将类的各个组成部分封装成其它对象。在Java中只要知道类的名字,通过Class.forName方法可以获得到类对象。通过Class类对象就可以获得类的所有信息。比如类中的成员变量和方法。我们可以对类里的这些方法进行执行或者用动态代理模式进行增强。我们常用的Spring和MyBatis框架就是利用Java反射+动态代理的技术编写的。
package com.tensoflow;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 反射操作 Student 类的完整示例
*/
public class ReflectDemo {
public static void main(String[] args) {
try {
// 获取 Class 对象
Class<?> studentClass = Class.forName("com.tensoflow.Student");
System.out.println("=== 1. 获取类基本信息 ===");
System.out.println("类名:" + studentClass.getName()); // 完整类名
System.out.println("简单类名:" + studentClass.getSimpleName()); // 仅类名
System.out.println("\n=== 2. 创建 Student 实例 ===");
// 调用公有有参构造创建实例
Constructor<?> publicConstructor = studentClass.getConstructor(String.class, int.class);
Object student1 = publicConstructor.newInstance("张三", 20);
System.out.println("有参构造创建的实例:" + student1);
// 调用私有无参构造创建实例(突破访问权限)
Constructor<?> privateConstructor = studentClass.getDeclaredConstructor();
privateConstructor.setAccessible(true); // 关闭访问检查
Object student2 = privateConstructor.newInstance();
System.out.println("私有构造创建的实例:" + student2);
// ===================== 操作字段 =====================
System.out.println("\n=== 3. 操作字段 ===");
// 3.1 访问公有字段 age
Field ageField = studentClass.getField("age");
ageField.set(student2, 18); // 给 student2 的 age 赋值 18
System.out.println("student2 的 age 字段:" + ageField.get(student2)); // 18
// 3.2 访问私有字段 name(突破访问权限)
Field nameField = studentClass.getDeclaredField("name");
nameField.setAccessible(true); // 关闭访问检查
nameField.set(student2, "李四"); // 给 student2 的 name 赋值 李四
System.out.println("student2 的 name 字段:" + nameField.get(student2)); // 李四
// 3.3 访问静态字段 school
Field schoolField = studentClass.getField("school");
System.out.println("静态字段 school 原值:" + schoolField.get(null)); // 北京大学(静态字段传 null)
schoolField.set(null, "清华大学"); // 修改静态字段
System.out.println("静态字段 school 新值:" + schoolField.get(null)); // 清华大学
// ===================== 4. 调用方法(反射方式) =====================
System.out.println("\n=== 4. 调用方法 ===");
// 4.1 调用公有方法 study
Method studyMethod = studentClass.getMethod("study", String.class);
studyMethod.invoke(student1, "Java编程"); // 张三 正在学习 Java编程
// 4.2 调用私有方法 sayHello(突破访问权限)
Method sayHelloMethod = studentClass.getDeclaredMethod("sayHello", String.class);
sayHelloMethod.setAccessible(true); // 关闭访问检查
String result = (String) sayHelloMethod.invoke(student1, "大家好!");
System.out.println("私有方法返回值:" + result); // [张三]:大家好!
// 4.3 调用静态方法 printSchool
Method printSchoolMethod = studentClass.getMethod("printSchool");
printSchoolMethod.invoke(null); // 学校:清华大学(静态方法传 null)
} catch (Exception e) {
// 捕获所有反射相关异常
e.printStackTrace();
}
}
}
package com.tensoflow;
/**
* 普通学生类
*/
public class Student {
// 私有字段
private String name;
// 公有字段
public int age;
// 静态字段
public static String school = "北京大学";
// 无参构造(私有)
private Student() {}
// 有参构造(公有)
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// 私有方法
private String sayHello(String msg) {
return "[" + name + "]:" + msg;
}
// 公有方法
public void study(String course) {
System.out.println(name + " 正在学习 " + course);
}
// 静态方法
public static void printSchool() {
System.out.println("学校:" + school);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{name='" + name + "', age=" + age + "}";
}
}
类的初始化过程
问:类的初始化过程
答:加载Class文件进内存,在栈内存开辟空间,在堆内存为对象开辟空间,对对象的成员变量进行默认初始化,对对象的成员变量进行显示初始化。通过构造方法对对象的成员变量赋值,把对象地址赋值给变量。
集合
ArrayList的底层
问:ArrayList的底层
答:ArrayList是基于数组实现的,是一个动态数组。底层维护了一个Object类型的数组elementData。如果使用无参构造器,则初始elementData容量为0,第一次添加扩容为10,之后如需再次扩容,则扩容为elementData的1.5倍。如果使用指定大小的构造器则初始elementData容量为指定大小,如果需要扩容,则直接扩容为elementData的1.5倍。另外ArrayList是线程不安全的。
HashMap的底层实现原理
问:HashMap的底层实现原理
答:HashMap的底层是数组+链表+红黑树。数组的初始大小是16,每个数组存储着一个链表。存数据时先根据Key的hashcode值计算出hash值,然后用hash值确定在数组中的位置,如果此位置没有东西则直接放入,如果有就会生成链表,把新的放入链表尾部。当取值时,会先根据Key的hashcode值计算出hash值,确定在数组中的位置,再根据equals方法从该位置上的链表中取出value值。如果数组的长度大于64并且链表的长度大于8就会树化成红黑树。数组扩容倍数是2倍。
项目
Jar包和War包的区别
问:Jar包和War包的区别
答:jar包就是别人写好的一些类,然后对这些类进行打包,开发人员可以将这些jar包引入到自己的项目中,使用这些类和属性。 jar包一般放在lib目录下。war包是一个web模块,可以直接运行,一般开发好的网站,打包后部署到tomcat的网站根目录下,然后重启tomcat,这个包就可以自动解压,相当于代码发布。
四种请求方式
问:四种请求方式
GET
POST
PUT
DELETE
各类默认端口号
问:各类默认端口号
tomcat:8080
MySql: 3306
Redis: 6379
Http:80
Https: 443
Http各类状态码
问:Http各类状态码
1xx 信息性状态码:100 Continue:服务器已收到请求的一部分,客户端应继续发送剩余部分。
101 Switching Protocols:服务器已经理解了客户端的请求,并将通过Upgrade消息头通知客户端更改协议。
其他1xx状态码用于协议交互中。
2xx 成功状态码:
200 OK:请求已成功。
201 Created:请求已经被实现,并且创建了新的资源。
204 No Content:服务器成功处理了请求,但没有返回任何内容。
3xx 重定向状态码:
301 Moved Permanently:请求的资源已永久移动到新位置。
302 Found:请求的资源已暂时移动到新位置。
304 Not Modified:客户端发送的请求已经存在且未修改,服务器告诉客户端使用本地缓存版本。
4xx 客户端错误状态码:
400 Bad Request:请求无效。
401 Unauthorized:请求要求用户身份认证。
403 Forbidden:服务器理解请求,但拒绝执行。
404 Not Found:请求的资源未找到。
5xx 服务器错误状态码:
500 Internal Server Error:服务器遇到了一个未知的错误。
502 Bad Gateway:服务器作为网关或代理时收到了无效的响应。
503 Service Unavailable:服务器暂时过载或维护,无法处理请求。
504 Gateway Timeout:服务器作为网关或代理时未及时从上游服务器收到请求。
