Java【基础】面试题

一、什么是面向对象?

  面向对象是一种思想,“一切皆对象”,这里只讨论面向对象编程(OOP)。

   Java是一个支持并发、基于类和面向对象的计算机编程语言,面向对象软件开发有以下的优点:

  • 代码开发模块化,更容易进行维护和修改。
  • 代码的复用性强。
  • 增强代码的可靠性和灵活性。
  • 增加代码的可读性。

二、面向对象的基本特征?

  四点:封装、继承、多态、抽象。

  1)封装

  给对象提供了隐藏内部特性和行为的能力。对象提供了一些被其他对象访问的方法来改变它内部的数据,在java中,有4种修饰符:default、public、private和protected,每一种修饰符给其他的位于同一个包或者不同包下面对象赋予了不同的访问权限。

  下面列出了使用封装的一些好处:

  • 通过隐藏对象的属性来保护对象内部的状态。
  • 提高了代码的可用性和可维护性,因为对象的行为可以被单独的改变或者是拓展。
  • 禁止对象之间的不良交互提高模块化。

  2)继承

  给对象提供了从基类获取字段和方法的能力,继承提供了代码的重用性。也可以在不修改类的情况下给现存的类添加新特性。

  3)多态

  多态:是编程语言给不同的底层数据类型做相同的接口展示的一种能力。一个多态类型上的操作,可以应用到其他类型的值上面。

  4)抽象

  抽象:是把想法从具体的实例中分离出来的步骤。因此,要根据他们的功能而不是实现细节来创建类。

  java支持创建值是暴露接口而不包含方法实现的抽象的类,这种抽象技术的主要目的是把类的行为和实现细节分离开。

java中实现多态的机制是什么?

  java中,靠的是父类或者接口定义的引用变量可以指向子类或者具体实现类的实例对象,而程序调用的方法在运行期才能动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。

java中有没有多继承?

  java的类是单继承的,即每一个类只能继承一个类

  但是java中的接口支持多继承,即一个接口可以继承多个接口。

三、面向对象和面向过程的区别?

  • 面向过程
    • 优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源。比如:单片机,嵌入式开发,linux\unix等一般采用面向过程开发,性能时最重要的因素。
    • 缺点:没有面向对象易于维护、易复用、易拓展。
  • 面向对象
    • 优点:易维护、易复用、易拓展,由于面向对象有封装、继承、多态、抽象等特性,可以设计出低耦合的系统,使系统更加灵活,更加易于维护。
    • 缺点:性能比面向过程低。

四、重载和重写的区别?

  1)重写 override

  • 方法名、参数、返回值相同。
  • 子类方法不能缩小父类方法的访问权限。
  • 子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)
  • 存在于父类和子类之间。
  • 方法被定义为final不能被重写。

  2)重载 overload

  • 参数类型,个数,顺序至少有一个不相同。
  • 不能重载只有返回值不同的方法名。
  • 存在于父类和子类,同类中。

五、java中,什么是构造方法?什么事构造方法重载?什么是拷贝构造方法?

  1)构造方法

  当对象被创建的时候,构造方法会被调用,每一个类都有构造方法。在程序员没有给类提供构造方法的情况下,java编译器会为这个类创建一个默认的构造方法。

  2)构造方法重载

  java中的方法重载和方法重载很相似,可以为一个类创建多个构造方法,每一个构造方法必须有它自己唯一的参数列表。

  3)拷贝构造方法

  java不支持C++中那样的拷贝构造方法,这个不同点是因为如果你不自己写构造方法的情况下,java不会创建默认的拷贝构造方法。

六、JDK、JRE、JVM分别是什么关系?

  1)JDK

  JDK即为java开发工具包,包含编写java程序所必须的编译、运行等开发工具以及JRE,开发工具如:

  • 用于编译java程序的javac命令。
  • 用于启动JVM运行java程序的java命令。
  • 用于生成文档的javadoc命令
  • 用于打包的jar命令等。
简单的说:jdk包含了JRE和JVM

  2)JRE

  JRE即为java运行环境,提供了运行java应用程序所必须的软件环境。包含有java虚拟机(JVM)和丰富的系统类库,系统类库即为java提前封装好的功能,只需要拿来直接使用即可,可以大大的提高开发效率。

即:jre包含了JVM

  3)JVM

  JVM即为java虚拟机,提供了字节码文件(.class)的运行环境支持。

 

