• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
打工人丶
博客园    首页    新随笔    联系   管理    订阅  订阅

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反射机制搭配使用。

  1. 类名.class
  2. 对象名.getClass
  3. 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://blog.csdn.net/S0001100/article/details/121227149?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~Rate-1-121227149-blog-108076088.235^v27^pc_relevant_t0_download&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~Rate-1-121227149-blog-108076088.235^v27^pc_relevant_t0_download&utm_relevant_index=1

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与一个没有元素的集合都判定为空。
posted @ 2023-02-15 16:06  &emsp;不将就鸭  阅读(67)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3