内容概括

java基础.png

常见题目

1.实际工作中使用的设计模式
2.接口和抽象类的对比
3.引用类型 4种
4.为什么反射性能差
5.IO的设计模式有哪些

题目:发布订阅模式 · Pub Sub Pattern

描述中文

发布/订阅模式是系统设计中广泛使用的模式。 在此问题中,您需要实现发布/订阅模式以支持特定频道上的用户订阅,并从订阅的频道获取通知消息。

您需要实现3种方法:

  • subscribe(channel,user_id):将给定用户订阅到给定频道。
  • unsubscribe(channel,user_id):取消订阅给定用户的给定用户。
  • publish(channel,message):您需要将消息发布到频道,以便在频道上订阅的每个人都会收到此消息。 调用PushNotification.notify(user_id,message)将消息推送给用户。

样例

  1. subscribe("group1", 1)
  2. publish("group1", "hello")
  3. >> user 1 received "Hello"
  4. subscribe("group1", 2)
  5. publish("group1", "thank you")
  6. >> user 1 received "thank you"
  7. >> user 2 received "thank you"
  8. unsubscribe("group2", 3)
  9. >> user 3 is not in group2, do nothing
  10. unsubscribe("group1", 1)
  11. publish("group1", "thank you very much")
  12. >> user 2 received "thank you very much"
  13. publish("group2", "are you ok?")
  14. >> # you don't need to push this message to anyone

如果在同一频道上订阅的用户超过1个,则用户接收该消息的时间顺序无关紧要。 您可以在将消息推送给用户1之前推送给用户2。

public class PubSubPattern {
    private HashMap<String, HashSet<Integer>> channels;

    public PubSubPattern(){
        channels = new HashMap<String, HashSet<Integer>>();
    }

    public void subscribe(String channel, int user_id) {
        if (!channels.containsKey(channel)) {
            channels.put(channel, new HashSet<Integer>());
        }
        HashSet<Integer> user_ids = channels.get(channel);
        user_ids.add(user_id);
    }

    public void unsubscribe(String channel, int user_id) {
        if (!channels.containsKey(channel)) {
            return;
        }

        HashSet<Integer> user_ids = channels.get(channel);
        user_ids.remove(user_id);
    }

    public void publish(String channel, String message) {
        if (!channels.containsKey(channel)) {
            return;
        }
        for (Integer user_id : channels.get(channel)) {
            PushNotification.notify(user_id, message);
        }
    }
}

题目:电梯系统

描述中文

题目:为一栋大楼设计电梯系统

  • 不需要考虑超重的情况
  • 该电梯系统目前只有1台电梯, 该楼共有n
  • 每台电梯有三种状态:上升,下降,空闲
  • 当电梯往一个方向移动时,在电梯内无法按反向的楼层

我们提供了其他几个已经实现好的类,你只需要实现Elevator Class内的部分函数即可。
注意:
Currently elevator status is : DOWN.
是指现在正在执行 down stop list里的命令
Currently elevator status is : UP.
是指现在正在执行 up stop list里的命令

每行命令之后我们都会调用elevatorStatusDescription 函数,用于测试你是否处于一个正确的状态。

样例

样例1

输入:
5
ExternalRequest(3, "Down")
ExternalRequest(1, "Up")
openGate()
closeGate()
openGate()
closeGate()

输出:
Currently elevator status is : DOWN.
Current level is at: 1.
up stop list looks like: [false, false, false, false, false].
down stop list looks like:  [false, false, true, false, false].
*****************************************
Currently elevator status is : DOWN.
Current level is at: 1.
up stop list looks like: [true, false, false, false, false].
down stop list looks like:  [false, false, true, false, false].
*****************************************
Currently elevator status is : DOWN.
Current level is at: 3.
up stop list looks like: [true, false, false, false, false].
down stop list looks like:  [false, false, false, false, false].
*****************************************
Currently elevator status is : UP.
Current level is at: 3.
up stop list looks like: [true, false, false, false, false].
down stop list looks like:  [false, false, false, false, false].
*****************************************
Currently elevator status is : UP.
Current level is at: 1.
up stop list looks like: [true, false, false, false, false].
down stop list looks like:  [false, false, false, false, false].

样例2

输入:
5         
ExternalRequest(3, "Down")
ExternalRequest(2, "Up")
openGate()
InternalRequest(1)
closeGate()
openGate()
closeGate()
openGate()
closeGate()

输出:
Currently elevator status is : DOWN.
Current level is at: 1.
up stop list looks like: [false, false, false, false, false].
down stop list looks like:  [false, false, true, false, false].
*****************************************

