java面试错题集积累

面试刷题笔记

最优二叉树(哈夫曼树)

哈夫曼树的定义:

  1. 是一种带权路径长度最短的二叉树,也称为最优二叉树。
  2. 带权路径长度达到最小,就是最优二叉树
  3. 由权值为9,5,2,7的四个叶子节点构造一棵最优二叉树,该树的带权路径长度为:44
  4. 在这里插入图片描述

构建哈夫曼树的算法:

​ 1.叶子结点先从小到大排序

​ 2.选取最小的两个节点作为最深的叶子节点

​ 3.计算两叶子节点的和

​ 4.将和加入到排序中去

​ 4.重复上面的操作

​ 5.直至最后一个叶子结点排完

题目

1.牛客网,货拉拉

在这里插入图片描述

此题答案有争议,已提交答案有误,有大佬如果知道为什么选BC的,欢迎留言。

程序判断输出类

值传递类型

值传递:在调用另一个方法的时候,将实际参数传入到该方法中,该方法中只会有一个形参与之对应,并且这个形参会接受实际参数的值,但是无论怎么修改形参的值,都不会影响实参。(形参类似于副本,实参类似于原文件,副本无论怎么变换,只要没有保存到源文件中去,就不会影响实参的值)

与之对应的是引用传递,此种形参与实参是同事指向一个地址的值,你修改了形参的值以后,实参也会发生改变。(指针)

注意:java中不存在引用传递,只有值传递。

题目一

来源:牛客网,货拉拉

题目描述:以下java运行结果是:

public class Tester{
public static void main(String[] args){
   Integer var1=new Integer(1);
   Integer var2=var1;
   doSomething(var2);
   System.out.print(var1.intValue());
   System.out.print(var1==var2);
}
public static void doSomething(Integer integer){
    integer=new Integer(2);
  }
}

答案:1true;

解析:

new Integer(1)意味着在内存中开辟一个空间,存储1。

var2 = var1,是把var2指向var1;

var2进doSomthing()函数,因为java是值传递,形参发生的什么不会影响到实参,var2还是跟var1指向同一片内存区域。

var1==var2很显然是比较两个对象指向的内存,结果是一样的,所以为true。

java类基础知识

五个基本原则:
单一职责原则(Single-Resposibility Principle):一个类,最好只做一件事,只有一个引起它的变化。单一职责原则可以看做是低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。
开放封闭原则(Open-Closed principle):软件实体应该是可扩展的,而不可修改的。也就是,对扩展开放,对修改封闭的。
Liskov替换原则(Liskov-Substituion Principle):子类必须能够替换其基类。这一思想体现为对继承机制的约束规范,只有子类能够替换基类时,才能保证系统在运行期内识别子类,这是保证继承复用的基础。
依赖倒置原则(Dependecy-Inversion Principle):依赖于抽象。具体而言就是高层模块不依赖于底层模块,二者都同依赖于抽象;抽象不依赖于具体,具体依赖于抽象。
接口隔离原则(Interface-Segregation Principle):使用多个小的专门的接口,而不要使用一个大的总接口

构造方法

题目一:

来源:牛客网,货拉拉

题目描述:

在这里插入图片描述

答案:

B

解析:

A选项,构造方法是不能有返回类型的。

B选项 正确,定义一个类而不在代码中写构造方法,该方法默认会有一个无参构造方法,而想要定义一个有参构造时需要注意,一旦定义有参构造后,无参构造方法就没有了,需要自己定义无参构造方法。

C选项,什么是重载:重载的概念在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。

重载构造方法的相互调用需要注意一下两点:

1.调用的构造方法必须写在构造器执行体的第一行语句

2.使用this调用另一个构造器,只能在构造器中使用

package demo;

class init{
    private int a;
    private int b;
    
    public init(int b){
    	this.b = b;
	}
    public init(int a,int b){
    	//-构造器里面调用其它构造器,格式方法如下:
    	//-1、使用this调用另一个重载构造器,只能在构造器中使用;
    	//-2、必须写在构造器执行体的第一行语句;
    	this(b);
    	this.a = a;	
	}
	
}

D选项,首先子类会默认调用父类的无参构造方法,

