zoukankan      html  css  js  c++  java
  • Java面试必知必会:基础

    面试考察的知识点多而杂,要完全掌握需要花费大量的时间和精力。但是面试中经常被问到的知识点却没有多少,你完全可以用 20% 的时间去掌握 80% 常问的知识点。

    一、基础

    包括:

    • 杂七杂八
    • 面向对象
    • 数据类型
    • String
    • 异常
    • IO
    • 反射
    • 泛型
    • 更多题目

    杂七杂八

    1. Java的优点

    • 平台无关性
    • 相对安全的内存管理与访问机制,可以避免大部分内存泄漏和指针越界
    • 完善的程序应用接口,支持第三方类库

    2. Java 如何实现平台无关?

    JVM:

    Java 编译器可生成与计算机体系结构无关的字节码指令,字节码文件不仅可以轻易地在任何机器上解释执行,还可以动态地转换成本地机器代码,转换是由 JVM 实现的,JVM 是平台相关的,屏蔽了不同操作系统的差异。

    语言规范

    基本数据类型大小有明确规定,例如 int 永远为 32 位,而 C/C++ 中可能是 16 位、32 位,也可能是编译器开发商指定的其他大小。Java 中数值类型有固定字节数,二进制数据以固定格式存储和传输,字符串采用标准的 Unicode 格式存储。

    3. JDK 和 JRE 的区别?

    • JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境。

    • JRE:Java Runtime Environment 的简称,java 运行环境,为 java 的运行提供了所需环境。

    具体来说 JDK 其实包含了 JRE,同时还包含了编译 java 源码的编译器 javac,还包含了很多 java 程序调试和分析的工具。简单来说:如果你需要运行 java 程序,只需安装 JRE 就可以了,如果你需要编写 java 程序,需要安装 JDK。

    4. Java 按值调用还是引用调用?

    • 按值调用指方法接收调用者提供的值,将不会影响到实际参数
    • 按引用调用指方法接收调用者提供的变量地址,将会影响到实际参数

    Java 总是按值调用!Java中不存在引用调用

    区别如下:

    值传递 引用传递
    根本区别 会创建副本 不创建副本
    所以 函数中无法改变原始对象 函数中可以改变原始对象

    更详细参考:https://blog.csdn.net/weixin_41838721/article/details/109774982 (似乎最后的举例有点不恰当)

    5. 访问修饰符public,private,protected,以及不写(默认)时的区别?

    修饰符 当前类 同包 子类 其他包
    public
    protected ×
    default × ×
    private × × ×

    6. ==和equals的区别?(这种题一般会丢个实例让你分析)

    • 首先,==是关系运算符,equals() 是方法,结果都返回布尔值

    • 其次,他们比较的方式不同

    • == :如果比较的是数值,则比较两个数值是否相等;如果比较的是引用类型,则比较的是引用类型的变量指向的地址是否相等。

    • equals():用来比较方法两个对象的内容是否相等

    • 代码示例如下:

      1String x = "string";
      2String y = "string";
      3String z = new String("string");
      4System.out.println(x==y); // true
      5System.out.println(x==z); // false
      6System.out.println(x.equals(y)); // true
      7System.out.println(x.equals(z)); // true
    • 因为 x 和 y 指向的是同一个引用,所以 == 也是 true,而 new String()方法则重写开辟了内存空间,所以 == 结果为 false,而 equals 比较的一直是值,所以结果都为 true。

    • 总的来说,== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重写了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。

    7. hashCode()相同,equals()也一定为true吗?

    答案肯定是不一定。同时反过来 equals() 为true,hashCode() 也不一定相同。

    • 两个对象相等,hashcode一定相等
    • 两个对象不等,hashcode不一定不等
    • hashcode相等,两个对象不一定相等
    • hashcode不等,两个对象一定不等

    8. 浅拷贝和深拷贝的区别?

    • 浅拷贝: 只复制当前对象的基本数据类型及引用变量,没有复制引用变量指向的实际对象。修改克隆对象可能影响原对象,不安全。
    • 深拷贝: 完全拷贝基本数据类型和引用数据类型,安全。

    9. final 在 java 中有什么作用?

    • final 修饰的类叫最终类,该类不能被继承。

    • final 修饰的方法不能被重写。

    • final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。

    面向对象

    1. 面向对象特征有哪些方面?

    面向对象的特征主要有一下方面

    1. 继承:继承是从已有类得到的类的信息创建新类的过程。提供继承信息的被成为父类(基类),得到继承信息的被称为子类

    2. 封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。

    3. 多态:多态性是指允许不同子类型的对象对同一消息做出不同的响应。简单来收就是用同样的方法做出不同的事情。
      分为:方法重载(overload),方法重写(override)

    4. 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象(方法抽象),抽象只关注对象有哪些属性和行为,不关注行为的细节是什么。

    2.重载(overload)和重写(override)的区别?重载的方法是否能根据返回值类型来区分?

    • 重载的规则:
    • 方法名一致,参数列表中的参数顺序,类型,个数不同。
    • 重载与方法的返回值无关,存在于父类和子类,同类中
    • 可以抛出不同的异常,可以有不同的修饰符。
    • 重写的规则:
    • 参数列表必须完全与被重写的方法一致(父类的方法),返回值类型必须完全与父类的返回值一致。
    • 构造方法不能被重写,声明为final的方法不能被重写,声明为static的方法不能被重写,但可以被再次声明。
    • 访问权限不能比父类重写的访问权限低。
    • 重写的方法能够抛出任何非运行时异常(UncheckedException)。
    • 区别:重载是编译时的多态性,重写是运行时的多态性。重载发生在一个类中,同名的方法如果有不同的参数列表,则视为被重载;重写发生在子类和父类之间,重写的子类要求和父类的方法返回值的类型一致。重载对返回值没有特殊要求。

    3. Object 类有哪些方法?

    equals:检测对象是否相等,默认使用 == 比较对象引用,可以重写 equals 方法自定义比较规则。equals 方法规范:自反性、对称性、传递性、一致性、对于任何非空引用 x,x.equals(null) 返回 false。

    hashCode:散列码是由对象导出的一个整型值,没有规律,每个对象都有默认散列码,值由对象存储地址得出。字符串散列码由内容导出,值可能相同。为了在集合中正确使用,一般需要同时重写 equals 和 hashCode,要求 equals 相同 hashCode 必须相同,hashCode 相同 equals 未必相同,因此 hashCode 是对象相等的必要不充分条件。

    toString:打印对象时默认的方法,如果没有重写打印的是表示对象值的一个字符串。

    clone:clone 方法声明为 protected,类只能通过该方法克隆它自己的对象,如果希望其他类也能调用该方法必须定义该方法为 public。如果一个对象的类没有实现 Cloneable 接口,该对象调用 clone 方***抛出一个 CloneNotSupport 异常。默认的 clone 方法是浅拷贝,一般重写 clone 方法需要实现 Cloneable 接口并指定访问修饰符为 public。

    finalize:确定一个对象死亡至少要经过两次标记,如果对象在可达性分析后发现没有与 GC Roots 连接的引用链会被第一次标记,随后进行一次筛选,条件是对象是否有必要执行 finalize 方法。假如对象没有重写该方法或方法已被虚拟机调用,都视为没有必要执行。如果有必要执行,对象会被放置在 F-Queue 队列,由一条低调度优先级的 Finalizer 线程去执行。虚拟机会触发该方法但不保证会结束,这是为了防止某个对象的 finalize 方法执行缓慢或发生死循环。只要对象在 finalize 方法中重新与引用链上的对象建立关联就会在第二次标记时被移出回收集合。由于运行代价高昂且无法保证调用顺序,在 JDK 9 被标记为过时方法,并不适合释放资源。

    getClass:返回包含对象信息的类对象。

    wait / notify / notifyAll:阻塞或唤醒持有该对象锁的线程。

    4. 内部类的作用是什么,有哪些分类?

    内部类可对同一包中其他类隐藏,内部类方法可以访问定义这个内部类的作用域中的数据,包括 private 数据。

    内部类是一个编译器现象,与虚拟机无关。编译器会把内部类转换成常规的类文件,用 $ 分隔外部类名与内部类名,其中匿名内部类使用数字编号,虚拟机对此一无所知。

    • 静态内部类: 属于外部类,只加载一次。作用域仅在包内,可通过 外部类名.内部类名 直接访问,类内只能访问外部类所有静态属性和方法。HashMap 的 Node 节点,ReentrantLock 中的 Sync 类,ArrayList 的 SubList 都是静态内部类。内部类中还可以定义内部类,如 ThreadLoacl 静态内部类 ThreadLoaclMap 中定义了内部类 Entry。
    • 成员内部类: 属于外部类的每个对象,随对象一起加载。不可以定义静态成员和方法,可访问外部类的所有内容。
    • 局部内部类: 定义在方法内,不能声明访问修饰符,只能定义实例成员变量和实例方法,作用范围仅在声明类的代码块中。
    • 匿名内部类: 只用一次的没有名字的类,可以简化代码,创建的对象类型相当于 new 的类的子类类型。用于实现事件监听和其他回调。

    5. 抽象类(abstract)和接口(interface)有什么区别?

    • 抽象类:

    • 抽象类可以定义构造器

    • 可以有抽象方法和具体方法

    • 接口的成员全都是public的

    • 抽象类中可以定义成员变量

    • 有抽象的方法的类必须声明为抽象类,而抽象类中未必要有抽象方法

    • 抽象类中可以包含静态方法

    • 一个类只能继承一个抽象类

    • 接口:

    • 接口不能定义构造器

    • 方法全部都是抽象方法

    • 抽象类中的成员可以是private,默认,protected,public

    • 接口定义的成员变量实际上都是常量

    • 接口中不能有静态方法

    • 一个类可以实现多个接口

    • 相同点:

    • 不能被实例化

    • 可以将抽象类和接口类型做为引用类型

    • 一个类如果继承了某个抽象类或者某个接口都需要对其中的抽象方法全部实现,否则该类需要被声明为抽象类。


    另一个版本


    • 抽象类可以有构造方法;接口中不能有构造方法。
    • 抽象类中可以有普通成员变量;接口中没有普通成员变量。
    • 抽象类中的抽象方法的访问权限可以是 public、protected 和 default;接口中的抽象方法只能是 public 类型的
    • 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量可以是任意访问权限;接口中变量默认且只能是 public static final 类型。
    • 一个类可以实现多个接口,用逗号隔开,但只能继承一个抽象类。
    • 接口不可以实现接口,但可以继承接口,并且可以继承多个接口,用逗号隔开。

    列个表


    接口和抽象类对实体类进行更高层次的抽象,仅定义公共行为和特征。

    语法维度 抽象类 接口
    成员变量 无特殊要求 默认 public static final 常量
    构造方法 有构造方法,不能实例化 没有构造方法,不能实例化
    方法 抽象类可以没有抽象方法,但有抽象方法一定是抽象类。 默认 public abstract,JDK8 支持默认/静态方法,JDK9 支持私有方法。
    继承 单继承 多继承

    数据类型

    1. Java 有哪些基本数据类型?

    数据类型 内存大小 默认值 取值范围
    byte 1 B(8位) (byte)0 -128 ~ 127
    short 2 B(16位) (short)0 -2^15^ ~ 2^15^-1
    int 4 B(32位) -2^31^ ~ 2^31^-1
    long 8 B(64位) 0L -2^63^ ~ 2^63^-1
    float 4 B(32位) 0.0F ±3.4E+38(有效位数 6~7 位)
    double 8 B(64位) 0.0D ±1.7E+308(有效位数 15 位)
    char 英文 1B,中文 UTF-8 占 3B,GBK 占 2B。 'u0000' 'u0000' ~ 'uFFFF'
    boolean 单个变量 4B / 数组 1B false true、false

    2. 自动装箱/拆箱是什么?

    每个基本数据类型都对应一个包装类,除了 int 和 char 对应 Integer 和 Character 外,其余基本数据类型的包装类都是首字母大写即可。

    • 自动装箱: 将基本数据类型包装为一个包装类对象,例如向一个泛型为 Integer 的集合添加 int 元素。
    • 自动拆箱: 将一个包装类对象转换为一个基本数据类型,例如将一个包装类对象赋值给一个基本数据类型的变量。

    比较两个包装类数值要用 equals ,而不能用 ==

    子问题:装箱和拆箱的执行过程(方法)?

    • 装箱是通过调用包装器类的valueOf 方法实现的
    • 拆箱是通过调用包装器类的xxxValue 方法实现的,xxx代表对应的基本数据类型。

    细节

    • 整型的包装类 valueOf 方法返回对象时,在常用的取值范围内,会返回缓存对象。(-128-127)
    • 浮点型的包装类 valueOf 方法返回新的对象。
    • 布尔型的包装类 valueOf 方法 Boolean类的静态常量 TRUE | FALSE。

    3. int和Integer的区别

    String

    1. String 是基本数据类型吗?

    不是。String 是引用类型,底层用 char 数组实现的。而且,String被final修饰,是不可变类。

    2. String 是不可变类为什么值可以修改?

    String 类和其存储数据的成员变量 value 字节数组都是 final 修饰的。对一个 String 对象的任何修改实际上都是创建一个新 String 对象,再引用该对象。只是修改 String 变量引用的对象,没有修改原 String 对象的内容。

    3. String a = "a" + new String("b") 创建了几个对象?

    常量和常量拼接仍是常量,结果在常量池,只要有变量参与拼接结果就是变量,存在堆。

    使用字面量时只创建一个常量池中的常量,使用 new 时如果常量池中没有该值就会在常量池中新创建,再在堆中创建一个对象引用常量池中常量。因此 String a = "a" + new String("b") 会创建四个对象,常量池中的 a 和 b,堆中的 b 和堆中的 ab。

    更详细的相关内容可以看我的[一文理解new String()创建几个对象]()

    4. String、StringBuffer、StringBuilder 的区别?

    • 可变不可变:

    • String:字符串常量,在修改时不会改变自身;若修改,等于重新生成新的字符串对象。

    • StringBuffer:在修改时会改变对象自身,每次操作都是对 StringBuffer 对象本身进行修改,不是生成新的对象;使用场景:对字符串经常改变情况下,主要方法:append(),insert()等。

    • 线程是否安全:

    • String:对象定义后不可变,线程安全

    • StringBuffer:是线程安全的(对调用方法加入同步锁),执行效率较慢,适用于多线程下操作字符串缓冲区大量数据。

    • StringBuilder:是线程不安全的,适用于单线程下操作字符串缓冲区大量数据。

    • 运行效率不同

    • String最慢

    • StringBuffer因为加入了同步锁,效率相比于StringBuilder慢,StringBuilder最快。

    • 共同点:

    • StringBuilder 与 StringBuffer 有公共父类 AbstractStringBuilder(抽象类)。

    • StringBuilder、StringBuffer 的方法都会调用 AbstractStringBuilder 中的公共方法,如 super.append(…)。只是 StringBuffer 会在方法上加 synchronized 关键字,进行同步。最后,如果程序不是多线程的,那么使用StringBuilder 效率高于 StringBuffer。

    5. 字符串拼接的方式有哪些?

    • 直接用 + ,底层用 StringBuilder 实现。只适用小数量,如果在循环中使用 + 拼接,相当于不断创建新的 StringBuilder 对象再转换成 String 对象,效率极差。
    • 使用 String 的 concat 方法,该方法中使用 Arrays.copyOf 创建一个新的字符数组 buf 并将当前字符串 value 数组的值拷贝到 buf 中,buf 长度 = 当前字符串长度 + 拼接字符串长度。之后调用 getChars 方法使用 System.arraycopy 将拼接字符串的值也拷贝到 buf 数组,最后用 buf 作为构造参数 new 一个新的 String 对象返回。效率稍高于直接使用 +
    • 使用 StringBuilder 或 StringBuffer,两者的 append 方法都继承自 AbstractStringBuilder,该方法首先使用 Arrays.copyOf 确定新的字符数组容量,再调用 getChars 方法使用 System.arraycopy 将新的值追加到数组中。StringBuilder 是 JDK5 引入的,效率高但线程不安全。StringBuffer 使用 synchronized 保证线程安全。

    6. String对象中的replace和replaceAll的区别?

    • 参数不同
    • replace方法:支持字符和字符串的替换。
    • replaceAll方法:基于正则表达式的字符串替换。
    • 替换不同
    • replace只替换第一个出现的字符
    • replaceall替换所有的字符

    异常

    1. error和exception的区别?

    共同点:Error和Exception的父类都是Throwable类;
    不同点:

    • error类一般值与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足;对于这类错误导致的应用程序中的,仅靠程序本身无法恢复和预防,遇到这类错误,建议让程序终止。
    • Exception 类又分为运行时异常(Runtime Exception)和受检查的异常(Checked Exception ),运行时异常;编译能通过,但是一运行就终止了,程序不会处理运行时异常,出现这类异常,程序会终止。而受检查的异常,要么用 try{}catch(){} 捕获,要么用 throws 字句声明抛出,交给它的父类处理,否则编译不会通过。

    2. throw 和 throws 的区别

    throw:

    • throw 语句用在方法体内,表示抛出异常,由方法体内的语句处理。
    • throw 是具体向外抛出异常的动作,所以它抛出的是一个异常实例,执行 throw 一定是抛出了某种异常.

    throws:

    • throws 语句是用在方法声明后面,表示如果抛出异常,由该方法的调用者来进行异常的处理
    • throws 主要是声明这个方法会抛出某种类型的异常,让它的使用者要知道需要捕获的异常的类型。
    • throws 表示出现异常的一种可能性,并不一定会发生这种异常。

    3. 你最常见的几个 RuntimeException

    • java.lang.NullPointerException 空指针异常;出现原因:调用了未经初始化的对象或者是不存在的对象。
    • java.lang.ClassNotFoundException 指定的类找不到;出现原因:类的名称和路径加载错误;通常都是程序试图通过字符串来加载某个类时可能引发异常。
    • java.lang.NumberFormatException 字符串转换为数字异常;出现原因:字符型数据中包含非数字型字符。
    • java.lang.IndexOutOfBoundsException 数组角标越界异常,常见于操作数组对象时发生。
    • java.lang.IllegalArgumentException 方法传递参数错误。
    • java.lang.ClassCastException 数据类型转换异常
    • java.lang.NoClassDefFoundException 未找到类定义错误。
    • SQLException SQL 异常,常见于操作数据库时的 SQL 语句错误。
    • java.lang.InstantiationException 实例化异常。
    • java.lang.NoSuchMethodException 方法不存在异常。

    4. final、finally、finalize 的区别?

    • final:用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,被其修饰的类不可继承。
    • finally:异常处理语句结构的一部分,表示总是执行。
    • finalize:Object 类的一个方法,在垃圾回收器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等

    IO

    1. 同步/异步/阻塞/非阻塞 IO 的区别?

    同步和异步是通信机制,阻塞和非阻塞是调用状态。

    同步 IO 是用户线程发起 IO 请求后需要等待或轮询内核 IO 操作完成后才能继续执行。异步 IO 是用户线程发起 IO 请求后可以继续执行,当内核 IO 操作完成后会通知用户线程,或调用用户线程注册的回调函数。

    阻塞 IO 是 IO 操作需要彻底完成后才能返回用户空间 。非阻塞 IO 是 IO 操作调用后立即返回一个状态值,无需等 IO 操作彻底完成。

    2. 什么是 BIO?

    BIO 是同步阻塞式 IO,JDK1.4 之前的 IO 模型。服务器实现模式为一个连接请求对应一个线程,服务器需要为每一个[客户端]()请求创建一个线程,如果这个连接不做任何事会造成不必要的线程开销。可以通过线程池改善,这种 IO 称为伪异步 IO。适用连接数目少且服务器资源多的场景。

    3. 什么是 NIO?

    NIO 是 JDK1.4 引入的同步非阻塞 IO。服务器实现模式为多个连接请求对应一个线程,[客户端]()连接请求会注册到一个多路复用器 Selector ,Selector 轮询到连接有 IO 请求时才启动一个线程处理。适用连接数目多且连接时间短的场景。

    同步是指线程还是要不断接收[客户端]()连接并处理数据,非阻塞是指如果一个管道没有数据,不需要等待,可以轮询下一个管道。

    核心组件:

    • Selector: 多路复用器,轮询检查多个 Channel 的状态,判断注册事件是否发生,即判断 Channel 是否处于可读或可写状态。使用前需要将 Channel 注册到 Selector,注册后会得到一个 SelectionKey,通过 SelectionKey 获取 Channel 和 Selector 相关信息。

    • Channel: 双向通道,替换了 BIO 中的 Stream 流,不能直接访问数据,要通过 Buffer 来读写数据,也可以和其他 Channel 交互。

    • Buffer: 缓冲区,本质是一块可读写数据的内存,用来简化数据读写。Buffer 三个重要属性:position 下次读写数据的位置,limit 本次读写的极限位置,capacity 最大容量。

    • flip 将写转为读,底层实现原理把 position 置 0,并把 limit 设为当前的 position 值。

    • clear 将读转为写模式(用于读完全部数据的情况,把 position 置 0,limit 设为 capacity)。

    • compact 将读转为写模式(用于存在未读数据的情况,让 position 指向未读数据的下一个)。

    • 通道方向和 Buffer 方向相反,读数据相当于向 Buffer 写,写数据相当于从 Buffer 读。

      使用步骤:向 Buffer 写数据,调用 flip 方法转为读模式,从 Buffer 中读数据,调用 clear 或 compact 方法清空缓冲区。

    4. 什么是 AIO?

    AIO 是 JDK7 引入的异步非阻塞 IO。服务器实现模式为一个有效请求对应一个线程,[客户端]()的 IO 请求都是由操作系统先完成 IO 操作后再通知服务器应用来直接使用准备好的数据。适用连接数目多且连接时间长的场景。

    异步是指服务端线程接收到客户端有数据才会处理,处理好再通知服务器。

    实现方式包括通过 Future 的 get 方法进行阻塞式调用以及实现 CompletionHandler 接口,重写请求成功的回调方法 completed 和请求失败回调方法 failed

    5. java.io 包下有哪些流?

    主要分为字符流和字节流,字符流一般用于文本文件,字节流一般用于图像或其他文件。

    字符流包括了字符输入流 Reader 和字符输出流 Writer,字节流包括了字节输入流 InputStream 和字节输出流 OutputStream。字符流和字节流都有对应的缓冲流,字节流也可以包装为字符流,缓冲流带有一个 8KB 的缓冲数组,可以提高流的读写效率。除了缓冲流外还有过滤流 FilterReader、字符数组流 CharArrayReader、字节数组流 ByteArrayInputStream、文件流 FileInputStream 等。

    泛型

    1. 什么是泛型,有什么作用?

    泛型本质是参数化类型,解决不确定对象具体类型的问题。泛型在定义处只具备执行 Object 方法的能力。

    泛型的好处:

    • 类型安全,放置什么出来就是什么,不存在 ClassCastException。
    • 提升可读性,编码阶段就显式知道泛型集合、泛型方法等处理的对象类型。
    • 代码重用,合并了同类型的处理代码。

    2. 泛型擦除是什么?

    泛型用于编译阶段,编译后的字节码文件不包含泛型类型信息,因为虚拟机没有泛型类型对象,所有对象都属于普通类。例如定义 List<Object>List<String>,在编译后都会变成 List

    定义一个泛型类型,会自动提供一个对应原始类型,类型变量会被擦除。如果没有限定类型就会替换为 Object,如果有限定类型就会替换为第一个限定类型,例如 <T extends A & B> 会使用 A 类型替换 T。

    反射

    1.什么是反射

    在运行状态中,对于任意一个类都能知道它的所有属性和方法,对于任意一个对象都能调用它的任意方法和属性,这种动态获取信息及调用对象方法的功能称为反射。缺点是破坏了封装性以及泛型约束。反射是框架的核心,Spring 大量使用反射。

    2. Class 类的作用?如何获取一个 Class 对象?

    在程序运行期间,Java 运行时系统为所有对象维护一个运行时类型标识,这个信息会跟踪每个对象所属的类,虚拟机利用运行时类型信息选择要执行的正确方法,保存这些信息的类就是 Class,这是一个泛型类。

    获取 Class 对象,若有Foo foo = new Foo();

    • 类名.class
    • Class c = foo.class;
    • 对象的 getClass方法。
    • Class c = foo.getClass();
    • Class.forName(类的全限定名)
    • Class c = Class.forName("XX.XX.Foo");

    补充

    反射实现的方式也包含了上述的三种,如果问如何获取一个class对象回答上面三种就可以了,如果问反射的实现方式,可以再补充下述两种:

    • 对于有空构造函数的类 可以直接用字节码文件获取实例:

    • Object o = clazz.newInstance();  // 会调用空参构造器 如果没有则会报错

    • 对于没有空的构造函数的类则需要先获取到他的构造对象 在通过该构造方法类获取实例:

    • java<br />Constroctor constroctor = clazz.getConstructor(String.class,int.class); // 获取构造函数<br />Object obj = constroctor.newInstance("jack", 18); // 通过构造器对象的newInstance方法进行对象的初始化<br />

    3. 实现Java反射的类/Java反射相关API:

    • Class:表示正在运行的Java应用程序中的类和接口,是反射的核心类,可以获取类的属性,方法等信息。
    • 注意: 所有获取对象的信息都需要Class类来实现。
    • Field:Java.lang.reflec 包中的类.提供有关类和接口的属性信息,以及对它的动态访问权限。
    • Constructor: Java.lang.reflec 包中的类,表示类的构造方法。提供关于类的单个构造方法的信息以及它的访问权限
    • Method: Java.lang.reflec 包中的类,表示类的方法,提供类或接口中某个方法的信息

    4. 反射机制的优缺点:

    • 优点
    • 能够运行时动态获取类的实例、成员变量、方法等,提高灵活性;
    • 与动态编译结合
    • 缺点
    • 使用反射性能较低,需要解析字节码,将内存中的对象进行解析。
    • 解决方案
    • 通过setAccessible(true)关闭JDK的安全检查来提升反射速度;
    • 多次创建一个类的实例时,有缓存会快很多

    5. 哪里会用到反射

    • JDBC
    • Class.forName('com.mysql.jdbc.Driver.class');//加载MySQL的驱动类
    • Spring框架
    • 依赖注入

    更多题目

    这属于一些场景题或不被常问的知识点, 答案放在Java面试必知必会(扩展)——Java基础

    • float f=3.4;是否正确?

    • &和&&的区别?

    • Math.round(11.5) 等于多少?Math.round(-11.5)等于多少?

    • switch 是否能作用在byte 上,是否能作用在long 上,是否能作用在String上?

    • 数组有没有length()方法?String有没有length()方法?

    • 在Java中,如何跳出当前的多重嵌套循环?

    • 构造器(constructor)是否可被重写(override)?

    • 两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?(考察对equals和hashcode掌握的熟不熟)

    • 是否可以继承String类?(考察String知识点)

    • 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?

    • char型变量能不能存储一个中文汉字,为什么?

    • 静态嵌套类(Static Nested Class)和内部类(Inner Class)的不同?

    • Java 中会存在内存泄漏吗,请简单描述。

    • 抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰?

    • 静态变量和实例变量的区别

    • 是否可以从一个静态(static)方法内部发出对非静态(no-static)方法的调用?

    • 如何实现对象克隆?

    • String s = new String("xyz");创建了几个字符串对象?

    • 接口是否可继承(extends)接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concrete class)?

    • 一个".java"源文件中是否可以包含多个类(不是内部类)?有什么限制?

    • 匿名内部类是否可以继承其它类?是否可以实现接口?

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

    • 如何将字符串转换为基本数据类型? 如何将基本数据类型转换为字符串?

    • 怎样将GB2312编码的字符串转换为ISO-8859-1编码的字符串?

    • try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后?

    • Java语言如何进行异常处理,关键字:throws、throw、try、catch、finally分别如何使用?

    • 列出一些你常见的运行时异常?

    • break和continue的区别?

  • 相关阅读:
    day01-python基础
    python3.5爬虫实例:根据网站的反爬虫策略,启用代理来防止爬虫被禁用
    python3.5爬虫实例:根据城市名称来获取该城市最近七天的天气预报
    python3.5爬虫基础urllib结合beautifulsoup实例
    python3.5爬虫基础urllib实例
    面向对象相关知识及常用操作(二)
    面向对象相关知识点及常见的操作
    常用的基础模块介绍
    利用正则表达式来实现求一个数学表达式的和
    正则表达式的方法及其匹配规则
  • 原文地址:https://www.cnblogs.com/kylinxxx/p/14525460.html
Copyright © 2011-2022 走看看