Currently elevator status is : DOWN.
Current level is at: 1.
up stop list looks like: [false, true, false, false, false].
down stop list looks like:  [false, false, true, false, false].
*****************************************

Currently elevator status is : DOWN.
Current level is at: 3.
up stop list looks like: [false, true, false, false, false].
down stop list looks like:  [false, false, false, false, false].
*****************************************

Currently elevator status is : DOWN.
Current level is at: 3.
up stop list looks like: [false, true, false, false, false].
down stop list looks like:  [true, false, false, false, false].
*****************************************

Currently elevator status is : DOWN.
Current level is at: 3.
up stop list looks like: [false, true, false, false, false].
down stop list looks like:  [true, false, false, false, false].
*****************************************

Currently elevator status is : DOWN.
Current level is at: 1.
up stop list looks like: [false, true, false, false, false].
down stop list looks like:  [false, false, false, false, false].
*****************************************

Currently elevator status is : UP.
Current level is at: 1.
up stop list looks like: [false, true, false, false, false].
down stop list looks like:  [false, false, false, false, false].
*****************************************

Currently elevator status is : UP.
Current level is at: 2.
up stop list looks like: [false, false, false, false, false].
down stop list looks like:  [false, false, false, false, false].
*****************************************

Currently elevator status is : IDLE.
Current level is at: 2.
up stop list looks like: [false, false, false, false, false].
down stop list looks like:  [false, false, false, false, false].
*****************************************
    enum Direction {
        UP, DOWN
    }

    enum Status {
        UP, DOWN, IDLE
    }

    class Request {
        private int level;

        public Request(int l) {
            level = l;
        }

        public int getLevel() {
            return level;
        }
    }

    class ElevatorButton {
        private int level;
        private Elevator elevator;

        public ElevatorButton(int level, Elevator e) {
            this.level = level;
            this.elevator = e;
        }

        public void pressButton() {
            InternalRequest request = new InternalRequest(level);
            elevator.handleInternalRequest(request);
        }
    }

    class ExternalRequest extends Request {

        private Direction direction;

        public ExternalRequest(int l, Direction d) {
            super(l);
            // TODO Auto-generated constructor stub
            this.direction = d;
        }

        public Direction getDirection() {
            return direction;
        }
    }

    class InternalRequest extends Request {

        public InternalRequest(int l) {
            super(l);
            // TODO Auto-generated constructor stub
        }
    }

    public class Elevator {

        private List<ElevatorButton> buttons;

        private List<Boolean> upStops;
        private List<Boolean> downStops;

        private int currLevel;
        private Status status;

        public Elevator(int n) {
            buttons = new ArrayList<ElevatorButton>();
            upStops = new ArrayList<Boolean>();
            downStops = new ArrayList<Boolean>();
            currLevel = 0;
            status = Status.IDLE;

            for (int i = 0; i < n; i++) {
                upStops.add(false);
                downStops.add(false);
            }
        }

        public void insertButton(ElevatorButton eb) {
            buttons.add(eb);
        }

        public void handleExternalRequest(ExternalRequest r) {
            if (r.getDirection() == Direction.UP) {
                upStops.set(r.getLevel() - 1, true);
                if (noRequests(downStops)) {
                    status = Status.UP;
                }
            } else {
                downStops.set(r.getLevel() - 1, true);
                if (noRequests(upStops)) {
                    status = Status.DOWN;
                }
            }
        }

        public void handleInternalRequest(InternalRequest r) {
            // check valid
            if (status == Status.UP) {
                if (r.getLevel() >= currLevel + 1) {
                    upStops.set(r.getLevel() - 1, true);
                }
            } else if (status == Status.DOWN) {
                if (r.getLevel() <= currLevel + 1) {
                    downStops.set(r.getLevel() - 1, true);
                }
            }
        }

        public void openGate() throws Exception {
            if (status == Status.UP) {
                for (int i = 0; i < upStops.size(); i++) {
                    int checkLevel = (currLevel + i) % upStops.size();
                    if (upStops.get(checkLevel)) {
                        currLevel = checkLevel;
                        upStops.set(checkLevel, false);
                        break;
                    }
                }
            } else if (status == Status.DOWN) {
                for (int i = 0; i < downStops.size(); i++) {
                    int checkLevel = (currLevel + downStops.size() - i) % downStops.size();
                    if (downStops.get(checkLevel)) {
                        currLevel = checkLevel;
                        downStops.set(checkLevel, false);
                        break;
                    }
                }
            }
        }

        public void closeGate() {
            if (status == Status.IDLE) {
                if (noRequests(downStops)) {
                    status = Status.UP;
                    return;
                }
                if (noRequests(upStops)) {
                    status = Status.DOWN;
                    return;
                }
            } else if (status == Status.UP) {
                if (noRequests(upStops)) {
                    if (noRequests(downStops)) {
                        status = Status.IDLE;
                    } else {
                        status = Status.DOWN;
                    }
                }
            } else {
                if (noRequests(downStops)) {
                    if (noRequests(upStops)) {
                        status = Status.IDLE;
                    } else {
                        status = Status.UP;
                    }
                }
            }
        }

        private boolean noRequests(List<Boolean> stops) {
            for (int i = 0; i < stops.size(); i++) {
                if (stops.get(i)) {
                    return false;
                }
            }
            return true;
        }

        public String elevatorStatusDescription() {
            String description = "Currently elevator status is : " + status
                    + ".\nCurrent level is at: " + (currLevel + 1)
                    + ".\nup stop list looks like: " + upStops
                    + ".\ndown stop list looks like:  " + downStops
                    + ".\n*****************************************\n";
            return description;
        }
    }

