JAVA面经复习(十)

<mark>面试难度</mark>:☆☆☆☆

问:String s = new String(“abc”)创建了几个对象?

答:2个,在JVM中存在着一个字符串池,其中保存着很多String对象,并且可以被共享使用,因此它提高了效率。JVM首先判断字符池中是否有“abc”这个对象,如果没有,则首先创建一个对象。而后由于new String()方法本身也会产生一个新的对象但该对象不会保存到内存池中。该新对象被赋值为“abc”。因此一共会创建两个对象。

问: 字符串常量池?

答:字符串常量池是用于维护JVM中字符串的区域吧。因为字符串属于final型变量,其一被创建就会保持不变,因为JVM会维护字符串常量池中的字符串只有一个,进而减少内存消耗。

问:静态绑定与动态绑定区别,private属于哪一种,如何理解?

答:首先明白,绑定是针对方法调用时,是调用子类方法还是父类方法而提出的概念。
静态绑定(前期绑定)是指:在程序运行前就已经知道方法是属于那个类的,在编译的时候就可以连接到类的中,定位到这个方法。在Java中,final、private、static修饰的方法以及构造函数都是静态绑定的。private之所以属于静态绑定,个人考虑是因为private对应的方法不可以被继承,因此不存在重写的可能性,因此属于静态绑定
动态绑定(后期绑定)是指:在程序运行过程中,根据具体的实例对象才能具体确定是哪个方法。动态绑定是多态性得以实现的重要因素,它通过方法表来实现:每个类被加载到虚拟机时,在方法区保存元数据,其中,包括一个叫做 方法表(method table)的东西,表中记录了这个类定义的方法的指针,每个表项指向一个具体的方法代码。如果这个类重写了父类中的某个方法,则对应表项指向新的代码实现处。从父类继承来的方法位于子类定义的方法的前面。

问:java泛型如何实现,与c语言泛型区别?

答:1、类型擦除,Java的泛型是伪泛型。在编译期间,所有的泛型信息都会被擦除掉。正确理解泛型概念的首要前提是理解类型擦出(type erasure)。Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会在编译器在编译的时候去掉。这个过程就称为类型擦除。如在代码中定义的List<object>和List<String>等类型,在编译后都会编译为List。
2、在c++中为每个模板的实例化产生不同的类型,这一现象被称为“模板代码膨胀”。比如 vector<int>, vector<char>, vector<double>, 这里总共会生成3份不同的vector代码。

问:java内存区域?

答:
1、程序计数器,用于计算下一条指令。
2、虚拟机栈是线程私有的,它的生命周期与线程相同。每个方法执行都会产生栈帧(可以把它看作是一个快照,记录下进入方法前的一些参数,实际上是方法运行时的基础数据结构)
3、是用来存放对象实例的,几乎所有对象实例都会在这里分配内存,也叫做GC管理的主要部分。
4、本地方法区与虚拟机栈类似,
5、方法区是各个线程共享的区域,它用于存储已经被虚拟机加载过的类信息,常量,静态变量,及时编译期编译后的代码(类方法)等数据。

问:gc回收区域?

答:堆嘛。保存有几乎所有的对象实例。

问:流量控制,拥塞控制?

答:流量控制可以采用滑动窗口;拥塞控制包括慢启动,拥塞避免,快重传,快恢复:

问:设计模式 单例模式?

答:懒汉模式和饿汉模式。懒汉即在对象实例化的时候直接在类初始化的时候,就进行new操作。而懒汉模式则在对象内对应资源被申请时再进行new操作创建。

问:数据库四大特性,隔离级别?

答:ACID,即持久性、一致性、原子性、隔离性;隔离级别为:未提交读,已提交读,可重复读,可序列化。

问:手写生产者消费者?

答:haiya,不讲武德。劳资反手就是一个代码糊脸。简单来说思想就是,构建临界区资源Storage,其中实现了两个方法,Produce()和Consume(),再分别写两个类runnable接口,
不采用BlockingQueue实现的代码如下:

import java.util.LinkedList;

class Consumer implements Runnable{
   
    private Storage storage;
    public Consumer(Storage storage) {
   
        this.storage = storage;
    }
    public Consumer() {
   }
    @Override
    public void run() {
   
        while (true){
   
            try {
   
                Thread.sleep(100);
                storage.consume();
            } catch (InterruptedException e) {
   
                e.printStackTrace();
            }
        }
    }
}

class Producer implements Runnable{
   
    private Storage storage;
    public Producer(Storage storage) {
   
        this.storage = storage;
    }
    public Producer() {
   }
    @Override
    public void run() {
   
        while (true){
   
            try {
   
                Thread.sleep(1000);
            } catch (InterruptedException e) {
   
                e.printStackTrace();
            }
            storage.produce();
        }
    }
}

class Storage {
   
    private final int  MAX_SIZE = 10;
    private LinkedList<Object> list = new LinkedList<>();//用于保存生产的商品。
    public void produce(){
   
        synchronized (list){
   
            while(list.size()+1>MAX_SIZE){
   
                System.out.println("生产者"+Thread.currentThread().getName()+"仓库已经满了");
                try{
   
                    list.wait();
                } catch (InterruptedException e) {
   
                    e.printStackTrace();
                }
            }
            list.add(new Object());
            System.out.println("生产者生产了一个物品,现有库存为"+list.size());
            list.notifyAll();
        }
    }

    public void consume(){
   
        synchronized (list){
   
            while(list.size()-1<0){
   
                System.out.println("消费者"+Thread.currentThread().getName()+"仓库已经空了");
                try {
   
                    list.wait();
                } catch (InterruptedException e) {
   
                    e.printStackTrace();
                }
            }
            list.remove();
            System.out.println("消费者消耗了一个物品,现有库存为"+list.size());
            list.notifyAll();
        }
    }
}

public class Main {
   
    public static void main(String[] args) {
   
        Storage storage = new Storage();
        Thread c1 = new Thread( new Consumer(storage));
        Thread c2 = new Thread(new Consumer(storage));
        Thread c3  = new Thread(new Consumer(storage));
        Thread p1 = new Thread(new Producer(storage));
        Thread p2 = new Thread(new Producer(storage));
        Thread p3 = new Thread(new Producer(storage));
        //启动消费者
        c1.start();
        c2.start();
        c3.start();
        //启动生产者
        p1.start();
        p2.start();
        p3.start();
    }
}

参考资料:

字节跳动客户端二面面经教育方向
String s=new String(“abc”)创建了几个对象?
Java泛型实现原理
Java泛型的实现原理(转)
Java多种方式解决生产者消费者问题(十分详细)