欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java工程师面试题之javaSE

程序员文章站 2022-05-02 12:52:25
...

1.switch支持的参数类型?

       java5之前支持char、short、int、byte,java5又支持了enum类型,java7及以后再支持String类型,long类型都不支持

 

int

short

byte

char

enum

String

Long

Java5以前

 

 

 

Java5-java7

 

 

Java7及以后

 

2. 八种基本数据及封装类          

 

基本数据类型

int

short

byte

char

 boolean

float

long

double

封装类

Integer

Short

Byte

Character

Boolean

Float

Long

Double

区别:

  1. 包装类型可以为 null,而基本类型不可以(数据库的查询结果可能是 null,如果使用基本类型的话,因为要自动拆箱(将包装类型转为基本类型,比如说把 Integer 对象转换成 int 值),就会抛出 NullPointerException 的异常。)

     2.  包装类型可用于泛型,而基本类型不可以(因为泛型在编译时只保留原始类型,而原始类型只能是 Object 类及其子类——基本类型不是Object及子类,因此会报错。)

     3.   基本类型比包装类型更高效(基本类型在栈中直接存储的具体数值,而包装类型则存储的是堆中的引用,需占较多的内存,而且对于多次用到的数值,使用包装类型就显得麻烦)

     4.   两个包装类型的值相同时,却并不相等(两个包装类型指向了不同的地址)

补充:自动拆箱与包装

具体见https://blog.csdn.net/qing_gee/article/details/101670051?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

把基本类型转换成包装类型的过程叫做装箱(boxing)。反之,把包装类型转换成基本类型的过程叫做拆箱(unboxing)

        //输出的是true
        int a = 100;
        Integer b = 100;
        System.out.println(a == b);*/

        //输出的true
        Integer c = 100;
        Integer d = 100;
        System.out.println(c == d);

        //输出的是false
        c = 200;
        d = 200;
        System.out.println(c == d);

第一题直接装箱,肯定是相等;

第二题和第三题的结果可能有点疑问,这里做个解释:java将int转为Integer是用的Integer.valueOf(),而根据源码可知,它对于-128到127的整数转成包装类型时不是去新建一个Integer对象,而是直接去IntegerCache中取出一个Integer对象,这样两个对象相等,所以返回是true,而对于超过这个范围的整数,就是常见的新建Integer对象了,由于对象地址不同,所以返回是true

 3.equals与==的区别

  1. ==常用于判断基本数据类型是否相等,而equals常用于判断对象相等
  2. 当==与equals都用来判断对象时,如果对象引用地址相同,==返回true,否则会返回false,因此==是来判断对象的内存地址是否相同。而equals返回true或者false主要取决于重写实现,如果没有重写,则单单判断内存地址是否相同,与==一样,当判断String对象,Integer对象时,默认会进行重写,这时只要值相同就会返回true.

 补充:


 String a="abc";
 String b="abc";
 System.out.println(a==b);//返回true
 System.out.println(a.equals(b));//返回true

 String str2 = new String("abc");
 System.out.println(a == str2);//返回false
 System.out.println(a.equals(str2));//返回true

Java的虚拟机在内存中开辟出一块单独的区域,用来存储字符串对象,这块内存区域被称为字符串常量池。当使用 String a = "abc"这样的语句进行定义一个引用的时候,首先会在字符串常量池中查找是否已经相同的对象,如果存在,那么就直接将这个对象的引用返回给a,如果不存在,则需要新建一个值为"abc"的对象,再将新的引用返回a。String a = new String("abc");这样的语句明确告诉JVM想要产生一个新的String对象,并且值为"abc",于是就在堆内存中的某一个小角落开辟了一个新的String对象

