java面试问题基础(1)

114 阅读12分钟

一:.基本功

面向对象的特征

  1. 封装:也就是将客观事物封装成抽象的类,并且类可以把自己的数据和方法只给可信的类或对象操作,对不可信的进行信息隐藏。封装了数据以及操作的逻辑实体。

  2. 继承:它可以使用现有类的全部功能,并在无需重新编写原来的类的情况下对这些功能进行扩展

  3. 多态:实例的相同方法在不同情形下有不同的表现形式。 最常见的多态是将子类传入父类的参数中,运行时调用父类方法时通过传入的子类决定具体的内部结构或行为。有二种方式,覆盖,重载。

final, finally, finalize 的区别

  1. final类不能被继承,没有子类,final类中的方法默认是final的。 final方法不能被子类的方法覆盖,但可以被继承。 final成员变量表示常量,只能被赋值一次,赋值后值不再改变。修饰变量,为常量,其中引用类型数据是指向不可改。内部类要访问局部变量,局部变量必须定义成final类型。一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。 final变量定义的时候,可以先声明,而不给初值,这中变量也称为final空白,无论什么情况,编译器都确保空白final在使用之前必须被初始化。为此,一个类中的final数据成员就可以实现依对象而有所不同,却有保持其恒定不变的特征。 当函数参数为final类型时,你可以读取使用该参数,但是无法改变该参数的值。
  2. finally是无论发不发生异常一定在方法结束时执行的代码块。
  3. finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法。JVM不保证此方法总被调用

int 和 Integer 有什么区别

  1. Integer是int的包装类,提供了常量和方法,是引用数据类型。

  2. Integer变量存的是引用值,指向此new的Integer对象;int是直接存储数据值 ;

  3. Integer的默认值是null;int的默认值是0。Integer变量必须实例化后才能使用;int变量不需要。

  4. 对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间-128到127之间,则比较结果为true,如果两个变量的值不在此区间,则比较结果为false。(给一个Integer对象赋一个int值的时候,会调用Integer类的静态方法valueOf,编译Integer i = 100 ;时,会翻译成为Integer i = Integer.valueOf(100)。而Integer.valueof()会在这个范围会返回缓存)

  5. 两个包装类比较不相等,不会自动拆箱。

重载和重写的区别

  1. 重载在同一类中,且重载除了方法名外都可以不同。但无法以返回型别作为重载函数的区分标准。

  2. 重写在不同类中,方法签名必须一致,且子类权限不能大于父类。

  3. 方法重载是让类以统一的方式处理不同类型数据的一种手段。重载Overloading是一个类中多态性的一种表现

  4. 写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常 抽象类和接口有什么区别

  5. 抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。

  6. 抽象类要被子类继承,接口要被类实现。

  7. 抽象类可以拥有实例方法,是对整体的抽象。接口只有抽象方法和全局常量,是对行为的抽象。

  8. 接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。

  9. 抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。

  10. 抽象方法只能申明,不能实现,接口是设计的结果 ,抽象类是重构的结果

  11. 抽象类里可以没有抽象方法

  12. 如果一个类里有抽象方法,那么这个类只能是抽象类

  13. 抽象方法要被实现,所以不能是静态的,也不能是私有的。

  14. 接口可继承接口,并可多继承接口,但类只能单根继承。

说说反射的用途及实现

很多框架(比如 Spring)都是配置化的(比如通过 XML文件配置 JavaBean,Action之类的),为了保证框架的通用性,他们可能根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射——运行时动态加载需要加载的类。例如,配置不同数据库的驱动类。

①、在运行时判断任意一个对象所属的类

②、在运行时构造任意一个类的对象

③、在运行时判断任意一个类所具有的成员变量和方法(通过反射设置可以调用 private)

④、在运行时调用任意一个对象的方法

反射通过对 Class 对象(类的数据结构接口)的操作实现的,Class 对象提供了一系列方法对类进行操作。在 JVM 这个角度来说,Class 文件是二进制流,通过对 Class 数据流的处理我们即可得到字段、方法等数据

  • 说说自定义注解的场景及实现 登陆、权限拦截、日志处理,以及各种 Java 框架,如 Spring,Hibernate,JUnit 提到注解就不能不说反射,Java 自定义注解是通过运行时靠反射获取注解。实际开发中,例如我们要获取某个方法的调用日志,可以通过 AOP(动态代理机制)给方法添加切面,通过反射来获取方法包含的注解,如果包含日志注解,就进行日志记录。

垂直化编程,就是A—B—C—D…等执行下去,一个逻辑一个逻辑完了再执行下一个,但是spring 中AOP提供了一种思想,它的作用就是,当在业务不知情的情况下,对业务代码的功能的增强,这种思想使用的场景,例如事务提交、方法执行之前的权限检测、日志打印、方法调用事件等等。 注解类型默认实现接口jannotation 元注解(注解其他注解类型):Java5.0定义的元注解:   这些类型和它们所支持的类在java.lang.annotation包中可以找到。      
  1. @Target:用户描述注解的作用范围
  取值(ElementType)有:
    1. CONSTRUCTOR:用于描述构造器
    2. FIELD:用于描述域
    3. LOCAL_VARIABLE:用于描述局部变量
    4. METHOD:用于描述方法
    5. PACKAGE:用于描述包
    6. PARAMETER:用于描述参数
    7. TYPE:用于描述类、接口(包括注解类型) 或enum声明

  1. @Retention:表示需要在什么级别保存该注释信息 取值(RetentionPoicy)有:     1.SOURCE:在源文件中有效(即源文件保留)     2.CLASS:在class文件中有效(即class保留)     3.RUNTIME:在运行时有效(即运行时保留)(常用)

  3. @Documented:Documented是一个标记注解 。  
  4. @Inherited :用于声明一个注解在子类也有效。   Java注解基本知识

