java基础面试题
1. 重载和重写的区别
重载:一个类中定义多个同名的方法,要求其方法的参数类型不同或参数个数不同。
重载的异常可以修改,访问级别可以修改。
重写:子类对父类的方法进行重新编写,要求其返回值和形参都不能发生改变。
重写的异常可以减少或删除,但不能抛出新异常或比原范围更广的异常,访问级别可以修改(但不能更严格)。静态方法不能重写。
构造方法可以重载,不能重写。
被final修饰的方法,不能重写。
构造方法可以和普通方法同名。
2. static
在java中,被static修饰的成员,被称为静态成员,也可以称为类成员,其不属于某个具体的对象,而是所有对象共享的。
被static修饰的成员变量称为静态成员变量。它不属于某一个对象,是类的属性,由所有对象共享的。
被static修饰的成员方法称为静态成员方法。它不属于某一个对象,是类的方法,由所有类共享的。
静态成员可以直接通过类名进行调用。
不能在静态成员方法中直接访问非静态成员变量。
若要调用,需要实例化对象,通过对象的引用来访问。
静态方法不能重写
静态属性可以重新赋值
//我们先创建一个学生类类型,再new三个学生对象,每个学生的姓名、年龄、性别都是有所差异的,
//但是每个学生所在的学校都是一样的:家里蹲大学,所以我们就可以用static来修饰school,让它成为每个学生对象所共享的一个变量。
class Student{
public String name; //姓名
public int age; //年龄
public String gender;//性别
public static String school = "家里蹲大学"; //学校
public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
}
public class Test {
public static void main(String[] args) {
Student student1 = new Student("张三",18,"男");
Student student2 = new Student("李四",19,"男");
Student student3 = new Student("王五",20,"女");
}
}
当我们调试的时候可以发现,这个静态成员变量并没有存储到某个具体的对象中:
static还可以修饰代码块,一般用于初始化静态成员变量。
静态代码块的内容只会随着类的加载而执行,只执行一次,不管你生成多少个对象
public class Dog {
public String name;
private String gender;
private int age;
private static String color;
//静态代码块:使用static定义的代码块称为静态代码块。一般用于初始化静态成员变量
static {
color="黄色";
System.out.println(color);
}
}
public class Demo1 {
public static void main(String[] args) {
Dog dog1=new Dog();
dog1.eat();
Dog dog2=new Dog();
dog2.eat();
}
}
3. final
被其修饰的变量,不能被重新赋值,只能赋值一次。
被其修饰的方法,不能被重写,可以重载。
被其修饰的类,不能被继承。
4. String,StringBuffer,StringBuilder
String:底层用char数组构成,被final修饰
。线程安全,重写了equals方法,一旦创建不可改变,可用“+”进行字符串拼接。
StringBuffer:底层用char数组构成
。线程安全,没重写了equals方法,一旦创建可改变
,不可用“+”进行字符串拼接。
StringBuilder:底层用char数组构成
。线程不安全,没重写了equals方法,一旦创建可改变
,不可用“+”进行字符串拼接。
字符串转Integer:Integer. parsInt(String s)
Integer转字符串:
String. valueOf(Integer i)
或
与""进行拼接
String常用方法:
length() 返回字符串中的字符数
charAt(index) 返回字符串s中指定位置的字符
toUpperCase() 返回一个新字符串,其中所有字母大写
concat(s1) 将本字符串和字符串s1连接,返回一个新字符串。等价"+"
trim() 返回一个新字符串,去掉两边的空白字符
equalsIgnoreCase(s1) 不区分大小写比较
startsWith(prefix) 如果字符串以特定前缀开始,返回true
contains(s1) 如果s1是该字符串的子字符串,返回true
substring() 返回字符串,从特定位置beginindex开始到字符串结尾 左闭右开
indexOf(ch) 返回字符串中出现第一个ch的下标,如果没有返回-1
indexOf(ch,fromIndex) //返回字符串中fromIndex之后出现的第一个ch下标,如果没有返回-1
// eg:"Welcome to Java".indexOf('o', 5) //返回9。
getBytes() 返回字符串的byte数组
isEmpty 长度是否为0,// 注意不能判断该字符串是否为空!!!
字符串转JSON / JSON转字符串:
有很多方法都能实现,例如:Jackson,FastJson,Gson。其中 Jackson在springboot里面已经集成整合了。
FastJson,Gson需要手动添加。
==========JSON使用场景介绍:==========
场景1.前端请求后端服务接口时通常发送的是一个json格式的字符串,这时后端需要将这个字符串进行解析转换成一个JavaBean对象;
场景2.有些时候为了数据在数据库中存储的方便经常需要将一个Java对象转换成一个json格式String对象,在数据库中使用一个字段进行保存;
场景3.在接口中定义时,对于一些字段个数无法确定的对象,我们往往也会将这个对象定义成一个jsonData进行请求;
以上几种场景是我们在项目开发中常见的json字符创和JavaBean对象进行转换的情况;
==========关于FastJson常用API介绍:==========
Fastjson常用的API:
可通过 JSON. 自行查看
一些API使用例子:https://blog.csdn.net/weixin_41251135/article/details/110231280
Fastjson常用的注解:
* https://blog.csdn.net/qq_45737613/article/details/121727312
* https://www.cnblogs.com/teach/p/15431163.html
* @JSONField:用于控制序列化和反序列化的属性名、格式、顺序等。
* @JSONType:用于控制<font color="red">类</font>级别的序列化和反序列化配置,包含序列化和反序列化的过滤器、序列化的顺序等。
* @JSONCreator:用于指定一个自定义的构造函数,用于反序列化。
* @JSONPOJOBuilder:用于指定一个自定义的Builder类,用于反序列化。
* @JSONScannerAware:用于指定一个自定义的JSONReader,用于反序列化。
==========关于JackJson常用API介绍:==========
Jackson常用的API:
* https://www.bilibili.com/read/cv17391720/
* https://ld246.com/article/1586941976507
Jackson常用的注解:
* https://blog.csdn.net/promsing/article/details/114986873
* @JsonIgnore 此注解用于属性上,作用是进行JSON操作时忽略该属性。
* @JsonFormat 此注解用于属性上,作用是把Date类型直接转化为想要的格式,如@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss")。
* @JsonProperty 此注解用于属性上,作用是把该属性的名称序列化为另外一个名称,如把trueName属性序列化为name,
5. ==与equals的区别
==与equals都是用于判断对象地址值是否相等。
其中==是运算符,而equals是方法。
==:当左右两边为基本数据类型时,判断数值是否相等,引用数据类型时,判断对象地址值是否相同。
equals:属于Object的方法,有一些类重写了该方法,如:String,String的equals方法用于比较字符串内容是否相同。
6. throw与throws的区别
throw用在方法体,用于抛出异常。
throws用在方法声明,若该方法抛出异常,由该方法的调用者来处理异常。
7. 接口与抽象类
接口:用interface修饰,不能直接实例化,需要被实现。全是抽象方法,无构造方法和静态方法。
接口可以继承接口。接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量。接口中的变量必须赋值才能使用,在调用的时候通过类名.去调用
抽象类:用abstract修饰,不能直接实例化,需要被继承。和普通类没啥区别,普通类可以有的方法都可以有。
包含抽象方法的类,一定是抽象类,抽象类不一定包含抽象方法。
java里面是单继承,多实现的特点。
8. length(),length,size()
length():字符串
length:数组
size():集合
9. int与Integer
int:基本数据类型,默认值为0。
Integer:int的包装类,默认值为null。
为什么有Integer?
因为Java语言是面向对象的。
在Java中绝大部分方法或类都是用来处理类类型对象的,如ArrayList集合类就只能以类作为他的存储对象,而这时如果想把一个int型的数据存入list是不可能的,必须把它包装成类,也就是Integer才能被List所接受。所以Integer的存在是很必要的。
在我们定义实体类的时候为什么往往用Integer而不用int:
如果返回字段值为null,int类型会报错,Integer不会报错。
因为int类型只能存0,而Integer可以存0或null。
在MySQL中没有给字段赋值默认为null,当你从数据库中查出来也是null,如果该字段在对应的Java代码中是int类型,null不能对应int类型,因为int代表的是基本数据类型,只能是基本的数字。
实体类的属性你可以给它赋值也可以不给它赋值,当你不给它赋值时,它拥有默认值,比如int的默认值就为0。但是主动给它设置值为0与它默认为零是不同的概念。比如,一个班的成绩,0代表某学生分数为0,null代表这个学生该门考试没有成绩,这是两个不同的概念。
10. &与&&
都是逻辑运算符,左右两边为true,才为true。&&为短路与,当左边不为true,则不继续判断右边。
if(name != null && name.equeals("张三")) 必须先判断不为null
if (("张三").equals(s) && s != null) 推荐这种
11. break与continue
break:结束当前循环
continue:跳过本次循环,继续下一次循环。
12. Object常用方法有哪些
getClass()
eauqls(Object obj)
toString()
wait()
notify()
notifyAll()
getClass()
hashCode()
hashCode:用于标识一个对象,若两个对象相同,则他们的hashCode值一定相同。 两个对象的hashCode值相同,对象不一定相同。
equals:public boolean equals(Object obj) { return (this == obj);}
用于比较两个对象是否相同,底层就是用 == 判断两个对象的地址值是否相同。
hashCode:是使用了一种叫“杂凑”算法的方法算出来的一个int值。
既然是算出来的,那么就是不准确的(接近准确但还是有误差)。
肯定会有一种情况,在某一时刻,多个对象传回相同的杂凑值,而且越糟糕的杂凑算法这种情况就越容易出现,所以就能够出现“hashCode相同,对象不一定相等”的情况;
反过来,“相等的对象,hashCode一定相同么?“,是的,两对象相等,hashCode 一定相同,why? 想想刚才的”杂凑算法“,应为是一种算法,所以,计算的方法肯定是不变的,所以,相等的对象,杂凑计算得出的hashCode一定相同。
13. this与super
this:所在类当前对象的引用。可以调用成员方法外,还能调用构造方法。
super:指向父类的引用。可以调用成员方法外,还能调用构造方法。
调用构造方法:
1. 只能在构造方法中使用this调用其他构造方法。
2. this调用构造方法时,必须写在该方法的第一条执行语句。
14. 成员变量与局部变量
成员变量:定义在类里,有默认值。
局部变量:定义在方法里,没有默认值。
15. 反射
反射:动态加载对象,在运行状态中,
对任意一个类,都能知道这个类的所有属性和方法。
对任意一个对象,都能调用它的任一方法。
这种动态获取信息及动态调用对象方法的功能就称为JAVA反射机制
反射能帮我们提供以下几种情况的功能:
1. 在运行时判断任意一个对象所属的类。
2. 在运行时判断任意一个类所具有的成员变量和方法。
3. 在运行时构造任意一个类的对象。
4. 在运行时调用任意一个对象的方法。
获取class(类对象)的三种方式:类对象通常和Java反射机制搭配使用。
- 类名.class
- 对象名.getClass
- Class.forName(全类名)
类对象常用方法:
static ClassforName(String name) 返回指定类名 name(全类名)的 Class 对象
Object newInstance() 调用无参构造器,返回该 Class 中对应的类的对象实例
getName() 返回此 Class 对象所表示的实体(类,接口,数组类,基本数据类型或 void) 的名称
Class getSuperClass() 返回当前Class 对象的父类的 Class 对象
Class getInterface() 获取当前Class 对象的接口
Class[] getinterfaces() 获取当前Class 对象的所有接口
ClassLoader getClassLoader() 返回该类的类加载器
Method getMothed(String name,Class..T) 返回一个Method对象,此对象的形参类型为paramType
Method[] getDeclaredMethods() 返回该类中的所有方法存储到Method[ ]对象数组
Constructor[] getConstructors() 返回该类中的所有的构造器存储到 (Constructor[ ])对象的数组中
Field[] getDeclaredFields() 返回该类中所有的属性存储到 Field[ ]对象数组中
Java的反射机制的实现要借助于4个类:Class,Constructor,Field,Method;
其中Class代表的是类对 象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象。通过这四个对象我们可以粗略的看到一个类的各个组 成部分。
Java在java.lang.reflect 包下新增了AnnotatedElement接口,该接口是(Class、Filed,Method和Constructor这几个类)的父接口。
//AnnotatedElement接口常用方法:
// 判断该元素上是否配置有某个指定的注解
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
return GenericDeclaration.super.isAnnotationPresent(annotationClass);
}
// 获取该元素上指定的注解。之后再调用该注解的注解类型元素方法就可以获得配置时的值数据;
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
Objects.requireNonNull(annotationClass);
return (A) annotationData().annotations.get(annotationClass);
}
// 获得该对象身上配置的所有的注解。它会返回给我们一个注解数组,需要注意的是该数组的类型是Annotation类型,这个Annotation是一个来自于java.lang.annotation包的接口。
public Annotation[] getAnnotations() {
return AnnotationParser.toArray(annotationData().annotations);
}
// getDeclaredAnnotation(Class<T> annotationClass): 返回此元素上存在的指定类型的注释,如果该类型注释不存在,则返回 null
// getDeclaredAnnotations(): 返回直接存在于此元素上的所有注释,包括其继承的注释和重复注释
// getAnnotationByType(Class<T> annotationClass): 返回此元素上存在的指定类型的注释,如果存在多个注释,则返回重复注释
// getAnnotationsByType(Class<T> annotationClass): 返回此元素上存在的指定类型的注释,包括其继承的注释和重复注释
16. 递归
递归:在函数中存在着调用函数本身的情况,这种现象就叫递归。
递:是将问题拆解成子问题来解决, 子问题再拆解成子子问题,...,直到被拆解的子问题无需再拆分成更细的子问题(即可以求解)。
归:是说最小的子问题解决了,那么它的上一层子问题也就解决了,上一层的子问题解决了,上上层子问题自然也就解决了。
以阶层函数为例,如下, 在 factorial 函数中存在着 factorial(n - 1) 的调用,所以此函数是递归函数。
public int factorial(int n) {
if (n < =1) { // 归
return 1;
}
return n * factorial(n - 1) // 递
}
// 以树形菜单结构为例,展示树形菜单【递归】 //
public class TreeUtil {
// 菜单实体类
@Data
@ToString
private static class Menu {
// 主键id
private Integer id;
// 父id
private Integer parentId;
// 菜单名
private String title;
}
// 菜单VO,返回给前端
@Data
@ToString
private static class MenuVO {
private Integer id;
private Integer parentId;
private String title;
private List<MenuVO> children;
}
// 模拟数据库
// 查询所有菜单
private static List<Menu> findAllMenu() {
Menu menu = new Menu();
menu.setId(1);
menu.setParentId(0);
menu.setTitle("一级标题:娃哈哈");
Menu menu2 = new Menu();
menu2.setId(2);
menu2.setParentId(1);
menu2.setTitle("二级标题:娃哈哈不好喝");
Menu menu3 = new Menu();
menu3.setId(3);
menu3.setParentId(2);
menu3.setTitle("三级标题:娃哈哈不好喝,但是有营养");
Menu menu4 = new Menu();
menu4.setId(4);
menu4.setParentId(0);
menu4.setTitle("一级标题:农夫山泉");
Menu menu5 = new Menu();
menu5.setId(5);
menu5.setParentId(null);
menu5.setTitle("一级标题:可口可乐");
Menu menu6 = new Menu();
menu6.setId(6);
menu6.setParentId(5);
menu6.setTitle("二级标题:可口可乐,甜蜜蜜");
List<Menu> list = new ArrayList<>();
list.add(menu);
list.add(menu2);
list.add(menu3);
list.add(menu4);
list.add(menu5);
list.add(menu6);
return list;
}
private static List<MenuVO> findTree() {
ArrayList<MenuVO> menuVOS = new ArrayList<>();
// 模拟数据库查询出所有菜单
List<Menu> allMenu = findAllMenu();
for (Menu menu : allMenu) {
// 如果菜单的 parentId 为null,或者为0。就代表它是根节点,需要为其添加子节点
if (menu.getParentId() == null || menu.getParentId() == 0) {
MenuVO vo = new MenuVO();
BeanUtils.copyProperties(menu, vo);
// getChild就是一个典型的递归算法
vo.setChildren(getChild(menu, allMenu)); // 这里有个不好的,应该把顶级菜单查出来,然后只遍历顶级菜单,对顶级菜单设置Childre,这里没有拿样写,导致要多循环几遍。
menuVOS.add(vo);
}
}
return menuVOS;
}
private static List<MenuVO> getChild(Menu result, List<Menu> list) {
List<MenuVO> childrenList = new ArrayList<>();
for (Menu menu : list) {
// 如果遍历出来的菜单parentId等于传入的菜单的id,则说明是其子菜单
if (result.getId().equals(menu.getParentId())) {
MenuVO menuVO = new MenuVO();
BeanUtils.copyProperties(menu, menuVO);
// 子菜单设置自己的子菜单
// 自己调自己
menuVO.setChildren(getChild(menu,list));
childrenList.add(menuVO);
}
}
return childrenList;
}
public static void main(String[] args) {
List<MenuVO> tree = findTree();
String s = JSON.toJSONString(tree);
System.out.println(s);
}
}
https://www.cnblogs.com/itlihao/p/14526178.html
代码示例:https://gitee.com/lihaocxs/recursion.git
17. 如何将一个对象的某个属性取出来用字符串存储,多个用,隔开
@GetMapping("/test001")
public MsgResult test001() {
StringBuilder builder = new StringBuilder();
List<Menu> list = menuService.list();
if (!CollectionUtils.isEmpty(list)) {
for (Menu menu : list) {
String name = menu.getName();
if (builder.length()>0) {
builder.append(",");
}
builder.append(name);
}
}
System.out.println(builder);
return MsgResult.success(builder);
}
18. org.springframework.util的StringUtils与org.apache.commons.lang3的StringUtils区别
String a = "";
String b = null;
String c = " ";
// org.springframework.util.StringUtils 提供
System.out.println(StringUtils.isEmpty(a)); // true
System.out.println(StringUtils.isEmpty(b)); // true
System.out.println(StringUtils.isEmpty(c)); // false
// org.apache.commons.lang3.StringUtils 提供
System.out.println(org.apache.commons.lang3.StringUtils.isEmpty(a));// true
System.out.println(org.apache.commons.lang3.StringUtils.isEmpty(b));// true
System.out.println(org.apache.commons.lang3.StringUtils.isEmpty(c));// false
System.out.println(org.apache.commons.lang3.StringUtils.isBlank(a));// true
System.out.println(org.apache.commons.lang3.StringUtils.isBlank(b));// true
System.out.println(org.apache.commons.lang3.StringUtils.isBlank(c));// true
// 结论:两者的isEmpty功能都一样,其中apache提供的了一个 isEmpty() 方法,不会判断空串,会将空串判断成空(null)
19. org.springframework.util的CollectionUtils与org.apache.commons.lang3的CollectionUtils区别
List<String> list1 = null;
List<String> list2 = new ArrayList<>();
List<String> list3 = new ArrayList<>();
list3.add("a");
list3.add("b");
// org.springframework.util.CollectionUtils 提供
System.out.println(CollectionUtils.isEmpty(list1));// true
System.out.println(CollectionUtils.isEmpty(list2));// true
System.out.println(CollectionUtils.isEmpty(list3));// false
System.out.println();
// org.apache.commons.collections.CollectionUtils 提供
System.out.println(org.apache.commons.collections.CollectionUtils.isEmpty(list1));// true
System.out.println(org.apache.commons.collections.CollectionUtils.isEmpty(list2));// true
System.out.println(org.apache.commons.collections.CollectionUtils.isEmpty(list3));// false
// 结论:null与一个没有元素的集合都判定为空。