重庆一站式建设网站平台,温州网站建设这个,淘宝客新增网站,新手做淘宝客网站教程9月13日
Q#xff1a;JDK、JRE、JVM之间的区别 A#xff1a;
JDK(Java SE Development Kit)#xff0c;Java标准开发包#xff0c;它提供了编译、运⾏Java程序所需的各种⼯具和资源#xff0c;包括Java编译器、Java运⾏时环境#xff0c;以及常⽤的Java类库等JRE( Java…9月13日
QJDK、JRE、JVM之间的区别 A
JDK(Java SE Development Kit)Java标准开发包它提供了编译、运⾏Java程序所需的各种⼯具和资源包括Java编译器、Java运⾏时环境以及常⽤的Java类库等JRE( Java Runtime Environment) Java运⾏环境⽤于运⾏Java的字节码⽂件。JRE中包括了JVM以及JVM⼯作所需要的类库普通⽤户⽽只需要安装JRE来运⾏Java程序⽽程序开发者必须 安装JDK来编译、调试程序。JVM(Java Virtual Mechinal)Java虚拟机是JRE的⼀部分它是整个java实现跨平台的最核⼼的部分负责运⾏字节码⽂件。 9月14日
Q什么是面向对象 A 面向过程更注重事情的每一个步骤及顺序面向对象更注重事情有哪些参与者对象、及各自需要做什么。 封装 封装的意义在于明确标识出允许外部使用的所有成员函数和数据项。 内部细节对外部调用透明外部调用无需修改或者关心内部实现
继承 继承基类的方法并做出自己的改变和/或扩展。 子类共性的方法或者属性直接使用父类的而不需要自己再定义只需扩展自己个性化的
多态 基于对象所属类的不同外部对同一个方法的调用实际执行的逻辑不同。 继承方法重写父类引用指向子类对象
9月15日
Q和equals比较 A 对比的是栈中的值基本数据类型是变量值引用类型是堆中内存对象的地址 equalsobject中默认也是采用 比较通常会重写
String中重写的 equals 方法比较的就是字符串的内容。 9月16日
Qfinal 关键字的作用 A
修饰类表示类不可被继承修饰方法表示方法不可被子类覆盖但是可以重载修饰变量表示变量一旦被赋值就不可以更改它的值。
1修饰成员变量
如果final修饰的是类变量只能在静态初始化块中指定初始值或者声明该类变量时指定初始值。如果final修饰的是成员变量可以在非静态初始化块、声明该变量或者构造器中执行初始值。
2修饰局部变量 系统不会为局部变量进行初始化局部变量必须由程序员显示初始化。因此使用final修饰局部变量时即可以在定义时指定默认值后面的代码不能对变量再赋值也可以不指定默认值而在后面的代码中对final变量赋初值仅一次 3修饰基本类型数据和引用类型数据
如果是基本数据类型的变量则其数值一旦在初始化之后便不能更改如果是引用类型的变量则在对其初始化之后便不能再让其指向另一个对象。但是引用的值是可变 的。 Q为什么局部内部类和匿名内部类只能访问局部final变量 A 编译之后会生成两个class文件Test.class Test1.class 首先需要知道的一点是: 内部类和外部类是处于同一个级别的内部类不会因为定义在方法中就会随着方法的执行完毕就被销毁。
这里就会产生问题当外部类的方法结束时局部变量就会被销毁了但是内部类对象可能还存在(只有没有人再引用它时才会死亡)。这里就出现了一个矛盾内部类对象访问了一个不存在的变量。为了解决这个问题就将局部变量复制了一份作为内部类的成员变量这样当局部变量死亡后内部类仍可以访问它实际访问的是局部变量的copy。这样就好像延长了局部变量的生命周期
将局部变量复制为内部类的成员变量时必须保证这两个变量是一样的也就是如果我们在内部类中修改了成员变量方法中的局部变量也得跟着改变怎么解决问题呢
就将局部变量设置为final对它初始化后我就不让你再去修改这个变量就保证了内部类的成员变量和方法的局部变量的一致性。这实际上也是一种妥协。使得局部变量与内部类内建立的拷贝保持一致。
9月17日
QString、StringBuffer、StringBuilder A
String是final修饰的不可变每次操作都会产生新的String对象StringBuffer和StringBuilder都是在原对象上操作StringBuffer是线程安全的StringBuilder线程不安全的StringBuffer方法都是synchronized修饰的
性能StringBuilder StringBuffer String 场景经常需要改变字符串内容时使用后面两个 优先使用StringBuilder多线程使用共享变量时使用StringBuffer
9月18日
Q重载和重写的区别 A 重载 发生在同一个类中方法名必须相同参数类型不同、个数不同、顺序不同方法返回值和访问修饰符可以不同发生在编译时。 重写 发生在父子类中方法名、参数列表必须相同返回值范围小于等于父类抛出的异常范围小于等于父类访问修饰符范围大于等于父类如果父类方法访问修饰符为private则子类就不能重写该方法。
9月19日
Q接口和抽象类的区别 A
抽象类可以存在普通成员函数而接口中只能存在public abstract 方法。抽象类中的成员变量可以是各种类型的而接口中的成员变量只能是public static final类型的。抽象类只能继承一个接口可以实现多个。
接口的设计目的是对类的行为进行约束更准确的说是一种“有”约束因为接口不能规定类不可以有什么行为也就是提供一种机制可以强制要求不同的类具有相同的行为。它只约束了行为的有无但不对如何实现行为进行限制。
而抽象类的设计目的是代码复用。当不同的类具有某些相同的行为(记为行为集合A)且其中一部分行为的实现方式一致时A的非真子集记为B可以让这些类都派生于一个抽象类。在这个抽象类中实现了B避免让所有的子类来实现B这就达到了代码复用的目的。而A减B的部分留给各个子类自己实现。正是因为A-B在这里没有实现所以抽象类不允许实例化出来否则当调用到A-B时无法执行。
抽象类是对类本质的抽象表达的是 is a 的关系比如 BMW is a Car 。抽象类包含并实现子类的通 用特性将子类存在差异化的特性进行抽象交由子类去实现。
而接口是对行为的抽象表达的是 like a 的关系。比如 Bird like a Aircraft 像飞行器一样可以 飞但其本质上 is a Bird 。接口的核心是定义行为即实现类可以做什么至于实现类主体是谁、 是如何实现的接口并不关心。
使用场景当你关注一个事物的本质的时候用抽象类当你关注一个操作的时候用接口。
抽象类的功能要远超过接口但是定义抽象类的代价高。因为高级语言来说从实际设计上来说也是每个类只能继承一个类。在这个类中你必须继承或编写出其所有子类的所有共性。虽然接口在功能上会弱化许多但是它只是针对一个动作的描述。而且你可以在一个类中同时实现多个接口。在设计阶段会降低难度
9月20日
QList和Set的区别 A
List 有序按对象进入的顺序保存对象可重复允许多个 Null 元素对象可以使用Iterator取出所有元素在逐一遍历还可以使用get(int index)获取指定下标的元素。
Set 无序不可重复最多允许有一个 Null 元素对象取元素时只能用Iterator接口取得所有元素在逐一遍历各个元素。
9月21日
QArrayList和LinkedList区别 A ArrayList 基于动态数组连续内存存储适合下标访问随机访问扩容机制因为数组长度固定超出长度存数据时需要新建数组然后将老数组的数据拷贝到新数组如果不是尾部插入数据还会涉及到元素的移动往后复制一份插入新元素使用尾插法并指定初始容量可以极大提升性能、甚至超过linkedList需要创建大量的node对象
LinkedList 基于链表可以存储在分散的内存中适合做数据插入及删除操作不适合查询需要逐一遍历
遍历LinkedList必须使用iterator不能使用for循环因为每次for循环体内通过get(i)取得某一元素时都需要对list重新进行遍历性能消耗极大。另外不要试图使用indexOf等返回元素索引并利用其进行遍历使用indexlOf对list进行了遍历当结果为空时会遍历整个列表。
9月22日
QHashMap和HashTable有什么区别其底层实现是什 么
A 区别 1HashMap方法没有synchronized修饰线程非安全HashTable线程安全 2HashMap允许key和value为null而HashTable不允许
HashMap底层实现数组链表实现 jdk8开始链表高度到8、数组长度超过64链表转变为红黑树元素以内部类Node节点存在
计算key的hash值二次hash然后对数组长度取模对应到数组下标如果没有产生hash冲突(下标位置没有元素)则直接创建Node存入数组如果产生hash冲突先进行equal比较相同则取代该元素不同则判断链表高度插入链表链表高度达到8并且数组长度到64则转变为红黑树长度低于6则将红黑树转回链表key为null存在下标0的位置
数组扩容
9月23日
QConcurrentHashMap原理jdk7和jdk8版本的区别 A jdk7 数据结构ReentrantLockSegmentHashEntry一个Segment中包含一个HashEntry数组每个HashEntry又是一个链表结构
元素查询二次hash第一次Hash定位到Segment第二次Hash定位到元素所在的链表的头部
锁Segment分段锁 Segment继承了ReentrantLock锁定操作的Segment其他的Segment不受影 响并发度为segment个数可以通过构造函数指定数组扩容不会影响其他的segment
get方法无需加锁volatile保证
jdk8 数据结构synchronizedCASNode红黑树Node的val和next都用volatile修饰保证可见性查找替换赋值操作都使用CAS锁锁链表的head节点不影响其他元素的读写锁粒度更细效率更高扩容时阻塞所有的读写操作、并发扩容
读操作无锁
Node的val和next使用volatile修饰读写线程对该变量互相可见数组用volatile修饰保证扩容时被读线程感知
9月24日
Q什么是字节码采用字节码的好处是什么 A java中的编译器和解释器 Java中引入了虚拟机的概念即在机器和编译程序之间加入了一层抽象的虚拟的机器。这台虚拟的机器在任何平台上都提供给编译程序一个的共同的接口。
编译程序只需要面向虚拟机生成虚拟机能够理解的代码然后由解释器来将虚拟机代码转换为特定系 统的机器码执行。在Java中这种供虚拟机理解的代码叫做 字节码即扩展名为 .class的文件它不 面向任何特定的处理器只面向虚拟机。
每一种平台的解释器是不同的但是实现的虚拟机是相同的。Java源程序经过编译器编译后变成字节码字节码由虚拟机解释执行虚拟机将每一条要执行的字节码送给解释器解释器将其翻译成特定机器上的机器码然后在特定的机器上运行。这也就是解释了Java的编译与解释并存的特点。
Java源代码----编译器----jvm可执行的Java字节码(即虚拟指令)----jvm----jvm中解释器-----机器可执行的二进制机器码----程序运行。
采用字节码的好处 Java语言通过字节码的方式在一定程度上解决了传统解释型语言执行效率低的问题同时又保留了解释型语言可移植的特点。所以Java程序运行时比较高效而且由于字节码并不专对一种特定的机器因此Java程序无须重新编译便可在多种不同的计算机上运行。
9月25日
QJava类加载器 A JDK自带有三个类加载器bootstrap ClassLoader、ExtClassLoader、AppClassLoader。 BootStrapClassLoader是ExtClassLoader的父类加载器默认负责加载%JAVA_HOME%lib下的jar包和 class文件。 ExtClassLoader是AppClassLoader的父类加载器负责加载%JAVA_HOME%/lib/ext文件夹下的jar包和class类。 AppClassLoader是自定义类加载器的父类负责加载classpath下的类文件。系统类加载器线程上下文加载器。 继承ClassLoader实现自定义类加载器
9月26日
Q双亲委托模型 A
双亲委派模型的好处
主要是为了安全性避免用户自己编写的类动态替换 Java的一些核心类比如 String。 同时也避免了类的重复加载因为 JVM中区分不同类不仅仅是根据类名相同的 class文件被不同的 ClassLoader加载就是不同的两个类。
同时也避免了类的重复加载因为 JVM中区分不同类不仅仅是根据类名相同的 class文件被不 同的 ClassLoader加载就是不同的两个类。
9月27日
QJava中的异常体系 A
Java中的所有异常都来自顶级父类Throwable。Throwable下有两个子类Exception和Error。Error是程序无法处理的错误一旦出现这个错误则程序将被迫停止运行。Exception不会导致程序停止又分为两个部分RunTimeException运行时异常和CheckedException检查异常。RunTimeException常常发生在程序运行过程中会导致程序当前线程执行失败CheckedException常常发生在程序编译过程中会导致程序编译不通过。
9月28日
QGC如何判断对象可以被回收 A
引用计数法每个对象有一个引用计数属性新增一个引用时计数加1引用释放时计数减1计数为0时可以回收可达性分析法从 GC Roots 开始向下搜索搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连时则证明此对象是不可用的那么虚拟机就判断是可回收对象。
引用计数法可能会出现A 引用了 BB 又引用了 A这时候就算他们都不再使用了但因为相互引用 计数器1 永远无法被回收。
GC Roots的对象有
虚拟机栈(栈帧中的本地变量表中引用的对象方法区中类静态属性引用的对象方法区中常量引用的对象本地方法栈中JNI(即一般说的Native方法)引用的对象
可达性算法中的不可达对象并不是立即死亡的对象拥有一次自我拯救的机会。对象被系统宣告死亡至 少要经历两次标记过程第一次是经过可达性分析发现没有与GC Roots相连接的引用链第二次是在由 虚拟机自动建立的Finalizer队列中判断是否需要执行finalize()方法。
当对象变成(GC Roots)不可达时GC会判断该对象是否覆盖了finalize方法若未覆盖则直接将其回 收。否则若对象未执行过finalize方法将其放入F-Queue队列由一低优先级线程执行该队列中对象 的finalize方法。执行finalize方法完毕后GC会再次判断该对象是否可达若不可达则进行回收否 则对象“复活”
每个对象只能触发一次finalize()方法 由于finalize()方法运行代价高昂不确定性大无法保证各个对象的调用顺序。
9月29日
Q线程的生命周期线程有几种状态 A 1.线程通常有五种状态创建就绪运行、阻塞和死亡状态。 2.阻塞的情况又分为三种
(1). 等待阻塞运行的线程执行wait方法该线程会释放占用的所有资源JVM会把该线程放入“等待池”中。进入这个状态后是不能自动唤醒的必须依靠其他线程调用notify或notifyAll方法才能被唤醒wait是object类的方法
(2). 同步阻塞运行的线程在获取对象的同步锁时若该同步锁被别的线程占用则JVM会把该线程放入“锁池”中。
(3). 其他阻塞运行的线程执行sleep或join方法或者发出了I/O请求时JVM会把该线程置为阻塞状态。当sleep状态超时、join等待线程终止或者超时、或者I/O处理完毕时线程重新转入就绪状态。sleep是Thread类的方法
新建状态New新创建了一个线程对象。就绪状态Runnable线程对象创建后其他线程调用了该对象的start方法。该状态的线程位于可运行线程池中变得可运行等待获取CPU的使用权。运行状态Running就绪状态的线程获取了CPU执行程序代码。阻塞状态Blocked阻塞状态是线程因为某种原因放弃CPU使用权暂时停止运行。直到线程进入就绪状态才有机会转到运行状态。死亡状态Dead线程执行完了或者因异常退出了run方法该线程结束生命周期。
9月30日
Qsleep()、wait()、join()、yield()的区别 A 锁池 所有需要竞争同步锁的线程都会放在锁池当中比如当前对象的锁已经被其中一个线程得到则其他线程需要在这个锁池进行等待当前面的线程释放同步锁后锁池中的线程去竞争同步锁当某个线程得到后会进入就绪队列进行等待cpu资源分配。 等待池 当我们调用 wait() 方法后线程会放到等待池当中等待池的线程是不会去竞争同步锁。只有调用了notify() 或 notifyAll() 后等待池的线程才会开始去竞争锁notify() 是随机从等待池选出一个线程放到锁池而 notifyAll() 是将等待池的所有线程放到锁池当中。
1、sleep 是 Thread 类的静态本地方法wait 则是 Object 类的本地方法。 2、sleep 方法不会释放 lock但是 wait 会释放而且会加入到等待队列中。 sleep就是把cpu的执行资格和执行权释放出去不再运行此线程当定时时间结束再取回cpu资源参与cpu 的调度获取到cpu资源后就可以继续运行了。而如果sleep时该线程有锁那么sleep不会释放这个锁而 是把锁带着进入了冻结状态也就是说其他需要这个锁的线程根本不可能获取到这个锁。也就是说无法执行程 序。如果在睡眠期间其他线程调用了这个线程的interrupt方法那么这个线程也会抛出 interruptexception异常返回这点和wait是一样的。 3、sleep 方法不依赖于同步器 synchronized但是 wait 需要依赖 synchronized 关键字。 4、sleep 不需要被唤醒休眠之后推出阻塞但是 wait 需要不指定时间需要被别人中断。 5、sleep 一般用于当前线程休眠或者轮循暂停操作wait 则多用于多线程之间的通信。 6、sleep 会让出 CPU 执行时间且强制上下文切换而 wait 则不一定wait 后可能还是有机会重新竞争到锁继续执行的。
yield() 执行后线程直接进入就绪状态马上释放了cpu的执行权但是依然保留了cpu的执行资格所以有可能cpu下次进行线程调度还会让这个线程获取到执行权继续执行
join() 执行后线程进入阻塞状态例如在线程B中调用线程A的 join()那线程B会进入到阻塞队列直到线程A结束或中断线程