Java基础题

一、JAVA中的几种基本数据类型是什么,各自占用多少字节。

二、String类能被继承吗,为何

不能。在Java中,只要是被定义为final的类,也能够说是被final修饰的类,就是不能被继承的。html

三、String,Stringbuffer,StringBuilder的区别。

四、ArrayList和LinkedList有什么区别。

简单的区别:java

1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。(LinkedList是双向链表,有next也有previous) 2.对于随机访问get和set,ArrayList以为优于LinkedList,由于LinkedList要移动指针。react

3.对于新增和删除操做add和remove,LinedList比较占优点,由于ArrayList要移动数据。程序员

深度的区别:spring

1.对ArrayList和LinkedList而言,在列表末尾增长一个元素所花的开销都是固定的。对ArrayList而言,主要是在内部数组中增长一项,指向所添加的元素,偶尔可能会致使对数组从新进行分配;而对LinkedList而言,这个开销是统一的,分配一个内部Entry对象。数据库

2.在ArrayList的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在LinkedList的中间插入或删除一个元素的开销是固定的。api

3.LinkedList不支持高效的随机元素访问。数组

4.ArrayList的空间浪费主要体如今在list列表的结尾预留必定的容量空间,而LinkedList的空间花费则体如今它的每个元素都须要消耗至关的空间安全

五、讲讲类的实例化顺序。

问题:好比父类静态数据,构造函数,字段,子类静态数据,构造函数,字 段,当new的时候,他们的执行顺序。性能优化

答案:类加载器实例化时进行的操做步骤(加载–>链接->初始化)。

父类静态变量、 父类静态代码块、 子类静态变量、 子类静态代码块、 父类非静态变量(父类实例成员变量)、 父类构造函数、 子类非静态变量(子类实例成员变量)、 子类构造函数。

六、用过哪些Map类,都有什么区别。

问题:好比HashMap是线程安全的吗,并发下使用的Map是什么,他们 内部原理分别是什么,好比存储方式,hashcode,扩容,默认容量等。

答案:不安全,并发下使用ConcurrentHashMap。

七、JAVA8的ConcurrentHashMap为何放弃了分段锁?

缘由:经过 JDK 的源码和官方文档看来, 他们认为的弃用分段锁的缘由由如下几点:

一、加入多个分段锁浪费内存空间。

二、生产环境中, map 在放入时竞争同一个锁的几率很是小,分段锁反而会形成更新等操做的长时间等待。

三、为了提升 GC 的效率

既然弃用了分段锁, 那么必定由新的线程安全方案, 咱们来看看源码是怎么解决线程安全的呢?CAS

首先经过 hash 找到对应链表事后, 查看是不是第一个object, 若是是, 直接用cas原则插入,无需加锁,而后若是不是链表第一个object, 则直接用链表第一个object加锁,这里加的锁是synchronized,虽然效率不如 ReentrantLock, 但节约了空间,这里会一直用第一个object为锁, 直到从新计算map大小, 好比扩容或者操做了第一个object为止。

八、ConcurrentHashMap(JDK1.8)为何要使用synchronized而不是如ReentranLock这样的可重入锁?

能够从下面几个方面讲述:

锁的粒度首先锁的粒度并无变粗,甚至变得更细了。每当扩容一次,ConcurrentHashMap的并发度就扩大一倍。Hash冲突 JDK1.7中,ConcurrentHashMap从过二次hash的方式(Segment -> HashEntry)可以快速的找到查找的元素。

在1.8中经过链表加红黑树的形式弥补了put、get时的性能差距。

扩容

JDK1.8中,在ConcurrentHashmap进行扩容时,其余线程能够经过检测数组中的节点决定是否对这条链表(红黑树)进行扩容,减少了扩容的粒度,提升了扩容的效率。

为何是synchronized,而不是可重入锁

减小内存开销 假设使用可重入锁来得到同步支持,那么每一个节点都须要经过继承AQS来得到同步支持。但并非每一个节点都须要得到同步支持的,只有链表的头节点(红黑树的根节点)须要同步,这无疑带来了巨大内存浪费。

