JAVA SE面试题及答案整理

java面试题

一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制?
可以有多个类,但只能有一个public的类,并且public的类名必须与文件名相一致。
Java有没有goto?
只作为java中的保留字,但java版本中没有用到.
new关键词一共做三件事:
第一件事: 在堆内存中开辟地址 开空间.
第二件事: 给当前开出来的空间中的成员变量赋初始值 赋初值.
第三件事: 将当前的堆空间的地址赋值给一个局部变量 指向引用.
说说&和&&的区别。
1、&和&&都可以用作逻辑与的运算符,表示逻辑,当运算符两边的表达式的结果都为true时,整个运算结果才为true,否则,只要有一方为false,则结果为false。
2、&&还具有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式。
在JAVA中如何跳出当前的多重嵌套循环?
1.标号方式
在java中,要想跳出多重循环,可以在外面的循环语句前定义一个标号,然后在里层循环体的代码中使用带有标号的的break语句,即可跳出
2.条件控制
外层的循环条件表达式的结果可以收到里层循环体代码的控制
3.抛出异常.
switch语句能否作用在byte上,能否作用在long上,能否作用在String上?
在switch(expr1)中,expr1只能是一个整数表达式或者枚举常量(更大字体),整数表达式可以是int基本类型或Integer包装类型,由于,byte,short,char都可以隐含转换为int,所以,这些类型以及这些类型的包装类型也是可以的。显然,long和String类型都不符合switch的语法规定,并且不能被隐式转换成int类型,所以,它们不能作用于swtich语句中。
short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?
对于short s1 = 1; s1 = s1 + 1; 由于s1+1运算时会自动提升表达式的类型,所以结果是int型,再赋值给short类型s1时,编译器将报告需要强制转换类型的错误。
  对于short s1 = 1; s1 += 1;由于 += 是java语言规定的运算符,java编译器会对它进行特殊处理,因此可以正确编译。
i++和+ +i的区别?
1: i++:是先运算再自增1.
2: ++i:是先自增1再运算.
3: 如果i++和++i是独立的一条语句,两者没有区别.
char型变量中能不能存贮一个中文汉字?为什么?
java采用unicode编码,2个字节(16位)来表示一个字符, 无论是汉字还是数字,字母,或其他语言都可以存储。 2.char 在java中是2个字节,所以可以存储中文。
用最有效率的方法算出2乘以8等於几?
2 << 3,
  因为将一个数左移n位,就相当于乘以了2的n次方,那么,一个数乘以8只要将其左移3位即可,而位运算cpu直接支持的,效率最高,所以,2乘以8等於几的最效率的方法是2 << 3。
使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?
只是引用不能变,但是引用所指向的对象是可以变化的。
  使用final关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的。
"=="和equals方法究竟有什么区别?
==是比较运算符
equals是Object的方法
在Object中的equals()比较的都是地址作用相同
在有些类中作用不同就是因为这些类中重写了equals方法
作用:
1.基本类型,比较的是值是否相等.
2.引用类型,比较内存地址是否相等
3.不能比较没有父子关系的两个对象
equals()方法的作用:
1.JDK中的类一般已经重写了equals(),比较的是内容
2.自定义类如果没有重写equals(),将调用父类(默认Object类)的equals方法,Object的 equals()比较使用了this
obj
3.可以按照需求逻辑,重写对象的equals()方法(重写equals方法,一般重写hashCode方法)
静态变量和实例变量的区别?
静态变量:被static修饰的变量
实例变量:没有被static修饰的变量
相同:都是成员变量
不同:
1.修饰符不同,是否被static修饰.
2.静态变量是属于类的:不但可以被对象调用,还可以被类直接调用.
3.静态变量是所有类的对象共享一个,实例变量是每个对象都拥有属于自己的实例变量.
4.加载的时间不同,静态变量在类加载时加载,实例变量在对象创建时才加载.
是否可以从一个static方法内部发出对非static方法的调用?
不能,加载的时间不同,实例方法必须在实例化后加载.
break return continue之间的区别?
continue:用于结束本次循环,跳到循环开头继续执行下一次循环。
break:用于结束并跳出当前所在循环。
return:用于结束当前所在方法.如果方法的返回值类型不为void.返回一个值。
Overload和Override的区别?Overloaded的方法是否可以改变返回值的类型?
1. 重载方法参数列表必须不同,而重写方法参数列表必须相同。
2.重载方法发生在同一个类中,而重写方法发生在子类的继承或接口的实现类中。
3.重载方法与返回值无关,而重写方法的返回值必须是当前类类型或子类类型或接口的实现类类型。
4. 私有方法可以重载但不能重写。
重写方法可以改变返回值类型,是其子类或该接口的实现类。
Integer与int的区别
相同点:
都代表整型变量,可以通过自动装箱和自动拆箱,互相转换.
不同点:
1.类型不同.int是基本数据类型,integer是引用数据类型.
2.默认值不同.integer类型的成员变量默认值为null,int默认值为0.
3.占内存不同,int固定占用4个字节.integer因为有方法和属性所占内存要大.
Math.round(11.5)等於多少? Math.round(-11.5)等於多少?
12 和 -11
下面的代码有什么不妥之处?
1. if(username.equals(“zxx”){}
2. int x = 1;
return x==1?true:false;
1.这种情况用"zxx".equals(username),比较好,这样的话当username的值为null时,不会抛出空指针异常.
2.直接 return x==1;即可
请说出作用域public,private,protected,以及不写时的区别
public:当前类、同一包中、子孙类、其他包 都可使用
protected:当前类、同一包中、子孙类 可使用,但其他package不能访问
默认:当前类、同一包中 可使用,子孙类、其他package都不能访问
private:仅当前类中可使用.
对面向对象的理解?
面向对象是一种思想,是基于面向过程而言的,就是说面向对象是将功能等通过对象来实现,将功能封装进对象之中,让对象去实现具体的细节.
面向对象有三大特征:封装性、继承性、多态性,其中封装性指的是隐藏了对象的属性和实现细节,仅对外提供公共的访问方式,这样就隔离了具体的变化,便于使用,提高了复用性和安全性。对于继承性,就是两种事物间存在着一定的所属关系,那么继承的类就可以从被继承的类中获得一些属性和方法;这就提高了代码的复用性。继承是作为多态的前提的。多态是说父类或接口的引用指向了子类对象,这就提高了程序的扩展性,也就是说只要实现或继承了同一个接口或类,那么就可以使用父类中相应的方法,提高程序扩展性.
Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型?
Overload是重载的意思,Override是覆盖的意思,也就是重写。
重载Overload表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不同)。通过参数个数和类型的不同判断该调用哪个方法
重载的概念是:
方法名相同,参数个数,次序,类型不同.
因此是否重载对返回值没有要求,可以相同,也可以不同.
如果参数的个数,类型,次序都相同,方法名也相同,仅返回值不同,刚无法构成重载.这种情况下编译器会直接报错.

