两个Integer的引用对象传给一个swap方法在方法内部交换引用,返回后,两个引用的值是否会发现变化?
不会。Java可以认为都是拷贝对应值的传值调用,基本类型、包装类型、字符串传字面量值,引用类型传地址值;特别注意就是方法形参是引用变量时传的是引用变量地址值的拷贝,方法内部对地址的更改不会影响实参地址,对地址对应变量内容的更改才会影响;
字符串的格式化方法
方法一: new MessageFormat().format();方法二:String.format();方法三:System.out.format();
时间的格式化方法
方法一:new SimpleDateFormat.parse();方法二:String.format();
定时器用什么做的
原理:Timer中维护了一个TaskQueue队列,存放TimerTask任务;Timer 定义了一个线程,用于执行轮询队列中的Task任务,并执行;
缺陷:
1. Timer底层使用一个单线程来实现多个TimerTask任务的处理,所有任务都是由同一个线程来调度,所有任务都是串行执行,意味着同一时间只能有一个任务得到执行,而前一个任务的延迟或者异常会影响到之后的任务;
2. Timer中所有的任务都是在一个线程中执行,那么如果有一个定时任务在运行时,产生未处理的异常,那么当前这个线程就会停止,那么所有的定时任务都会停止,受到影响;
替代:使用ScheduledExecutorService替代Timer,基于线程池的,可以开启多个线程进行执行多个任务,每个任务开启一个线程,这样就可以避免上述的两个致命缺陷;
类序列化时类的版本号的用途,如果没有指定一个版本号,系统是怎么处理的?如果加了字段会怎么样?
用途:JAVA 序列化的机制是通过判断类的 serialVersionUID 来验证的版本一致的。序列化操作时会把系统当前类的 serialVersionUID 写入到序列化文件中,在进行反序列化时,JVM 会把传来的字节流中的 serialVersionUID 与本地相应实体类的 serialVersionUID 进行比较。如果相同说明是一致的,可以进行反序列化,否则会出现反序列化版本一致的异常,即 InvalidCastException。
没指定时: 会根据类信息计算一个作为默认值,而且不同编译器也可能不一样;对类做了修改或者不同编译器版本会导致序列化ID不一样导致反序列化失败的不兼容;所以为了兼容先前版本需要显示定义;
什么是序列化,怎么序列化,为什么序列化,反序列化会遇到什么问题,如何解决。
概念:序列化:把对象转换为字节序列的过程称为对象的序列化。反序列化:把字节序列恢复为对象的过程称为对象的反序列化;
作用:内存中的对象保存到磁盘或数据库;Socket或RMI接口的网络传输;
实现:实现Serializable或者Externalizable接口之一,调用ObjectOutputStream.writeObject()和readObject()序列化或反序列化;
问题:
通过序列化ID校验类的一致性,不一致会抛InvalidCastException,所以需要显式的指定;
反序列化注入漏洞问题,可通过防火墙过滤和设置Java类型白名单;
静态变量和方法不参与序列化,同一对象只会序列化一次,对象更改后不会重新序列化;
字符串乱码问题,序列化和反序列化时编解码;
泛型反序列化失败的问题,JSON序列化时可指定具体类型;
Override和Overload的区别,分别用在什么场景
Override:重写,父类与子类之间多态性的一种表现,通过子类中定义某方法与其父类有相同的名称和参数而实现,是一种动态绑定的多态机制(执行的是哪个代码是根据运行时实际情况而定的);
Overload:重载,一个类中多态性的一种表现,通过参数的类型或个数不同而实现,是一种静态的绑定机制(编译时已经知道具体执行的是哪个代码段);
反射的原理,反射创建类实例的三种方式是什么
概念:Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性,并且能改变它的属性;
原理:Java类的执行首先需要编译成.class字节码文件,再由类加载器根据类的全限定名读取字节码文件二进制流并加载进内存,存储在方法区,然后将其转换为对应的class对象,class对象包含类的所有信息,反射就是利用class对象来完成的;
获取类对象的方式:类名.class;类对象.getClass;Class.forName(className);this.getClass().getClassLoader().loadClass(className);获取类对象的2种方式:class.newInstance;constructor.newInstance;
操作反射用到的类:Class:类对象,Constructor:类的构造器对象,Field:类的属性对象,Method:类的方法对象;
说说反射的用途及实现,反射是不是很慢,我们在项目中是否要避免使用反射;
用途:开发通用框架,通过配置化保证框架的通用性,如Spring的IOC、JavaBean和Jsp之间调用、JDBC的classForName()加载驱动、hibernate的findClass;
优缺点:反射提高了程序的灵活性和扩展性,降低了代码的可读性及可维护性,反射代码执行的性能低(Class.forName调用本地方法耗时,getMethod会遍历所有方法匹配,invoke方法参数变长,不确定类型,会自动装箱),反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题;反射会额外消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射;
反射中,Class.forName和ClassLoader区别
Class.forName方法,内部实际调用的方法是Class.forName(className,true,classloader),第2个boolean参数表示类是否需要初始化,Class.forName(className)默认是需要初始化,一旦初始化,就会触发目标对象的static块代码执行,static参数也也会被再次初始化;ClassLoader.loadClass(className)方法,内部实际调用的方法是ClassLoader.loadClass(className,false),第2个boolean参数,表示目标对象是否进行链接,false表示不进行链接,不进行链接意味着不进行包括初始化等一些列步骤,那么静态块和静态对象就不会得到执行;Class.forName也是通过ClassLoader实现的;
说说自定义注解的场景及实现;
注解本质是一个继承了Annotation的特殊接口,是一种元数据,用于装饰类,方法,字段,参数,变量,构造函数或包,Java自定义注解是运行时靠反射获取注解,在实现逻辑操作;使用场景如AOP、日志处理、框架、权限拦截、Junit等;
JAVA中的几种基本数据类型是什么,各自占用多少字节
char(16bit)、boolean(1bit)、byte(8bit)、short(16bit)、int(32bit)、long(64bit)、float(32bit)、double(64bit),Java不存在无符号的,取值范围和大小是固定的(不随机器变化)
String类能被继承吗,为什么。
String类的定义被final申明,不能被继承
String,Stringbuffer,StringBuilder的区别。
String:不可变所以线程安全,使用final char数组保存,每次操作都会生成新的对象,效率低,耗内存;StringBuffer和StringBuilder都继承自AbstractStringBuilder类,使用char数组保存,没有final,append字符串时会判断当前数组容量是否足够,不够时使用数组拷贝进行扩容,因此是可变的,StringBuffer的方法都有synchronized修饰,是线程安全的,StringBuilder是线程不安全的;
讲讲类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字 段,当new的时候,他们的执行顺序。
父类静态变量、父类静态代码块、子类静态变量、子类静态代码块、父类非静态变量(父类实例成员变量)、父类构造函数、子类非静态变量(子类实例成员变量)、子类构造函数
抽象类和接口的区别,类可以继承多个类么,接口可以继承多个接口么,类可以实现多个接口 么。
抽象类:作为子类的父类模板,不能实例化,可以有方法实现,子类可以不实现所有方法;接口:是一种规范,必须实现所有方法,方法默认是抽象的;一个类只能继承一个类但可以实现多个接口,一个接口可以继承多个接口
描述动态代理的几种实现方式,分别说出相应的优缺点。
JDK动态代理:基于Java反射机制实现,通过实现接口,反射生成代理类ProxyXX,只能代理接口是因为代理类本身已经extends了Proxy类,而java是不允许多重继承的,但是允许实现多个接口,主要接口:InvocationHandler、Proxy;
cglib动态代理:基于ASM机制实现,高性能高质量,继承生成子类实现,通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,比JDK耗时,主要接口:MethodInterceptor、Enhancer,无需实现接口,达到代理类无侵入
final的用途。
使用层面:修饰类,类不能继承;修饰方法,方法不能覆写;修饰变量,基础类型值不能改,引用类型地址不能改但内容可以修改;成员变量在定义或者构造函数中初始化,局部变量定义时初始化;
JVM层面:另外被final修饰的方法,JVM会尝试为之寻求内联,有助于提升效率,被final修饰的常量,在编译阶段会存入调用类的常量池中;重排序:final域对象的读不能重排序;final域的写不能重排序到构造函数之外;
如何在父类中为子类自动完成所有的hashcode和equals实现?这么做有何优劣。
父类的equals不一定满足子类的equals需求。比如所有的对象都继承Object,默认使用的是Object的equals方法,在比较两个对象的时候,是看他们是否指向同一个地址。但是我们的需求是对象的某个属性相同,就相等了,而默认的equals方法满足不了当前的需求,所以我们要重写equals方法。如果重写了equals方法就必须重写hashcode方法,否则就会降低map等集合的索引速度。
这样的a.hashcode() 有什么用,与a.equals(b)有什么关系。
hashcode方法提供了对象的hashCode值,用一个数字来标识对象,比如在HashMap集合中,如果用对象本身作为Key,就要需要hashcode来实现查找和对比;hashcode只是标识对象,在hash算法中可以将对象相对离散开,这样就可以在查找数据的时候根据这个key快速缩小数据的范围,但hashcode不一定是唯一的;
equals与hashcode的关系:两个对象equals,Java运行时环境会认为他们的hashcode一定相等;两个对象不equals,他们的hashcode有可能相等;两个对象hashcode相等,他们不一定equals;两个对象hashcode不相等,他们一定不equals;判断两个对象相等可以先比较hashcode来提升效率;
说一说你对java.lang.Object对象中hashCode和equals方法的理解。在什么场景下需 要重新实现这两个方法。
Object类中equals方法默认判断对象地址是否相等,hashcode方法是native方法;当父类默认的equals和hashcode方法不满足使用场景时,子类就需要一起重写
请结合OO设计理念,谈谈访问修饰符public、private、protected、default在应用设计中的作用。
OO设计理念:封装、继承、多态,封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏,所以我们可以通过public、private、protected、default来进行访问控制;protected外部包不可用,default外部包和子类不可用,private尽在内内部使用;
深拷贝和浅拷贝区别。
浅拷贝会拷贝基础类型的值和引用类型的地址;深拷贝会拷贝基础类型的值和引用类型各个属性的值,重新生成对像
error和exception的区别,CheckedException,RuntimeException的区别。请列出5个运行时异常。
Throwable包括Error(虚拟机错误,无法处理)、Exception(程序错误,可处理);Exception包括RuntimeException(运行时异常,未受检异常,程序设计问题,尽量不捕获而是从设计上解决)、checked exception(受检异常,必须捕获,不然不能编译);运行时异常包括:NullPointerException、IndexOutOfBoundsException、ClassCastException、ArrayStoreException、BufferOverflowException
在自己的代码中,如果创建一个java.lang.String类,这个类是否可以被类加载器加载?为什么。
不可以,双亲委派模式会保证父类加载器先加载类,就是BootStrap(启动类)加载器加载jdk里面的java.lang.String类,而自定义的java.lang.String类永远不会被加载到
泛型通配符?在什么情况下使用?
泛型即参数化类型,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(类型形参),然后在使用时传入具体的类型(类型实参);通配符类型: extends Parent> 指定上界,只能是Parent及子类; super Child> 指定下界,只能是Child及父类;> 指定无界;泛型在编译期用,运行期不可见,会被擦除为它的上级类型,如果没有限定则会被替换为Object;泛型类的原生类型与所传递的泛型无关,无论传递什么类型,原生类是一样的;一般用来定义通用的实现类或方法;
IO会阻塞吗?readLine是不是阻塞的?
传统IO是阻塞式的,readLine是阻塞模式,也就是说如果readLine读取不到数据的话,会一直阻塞,而不是返回null;网络中读取时遇到回车换行符时标识当前行结束,在数据流发生异常或者另一端被close()掉时,才会返回null值;文件读取时只有读到文件末尾才会返回null
IO模型有哪些,讲讲你理解的nio ,他和bio,aio的区别是啥,谈谈reactor模型。
JAVA BIO:同步并阻塞,面向流,一个连接一个线程,线程阻塞等待数据就绪,适用于连接数目比较小且固定的架构;
JAVA NIO:同步非阻塞,面向缓冲,采用Reactor模式实现的多路复用IO实现,一个selector线程轮训所有channel的事件,事件到达时则启动新线程处理,否则阻塞轮训,同步是因为它的accept/read/write方法的内核I/O操作都会阻塞当前线程,适用于连接数目多且连接比较短(轻操作)的架构;
JAVA AIO(NIO2):异步非阻塞,JDK1.7对NIO的增强,增加了几个异步处理的Channel,read/write是异步执行,调用则返回,需要注册回调函数,数据就绪写入缓冲区后由操作系统调用回调函数实现,适用于连接数目多且连接比较长(重操作)的架构;
Reactor线程模型:所有线程都是NIO线程,单线程模型:1个Reactor线程(完成所有IO操作包括接收acceptor、分发reactor和处理handler);多线程模型:1个Reactor线程(负责接收Acceptor和派发)+多个Handler线程(线程池,负责处理);主从模型:1个主Reactor线程(负责接收,只负责接入认证、握手等,然后重新注册到从Reactor)+1个从Reactor线程(负责接收Acceptor和派发)+多个Handler线程(线程池,负责处理);
Java8的新特性
接口默认方法、Lamda表达式、函数式接口(Predicate、Function、Supplier、Consumer)、::关键字来传递方法或者构造函数引用、Optional、Stream流操作、日期API(LocalDateTime等);
Java9比Java8改进了什么
JShell(命令行写代码)、接口支持私有方法、try关闭资源方式优化、String底层结构由char[]变为byte[]、Stream API增强、引入了HttpClient可直接使用、支持HTTP/2.0、新模块系统