得到JVM的支持 可重入锁毕竟是API这个级别的,后续的性能优化空间很小。synchronized则是JVM直接支持的,JVM可以在运行时做出相应的优化措施:锁粗化、锁消除、锁自旋等等。这就使得synchronized可以随着JDK版本的升级而不改动代码的前提下得到性能上的提高。

九、有没有有顺序的Map实现类,若是有,他们是怎么保证有序的。

Hashmap和Hashtable 都不是有序的。TreeMap和LinkedHashmap都是有序的。(TreeMap默认是key升序,LinkedHashmap默认是数据插入顺序) TreeMap是基于比较器Comparator来实现有序的。LinkedHashmap是基于链表来实现数据插入有序的。

https://www.iteye.com/blog/uule-1522291

十、抽象类和接口的区别,类能够继承多个类么,接口能够继承多个接口么,类能够实现多个接口么。

区别:

一、抽象类和接口都不能直接实例化,若是要实例化,抽象类变量必须指向实现全部抽象方法的子类对象,接口变量必须指向实现全部接口方法的类对象。

二、抽象类要被子类继承,接口要被类实现。

三、接口只能作方法申明,抽象类中能够作方法申明,也能够作方法实现 四、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。五、抽象类里的抽象方法必须所有被子类所实现,若是子类不能所有实现父类抽象方法,那么该子类只能是抽象类。一样,一个实现接口的时候,如不能所有实现接口方法,那么该类也只能为抽象类。

六、抽象方法只能申明,不能实现。abstract void abc();不能写成abstract void abc(){}。

七、抽象类里能够没有抽象方法 八、若是一个类里有抽象方法,那么这个类只能是抽象类 九、抽象方法要被实现,因此不能是静态的,也不能是私有的。

十、接口可继承接口,并可多继承接口,但类只能单根继承。

类不能继承多个类 接口能够继承多个接口 类能够实现多个接口

十一、继承和聚合的区别在哪。

继承

指的是一个类继承另外的一个类的功能,并能够增长它本身的新功能的能力,继承是类与类或者接口与接口之间最多见的关系;在Java中此类关系经过关键字extends明确标识。

聚合

聚合体现的是总体与部分、拥有的关系,此时总体与部分之间是可分离的,他们能够具备各自的生命周期;好比计算机与CPU、公司与员工的关系等;

十二、IO模型有哪些,讲讲你理解的nio ,他和bio,aio的区别是啥,谈谈reactor模型。

各IO的区别:

reactor是什么?

  1. 事件驱动

  2. 能够处理一个或多个输入源

  3. 经过Service Handle同步的将输入事件采用多路复用分发给相应的Request Handler(一个或多个)处理

1三、反射的原理,反射建立类实例的三种方式是什么。

  
    
  
  
  
   
   
            
   
   


//建立Class对象的方式一:(对象.getClass()),获取类中的字节码文件Class class1 = p1.getClass();//建立Class对象的方式二:(类.class:须要输入一个明确的类,任意一个类型都有一个静态的class属性)Class class3 = Person.class;//建立Class对象的方式三:(forName():传入时只须要以字符串的方式传入便可)//经过Class类的一个forName(String className)静态方法返回一个Class对象,className必须是全路径名称;//Class.forName()有异常:ClassNotFoundExceptionClass class4 = Class.forName("cn.xbmchina.Person");

https://blog.csdn.net/LianXu3344/article/details/82906201

1四、反射中,Class.forName和ClassLoader区别 。

Class.forName(className)方法,内部实际调用的方法是 Class.forName(className,true,classloader); 第2个boolean参数表示类是否须要初始化, Class.forName(className)默认是须要初始化。一旦初始化,就会触发目标对象的 static块代码执行,static参数也也会被再次初始化。ClassLoader.loadClass(className)方法,内部实际调用的方法是 ClassLoader.loadClass(className,false); 第2个 boolean参数,表示目标对象是否进行连接,false表示不进行连接,由上面介绍能够, 不进行连接意味着不进行包括初始化等一些列步骤,那么静态块和静态对象就不会获得执行