重写Override表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那个完全相同的方法给覆盖了,这也是面向对象编程的多态性的一种表现。在重写时要注意下面几点:
1、覆盖的方法的方法名必须要和被覆盖的方法的方法名完全匹配,才能达到覆盖的效果;
2、覆盖的方法的返回值必须和被覆盖的方法的返回一致或者是父类返回值类型的子类;
3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;
4、被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
构造器的特点?
构造器就是一个特殊的方法: 专门用来创建的对象。
1: 方法名和类名同名 .
2: 不需要void或者其他返回值类型.
3: 不需要显示通过return语句返回结果.
4: 不能随便调用 外部只能通过new关键词调用.
5: JVM会自动给每个类添加一个没有参数的空构造器 方便通过这个构造器能够创建对象.
6: 在构造器层面是是允许方法重载的,也就意味着可以通过参数给当前对象进行初始化动 作,让对象在创建之后就存在某些属性的值.
7: JVM会给当前类中默认防止一个空构造器,但是有个前提,就是当前这个类中没有构造器,如果类中存在任意一个构造器,JVM提供的空构造器就不存在了。 [建议:都给类中增加一个空构造器]
在Java中定义一个不做事且没有参数的构造方法的作用?
1)便于通过反射,创建运行时类的对象.
2)便于子类继承此运行时类时,默认调用super()(空参构造器)时,保证父类有此构造器
构造器Constructor是否可被override?
构造器Constructor不能被继承,因此不能重写Override,但可以被重载Overload,典型的应用就是一个类中有无参构造和有参构造.
接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)? 抽象类中是否可以有静态的main方法?
接口可以继承接口.抽象类可以实现接口,抽象类可以继承具体类.抽象类中可以有静态main方法.
抽象类与普通类的唯一区别就是不能创建实例和允许有abstract方法.
abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?
抽象类的方法可以是static的,可以是native的,也可以是同步的.
面向对象的特征有哪些方面
1.封装
把对象的状态和行为看成一个整体.通过访问控制符隐藏对象的属性和方法的实现细节,让使用者只能通过写好的访问方法,访问类中的属性.使用封装可以隐藏方法的实现细节,方便数据检查.
封装的好处:
1.调用者只能通过对外暴露的方法进行正确方便的调用 ,防止随意修改系统属性.
2.把特定的功能 封装起来,提高代码的复用性.
3.降低耦合性,只要对象暴露的接口和方法保持不变,不会影响其他调用者.


2.抽象.
抽象就是找出一些事物的相似和共性之处,然后将这些事物归为一个类,这个类只考虑这些事物的相似和共性之处.


3.继承.
假设多个类存在相同属性和方法时,我们同样可以将这些内容抽取到单独一个类中,那么这多个类没有必要重复的定义这些属性和方法,只要继承这个含有共同属性和方法的类就好了.继承可以提高代码的复用性.