java虚拟机(JVM)以及跨平台的原理详细介绍:

  JVM是一个软件,不同的平台由不同的版本。我们编写的java源码,编译后生成一种.class文件,称为字节码文件。java虚拟机就是负责将字节码文件翻译成待定平台下的机器码然后运行。也就是说,只要在不同的平台上安装对应的JVM,就可以运行字节码文件,运行我们编写的java程序。

  而这个过程中,我们编写的java程序没有做任何改变,仅仅通过jvm这一“中间层”,就能在不同平台上运行,真正实现了“一次编译,处处运行”的目的。

  JVM是一个“桥梁”,是一个“中间件”。是实现跨平台的关键,java代码首先被编译成字节码文件,再由jvm将字节码文件翻译成机器语言,从而达到运行java程序的目的。

注意:编译的结果不是生成机器码,而是生成字节码,字节码不能直接运行,必须通过JVM翻译成机器码才能运行。不同平台下编译生成的字节码是一样的,但是由JVM翻译成的机器码却是不一样的。

 

  所以,运行JAVA程序必须有JVM支持,因为编译的结果不是机器码,必须要经过JVM的再次翻译才能执行。即使你讲JAVA程序打包成可执行文件(例如.exe),仍然需要JVM的支持。

注意:

跨平台的是Java程序,不是JVM。JVM是用C\C++开发的,是编译后的机器码,不能跨平台,不同平台下需要安装不同版本的JVM。

 

 java可以进行跨平台运行时,因为提前编译成了.class文件。安装不同环境下的jvm就可以运行这份文件。而c或者c++可以跨平台是因为:在不同的类库下载不同的类库信息,比方说在win下,就下载win下的类库,在linux下,就下载linux中的类库,实现跨平台。

七、为什么java被称作是“平台无关的编程语言”?

  java虚拟机是一个可执行java字节码的虚拟机进程。

  • Java源文件(.java)被编译成能被java虚拟机执行的字节码文件(.class)
  • Java被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每一个平台单独重写或者是重新编译。java虚拟机让这个变成可能,因为他知道底层硬件平台的指令长度和其他特性。

八、JDK各版本的新特性?

  JDK8引入了Lambda表达式和集合之流式操作。

九、Java和C++的区别?

  • 都是面向对象的语言,都支持继承、封装和多态。
  • Java不提供指针来直接访问内存,程序内存更加安全。
  • Java的类是单继承的,C++支持多重继承;虽然java的类不可以多继承,但是接口可以多继承。
  • java有自动内存管理机制,不需要程序员手动释放无用的内存信息。

十、什么是字节码?采用字节码的最大好处是什么?

  java中引入了虚拟机的概念,即在机器和编译程序之间加入一层抽象的虚拟的机器,这台虚拟的机器在任何平台上都提供给编译程序一个共同的接口。

  编译程序只需要面向虚拟机,生成虚拟机能够理解的代码,然后由解释器来将虚拟机代码转换成特定系统的机器码执行。在java中,这种提供虚拟机理解的代码叫做字节码(即拓展名为.class的文件),它不面向任何特定的理解器,只面向虚拟机。

  每一种平台的解释器是不同的,但是实现的虚拟机是相同的。java源程序经过编译器编译后变成字节码,字节码由虚拟机解释执行,虚拟机将每一条要执行的字节码送给解释器,解释器将其翻译成特定机器上的机器码,然后在特定的机器上运行,这也就是解释了java的编译与解释并存的特点。

Java源代码=》编译器=〉JVM可执行的Java字节码(即虚拟机指令)=》JVM=〉JVM中解释器=》机器可执行的二进制机器吗=〉程序运行。

 

 

  采用字节码的好处?

  java语言通过字节码的方法,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以Java程序运行的比较高效,而且,由于字节码并不专对一种特定的机器,因此,java程序无须重新编译便可在多种不同的机器上运行。

解释型语言:是在运行的时候将程序翻译成机器语言。解释型语言的程序不需要在运行前编译,在运行程序的时候才翻译,专门的解释器负责在每个语句执行的是欧解释程序代码。这样解释型语言每执行一次就要翻译一次,效率比较低。
例如:Python、PHP

十一、Java中的几种基本数据类型是什么?各占用多少字节?