4. Object有哪些公用方法?

  1. clone方法:实现对象的浅复制,只有当对象实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。主要是JAVA里除了8种基本类型传参数是值传递,其他的类对象传参数都是引用传递,我们有时候不希望在方法里把参数改变,这就需要在类中复写clone方法,如下:
    public class Hello implements Cloneable{
        int x =15;
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    
        public static void main(String []args) throws CloneNotSupportedException {
            Hello hello = new Hello();
            Hello hello2 = (Hello)hello.clone();
            hello2.x = 20;
            System.out.println(hello.x);//返回15
            System.out.println(hello2.x);//返回20
        }
    }

     

  2. getClass方法:final修饰,不能被重写,获得运行时类型。
    package com.example.demo;
    public class Hello{
        public static void main(String []args) throws CloneNotSupportedException {
            Hello hello = new Hello();
            System.out.println(hello.getClass());//返回com.example.demo.Hello
        }
    }

     

  3. toString方法:该方法用得比较多,一般子类要进行重写,否则返回“类型@HashCode“,如aaa@qq.com
  4. finalize方法:该方法用于释放资源。因为无法确定该方法什么时候被调用,很少使用。
  5. equals方法:常用于对象相等比较,子类一般都要重写这个方法,否则和==一样.
  6. hashCode方法:该方法常用于哈希查找,可以减少在查找中使用equals的次数,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。一般必须满足obj1.equals(obj2)==true,可以推出obj1.hashCode()==obj2.hashCode(),但是hashCode相同不一定就满足equals(有可能equals被重写了)。不过为了提高效率,应该尽量使上面两个条件接近等价。如果不重写hashCode(),在HashSet中添加两个equals的对象,会将两个对象都加入进去。
  7. wait方法:不可被重写,就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。调用该方法后当前线程进入睡眠状态,直到以下事件发生:

            (1)其他线程调用了该对象的notify方法。

            (2)其他线程调用了该对象的notifyAll方法。

            (3)其他线程调用了interrupt中断该线程。

            (4)时间间隔到了。

         此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。

      8.notify方法:不可被重写,该方法唤醒在该对象上等待的某个线程。

      9.notifyAll方法该方法唤醒在该对象上等待的所有线程。

 补充:

作者: MoonGeek

出处:https://www.cnblogs.com/moongeek/p/7631447.html

 

java多线程学习之wait、notify/notifyAll 详解

1、wait()、notify/notifyAll() 方法是Object的本地final方法,无法被重写。

2、wait()使当前线程阻塞,前提是 必须先获得锁,一般配合synchronized 关键字使用,即,一般在synchronized 同步代码块里使用 wait()、notify/notifyAll() 方法。

3、 由于 wait()、notify/notifyAll() 在synchronized 代码块执行,说明当前线程一定是获取了锁的。当线程执行wait()方法时候,会释放当前的锁,然后让出CPU,进入等待状态。只有当 notify/notifyAll() 被执行时候,才会唤醒一个或多个正处于等待状态的线程,然后继续往下执行,直到执行完synchronized 代码块的代码或是中途遇到wait() ,再次释放锁。也就是说,notify/notifyAll() 的执行只是唤醒沉睡的线程,而不会立即释放锁,锁的释放要看代码块的具体执行情况。所以在编程中,尽量在使用了notify/notifyAll() 后立即退出临界区,以唤醒其他线程让其获得锁

4、wait() 需要被try catch包围,以便发生异常中断也可以使wait等待的线程唤醒。

5、notify 和wait 的顺序不能错,如果A线程先执行notify方法,B线程在执行wait方法,那么B线程是无法被唤醒的。

6、notify 和 notifyAll的区别

notify方法只唤醒一个等待(对象的)线程并使该线程开始执行。所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪个线程取决于操作系统对多线程管理的实现。notifyAll 会唤醒所有等待(对象的)线程,尽管哪一个线程将会第一个处理取决于操作系统的实现。如果当前情况下有多个线程需要被唤醒,推荐使用notifyAll 方法。比如在生产者-消费者里面的使用,每次都需要唤醒所有的消费者或是生产者,以判断程序是否可以继续往下执行。

