1.面向对象的理解
是一种设计程序的思想,侧重于程序中有哪些对象,不同的对象中有哪些属性和行为,以及对象和对象之间的关系,面向过程,更注重功能实现的步骤和顺序。
面向对象的三个基本特征:封装、继承、多态
通常应禁止直接访问对象中的数据,应该通过操作接口来访问,这称作信息隐蔽。
2.JRE、JDK、JVM分别是什么,以及他们之间的关系
JDK是java development kit:java发开工具包,主要是给java程序开发人员使用
JRE是java runtime environment:运行java程序,主要是java程序使用者用
JVM:java虚拟机
关系:
JRE = JVM + 类库(Object,String...)
JDK = JRE + JAVA工具(javac java jconsole,jmap)
3.JDK1.8之前和1.8之后定义接口区别?
1.8之前,接口中只能定义抽象方法和静态常量
1.8之后,接口中可以有默认(default)方法和静态方法
如何使用:
静态常量和静态方法:通过接口名称使用
默认(default)方法:由实现类对象调用
抽象方法:必须有实现类重写,实现类对象可以调用
4.接口和抽象类的区别?
语法区别:
抽象类中可以有非抽象方法,但有抽象方法的类必须是抽象类
在JDK1.8之前接口中只能定义抽象方法和静态常量
功能区别:
接口的目的是为类中的方法进行约束,接口是行为的抽象;
抽象类的目的是为代码的复用。
5.final、finally、finalize区别,什么作用?
final:是一个关键字,可以修饰类、变量和方法
作用:被final修饰的类不可以被继承
被final修饰的方法不能被重写
被final修饰的变量为常量,必须给初始值,并且只能赋值一次
finally:是异常处理相关的关键字
作用:在异常处理是提供finally代码块来执行最终方法,通常用来释放资源
finalize:是Object中定义的方法
作用:垃圾回收器在将对象从堆内存中回收之前,会调用对象的finalize方法
6.局部变量和成员变量区别?
1.定义的位置不同:局部变量定义在方法内部;成员变量定义在类中方法外
2.作用范围不同:局部变量只能在本方法内使用;在使用范围方面,成员变量又分为静态成员变量和非静态成员变量,静态成员变量可以在所有方法中使用,而非静态成员变量可以在所有非静态方法中使用。
3.默认值不同:
成员变量有默认值;基本类型是0,Boolean类型是false;引用类型的默认值是null;
局部变量没有默认值,必须手动赋值。
4.生命周期不同:
局部变量随着方法入栈而生成,随着方法出栈而销毁
实例变量(非静态成员变量):随着对象创建而生成,随着对象被gc回收而销毁(GC就是Garbage Collection,即垃圾回收)
静态成员变量:随着类被加载而生成,类被卸载时销毁
7.值传递和引⽤传递区别?
指的是方法在调用时将实参复制给形参。
区别:
基本数据类型的变量存储的是数据本身,所以是值传递
引用数据类型的变量存储的是对象的地址值,所以是引用传递
8.==和equals区别?
==: 基本类型的变量在内存中存储的是数据,那么对比的就是数据;
引用类型的变量在内存中存储的是对象的地址值,那么对比的就是地址值。
equals:是Object类中的一个方法,是一个运算符,用来2个变量的内容是否一致;
该方法默认实现是对比当前对象的引用和传进来的对象引用是否指向同一个对象
该方法可以被重写。
9.hashcode和equals的区别?
1. hashCode和equals都是Object类中的方法;
2. equals默认的实现:对象地址值是否一样;
3. hashCode是基于native方法实现的,底层是通过hash函数返回一个哈希值
该问题通常会结合HashSet和HashMap为何要要求元素重写hashCode和equals方法;
因为每一个对象的hashCode值都不同,而不同的对象使用equals方法比较的只是内存地址,而内存地址也不同;但我们想要的结果是相同内容的hashCode值相同,相同内容的比较相同!
所以我们要针对我们的对象内容重写hashCode方法和equals方法;
10.重载和重写区别?
重载: 在同一个类中,方法名相同,参数列表不同,构成的方法重载 参数列表不同分为: 参数个数 参数类型 参数顺序
重写:发生在父子类中
方法的名称参数必须相同,
抛出的异常小于父类,
访问修饰符大于等于父类。
返回值类型如果是基本类型,必须一样;返回值如果是引用类型,可以是父类方法返回值的子类类型;
满足以上条件就构成了方法的重写;并使用@Override 注解来规范方法重写,如果不是重写方法,会报错
11.Java数据类型?
基本数据类型(4类8种):
整数:byte、short、int、long
浮点:float、double
字符:char
布尔:boolean
引用类型:
类、接口、枚举、数组、注解
12.包装类和基本数据类型区别?
包装类是对基本数据类型的封装,比如Integer类;就封装了一个int类型的成员变量
13.为什么要提供包装类?
包装类中提供了对应基本数据类型最大值、最小值等属性以及相关方法,比如Integer取值范围位-2147483648 ~ 2147483647和parseInt方法,还有包装类作为基本数据类型的引用数据类型,也方便了涉及到对象的操作。
14.包装类和基础类型怎么转换?
基本数据类型转包装类,称为装箱,使用包装类的valueOf(基本类型)方法;
包装类转基本数据类型,称为拆箱,使用对象的.xxValue()方法就可以返回对象的基本数据类型;
JDK1.5之后提供了自动的包装类与基本类型互相转化的功能,不需调用对应的方法就可以进自动转换,称为自动拆/装箱。
15.构造器代码块、局部代码块、静态代码块执⾏顺序和执⾏次数?
执行顺序:
静态代码块:1.当类加载的时候执行。2.如果类中有多个静态代码块,则按照书写顺序执行。
【执行次数:一次。】
构造器代码块:1.对象被创建之前执行,优先于构造方法;2.如果类中有多个构造代码块,则按照书写顺序执行。
【执行次数:每次创建对象都会执行。】
局部代码块:1.当方法执行的时候执行;2.如果方法中有多个局部代码块,则按照书写顺序执行。
【执行次数:每次调用方法都会执行】
16.构造代码块的作⽤?
1.可以吧所有构造方法公共的代码放在构造代码块中。
2.匿名内部类的初始化操作,匿名内部类没有明显的构造方法。
17.Integer String 是否可以被继承?为什么?
不能,因为Integer等包装类或String类都被final修饰;
之所以被final修饰是因为:1.把方法锁定,避免任何继承关系修改它的意义和实现;2.高效,编译器在遇到调用final方法时,会自动转入内嵌机制,大大的提供效率;所谓内嵌机制:当代码调用到final方法时,这个方法会自动展开而不是以函数调用的形式,从而提高运行效率。
18.Integer缓存区间?什么时候触发缓存区间?
所谓Integer缓存区间,就是Integer类中定义了一个名为IntegerCache的内部类,在该内部类中维护了一个从-128~127的Integer数组;在基本数据类型转化为包装类的时候,如果基本数据类型的范围在该数组的取值范围之内,则直接返回对应的Integer实例,否则创建Integer实例。
19.String str1 = "abc" 和 String str2 = new String("abc")区别?
指向不同
第一种,如果常量池中没有"abc"则在常量池中创建"abc",str1指向的是常量池中的"abc";
第二种,如果常量池中没有"abc"则在常量池中创建"abc",再在堆中创建对象,将常量池中的"abc"复制到堆中,str2指向堆中对象。
20.String、StringBuffer、StringBuilder区别?是否线程安全?怎么做的到线程安全?
String底层维护的是char[]数组,并被final修饰,所以String为字符串常量,String对象一旦创建是不可更改的。至于String中的操作字符串的方法,比如替换、拼接、切割等都是返回了一个新的字符串;而StringBuffer和StringBuilder底层所维护的char[]数组没有被final修饰,方法都是在原来对象的字符数组基础上进行操作,所以不会产生新的对象。
线程安全:StringBuffer的所有方法都被synchronized修饰、还有String是字符串常量,不可变,所以StringBuffer和String是线程安全;StringBuilder线程不安全。
使用场景:如果不经常改变字符串的值、拼接等操作,使用String
如果有拼接需求,没有线程安全使用StringBuilder,有线程安全使用StringBuffer
21.&和&& | || 区别是什么?
区别一:作用方面的区别:
&(与)和|(或)即可以作为逻辑运算符又可以作为位运算符;
&&(短路与)和||(短路或)只可以作为逻辑运算符。
区别二:作为逻辑运算符的区别:
&& 是左边为false时就终止了,整个表达式都为false,不会继续计算右边条件;而&是无论左边是否满足都会继续计算右边。
||是左边条件为true时,整个表达式都为true,不会继续计算右边条件;而|是无论左边是否满足都会继续计算右边。
(&和|作为运算符:&:有0则为0;|:有1则为1)
22.JDK1.8之后的新特性:
1.lambda表达式
2.stream
3.接口增强
4.并行数组排序
5.Optional
6.新的时间和日期的API
7.可重复注解
23.Java中深克隆和浅克隆的区别?怎么实现?
克隆就是创建一个对象的副本对象;
深克隆和浅克隆就是指对象的克隆,一个对象中存在两种类型的属性,一种是基本数据类型,一种是实例对象的引用地址,浅克隆只会克隆基本数据类型的值,以及引用地址,并不会复制一份引用地址所指向的对象,浅克隆出来的对象和当前对象,内部属性指向的是同一个对象;深克隆既会克隆基本数据类型的值,也会针对引用地址所指向的对象进行复制,深克隆出来的对象和当前对象,内部属性指向的不是同一个对象。
通俗点就是,浅克隆新对象的引用是老对象;深克隆是创建一个新的副本,两者互不影响。如果不小心使用了错的拷贝方法,就会导致多个线程同时操作同一个对象造成数据安全问题。
实现浅克隆常用的API有三种:
第一种:Spring中的工具类BeanUtils和Apache的commons包中提供的工具类PropertyUtils
BeanUtils的方法copyProperty和copeProperties;
PropertyUtils的方法copeProperties;
第二种:实现Clonenable接口
第三种:Arrays的copyOf()方法
实现深克隆常用的API有五种:
第一种:每个对象都要实现Clonenable接口并重写Object类中的clone()方法
第二种:序列化,必须实现Serializable接口
第三种:Apache Commons工具包中的SerializationUtils.clone()方法
第四种:通过JSON工具类实现深克隆
第五种:通过构造方法手动new对象
24.包装类型、Math,String类常⽤的⽅法有哪些?
包装类中的常用方法分为两大类:将包装类转化为基本数据类型的方法;和将字符串转化为基本数据类型的方法;包装类-基本数据类型的方法有xxxValue()比如intValue();字符串-基本数据类型的方法有Integer.parseInt(String str)等
Math中的常用方法:
取绝对值Math.abs
向上取整Math.ceil/向下取整Math.floor
取最大值Math.max/取最小值Math.min
返回大于等于0.0小于1.0的随机小数Math.random
25.Comparable 和Comparator的区别,分别说出使⽤场景?
Comparable称为自然排序,排序逻辑要写在需要排序的类,该类要实现Comparable接口,重写int compareTo(E o1)方法。
Comparator称为比较器排序,排序逻辑在另一个类中实现,重写int compare(E o1,E o2)方法;
使用场景:TreeSet、Collections.sort(List<E> list)、Collections.sort(List<E> list,Comparator<E> comparator)
26.Object类和范型的区别,说出范型的执⾏机制,为什么要使⽤范型?
1.Object类和泛型的区别:
从方法的调用上来看,没有区别,但是如果一个方法的返回值为Obj类型,但传递的是String,那么返回也是String,就需要将返回的Obj强转为String;但如果泛型为String的话则不需要。
2.为什么使用泛型:
首先,不需要做强制类型转换,其次,编译时会自动检查类型安全。如果使用的是Object类的话,你没法保证一定是String,也有可能是其他类,这时在运行的话会报类型转换异常。
3.泛型的执行机制:
泛型的本质是一种参数化类型,也就是将数据类型作为参数传递,其中T相当于形式参数负责占位,如果传递的数据类型为String,那么String就将作为实际参数类型给形参T赋值,从而使所有T都替换为String,由于实际参数可以传递各种引用类型,因此叫泛型。
27.Error 和Exception 有什么区别?
从继承体系来看,Error和Exception都是Throwable的子类;
从功能方面来看,Error是程序无法处理的异常,Exception是程序可以处理的异常分为运行时异常和编译时异常。
28.什么是反射?
反射是为了动态加载一个类,动态调用一个方法,动态访问一个属性 这些动态需求而设计的;虚拟机会为每一个类创建一个java.lang.Class(字节码文件)的实例,通过该对象就能获取到该类中的信息,然后通过java.lang.reflect包下的各种API达成各种动态需求。
抽象类和接口有什么区别
抽象类和接口是 Java 中常用的两个概念,它们用于实现类的继承和复用,并且被广泛地运用在 Java 编程中。它们的主要区别如下:
1. 实现方式不同 抽象类使用 `abstract` 关键字来定义,可以包含抽象和非抽象方法,抽象方法必须在子类中被重写才能使用,而非抽象方法则可以在子类中被直接调用。 接口使用 `interface` 关键字来定义,只能包含抽象方法和常量,不能包含非抽象方法和属性。在 Java 8 之后,可以在接口中定义默认方法和静态方法实现功能。
2. 多继承支持差异 抽象类只能单继承,即一个子类只能继承一个抽象类。但是,子类可以同时实现多个接口。 接口可以多继承,即一个接口可以继承自多个接口。一个类可以实现多个接口,但不能同时继承抽象类和接口。
3. 实现方式差异 抽象类需要子类继承,因此可以有构造方法和实例变量。在使用时需要创建子类的实例对象,才能使用其属性和方法。 接口不能被实例化,只能使用 `implements` 关键字,由实现类实现接口定义的具体方法。
4. 设计意图不同 抽象类是为了实现代码复用和共享而提出的概念,主要用于类的继承。 接口是为了解决多重继承中方法的二义性而提出的概念,主要用于类的实现。
总之,抽象类和接口在实现方式、多继承支持、实现方式和设计意图等方面存在明显差异。在实际应用中,开发者可以根据业务需求和代码特点,选择合适的方式继承和实现类,从而达到更好的代码复用和共享的目的。
设计模式
设计模式分为创建型模式、结构性模式、以及行为型模式;
创建型模式提供了对象在创建过程中的各种问题的解决方案总结,如单例模式、抽象工厂模式、原型模式、构建者模式、工厂方法模式。
构建者模式是对类在设计上的总结,比较关注类的继承和组合关系,如适配器模式、桥接模式、装饰者模式、外观模式、享元模式、组合模式以及代理模式,代理模式分为静态代理和动态代理。
行为模式是对象直接的交互和职责划分总结,即观察者模式、模板模式、策略模式、职责链模式、迭代器模式、状态模式、访问者模式、备忘录模式、命令模式、解释器模式、中介模式。