Java基础经典题集

java的垮平台原理
为什么要跨平台使用?其实说白了就是个操作系统支持的指令集是不一样的。我们的程序需要再不同的操作系统上运行这些代码。
但是不要说jvm是跨平台的,而真正跨平台的是 Java 程序,而不是 JVM。JVM 是用 C/C++ 开发的,是编译后的机器码,不能跨平台,不同平台下需要安装不同版本的 JVM
答:我们编写的 Java 源码,编译后会生成一种 .class 文件,称为字节码文件。Java 虚拟机(JVM)就是负责将字节码文件翻译成特定平台下的机器码然后运行,也就是说,只要在不同平台上安装对应的 JVM,就可以运行字节码文件,运行我们编写的 Java 程序。而这个过程,我们编写的 Java 程序没有做任何改变,仅仅是通过 JVM 这一 “中间层” ,就能在不同平台上运行,真正实现了 “一次编译,到处运行” 的目的。

JVM由哪些部分组成?
JVM 的结构基本上由 4 部分组成:

类加载器,在 JVM 启动时或者类运行时将需要的 class 加载到 JVM 中
执行引擎,执行引擎的任务是负责执行 class 文件中包含的字节码指令,相当于实际机器上的 CPU
内存区,将内存划分成若干个区以模拟实际机器上的存储、记录和调度功能模块,如实际机器上的各种功能的寄存器或者 PC 指针的记录器等
本地方法调用C 或 C++ 实现的本地,调用方法的代码返回结果
 类加载器是有了解吗?
答:顾名思义,类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说, Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。
类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象

Java 虚拟机是如何判定两个 Java 类是相同的?
答:Java 虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。比如一个 Java 类 com.example.Sample,编译之后生成了字节代码文件 Sample.class。两个不同的类加载器 ClassLoaderA和 ClassLoaderB分别读取了这个 Sample.class文件,并定义出两个 java.lang.Class类的实例来表示这个类。这两个实例是不相同的。对于 Java 虚拟机来说,它们是不同的类。试图对这两个类的对象进行相互赋值,会抛出运行时异常 ClassCastException。 

双亲委派模型(Parent Delegation Model)
该模型要求除了顶层的 Bootstrap class loader 启动类加载器外,其余的类加载器都应当有自己的父类加载器。子类加载器和父类加载器不是以继承(Inheritance)的关系来实现,而是通过组合(Composition)关系来复用父加载器的代码。每个类加载器都有自己的命名空间(由该加载器及所有父类加载器所加载的类组成,在同一个命名空间中,不会出现类的完整名字(包括类的包名)相同的两个类;在不同的命名空间中,有可能会出现类的完整名字(包括类的包名)相同的两个类)

双亲委派模型的工作过程?
1.当前 ClassLoader 首先从自己已经加载的类中查询是否此类已经加载,如果已经加载则直接返回原来已经加载的类。
每个类加载器都有自己的加载缓存,当一个类被加载了以后就会放入缓存,
等下次加载的时候就可以直接返回了。
2.当前 ClassLoader 的缓存中没有找到被加载的类的时候,委托父类加载器去加载,父类加载器采用同样的策略,首先查看自己的缓存,然后委托父类的父类去加载,一直到 bootstrap ClassLoader.
当所有的父类加载器都没有加载的时候,再由当前的类加载器加载,并将其放入它自己的缓存中,以便下次有加载请求的时候直接返回。

为什么这样设计呢?
解析:这是对于使用这种模型来组织累加器的好处
答:主要是为了安全性,避免用户自己编写的类动态替换 Java 的一些核心类 
同时也避免了重复加载,因为 JVM 中区分不同类,不仅仅是根据类名,相同的 class 文件被不同的 ClassLoader 加载就是不同的两个类,如果相互转型的话会抛java.lang.ClassCaseException.

 装箱和拆箱:有了基本的数据类型,我们为什么还要有包装类型。
就是体现面向对象的思想
自动装箱是jdk1.5以后增加的功能。装箱:就是把基本数据类型转化成对应的包装类型。
总结一下:Java是一个面向对象的语言,而基本的数据类型,不具备面向对象的特性。

 讲一下java中的集合

Java集合分为两种,一个是value类型的,另一个就是key.value (Map)两种

List是有序的,可以重复的
Set是无序的,不可以重复的(根据equals和hashcode来判断。)也就是说如果一个对象要存储到set当中,就必须要重写我们的equals和hashcode的方法。
Map就是key.value的类型数据。

Hashmap存储原理
API中的常用的属性
Hashmap、默认四个构造方法
Hash碰撞  ,桶的概念
Entry,next属性

ArrayList 和LinkedList的区别       
ArrayList底层使用的是数组,LinkedList底层使用的是链表
数组查询的时候具有查询特定元素比较快。而插入和删除和修改比较慢(数组在内存当中是一块联系的内存,如果插入或者删除是需要移动内存的)
链表不要求内存是连续的,当查询的时候,需要从头部一个一个的找,所以查询效率低,而插入的时候不需要移动内存,只需要改变引用的指向。
应用场景:ArrayList使用在查询比较多,答案是插入和删除比较少的情况,而LinkedList使用在查询比较少而插入和删除比较多的情况
HashMap和HashTable的区别 
相同点:都可以用来存储Key.value型数据
区别:
1、    hashMap是可以把null作为可以key或者value,而hashtable不可以
2、    HashMap是线程不安全的,效率较高,而hashtable是线程安全的,效率较低
我想线程安全我又想效率比较高?????what?????
 
    原理—》就是把整个map分为N个segment(类似于hashtable),可以提供相同的线程安全,但是效率提升N。默认提升的16倍。

 

线程的的实现方式?怎么启动线程?怎么区分线程?
1. 实现方式


a)    常用的通过继承Thread类来实现一个线程
b)    通过实现Runnable接口来实现一个线程。
c)    通过实现Callable接口来实现一个线程
2. 怎么启动
    我们通过
Thread thread=new Thread(继承了thread类的对象\或者把实现了runnable接口的对象)
            thread.start();
启动线程的时候用的是start()方法,然后执行线程的时候用的是run()方法;
3. 怎么样区分线程???
a)    在一个系统当中我们有很多线程,每个系统都会打印日志,我想区分一下到底是哪个系统打印的???
thread.setName(设置一个线程的名称),这是一个规范,你们将来在开发的时候写完多线程一定要及记得设置线程名称。

线程并发库和线程池的作用
Jdk1.5的时候增加了Doug Lea的并发库,大大的增加了便利性。
Java.util.current包提供了对线程的优化,包括管理的各项操作。--》线程池的创建,以及线程的生命周期的管理。
Java通过Executors提供四个静态方法来创建四种线程 池:

newCachedThreadPool,可缓存的线程池
newFixedThreadPool,创建一个定长线程池
newScheduledThreadPool,创建一个定长线程池,支 持定时以及周期性任务
newSingleThreadExcutor,创建一个单线程化的线程池
线程池的作用
限定了线程的个数,不会导致由于线程过多导致系统运行缓慢或崩溃
节约资源,我们不会去关心它的创建于销毁。

您可能还会对下面的文章感兴趣: