抽象类android我爱编程

面试相关--JAVA基础部分

2017-01-11  本文已影响184人  大弃

1.Java中的原始数据类型都有哪些,它们的大小及对应的封装类是什么?

数据类型 大小(字节) 内存空间(8位等于1字节) 包装类
byte 1 8位 Byte
char 2 16位 Character
short 2 16位 Short
int 4 32位 Integer
long 8 64位 Long
float 4 32位 Float
double 8 64位 Double
boolean - - Boolean
关于boolean的说明:

boolean数据类型非true即false。这个数据类型表示1 bit的信息,但是它的大小并没有精确定义。
《Java虚拟机规范》中如是说:“虽然定义了boolean这种数据类型,但是只对它提供了非常有限的支持。在Java虚拟机中没有任何供boolean值专用的字节码指令,Java语言表达式所操作的boolean值,在编译之后都使用Java虚拟机中的int数据类型来代替,而boolean数组将会被编码成Java虚拟机的byte数组,每个元素boolean元素占8位”。这样我们可以得出boolean类型单独使用是4个字节,在数组中又是1个字节。那虚拟机为什么要用int来代替boolean呢?为什么不用byte或short,这样不是更节省内存空间吗?实际上,使用int的原因是,对于当下32位的CPU来说,一次进行32位的数据交换更加高效。
综上,我们可以知道:官方文档对boolean类型没有给出精确的定义,《Java虚拟机规范》给出了“单独时使用4个字节,boolean数组时1个字节”的定义,具体还要看虚拟机实现是否按照规范来,所以1个字节、4个字节都是有可能的。这其实是一种时空权衡。

2.谈一谈”==“与”equals()"的区别。

《Think in Java》中说:“关系操作符生成的是一个boolean结果,它们计算的是操作数的值之间的关系”。

综上,对于枚举类型和原始数据类型的相等性比较,应该使用"==";对于引用类型的相等性比较,应该使用equals方法。

3.Java中的四种引用及其应用场景是什么?

4.Object中定义了哪些方法?

Object是所有类的父类,任何类都默认继承Object。

  1. 其他线程调用了该对象的notify方法
  2. 其他线程调用了该对象的notifyAll方法
  3. 其他线程调用了interrupt中断该线程
  4. 时间间隔到了

此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常

5.hashCode的作用是什么?

什么是HashCode,总结几个关键点:

  1. HashCode的存在主要是为了查找的快捷性,HashCode是用来在散列存储结构中确定对象的存储地址的
  2. 如果两个对象equals相等,那么这两个对象的HashCode一定也相同
  3. 如果对象的equals方法被重写,那么对象的HashCode方法也尽量重写
  4. 如果两个对象的HashCode相同,不代表两个对象就相同,只能说明这两个对象在散列存储结构中,存放于同一个位置

HashCode有什么用?举个例子:

  1. 假设内存中有0 1 2 3 4 5 6 7 8这8个位置,如果我有个字段叫做ID,那么我要把这个字段存放在以上8个位置之一,如果不用HashCode而任意存放,那么当查找时就需要到8个位置中去挨个查找
  2. 使用HashCode则效率会快很多,把ID的HashCode%8,然后把ID存放在取得余数的那个位置,然后每次查找该类的时候都可以通过ID的HashCode%8求余数直接找到存放的位置了
  3. 如果ID的HashCode%8算出来的位置上本身已经有数据了怎么办?这就取决于算法的实现了,比如ThreadLocal中的做法就是从算出来的位置向后查找第一个为空的位置,放置数据;HashMap的做法就是通过链式结构连起来。反正,只要保证放的时候和取的时候的算法一致就行了。
  4. 如果ID的HashCode%8相等怎么办(这种对应的是第三点说的链式结构的场景)?这时候就需要定义equals了。先通过HashCode%8来判断类在哪一个位置,再通过equals来在这个位置上寻找需要的类。对比两个类的时候也差不多,先通过HashCode比较,假如HashCode相等再判断equals。如果两个类的HashCode都不相同,那么这两个类必定是不同的

