第一部分
1.为什么重写equals还要重写hashcode?
- 解:首先equals和hashcode的关系如下:1.如果两个对象equals返回true,那么它们的hashcode一定相同。2.如果两个对象的hashcode相同,它们并不一定相同。
- 为了提高程序效率,先进行hashcode的比较。如果hashcode不同,则没必要进行equals的比较了。
- 最后如果只重写了equals,没有重写hashcode。可能会出现两个没有关系的对象equals相同的,但是hashcode不同的情况。
hashcode方法是根据对象地址经过哈希算法得来的。
2. map的分类和常见情况?
- java为数据结构中的映射定义了一个接口java.util.Map;它有四个实现类,分别是HashMap Hashtable LinkedHashMap 和TreeMap.
- Map主要用于存储健值对,根据键得到值,因此不允许键重复(重复了覆盖了),但允许值重复。
- Hashmap 是一个最常用的Map,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的。 HashMap最多只允许一条记录的键为Null;允许多条记录的值为Null;HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致。如果需要同步,可以用Collections的synchronizedMap方法使HashMap具有同步的能力,或者使用ConcurrentHashMap。
- Hashtable与HashMap类似,它继承自Dictionary类,不同的是:它不允许记录的键或者值为空;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了 Hashtable在写入时会比较慢。
- LinkedHashMap是HashMap的一个子类,保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。
- TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排过序的。
- 一般情况下,我们用的最多的是HashMap,在Map 中插入、删除和定位元素,HashMap是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现,它还可以按读取顺序来排列.
3.Object若不重写hashCode()的话,hashCode()如何计算出来的?
- Object 的 hashcode 方法是本地方法,也就是用 c 语言或 c++实现的,该方法直接返回对象的内存地址。
4.==比较的是什么?
- 当使用关系运算符“==”比较两个对象时,是比较两个对象使用的内存地址和内容是否相同,如果两个对象使用的是同一个内存地址,并且内容相同,则结果为true,否则结果为false。
- 当使用equals()方法比较两个对象时,则是比较两个对象的内容是否相同,而与对象的内存地址无关,如果两个对象的内容相同,则结果为true,否则结果为false。
- 当“==”比较的是基本类型的时候,比较的是值是狗相同。
5.若对一个类不重写,它的equals()方法是如何比较的?
- 那么equals与”==“一样,比较的是比较的是引用类型的变量所指向的对象的地址。
- java8的新特性?
- Lambda表达之。lambda允许把函数作为一个方法的参数,或者把代码看成数据。一个labbda表达式由逗号分隔的参数列表、->符号与函数体三部分表示。
Arrays.asList( "p", "k", "u","f", "o", "r","k").forEach( e -> System.out.println( e ) );
- 引入了函数式接口的概念。函数式接口就是只有一个方法的普通接口。java.lang.Runnable与java.util.concurrent.Callable是函数式接口最典型的例子。为此,Java8增加了一种特殊的注解@FunctionalInterface
@FunctionalInterface
public interface Functional {
void method();
}
- 接口的默认方法与静态方法:我们可以在接口中定义默认方法,使用default关键字,并提供默认的实现。所有实现这个接口的类都会接受默认方法的实现,除非子类提供的自己的实现。例如:
public interface DefaultFunctionInterface {
default String defaultFunction() {
return "default function";
}
}
- stream:Stream理解为MapReduce,当然Google的MapReduce的灵感也是来自函数式编程。她其实是一连串支持连续、并行聚集操作的元素。
7.一个十进制的数在内存中是怎么存的?
- 二进制补码
8.为什么会出现4.0-3.6=0.40000001这种现象?
- 2进制的小数无法精确的表达10进制小数,计算机在计算10进制小数的过程中要先转换为2进制进行计算,这个过程中出现了误差。如果在数值计算中不允许有任何舍入误差 ,就应该使用BigDecimal类。
9.Java支持的数据类型有哪些?什么是自动拆装箱?
- 基本数据类型:
整数值型:byte,short,int,long,
字符型:char
浮点类型:float,double
布尔型:boolean
整数默认int型,小数默认是double型。Float和long类型的必须加后缀。 - 自动装箱和拆箱就是基本类型和引用类型之间的转换,至于为什么要转换,因为基本类型转换为引用类型后,就可以new对象,从而调用包装类中封装好的方法进行基本类型之间的转换或者toString
10.Array和ArrayList的区别?
- 存储内容不同:Array可以包含基本类型和对象类型。ArrarList只能包含对象类型。
- 空间大小比较:Array数组空间的大小是固定的,事前确定合适的空间大小。ArrayList的空间是动态增长的,每次添加新元素都会检查内部数组是否足够。
- ArrayList方法比Array更加多样化。比如返回贴带起,添加全部、删除全部。
11.简述正则表达式及用途?
- 编写处理字符串操作时,会有查找符合某些复杂规则的字符串的需要。正则表达式就是描述这些规则的工具。也就是记录文本规则的代码。
12.java中是如何支持正则表达式的。
- java中的string类提供了正则表达式操作的方法,包括:matches、replaceAll、split。此外java中可以用pattern类表示正则表达式对象。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class RegExpTest {
public static void main(String[] args) {
String str = "成都市(成华区)(武侯区)(高新区)";
Pattern p = Pattern.compile(".*?(?=\\()");
Matcher m = p.matcher(str);
if(m.find()) {
System.out.println(m.group());
}
}
}
13.String,StringBuilder和StringBuffer三者的区别?
- 运行速度方面StringBuilder>StringBuffer>String.
- String为字符串常量,而StringBuilde和StringBuffer均为字符串变量,即String对象一旦创建之后不能更改,后者的对象时变量是可以更改的。
- StringBuilder是线程安全的,很多方法是带有synchronized关键紫的。StringBuilder则没有这个关键字。
- String:适用于少量的字符串操作的情况 StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况 StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
StringBuilder和StringBuffer都集成了AbstractStringBuilder,所以大部分操作上实现都是相同的的。只不过buffer用了同步块。
14.&和&&的区别
- &和&&都可以用作逻辑与的运算符,表示逻辑与(and),当运算符两边的表达式的结果都为true时,整个运算结果才为true,否则,只要有一方为false,则结果为false。
- &&还具有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式。
- &还可以用作位运算符,当&操作符两边的表达式不是boolean类型时,&表示按位与操作,我们通常使用0x0f来与一个整数进行&运算,来获取该整数的最低4个bit位。
15.Java和JavaSciprt的区别
- 基于对象和面向对象:Java是一种真正的面向对象的语言,即使是开发简单的程序,必须设计对象;JavaScript是种脚本语言,它可以用来制作与网络无关的,与用户交互作用的复杂软件。
- Java的源代码在执行之前,必须经过编译。JavaScript是一种解释性编程语言,其源代码不需经过编译,由浏览器解释执行。
- 强类型变量和类型弱变量:Java采用强类型变量检查,即所有变量在编译之前必须作声明;JavaScript中变量是弱类型的,甚至在使用变量前可以不作声明。
- 代码格式不一样。
第二部分 关键字
1.介绍一下Syncronized锁,如果用这个关键字修饰一个静态方法,锁住了什么?如果修饰成员方法,锁住了什么?
- java中提供同步方法的关键字。包含三种常见的锁状态。
- 普通的同步方法:锁的是当前对象
- 静态函数的同步方法:引用当前类的class对象
- 同步方法块的内容:synchronized括号里配置的对象。
2.介绍一下volatile?
- volatile作为java中的关键词之一,用以声明变量的值可能随时会别的线程修改,使用volatile修饰的变量会强制将修改的值立即写入主存,主存中值的更新会使缓存中的值失效(非volatile变量不具备这样的特性,非volatile变量的值会被缓存,线程A更新了这个值,线程B读取这个变量的值时可能读到的并不是是线程A更新后的值)。
- volatile会禁止指令重排volatile具有可见性、有序性,不具备原子性。
- 注意,volatile不具备原子性,这是volatile与java中的synchronized、java.util.concurrent.locks.Lock最大的功能差异
3.extends 和super 泛型限定符?
- extends 指定上界限,只能传入本类和子类
- super 指定下界限,只能传入本类和父类
- 上界不存,下届不取。
第三部分 面向对象部分
1、wait方法底层原理
- wait是object中的方法,可以暂停线程,期间会释放对象所。与Thread类中的sleep方法不同,在线程休眠期间依然持有锁。wait方法的线程,必须调用notufy和notifyAll方法唤醒线程。
2、Java有哪些特性,举个多态的例子。
- 继承、封装和多态。多态的主要特征就是父类引用指向子类的对象。
Animal animal = new Dog();
3、String为啥不可变?
- string底层的字符串数组是被final修饰的,因此不可变。
4、类和对象的区别
- 类为抽象的概念,它不存在于现实的空间中。类只是为所有对象定义了行为与属相。
- 对象为类的一个具体实现,包含着实实在在的东西。
- 类是一个静态的概念,类本身不懈怠数据。当没有类创建的任何对象时,类本身并不存在于内存空间
- 对象是一个动态的概念。每个对象都存在着与其他对象不同的行为和属性。
5、请列举你所知道的Object类的方法。
- getClass():用于返回当前运行时对象的Class对象,使用了final关键字修饰,故不允许子类重写;
- equals():用于比较两个对象的地址是否相同,即两个引用是否指向同一个对象;
- clone():用于创建并返回当前对象的一份拷贝;
toString():返回类的名字@实例的哈希码的16进制字符串; - notify():唤醒等待队列中的其中一个线程;
- notifyAll():唤醒线程等待队列中的所有线程;
- wait(long timeout):让一个线程等待一段时间。
6、重载和重写的区别?相同参数不同返回值能重载吗?
7、”static”关键字是什么意思?Java中是否可以覆盖(override)一个private或者是static的方法?
- static表示静态的意思,可以修饰一个变量和一个方法。被修饰的变量称为类变量,方法被成为类方法,随着类的加载而被加载。
- 无法重写private修饰的方法,private修饰的父类方法不可见。
- static修饰的是静态绑定的,而方法覆盖是为了实现多态,动态绑定,所以static修饰的方法不需要被覆盖。
8、String能继承吗?
- 不能,String类是被final修饰的。
9、类加载机制,双亲委派模型,好处是什么?
jvm的类加载器从上到下一共分为三类:
- 启动类加载器:负责加载java_home\lib目录中的且被虚拟机认可的类。
- 扩展类加载器:java_home\lib\ext目录中的,或者通过java.ext.dirs系统变量指定路径中的类库。
- 应用程序类加载器:负责加载用户路径上的类库。
- 双亲委派模型:当一个加载器不管是应用程序类加载器还是我们自定义的类加载器在进行类加载的时候它首先不会自己去加载,它首先会把加载任务委派给自己的父类加载器,比如现在有个类需要我们的自定义类加载器来加载,其实它首先会把它交给应用程序类加载器,应用程序类加载器又会把任务交给扩展类加载器,一直往上提交,直到启动类加载器。启动类加载器如果在自己的扫描范围内能找到类,它就会去加载,如果它找不到,它就会交给它的下一级子加载器去加载,以此类推。
双亲委派的作用:对于任意一个类,都需要类加载器和类本身一同确立其在虚拟机中的唯一性。
每一个类加载器都有一个独立的类名称空间。使用双亲委派母性使类随着它的类加载器一起具备了带有优先级的层次关系。
举例
- java.lang.Object.它有启动类加载器加载。模型可以保证任何类加载器收到对java.lang.Object的加载请求,最终都会委派给处于模型顶端的启动类加载器进行加载。因此object类在程序各种累加载器中都是同一个类。如果没有这个模型,用各个类加载器去加载的话。如果用户自己编写了一个java.ang.object的类,并用自定义的类加载器加载,那系统中会出现不同的Objcet类,java类型体系中最基本的行为都无法保证,应用程序会一片混乱。
11、静态变量存在哪? - 静态变量在方法区的静态存储区。static变量保存在class实例的尾部。
12、讲讲什么是泛型? - 泛型的本质是参数化类型,类型参数只能是类类型,不能是简单类型。
13、解释extends 和super - 限定符-上界不存下界不取
- extend是指定上界,只能传入本类和子类
- super指定下界,只能传入本类和父类。
14、是否可以在static环境中访问非static变量? - 不能,因为static变量属于类的,在类加载的时候就被初始化了。这时候非静态变量还不存在,因此静态变量不能访问。
15、谈谈如何通过反射创建对象?
- 调用运行类本身的.class属性
Class classz = person.class;
- 通过运行时类的对象获取
person p = new person();
Class clazz = p.getclass();
- 通过class的静态方法获取
String a = "com.atui.javaj.person";
Class claz = Class.forName(a);
- 通过类的加载器
classloader classload =this.getclass().getclassloader();
class clazz5 = classload.loadclass(a);
16、Java支持多继承么?
- java不支持多继承,只支持单继承,但是java接口支持多继承。即一个接口可以有多个父接口。(接口作用是用来扩展对象的功能,一个子接口可以继承多个父接口)
17、接口和抽象类的区别是什么?
18、Comparable和Comparator接口是干什么的?列出它们的区别。
- Comparable & Comparator 都是用来实现集合中元素的比较、排序的,只是Comparable 是在集合内部定义的方法实现的排序,Comparator 是在集合外部实现的排序,所以,如想实现排序,就需要在集合外定义Comparator接口的方法或在集合内实现Comparable接口的方法。
- Comparator在java.util下,然而Comparable在java.lang下。
20、final, finally, finalize的区别。
21、Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型?
22、JAVA语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try块中可以抛出异常吗?
27、内部类可以引用他包含类的成员吗?有没有什么限制?
- 完全可以。如果不是静态内部类,那没有什么限制! 一个内部类对象可以访问创建它的外部类对象的成员包括私有成员。
- 如果你把静态嵌套类当作内部类的一种特例,那在这种情况下不可以访问外部类的普通成员变量,而只能访问外部类中的静态成员。
28、两个对象值相同(x.equals(y) == true),但却可有不同的hash code说法是否正确?
- 错的
29、java的匿名内部类访问局部变量为什么要用final修饰?
- 局部变量是在方法里面定义的变量,因此内部类能够访问局部变量,说明这个类并不是成员内部类和静态内部类,而是定义在方法中的局部内部类。
- 局部变量的作用域是在方法中定义,当方法执行之后,局部变量也就消失了。但是当我们使用局部内部类或者是匿名内部类时,会扩大局部变量的作用域。因此在局部变量上加final,防止内部类中随意修改该局部变量的值。
30、如何通过反射获取和设置对象私有字段的值?
31、谈一下面向对象的"六原则一法则"。
- 单一职责原则,里氏替换原则,依赖倒置原则,开闭原则,接口隔离原则,合成聚合复用原则和迪米特法则
32、Java中,什么是构造函数?什么是构造函数重载?什么是复制构造函数?
- 当新对象被创建的时候,构造方法会被调用。每一个类都有构造方法。在程序员没有给类提供构造方法的情况下,Java编译器会为这个类创建一个默认的构造方法。
- Java中构造方法重载和方法重载很相似。可以为一个类创建多个构造方法。每一个构造方法必须有它自己唯一的参数列表。
- Java不支持像C++中那样的复制构造方法,这个不同点是因为如果你不自己写构造方法的情况下,Java不会创建默认的复制构造方法。