基本的数据类型如下:

  • 整数值型:byte、short、int、long
  • 字符型:char
  • 浮点型:float、double
  • 布尔型:boolean
  • 整数型:默认为int型,小数默认是double型。Float和Long类型的必须加后缀。比如:float f=100f;

  byte:   1字节  -128--127

  short:  2字节   -32768 -- 32767

  int:  4个字节   -2147483648  -- 2147483647(超过20亿)

  long: 8个字节   -9223372036854775808  -- 9223372036854775807

  注:java中所有的数据类所占据的字节数量与平台无关,java也没有任何无符号类型

应用数据类型:

  类class,数组array,接口interface

基本数据类型和应用数据类型的区别:基本数据类型被分配到栈中,引用数据类型被分配到堆中。

但是不论是基本数据类型,还是引用数据类型都会进入栈,被分配一块内存,对于基本数据类型来说,这块区域包含的就是基本数据类型的内容,而引用数据类型在这块区域中包含的是指向真正内容的指针,真正的内容被手动的分配在堆上.

 什么是数值提升?

数值提升指的是数据从一个较小的数据类型转换位一个更大的数据类型

Byte、char、short值会被转化成int类型,需要的时候int类型也可以被提升位long类型,long类型和float则可能会被提升为double类型。

什么是隐式转换?什么是显式转换?

隐式转换:自动类型强转,数字表示范围小的数据类型可以自动转成范围大的数据类型。

显式转换:就是强制类型转换,就是大范围的变量能够接收小范围的数据

 

十二、引用类型

  声明的变量是指该变量在内存中实际存储的是一个引用地址,实体在堆中

  • 引用类型包括类、接口、数组等。
  • 特别注意:String是引用类型不是基本类型。

十三、什么是值传递和引用传递?

  • 值传递,是对基本型变量而言,传递的是该变量的一个副本,改变副本不影响原变量。
  • 引用传递,一般是对于对象型变量而言的,传递的是该对象地址的一个副本,并不是原对象本身。

  一般认为,java内的传递都是值传递,java中实例对象的传递是引用传递。

十四、是否可以在static环境中访问非static变量?

  static变量在java中是属于类的,它在所有的实体中的值都是一样的。当类被java虚拟机载入的时候,会对static变量进行初始化。

  如果你的代码尝试不用实例来访问非static的变量,编译器会报错,因为这些变量还没有被创建出来。还没有跟任何实例关联上。

十五、char型变量中能不能存储一个中文汉字?为什么?

  • 在C语言中,char类型占1个字节,而汉字占2个字节,所以不能存储。
  • 在java语言中,char类型占2个字节,而且java默认采用unicode编码,一个unicode码是16位,所以一个unicode码占两个字节,java中无论汉字还是英文字母,都是Unicode编码来表示的,所以在java中,char类型变量可以存储一个中文汉字。

十六、String、StringBuffer、StringBuilder的区别?

  java平台提供了两种类型的字符串:String和StringBuffer\StringBuilder,他们可以存储和操作字符串。

  • String,是只读字符串,也就意味着String引用的字符串内容是不能被改变的。
每次对String类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String对象。
  • StringBuilder\StringBuffer,表示的字符串对象可以直接进行修改。StringBuilder是java5中引入的,它和StringBuffer的方法完全相同,区别在于它是在单线程环境下使用的,因为他的所有方面都没有被synchronized修饰,因此它的效率也比StringBuffer高。
StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。
相同情况下使用StringBuilder相比使用StringBuffer仅能获得10%-15%左右的性能提升,但却要冒着多线程不安全的风险。

对于三者的使用总结?

  • 操作少量的数据=String
  • 单线程操作字符串缓冲区下操作大量数据=StringBuilder。
甚至有时候,我们为了避免每个线程重复创建StringBuilder对象,会通过ThreadLocal+StringBuilder的方式,进行对StringBuilder的重用。
  • 多线程环境下操作字符串缓冲区操作大量数据=StringBuffer
实际场景下,我们基本上不会出现,多线程操作同一个StringBuffer对象。

十六、String s=new String(“xyz”)会创建几个对象?

  • 首先,在String池内找,找到“xyz”字符串,不创建“xyz”对应的String对象,否则创建一个对象。
  • 然后,遇到new关键字,在内存上创建String对象,并将其返回给s,又一个对象。

即:如果常量池中没有“xyz”则创建两个对象,如果有“xyz”则创建一个对象。

十七、String为什么是不可变的?

  简单的来说,String类中使用final关键字字符数组保存字符串。

// String.java
private final char[] value;
  • 所以String对象是不可变的。

而StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串char[] value,但是没有用final关键字修饰。

// AbstractStringBuilder.java
char[] value;
  • 所以这两种对象都是可变的。

十八、StringTokenizer是什么?

  StringTokenizer,是一个用来分割字符串的工具类。

StringTokenizer st = new StringTokenizer(”Hello World”);
 while (st.hasMoreTokens()) { 
    System.out.println(st.nextToken()); }

输出:

Hello
World

十九、什么事自动拆装箱?

  自动装箱和拆箱,就是基本类型和引用类型之间的转换。

为什么要转换?

  如果你在java5下进行过编程的话,你一定不会陌生这一点,你不能直接地向集合(Collection)中放入原始类型值,因为集合只接收对象。

  • 通常这种情况下你的做法是:将这些原始类型的值转换成对象,然后将这些转换的对象放入集合中,使用Integer、Double、Boolean等这些类,我们可以将原始类型值转换成对应的对象,但是从某些程度可能使得代码不是那么简洁精炼。
  • 为了让代码简练,java5引入了具有在原始类型和对象类型自动转换的装箱和拆箱机制。
  • 但是自动装箱和拆箱并非完美,在使用的时候需要注意一些事项,如果没有搞明白自动装箱和拆箱,可能会引起难以察觉的Bug。

int和Integer有什么区别?

  • int是基本数据类型。
  • Integer是其包装类,注意是一个类。
  • Integet会缓存一些数据
    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() {}
    }

二十、equals与==的区别?

  • 值类型(基本的数据类型)
    • 都是使用==判断相等性。
  • 对象的话
    • ==判断引用所指的对象是否为同一个。
    • equals方法,是Object的成员函数,有些类会覆盖(override)这个方法,用于判断对象的等价性。
例如:String类,两个引用所指向的String都是“abc”,但可能出现他们实际对应的对象并不是同一额(和JVM实现方式有关),因此用==判断他们可能不想等,但是用equals方法判断一定是相等的。

二十一、如何在父类中为子类自动完成所有的hashcode和equals实现?这么做有什么优劣?

父类的equals,一般情况下是无法满足子类的equals的需求的。

  • 比如所有的对象都继承object,默认使用的是object的equals方法,在比较两个对象的时候,是看他们是否指向同一个地址。但是我们的需求是对象的某个属性相同,就相等了,而默认的equals方法满足不了当前的需求,所以我们需要重写equals方法。
  • 如果重写了equals方法,就必须重写hashcode方法,否则就会降低Map等集合的索引速度。

二十二、说一说你对java.lang.Object对象中hashcode和equals方法的理解,在什么场景下需要重新实现这两个方法?

这样的a.hashcode()有什么用?与a.equals(b)有什么关系?

  1.equals方法,用于比较对象的内容是否相等。

当覆盖了equals方法时,比较对象是否相等将通过覆盖后的equals方法进行比较(判断对象的内容是否相等)

  2.hashcode方法,大多在集合中用到。

将对象放入到集合中,首先判断要放入对象的hashcode值与集合中的任意一额元素的hashcode值是否相等,如果不想等直接将对象放入集合中。
如果hashcode值相等,然后再通过equals方法判断要放入对象与集合中的任意一个对象是否相等,如果equals相等,直接将该元素放入到集合中,否则不放入。

有没有可能2个不想等的对象有相同的hashcode?

可能会发生,这个被称为哈希碰撞,当然,相等的对象,即我们重写了equals方法,一定也要重写hashcode方法,否则将出现我们再hashmap中,相等的对象作为key,将找不到对应的value。

所以说:

  • equals不相等,但是hashcode可能会相等。
  • equals相等,请重写hashcode方法,保证hashcode相等。

 二十三、final、finally、finalize的区别?

1)final

final,是修饰符关键字。

  • 如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承,因此一个类不能既被声明为abstract的,又被声明为final的。
  • 将变量或者方法声明为final,可以保证他们在使用中不被修改。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重写。
另外,在早期的java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升(现在的java版本已经不需要使用final方法进行这些优化了)。类中所有的private方法都隐式被指定为final。

总结:

  1. 用来修饰数据,包括成员变量和局部变量,该变量只能被赋值一次且它的值无法被改变。对于成员变量来说,必须在声明时或者构造方法中对它赋值。
  2. 修饰方法:表示该方法无法被重写。
  3. 修饰类:表示类无法被继承。

 

2)finally

在异常处理时提供finally块来执行任何清除操作。如果抛出一个异常,那么相匹配的catch子句就会执行。然后控制就会进入finally块(如果有的话)

以下4种特殊情况下,finally块不会被执行:

  • 在finally语句块中发生了异常。
  • 在前面的代码中用了system.exit()退出程序。
  • 程序所在的线程死亡。
  • 关闭CPU

3)finalize

finalize,是方法名。

java允许使用finalize()方法,在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。

  • 它是在Object类中定义的,因此所有的类都继承了它。
  • 子类覆盖finalize()方法,以整理系统资源或者执行其他清理工作。
  • finalize()方法,是在垃圾收集器删除对象之前对这个对象调用的。

String类能被继承吗?为什么?

不能,因为String类被final修饰了。

二十四、抽象类和接口有什么区别?

从设计层面说:抽象是对类的抽象,是一种模版设计,接口是行为的抽象,是一种行为的规范:

  • 接口中的方法都是抽象的,而抽象类中可以是抽象的,也可以是非抽象的。
  • 接口中的变量都是final修饰,而抽象类中可以包含非final的变量。
  • 接口中的成员函数默认是public的,抽象类的成员函数可以是private、protected或者是public
  • 接口是绝对抽象的,不可以被实例化,抽象类也不可以被实例化,但是,如果抽象类中包含了main()方法,这个方法是可以被调用的。
  • 抽象类可以在不提供接口方法实现的情况下实现接口。
  • 类可以实现很多接口,但是只能继承一个抽象类,类可以不实现抽象类和接口声明的所有方法,当然,在这种情况下,类也必须得声明称是抽象的。

抽象类不能被实例化那他的构造器是用来干什么的?

  子类继承抽象类的时候,构造函数不会被覆盖。在实例化子类对象时首先调用的是抽象类中的构造函数再调用子类中的。

 

二十五、继承和组合的区别在哪里?

  • 继承:指的是一个类(称为子类、子接口)继承另外一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力,继承是类与类或者接口与接口之间最常见的关系。在java中,此类关系通过关键字extends明确标识,在设计时也一般没有争议性。
  • 组合:组合时关联关系的一种特例,他体现的是整体与部分、拥有的关系,即has-a的关系,此时整体与部分之间是可分离的。他们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享。

二十六、讲讲类的实例化顺序?

  • 父类静态变量
  • 父类静态代码块
  • 子类静态变量
  • 子类静态代码块。
  • 父类非静态变量
  • 父类构造函数
  • 子类非静态变量
  • 子类构造函数。

 二十七、什么是内部类?

就是在一个类、接口或者方法的内部创建另一个类。

内部类的作用是什么?

内部类提供了更好的封装,除了该外围类,其他类都不能访问。

Anonymous Inner Class(匿名内部类)是否可以继承其他类?是否可以实现接口?

可以继承其他类或者实现其他接口,在java集合的流式操作中,我们常常这么做。

内部类可以引用它的包含类(外部类)的成员么?有没有什么限制?

一个内部类对象可以访问创建它的外部类对象的成员,包括私有成员。

二十八、什么事java io?

javaio 相关的类,在java.io包下,具体操作分成面向字节(Byte)和面向字符(Character)两种方式。如下图所示:

 

 

 

二十九、什么是java序列化?

序列化就是一种用来处理对象流的机制,所谓对象流就是将对象的内容进行流化。

  • 可以对流化后的对象进行读写操作,也可将流化后的对象用于网络之间的传输。
  • 序列化是为了解决在对对象流进行读写操作时引发的问题。

反序列化的过程,则是和序列化相反的过程。

我们不能将序列化局限在java对象转成二进制数组,例如说,我们将一个java对象,转成json字符串,或者xml字符串,这也可以理解为序列化。

如何实现序列化?

将需要被序列化的类,实现Serializable接口,该接口没有需要实现的方法,implement Serializable只是为了标注对象是可以被序列化的。

  • 序列化
    • 使用输出流:fileOutputStream来构造一个ObjectOutputStream对象
    • 接着,使用ObjectOutputStream对象的writeobject(Object object)方法,就可以将参数为obj的对象写出
  • 反序列化
    • 要恢复的话则使用输入流。

java序列化中,如果有些字段不想进行序列化怎么办?

对于不想进行序列化的变量,使用transient关键字进行修饰

  • 当对象被序列化时,阻止实例中那些用此关键字修饰的变量序列化。
  • 当对象被反序列化时,被transient修饰的变量值不会被持久化和恢复。
  • transient只能修饰变量,不能修饰类和方法。