多态:
多态就是同一个行为 具有多个不同表现形式的能力,多态就是同一个接口,使用不同的实例而执行不同的操作.多态的特征是向上转型.
方法重写的细节(补充)?
子类中的重写方法 父类中被重写的方法
== 方法签名完全相等
<= 返回值类型 : 基本数据类型要求完全相等 引用数据类型:重写方法的返回值类型<=被重写方法的返回值类型
>= 权限修饰符 : 重写方法的权限修饰符>=被重写方法的权限修饰符.
什么是数组?
一组相同数据类型的 有序 的 数据集合 (引用类型)
java中实现多态的机制是什么?
靠的是父类或接口定义的引用变量可以指向子类或具体实现类的实例对象,
而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,
也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。
abstract class和interface有什么区别?
1.抽象类可以有构造方法,接口中不能有构造方法.
2.抽象类中可以有普通成员变量,接口中没有普通成员变量.
3.抽象类中可以包含非抽象的普通方法,接口中所有方法必须是抽象的,不能有非抽象的普通方法.
4.抽象类中的抽象方法的访问权限可以是public,protected和默认,接口中的抽象方法只能 是public abstract类型.
abstractclass和interface语法上有什么区别?
1. 抽象类:[权限修饰符] abstract 类名{}
2. 接口:interface 接口名{}
String s = new String(“xyz”);创建了几个StringObject?是否可以继承String类?
创建了2个字符串对象,一个在堆内存中new出来的对象,一个在字符串常量池中创建的对象。
不可以继承String类,因为String类有final修饰符,而final修饰的类是不能被继承的,实现细节不允许改变。
下面这条语句一共创建了多少个对象:String s=“a”+“b”+“c”+“d” ?
1个对象"abcd"。因为如果是常量运算,编译期间会直接做字符串的拼接。
String,StringBuffer,Stringbuilder的区别是什么?效率怎么样?是否可变?否线程安全?
String不可变的字符序列.不可变就没有线程安全的问题.
StringBuffer可变字符序列,并且线程安全,但是效率低.
StringBuilder可变字符序列,线程 不安全,但是效率高 (适用于单线程的场合.)
StringBuffer是如何实现线程安全的?
StringBuffer中所有的方法都由线程锁(synchronized)修饰.
接口的概念.
1.引用数据类型
2.特殊的抽象类
3.接口为功能的集合,一般为抽象功能的集合
4.class定义类,interface定义接口
5.类只能单继承,接口多实现
6.继承与实现非常像
子类继承父类,有权直接使用父类的成员,可以不重写直接使用
实现类实现一个接口,拥有了接口中的功能,但是都为抽象功能,需要实现类自己重写,侧重点关注的重写
7.定义开发规范
8.实现解耦,降低耦合度
接口的使用.
使用:
1.接口不能实例化
2.需要通过实现类进行实现 implements
3.使用: 通过具体的实现类对象调用
具体实现类 : 重写所有的抽象方法 + 按需新增
抽象实现类 : 按需重写 + 按需新增
需要具体的子类继承,重写抽象方法
4.接口可以多实现,类只能单继承
5.一个类先继承父类,后实现接口
6.类与接口之间 : 只能类实现接口,多实现的关系
7.接口与接口之间 : 只能继承不能现, 一个接口可以多继承其他接口
内部类的分类.
成员内部类
私有内部类
静态内部类
局部内部类
匿名内部类
静态内部类
静态内部类
任意定义静态内容,其他内部类中指定定义静态的常量
在静态内部类中的静态方法,与成员方法中都需要通过外部类的对象调用外部类的成员,但是可以直接使用外部类静态的内容
在外部类中可以通过类名直接使用静态内部类中静态内容,需要通过静态内部类的对象访问内部类中的成员
通过外部类类名找到静态内部类,通过静态内部类的对象方法其成员,通过静态内部类的类名访问静态内容
局部内部类
局部内部类 只了解一下
无法被外部使用,只能在当前局部内部类所在的方法中使用,通过对象调用
局部内部类中不能定义静态内容,除了静态的常量
在局部内部类中如果使用到所在当前的局部变量(包含方法的形参),默认被final修饰,如果没有使用到,不会默认final,但是如果在jdk1.7及之前,需要手动添加final,否则无法使用
匿名内部类
匿名内部类也就是没有名字的内部类,正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写. 使用方法是把接口或抽象类中的方法直接在大括号中实现.
异常的超类是什么?
Throwable类是Java语言中所有错误和异常的超类
Error的概念.
称为错误 ,一般是由虚拟机生成并脱出的,不由程序猿控制
Exception : 异常分为哪两种?分别是什么?
RuntimeException运行时异常 : 发生在程序运行期间,一旦遇到下面代码无法执行,可以通过简单的增强程序健壮性的代码处理.
常见的运行时异常?
NullPointerException 空指针异常
ClassCastException 类型转换异常
NegativeArraySizeException 数组长度负数异常
ArrayIndexOutOfBoundsException 数组索引越界
ArithmeticException 数学异常
NumberFormatException 数字格式化异常
运行时异常的继承?编译时异常的继承?
运行时异常都会直接或者间接的继承自RuntimeException,编译时异常则继承Exception(继承链上没有RuntimeException,否则是运行时异常.).
异常的处理方案
所有的异常都可以通过异常处理方案处理
编译时异常只能通过异常处理方案
运行时异常可以通过简单增强程序健壮性的代码解决,也可以通过异常处理方案
try - catch - finally
try中的一旦遇到异常,try中的代码无法继续执行,直接判断能够被哪一个catch捕获.
从上到下判断,如果所有的catch都不能捕获,程序直接结束,这个异常没有处理.
try中如果执行没有遇到异常,就不会判断catch的捕获.
一个try后面可以跟1~n个catch.
大范围类型的catch捕获放在后面,小返回的放前面
finally中的代码无论try中是否出现异常都会在最后执行finally中的内容
一般在finally中定义一些资源关闭等代码.
简单说说Java中的异常处理机制的简单原理和应用.
原理:异常处理机制可以分为捕获异常和抛出异常。
1:捕获异常:用try{…}catch(){…}…finally{}捕获异常,try中是可能出现异常的代码;catch中是异常的捕获catch(异常类型 变量名){处理异常的代码};finally是无论是否发生异常都会执行的代码。
2:抛出异常:用throws在类或方法上抛出异常,谁调用谁处理。
应用:可以通过异常处理机制加强程序的健壮性。
单例模式的概念.
在有些系统中,为了节省内存资源、保证数据内容的一致性,对某些类要求只能创建一个实例,这就是所谓的单例模式。
单例模式分为哪两种.
懒汉式 : 在调用功能时才创建对象 ->线程不安全(可通过加锁(synchronized)的方式实现线程安全.)
饿汉式 : 在类加载完成之后就创建对象->原生的线程安全.(缺点:即使不使用这个类,也会占用内存.)
单例模式的步骤(三要素)
1.构造器私有化.
2.私有的静态的该类的引用.
3.公共的静态的访问方式.
代理模式分为哪几种?
静态代理和动态代理.
代理模式的3种角色?
1. 抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
2. 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
3:真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
静态代理的特点.
1:代理角色与真实角色实现相同的接口
2: 代理角色持有真实角色的引用
3: 被代理的行为.
工厂模式的特点.
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
工厂模式的创建过程.
1:定义一个接口作为工厂产品类的公共接口.
2:定义工厂的产品类.并实现定义的接口.
3:定义一个工厂类.类中定义一个生产方法,入参接收要创建的对应的类型.返回方法则为这一类产品抽象对象.(即定义公共接口.)
基本数据类型和对应的包装类型.
byte --> Byte
short --> Short
int --> Integer
long --> Long
float --> Float
double --> Double
char --> Character
boolean --> Bollean
有了基本数据类型为什么需要包装类?
1.包装类中定义很多成员,可以灵活的操作这些数据
2.集合中只能存储引用数据类型数据,可以基本装箱为包装类类型,进行存储
3.基本数据类型的默认值与引用数据类型默认值不同,比如账户余额属性double->0.0 Double->null.
关于基本数据类型和包装使用类型的规范(阿里巴巴标准)
1 [强制] 所有的pojo(实体类)属性必须使用包装数据类型.
2 [强制] 所有的远程调用的返回值和参数必须使用包装数据类型.
3 [推荐] 所有的局部变量使用基本数据类型.
说明: 包装类型的的初值为null,就是为了提醒使用者,要显示的进行赋值;空指针校验,或者入库校验都由使用者来保证.
如int类型: 如果调用者没有显式的赋值.默认应该为null,而不是有意义的数字0.可以更好的阻断异常参数.
基本数据类型的好处?
有利于节省内存空间,使用简单方便
基本类型与包装类对象比较问题?
1.如果是两个new Integer比较肯定不相等,因为堆内存中对象地址不同
2.如果两个int类型比较,数据值相等就相等
3.如果int类型与Integer,或者newInteger比较,只要数据值相等就相等,因为会先发生自动拆箱,然后再对基本数据类型比较
4.如果两个Integer比较,如果数据值相等并且在[-128~127]之间返回缓冲区对象相等,否则返回new Integer不相等.
想要让对象具有克隆的能力,需要做什么?
对象的类型要求实现Cloneable,才具有克隆的能力
出现java.lang.CloneNotSupportedException 的情况.
抛出此异常表示已调用类Object中的clone方法来克隆对象,但该对象的类未实现Cloneable接口。
什么是浅拷贝(浅克隆)?什么是深拷贝(深克隆)?
浅克隆:当拷贝对象的时候,对象的属性如果为引用数据类型,属性所指向的对象不拷贝.
深克隆:当拷贝对象的时候,对象的属性如果为引用数据类型,属性所指向的对象也拷贝一份.
克隆用到的场景?
当对象的属性是通过复杂的运算或者算法计算出来,在想要等到相同内容的对象时候可以使用clone克隆,提高效率.因为是克隆出来的对象是新的内存地址.
重写clone()方法时,通常都有一行代码,是什么?
重写clone()方法的时候 需要先克隆父类,所以 一般来说,通常都有的一行代码是
super.clone()
枚举
枚举 : 确定一种事物的所有可能.
枚举是类,特殊的枚举类型,具有枚举类型特殊的约束
定义枚举使用enum.
枚举类中的字段默认为当前枚举类型的实例,修饰符默认为public static final.
枚举类中可以根据需求定义成员,构造器…
枚举类中默认构造器私有化.
自定义的枚举类型默认隐式的继承自 java.lang.Enum->这是所有Java语言枚举类型的公共基类.
IO流指的是什么.
IO流指的是数据的计入写出,文件的上传下载.
流的概念.
一连串流动的数据,以先入先出的方式进行传输.
流的分类:
按操作单元分:分为字节流(万能流)和字符流.
按流向分: 是以程序为中心. 输入流和输出流.
按功能分: 分为节点流(真实能做读入写出的)和功能流(增强节点流的功能,提高节点流的性能.)
字节输入流中最上层父类?
InputStream.
什么是序列化?
将对象数据转为可存储或者可传输的状态的过程.
需要序列化的对象有什么要求?
不是所有类型的数据都能序列化, 对象序列化需要实现java.io.Serializable接口. 如果写出的对象类型没有实现序列化接口,会遇到运行时异常java.io.NotSerializableException.
static(静态的)成员不会被序列化.
如果父类实现了序列化接,子类所有的内容都可以进行序列化.
如果子类实现了序列化接口.只有序列化子类独有的内容.
什么是 serialVersionUID?
序列化是将对象的状态信息转换为可存储或传输的形式的过程。我们都知道,Java对象是保存在JVM的堆内存中的,也就是说,如果JVM堆不存在了,那么对象也就跟着消失了。
而序列化提供了一种方案,可以让你在即使JVM停机的情况下也能把对象保存下来的方案。就像我们平时用的U盘一样。把Java对象序列化成可存储或传输的形式(如二进制流),比如保存在文件中。这样,当再次需要这个对象的时候,从文件中读取出二进制流,再从二进制流中反序列化出对象。
虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致,这个所谓的序列化ID,就是我们在代码中定义的serialVersionUID。
这是因为,在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是InvalidCastException。
数组和集合
1:数组:存储多个数据,一段连续的内存空间.
数组的特点:
1.引用数据类型.
2.定长,长度一旦确定不可改变.
3.存储数据的类型相同.
4.有序,有索引.
集合的特点:
1.存储任意引用数据类型.
2.集合的长度可变 ,可能根据需求动态的增删数据.长度随之改变.
数组和集合的相同和不同.
相同:
1.都可以存储多个数据.
不同:
1.数组定长,长度一旦确定不可改变;集合可以根据需求动态增删数据.长度随之改变.
2.数组可以存储基本数据类型和引用数据类型.而集合只有存储引用数据类型.
3.定义数组时必须指定数组元素类型,集合默认其中所有元素都是Object.
4.无法直接获取数组实际存储的元素个数,length用来获取数组的长度,但可以通过size()直接获取集合实际存储的元素个数.
集合的继承关系
集合的基类是Collection.
接口List和接口Set直接或间接继承于Collection.
接口List的实现类有ArrayList,LinkedList,Vector.
接口Set的实现类有TreeSet,HashSet.
List和Set各自的特点?
Set 无序不可重复.
List 有序可重复,有索引.
ArrayList的扩容机制?
初始容量 : 默认初始容量为10 ,在第一次添加add的时候进行构建.
容量判断:每次添加的时候,会判断现有的容量,以确保有足够的容量存储这个新的对象.
扩容机制 :当没有足够的容量时,就会进行扩容,每次扩容原容量的1.5倍 ,即新建一个长度更长的数组,旧的数据用Array.copyOf方法复制到新的数组中去.现有的数组引用指向.
ArrayList和Vector的区别?
内部都是长度可变数组的实现/都是List有序列表的实现类
不同之处:
1:线程是否安全
ArrayList:线程不安全 效率高 Vector:线程安全 效率低
2:版本不同
Vector是JDK1.0 ArrayList是JDK1.2
3:扩容原则不同
当元素个数大于当前当前集合长度时:Vector容量会增加1倍 ArrayList会增加0.5
倍.
ArrayList 和 LinkedList 的区别?
都是List列表的实现类/都是线程不安全的
不同之处:
1.底层不同:
ArrayList 底层是数组,LinkedList 底层是双向链表
2.占内存不同:
LinkedList 比 ArrayList 更占内存,因为 LinkedList 的节点除了存储数据.还存储了相邻元素的两个引用
3.效率不同:
ArrayList根据索引查询遍历效率较高,增删效率低.
LinkedList查询效率低,增删效率高.
list的常用的遍历方法.
1: 普通for循环.
2: 增加for循环.
3: iterator迭代器.
Iterrator和listIterator列表迭代器
listIterator列表迭代器->List新增的迭代方式.
Iterator:
1:Iterator只能单向移动。
2:Iterator.remove()是唯一安全的方式来在迭代过程中修改集合;
3: ListIterator是一个功能更加强大的, 它继承于Iterator接口,只能用于各种List类型的访问。可以通过调用listIterator()方法产生一个指向List开始处的ListIterator, 还可以调用listIterator(n)方法创建一个一开始就指向列表索引为n的元素处的ListIterator。
1:双向移动(向前/向后遍历).
2:产生相对于迭代器在列表中指向的当前位置的前一个和后一个元素的索引.
3:可以使用set()方法替换它访问过的最后一个元素.
4:可以使用add()方法在next()方法返回的元素之前或previous()方法返回的元素之后插入一个元素.
泛型
泛型: jdk1.5
参数化类型 : 数据类型作为参数传递
只能配置引用数据类型
<>定义泛型
泛型的行为发生在编译期间,运行期间发型配置的所有内容无效,泛型擦除
要求先定义泛型,才能使用泛型
泛型类 : 类型的后面定义泛型,在使用类型的时候可以通过泛型传递具体的类型,类中可以进行使用泛型方法 泛型的优点:
1:代码简单简洁
2:增强程序健壮性,避免类型转换异常的出现
3:增强稳定性与可读性
Set集合的特点?
无序,不可重复|去重
无序: 存放的顺序与内部真实存储的顺序不一致
去重: 集合中不会出现两个相等的元素(这里的相等指的是通过equels判断相等的两个元素)和最多一个null.
Set集合的遍历方法.
1:增强for(forcach).
2:iterator迭代器.
需要明确的是:set是无索引操作的.所以普通for循环不能用来遍历set.
TreeSet的概念.
TreeSet的底层结构是红黑树.
TreeSet的查询效率较高.自动把数据做升序排序.
底层是TreeMap维护的.
新增功能:新增了一些与大小比较相关的方法.
需要注意的是TreeSet需要存储相同类型的数据,因为会默认的比较排序.
TreeSet的自定义排序?
ThreeSet能够对集合中的对象排序,当TreeSet想集合中加入一个对象时,会把它插入到有序的对象序列中。
TreeSet自带了一个排序方法,这个方法规定了一般数据的排序规则.如果Tree中存的是自定义的javaBean类型,则需要自定义排序规则.
去重与排序: 都是根据比较规则实现的,与equals没有关系.
javaBean排序的实现规则.
内部比较器|内部比较规则|自然排序 : 比较规则定义在javabean类型的内部 javabean类型实现Comparable接口,重写compareTo(T o)方法,在方法中定义比较规则外部比较器
外部比较规则|定制排序 : 比较规则定义在javabean类型的外部 定义一个实现类,实现Comparator接口,重写int compare(T o1, T o2),在方法中定义比较规则.此方法可用lambda表达式格式简化代码.
Map的特点?
map是关联键值对关系的集合.
Key(键) : 是无序的,去重的,唯一的.
Value(值): 是无序的.可重复的.
键值可是为任意引用数据类型.
一个key对应一个value. 如果对一个key进行了多次put,后面的将覆盖前面的.
遍历方式.
1: values(): 获取所有键值对的值.此方法返回的是map中所有值的值.返回的是Collection集合.然后遍历这个集合就可以取到所有的值.
2: keySet() : 获取所有键值对的key, 因为键是不可重复的,返回的是一个set集合.遍历这个set集合.通过遍历的过程中可能用遍历的key通过map.get(String key)方法获取到key对应的value.
3: entrySet(): 获取所有的键值对,第一个键值对都是一个Entry类型表示一个键值对.该方法返回Entry的Set集合.通过循环取对出对应的key和value.
HashMap的特点?
基于哈希表的Map接口的实现.允许null值和null键. 底层结构是哈希表(数组+链表+红黑树)
HashMap中的Node[]数组和扩容机制?
1 : HashMap中的节点数组Node[]要求长度为2的整数次幂.
2 :每个node中存的有计算的hash值.Object key,Object value, Node next(下一个节点的引用.)
3 :每个索引位置存储的为一个单向链表的首节点.第一个索引的位置的新值是插入到尾部.
4 : 当链表的长度>8,数组的长度>64,会把链表优化成为红黑树.
5 : 当链表的长度>8,但是数组的长度不大于64,这时候会实现扩容(数组的扩容).
6 : 初始容: 哈希表中的数组默认的初始长度为16.
7 : 加载因子: 默认为0.75.
8: 扩容阀值 : 扩容的临界值. 数组的长度 * 加载因子. 当数据的个数size>这个临界值.就会执行扩容操作.
9 : 扩容为原容量的2倍.
HashMap的哈希表存储数据的过程?(了解)
1.根据key计算哈希值 通过key的hashCode方法的返回值进一步进行hash算法的运算,得到的整数 int hash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
2.调用putVal方法实现添加数据(hash,key,value)
1)判断是否是第一次调用put方法做添加 if ((tab = table) == null || (n = tab.length) == 0) 如果是第一次添加,直接调用resize()实现扩容
2)计算位桶的索引 int index = (n - 1) & hash
3)判断哈希表结构的数组table[index]是否存在数据,
如果不存在数据,证明没有头节点,创建新节点,放入当前数组的对应索引位置作为头节点 table[index] = new Node<>(hash, key, value, next); size数据的个数+1,判断是否>扩容的阀值,如果大于需要调用resize方法进行扩容,如果不大于,不需要扩容直接返回null if (++size > threshold) resize(); return null;
如果存在数据,作为链表的头结点,遍历这个链表,拿到每一个节点的key与hash值判断是否与要添加的key和hash相同,如果相同,value覆盖 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) value覆盖之后,返回被覆盖的value V oldValue = e.value; e.value = value; return oldValue;
Hashtable 与 HashMap之间的区别:
共同点 : 都是Map接口的实现类,底层结构都是哈希表.
不同点 :
1 : 继承体系不同.
2 : 线程是否安全不同 HashMap 线程不安全,HashTavle线程安全.
3 : 扩容机制不同. HashMap 每次扩容原容量的2倍. HashTable是原容量的2倍+1.
4 : 键值对对数据null值的支持不同. hashMap 键值都可以为null;HashTable key与value都不为null.
5 : 计算hash值与位桶索引index的算法不同.
如何处理HashMap线程不安全问题?
1.使用Hashtable.
2.使用Collections工具类中static Map synchronizedMap(Map m) 返回由指定映射支持的同步(线程安全)映射。
3.juc高级并发编程包 ConcurrentHashMap-> 线程安全的哈希表.
Properties的概念.
Properties类表示一组持久的属性.Properties可以保存到流中或从流中加载。
属性列表中的每个键及其对应的值都是一个字符串。因此设置和获取参数要用setProperty和getProperty.而不要用put 和 get.
如何从配置文件中读取键值对数据?
1.定义配置文件xxx.properties.
2.定义Properties对象.
3.调用load(),与从流中加载数据.
4.根据key获取value->getProperty.
什么是函数式接口?
只有一个必须被重写的抽象方法的接口@FunctionalInterface 注解强制检测是否为函数式接口
四大内置函数式接口 ?(了解)
1:Consumer 消费型接口 void accept(T t) 对给定的参数执行此操作。(有参数无返回值)
Function 函数型接口 R apply(T t) 将此函数应用于给定的参数。(定义参数和返回值的类型.)
Supplier 供给型接口 T get() 获取结果。(无参数定义返回值.)
Predicate 段言型接口 boolean test(T t) (定义参数返回布尔值)根据给定的参数计算此谓词。
什么是方法引用?(了解)
简化lambda表达式的是lambda表达式的另外一种变现形式.
方法引用的前提?(了解)
当lambda体的实现是通过调用另外一个方法实现的,可以通过方法引用直接引用这个方法,用来简化完整的lambda表达式的结构.
方法引用的要求?(了解)
1.lambda的参数列表与返回值要求能够一一对应lambda体中所引用方法的参数列表与返回值
2.lambda的返回值要求与所引用方法的返回值保持对应一致
lambda的参数列表如果只有一个参数 : 作为调用所引用的成员方法的对象存在.
lambda的参数列表如果存在多个参数 : 第一个参数作为调用所引用的成员方法的对象存在,lambda的第二个参数开始,一一对应匹配所引用方法的参数列表.

