【Todo】Java类面试题分析

Java 面试中的重要话题

多线程,并发及线程基础
数据类型转换的基本原则
垃圾回收(GC)
Java 集合框架
数组
字符串
GOF 设计模式
SOLID (单一功能、开闭原则、里氏替换、接口隔离以及依赖反转)设计原则
抽象类与接口
Java 基础,如 equals 和 hashcode
泛型与枚举
Java IO 与 NIO
常用网络协议
Java 中的数据结构和算法
正则表达式
JVM 底层
Java 最佳实践
JDBC
Date, Time 与 Calendar
Java 处理 XML
JUnit
编程

http://www.codeceo.com/article/133-java-interview-5-years.html

1)Java 中能创建 Volatile 数组吗?
能,Java 中可以创建 volatile 类型数组,不过只是一个指向数组的引用,而不是整个数组。我的意思是,如果改变引用指向的数组,将会受到 volatile 的保护,但是如果多个线程同时改变数组的元素,volatile 标示符就不能起到之前的保护作用了。

http://blog.csdn.net/u013159040/article/details/51020218

JMM内存模型 

A:Easy,撸过~~~  注:写了这篇文章来跟进:http://www.cnblogs.com/charlesblc/p/6126551.html

OpenJDK

参考 https://www.zhihu.com/question/19646618 是区别于Oracle的JDK的在Linux上面的一个JDK版本。Oracle Java使用JRL(JavaResearch License),只能个人研究用;OpenJDK使用 GPL v2协议放出。

goto

1   在Java中,没有goto语句。因为大量使用goto语句会降低程序的可读性和可维护性,所以Java语言取消了goto的使用。同时,为了避免程序员自行使用goto所带来的混乱,Java语言仍将goto定义为一个关键字,但是没有定义任何语法,故称为“保留字”。

定义名称中的$

3   定义名称时尽量避免使用$,因为编译器在对.java文件进行编译的时候,会将”$”编译成顶层类型与底层类型的连接符。见下例:

package com.laixintao.Test;
 
public class Outer$Inner {
    public static void main(String[] args) {
        Outer o = new Outer();
        Outer.Inner i = o.new Inner();
        i.innerPrint();
    }
}
 
class Outer {
    class Inner {
        void innerPrint() {
            System.out.println("Inner Print!");
        }
    }
}

在编译(javac Test3.java)这段代码的时候,编译器会报以下错误:Test.java:12: 错误: 类重复: com.laixintao.Test.Outer.Inner class Inner{ ^

已实验,如下定义,的确会报错:

class Outer$Inner {

}

class Outer {
    class Inner {
    }
}

类型转换

从byte到char的转换为扩展收缩转换,该转换比较特殊,即先将byte扩展转换到int,然后再收缩到char。

注意char类型,这是一个无符号类型。因此,char与short或char与byte之间的转换必须显示地使用类型转换。

在整型数据间的扩展转换中,如果操作数是char类型(无符号类型),则进行无符号扩展,扩展位为0.如果操作数是byte,short或int(有符号类型),则进行有符号扩展,扩展位为该变量的符号位。

整型数据之间的收缩转换,仅仅是截断并丢弃高位,不做任何其他处理。

Java类型转换的内容详见:http://www.cnblogs.com/charlesblc/p/6132988.html

浮点数近似值

1) 0.1+0.2不等于0.3.System.out.println((double)0.1+(double)0.2);这条语句的输出结果是0.30000000000000004。因为计算机使用二进制来存储数据,而很多小数都不能够准确地使用二进制来表示(事实上,大多数地小数都是近似的),就像使用十进制小数不能准确地表示1/3这样地分数一样。

2) 大多数地浮点型,在计算机中只是近似地存储其值,而不像整型那样准确地存储。又例,这是一个死循环:for(float f = 10.1f;f != 11;f+=0.1f){}

3) float类型可以保留7~8个有效数字,而double类型可以保留15~16个有效数字,因而当int类型或long类型数值多于double或float地有效数字时,该值的一些最低有效位就会丢失,从而造成精度丢失,这时,就会采用IEEE754最近舍入模式,提取与该整型值最接近的浮点值。尽管整型向浮点型的转换属于扩展转换,但当数值很大或很小(绝对值很大)时,就会产生一定的精度丢失。

4) +0与-0在浮点类型变量存储中,符号位是不同的。当-0和+0参与浮点类型的相关运算(例如相除与求余运算)时,可以产生不同的结果。

5) 浮点的相除与求余运算不同与整型的相除与求余运算,当除数为0时,浮点运算不会产生ArithmeticException异常