三十、如何实现对象的克隆?

一般来说,有两种方式:

  • 实现cloneable接口,并重写Object类中的clone()方法,可以实现浅克隆,也可以实现深克隆
  • 实现Serializable接口,通过对象的序列化和反序类化实现克隆,可以实现真正的深克隆。

三十一、error和exception有什么区别?CheckedException和RuntimeException有什么区别?

java的异常体系,基于共同的祖先java.lang.Throwable类,如下图所示:

 

 

 

1. 图中的 ArrithmeticException 异常,多了一个 r ,正确拼写是 ArithmeticException 。 2. 图中 ClassNotFoundException 异常,父类是 ReflectiveOperationException => Exception ,
不属于 RunTimeException 。
  • Error(错误)表示系统级的错误和程序不必处理的异常,是java运行环境中的内部错误或者硬件问题。
    • 例如:内存资源不足。
    • 对于这种错误,程序基本无能为力,除了退出运行外别无选择,它是由java虚拟机抛出的。
  • Exception(异常)表示需要捕捉或者需要程序处理的异常,它处理的是因为程序设计的瑕疵而引起的问题或者在外的输入等引起的一般性问题,是程序必须处理的。Exception分为运行时异常,受检查异常。
    • RuntimeException(运行时异常),表示无法让程序恢复的异常,导致的原因通常是因为执行了错误的操作,建议终止逻辑,因此,编译器不检查这些异常。
    • CheckedException(受检查异常),是表示程序可以处理的异常,也即表示程序可以修复(由程序自己接受异常并且做出处理),所以称之为受检查异常。

异常的使用的注意地方?

  • 不要将异常处理用于正常的控制流(设计良好的API不应该强迫它的调用者为了正常的控制流而使用异常)
  • 对可以恢复的情况使用受检查异常,对编程错误使用运行时异常。
  • 避免不必要的使用受检异常(可以通过一些状态检测手段来避免异常的发生)
  • 优先使用标准的异常
  • 每个方法抛出的异常都要有文档。
  • 保持异常的原子性。
  • 不要在catch中忽略掉捕获的异常。

Throwable类常用方法?

  • getMessage()方法:返回异常发生时的详细信息
  • getCause()方法:获得导致当前Throwable异常的Throwable异常。
  • getStackTrace()方法:获得Throwable对象封装的异常信息。
  • printStackTrace()方法:在控制台上打印。

请列举5个运行时异常?

  • NullPointerException
  • IndexOutOfBoundsException
  • ClassCastException
  • ArrayStoreException
  • BufffferOverflflowException

throw和throws的区别?

  • throw,用于在程序中显式地抛出一个异常。
  • throws,用于指出在该方法中没有处理的异常,每个方法必须显式指明那些异常没有处理,以便该方法的调用者可以预防可能方法的异常,最后,多个异常用逗号分隔。

异常处理中finally语句块的重要性?

不管程序是否发生了异常,finally语句块都会被执行,甚至当没有catch声明但抛出了一个异常时,finally语句块也会被执行。

finally语句块通常用于释放资源,如io缓冲区,数据库连接等等。

异常被处理后的异常对象会发生什么?

异常对象会在瑕疵GC执行时被回收。

三十二、说说反射的用途和实现?

java反射机制主要提供了以下功能:

  •  在运行时构造一个类的对象。
  • 判断一个类所具有的成员变量和方法
  • 调用一个对象的方法。
  • 生成动态代理

反射的应用很多,很多框架都用到:

  • Spring框架的IOC基于反射创建对象和设置依赖属性。
  • SpringMVC的请求调用对应的方法,也是通过反射。
  • JDBC的ClassForName(String className)方法,也是使用反射。

反射中,Class.forName和classLoader区别?

这两者,都可用来对类进行加载,差别在于:

  • Class.ForName(...)方法,除了将类的.class文件加载到JVM中之外,还会对类进行解释,执行类中的static块。
  • ClassLoader只干了一件事情,就是将.class文件加载到JVM中,不会执行static中的内容,只有在newinstance才会执行static块。
Class#forName(name, initialize, loader) 方法,带参函数也可控制是否加载 static 块,并
且只有调用了newInstance 方法采用调用构造函数,创建类的对象。

UnsupprotedOperationException是什么?

UnsuprotedOperationExcetion,是用于表明操作不支持的异常。

在JDK类中已被大量运用,在集合框架