注解是代码的附属信息,不能干扰代码的正常执行,无论删除或增加注解,代码都能够正常执行 定义注解使用@interface修饰符 Java预定义注解被称为元注解,它们被Java编译器使用,比如:@Retention注解和@Target注解,前者定义注解的保留期限,后者定义注解的应用目标 注解的成员声明和接口的方法声明类似,还可以使用default关键字指定成员的默认值 如果注解只有一个成员,则成员名必须取名为value(),使用时如果给成员赋值可以不写成员名和赋值符号’=’ 如果注解有多个成员,在赋值时如果只给value()成员赋值,也可以不写成员名和赋值符号’=’ 如果在赋值时要同时给多个成员赋值,则必须写成员名和赋值符号’=’ 所有注解类都隐式继承与java.lang.annotation.Annotation,但是注解不允许显示继承于其他的接口

如何访问注解

通过Java的反射机制读取注解的信息 若要通过反射来读取注解信息,那么被定义的注解的保留期限必须是RententionPolicy.RUNTIME, 只有该策略下的注解信息会被保留在目标类代码的字节码中,并且当类加载器加载字节码时会将注解信息加载到JVM中 自定义注解使用场景

类属性自动赋值。
验证对象属性完整性。
代替配置文件功能,像spring基于注解的配置。
可以生成文档,像Java代码注释中的@see,@param等

string、stringbuilder、stringbuffer区别 修改字符串速度 StringBuilder>StringBuffer>String 内容是否可变 只有String不可变。 线程安全 只有StringBuilder是线程不安全的。 String作为不可变类,是明显线程安全的,Java中所有不可变类都是线程安全的。(无资源共享的问题)。 StringBuffer类是可变类,但是StringBuffer类中实现的方法都是被Sychronized关键字所修饰的,因此它靠锁实现了线程安全。 Stringbuilder类是可变类,并且方法没有被Sychronized修饰,因此它是线程不安全的。


实现比较器,compareable和comparetor区别 Comparable 是排序接口。

若一个类实现了Comparable接口,就意味着“该类支持排序”。 List列表(或数组)可以通过 Collections.sort(或 Arrays.sort)进行排序。

此外,“实现Comparable接口的类的对象”可以用作“有序映射(如TreeMap)”中的键或“有序集合(TreeSet)”中的元素,而不需要指定比较器。

Comparator 是比较器接口。

我们若需要控制某个类的次序,而该类本身不支持排序(即没有实现Comparable接口);那么,我们可以建立一个“该类的比较器”来进行排序。这个“比较器”只需要实现Comparator接口即可。

也就是说,我们可以通过“实现Comparator类来新建一个比较器”,然后通过该比较器对类进行排序。


session与cookie区别 Cookie保存在客户端,未设置存储时间的cookie保存在浏览器进程开辟的内存中,关闭后被删除;设置了存储时间的cookie保存在磁盘中直到过期。

session保存在服务器端,存储在IIS的进程开辟的内存中。

当服务器端生成一个session时就会向客户端发送一个cookie保存在客户端,这个cookie保存的是session的sessionId。保证客户端用户能够匹配到保存了该用户信息session,确保不同页面之间传值时的正确匹配。

注:为了防止客户端禁用了cookie而无法使用session的情况可以把sessionId和其他用户信息重写到url中,每次请求都在url中附带sessionId和用户信息(不包含用户的敏感信息)


equals 与== 的区别

值类型(int,char,long,boolean等)都是用==判断相等性。对象引用的话,==判断引用所指的对象是否是同一个。equals是Object的成员函数,有些类会覆盖(override)这个方法,用于判断对象的等价性。例如String类,两个引用所指向的String都是"abc",但可能出现他们实际对应的对象并不是同一个(和jvm实现方式有关),因此用==判断他们可能不相等,但用equals判断一定是相等的。

==操作符比较变量对应的内存中所存储的数值是否相同。

如果一个变量指向的数据是对象类型的,那么,这时候涉及了两块内存,对象本身占用一块内存(堆内存),变量也占用一块内存,例如Objet obj = new Object();变量obj是一个内存,new Object()是另一个内存,此时,变量obj所对应的内存中存储的数值就是对象占用的那块内存的首地址。

equals方法是用于比较两个独立对象的内容是否相同,就好比去比较两个人的长相是否相同,它比较的两个对象是独立的。

如果一个类没有自己定义equals方法,那么它将继承Object类的equals方法,Object类的equals方法的实现代码如下:

boolean equals(Object o){ return this==o; }

这说明,如果一个类没有自己定义equals方法,它默认的equals方法(从Object类继承的)就是使用==操作符,比较两个变量指向的对象是否是同一对象,如果比较的是两个独立的对象则总返回false。 覆盖equals方法,由你自己写代码来决定在什么情况即可认为两个对象的内容是相同的。 equals和hashcode的关系


Java集合中本质是散列表的类,如HashMap,Hashtable,HashSet。 也就是说:hashCode() 在散列表中才有用,在其它情况下没用。在散列表中hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。 一般第一步是hashcode,第二步equals