7、在多线程中要测试某个条件的变化,使用if 还是while?

  要注意,notify唤醒沉睡的线程后,线程会接着上次的执行继续往下执行。所以在进行条件判断时候,可以先把 wait 语句忽略不计来进行考虑;显然,要确保程序一定要执行,并且要保证程序直到满足一定的条件再执行,要使用while进行等待,直到满足条件才继续往下执行。如下代码:

 public class K {
     //状态锁
    private Object lock;
      //条件变量
    private int now,need;
    public void produce(int num){
         //同步
          synchronized (lock){
             //当前有的不满足需要,进行等待,直到满足条件
             while(now < need){
                 try {
                     //等待阻塞
                     lock.wait();
                 } catch (InterruptedException e) {
                    e.printStackTrace();
                 }
                 System.out.println("我被唤醒了!");
            }
            // 做其他的事情
         }
     }
 }
             

 

显然,只有当前值满足需要值的时候,线程才可以往下执行,所以,必须使用while 循环阻塞。注意,wait() 当被唤醒时候,只是让while循环继续往下走.如果此处用if的话,意味着if继续往下走,会跳出if语句块。

8、实现生产者和消费者问题

  什么是生产者-消费者问题呢?java工程师面试题之javaSE

  如上图,假设有一个公共的容量有限的池子,有两种人,一种是生产者,另一种是消费者。需要满足如下条件:

    1、生产者产生资源往池子里添加,前提是池子没有满,如果池子满了,则生产者暂停生产,直到自己的生成能放下池子。

    2、消费者消耗池子里的资源,前提是池子的资源不为空,否则消费者暂停消耗,进入等待直到池子里有资源数满足自己的需求。

 实现:

      1.先定义一个仓库接口,包含消费和生产方法

1 public interface AbstractStorage {
2     void consume(int num);
3     void produce(int num);
4 }

        2. 仓库接口实现类

 1 import java.util.LinkedList;
 2 
 3 /**
 4  *  生产者和消费者的问题
 5  *  wait、notify/notifyAll() 实现
 6  */
 7 public class Storage1 implements AbstractStorage {
 8     //仓库最大容量
 9     private final int MAX_SIZE = 100;
10     //仓库存储的载体
11     private LinkedList list = new LinkedList();
12 
13     //生产产品
14     public void produce(int num){
15         //同步
16         synchronized (list){
17             //仓库剩余的容量不足以存放即将要生产的数量,暂停生产
18             while(list.size()+num > MAX_SIZE){
19                 System.out.println("【要生产的产品数量】:" + num + "\t【库存量】:"
20                         + list.size() + "\t暂时不能执行生产任务!");
21 
22                 try {
23                     //条件不满足,生产阻塞
24                     list.wait();
25                 } catch (InterruptedException e) {
26                     e.printStackTrace();
27                 }
28             }
29 
30             for(int i=0;i<num;i++){
31                 list.add(new Object());
32             }
33 
34             System.out.println("【已经生产产品数】:" + num + "\t【现仓储量为】:" + list.size());
35 
36             list.notifyAll();
37         }
38     }
39 
40     //消费产品
41     public void consume(int num){
42         synchronized (list){
43 
44             //不满足消费条件
45             while(num > list.size()){
46                 System.out.println("【要消费的产品数量】:" + num + "\t【库存量】:"
47                         + list.size() + "\t暂时不能执行生产任务!");
48 
49                 try {
50                     list.wait();
51                 } catch (InterruptedException e) {
52                     e.printStackTrace();
53                 }
54             }
55 
56             //消费条件满足,开始消费
57             for(int i=0;i<num;i++){
58                 list.remove();
59             }
60 
61             System.out.println("【已经消费产品数】:" + num + "\t【现仓储量为】:" + list.size());
62 
63             list.notifyAll();
64         }
65     }
66 }

   3.实现生产者类

 