具体可以看以下文章:
谈谈HashCode的作用
散列表的原理与实现

6.ArrayList, LinkedList, Vector的区别是什么?

7.String, StringBuilder, StringBuffer的区别是什么?

8.Map, Set, List, Queue、Stack的特点及用法。

9.HashMap和HashTable的区别。

详细分析请参考深入解析HashMap、HashTable

10.HashMap的实现原理。

简单说,HashMap就是将key做hash算法,然后将hash所对应的数据映射到内存地址,直接取得key所对应的数据。在HashMap中。底层数据结构使用的是数组,所谓的内存地址即数组的下标索引。HashMap的高性能需要保证以下几点:

具体可参考从源码分析HashMap

11.ConcurrentHashMap的实现原理

ConcurrentHashMap是支持并发读写的HashMap,它的特点是读取数据时无需加锁,写数据时可以保证加锁粒度尽可能的小。由于其内部采用“分段存储”,只需对要进行写操作的数据所在的“段”进行加锁。关于ConcurrentHashMap底层实现的详细分析请参考Java并发编程:并发容器之ConcurrentHashMap

12.TreeMap, LinkedHashMap, HashMap的区别是什么?

13.Collection与Collections的区别是什么?

Collection是一个接口,它是Set、List等容器的父接口;Collections是一个工具类,提供了一系列的静态方法来辅助容器操作,这些方法包括对容器的搜索、排序、线程安全化等等。

14.Set、List、Map之间的区别是什么?

Collection是最基本的集合接口,Set 和List 都继承了Conllection,Map没有。

详细可参考java 中的Set,List,Map

15.特殊关键字:final

16.Switch能否用string做参数?

在Java7之前,switch只支持byte、short、char、int及其对应的封装类,以及Enum类型,在Java 7中,String类型被加上。

17.对于“try-catch-finally”,若try语句块中包含“return”语句,finally语句块会执行吗?

答案是会执行。只有两种情况finally块中的语句不会被执行:

18.泛型的优缺点

优点:

使用泛型类型可以最大限度地重用代码、保护类型的安全以及提高性能。

泛型最常见的用途是创建集合类。

缺点:

在性能上不如数组快。

19.Java中的异常层次结构

Java中的异常层次结构如下图所示:


java中的异常

我们可以看到Throwable类是异常层级中的基类。Error类表示内部错误,这类错误使我们无法控制的;Exception表示异常,RuntimeException及其子类属于未检查异常,这类异常包括ArrayIndexOutOfBoundsException、NullPointerException等,我们应该通过条件判断等方式语句避免未检查异常的发生。IOException及其子类属于已检查异常,编译器会检查我们是否为所有可能抛出的已检查异常提供了异常处理器,若没有则会报错。对于未检查异常,我们无需捕获(当然Java也允许我们捕获,但我们应该做的事避免未检查异常的发生)。

20.Interface与abstract类的区别。

抽象类和接口都不能够实例化,但可以定义抽象类和接口类型的引用。一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要被声明为抽象类。接口比抽象类更加抽象,因为抽象类中可以定义构造器,可以有抽象方法和具体方法,而接口中不能定义构造器而且其中的方法全部都是抽象方法。抽象类中的成员可以是private、默认、protected、public的,而接口中的成员全都是public的。抽象类中可以定义成员变量,而接口中定义的成员变量实际上都是常量。有抽象方法的类必须被声明为抽象类,而抽象类未必要有抽象方法。

21.Java面向对象的三个特征与含义。

三大特征:封装、继承、多态。

22.Override, Overload的含义与区别。

23.接口与抽象类的区别

接口是一种约定,实现接口的类要遵循这个约定;抽象类本质上是一个类,使用抽象类的代价要比接口大。接口与抽象类的对比如下:

24.静态内部类与非静态内部类的区别。

内部静态类不需要有指向外部类的引用。但非静态内部类需要持有对外部类的引用。非静态内部类能够访问外部类的静态和非静态成员。静态类不能访问外部类的非静态成员。他只能访问外部类的静态成员。一个非静态内部类不能脱离外部类实体被创建,一个非静态内部类可以访问外部类的数据和方法,因为他就在外部类里面。

