hazy的面试小笔记之Java(持续更新)
最近准备面试,所以会收集一些不懂得题目然后进行答案的搜索,以下答案基本都是来自网络,然后进行了一点删减和自己的总结,如果有侵权,请评论或者私信联系我,我马上删除
ReentrantLock实现原理
答:内部有一个NonfairSync/FairSync静态内部类,继承于同样是静态内部类的Sync类,Sync继承了AbstractQueuedSynchronizer,在lock()调用的时候实际上是调用这个Sync类的lock方法,这个Sync类的lock方法是实现了AQS的lock方法,使用了CAS比较并交换的方法去试图获取一个锁
如果成功就设置当前线程为获得者,并且把数值变为1,如果获取失败就执行acquire->tryAcquire->nonfairTryAcquire方法,就是再获取一次锁,如果还是失败就加入到阻塞队列中,nonFairSync即使是也会添加;通过 addWaiter 方法将当前线程封装成 Node 添加到 AQS 队列尾部,然后acquireQueued,将 Node 作为参数,如果此时node前面就是head并且锁已被释放,就可以拿锁;如果前面不是,则进入阻塞状态(使用LockSupport中的函数)等待下一次判断(自旋),并设置状态为signal;如果获取失败并且当前线程不是该锁的拥有者,并且队列加入也失败,那就执行中断
NonfairSync和FairSync的区别就是在获取锁时是否先进行CAS去抢占锁,然后再考虑队列
tryLock()方法是非阻塞式的,普通的lock()是阻塞式的
unlock()方法会使同步量减一,如果为零了,那就把锁拥有者清空,并唤醒下一个线程.如果下一个线程不存在或者状态不正常,就从尾部向前唤醒,保证别的线程添加节点时的正常操作
park()和unpark()操作代表线程挂起和唤醒
final boolean acquireQueued(final Node node, int arg) {boolean failed = true;try {//表示是否被打断boolean interrupted = false;for (;;) {//获取node.pre节点final Node p = node.predecessor();if (p == head //当前节点是否是同步队列中的第二个节点&& tryAcquire(arg)) {//获取锁,head指向当前节点setHead(node);//head=head.nextp.next = null;//置空 failed = false;return interrupted;//返回是否被中断过}if (shouldParkAfterFailedAcquire(p, node) && //是否阻塞(因为阻塞唤醒是个耗时操作,进入阻塞前判断pre节点状态.如果pre节点即将释放锁,则不进入空转)parkAndCheckInterrupt())//利用unsafe.park()进行阻塞interrupted = true;//如果Thread.interrupt()被调用,(不会真的被打断,会继续循环空转直到获取到锁)}} finally {if (failed)//tryAcquire()过程出现异常导致获取锁失败,则移除当前节点cancelAcquire(node);}
}
用过CountDownLatch么?什么场景下用的?
答:就像是AtomicInteger的另一个版本,创建对象时设置一个数,然后使用countDown()方法进行CAS减一操作,直至减到0时返回true
只不过内部依然是使用的Sync继承AQS来实现的。CountDownLatch是一次性的
可以用于多个线程不按顺序同时工作,并需要在主线程中判断所有工作是否完成的情况,设置为对应线程数,每个线程完成对应的任务之后就减一,在主线程完成自己的活之后,循环判断countDownLatch是否为0,就可以知道任务是否都完成了。
AQS底层原理
答:AQS内部有一个静态内部类Node,是由线程和状态变量组成的;AQS内部有一个双向队列,以Node为节点,当有新的线程获取锁失败时,添加到tail之后,并把新的这个节点设置为tail(此过程需要CAS来保证成功)。如果获取锁成功,就是添加到头部,此方法不需要CAS因为添加的动作肯定是锁获得者,一定安全。
AQS 是一个同步双向链表,它能够实现线程的阻塞以及唤醒,但它并不具备业务功能,所以在不同的同步场景中,会继承 AQS 来实现对应场景的功能
加锁会带来哪些性能问题。如何解决?偏向锁、轻量级锁、重量级锁?
答:三种锁用于synchronized的底层jvm优化中,并且只能沿着偏向->轻量级->重量级的方向演进
如果一个锁只被一个线程获取过,那就直接设置为偏向锁,在锁的对象头中设置对应线程的id,不需要设置互斥量
假如出现了锁竞争,那就直接膨胀为轻量级锁,跟偏向锁类似,但仍然不需要设置互斥量。如果轻量级锁通过自旋失败,再膨胀为重量级锁;适用于持有锁的线程能在很短时间内释放锁资源。
重量级锁由于需要设置互斥量,并且挂起、恢复线程,因此会有性能损失.
尽可能地减少锁的出现与持有时间! JIT编译器的逃逸分析也会对没必要的锁进行锁消除,但不能依赖编译器优化
出现 OOM 后怎么排查问题?
答:1、万事先找到java的pid:ps -aux | grep java
2、可以用top查看内存情况
3、jmap -参数 pid 把java虚拟机内存弄进一个快照,查看堆、元空间的对象情况,查看哪种对象最多
4、使用一些分析工具(jstat)查看gc情况
5、不只是OOM要进行排查,太过频繁的full gc也应该进行排查与优化
6、如果是设置的内存太小,应该调大内存
7、最容易出现内存不足的情况:从mysql中取出大量的数据进行处理
手写LRU 缓存
class LRUCache extends LinkedHashMap<Integer, Integer>{private int capacity;public LRUCache(int capacity) {super(capacity, 0.75F, true);this.capacity = capacity;}public int get(int key) {return super.getOrDefault(key, -1);}public void put(int key, int value) {super.put(key, value);}@Overrideprotected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {return size() > capacity; }
}
什么时候需要自定义类加载器?
答:1、加密源码。因此java代码容易被反编译 2、从非标准的来源加载代码 3、动态创建
ConcurrentHashMap原理?
答:HashTable是线程安全的原因是因为在方法上使用synchronized,效率很低
ConcurrentHashMap采用了"分段锁"的思想,多线程访问不同的数据段时不会竞争同一个锁,可以提高效率。
**JDK1.7版本:**拥有多个Segment<K,V>,每一个segment都是一个HashEntry<K,V>[] table即一个Entry数组,就相当于一个小HashMap
并且Segment继承了ReentrantLock,可以作为互斥锁使用。put时根据key的hash查找对应的Segment,跟HashMap查找table上的位置是一样的,然后用头插法进行插入
**JDK1.8版本:**取消了Segment,采用volatile HashEntry<K,V>[] table,跟HashMap相比多了一个volatile关键字,并采用synchronized和CAS来进行操作。并且与HashMap的更新同步,采用链表加红黑树的结构。而TreeNode又有一层TreeBin的包装类作为根节点并带有读写锁。
put操作:首先进行底层数组是否为空的判断,如果是就进行数组初始化。然后计算得到key对应的位置,如果是空则通过CAS试图去插入节点,如果对应的位置上的状态是正在进行拓展,则帮助它进行拓展。如果这个位置已经有数据了,那就使用synchronized锁住然后插入(根据链表/红黑树进行插入,尾插法),然后再判断是否需要转换或退化红黑树(如果已经存在key,则修改值)。
初始化的过程也会对当前的状态进行判断,如果在当前线程将要进行初始化的时候发现状态量是正在初始化,则yield()让步。(MOVED:-1表示正在扩容)
get操作:当key为null时抛出异常;计算key的hash值对应的数组,遍历。如果找到就返回值,否则返回null;如果遇到扩容的时候,会调用标志正在扩容节点ForwardingNode的find方法,查找该节点,匹配就返
**同步机制:**1、读操作:在get操作中,没有使用同步机制,也没有使用unsafe方法,所以读操作是支持并发操作的。并且由于node节点的setValue是不支持的,只能进行原子性的等号赋值,所以可以保证拿到的就是同一个值
2、扩容是通过transfer方法来进行的。而调用transfer方法的只有trePresize(树化操作时)、helpTransfer(正在扩容时加入帮忙)和addCount(操作数组导致数组元素增加)三个方法
3、当在进行数组扩容的时候,如果当前节点还没有被处理(也就是说还没有设置为fwd节点),那就可以进行设置操作。如果该节点已经被处理了,则当前线程也会加入到扩容的操作中去
4、sizeCtl负数代表正在进行初始化或扩容操作、-N 表示有N-1个线程正在进行扩容操作,正数或0代表hash表还没有被初始化,这个数值表示初始化或下一次进行扩容的大小
5、计算元素数量时,使用baseCount+countCell数组,countCell数组是多个线程对元素的增减数量
Synchronized与ReentrantLock区别?CAS和synchronize有什么区别?
答:1、Lock是一个接口,synchronized是Java中的关键字,synchronized是内置的语言实现
2、synchronized发生异常时,会自动释放线程占用的锁,故不会发生死锁现象。Lock发生异常,若没有主动释放,极有可能造成死锁,故需要在finally中调用unLock方法释放锁;
3、Lock可以让等待锁的线程响应中断,使用synchronized只会让等待的线程一直等待下去,不能响应中断
4、通过Lock可以知道有没有成功获取到锁,synchronized就不灵
5、ReentrantLock可以是公平锁,而synchronized只能是非公平锁
6、ReentrantLock主要使用CAS,synchronized可以由偏向、轻量、重量级锁演进,如果能用synchronized的话尽量使用它
HashMap存储了50w的数据,给出最快速的遍历方法
答:用entrySet进行遍历
Semaphore用过吗?
答:Semaphore就相似于ReentrantLock的多值版本,如果设值为1,就约等于ReentrantLock。与CountDownLatch不同的是CountDownLatch只能减,而Semaphore的acquire减完之后要release去加回去
CompletableFuture用过吗?
答:CompletableFuture类实现了CompletionStage和Future接口,是一个用来实现异步功能的类,它可以通过传入一些函数式接口实现来进行异步的流程处理,并自行处理最终的结果;原先的Future的话采用的是轮询的方法去获得结果,而CompletableFuture使用传入的函数式进行结果的处理。
//采用异步的方法,得到hello后,调用join回到主线程,此时s = hello
String s = CompletableFuture.supplyAsync(() -> ("hello")).join();
//还可以调用thenAccept thenRun等方法
JVM有了解吗?JVM中参数 –Xms 和 -Xmx 是什么意思?
答:JVM是操作系统和java程序之间的一个桥梁,模拟了一个运行环境;
–Xms:设定堆内存的起始大小 –Xmx :设定堆内存的最大大小 -Xmn:memory newgeneration新生代内存 –Xss:设定stack size每个线程的堆栈大小
fast-fail和fast-safe?
答:Iterator的安全失败fast-safe是基于对底层集合做拷贝,因此它不受原集合上修改的影响。java.util包下面的所有的集合类都是快速失败的,而java.util.concurrent包下面所有的类都是fast-safe的。快速失败fast-fail的迭代器会抛出ConcurrentModificationException异常。
在调用 next() 和 remove()时,都会执行 checkForComodification()去检查ExpectModCount与ModCount是否一致;无论是add()、remove(),还是clear(),只要涉及到修改集合中的元素个数时,都会改变modCount的值。所以在多线程访问和修改的情况下就会出现fast-fail情况。
CopyOnWriteArrayList在进行添加操作的时候,将原数组进行一次复制,在复制的数组上进行操作并替代原数组,并且在这个过程中是加锁的,可以保证安全,但是速度有所下降。CopyOnWriteArrayList的迭代器是内部设计的,迭代器所访问的数组是不变的,即其他线程的修改引起了原list的数组中对象的改变,此时迭代器中所访问的数组依然不变。因此,这个迭代器是只读的,其他操作会抛出异常。
解决哈希冲突的四种方法
答:1、开放定址法:一旦发生了冲突,就去寻找下一个空的散列地址。为减少冲突,要求装填因子α较小,故当结点规模较大时会浪费很多空间
2、再哈希法:一次哈希不行就再哈希一次,但是会浪费计算。
3、链地址法:使用链表代替节点,但是指针需要额外的空间
4、公共溢出区:冲突溢出的部分放在专门的区域
HashMap为什么不是线程安全的?(JDK1.7和1.8的不同)
答:主要存在两个不安全的情况:put和resize
put时,如果有链表a->b,此时线程1持有c,线程2持有d,都要插入到b之后。若线程1拿到b准备插入c时,线程2进入并在b后插入了d,那么回到线程1插入c之后,d就丢失了,即造成了数据丢失的情况
在JDK7中,resize时使用头插法。若有链表a->b->c,扩容时插入到另一链表中,若此时插入a完成,准备插入b,另一线程进入完成了resize,则另一链表此时为c->b->a,回到原先的线程,a插入完毕准备插入下一个节点,发现下一个节点时b,就会造成死循环
在JDK8中改为尾插法之后,就不会出现这种问题,但是put问题依然存在
线程池的线程数怎么确定?如果是IO操作、计算型为主怎么确定?
答:根据任务的不同类型进行区分。由于IO操作在IO过程中不需要使用到cpu因此可以使用多个线程,而计算型不应该频繁切换cpu
如果是CPU密集型应用,则线程池大小设置为N+1 (N为CPU总核数)
如果是IO密集型应用,则线程池大小设置为2N+1 (N为CPU总核数)
可以在这两者的基础上进行优先级的顺序安排
写个BlockingQueue?阻塞队列有没有看过底层是怎么实现的?
答:以BlockQueue为例,其内部有两个锁:take锁和put锁(ReentrantLock),和一个原子计数器(AtomicInteger)
当offer时,锁住put锁,进行入队操作,并把计数器加一
当poll时,锁住take锁,进行出队操作,并把计数器减一
如果是要移除、查询中间的某个节点,或是进行其他非首尾节点的操作,那就要把两个锁都锁住
当队列的size == capacity时,用Condition notfull的notFull.await()再套个while去阻塞,当size + 1 < capacity时,用notfull的signal()去唤醒被阻塞的现场。与上述情况相反的是notEmpty的使用,即队列为空时阻塞想要poll的线程
//利用阻塞队列可以实现消费者-生产者模型
private static BlockingQueue<String> blockingDeque = new ArrayBlockingQueue<String>(5);//生产者进行生产...
blockingDeque.put("food");//消费者进行消费...
String food = blockingDeque.take();
AtomicInteger的底层?使用?
答:底层使用是sun.misc下的unsafe类和CAS操作,是一个类似c++可以直接操作内存的类,在AtomicInteger初始化是会去获取类的地址,后续unsafe就在这个地址上进行操作。直接进行底层的操作,好处是保证了原子性,坏处是有安全问题,因此unsafe类在jdk9中被删除了。并且AtomicInteger不能解决ABA问题。
常用方法有**getAndIncrement()**加返旧、**getAndDecrement()**减返旧、getAndAdd(int delta)加n返旧、addAndGet(int delta)加n返新、incrementAndGet()加返新、decrementAndGet减返新
Java中线程的状态?
新建状态(New): 线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()。
就绪状态(Runnable): 也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。
运行状态(Running): 线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。
阻塞状态(Blocked): 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(01) 等待阻塞 – 通过调用线程的wait()方法,让线程等待某工作的完成。
(02) 同步阻塞 – 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。
(03) 其他阻塞 – 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。死亡状态(Dead): 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
join()、yield()方法是干什么?
yield() 方法和 sleep() 方法类似,也不会释放“锁标志”,区别在于,它没有参数,即 yield() 方法只是使当前线程重新回到可执行状态,所以执行 yield() 的线程有可能在进入到可执行状态后马上又被执行,另外 yield() 方法只能使同优先级或者高优先级的线程得到执行机会,这也和 sleep() 方法不同。
join() 方法会使当前线程等待调用 join() 方法的线程结束后才能继续执行。比如在main中调用线程A.join() 会等线程A执行完再继续执行main
join就像是完全让开,而yield是只让上级,并且不交出锁,而且有可能继续执行
wait(),notify() 及 notifyAll() ?
答:都是 Object 类的方法,wait(),notify() 及 notifyAll() 只能在 synchronized 语句中使用,但是如果使用的是 ReenTrantLock 实现同步,该如何达到这三个方法的效果呢?解决方法是使用 ReenTrantLock.newCondition() 获取一个 Condition 类对象,然后 Condition 的 await(),signal() 以及 signalAll() 分别对应上面的三个方法。
ThreadLocal了解吗?原理?为什么会发送内存泄漏?使用的是开放地址法?
答:Thread类中有两个变量threadLocals和inheritableThreadLocals,二者都是ThreadLocal内部类ThreadLocalMap类型的变量
ThreadLocal内的方法调用的是当前线程中的threadLocals变量,把当前这个ThreadLocal变量作为key,传入的value作为value设置进对应线程的map,即currentThread.threadLocals中。
注意,ThreadLocalMap不是HashMap,结构类似但是内部的Entry是WeakReference<ThreadLocal<?>> 弱引用的
发生内存泄漏的原因:ThreadLocalMap的这个ThreadLocal被gc了,则当前线程的这个map里key变为null,但value依然存在,则这个线程不停止,这个value就无法被回收,造成内存泄漏
若ThreadLocalMap的Entry使用的是强引用,则不主动删除的话,ThreadLocal变量会伴随到全部使用它的线程的死亡才被回收
即强引用的话会造成key(ThreadLocal)和value两者内存泄漏,弱引用的话最多造成value的内存泄漏
将ThreadLocal变量定义成private static,这样就一直存在ThreadLocal的强引用,也就能保证任何时候都能通过ThreadLocal的弱引用访问到Entry的value值,进而清除掉
InheritableThreadLocal则是提供了一种子线程访问父线程的方法:把父线程的InheritableThreadLocal赋给子线程
使用开放地址法的原因:线程数一般较少,使用开放地址法比较节省空间,并且不用遍历链表,效率较高
TreeMap查询、写入的时间复杂度多少?底层数据结构?
答:O(logN)。底层数据结构是红黑树,红黑树需要满足以下几点:
1、每个节点都只能是红色或者黑色
2、根节点是黑色
3、每个叶节点(NIL节点,空节点)是黑色的。
4、如果一个结点是红的,则它两个子节点都是黑的。也就是说在一条路径上不能出现相邻的两个红色结点。
5、从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
put节点时,找到合适的位置插入再进行旋转;删除节点时,用特定的叶子节点(右分支最左边 或者 左分支最右边)替代要删除的节点再进行旋转
Arrays.sort()用的是什么算法?
答:元素小于47个时用插入排序,47到286用快排,大于296用归并排序。但也不是绝对,比如大于286但是不具备归并排的区间升区间降,就会用快排
如何用cglib来实现动态代理
答:使用一个Enhance增强器和一个MethodInterceptor方法拦截器
//MethodInterceptor内的方法
public Object getProxy(Class clazz) {enhancer.setSuperclass(clazz);enhancer.setCallback(this);return enhancer.create();//实现此方法进行增强
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable
GC Roots?
答:1、各个线程的局部变量 2、类的静态变量 3、方法区中常量引用的对象 4、被synchronized锁住的对象 5、虚拟机内部的引用如基本数据类型的Class对象等
小技巧:由于Root采用栈方式存放变量和指针,所以如果一个指针,它保存了堆内存里面的对象,但是自己又不存放在堆内存里面,那它就是一个Root
btw:System.gc()和Runtime.gc()没有区别,System.gc()调用了Runtime.gc()
逃逸分析?
答:一、同步省略。如果一个对象被发现只能从一个线程被访问到,那么对于这个对象的操作可以不考虑同步。
二、将堆分配转化为栈分配。如果一个对象在子程序中被分配,要使指向该对象的指针永远不会逃逸,对象可能是栈分配的候选,而不是堆分配。
三、分离对象或标量替换。有的对象可能不需要作为一个连续的内存结构存在也可以被访问到,那么对象的部分(或全部)可以不存储在内存,而是存储在CPU寄存器中。
垃圾回收器?G1?CMS?
答:
在jvm的client模式下用的是Serial + SerialOld组合,对于这种垃圾量小且单核的情况比较适用
ParNew回收器相当于Serial的多线程版,ParNew + SerialOld模式在JDK8已经标记为过时,ParNew一般与CMS一起使用
Parallel Scavenge + Parallel Old组合是JDK8的默认组合,以高吞吐量为目标,并具有自适应调节功能
CMS回收器以低延迟为目标,先进行初步标记(stw)然后与用户线程一起运行时进行并发标记,然后再次STW进行重新标记,接下来就可以进行一次并发清除了,最后用重置线程进行收尾。如果内存碎片太多的话,则依然需要一次SerialOld来兜底。常与ParNew进行搭配使用。如果改为标记整理的话,会对用户线程造成影响
**G1(Garbage First)**回收器:是新生代和老年代同时的算法,将内存看作一个个的小块,每个小块可以是Eden或是Survivor或是old区,在回收时维护一个队列,按照回收后的效益进行排序,回收时将要回收的小块用标记复制算法到另一个空闲小块中,如果是比较大的对象,G1中还有一种针对于大对象的块,是连续的。虽然用标记复制算法但是从效果上看更像是标记整理。由于可以知道回收的小块的数量,因此可以预测大概的回收时长是多少。与CMS相比,最好不一定有它好,但最坏一定比它好。在大内存的情况下,G1会有优势。G1采用了Remembered Set来记录本小块指向了哪些小块,因此会有性能消耗,但不需要进行全部小块的扫描
混合回收:回收新生代和部分老年代(1/8);根区域扫描->并发标记->再次标记->独占清理(只是排序,找要回收的小块)->并发清理
full gc:如果以上效果不好,则进行一次full gc(串行)
命令:-XX:+UseXX垃圾回收器
JDBC是如何实现和数据库连接的,基于什么协议?
答:使用的应该是封装的TCP/IP协议,具体实现应该是类似于SSH连接这种吧
JDBC中的PreparedStatement有哪些优点
答:是一个预编译的语句执行器,所以主要是预编译的好处:1、可以批量处理数据,因为要填入的数据已经提前可知了
2、预编译防止sql注入 3、当然,单条语句的执行没有普通的Statemen快
new一个对象的过程?
答:1、查看常量池中是否有这个类的符号引用 2、如果还没加载过类,就进行父类、类的加载(双亲委派) 3、为对象分配一个内存空间:指针碰撞、空闲列表 4、对数据类型都赋0值 5、对对象头进行设置:GC年龄等等 6、调用init方法 7、创建栈中引用
啥时候破坏双亲委派?
答:系统类加载器需要加载用户类时,比如JDBC中驱动的加载,使用的就是系统类加载器.实现方法就是重写类加载器的loadclass方法
如何判断一个JVM进程是否发生了内存泄漏?
答:1、首先查看关键容易出现泄漏的代码段
2、查看整个JVM进程的内存使用情况是否符合预期
3、查看新生代老年代的对象数量
hazy的面试小笔记之Java(持续更新)相关推荐
- Vue -- 指令【学习笔记】(持续更新)
Vue – 指令[学习笔记](持续更新) 记录了Vue第三天的学习笔记 v-show 注意,v-show 不支持 <template> 元素,也不支持 v-else. 带有 v-show ...
- 尚硅谷(李立超)——HTML5CSS3笔记总结【持续更新】
尚硅谷(李立超)--HTML5&CSS3笔记总结[持续更新] 本文适合前端菜鸟食用,小编自己整理的李立超老师视频的笔记,手打不易,那就望您每年快乐吧.逃) 一.进制 1.十进制(日常使用): ...
- 前端(js/css/html)那些小的知识点,持续更新......
前端(js/css/html)那些小的知识点,持续更新...... 1.行内元素与块级元素有哪些及区别? 块级元素和行内元素的区别是,块级元素会占一行显示,而行内元素可以在一行并排显示.通过样式控制, ...
- 全部文章分类与整理(找工作+面试+资源分享),持续更新
阅读本文大概需要 6 分钟 由于本公众号发表的文章有点多,并且发的文章也不是一个专题一个专题这样发的,所以难免有读者过来找我吐槽说,想搜索历史的文章,不太方便. 鉴于此,为了大家阅读文章方便,我整理了 ...
- 2019最新Web前端经典面试试题及答案,持续更新
Ps: 文章所述内容,来源渠道平时积累以及网上摘录.按日期持续更新...目录: 转载请注明来源. -2018/6/8 1.position的定位方式 2.描述下从输入URL到整个网页加载完毕及显示 ...
- 最实用的微信小程序大全,持续更新中...
最全的小程序开发教程,点击下载掘金App. 小程序上线 1月9日,张小龙没有食言,微信小程序如约而至.凌晨刚过,我们便在微信发现页看到了小程序的入口. 微信发现页 之后的一个小时里,每个微信群都在疯狂 ...
- 个人学习笔记汇总(持续更新)
白墨的个人学习笔记 HTML JAVA Python MySQL 等待添加 说明 大家好,这里白墨,话不多说,先放笔记: HTML HTML笔记 JAVA JAVA笔记Myeclipse快捷键占位符的 ...
- AutoCAD2019+vs2019+C# 二次开发学习笔记day01(持续更新)
目录 一.新建项目 1.应用程序 目标框架 选择 4.7.2版 2.生成 目标平台选择x64 3.调试 启动外部程序 选择 acad.exe 二.添加autocad类库 三.如何运用命名空间 1.[C ...
- 数据结构(Java)-持续更新补充
复习一下数据结构,巩固一下基础. 之后打算再学一下算法,之前刷题总感觉摸不清门道,应该是概念没彻底搞明白. 栈 import java.util.Arrays;public class Stack { ...
- 2020年Java面试题及答案_Java面试宝典_Java笔试题(持续更新中)
推荐面试视频教程 2019年最新Java互联网大厂面试精粹 前言 前言: 少年易老学难成,一寸光阴不可轻.未觉池塘春草梦,阶前梧叶已秋声 .-朱熹<劝学诗> 勤奋才是改变你命运的唯一捷径. ...
最新文章
- 飞机的“黑色十分钟”能被人工智能消灭吗?
- 超实用总结:AI实践者需要用到的10个深度学习方法
- exit的用法python_python 中exit,sys.exit,os._exit用法
- java jxl创建多个sheet,使用jxl导出excel时怎么创建多个sheet | 学步园
- java学习(89):Charactor包装类统计
- python图像分类代码_Kaggle—So Easy!百行代码实现排名Top 5%的图像分类比赛
- 0626 Django模型(ORM)
- 洛谷 P2010 回文日期
- java的jdk和jre有什么区别
- 红胖子创业一年整总结:前二十年题记,萌芽初期,外包初期,创业初期,未来规划
- 魔兽争霸lostTemple地图
- mysql every derived table must_Mysql错误Every derived table must have its own alias解决方法
- 什么是「设计模式」?
- java 代码箭头代表什么_箭头运算符' - '在Java中做什么?
- 跟涛哥一起学嵌入式 26:深入浅出计算机编码、乱码问题
- Zabbix 配置钉钉告警
- SAP 财务校验(基本内容及常用财务校验配置涉及退出提供源代码)
- Java十六进制操作
- UGUI Text组件上动态显示Emoji
- 什么是分库分表?为什么需要分表?什么时候分库分表
热门文章
- windows s2019安装crucible-4.8.2
- 无线路由器DNS服务器异常,fast无线路由器dns异常的解决方法
- 查询淘宝京东商品历史价格的方法
- 什么是数据结构?是举一个例子,叙述逻辑结构、存储结构和运算三个方面的内容。
- 同花顺没签三方要赔钱才能拿回三方!!!!
- win10子系统基本备份
- 纯电动汽车架构设计(一) :电动车架构设计核心与前悬架选择
- openwrt默认mac地址配置(MT7620a)
- Permission denied: user=10273, access=WRITE, inode=“/cou/jd_phone_list“:root:supergroup:-rw-r--r--
- 网站被劫持,打开一个网站会跳到另一个怎么办,直接输入网址也是这样。怎么办呢?