注意看下面两个语句的区别。实验可以看出float打印出Infinity,而int报错。另外,数字直接赋值给float会报错,需要加上F

        float t = 5.0F/0.0F;
        System.out.println("Hello!" + t);
        int it = 5 / 0;
        System.out.println("Hello2!" + it);

得到结果:
Hello!Infinity

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at com.company.Main.main(Main.java:15)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

String

由于String对象是不可改变的,因此具有线程安全性,可以自由地实现共享。

String类是非可变类,其对象一旦创建,就不可销毁。String类那些看似修改字符序列的方法实际上都是返回新创建的String对象,而不是修改自身对象。

在String类内部,是使用一个字符数组(char[])来维护字符序列的。String的最大长度也就是字符数组的最大长度,理论上最大长度为int类型的最大值,即2147483647.在实际中,一般可获取的最大值小于理论最大值。

函数重载 

main()方法在表现行为上,与其他方法基本相同,可以重载,由其他方法调用,继承,隐藏,也可以抛出异常,带有类型参数。我们也可以在一个程序中通过反射来调用main方法(或其他方法)。

当两个或多个方法的名称相同,而参数列表不同时,这几个方法就构成了重载。重载方法可以根据参数列表对应的类型与参数的个数来区分,但是,参数的名称、方法的返回类型,方法的异常列表与类型参数不能作为区分重载方法的条件。

究竟选择哪个方法调用,顺序是这样的:

在第一阶段,自动装箱(拆箱)与可变参数不予考虑,搜索对应形参类型可以匹配实参类型并且形参个数与实参个数相同的方法;

如果在步骤一不存在符合条件的方法,在第二阶段,自动装箱与拆箱将会执行。

如果在步骤二中不存在符合条件的方法,在第三阶段,可变参数的方法将会考虑。

如果3个阶段都没有搜索到符合条件的方法,将会产生编译错误。如果如何条件的方法多于一个,将会选择最明确的方法。
最明确的方法定义为:如果A方法的形参列表类型对应的都可以赋值给B方法的形参列表类型,则A方法比B方法明确。如果无法选出最明确的方法,则会产生编译错误。

函数重写与隐藏

注:重写是父类子类之间的。重载是同一个类的各个函数之间的。Overwrite和Overload的区别。

重写和隐藏的区别、比较和代码示例,可以参考我的这篇文章:http://www.cnblogs.com/charlesblc/p/6133605.html

构造器

构造器是递归调用的,子类的构造器会调用父类的构造器,直到调用Object类的构造器为止。

构造器是使用new创建对象时由系统调用的,用来初始化类的实例成员。从顺序上说,先是创建对象,然后再调用构造器的。(构造器并没有产生新的对象)

构造器会调用父类的无参构造器,并可能执行实例成员变量的初始化。所以,默认的构造器至少调用了父类的构造器,它做的工作还可能更多,包括实例变量声明初始化与实例初始化块,都是在构造器中执行的。

比较

当==或!=运算符的两个操作数的类型一个是基本数据类型,另一个是包装类引用类型时,将引用类型拆箱转换为基本数据类型,然后比较两个基本数据类型的值是否相等。

数组

在Java中,数组也是类,数组声明的引用变量指向数组类型的对象。所有的数组都继承Object类,并且实现了java.lang.Cloneable与java.io.Serializable接口。数组的成员包括变量length(隐式存在)与从Object类继承的成员。Cloneable与Serializable是两个标记的接口,这两个接口中没有显式声明任何成员。

接口

接口是完全抽象的设计,不能实例化。使A用new方式创建的借口类型,实际上是创建了一个匿名类,该匿名类实现了接口类型。

命名冲突:

如果两个接口声明了相同的变量x,则当某接口同时继承这两个接口,或者某类同时实现这两个接口时,通过简单名称访问会产生编译错误。

如果两个接口中声明了相同名称的方法m,并且两个方法没有构成重载,则当某接口能够同时继承这两个接口,或者某类能够同时继承这两个接口时,必须存在一种方法签名,使得该签名同时为两个m方法签名的子签名,并且在方法的返回类型上,必须存在一种类型,使得该类型同时为两个m方法返回类型的可替换类型。

Java多线程

参考这篇文章:http://www.cnblogs.com/charlesblc/p/6135488.html

Java内存模型

参考这篇文章:http://www.cnblogs.com/charlesblc/p/6126551.html

原文地址:https://www.cnblogs.com/charlesblc/p/6126535.html