1.JAVA中的几种基本数据类型是什么,各自占用多少字节。
int 32bit short 16bit
long 64bit byte 8bit
char 16bit float 32bit
double 64bit boolean 1bit
============================================================
2.String类能被继承吗,为什么?
public final class String
implements java.io.Serializable, Comparable
String 被final修饰了,所有不能被继承。
1.final修饰的对象不能被修改;
2.final修饰的类不能被继承;
3.final修饰的方法不能被重写;
==================================================================
1.可变与不可变
String类中使用字符数组保存字符串,如下就是,因为有“final”修饰符,所以可以知道string对象是不可变的。
private final char value[];
StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,如下就是,可知这两种对象都是可变的。
char[] value;
2.是否多线程安全
String中的对象是不可变的,也就可以理解为常量,显然线程安全。
AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。
StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。看如下源码
最后,如果程序不是多线程的,那么使用StringBuilder效率高于StringBuffer。
。
==================================================================
ArrayList和Vector使用了数组的实现,
LinkedList使用了循环双向链表数据结构。 场景使用不同
对ArrayList和LinkedList而言,在列表末尾增加一个元素所花的开销都是固定的。对ArrayList而言,主要是在内部数组中增加一项,指向所添加的元素,偶尔可能会导致对数组重新进行分配;而对LinkedList而言,这个开销是统一的,分配一个内部Entry对象。
2.在ArrayList的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在LinkedList的中间插入或删除一个元素的开销是固定的。
3.LinkedList不支持高效的随机元素访问。
4.ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间
可以这样说:当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了。
==================================================================
5 讲讲类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,当new的时候,他们的执行顺序。
类的实例化顺序:先静态再父子
父类静态数据->子类静态数据->父类字段->子类字段->父类构造函数->子类构造函数
==================================================================
6 Map区别
用过哪些Map类,都有什么区别,HashMap是线程安全的吗,并发下使用的Map是什么,他们内部原理分别是什么,比如存储方式,hashcode,扩容,默认容量等。
最常用的Map实现类有:HashMap,ConcurrentHashMap(jdk1.8),LinkedHashMap,TreeMap,HashTable;
其中最频繁的是HashMap和ConcurrentHashMap,他们的主要区别是HashMap是非线程安全的。ConcurrentHashMap是线程安全的。
并发下可以使用ConcurrentHashMap和HashTable,他们的主要区别是:
1.ConcurrentHashMap的hash计算公式:(key.hascode()^ (key.hascode()>>> 16)) & 0x7FFFFFFF
HashTable的hash计算公式:key.hascode()& 0x7FFFFFFF
2.HashTable存储方式都是链表+数组,数组里面放的是当前hash的第一个数据,链表里面放的是hash冲突的数据
ConcurrentHashMap是数组+链表+红黑树
3.默认容量都是16,负载因子是0.75。就是当hashmap填充了75%的busket是就会扩容,最小的可能性是(16*0.75),一般为原内存的2倍
4 .线程安全的保证:HashTable是在每个操作方法上面加了synchronized来达到线程安全,ConcurrentHashMap线程是使用CAS(compore and swap)来保证线程安全的
==================================================================
jdk8 放弃了分段锁而是用了Node锁,减低锁的粒度,提高性能,并使用CAS操作来确保Node的一些操作的原子性,取代了锁。
但是ConcurrentHashMap的一些操作使用了synchronized锁,而不是ReentrantLock,虽然说jdk8的synchronized的性能进行了优化,但是我觉得还是使用ReentrantLock锁能更多的提高性能
==================================================================
LinkedHashMap 是基于元素进入集合的顺序或者被访问的先后顺序排序,TreeMap 则是基于元素的固有顺序 (由 Comparator 或者 Comparable 确定)。
==================================================================
1.抽象类可以有自己的实现方法,接口在jdk8以后也可以有自己的实现方法(default)
2.抽象类的抽象方法是由非抽象类的子类实现,接口的抽象方法有接口的实现类实现
3.接口不能有私有的方法跟对象,抽象类可以有自己的私有的方法跟对象
类不可以继承多个类,接口可以继承多个接口,类可以实现多个接口
==================================================================
继承:指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力,继承是类与类或者接口与接口之间最常见的关系;在Java中此类关系通过关键字extends明确标识,在设计时一般没有争议性;
聚合:聚合是关联关系的一种特例,他体现的是整体与部分、拥有的关系,即has-a的关系,此时整体与部分之间是可分离的,他们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享;比如计算机与CPU、公司与员工的关系等;表现在代码层面,和关联关系是一致的,只能从语义级别来区分;
==================================================================
BIO:同步阻塞式IO,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
NIO:同步非阻塞式IO,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
reactor模型:反应器模式(事件驱动模式):当一个主体发生改变时,所有的属体都得到通知,类似于观察者模式。
==================================================================
反射的原理:如果知道一个类的名称/或者它的一个实例对象, 就能把这个类的所有方法和变量的信息(方法名,变量名,方法,修饰符,类型,方法参数等等所有信息)找出来。
反射创建类实例的三种方式:
1.Class.forName("com.A");
2.new A().getClass();
3.A.class;
==================================================================
class.forName()除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块。
classLoader只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。
==================================================================
14. 描述动态代理的几种实现方式,分别说出相应的优缺点。
动态代理有两种实现方式,分别是:jdk动态代理和cglib动态代理
jdk动态代理的前提是目标类必须实现一个接口,代理对象跟目标类实现一个接口,从而避过虚拟机的校验。
cglib动态代理是继承并重写目标类,所以目标类和方法不能被声明成final。
==================================================================
动态代理有两种实现方式,分别是:jdk动态代理和cglib动态代理
jdk动态代理的前提是目标类必须实现一个接口,代理对象跟目标类实现一个接口,从而避过虚拟机的校验。
cglib动态代理是继承并重写目标类,所以目标类和方法不能被声明成final。
==================================================================
cglib动态代理是继承并重写目标类,所以目标类和方法不能被声明成final。而接口是可以被继承的。
==================================================================
1.final修饰的对象不能被修改;
2.final修饰的类不能被继承;
3.final修饰的方法不能被重写;
==================================================================
父类的equals不一定满足子类的equals需求。比如所有的对象都继承Object,默认使用的是Object的equals方法,在比较两个对象的时候,是看他们是否指向同一个地址。
但是我们的需求是对象的某个属性相同,就相等了,而默认的equals方法满足不了当前的需求,所以我们要重写equals方法。
如果重写了equals 方法就必须重写hashcode方法,否则就会降低map等集合的索引速度。
==================================================================
OO设计理念:封装、继承、多态
封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。所以我们可以通过public、private、protected、default 来进行访问控制
关键字 |
类内部 |
本包 |
子类 |
外部包 |
public |
√ |
√ |
√ |
√ |
protected |
√ |
√ |
√ |
× |
default |
√ |
√ |
× |
× |
private |
√ |
× |
× |
× |
java访问控制符的含义和使用情况
==================================================================
浅拷贝只拷贝指针,深拷贝就是拷贝他的值,重新生成的对像。
==================================================================
Error(错误)表示系统级的错误和程序不必处理的异常,是java运行环境中的内部错误或者硬件问题。比如:内存资源不足等。对于这种错误,程序基本无能为力,除了退出运行外别无选择,它是由Java虚拟机抛出的。
Exception(违例)表示需要捕捉或者需要程序进行处理的异常,它处理的是因为程序设计的瑕疵而引起的问题或者在外的输入等引起的一般性问题,是程序必须处理的。
Exception又分为运行时异常,受检查异常。
RuntimeException(运行时异常),表示无法让程序恢复的异常,导致的原因通常是因为执行了错误的操作,建议终止程序,因此,编译器不检查这些异常。
CheckedException(受检查异常),是表示程序可以处理的异常,也即表示程序可以修复(由程序自己接受异常并且做出处理), 所以称之为受检查异常。
==================================================================
NullPointerException
IndexOutOfBoundsException
ClassCastException
ArrayStoreException
BufferOverflowException
==================================================================
不可以,双亲委派模式会保证父类加载器先加载类,就是BootStrap(启动类)加载器加载jdk里面的java.lang.String类,而自定义的java.lang.String类永远不会被加载到
==================================================================
父类的equals不一定满足子类的equals需求。比如所有的对象都继承Object,默认使用的是Object的equals方法,在比较两个对象的时候,是看他们是否指向同一个地址。
但是我们的需求是对象的某个属性相同,就相等了,而默认的equals方法满足不了当前的需求,所以我们要重写equals方法。
如果重写了equals 方法就必须重写hashcode方法,否则就会降低map等集合的索引速度。
==================================================================
泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。==================================================================
有可能,最简单的方法,百分百实现的方式就是重写hascode();
==================================================================
序列化是一种用来处理对象流的机制 ,所谓对象流就是将对象的内容进行流化。
序列化是为了解决在对对象流进行读写操作时所引发的问题。
序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流;