java面试题——转载

转载自

1、java中“==”和equals和hashCode的区别

  操作符“==”:

  专门用来比较两个变量的值是否相等,即用于比较变量所对应的内存中所存储的数值是否相同。比如比较两个基本类型的数据是否相等或两个引用变量是否指向同一个对象等,需要使用“==”

  equals方法:

  是Java类层次中根类Object中定义的方法,也就是说每个类都继承了这个方法,一般都来比较两个非空对象是否相同,返回true or false。

  无论何时重写此方法,通常都必须重写hashCode方法,以维护hashCode方法的一般约定——该方法声明相等对象必须具有相同的hashcode。

  hashcode方法:  

  返回对象的hashcode值。这个方法支持散列表,例如HashMap提供的散列表。

  hashcode的一般规约:

  • 在一个Java应用程序的执行过程中,无论同一个Object的hashcode()方法被调用了多少次,只要在equals比较中需要用到的信息没有被修改,hashcode()方法必须始终返回相同的整数。当然在不同的执行过程中,该整数无需保持一致。
  • 如果两个对象根据equals方法的判别是相等的,那么对每个对象的hashcode()方法的调用都会得到相同的整数。
  • 根据equals方法判别不相等的两个对象,并不要求两个对象的hashcode()方法必须返回不同的整数。但是,程序员应该注意,为不相等的对象生成不同的整数结果可能会提高散列表的性能。

  事实上,Object中定义的hashcode()方法的确为不同的对象返回不同的整数值。这是通过将对象的内部地址转换为整数来实现的,但这种转换技术并不是Java语言要求的。

  (http://www.cnblogs.com/bigbigbigo/p/8553320.html)

  2、int、char、long各占多少字节数?

  整数型:byte:1B  short :2B  int:4B  long:8B

  浮点型:float:4B  double:8B

  字符型:char:2B

  关于boolean:The boolean data type has only two possible values: true and false. Use this data type for simple flags that track true/false conditions. This data type represents one bit of information, but its "size" isn't something that's precisely defined.

  

  3、int与Integer的区别

  Java为每个基本数据类型提供了一个包装类,Integer就是int的包装类。

  包装类有属性和方法,功能比基本数据类型更加强大。

  Java也提供自动将基本类型数据和他们包装类之间转换的机制。

  4、谈谈对Java多态的理解

  多态的定义:在程序中定义的引用变量所指向的具体类型在编程时并不确定,而是在程序运行期间才确定。

  多态的表现:相同的消息使得不同的对象做出不同的响应。

  多态的类型:编译时多态,运行时多态

  多态的实现方式:继承(继承关系、方法重写、向上转型)和接口(通过接口变量调用不同的对象中的接口方法)。

  

  5、String、StringBuffer、StringBuilder区别

  String:

  String对象是不可变对象,即当你修改一个String对象的内容时,JVM不会改变原来的对象,而是生成一个新的String对象;

  String对象被保存在String Pool中;

  Java中的不可变对象都是线程安全的,所以String对象也是线程安全的,意味着String对象不能被两个线程同时使用。

  StringBuffer:

  StringBuffer对象是可变对象,即它的值可以被修改。StringBuffer在进行字符串处理时,不生成新的对象。

  StringBuffer对象被存储在heap中;

  StringBuffer中的方法与StringBuilder中的方法是相同的,但是StringBuffer中的方法都是具有同步性的,即是线程安全的。因此,StringBuffer对象不允许两个线程同时访问同一个方法。

  因为保证了线程安全,StringBuffer的性能会降低。

  可以通过toString()方法转换成String类;可以通过String对象构造一个StringBuffer对象。

  StringBuffer的内部实现方式和String不同;

  StringBuilder:

  和StringBuffer基本一致;

  不同点在于,StringBuilder中的方法都不保证同步性和线程安全,因此速度会比StringBuffer快一些。

  

  6、什么是内部类?内部类的作用

  将一个类的声明和定义放在另一个类的内部。内部类相当于外部类的类成员,可以访问外部类的成员变量、方法和其它内部类。

  内部类的作用:

  • 对类进行逻辑分组。如果类A仅对类B有作用,则可以把类A作为类B的内部类。
  • 提高了封装程度。内部类可以被申明为private,可以访问外部类的私有成员。这时也只有外部类可以访问内部类。
  • 可以使代码更可读和更易维护。把小型类定义在大型类的内部,可以使它更靠近它被使用到地方,从而更可读。
  • 内部类对象创建时刻不依赖外部类对象的创建,内部类没有(和外部类)令人迷惑的“is a”关系,就是一个独立的实体。
  • 每个内部类都能独立地继承一个类或实现一个接口,所以无论外部类是否已经继承了某个类或者实现了某个接口,对内部类没有影响。

  (https://www.geeksforgeeks.org/nested-classes-java/)

  7、抽象类和接口区别

  接口和抽象类的不同表现在下面三个方面:

  (1)抽象层次不同

    抽象类是对整个类的整体进行抽象,包括属性、行为;

    接口只对行为抽象。 

  (2)建模关系不同

    抽象类对有相似特点的类建模,抽象类体现的更多是一种继承关系;

    而接口可以对不相关的类建模。

  (3)设计层次不同

    抽象类是自下而上进行设计;

    接口只需要定义一个规则,只关心行为的需求描述;

  

  8、抽象类的意义

  抽象类可以有属性和方法,但是不能创建实例,它是用来被继承的。但是,抽象类可以有构造方法!

  抽象类中的抽象方法的具体实现由子类自己负责完成,从抽象父类派生的子类要能够实现所有的抽象方法。

  9、抽象类与接口的应用场景

  一个类可以实现多个接口;一个类只能继承一个抽象类;

  选择抽象类:

  • You want to share code among several closely related classes.
  • You expect that classes that extend your abstract class have many common methods or fields, or require access modifiers other than public (such as protected and private).
  • You want to declare non-static or non-final fields. This enables you to define methods that can access and modify the state of the object to which they belong.

  选择接口:

  • You expect that unrelated classes would implement your interface. For example, the interfaces Comparable and Cloneable are implemented by many unrelated classes.
  • You want to specify the behavior of a particular data type, but not concerned about who implements its behavior.
  • You want to take advantage of multiple inheritance of type.

  10、抽象类是否可以没有方法和属性?

  可以!

  接口也可以没有方法和属性。

  11、接口的意义

  接口为实现类提供一个必须做到的行为规范;

  一个接口可以继承多个接口;

  一个类可以实现多个接口,弥补了类之间单继承的缺陷;

  12、泛型中extends和super的区别

  为泛型的类型限制提供上界(还可以使用上界类中的方法)和下界;

  13、父类的静态方法能否被子类重写

  可以,但是重写的方法也必须申明为static。

  14、进程和线程的区别

  15、final,finally,finalize的区别

  final:

  final修饰类,避免产生子类。如果一个类声明为final,它的所有方法默认为final(反正也不会被重写),但是它的属性不这样;

  final修饰方法,意味着方法不能被子类重写;

  final修饰属性或者变量,变量被初始化后就不能修改。一般情况下我们可以在声明final变量时初始化它,但是,也可以声明一个空的final变量,然后在构造方法中初始化(体会两种方式在类中的差别)。空的final变量常用于创建不可变对象。;

  (https://www.geeksforgeeks.org/blank-final-in-java/)

  finally:

  常用在异常处理机制中,它保证了finally语句块总是被执行,用来回收资源。

  inally块将在try和catch块之后执行,在控制权转移回其原处之前执行。

  

  finalize:

  在Object类中定义的 protected void finalize() throws Throwable;

  如果一个对象可以进行垃圾回收了(没有任何指向这个对象的引用变量了),那么垃圾回收器在销毁这个对象前,会自动调用它的finalize()方法进行资源回收。方法结束后,对象立即被销毁。

  (https://www.geeksforgeeks.org/g-fact-24-finalfinally-and-finalize-in-java/)

  

   

  16、序列化的方式

  如果一个Java对象的所属类或者其任意一个父类实现了接口 java.io.Serializable 或者它的子类 java.io.Externalizable,那么我们称这个对象是可序列化的。

  (https://www.geeksforgeeks.org/object-serialization-inheritance-java/)

  (https://www.geeksforgeeks.org/serialization-in-java/)

  18、静态属性和静态方法是否可以被继承?是否可以被重写?以及原因?

  都可以被继承;

  静态方法可以被重写,但重写的方法也必须是静态的;

  属性只存在隐藏一说,没有重写一说。

  19、静态内部类的设计意图

  非静态内部类在编译完成后会隐含地保存一个引用,该引用指向创建它的外部类。但是,静态内部类没有这样的引用,意味着静态内部类的对象创建不依赖外部类的对象创建,因此不能访问外部类任何的非静态成员。

  参考

  One common use of a static member class is as a public helper class, useful only in conjunction with its outer class.

  One common use of a nonstatic member class is to define an Adapter that allows an instance of the outer class to be viewed as an instance of some unrelated class. 

  Use a non-static nested class (or inner class) if you require access to an enclosing instance's non-public fields and methods.

  Use a static nested class if you don't require this access.

  20、成员内部类、静态内部类、局部内部类和匿名内部类的理解,以及项目中的应用

-----------------------------------------

1、哪些情况下的对象会被垃圾回收机制处理掉?

  当一个对象不再使用时,应该回收对象占用的内存空间,从而提高内存利用率。Java中内存的回收由垃圾回收器(Garbage Collection,GC)自动处理,GC只负责内存相关的清理,其它资源必须手动释放。

  Java的垃圾自动收集机制:JVM查看堆内存,区分出正在使用的对象和未使用的对象,接着删除未使用的对象。

  正在使用的对象是指程序有一个指向该对象的引用;未使用的对象则是指不被程序的任何部分持有引用的对象。

标记垃圾的算法
Java中标记垃圾的算法主要有两种, 引用计数法和可达性分析算法。我们首先来介绍引用计数法。

引用计数法
  引用计数法就是给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加 1;当引用失效,计数器就减 1
  任何时候计数器为 0 的对象就是不可能再被使用的,可以当做垃圾收集。这种方法实现起来很简单而且优缺点都很明显。 优点 执行效率高,程序执行受影响较小 缺点 无法检测出循环引用的情况,导致内存泄露 可达性分析算法 这个算法的基本思想就是通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的。

 

 

 

  2、讲一下常见编码方式?

  常见的有 ASCII、ISO-8859-1、GB2312、GBK、UTF-8、UTF-16 等

  参考:深入分析Java中的中文编码问题

  3、utf-8编码中的中文占几个字节;int型几个字节?

  UTF-8使用可变长度字节来储存 Unicode字符,例如ASCII字母继续使用1字节储存,重音文字、希腊字母或西里尔字母等使用2字节来储存,而常用的汉字就要使用3字节。辅助平面字符则使用4字节。

  Java中int类型是4个字节存储

  4、静态代理和动态代理的区别,什么场景使用?

   静态代理:由程序员创建或特定工具自动生成源代码,再对其编译,在程序运行前,代理类的.class文件就已经存在了。一个代理类只能为一个接口服务。

  动态代理:动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。可以通过一个代理类,完成所有代理工作,不需要向静态代理需要一个一个实现接口来代理。

  参考阅读:Java的动态代理机制     静态代理与动态代理

  5、Java的异常体系

     所有非正常情况分为两种:异常(Exception)和错误(Error),均继承自类Throwable。

  错误:是指虚拟机相关问题如系统崩溃、虚拟机出错等,这类错误无法恢复,程序也不用捕获了。

  异常:异常分为两大类:受查异常(Checked)和运行时异常(Runtime)。

  运行时异常:

  所有运行时异常类和它的子类的对象被称为运行时异常。运行时异常不需要显示声明抛出,如果程序需要捕捉运行时异常,可以用try…catch块。   

  受查异常:

  不是运行时异常实例都归为受查异常,它是可以被修复的异常。程序必须显示地处理受查异常,如果没有处理,在编译时就无法通过。

  必须用try…catch块捕获,在catch中修复。当方法不知道如何处理,在定义方法时声明抛出(throws)异常,由上一级调用处理。

  6、谈谈你对解析与分派的认识。

  深入理解JVM。 

  7、修改对象A的equals方法的签名,那么使用HashMap存放这个对象实例的时候,会调用哪个equals方法?

  

  8、Java中实现多态的机制是什么?

  编译时多态、运行时多态。

  实现方式:继承、接口。

  继承中:继承关系、方法重写、向上转型。

  9、如何将一个Java对象序列化到文件里?

 

  10、说说你对Java反射的理解(反射的用途和实现)

  (1)反射的基础是因为在运行状态中,JVM能够知道对象的所有属性和方法,并且能够调用它的任意一个方法或访问其任一属性。反射机制使得程序可以在运行时动态加载、查看和使用编译期间完全未知的类(对象)

   (2)反射的通常用途:

  • 用于程序检查工具和调试器,它能获取程序在运行时刻的内部结构。只需要短短十几行代码,就可以遍历出对象所属类的结构,包括构造方法、声明的属性和定义的方法和修饰符等。
  • 在运行时刻与注解配合,动态改变对象的行为,例如,为特定对象添加日志、权限控制等操作。

  11、说说你对Java注解的理解(自定义注解的使用场景和实现)

  12、说说你对依赖注入的理解

  13、说一下泛型原理,并举例说明

  15、String为什么要设计成不可变的?

 

  16、Object类的equal和hashCode方法重写,为什么?

  21、谈谈对Kotlin的理解

   Kotlin的设计目标:创建一种兼容Java的语言,它比Java更安全、更简洁。

  22、闭包和局部内部类的区别

  闭包在现在的很多流行的语言中都存在,例如 C++、C# 。闭包允许我们创建函数指针,并把它们作为参数传递。即函数式编程,Java 8提供了Lambda表达式,Lambda实现了函数式编程,可以用于替代广泛使用的匿名内部类实现回调功能,用于事件响应器。

  (https://www.oschina.net/translate/at-first-sight-with-closures-in-java?lang=chs&page=1#)

  23、String 转换成 Integer的方式及原理

   Integer.parseInt("10");

  String的本质是char数组(String.toCharArray()),我们可以根据ASCII表,将一个数字字符转换成一个数字。如字符‘0’~‘9’的ASCII值为48~57。

 char[] chars={'0','1'};
 System.out.println(chars[0]);    //0

 int c=(int)chars[0];
 System.out.println(c);    //48

猜你喜欢

转载自www.cnblogs.com/zwq20134/p/11620213.html