架 java.util.Collections.UnmodifiableCollection 将会在所有 add和 remove 操作中抛出这个异常
三十三、什么时候用断言( assert )?
  断言,在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。
  一般来说,断言用于保证程序最基本、关键的正确性。断言检查通常在开发和测试时开启。为了保证程序的执行效率,在软件发布后断言检查通常是关闭的。
  断言是一个包含布尔表达式的语句,在执行这个语句时假定该表达式为 true ;如果表达式的值为 false ,那么系统会报告一个AssertionError 错误。断言的使用如下面的代码所示:
assert(a > 0); // throws an AssertionError if a <= 0

 

断言可以有两种形式:
  • assert Expression1; 。 
  • assert Expression1 : Expression2; 。
  • Expression1 应该总是产生一个布尔值。
  • Expression2 可以是得出一个值的任意表达式;这个值用于生成显示更多调试信息的字符串消息。
  要在运行时启用断言,可以在启动 JVM 时使用 -enableassertions 或者 -ea 标记。要在运行时选择禁用断言,可以在启动 JVM 时使用 -da 或者 -disableassertions 标记。要在系统类中启用或禁用断言,可使用 -esa 或 -dsa 标记。还可以在包的基础上启用或者禁用断言。
当然,实际场景下,我们会在 Spring 的源码中看到,它自己封装了 Assert 类,实现更方便的断言功能,并且,在生产环境下也启用。
另外,在单元测试中,也会使用自己封装的断言类,判断执行结果的正确与错误
三十四、对象创建的方式?
  • 1.使用new关键字创建对象。
  • 2.使用Class类的newInstance方法(反射机制)
  • 3.使用Construcetor类的newInstance方法(反射机制)
  • 4.使用clone方法创建对象
  • 5.使用(反)序列化机制创建对象。

三十五、简述path和pathclass的区别?

path是系统变量,跟java无关,里面存放的是各种可执行的应用程序的路径。

  ClassPath是java使用的,从字面上来理解,就是类的路径,主要是模仿path,将类文件的路径配置到classpath中实现在系统的任何位置可以对类文件进行编译和执行。

三十六、java的关键字中有没有goto?

  goto是java中的保留字不是关键字的一员

三十七、static关键字是什么意思?java中是否可以覆盖要给private方法或者static方法?

  static关键字表明一个成员变量或者是成员方法可以在没有所属的类的实例变量的情况下被访问。

  在java中static方法不能被覆盖,因为方法覆盖是基于运动时动态绑定的,而static方法是编译时静态绑定的,static方法跟类的任何实例都不相关。

三十八、构造器是否可以被overide?

Constructor(构造器)不能被继承,所以不能被override(重写),但是可以被overload(重载)

三十九、简述&和&&的区别?

  &和&&都可以用作逻辑与的运算符,标识逻辑与(and)。

  当运算符两边的表达式的结果都是true时,整个运算结果才位true,否则,只要由一方位false,则结果位false。

  &&还具有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式&,还可以用作位运算符。

四十、垃圾回收机制。

GC是什么?为什么有GC?

  GC是垃圾收集的意思。

  是指JVM用于释放那些不再使用的对象所占用的内存,垃圾回收可以有效的防治内存泄漏,有效的使用可以使用的内存,java由GC,就不需要人工释放内存空间了。

在java中,对象什么时候可以被垃圾回收?

  一般情况下,java中UI相爱那个可被回收的前提是:该对象不再被引用,然后垃圾回收器再回收的时候便会把这个对象清理掉。

java中会存在内存泄漏么?

  会存在,内存泄漏是指程序分配的堆内存未释放或者无法释放的现象。

  原因:长生命周期的对象持有短生命周期的对象的引用。

  java中内存泄漏的发生场景:全局的集合变量,不正确的单例模式的使用。

java中内存泄漏产生的原因可能有哪些?

  • 静态集合类引起的内存泄漏
  • 当集合里面的对象属性被修改后,再调用remove()方法时不起作用。
  • 监听器
  • 各种连接
  • 内部类和外部模块的引用。
  • 单例模式

java中垃圾回收的目的?什么时候进行回收?

垃圾回收的目的时:识别并且丢弃应用而不再使用的对象来释放和重用资源。

如果对象的引用被置为null,垃圾收集器是否会立即释放对象占用的内存?

不会,会在下一个垃圾回收周期中,这个对象才是可以被回收的。

