目录
1.什么是JDK,JRE,JVM;他们之间有什么联系 2.Java的八种数据类型
3.& 和 && 区别 4.switch的参数可以有哪些类型
5.类与对象如何理解 6.成员变量和局部变量的区别
7.static关键字都能修饰什么,有什么特点 8.什么是封装,为什么要封装
9.什么是面向对象 10.overload和override的区别
11.final和finally的区别 12.this和super有什么区别,能作用到什么地方
13.接口和抽象类的区别 14.静态变量和成员变量的区别
15.throw和throws的区别 16.String,StringBuilder与StringBuffer的区别
17.new String("abc")到底创建了几个对象? 18.==和equals的区别
19.包装类拆箱装箱 20.HashSet去重原理
21. jvm内存划分 22.构造方法是否可以被重写?为什么?
23.Collection 与 Collections 的区别 24.集合与数组的区别
25. 多线程的三种实现方式 26.多线程的生命周期
27.TreeSet和HashSet的区别 28.TreeMap如何去重
29.所学习的io流一共分为几类 30.目前学习的最高效的文件复制方式
31.map的两种遍历方式 32.HashMap与HashTable 的区别
33.什么是反射? 34.字节流与字符流有什么区别
36.sleep wait notify notifyAll的作用
37.HashMap的底层数据结构是什么?那什么时候变为红黑树呢?
38.final,finally,finalize有什么区别?
1.什么是JDK,JRE,JVM;他们之间有什么联系?
JDK(Java Development Kit):Java开发工具包
JRE(Java Runtime Environment):Java运行时环境
JVM(Java Virtual Machine):Java虚拟机
JDK是开发工具包,它包含了JRE和编译器(javac)以及调试工具等,它支持从编写程序到编译程序再到运行程序的整套流程;JRE包含了JVM和标准类库,允许运行已经编译好的java程序;JVM会将字节码文件解释成机器语言,也就是说最终的java程序会变成机器语言被运行。
也就是说-----JDK>JRE>JVM
2.Java的八种数据类型
整数类型:
byte 8位 1字节 范围从-128到127
short 16位 2字节 范围从-32768到32767
int 32位 4字节 范围从-2^31到2^31-1
long 64位 8字节 范围从-2^64到2^64-1
浮点类型:
float 32位(单精度浮点数) double 64位(双精度浮点数)
字符型: 布尔型:
char 16位 boolean
这些基本数据类型可以在内存中操作,操作效率非常高
3.&
和 &&
区别
&(按位与/逻辑与) | &&(短路与) |
//按位与 //逻辑与 | //短路与 boolean x = true; |
如果左边为假,那么右边任然要执行 | 如果左边为假,则右边不需要执行,提高了效率。 |
4.switch的参数可以有哪些类型
byte,short,int,char,String,枚举
5.类与对象如何理解
类是模板,是蓝图,是框架,类规定了或者限制了对象属性和行为,类自身是抽象的;而对象是类的具体体现形式,每个对象拥有自己独立的属性,用自己的属性值来共享类定义的行为,对象是具体的,在内存中占有空间。
类是模具,决定了如何制造产品(对象),对象是产品,根据模具创建出来的具体示例
6.成员变量和局部变量的区别
- 定义位置
成员变量:定义在类中,方法之外 |
局部变量:定义在方法,构造器,代码块内部 |
- 生命周期
成员变量:和对象的生命周期一样,随对象的消亡而消亡 |
局部变量:随着方法执行结束就会消亡 |
- 默认值
成员变量:不给成员变量初始化值,它们也有默认值(自动被赋予默认值) (例如int为0,对象引用为null,boolean为false) |
局部变量:没有默认值,如果运行就会有异常 |
- 访问修饰符
成员变量:可以有修饰符修饰 |
局部变量:不能被修饰符修饰 |
- 存储位置
成员变量:存储在堆中,因为对象在堆中,它属于对象 |
局部变量:存储在栈中 |
7.static关键字都能修饰什么,有什么特点
- 修饰成员变量
又称静态变量,在类加载时静态变量就被初始化,静态变量不属于任何类的对象,而属于类本身,只会存在一份,可以通过类名直接调用。因此,静态变量节约了内存。
- 修饰方法
静态方法属于类,不属于任何类的对象,因此,只能通过类名来调用,且不能访问非静态成员与方法,静态方法内不能使用this和super关键字。
- 修饰代码块
在类加载时就会被初始化,并且只会执行一次。比构造方法先执行。
- 修饰内部类
不需要通过实例化外部类的对象,而是通过外部类的类名直接创建内部类的对象。静态内部类只能访问外部类的静态成员
8.什么是封装,为什么要封装
将对象的属性和行为绑定在一块,隐藏实现的细节,通过特定修饰符修饰,只能通过特定的方法访问对象内部的状态,这样提高的代码的安全性和灵活性。
9.什么是面向对象
是一种以事物为中心的编程思想,其中分为封装,继承,多态
- 封装是一种将对象的行为和属性绑定在一起,隐藏其中的细节,通过特定的修饰符修饰,只能用特定的方法访问对象内部的状态
- 继承是子类继承于父类,获得父类的属性和行为,促进了代码的重用,并且还可以进一步扩展或者修改父类的行为
- 多态允许对象以多种形式出现。它可以通过方法的重载(同一方法名不同参数)或重写(子类覆盖父类的方法)来实现。多态性使得同一接口可以对应不同的实现,提高了程序的灵活性和可扩展性
10.overload和override的区别
- overload 是重载 要求在同一个类中,方法名相同,参数列表不同与返回值类型无关
- override是重写 要求发生在子父级的继承关系中,方法名相同,参数列表相同,返回值类型是父类返回值类型本身或其子类, 异常等于父类本身异常类型或小于父类本身异常
11.final和finally的区别
final | finally |
1.修饰类,类不可被继承 2.修饰方法,方法不可被重写 3.修饰变量,变量不可被修改 | 它是异常处理机制中的关键字,其内 的代码逻辑一定会被执行。 |
12.this和super有什么区别,能作用到什么地方
this | super | |
作用对象 | 作用与本类的对象 | 作用与父类的对象 |
构造方法 | 调用本类的构造方法 this()或者this(参数) | 调用父类的构造方法 super()或者super(参数) |
方法属性的访问 | 调用本类的方法,或者 局部变量区别于本类的 成员变量 | 调用父类的方法,特别是想访问 被子类重写前的方法时;局部变量 区别于父类的成员变量时 |
13.接口和抽象类的区别
- 接口可以多重实现,而抽象类只能被单继承
- 接口中的成员变量一定时常量,修饰词是public static final,而抽象类的成员变量就没有限制
- 接口不能有构造方法,抽象类可以有
- 接口不能有方法的具体实现,JDK1.8之后有例外;而抽象类可以有抽象方法和成员方法
- 对于设计理念而言,接口是一种规范,规定了这个类必须要做那些事情;而抽象类则是代码复用,对于多个类有共同的特性的时候,将这个共性抽取出来成为一个父类
14.静态变量和成员变量的区别
静态变量它是属于类本身的,而成员变量是属于对象的;所以由于这个特性,两者出现了许多的区别,就像生命周期,静态变量随着类而消亡,成员变量则是随着对象而消亡;又像加载的时机,静态变量随着类加载而加载,而成员变量是对象创建后,才有自己独立的属性,也就是成员变量;静态变量是所有类的对象所共享的;还有调用的时候,静态变量可以通过类名来调用,从而不需要创建对象,成员变量则是创建对象之后才能调用的
15.throw和throws的区别
- throw是具体抛出一个异常对象,后面必须跟一个且只能为一个异常实例,如果代码执行到这里,程序就会终止,并且它在方法内部
- throws是申明异常,表示可能出现的异常,后面可以跟多个异常类型,位置在方法小括号后面,程序不一定会出现异常
16.String,StringBuilder与StringBuffer的区别
- String是不可变字符串序列,StringBuilder和StringBuffer是可变字符串序列
- StringBuilder是线程不安全的,但效率高;StringBuffer是线程安全的,但效率低
17.new String("abc")到底创建了几个对象?
首先得看方法区中的常量池,如果常量池中有abc,那么有new关键字,就会创建一个对象在堆内存中,这个对象的abc是在常量池中拿到的,即创建了一个对象,也就是new String这个实例对象;如果常量池没有abc,那会首先创建new String这个实例对象,然后会创建abc这个常量对象,之后再把这个常量对象的引用放进常量池中,创建了两个对象。
18.==和equals的区别
- ==:表示比较两个引用的地址是否相同或者基本数据类型中比较两个值是否相同
- equals:在Object类中,equals方法比较的和“==”一样,由于Object是所有类的父类,所以,有些类会重写Object类的equals方法,例如String中重写的equals方法,比较的就是两者值是否相同,而并非是比较地址值,其实equals方法主要还是要看类中重写后的逻辑是什么。
19.包装类拆箱装箱
装箱是基本数据类型转换为引用数据类型,拆箱是引用数据类型转换为基本数据类型
在Integer中,有一个缓存机制,-128~127之间的值,不会创建对象,而超出这个范围内的值,照常会创建对象,这个缓存的位置就在堆中
20.HashSet去重原理
首先对要加入集合的元素通过hashCode()进行哈希值的计算,然后在通过哈希算法得到该元素加入的数组的位置,查看这个位置上是否有其他元素,如果没有,直接插入,如果有,则用equals方法进行比较,一般来说,比较两个元素的内容是否一样,如果比较后是一样的,则去重,如果不一样,则通过链表或者红黑树的结构进行存储,链表超过一定的数量后,就变成红黑树了。
21. jvm内存划分
栈内存,堆内存,方法区,本地方法栈,程序计数器
- 栈内存:正在执行的方法和局部变量
- 堆内存:对象和数组在这个区域
- 方法区:字节码文件,静态变量,常量池;其中常量池包含字面量和符号引用,前者就是final修饰的常量,后者就是类和接口的全局限定名,字段的名称和描述符等等
22.构造方法是否可以被重写?为什么?
每个类有拥有自己独立的构造方法,重写后意味着纂改了父类的构造;再者构造方法的方法名和类名保持一致,所以不能重写。
23.Collection 与 Collections 的区别
- Collection是所有单列集合的最上层接口,规范了结合的基本操作
- Collections是一个工具类,由于构造方法是私有的,所以只能用类名来调用它的静态方法
24.集合与数组的区别
- 集合是动态长度;数组是定长,无法改变
- 集合只能存引用数据类型;数组既可以存基本数据类型,也可以存引用数据类型
- 集合可以存许多中引用类型;数组只能存一种
25. 多线程的三种实现方式
- 第一种:本类继承Thread类,重写run方法,创建本类的对象,调用start方法开启线程
- 第二种:本类实现Runnable接口,重写run方法,创建本类的对象,创建Thread对象,把本类的对象放进Thread的构造函数中,然后通过Thread调用start方法启动线程
- 第三种:本类实现Callable接口,重写call方法,创建本类对象后,再创建FutureTask对象,把本类对象放进FutureTask对象的构造函数中,再创建Thread对象,把FutureTask放进Thread的构造函数中,然后调用Thread对象的start方法,开启线程
26.多线程的生命周期
- 新建态:new关键字出现后,线程加入新建太,还不具备拿到cpu的执行权
- 就绪态:start后,线程进入就绪态,具备了cpu的执行权,等待cpu执行这个线程
- 执行态:线程拿到cpu执行权,也就是开始了执行run方法内的逻辑,在这个状态,线程可能会变成阻塞态,就绪态和死亡态;如果线程丢失了cpu执行权,就会变成就绪态,重新等待拿到cpu执行权
- 阻塞态:线程执行过程中,遇到sleep,wait,或者获取同步锁失败以及io流阻塞时会变成阻塞状态,直到进入就绪态才具备拿到cpu执行权的资格
- 死亡态:本次线程执行完毕或者程序出现异常时会变成死亡态
27.TreeSet和HashSet的区别
- TreeSet的时间复杂度是O(logn),而HashSet的时间复杂度是O(1),最坏的情况是O(n),因为同一个数组下标位置可能存在多个哈希码一样,是链表存储的
- TreeSet是有序的,默认是自然排序,也可自己指定排序规则;HashSet由于是基于哈希表实现的,所以是无序的
- 两者都有去重的功能
28.TreeMap如何去重
TreeMap去重是根据key值的compareTo方法,如果此方法返回值是0,证明是同一个元素,进行去重
在put源码中,如果TreeMap的构造函数中没有传递比较器的对象,那么在put方法中就会执行比较器为空的代码;反之,执行的是有构造器的逻辑。源码中put方法走了两层,一个是没有比较器的,一个是有比较器的(比较器是TreeMap的一个成员变量)。
假设我键的类型是String,String实现了Comparable接口,重写了compareTo方法。首先会对成员变量comparator进行强转成String类型的(这就是为什么我们自己构造一个对象时不写比较规则就会抛异常的原因),然后在put的时候,走的就是没有构造器的逻辑,自然排序,接着父节点,左子节点,右子节点等一系列操作,如果比较返回值是0,就说明重复了,不添加
所以去重分为两种情况:
- 传入比较器对象的时候,TreeMap的成员变量comparator指向了这个比较器,所以比较规则就是这个比较器的指定的规则,这个比较器内的compare方法返回值如果大于0,放在根节点的右边,小于0放根节点左边,等于0,就去重
- 没有传入比较器的时候,首先对key值进行强转成比较器(这个key的类必须继承Comparable接口,并且实现compareTo方法),然后调用这个比较器的compareTo方法进行自然排序,返回值为0的去重。
29.所学习的io流一共分为几类
- IO流根据流向 有输入流和输出流两种
- IO流根据类型分类有 字节输入输出流 和 字符输入输出流
30.目前学习的最高效的文件复制方式
缓冲字节输入输出流,加上字节数组,大小一般是1024
31.map的两种遍历方式
map的遍历方式说法不一,但最终其实还是两个方法实现的
- keySet,把map的键放进set集合,然后遍历set集合,通过map的get方法由键拿到值
- entrySet,把键值对放进map的内部类entry中,再把entry放进set集合中,然后通过每一个entry对象的getKey和getValue获得键和值
32.HashMap与HashTable 的区别
- HashMap是线程不安全的;HashTable由于所有方法都加了同步锁,所以线程安全
- HashMap效率更高,底层是采用数组+链表+红黑树的结构;而HashTable底层是数组+链表,并且使用的同步锁,所以效率低
- HashMap允许null键和null值;HashTable不允许
33.什么是反射?
反射是在程序运行的时候动态的获取类的相关信息,从而对这个类进行操作
假如我对java.lang.String进行反射:jvm会在类加载器的缓存中查找是否有这个类的元信息,如果有,就直接返回这个Class对象,如果没有就加载这个类。
34.字节流与字符流有什么区别
- 字节流的编码方式是ASCII,而字符流是unicode
- 字节流读写操作是直接把数据读写到目的地;但字符流读写的时候,内存中会有一个缓冲区,不管读还是写,数据先到缓冲区,再到目的地。
- 字节流不管什么文件都能操作,字符流只能操作字符类型的数据
35.Java的线程池有哪些?那你最常用的线程池是哪个?
- newCachedThreadPool:动态线程池
- newFixedThreadPool:固定线程数量线程池
- newScheduledThreadPool:定时线程池
- newSingleTheradExecutor:一条线程的线程池
一般不使用这四种,而是自定义线程池,最多有7个参数:核心线程数量,最大线程数量,空闲线程的等待时间,空闲线程等待时间的单位,阻塞队列(规定队列长度),线程创建工程,拒绝策略
36.sleep wait notify notifyAll的作用
- sleep是Thread的一个静态方法,该方法会让当前线程进入睡眠状态,并且不会释放当前的对象锁
- wait是Object提供的方法,该方法会让当前线程进入等待状态,并且释放当前的对象锁,且必须在同步代码块或者同步方法中使用
- notify也是Object的方法,作用是随机唤醒等待该对象锁的一条线程,被唤醒的线程重新进入等待队列开始竞争cpu执行权,且只能在同步代码块或者同步方法内
- notifyAll和notify一样,只不过是唤醒所有等待该对象锁的所有线程
37.HashMap的底层数据结构是什么?那什么时候变为红黑树呢?
在jdk1.7的时候,底层是数组+链表;jdk1.8的时候,底层是数组+链表+红黑树
在数组同一个位置的链表长度超过8的时候,链表变成红黑树
38.final,finally,finalize有什么区别?
- final:
- 被final修饰的类不能被继承
- 被final修饰的方法不能被重写
- 被final修饰的变量不能被修改
- finally:是异常结构中的一部分,内的代码不管怎么样一定会被执行到
- finalize:是Object内的方法,当对象被回收的时候,会调用这个方法
标签:面试题,Java,变量,区别,对象,线程,父类,方法,SE From: https://blog.csdn.net/iwjijksw/article/details/141883584