1. JDK和JRE有什么区别?
JRE:JRE是Java Runtime Environment的缩写,顾名思义是java运行时环境,包含了java虚拟机,java基础类库。是使用java语言编写的程序运行所需要的软件环境,是提供给想运行java程序的用户使用的,还有所有的Java类库的class文件,都在lib目录下,并且都打包成了jar。
至于在Windows上的虚拟机是哪个文件呢?就是
JDK:Jdk是Java Development Kit的缩写,顾名思义是java开发工具包,是程序员使用java语言编写java程序所需的开发工具包,是提供给程序员使用的。JDK包含了JRE,同时还包含了编译java源码的编译器javac,还包含了很多java程序调试和分析的工具:jconsole,jvisualvm等工具软件,还包含了java程序编写所需的文档和demo例子程序。
如果你需要运行java程序,只需安装JRE就可以了。如果你需要编写java程序,需要安装JDK。
2.==和equals的区别是什么?
==:
对于基本类型和引用类型==的作用效果是不同的,如下所示:
- 基本类型:比较的是值是否相同;
- 引用类型:比较的是引用是否相同。所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。 JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地 址,但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。
String x = "string";
String y = "string";
String z = new String("string");
System.out.println(x==y); // true
System.out.println(x==z); // false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true
代码解读:程序在运行的时候会创建一个字符串缓冲池,当使用y=”string"这样的表达式创建字符串的时候,程序首先会在这个String缓冲池中寻找相同值的对象,由于x先被放到了缓冲池中,所以在y被创建的时候,程序找到了具有相同值的x,将x的引用交给了y。而z使用的new操作符,它告诉程序我需要一个新的,于是创建了一个新对象到内存中。
修改下程序:
String x = "string";
String z = new String("string");
z=z.intern();
System.out.println(x==z); //true
System.out.println(x.equals(z)); // true
java.lang.String的intern()方法"string".intern()方法的返回值还是字符串"string",表面上看起来好像这个方 法没什么用处。但实际上,它做了个小动作:检查字符串池里是否存在"string"这么一个字符串,如果存在,就返回池里的字符串;如果不存在,该方法会 把"string"添加到字符串池中,然后再返回它的引用。
equals:
equals 本质上就是 ==,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较。
总结 :== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重写了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。
3.两个对象的hashCode()相同,则equals()也一定为 true,对吗?
不对。
String str1 = "通话";
String str2 = "重地";
System.out.println(String.format("str1:%d | str2:%d", str1.hashCode(),str2.hashCode()));
System.out.println(str1.equals(str2));
执行结果:
str1:1179395 | str2:1179395
false
JDK中关于hashCode的规定:
hashCode
public int hashCode()返回该对象的哈希码值。支持此方法是为了提高哈希表(例如 Java.util.Hashtable 提供的哈希表)的性能。
hashCode 的常规协定是:
在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不 要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。
实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)
JDK规定当你调用equals方法比较两个对象相等时,他们调用hashcode方法时,都应该返回相同的整数值,也就是hashcode相等。记住,是应该相同。为什么应该?下面这段红色字体说了,必须重写hashcode方法维护协定!如果你不重写,那么就不能保证hashcode返回相同结果。
换句话说:重写equals方法时请必须重写hashcode方法,以保证equals方法相等时两个对象hashcode返回相同的值。如果没有重写hashcode方法的话,hashcode的值就不一定相等了。
4.final在java中有什么作用?
- final修饰的类叫最终类,该类不能被继承。
- final修饰的方法不能被重写。
- final修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。
final的一些重点知识:
1.final成员变量必须在声明的时候初始化或者在构造器中初始化,否则就会报编译错误。
2.不能够对final变量再次赋值。
3.在匿名类中所有变量都必须是final变量。
4.final和abstract这两个关键字是反相关的,final类就不可能是abstract的。
5.final方法在编译阶段绑定,称为静态绑定。
6.对于集合对象声明为final指定是引用不能被更改,但是你可以向其中增加,删除或者修改内容。
5.java 中的 Math.round(-1.5) 等于多少?
等于 -1,因为在数轴上取值时,中间值(0.5)向右取整,所以正 0.5 是往上取整,负 0.5 是直接舍弃。
Math类的几个常见方法:
- ceil():返回大于等于(>=)给定参数的最小整数。
- floor():返回小于等于(<=)给定参数的最大整数。
- rint():返回与参数最接近的整数。返回类型为double。
- round():6它表示四舍五入,算法为Math.floor(x+0.5),即将原来的数字加上0.5后再向下取整。
6.String 属于基础的数据类型吗?
Strng不属于基础类型,基础类型有8种:byte,boolean,char,short,int,float,long,double。String属于对象。
7.java 中操作字符串都有哪些类?它们之间有什么区别?
操作字符串的类有:String、StringBuffer、StringBuilder。
String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。
8.String str="i"与 String str=new String("i")一样吗?
不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String("i") 则会被分到堆内存中。
9.接口和抽象类有什么区别?
- 接口能够多实现,而抽象类只能单独被继承,其本质就是,一个类能继承多个接口,而只能继承一个抽象类。
- 方法上,抽象类的方法可以用abstract和public或者protect修饰。而接口默认为public abstract修饰。
- 抽象类的方法可以有需要子类实现的抽象方法,也可以有具体的方法。而接口在老版本的jdk中,只能有抽象方法,但是Java8版本的接口中,接口可以带有默认方法。
- 属性上,抽象类可以用各种各样的修饰符修饰。而接口的属性是默认的public static final。
- 抽象类中可以含有静态代码块和静态方法,而接口不能含有静态方法和静态代码块。
- 抽象类可以含有构造方法,接口不能含有构造方法。
10.面向对象的特征?
- 封装
- 抽象
- 继承
- 多态
11.int 和 Integer 有什么区别?
Integer是int的包装类,int的初值为0,Integer的初值为null。
int i = 128;
Integer i2 = 128;
Integer i3 = new Integer(128);
//Integer会自动拆箱为int,所以为true
System.out.println(i == i2);
System.out.println(i == i3);
System.out.println("**************");
Integer i5 = 127;//java在编译的时候,被翻译成-> Integer i5 = Integer.valueOf(127);
Integer i6 = 127;
System.out.println(i5 == i6);//true
/*Integer i5 = 128;
Integer i6 = 128;
System.out.println(i5 == i6);//false
*/ Integer ii5 = new Integer(127);
System.out.println(i5 == ii5); //false
Integer i7 = new Integer(128);
Integer i8 = new Integer(123);
System.out.println(i7 == i8); //false
首先,i和i2,i3比较都会输出true,这是因为Integer和int比都会自动拆箱。
i5和i6第一次比较输出的是true,而第二次输出的就是false,这是为什么呢?在java编译的时候,Integer i5=127会被翻译为Integer.valueOf(127)。以下是valueOf方法的源码:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
从源代码可以看出-128到127之间的值,会直接返回缓存中对应的值,并不会new,所以第二次比较为false。
总结:
- 无论如何,Integer和new Integer都不会相等。不会经历拆箱过程,类似i2和i3,i5和ii5的比较。
- 如果两个都是非new出来的Integer,如果数在-128到127之间,则为true,否则为false。
- int和Integer(无论是通过什么创建),都为true,因为会把Integer自动拆箱为int再去比。
12.重载和重写的区别?
重载是编译时的多态性,重写是运行时的多态性。对于重载而言,是发生在一个类中,同名的方法如果有不同的参数列表(类型,数量)则视为重载;重写发生在子类和父类之间,重写要求子类与父类被重写方法有相同的参数列表,兼容的返回类型,比父类方法更好访问,不能比父类声明更多的异常。重载对返回类型没有特殊的要求,不能根据返回类型进行区分。
13.session 与 cookie 区别?
- session是保存在服务器端,理论上是没有大小限制,只要内存够大。
- 浏览器第一次访问服务器的时候后创建一个session对象并返回一个JSESSIONID=ID的值,创建一个Cookie对象key为JISSIONID,value为ID的值是,将这个Cookie协会浏览器。
- 浏览器在第二次访问服务器的时候携带Cooike信息JSESSIONID=ID的值,如果该JESSIONID的session已经销毁,那么会重新创建一个新的session再返回一个新的JSESSIONID通过Cookie返回到浏览器。
- 针对一个web项目,一个浏览器是共享一个session,就算有两个web项目部署在同一个服务器上,针对两个项目的session是不同的。
- session是基于Cookie技术实现,重启浏览器后再次访问原有的连接依然会创建一个新的session,因为Cookie在关闭浏览器后就会消失,但是原来服务器的Session还在,只有等到了销毁的时间会自动销毁。
- 如果浏览器端禁用了Cookie,那么每次访问都会创建一个新的Session,但是我们可以通过服务器端程序重写URL即可,如果页面多连接多,会增加不必要的工作量,
那可以强制让你用户开启接收Cookie后再让其访问即可。
说说Cookie和Session的区别?
1、Cookie和Session都是会话技术,Cookie是运行在客户端,Session是运行在服务器端。
2、Cookie有大小限制以及浏览器在存cookie的个数也有限制,Session是没有大小限制和服务器的内存大小有关。
3、Cookie有安全隐患,通过拦截或本地文件找得到你的cookie后可以进行攻击。
4、Session是保存在服务器端上会存在一段时间才会消失,如果session过多会增加服务器的压力。
14.HTTP 请求的 GET 与 POST 方式的区别?
- GET在浏览器回退时是无害的,而POST会再次提交请求。
- GET产生的URL地址可以被Bookmark,而POST不可以。
- GET请求会被浏览器主动cache,而POST不会,除非手动设置。
- GET请求只能进行url编码,而POST支持多种编码方式。
- GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- GET请求在URL中传送的参数是有长度限制的,而POST么有。
- 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
- GET参数通过URL传递,POST放在Request body中。
GET和POST是什么?HTTP协议中的两种发送请求的方法。
HTTP是什么?HTTP是基于TCP/IP的关于数据如何在万维网中如何通信的协议。
HTTP的底层是TCP/IP。所以GET和POST的底层也是TCP/IP,也就是说,GET/POST都是TCP链接。GET和POST能做的事情是一样一样的。你要给GET加上request body,给POST带上url参数,技术上是完全行的通的。
GET和POST还有一个重大区别,简单的说:
GET产生一个TCP数据包;POST产生两个TCP数据包。
对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);
而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
也就是说,GET只需要汽车跑一趟就把货送到了,而POST得跑两趟,第一趟,先去和服务器打个招呼“嗨,我等下要送一批货来,你们打开门迎接我”,然后再回头把货送过去。
因为POST需要两步,时间上消耗的要多一点,看起来GET比POST更有效。因此Yahoo团队有推荐用GET替换POST来优化网站性能。但这是一个坑!跳入需谨慎。为什么?
- GET与POST都有自己的语义,不能随便混用。
- 据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。
- 并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。
原文链接
15.Anonymous Inner Class(匿名内部类)是否可以继承其他类,是否可以实现接口?
匿名内部类是没有名字的内部类,不能继承其他类,但一个内部类可以作为一个接口,由另一个内部类实现。
16.Collection和Collections的区别?
Collection是集合类的接口,继承该接口的主要有Set和List。
Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索,排序,线程安全化等操作。
17. += 和 = +的区别?
+=是复合赋值操作符,= +是简单赋值操作符。复合赋值表达式可以自动将所执行计算的结果I转型为其左侧变量的类型。如果左侧变量比右侧变量要窄,复合赋值操作符会自动进行类型转换,而简单赋值操作符需要强制类型转换。
18.jdk1.8和jdk1.7下的ConcurrentHashMap
jdk1.7
- 将数据分为一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问。
- 由Segment数组结构和HashEntry数组结构组成。
- 一个ConcurrentHashMap里包含一个Segment数组。Segment的结构和HashMap类似,是一种数组和链表结构,一个Segment包含一个HashEntry数组,每个HashEntry是一个链表结构的元素,每个Segment守护着一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先获得对应的Segment的锁。
jdk1.8
- 采用CAS和synchronized来保证并发安全
- 数据结构是:数组+链表/红黑二叉树
- synchronized只锁定当前链表或红黑二叉树的首节点。
19.Java对象的实例化顺序?
- 父类的静态成员变量和静态代码块
- 子类的静态成员变量和静态代码块
- 父类成员变量和方法块加载
- 父类构造函数加载
- 子类成员变量和方法块加载
- 子类的构造函数加载
20.不用final还可以用什么办法使得这个类不被继承?
构造函数私有化。
21.Exception与error的差别?
都继承于Throwable。
Error类一般指与虚拟机相关的问题,如系统崩溃、虚拟机错误、内存空间不足、方法调用栈溢等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和预防,遇到这样的错误,建议让程序终止。
Exception类表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。
Exception类又分为运行时异常(Runtime Exception)和受检查的异常(Checked Exception ),运行时异常;ArithmaticException,IllegalArgumentException,编译能通过,但是一运行就终止了,程序不会处理运行时异常,出现这类异常,程序会终止。而受检查的异常,要么用try。。。catch捕获,要么用throws字句声明抛出,交给它的父类处理,否则编译不会通过。
22.string的最大长度?
编译时65535,运行时Integer.MAX_VALUE。(与堆内存大小有关)
23.lambad表达式和匿名类的区别?
- 匿名类的this关键字指向匿名类,而lambda表达式的this关键字指向包围lambda表达式的类。
- Java编译器将lambda编译成类的私有方法。
24.什么是函数式接口(@FunctionInterface)?
函数式接口就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
25. static方法能不能被重写?
不能。重写是运行时多态,而static方法是在编译期绑定的,不存在多态。静态方法从程序开始运行后就已经分配了内存,所有引用到该方法的对象所指向的都是同一块内存中的数据,也就是该静态方法。子类中如果定义了相同名称的静态方法,并不会重写,而应该是在内存中又分配了一块给子类的静态方法。
26.多态
事物在运行过程中存在不同的状态。
27.为什么内部类实现的单例模式是线程安全的?
当第一次加载Singleton类时并不会初始化instance,只有在第一次调用getInstance方法时才会导致instance被初始化。
虚拟机会保证一个类的构造器
29.BIO NIO AIO
29.1 BIO
同步阻塞I/O模式,数据的读取写入阻塞在一个线程内等待完成。
Java中由一个独立的Acceptor线程负责监听客户端的连接。通过在while循环调用accept()方法等待客户端连接,请求一旦接收到一个连接请求,就通过线程池进行连接处理。
29.2 NIO
同步非阻塞I/O,通过多路复用器不断轮询各个连接的状态,当有读或写时,才会处理它。
29.3 AIO
异步非阻塞I/O,在相应的状态发生改变时,会通知对应的线程来处理。
30. 序列化
序列化就是将对象的状态(各个属性量)保存起来,以便存储在文件中或在网络上传输。
31. transient关键字的作用?
让成员变量不被初始化。