1 public class Producer extends Thread{
 2     //每次生产的数量
 3     private int num ;
 4 
 5     //所属的仓库
 6     public AbstractStorage abstractStorage;
 7 
 8     public Producer(AbstractStorage abstractStorage){
 9         this.abstractStorage = abstractStorage;
10     }
11 
12     public void setNum(int num){
13         this.num = num;
14     }
15 
16     // 线程run函数
17     @Override
18     public void run()
19     {
20         produce(num);
21     }
22 
23     // 调用仓库Storage的生产函数
24     public void produce(int num)
25     {
26         abstractStorage.produce(num);
27     }
28 }

 4.实现消费者类

 1 public class Consumer extends Thread{
 2     // 每次消费的产品数量
 3     private int num;
 4 
 5     // 所在放置的仓库
 6     private AbstractStorage abstractStorage1;
 7 
 8     // 构造函数,设置仓库
 9     public Consumer(AbstractStorage abstractStorage1)
10     {
11         this.abstractStorage1 = abstractStorage1;
12     }
13 
14     // 线程run函数
15     public void run()
16     {
17         consume(num);
18     }
19 
20     // 调用仓库Storage的生产函数
21     public void consume(int num)
22     {
23         abstractStorage1.consume(num);
24     }
25 
26     public void setNum(int num){
27         this.num = num;
28     }
29 }

 测试

 1 public class Test{
 2     public static void main(String[] args) {
 3         // 仓库对象
 4         AbstractStorage abstractStorage = new Storage1();
 5 
 6         // 生产者对象
 7         Producer p1 = new Producer(abstractStorage);
 8         Producer p2 = new Producer(abstractStorage);
 9         Producer p3 = new Producer(abstractStorage);
10         Producer p4 = new Producer(abstractStorage);
11         Producer p5 = new Producer(abstractStorage);
12         Producer p6 = new Producer(abstractStorage);
13         Producer p7 = new Producer(abstractStorage);
14 
15         // 消费者对象
16         Consumer c1 = new Consumer(abstractStorage);
17         Consumer c2 = new Consumer(abstractStorage);
18         Consumer c3 = new Consumer(abstractStorage);
19 
20         // 设置生产者产品生产数量
21         p1.setNum(10);
22         p2.setNum(10);
23         p3.setNum(10);
24         p4.setNum(10);
25         p5.setNum(10);
26         p6.setNum(10);
27         p7.setNum(80);
28 
29         // 设置消费者产品消费数量
30         c1.setNum(50);
31         c2.setNum(20);
32         c3.setNum(30);
33 
34         // 线程开始执行
35         c1.start();
36         c2.start();
37         c3.start();
38 
39         p1.start();
40         p2.start();
41         p3.start();
42         p4.start();
43         p5.start();
44         p6.start();
45         p7.start();
46     }
47 }

输出 

【要消费的产品数量】:50    【库存量】:0    暂时不能执行生产任务!
【要消费的产品数量】:20    【库存量】:0    暂时不能执行生产任务!
【要消费的产品数量】:30    【库存量】:0    暂时不能执行生产任务!
【已经生产产品数】:10    【现仓储量为】:10
【要消费的产品数量】:30    【库存量】:10    暂时不能执行生产任务!
【要消费的产品数量】:20    【库存量】:10    暂时不能执行生产任务!
【要消费的产品数量】:50    【库存量】:10    暂时不能执行生产任务!
【已经生产产品数】:10    【现仓储量为】:20
【已经生产产品数】:10    【现仓储量为】:30
【要消费的产品数量】:50    【库存量】:30    暂时不能执行生产任务!
【已经消费产品数】:20    【现仓储量为】:10
【要消费的产品数量】:30    【库存量】:10    暂时不能执行生产任务!
【已经生产产品数】:10    【现仓储量为】:20
【要消费的产品数量】:50    【库存量】:20    暂时不能执行生产任务!
【要消费的产品数量】:30    【库存量】:20    暂时不能执行生产任务!
【已经生产产品数】:10    【现仓储量为】:30
【已经消费产品数】:30    【现仓储量为】:0
【要消费的产品数量】:50    【库存量】:0    暂时不能执行生产任务!
【已经生产产品数】:10    【现仓储量为】:10
【要消费的产品数量】:50    【库存量】:10    暂时不能执行生产任务!
【已经生产产品数】:80    【现仓储量为】:90
【已经消费产品数】:50    【现仓储量为】:40

 

 

 

 

 

 

 

 

相关标签: 面试题整理