@x-power
2022-12-27T05:19:50.000000Z
字数 8319
阅读 832
面试
重写: 表示将子类中的方法与父类中的某个方法的名称和参数完全相同,这个时候子类重写了父类的该方法, 这个是多态性的一种表现.
子类覆盖父类的时候只能抛出比父类更少的异常, 因为子类用于解决父类存在的一些问题, 所以不能比父类有更多的问题. --- 越来越完美
子类方法的访问权限只能比父类的更大,不能更小, 如果父类的该方法使用私有修饰符修饰的话, 这样就不存在继承. --- 越来越开放.
| 参数 | 抽象类 | 接口 |
|---|---|---|
| 默认的方法实现 | 可以有默认的方法实现 | 接口是抽象的,不存在方法的实现(JDK8 default). |
| 实现 | 子类使用extend关键字来继承抽象类,如果子类不是抽象类的话,他需要提供抽象类中所有声明方法的实现. | 子类使用关键字来implates来实现接口, 他需要提供接口中所有声明的方法和实现. |
| 构造器 | 抽象类可以有构造器 | 接口不能有构造器 |
| 与正常的Java类的区别 | 除了不能实例化抽象类之外,它和普通的Java类没有区别(实例化抽象类, 其实是匿名类,需要将其中所有的抽象函数实现之后可以实现匿名类.) | 接口和类不是同一个东西. |
| 访问修饰符 | 抽象方法可以有public,protected,default这些访问修饰符. | 接口方法默认的修饰符是public,你不可以使用其他修饰符 |
main方法 |
抽象方法可以有main方法,并且我们可以运行它 |
接口没有main方法,因此我们不能运行它 |
| 多继承 | 抽象方法可以继承一个类和实现多个接口 | 接口只能继承一个或者多个其他接口 |
| 速度 | 比接口的速度更快 | 接口式比较慢的,因为它需要时间去寻找在类中实现的方法 |
| 添加新方法 | 如果向抽象类中添加新的方法,你可以给他提供默认的实现,因此你不需要改变你现在的代码 | 如果在接口中添加方法,那么你必须改变实现该接口的类. |
package pers.ycy.base;public class FinalClass {public static void main(String[] args) {Animal ag = new Dog();new Dog();new Dog().run();Animal animal = new Animal() {@Overrideprotected void sing() {System.out.println("sing");}};animal.sing();}}/*** 抽象类, 动物.*/abstract class Animal {int age;String name;public static void main(String[] args) {Animal sing_sing = new Animal() {@Overrideprotected void sing() {System.out.println("sing sing");}};sing_sing.run();}// 每次创建 新对象的时候会调用一次, 运行优先级 高于构造函数 低于静态代码块.{System.out.println("构造代码块");}// 在第一次创建对象的时候会执行一次. 运行优先于 构造代码块, 通常用于初始化只调用一次的数据, 例如: 初始化程序的运行配置信息static {System.out.println("静态代码块");}Animal() {System.out.println("抽象类的构造函数");}abstract protected void sing();protected void run() {{int x = 10;System.out.println(x);System.out.println("用于限定变量的作用域.");}System.out.println("动物是可以跑得");}}class Dog extends Animal {@Overrideprotected void sing() {System.out.println("汪汪");}}abstract class AGou extends Dog{}
public class FinalClass {public static void main(String[] args) {Dog dog = new Dog();dog.eat();}}/*** 接口和类 是不同的, 抽象类中的 构造代码块, 静态代码块, 构造函数. 接口中是没有的.*/interface Animal{default void eat(){System.out.println("接口的默认方法, 如果使用该方法, 则该方法需要对所有实现该接口的类都有用 .");}}class Dog implements Animal{}
获取一个对象对应的反射类在,Java方法中有下面几种方法可以获得反射类.
getClass()Class.forName()类.classgetClassLoader()在支持Session复制的Web服务器上,通过修改Web服务器的配置,可以实现将Session同步到其它Web服务器上,达到每个Web服务器上都保存一致的Session.
将用户的每次请求都通过某种方法强制分发到某一个Web服务器上,只要这个Web服务器上存储了相应的Session数据,就可以实现会话跟踪.
在单独的服务器或者服务器集群上使用缓存技术,如Redis存储Session数据,集中管理所有的Session.所有的Web服务器都从这个存储介质中去的对应的Session,实现Session共享.
这种方式每次发起请求的时候都需要将Session数据放到Cookie中传递给服务端.
DriverManager类注册驱动数据库驱动程序.DriverManager.getConnection方法,通过JDBC URL将用户名,密码,数据表等信息传入,以得到数据库链接.MVC是三个单词的首字母缩写, 他们是Model, View, Controller. 这个模式认为, 程序不论简单与复杂, 从结构上来看,都可以分为三层:
equals和==的区别两个对象用
equals比较返回true,那么两个对象的hashcode方法必须返回相同的结果.
hashtable中, 两个自认为相同的对象(equals为true), 在取值和存值的时候就会出现, 下表地址不同的情况. 这样就麻烦很大了.两个对象用
equals比较返回false,那么两个对象的hashcode方法也不一定返回不同的值,但是最好返回不同的值,这样可以提高哈希表的性能.
根据第二点,重写
equals的时候,必须重写hashcode,以确保equals方法相等的时候两个对象的hashcode返回相同的值.
equals和hashcode应该保持一致性.set集合去重的时候, 判断是否相等用的是 哈希值和equals同时成立与否. 这样也可以看出应该让 equals和hashcode应该保持一致性.
equals和==的区别是: ==用于比较原生类型,而equals方法用于检查对象的相等性.==和equals用于比较对象,当两个引用地址相同,==返回true.而equals可以返回true或false主要取决于重写的实现.最常见的一个例子,字符串的比较,不同情况==和equals返回不同的结果.list和map的区别.
Map是键值对的方式进行存储的, 根据值去获取键,List是根据下标进行存储的, 所以必须要有顺序,有下标才能顺利的进行存取. 但是Map就不需要下标,且没有顺序. 只需计算Hash值即可
Map接口有三个实现类:HashMap,HashTable,LinkedHashMap.
List接口有三个实现类:LinkList,ArrayList,Vector.
LinkedList: 底层基于链表实现, 链表内存是散乱的, 每一个内节点都存储着 上一个节点的地址和下一个节点的地址以及本身的值.
Map相当于和Collection一个级别的,Map集合存储键值对,且要求保持键的唯一性.
Map是基于哈希存储的所以要求保持键的唯一性.其中区别: List特点 元素放入有顺序,元素且可以重复. Map特点 元素按键值对存储,无放入顺序.
List和Set的区别
List和Set都是继承自Collection接口.
List特点: 要么是链表要么是顺序数组,所以有顺序,元素可重复.
Set特点: HashSet(底层是HashMap),LinkedHashSet.
ArrayList和LinkList的区别其实就是顺序数组和链表的区别
ArrayList和Vector的区别都是顺序数组, 但是
Vector是线程安全的,ArrayList是线程不安全的.
Vector的数据增长是原来的一倍,ArrayList是增加原来的50%.
Vector这样可以减少因为扩容产生的时间消耗. ArrayList.HashMap和HashTableHashMap几乎可以等价于HashTable,除了HashMap是非
synchronized的,并且可以接受null(HashMap可以接受为null的键值和值,而HashTable则不可以).
HashMap是非synchronize,而HashTable是synchronize的.这意味着HashTable是线程安全的,多个线程可以共享一个HashTable,如果没有一个正确的同步的话,多个线程是不能共享HashMap的, Java5提供了ConcurrentHashMap,它是HashMap的替代,比HashMap的扩展性更好.
Synchronization关键字.java.util.concurrent.atomic包中的原子类, 例如AtomicInteger.java.util.concurrent.locks 包中的锁ConcurrentHashMapvolatile 关键字,保证变量可见性(直接从内存读,而不是从线程 cache 读)在JVM底层volatile 是采用“内存屏障”来实现的.
缓存一致性协议(MESI协议)它确保每个缓存中使用的共享变量的副本是一致的。其核心思想如下:当某个 CPU 在写数据时,如果发现操作的变量是共享变量,则会通知其他 CPU 告知该变量的缓存行是无效的,因此其他 CPU 在读取该变量时,发现其无效会重新从主存中加载数据
synchronized 与 lock 的区别synchronized 与 lock 的区别
synchronized(隐式锁): 在需要同步的对象中加入此控制, synchronized方法上, 也可以加在特定代码块中, 括号中表示需要上锁的对象.lock(显示锁): 需要显示指定其实位置和终止位置. 一般使用ReentrantLock类作为锁, 多个线程中必须要使用一个 ReentrantLock 类做为对象才能保证锁的生效。且在加锁和解锁处需要通过 lock() 和 unlock() 显示指出。所以一般会在 finally 块中写 unlock() 以防死锁。synchronized 和 lock 性能区别
synchronized 是托管给 JVM 执行的,而 lock 是 Java 写的控制锁的代码。在 JDK 1.5 中,synchronize 是性能低效的。因为这是一个重量级操作,需要调用操作接口,导致有可能加锁消耗的系统时间比加锁以外的操作还多。相比之下使用 Java 提供的 Lock 对象,性能更高一些。但是到了 JDK 1.6,发生了变化。synchronize 在语义上很清晰,可以进行很多优化,有适应自旋,锁消除,锁粗化,轻量级锁,偏向锁等等。导致在 JDK 1.6 上 synchronize 的性能并不比 Lock 差。
public static void main(String[] args) {ok:for(int i=0;i<10;i++){for(int j=0;j<10;j++){if(j==5){System.out.println("j==5");break ok;}}}}
final 修饰一个关键字的时候,是栈内存不能变,和堆内存无关。
public static void main(String[] args) {final StringBuilder a = new StringBuilder("1qwe");a.append("asdasd");}
String被声明为final类型,因此不可以继承
String使用final修饰的原因如下
字符串是不可变的, 所以是多线程安全的, 同一个字符串可以被多个线程共享. 这样便不用因为线程安全问题而使用同步(牵扯到Volatile关键字). 字符串自己便是线程安全的.
数据库的用户名,密码都是以字符串的形式传入来获得数据库的链接, 或者在Socket编程中, 主机的主机名和端口都是以字符串的形式传入的, 因为字符串是不可变的, 所以值是不可变的, 否则黑客可以改变字符串指向的对象的值, 造成安全漏洞. (非安全专业, 但是这种东西 还是和纸糊的墙差的不).
字符串是不可变的, 所以他在创建的时候HashCode就被缓存了, 不需要重新计算, 这就使得字符串很适合作为Map中的键, 字符串的处理速度也要快过其他键的对象. 所以HashMap中的键一般都是字符串.
静态方法:静态方法在类加载的时候就已经存在了、他不依赖于任何实例。所以静态方法必须有实现,不能是抽象方法。并且方法中不能有super和this关键字,因为这两个关键字适合具体对象相关联的。
静态语句块:在类初始化的时候执行一次,一般用于初始化该类的一些信息。
静态内部类:非静态内部类依赖于外部类的实例,也就是说需要先创建外部类实例,才可以用这个实例去创建非静态内部类。而静态内部类就可以直接创建。
monitor lock从而进入synchronized函数或者代码块,但是其他线程已经占用了该monitor,所以处于阻塞状态。要结束该状态进入状态2需要其他线程释放monitor lock。阻塞和等待的区别:阻塞是被动的,它是在等待获取monitor lock。而等待是主动的,通过调用Object.wait()等方法进入。
Waiting状态进入和退出的方法:
| 进入方法 | 退出方法 |
|---|---|
没有设置Timeout参数的Object.wait()方法 |
Object.notify()/Object.notifyAll() |
没有设置Timeout参数的Thread.join()方法 |
被调用的线程执行完毕 |
LockSupport.park()方法 |
LockSupport.unpark(Thread) |