25.Java中多态的实现原理。

所谓多态,指的就是父类引用指向子类对象,调用方法时会调用子类的实现而不是父类的实现。多态的实现的关键在于“动态绑定”。详细介绍请戳Java动态绑定的内部实现机制

详细可查看JAVA多态的实现原理(JVM实现方式)

26.简述Java中创建新线程的两种方法。

实现方式和继承方式有什么区别?

27.简述Java中进行线程同步的方法。

28.简述Java中具有哪几种粒度的锁

Java中可以对类、对象、方法或是代码块上锁。

更加详细的介绍请查看:Java核心技术点之多线程

29.给出“生产者-消费者”问题的一种解决方案。

public class BlockingQueueTest {
    
    private int size = 20;    
    private ArrayBlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(size); 
       
    public static void main(String[] args)  { 
            BlockingQueueTest test = new BlockingQueueTest();        
            Producer producer = test.new Producer();        Consumer consumer = test.new Consumer();                   producer.start();        
            consumer.start();    
    }
        
    class Consumer extends Thread{
        
        @Override        
        public void run() {             
            while(true){                
                try {                    
                    //从阻塞队列中取出一个元素
                    queue.take();                    
                    System.out.println("队列剩余" + queue.size() + "个元素");                
                } catch (InterruptedException e) {                                  
                }            
            }        
        }    
    } 
       
    class Producer extends Thread{                  

        @Override
        public void run() {            
            while (true) {                
                try {                    
                    //向阻塞队列中插入一个元素    
                    queue.put(1);                    
                    System.out.println("队列剩余空间:" + (size - queue.size()));                
                } catch (InterruptedException e) {                              
                }            
            }        
        }    
    }

}

30.ThreadLocal的设计理念与作用。

ThreadLocal的作用是提供线程内的局部变量,在多线程环境下访问时能保证各个线程内的ThreadLocal变量各自独立。也就是说,每个线程的ThreadLocal变量是自己专用的,其他线程是访问不到的。ThreadLocal最常用于以下这个场景:多线程环境下存在对非线程安全对象的并发访问,而且该对象不需要在线程间共享,但是我们不想加锁,这时候可以使用ThreadLocal来使得每个线程都持有一个该对象的副本。
关于ThreadLocal的实现原理分析请戳深入剖析ThreadLocal

31.concurrent包的整体架构。

concurrent包的整体架构

32.ArrayBlockingQueue, CountDownLatch类的作用.

33.wait(),sleep() 的区别

34.线程池的用法与优势

关于线程池的详细介绍以及实现原理分析请查看:深入理解java线程池—ThreadPoolExecutor

35.for-each与常规for循环的效率对比

关于这个问题我们直接看《Effective Java》给我们做的解答:
for-each能够让代码更加清晰,并且减少了出错的机会。下面的惯用代码适用于集合与数组类型:

for (Element e : elements) {
    doSomething(e);
}

使用for-each循环与常规的for循环相比,并不存在性能损失,即使对数组进行迭代也是如此。实际上,在有些场合下它还能带来微小的性能提升,因为它只计算一次数组索引的上限。

36.简述Java IO与NIO的区别

更进一步的说明请查看:Java NIO与IO

37.父类的静态方法能否被子类重写,为什么?

父类的静态方法可以被子类继承,也就是说子类可以调用父类的静态方法,但是不能重写。
可以写个例子进行验证:

父类代码:
public class Fu {  

    public static void show() {  

        System.out.println("父类的静态方法");  

    }  

    public void method() {  

        System.out.println("父类的普通方法");  

    }  

}

子类代码:
public class Zi extends Fu {  
    public static void main(String[] args) {  
        Fu fu = new Zi();  
        fu.show();  
        fu.method();  
    }  
    public static void show() {  
        System.out.println("子类的静态方法");  
    }  
    public void method() {  
        System.out.println("子类的普通方法");  
    }  
      
}  