public class Derived extends Base {
       public Derived (String s) {
           //此处省略了一句话
           //super();
              System.out.println("这是子类的构造方法");
       }
       public static void main(String [] args) {
              new Derived ("C");
       }
}
class Base {
       public Base() {
           System.out.println("这是父类的构造方法");
       }
     }

其次:当父类中没有无参构造函数时,子类必须调用父类有参的构造函数,因为1已经证明了 子类默认调用父类的构造方法,如果父类中没有无参的构造函数,就会出现编译错误。

异常类

题目一:

来源:牛客网,货拉拉

题目描述:

在这里插入图片描述

答案:

ABC

解析:背就完事。

Exception:这种在编译时被强制检查的异常称为"受检查的异常",这种异常强制我们catch或throw的异常。遇到这种异常必须进行catch或throw,如不处理,编译器会报错。比如: IOException。

RuntimeException:运行时异常,这种异常我们不需要处理,完全有虚拟机接管,比如我们常说的NullPointerException,我们在写程序时不会进行catch或throw。
RuntimeException是继承自Exception的,只是虚拟机对这两种异常进行了区分。

异常的继承结构

在这里插入图片描述

详情参考这位带佬的博文。

img

https://blog.csdn.net/wuyingya_12/article/details/104482067

题目二:

来源:csdn

题目描述:

下面关于Java异常类的描述,说法正确的有?
A. 异常类的继承结构:基类为Throwable,Error和Exception实现Throwable,RuntimeException和IOException等继承Exception
B. 非RuntimeException一般是外部错误(不考虑Error的情况),其必须在当前类被try{}catch语句所捕获
C. Error类体系描述了Java运行系统中内部错误以及资源耗尽的情形,Error不需要捕捉
D. RuntimeException体系包含错误的类型转换、数组越界访问和视图访问空指针等等,必须被try{}catch语句块捕获

答案:

B.C

解析:

A. Error和Exception应该为继承Throwable类
D. RuntimeException(运行时异常/受查异常),这种异常由虚拟机进行处理,不需要try{}catch语句块捕获或throw处理

题目三

关于异常处理机制的叙述正确的是
A.catch部分捕捉到异常情况时,才会执行finally部分
B.当try区段的程序发生异常时,才会执行finally部分
C.当try区段不论程序是否发生错误及捕捉到异常情况,都会执行finally部分
D.以上都是
答案C

解析:finally中的代码是无论如何都会执行的。

题目四

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2Lc7een0-1617854416599)(C:\Users\Yokna\AppData\Roaming\Typora\typora-user-images\image-20210330084256520.png)]

解析:try 和 catch 不需要一定共存😋,try是尝试对其中代码捕获异常,catch是捕获异常并且可以处理异常。。你可以 try 来搜寻异常,不去捕获。也就是不去catch 这是可以的。。至于提示加finally,finally的意思是,其中的代码一定会执行,也就是说,如果try 其中的代码产生了异常,如果有catch 则会直接跳转到catch部分,如果没有catch 会跳转到‘}’后面的代码,这样,以上方法就没有一个确定的返回值,所以要加finally 作为方法出异常以后的返回的结果。。。

final

题目一:

abstract和final可以同时作为一个类的修饰符

答案:错误

解释:final的类不能被重写和继承

final类的方法能否被同一个包的类访问不是由final决定解析:final变量,如果是基本数据类型,则其数值一旦初始化后就不能被改变。如果是引用类型的变量,则对其初始化后,便不能再指向另一个对象,但是其里面的值是可以改变的。引用变量所指向的对象中的内容是可以改变的。

JVM内存管理

以下关于内存管理描述错误的是:(D)

A 基本数据类型的变量、对象的引用及函数调用的现场保存都使用内存栈空间
B 通过new关键字和构造器创建的对象放在堆空间,类信息、常量、静态变量放在方法区
C 计数器是唯一一个没有规定任何OutOfMemoryError情况的区域
D 直接内存的分配不会受到Java堆大小的限制,所以不会抛OutOfMemoryError异常

多线程

知识点一:什么是线程安全?

当多个线程访问某个方法时,不管你通过怎样的调用方式、或者说这些线程如何交替地执行,我们在主程序中不需要去做任何的同步,这个类的结果行为都是我们设想的正确行为,那么我们就可以说这个类是线程安全的。

线程不安全的例子

public class ThreadDemo{
    int count = 0;
    
    public void threadMethod(int j){
        count ++;
    }
}

此程序的作用是记录下threadMethod方法的执行次数

很显然,在多线程下,count的值不能同步,会导致程序的结果与我们预期不一样,这样的程序是线程不安全的。我们需要手动处理,使得这个程序变的安全。

处理方法:

法1:synchronized 关键字同步。

synchronized关键字,是用来控制线程同步的,保证我们的线程在多线程环境下,不被多个线程同时执行,确保我们数据的完整性。

public class ThreadDemo{
    int count = 0;
    
    public synchronized void threadMethod(int j){
        count ++;
        int i = 1;
        j = j + i;
    }
}

法2:Lock

private Lock lock = new ReentrantLock(); // ReentrantLock是Lock的子类

   private void method(Thread thread){
       lock.lock(); // 获取锁对象
       try {
           System.out.println("线程名:"+thread.getName() + "获得了锁");
           // Thread.sleep(2000);
       }catch(Exception e){
           e.printStackTrace();
       } finally {
           System.out.println("线程名:"+thread.getName() + "释放了锁");
           lock.unlock(); // 释放锁对象
       }
   }

详见带佬的博文。

https://blog.csdn.net/csdnnews/article/details/82321777?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161665364816780266266269%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=161665364816780266266269&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allbaidu_landing_v2~default-1-82321777.pc_search_result_no_baidu_js&utm_term=XIANCHENGANQUAN+

线程不安全的类有哪些:

线程不安全线程安全
StringBuilderStringBuffer
SimpleDateFormatDateTimeFormatter
ArrayList
HashSetHashTable
HashMap等Collection类ConcurrentHashMap

并发操作会带来哪些数据不一致性?

答:丢失修改、不可重复读、脏读。

反射

创建对象的几种方法

方法一:直接new 调用构造函数,使用静态编码&编译实现

Object a = new Object();

方法二:克隆clone

public class B implement Cloneable{
    public void hello(){
        System.out.println("hello from B");
    }
    
    protected Object clone() throws CloneNotSupportedException{
        return super.clone();
    }
}

B obj2 = new B();
obj2.hello();

B obj3 = (B)obj2.clone();
obj3.hello;

方法三:序列化与反序列化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6e3NL8fa-1617854416601)(C:\Users\Yokna\AppData\Roaming\Typora\typora-user-images\image-20210325162251791.png)]

方法四:反射

Object obj1 = Class.forName("A").newInstance();
Method m = Class.forName("A").getMethod("hello");
m.invoke(obj1);

A obj2 = (A) Class.forName("A").newInstance();

Constructor<A> constructor = A.class.getConstructor();
A obj3 = constructor.newInstance();
obj3.hello();

SQL

写个的sql查询语句,如有一张表示英语口语练习每个学员的学时的表a,字段有 studentid(学号) name(可重复) grade(年级) hours(学时),找出那些学时高于他们同一年级的平均学时的学生。

select a.* 
from a
left join
(select grade,avg(hours) avg_hours
from a
group by grade) b
on a.grade = b.grade
where a.hours>b.avg_hours;select id,name 
from table a left jion(
    select grade,AVG(hours) as hours 
    from table group by grade
) as b

数据结构

在这里插入图片描述

数组引用类型的变量的默认值为 null。当数组变量的实例后,如果没有没有显示的为每个元素赋值,Java 就会把该数组的所有元素初始化为其相应类型的默认值。

int型的默认值为0

复) grade(年级) hours(学时),找出那些学时高于他们同一年级的平均学时的学生。

select a.* 
from a
left join
(select grade,avg(hours) avg_hours
from a
group by grade) b
on a.grade = b.grade
where a.hours>b.avg_hours;select id,name 
from table a left jion(
    select grade,AVG(hours) as hours 
    from table group by grade
) as b

数据结构

[外链图片转存中…(img-nYGLz9oZ-1617854416602)]

数组引用类型的变量的默认值为 null。当数组变量的实例后,如果没有没有显示的为每个元素赋值,Java 就会把该数组的所有元素初始化为其相应类型的默认值。

int型的默认值为0

img

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值