垃圾回收机制有集中方法:标记清除,复制,标记整理,分代收集算法。

四十一、讲一讲java内存的堆(heep)、栈(stack)和方法(method)

栈:调用方法时,将会在栈中开辟出一片内存,称为入栈(压栈)。栈内存放基本数据类型值和引用数据类型的地址,栈内存中的数据,没有默认初始值,需要手动设置,方法调用完成后,栈内存立即释放,称为弹栈。

堆:用于存放使用new创建的对象和数组,所有的对象都有内存地址值,数据都有默认初始化值,堆内存中的对象不再被引用时,jvm启动垃圾回收机制,进行自动清除。

方法区:与java堆一样,各个线程共享的区域,存储已经被java虚拟机加在的类信息,常量,静态变量,和编译器编译后的代码等。

四十二、++i、i++、+=这些运算符的含义?

++i:先自增,后赋值。

i++:先赋值,再自增

+=: a+=b =》a=a+b

四十三、super()和this()的区别?

this表示对象本身,用来调用当前类的属性,方法,也可以调用从父类继承而来的未被重写,非私有的方法。

super表示当前对象类的父类对象部分,用来调用父类里的属性方法。

this和super用来调用构造器方法。

  • 不同点:super()从子类中调用父类的构造器,this()再同一类内调用其他构造方法。
  • 相同点:super()和this()都必须再构造函数的第一行进行调用,否则就是错误。

四十四、replace和replaceAll的区别?

  replace的参数是:char和charSwquence,即可以支持字符的替换,也支持字符串的替换(char和charsequence即字符串序列的意思,也就是字符串。)

  replaceAll参数是:regex。即基于正则表达式的替换,比如:可以通过replaceAll("\\d", "*")把一个字符串所有的数字字符都换成星号;

相同点:

  • 都是全部替换,即把源字符串中的某一字符 或者字符串全部换成指定的字符或者字符串。

不同点:

  • replaceAll支持正则表达式,因此会对参数进行解析(两个参数均是),如replaceAll("\\d", "*"),而replace则不会,replace("\\d","*")就是替换"\\d"的字符串,而不会解析为正则
  • “\”在java中是一个转义字符,所以需要用两个代表一个。例如System.out.println( "\\" ) ;只打印出一个"\"。但是“\”也是正则表达式中的转义字符,需要用两个代表一个。所以:\\\\被java转换成\\,\\又被正则表达式转换成\,因此用replaceAll替换“\”为"\\",就要用replaceAll("\\\\","\\\\\\\\"),而replace则replace("\\","\\\\")。

如果只是想替换第一次出现的,可以使用replaceFirst(),这个方法也是基于规则表达式的替换,但与replaceAll()不同的是,只替换第一次出现的字符串。

四十五、静态变量和成员变量的初始化时机?

  静态初始化只在Class独享首次被加载的时候进行一次。

  成员变量初始化,在new对象的时候被初始化,在构造函数的隐式三步其中一步进行初始化,初始化完成以后才会执行构造器中的代码。

四十六、while循环和do循环有什么不同?

  while结构在循环的开始判断下一个迭代是否应该继续。

  do\while结构在循环的结尾来判断是否继续下一轮迭代,do结构至少会执行一次循环体。

四十八、break和Continue?

  break常用于循环中,含义:结束循环,跳出循环体。

  其他应用场景:switch语句中,结束语句。

continue:结束本次循环,进入下一个循环中。

注意:如果循环进行到最后一次,continue执行,结束本次循环,继续进行循环,逻辑判断结束循环,循环结束与continue无关。

四十九、for循环和增强for哪一个遍历list集合更快?为什么?

ArrayList使用普通for循环效率更高,因为对于数组结构的数据来说,for循环采用的是下标访问。

但是LinkedList是通过链表实现的,for循环每次获取第i个元素都必须从头开始进行遍历,foreach是通过iterator实现的遍历,而iterator遍历就是从头开始遍历的,遍历完只需要一次,所以增强for效率更高。for和foreach循环效率差不多。for循环更加好一点,但是对于链表来说foreach的效率更高。

 五十、反射的原理及其应用?

原理:反射在程序运行时,能够动态的操作类的成员。

反射的前提:通过字节码获得class对象。

反射的操作:通过Class对象对构造Constructor,字段field,方法method进行动态操作。

反射的应用:框架底层都是用了反射。

 

posted @ 2020-09-27 21:56  King-DA  阅读(582)  评论(0编辑  收藏  举报