https://www.cnblogs.com/zabulon/p/5826610.html

1五、描述动态代理的几种实现方式,分别说出相应的优缺点。

原理区别:

java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,经过修改其字节码生成子类来处理。

一、若是目标对象实现了接口,默认状况下会采用JDK的动态代理实现AOP  二、若是目标对象实现了接口,能够强制使用CGLIB实现AOP 

三、若是目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

如何强制使用CGLIB实现AOP? 

(1)添加CGLIB库,SPRING_HOME/cglib/*.jar  (2)在spring配置文件中加入

JDK动态代理和CGLIB字节码生成的区别? 

(1)JDK动态代理只能对实现了接口的类生成代理,而不能针对类 (2)CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法    由于是继承,因此该类或方法最好不要声明成final

https://blog.csdn.net/qq_23000805/article/details/89573804

1六、final的用途。

一、被final修饰的类不能够被继承 二、被final修饰的方法不能够被重写 三、被final修饰的变量不能够被改变(切记不可变的是变量的引用而非引用指向对象的内容。) 四、被final修饰的方法,JVM会尝试为之寻求内联,这对于提高Java的效率是很是重要的。所以,假如能肯定方法不会被继承,那么尽可能将方法定义为final的,具体参见运行期优化技术的方法内联部分 五、被final修饰的常量,在编译阶段会存入调用类的常量池中,具体参见类加载机制最后部分和Java内存区域

https://www.cnblogs.com/swisszhang/p/9892309.html

1七、写出三种单例模式实现 。

1 饿汉式

  
    
  
  
  
   
   
            
   
   





public class EagerSingleton {static { System.out.println("EagerSingleton 被加载");}//私有化构造方法,限制直接构造,只能调用 getInstance() 方法获取单例对象private EagerSingleton(){} private static final EagerSingleton eagerSingleton=new EagerSingleton(); // 私有化静态 final成员,类加载直接生成单例对象,比较占用内存public static EagerSingleton getInstance(){ //提供对外的公共api获取单例对象 return eagerSingleton;}}

总结:饿汉式单例的特色:饿汉式在类建立的同时就实例化一个静态对象出来,无论以后会不会使用这个单例,都会占据必定的内存,可是相应的,在第一次调用时速度也会更快,由于其资源已经初始化完成。

2 懒汉式

  
    
  
  
  
   
   
            
   
   


public class LazySingleton {static { System.out.println("LazySingleton 被加载");}private LazySingleton(){} //私有化构造方法,限制直接构造,只能调用 getInstance() 方法获取单例对象private static LazySingleton lazySingleton=null;//静态域初始化为null,为的是须要时再建立,避免像饿汉式那样占用内存public static LazySingleton getInstance(){//提供对外的公共api获取单例对象 if(lazySingleton==null){ synchronized (LazySingleton.class){ //在getInstance中作了两次null检查,确保了只有第一次调用单例的时候才会作同步,这样也是线程安全的,同时避免了每次都同步的性能损耗 if(lazySingleton==null){ lazySingleton = new LazySingleton(); } } } return lazySingleton; }}

总结:有同步锁的性能消耗

3 静态内部类实现

  
    
  
  
  
   
   
            
   
   






public class IoDHSingleton {static {System.out.println("IoDHSingleton 被加载");}private IoDHSingleton(){} //私有化构造方法,限制直接构造,只能调用 getInstance() 方法获取单例对象public static IoDHSingleton getInstance(){//提供对外的公共api获取单例对象//当getInstance方法第一次被调用的时候,它第一次读取HolderClass.ioDHSingleton,内部类HolderClass类获得初始化;//而这个类在装载并被初始化的时候,会初始化它的静态域,从而创ioDHSingleton 的实例,因为是静态的域,所以只会在虚拟机装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。 return HolderClass.ioDHSingleton; } private static class HolderClass{ static { System.out.println("HolderClass 被加载"); } private static IoDHSingleton ioDHSingleton = new IoDHSingleton(); } // 防止反序列化获取多个对象的漏洞 private Object readResolve() throws ObjectStreamException { return HolderClass.ioDHSingleton; } }

这个模式的优点在于,getInstance方法并无被同步,而且只是执行一个域的访问,所以延迟初始化并无增长任何访问成本。

考虑反射:  

因为在调用 SingletonHolder.instance 的时候,才会对单例进行初始化,并且经过反射,是不能从外部类获取内部类的属性的。因此这种形式,很好的避免了反射入侵。

考虑多线程:  

因为静态内部类的特性,只有在其被第一次引用的时候才会被加载,因此能够保证其线程安全性。

总结:  

优点:兼顾了懒汉模式的内存优化(使用时才初始化)以及饿汉模式的安全性(不会被反射入侵)。  

劣势:须要两个类去作到这一点,虽然不会建立静态内部类的对象,可是其 Class 对象仍是会被建立,并且是属于永久带的对象。

https://www.cnblogs.com/ngy0217/p/9006716.html

1八、如何在父类中为子类自动完成全部的hashcode和equals实现?这么作有何优劣。

https://www.iteye.com/blog/java-min-1416727

1九、请结合OO设计理念,谈谈访问修饰符public、private、protected、default在应用设计中的做用。

访问修饰符,主要标示修饰块的做用域,方便隔离防御。

public:Java语言中访问限制最宽的修饰符,通常称之为“公共的”。被其修饰的类、属性以及方法不只能够跨类访问,并且容许跨包(package)访问。

private: Java语言中对访问权限限制的最窄的修饰符,通常称之为“私有的”。被其修饰的类、属性以及方法只能被该类的对象访问,其子类不能访问,更不能容许跨包访问

protect: 介于public 和 private 之间的一种访问修饰符,通常称之为“保护形”。被其修饰的类、属性以及方法只能被类自己的方法及子类访问,即便子类在不一样的包中也能够访问。

default:即不加任何访问修饰符,一般称为“默认访问模式“。该模式下,只容许在同一个包中进行访问。

20、深拷贝和浅拷贝区别。

浅拷贝(Shallow Copy):

①对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。由于是两份不一样的数据,因此对其中一个对象的该成员变量值进行修改,不会影响另外一个对象拷贝获得的数据。

②对于数据类型是引用数据类型的成员变量,好比说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。由于实际上两个对象的该成员变量都指向同一个实例。在这种状况下,在一个对象中修改该成员变量会影响到另外一个对象的该成员变量值。

深拷贝:

首先介绍对象图的概念。设想一下,一个类有一个对象,其成员变量中又有一个对象,该对象指向另外一个对象,另外一个对象又指向另外一个对象,直到一个肯定的实例。这就造成了对象图。那么,对于深拷贝来讲,不只要复制对象的全部基本数据类型的成员变量值,还要为全部引用数据类型的成员变量申请存储空间,并复制每一个引用数据类型成员变量所引用的对象,直到该对象可达的全部对象。也就是说,对象进行深拷贝要对整个对象图进行拷贝!

简单地说,深拷贝对引用数据类型的成员变量的对象图中全部的对象都开辟了内存空间;而浅拷贝只是传递地址指向,新的对象并无对引用数据类型建立内存空间。

https://www.cnblogs.com/shakinghead/p/7651502.html

2一、数组和链表数据结构描述,各自的时间复杂度。

数组和链表的区别:

一、从逻辑结构角度来看:数组必须事先定义固定的长度(元素个数),不能适应数据动态地增减的状况。当数据增长时,可能超出原先定义的元素个数;当数据减小时,形成内存浪费。链表动态地进行存储分配,能够适应数据动态地增减的状况,且能够方便地插入、删除数据项。(数组中插入、删除数据项时,须要移动其它数据项) 二、数组元素在栈区,链表元素在堆区;

三、从内存存储角度来看:(静态)数组从栈中分配空间, 对于程序员方便快速,但自由度小。链表从堆中分配空间, 自由度大但申请管理比较麻烦。数组利用下标定位,时间复杂度为O(1),链表定位元素时间复杂度O(n);数组插入或删除元素的时间复杂度O(n),链表的时间复杂度O(1)。

2二、error和exception的区别,CheckedException,RuntimeException的区别。

2三、在本身的代码中,若是建立一个java.lang.String类,这个类是否能够被类加载器加载?为何。

加载过程当中会先检查类是否被已加载,检查顺序是自底向上,从Custom ClassLoader到BootStrap ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只全部ClassLoader加载一次。

而加载的顺序是自顶向下,也就是说当发现这个类没有的时候会先去让本身的父类去加载,父类没有再让儿子去加载,那么在这个例子中咱们本身写的String应该是被Bootstrap ClassLoader加载了,因此App ClassLoader就不会再去加载咱们写的String类了,致使咱们写的String类是没有被加载的。

https://blog.csdn.net/u013206465/article/details/47170253

2四、说一说你对java.lang.Object对象中hashCode和equals方法的理解。在什么场景下须要从新实现这两个方法。

对于equals()与hashcode(),比较通用的规则:

①两个obj,若是equals()相等,hashCode()必定相等 ②两个obj,若是hashCode()相等,equals()不必定相等

2五、在jdk1.5中,引入了泛型,泛型的存在是用来解决什么问题。

面向对象的转型只会发生在具备继承关系的父子类中(接口也是继承的一种) 向上转型:其核心目的在于参数的统一上,根本不须要强制类型转换。

向下转型:是为了操做子类定义的特殊功能,须要强制类型转换,但是如今存在的问题是:向下转型实际上是一种很是不安全的操做,觉得编译的时候,程序不会报错,而在运行的时候会报错,这就是传说中的—迷之报错。

不过呢,在JDK1.5以后,新增长了泛型的技术,这就将上述向下转型的问题消灭在了萌芽之中。

泛型的核心意义在于:类在进行定义的时候可使用一个标记,此标记就表示类中属性或者方法以及参数的类型,标记在使用的时候,才会去动态的设置类型。

2六、Java中的HashSet内部是如何工做的。

HashSet 的内部采用 HashMap来实现。因为 Map 须要 key 和 value,因此HashSet中全部 key 的都有一个默认 value。

相似于HashMap,HashSet 不容许重复的 key,只容许有一个null key,意思就是 HashSet 中只容许存储一个 null 对象。

https://blog.csdn.net/qq_32575047/article/details/78901492

2七、什么是序列化,怎么序列化,为何序列化,反序列化会遇到什么问题,如何解决。

什么是序列化?

序列化:把对象转换为字节序列的过程称为对象的序列化。反序列化:把字节序列恢复为对象的过程称为对象的反序列化

什么状况下须要序列化?

当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;当你想用套接字在网络上传送对象的时候;当你想经过RMI传输对象的时候;

如何实现序列化?

实现Serializable接口便可

注意事项:

transient 修饰的属性,是不会被序列化的 静态static的属性,他不序列化。

实现这个Serializable 接口的时候,必定要给这个 serialVersionUID 赋值

关于 serialVersionUID 的描述:

序列化运行时使用一个称为 serialVersionUID 的版本号与每一个可序列化类相关联,该序列号在反序列化过程当中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。若是接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不一样,则反序列化将会致使 InvalidClassException。可序列化类能够经过声明名为 “serialVersionUID” 的字段(该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其本身的 serialVersionUID

https://blog.csdn.net/riemann_/article/details/87835260

2八、java8的新特性。

https://www.cnblogs.com/frankdeng/p/9019887.html


本文分享自微信公众号 - 爱编码(ilovecode)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索