步骤:

什么是集合的stream?(了解)
数据的渠道,用来操作由数据源(数组,集合)所产生的元素序列.
集合stream的特点?(了解)
1.Stream流本身不会存储数据.
2.Stream不会修改数据源|源对象,每次回返回持有结果的新的流Stream.
3.延迟执行|惰性加载 : 当获取终止行为时候,才会执行一系列的中间操作.
4.流都是一次性的流,不能重复使用多次,一旦使用过就已经被破坏.
集合stream 的使用步骤?(会敲,概念了解)
1.创建Stream .
2.一系列流式的中间操作(都会返回一个持有结果的新的流) .
3.终止行为
集合stream的中间操作?(会敲,概念了解)
1.过滤 Stream filter(Predicate predicate);
2.去重 distinct() 比较用到equals与hashCode()
3.截取 limit(long) 从第一个开始截取几个
4.跳过 skip(long) 跳过前n个
5.排序 sorted() --> 内部比较器 sorted(Comparator) ->外部比较器
6.映射 map(Function fun) stream操作的每一个数据都所用于参数函数,映射成一个新的结果,最后返回一个持有所有映射后的新的结果的流
集合stream的终止行为?(会敲,概念了解)
1.遍历 foreach(Consumer)
2.查找与匹配
// allMatch-检查是否匹配所有元素
// anyMatch-检查是否至少匹配一个元素
// noneMatch-检查是否没有匹配所有元素
// findFirst-返回第一个元素
// findAny-返回当前流中的任意元素
// count-返回流中元素的总个数
// max-返回流中最大值
// min-返回流中最小值
3.规约 reduce map->reduce 加工->计算结果
4.收集 collect()
多线程的优点?
提高性能,提高效率,能够更有效的利用CPU.
进程与线程之间的区别?
进程 : 系统中的程序,一个进程之间可以包含1~n个线程,系统中资源分配的最小单位,每个进程都有自己的代码与数据空间,进程之间的切换开销较大.
线程 : 程序中的顺序流,线程是cpu调度与执行的最小单位,多个线程之间共享进程的代码和数据空间,每一个线程都有自己的程序计数器运行栈,线程之间切换开销较小.
一个cpu同一时刻只能调度一个线程.
创建线程的方式?
1 : 继承Thread,重写run方法 + start开启线程
2 : 实现Runnable接口,重写run方法 + start开启线程
3 : 实现Callable接口,重写call方法 + 线程池.
实现实现Runnable接口创建线程的优点?
因为Runnable是接口,java接口多实例的机制,决定了用这种方式更为灵活.
线程的状态有哪几种?
1 : 新生状态 : 线程对象new出来后
2 : 就绪状态
3 : 运行状态 : CPU调度.
4 : 阻塞状态 :一个线程如果进入到阻塞状态,阻塞解除之后,不能直接恢复到运行,会直接恢复高就绪状态,等待cpu的调度.
5 : 终止状态 : 一个线程如果一旦进入终止状态,不可恢复.
如何让线程进入到就绪状态:
1.start()
2.阻塞解除
3.cpu的调度切换
4.yield 礼让线程.
如何让线程进入阻塞状态?
1.sleep()
2.join() 插队线程
3.wait() 等待
4.IO
何让线程进入终止状态?
1.正常执行完毕
2.stop() 过时–> 不推荐使用
3.通过标识判断
sleep的状态?
当一个线程调度sleep进入睡眠状态,让出cpu的资源抱着资源睡觉: 这个资源不是cpu的资源, 值的是对象的锁资源.
什么是yield 礼让线程?
当线程执行到yield方法,会让出cpu的资源,同时线程会恢复就绪状态?
什么是join() 插队线程?
A线程执行过程中,如果B线程插队了,A线程就会进入到阻塞状态,等待插队线程执行完毕|等待执行的时间,A线程会恢复到就绪状态
线程有哪些状态?
Thread.State 线程状态。 线程可以处于以下状态之一:
NEW : new Thread()尚未启动的线程处于此状态。
RUNNABLE : 就绪|运行,在Java虚拟机中执行的线程处于此状态。
BLOCKED : 等待对象锁的阻塞状态被阻塞等待监视器锁定的线程处于此状态。
WAITING : wait(),join()等无限期等待另一个线程执行特定操作的线程处于此状态。TIMED_WAITING : 与时间相关的等待,sleep(ms),join(ms),wait(ms)…正在等待另一个线程执行最多指定等待时间的操作的线程处于此状态。
TERMINATED : 终止已退出的线程处于此状态。
什么是线程的优先级?
是指某个线优先执行的可能性.
什么是守护线程?有什么特点?
是指守护用户线程的线程.
当所有的用户线程全都执行完毕,守护线程直接结束.
垃圾回收机制典型守护线程.
void setDaemon(boolean on) 将此线程标记为 daemon线程或用户线程。
什么是线程安全的问题?
当多个线程同时操作同一份资源,才有可能出现线程不安全问题.
什么是同步锁synchronized?
有可能出现数据不安全的代码段,让多个线程排队执行.
synchronized的用法?
修饰方法 : 将方法变成同步方法.
修饰块: synchronized(条件){ 排队执行的代码;}
同步方法?
在方法上通过synchronized关键字修饰方法 .
成员方法 锁的是调用成员方法的对象
静态方法 锁的是类的Class对象优点: 简单,直接同步整个方法体缺点: 代码范围太大,效率较低
synchronized同步块的三种情况?
锁类:锁类相当于锁住了这个类的所有对象,如果只想要锁当前类的某一个对象,建议锁那一个具体的对象this.
锁this: 成员方法中this默认指代当前调用成员方法的对象 如果锁this,就是锁一个对象,相当于锁住了这个对象的所有资源(成员),如果指向锁一个对象的某一个资源,建议可以直接锁资源.
锁资源: 锁住多线程共享的资源.资源必须是引用数据类型.

你可能感兴趣的:(面试题整理,java,面试,jvm)