输出的结果是:
  父类的静态方法
  子类的普通方法

38.反射的作用与原理

JAVA反射机制是在运行状态中, 对于任意一个类, 都能够知道这个类的所有属性和方法; 对于任意一个对象, 都能够调用它的任意一个方法和属性; 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制.

主要作用有三:

用处如下:

39.Java中的泛型机制

泛型:JDK1.5版本以后出现的新特性,用于解决安全问题,是一个类型安全机制。
其好处是:

泛型技术是给编译器使用的技术,用于编译时期。确保了类型的安全。 运行时,会将泛型去掉,生成的class文件中是不带泛型的,这个称为泛型的擦除。 为什么擦除呢?因为为了兼容运行的类加载器。 泛型的补偿:在类加载器原有基础上,编写一个补偿程序。在运行时,通过反射, 获取元素的类型进行转换动作。不用使用者在强制转换了。

具体可查看Java核心技术点之泛型

40.内部类的作用

  1. 完善多重继承
  1. 实现事件驱动系统
    用来开发GUI的Java Swing使用了大量内部类,主要用来响应各种事件。Swing的工作就是在事件就绪的时候执行事件,至于事件具体怎么做,这由事件决定。这里面有两个问题:1.事件必须要用到继承2.事件必须能访问到Swing。所以必须把事件写成内部类。

  2. 闭包。
    内部类是面向对象的闭包,因为它不仅包含创建内部类的作用域的信息,还自动拥有一个指向此外围类对象的引用,在此作用域内,内部类有权操作所有的成员,包括private成员。一般使用一个库或类时,是你主动调用人家的API,这个叫Call,有的时候这样不能满足需要,需要你注册(注入)你自己的程序(比如一个对象),然后让人家在合适的时候来调用你,这叫Callback。
    当父类和实现的接口出现同名函数时,你又不想父类的函数被覆盖,回调可以帮你解决这个问题。

摘取至知乎中Java 中引入内部类的意义一文的回答

41.if和switch的区别:

对于几个固定值的判断,建议使用switch语句,因为switch语句会将具体的答案加载进内存,相对高效一点。

42.进程和线程的区别

进程就是一个应用程在处理机上的一次执行过程, 它是一个动态的概念。而线程是进程的一部分,一个进程可以包含多个线程. 进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。它可以申请和拥有系统资源,是一个动态的概念,是一个活动的实体。它不只是程序的代码,还包括当前的活动,通过程序计数器的值和处理寄存器的内容来表示。

进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体,我们称其为进程。

通常在一个进程中可以包含若干个线程,它们可以利用进程所拥有的资源。在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位。由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统内多个程序间并发执行的程度。

线程和进程的区别在于,子进程和父进程有不同的代码和数据空间,而多个线程则共享数据空间,每个线程有自己的执行堆栈和程序计数器为其执行上下文。多线程主要是为了节约CPU时间,发挥利用,根据具体情况而定。线程的运行中需要使用计算机的内存资源和CPU。

线程与进程的区别归纳:

进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

来源于文章面试题二(谈谈进程与线程)

43.Java 7与Java 8的新特性

Java 7:

Java 8:

这里有两篇总结的非常好的:
Java 7的新特性
Java 8的新特性

44.常见设计模式

所谓“设计模式”,不过是面向对象编程中一些常用的软件设计手法,并且经过实践的检验,这些设计手法在各自的场景下能解决一些需求,因此它们就成为了如今广为流传的”设计模式“。也就是说,正式因为在某些场景下产生了一些棘手的问题,才催生了相应的设计模式。明确了这一点,我们在学习某种设计模式时要充分理解它产生的背景以及它所解决的主要矛盾是什么。

常用的设计模式可以分为以下三大类:

关于每个模式具体的介绍请参考图说设计模式

45.动态代理的定义、应用场景及原理

公共技术点之 Java 动态代理

46.注解的基本概念与使用


本文主要根据以下文章整理:

  1. Java面试知识点总结
  2. LearningNotes

后续会持续添加我认为重要的东西

上一篇下一篇

猜你喜欢

热点阅读