高频面试题

1.实际工作中使用的设计模式
2.接口和抽象类的对比
3.引用类型 4种
4.为什么反射性能差
5.IO的设计模式有哪些

答疑问题

集合

扩容过程中,如果新数据过来,加在哪里?2扩容是直接停下来扩容,还是写时复制
为什么链表是8(柏松分布)
image.png
image.png

引用类型

虚引用有什么意义?他的作用是什么?
虚引用的存在就是为了跟踪某个对象是否被回收掉了,虚引用存在的价值不大,最主要就是做对象跟踪用的,引用队列的作用可以用作其他引用对象,队列中引用被回收以后加入到引用队列中

数据类型

接口和抽象类的区别?
什么时候用接口,什么时候用抽象类?

接口和抽象类的区别?
接口:单纯的对行为的一种抽象
抽象类:对一些类的公共部分的抽象
image.png
image.png

Java反射

反射是如何体现面向对象的思想的?/怎么理解反射是面向对象的一种应用的?
答:面向对象就是对一种事物的抽象,而反射就是吧Java本身进行抽象,比如Class,Method,Value,因此可以动态的实现类以及执行一些方法和调用属性,所以说反射是面向对象的一种体现。

反射为何能差?
1. Class.forName,Class.getMethod 涉及native调用;符号引用转为直接引用;getMethod涉及遍历查找
2. Method.invoke 变长参数方法传的 Object 数组 ->基本类型的自动装箱、拆箱 -> 堆分配空间;涉及native调用;
3. 安全检查
4. jvm没办法jit优化

如何优化反射的性能?
1. 缓存访问的元素
2. 接口优先于反射
3. 字节码增强(第一次使用会很慢,后面就相当于转成直接调用了)
4. 魔法类:sun.misc.Unsafe

设计模式

设计模式中懒汉模式双重检查枷锁的类需要添加volatile关键字进行修饰

引用类型

这么说,大家估计乱套了,群里的小伙伴估计都蒙了,我总结下说法吧,我不敢保证对不对,请大家指出问题,根据官方api: https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/ref/PhantomReference.html, 虚引用主要用来做一些对象的善后操作,Java中我们可以通过分配一块堆外内存,比如NIO中的 DirectByteBuffer,为啥要复制到堆外呢,是因为,我们一般做IO操作,需要把堆内存中的东西先拉到操作系统地内存中,也就是有的小伙伴提到的,用户态,内核态,如果我们直接在堆外内存分配,那么我们就可能减少一次IO复制,大家理解到这就可以,至于虚引用与这个东西的关系,其实并没有太大关系,不能说我初始化一个对象,传入一个int类型,你就要说int与对象初始化是必须绑定的,虚引用官方文档说的很清楚了,就是一般处理对象的善后操作,我们创建一个堆外内存,既然堆的回收器无法回收,我们必然想办法,所以,通过继承虚引用,是不是就将堆外的对象与堆内的垃圾回收对象保持了某种关系,然后当我们堆内发生GC的时候,我们是不是就可以通知unsafe类去回收堆外对象,当然说是这么说,实现可能不是这样,我只是看了nio文档中的那个继承虚引用的对象代码,感觉是这么回事

实际上还有个类似功能的叫 FinalReference,和finalize有关,有点偏的知识点。
大家了解就行,暂时不用纠结,时间宝贵,先学主要的。