Android面试必问之Java基础
Android面试必问之Java基础
- 基础概念与常识
- 1. Java语言有哪些特点?
- 2. JVM vs JDK vs JRE
- 3. 字节码
- 4. 为什么说Java语言"编译与解释并存"?
- 5. Java和C++的区别?
- 基础语法
- 1. 字符型常量和字符串常量的区别?
- 2. 可变长参数
- 3. 注释
- 4. 标识符和关键字的区别是什么?
- 5. 自增自减运算符
- 6. continue、break 和 return 的区别是什么?
- 方法
- 1. 静态方法为什么不能调用非静态成员
- 2. 静态方法和实例方法有何不同?
- 3. 重载和重写的区别
- 泛型
- 1. Java泛型了解吗?什么是类型擦除?介绍一下常用的通配符?
- 2. 你的项目中哪里用到了泛型?
- ==和equals()的区别
- hashCode()与equals()
- 基本数据类型
- 1. Java 中的几种基本数据类型是什么?各自占用多少字节呢?对应的包装类型是什么?
- 2. 包装类型的常量池技术了解吗?
- 3. 自动装箱和拆箱了解吗?原理是什么?
基础概念与常识
1. Java语言有哪些特点?
- 面向对象(封装,继承,多态)
- 平台无关性( Java 虚拟机实现平台无关性)
- 支持多线程
- 支持网络编程并且很方便
- 编译与解释并存
- “Write Once, Run Anywhere(一次编写,随处运行)”
- 强大的生态
2. JVM vs JDK vs JRE
JVM:
Java 虚拟机(JVM)是运行 Java 字节码的虚拟机。JVM 有针对不同系统的特定实现(Windows,Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。
JVM 并不是只有一种!只要满足 JVM 规范,每个公司、组织或者个人都可以开发自己的专属 JVM。
除了我们平时最常用的 HotSpot VM
外,还有 J9 VM、Zing VM、JRockit VM 等 JVM 。
JDK:
JDK 是 Java Development Kit 缩写,它是功能齐全的 Java SDK。
它拥有 JRE 所拥有的一切,还有编译器(javac
)和工具(如 javadoc
和 jdb
)。它能够创建和编译程序
。
JRE:
JRE 是 Java 运行时环境。
它是运行已编译 Java 程序所需的所有内容的集合
,包括 Java 虚拟机
(JVM),Java 类库
,java 命令
和其他的一些基础构件。但是,它不能用于创建新程序。
运行Java程序——JRE
Java编程——JDK
3. 字节码
在 Java 中,JVM 可以理解的代码就叫做字节码
(即扩展名为 .class
的文件),它不面向任何特定的处理器,只面向虚拟机。
Java 语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低
的问题,同时又保留了解释型语言可移植
的特点。
由于字节码并不针对一种特定的机器,因此,Java 程序无须重新编译便可在多种不同操作系统的计算机上运行。
我们需要格外注意的是 .class->机器码
这一步。在这一步 JVM 类加载器首先加载字节码文件
,然后通过解释器逐行解释执行
,这种方式的执行速度会相对比较慢
。而且,有些方法和代码块是经常需要被调用的(也就是所谓的热点代码
),所以后面引进了 JIT(just-in-time compilation)编译器
,而 JIT 属于运行时编译
。当 JIT 编译器完成第一次编译后,其会将字节码对应的机器码保存下来
,下次可以直接使用
。而我们知道,机器码的运行效率肯定是高于 Java 解释器的。这也解释了我们为什么经常会说 Java 是编译与解释共存的语言
。
JDK 9 引入了一种新的编译模式
AOT(Ahead of Time Compilation)
,它是直接将字节码编译成机器码,这样就避免了 JIT 预热等各方面的开销。JDK 支持分层编译和 AOT 协作使用。但是 ,AOT 编译器的编译质量是肯定比不上 JIT 编译器的。
4. 为什么说Java语言"编译与解释并存"?
我们可以将高级编程语言按照程序的执行方式分为两种:
编译型 :编译型语言 (opens new window) 会通过编译器 (opens new window)将源代码一次性翻译成可被该平台执行的机器码
。一般情况下,编译语言的执行速度比较快
,开发效率比较低
。常见的编译性语言有 C、C++、Go、Rust
等等。
解释型 :解释型语言 (opens new window)会通过解释器 (opens new window)一句一句的将代码解释(interpret)为机器代码后再执行
。解释型语言开发效率比较快
,执行速度比较慢
。常见的解释性语言有 Python、JavaScript、PHP
等等。
Java 语言既具有编译型语言
的特征,也具有解释型语言
的特征。因为 Java 程序要经过先编译,后解释
两个步骤,由 Java 编写的程序需要先经过编译步骤,生成字节码
(.class 文件),这种字节码必须由 Java 解释器来解释执行
。
5. Java和C++的区别?
- 都是
面向对象
的语言,都支持封装
、继承
和多态
- Java
不提供指针来直接访问内存
,程序内存更加安全 - Java 的类是
单继承
的,C++ 支持多重继承;虽然 Java 的类不可以多继承,但是接口可以多继承
。 - Java 有
自动内存管理垃圾回收机制(GC)
,不需要程序员手动释放无用内存。 - C ++同时支持方法重载和操作符重载,但是 Java
只支持方法重载
(操作符重载增加了复杂性,这与 Java 最初的设计思想不符)。
基础语法
1. 字符型常量和字符串常量的区别?
- 字符常量是
单引号
引起的一个字符
,字符串常量是双引号
引起的0 个或若干个字符
- 字符常量相当于一个
整型值
( ASCII 值),可以参加表达式运算
; 字符串常量代表一个地址值
(该字符串在内存中存放位置) - 字符常量只占
2 个字节
; 字符串常量占若干个字节
2. 可变长参数
从 Java5 开始,Java 支持定义可变长参数,所谓可变长参数就是允许在调用方法时传入不定长度的参数。接受 0 个或者多个参数
。
public static void method2(String arg1, String... args) {//......
}
3. 注释
- 单行注释
- 多行注释
- 文档注释
4. 标识符和关键字的区别是什么?
简单来说,标识符就是一个名字。但是有一些标识符,Java 语言已经赋予了其特殊的含义,只能用于特定的地方,这种特殊的标识符就是关键字。
关键字是被赋予特殊含义的标识符。
【Java中的常见的关键字】
5. 自增自减运算符
符号在前就先加/减,符号在后就后加/减
6. continue、break 和 return 的区别是什么?
continue
:指跳出当前的这一次循环,继续下一次循环。break
:指跳出整个循环体,继续执行循环下面的语句。return
:用于跳出所在方法,结束该方法的运行。
return;
:直接使用 return 结束方法执行,用于没有返回值函数的方法
return value;
:return 一个特定值,用于有返回值函数的方法
方法
1. 静态方法为什么不能调用非静态成员
这个需要结合 JVM 的相关知识,主要原因如下:
静态方法是属于类的
,在类加载的时候就会分配内存,可以通过类名直接访问。而非静态成员属于实例对象
,只有在对象实例化之后才存在,需要通过类的实例对象去访问。- 在类的非静态成员不存在的时候静态成员就已经存在了,此时调用在内存中还不存在的非静态成员,属于非法操作。
2. 静态方法和实例方法有何不同?
- 调用方式:在外部调用静态方法时,可以使用
类名.方法名
的方式,也可以使用对象.方法名
的方式,而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象
。不过,需要注意的是一般不建议使用 对象.方法名 的方式来调用静态方法。这种方式非常容易造成混淆,静态方法不属于类的某个对象而是属于这个类。因此,一般建议使用类名.方法名
的方式来调用静态方法。 - 访问类成员是否存在限制:
静态方法在访问本类的成员时,只允许访问静态成员
(即静态成员变量和静态方法),不允许访问实例成员(即实例成员变量和实例方法),而实例方法不存在这个限制
。
3. 重载和重写的区别
重载就是同样的一个方法能够根据输入数据的不同,做出不同的处理。发生在同一个类中(或者父类和子类之间),方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同
。综上:重载就是同一个类中多个同名方法根据不同的传参来执行不同的逻辑处理。
重写就是当子类继承自父类的相同方法,输入数据一样,但要做出有别于父类的响应时,你就要覆盖父类方法。重写发生在运行期,是子类对父类的允许访问的方法的实现过程进行重新编写
。综上:重写就是子类对父类方法的重新改造,外部样子不能改变,内部逻辑可以改变。
泛型
1. Java泛型了解吗?什么是类型擦除?介绍一下常用的通配符?
Java泛型(generics) 是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制
,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型
,也就是说所操作的数据类型被指定为一个参数
。
Java 的泛型是伪泛型
,这是因为 Java 在运行期间,所有的泛型信息都会被擦掉
,这也就是通常所说类型擦除
。
List<Integer> list = new ArrayList<>();
list.add(12);
list.add("a"); //这里直接添加会报错
Class<? extends List> clazz = list.getClass();
Method add = clazz.getDeclaredMethod("add", Object.class);
//但是通过反射添加是可以的
//这就说明在运行期间所有的泛型信息都会被擦掉
add.invoke(list, "kl");
System.out.println(list);
泛型一般有三种使用方式: 泛型类
、泛型接口
、泛型方法
。
- 泛型类:
//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
//在实例化泛型类时,必须指定T的具体类型
public class Generic<T> {private T key;public Generic(T key) {this.key = key;}public T getKey() {return key;}
}
实例化泛型类:
Generic<Integer> genericInteger = new Generic<Integer>(123456);
- 泛型接口:
public interface Generator<T> {public T method();
}
实现泛型接口,不指定类型:
class GeneratorImpl<T> implements Generator<T>{@Overridepublic T method() {return null;}
}
实现泛型接口,指定类型:
class GeneratorImpl implements Generator<String>{@Overridepublic String method() {return "hello";}
}
- 泛型方法:
public static <E> void printArray(E[] inputArray) {for (E element : inputArray) {System.out.printf("%s ", element);}System.out.println();
}
使用:
// 创建不同类型数组: Integer, Double 和 Character
Integer[] intArray = { 1, 2, 3 };
String[] stringArray = { "Hello", "World" };
printArray(intArray);
printArray(stringArray);
常用的通配符:T 、E、K、V、?
- ? 表示不确定的Java类型
- T(type) 表示具体的一个Java类型
- K V(key value) 分表代表Java键值中的Key Value
- E(element) 代表Element
2. 你的项目中哪里用到了泛型?
- 可用于定义通用返回结果
CommonResult<T>
通过参数T
可根据具体的返回类型动态指定结果的数据类型 - 用于构建集合工具类。参考 Collections 中的 sort, binarySearch 方法
- …
==和equals()的区别
== 对于基本类型和引用类型的作用效果是不同的:
- 对于基本数据类型来说,== 比较的是值。
- 对于引用数据类型来说,== 比较的是对象的内存地址。
因为 Java 只有
值传递
,所以,对于 == 来说,不管是比较基本数据类型,还是引用数据类型的变量,其本质比较的都是值
,只是引用类型变量存的值是对象的地址
。
equals() 作用不能用于判断基本数据类型的变量,只能用来判断两个对象是否相等。
Object类equals()方法:
public boolean equals(Object obj) {return (this == obj);
}
hashCode()与equals()
hashCode() 介绍
hashCode() 的作用是获取哈希码
(int 整数),也称为散列码
。这个哈希码的作用是确定该对象在哈希表中的索引位置
。Object 的 hashCode() 方法是本地方法,该方法通常用来将对象的内存地址转换为整数之后返回
。
散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!
为什么要有hashCode?
以
HashSet
为例:
当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置
,同时也会与其他已经加入的对象的 hashcode 值作比较
,如果没有相符的 hashcode,HashSet 会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 equals() 方法来检查 hashcode 相等的对象是否真的相同
。如果两者相同,HashSet 就不会让其加入操作成功
。如果不同的话,就会重新散列到其他位置
。这样我们就大大减少了equals的次数,相应就大大提高了执行速度。
为什么重写equals()时必须重写hashCode()方法?
hashCode()的默认行为是对堆上的对象产生独特值
。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等
。
如果 equals 方法判断两个对象是相等的,那这两个对象的 hashCode 值也要相等。
为什么两个对象有相同的 hashcode 值,它们也不一定是相等的?因为 hashCode() 所使用的哈希算法也许刚好会让多个对象传回相同的哈希值
。越糟糕的哈希算法越容易碰撞,但这也与数据值域分布的特性有关(所谓碰撞也就是指的是不同的对象得到相同的 hashCode )。“两个不同的键值对,哈希值相等”,这就是哈希冲突
。
刚刚也提到了 HashSet,如果 HashSet 在对比的时候,同样的 hashcode 有多个对象,它会使用 equals() 来判断是否真的相同
。也就是说 hashcode 只是用来缩小查找成本。
因为HashSet判断对象是否相同是根据其hashCode()值比较,而equals()默认比较也是采用hashCode()。当我们什么都不重写,默认创建的对象对应的hashCode值就是不一致的;但是当我们重写equeals()时,说明我们想更改判断对象是否相等的方式,因此我们需要同时重写hashCode(),才能保证对象判断方式是我们想要的效果。
基本数据类型
1. Java 中的几种基本数据类型是什么?各自占用多少字节呢?对应的包装类型是什么?
Java 中有 8 种基本数据类型,分别为:
- 6 种数字类型 :
byte
、short
、int
、long
、float
、double
- 1 种字符类型:
char
- 1 种布尔型:
boolean
。
这八种基本类型都有对应的包装类
分别为:Byte
、Short
、Integer
、Long
、Float
、Double
、Character
、Boolean
。
包装类型不赋值就是 Null ,而基本类型有默认值且不是 Null。
基本数据类型
直接存放在 Java 虚拟机栈中的局部变量表
中,而包装类型
属于对象类型,我们知道对象实例都存在于堆中
。相比于对象类型, 基本数据类型占用的空间非常小。
局部变量表:
局部变量表主要存放了编译期可知的基本数据类型 (boolean、byte、char、short、int、float、long、double)、对象引用(reference 类型,它不同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)。
2. 包装类型的常量池技术了解吗?
Java 基本类型的包装类的大部分都实现了常量池技术。
Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,Character 创建了数值在 [0,127] 范围的缓存数据,Boolean 直接返回 True or False。
举例Integer缓存源码:
public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);
}
private static class IntegerCache {static final int low = -128;static final int high;static {// high value may be configured by propertyint h = 127;}
}
所有整型包装类对象之间值的比较,全部使用 equals 方法比较。
3. 自动装箱和拆箱了解吗?原理是什么?
什么是自动拆装箱?
- 装箱:将基本类型用它们对应的引用类型包装起来;
- 拆箱:将包装类型转换为基本数据类型;
Integer i = 10; //装箱
int n = i; //拆箱
从字节码中,我们发现装箱
其实就是调用了 包装类的valueOf()
方法,拆箱
其实就是调用了 xxxValue()
方法。
注意:如果频繁拆装箱的话,也会严重影响系统的性能。我们应该尽量避免不必要的拆装箱操作。
Android面试必问之Java基础相关推荐
- Android面试必问框架原理
Android面试必问框架原理 volatile的实现原理 synchronized的实现原理 join方法实现原理 CAS无锁编程的原理 ReentrantLock的实现原理 AQS的大致实现思路 ...
- Android面试必问之触摸事件传递机制
Android面试必问之触摸事件传递机制 一.Activity的构成 二.触摸事件的类型 三.事件传递的三个阶段 Activity对点击事件的分发过程 五.View的事件分发机制 六.点击事件分发的传 ...
- 面试常问集锦——Java基础部分
java基础部分 <我想进大厂>之Java基础夺命连环16问 https://mp.weixin.qq.com/s?__biz=MzkzNTEwOTAxMA==&mid=22474 ...
- 今年Android面试必问的这些技术面,面试心得体会
前言 不清楚你是不是知道,咱们中国有相当大的一部分软件公司,他们的软件开发团队都小的可怜,甚至只有1-3个人,连一个项目小组都算不上,而这样的团队却要承担一个软件公司所有的软件开发任务,在软件上线和开 ...
- 划重点!百度、阿里、腾讯大厂Android面试必问知识点系统梳理,啃一半公司随便挑
前言 大厂面试一直是我们程序员小伙伴茶余饭后所津津乐道的话题.能进一线互联网大厂工作,也是每个程序员生涯的梦想,为的不仅仅是大厂的种种福利.工作环境和高薪,更为的是大厂的工作氛围,能加入到大牛的圈子, ...
- 升职加薪必看!阿里、腾讯大厂Android面试必问知识点系统梳理,深度好文
前言 今年是转折的一年,很多学android开发的小伙伴失业了,虽找到了一份工作,但高不成低不就,下半年金九银十有想法更换一份工作,很多需要大厂面试经验和大厂面试真题的小伙伴,想提前准备刷下题.接下来 ...
- 阿里、腾讯大厂Android面试必问知识点系统梳理,满满干货指导
前言 金三银四,又是一年校招季. 经历过,才深知不易.最近,和作为校招面试官的同事聊了聊,问他们是如何去考察一个学生的,我简单归为以下几点: 聪明.反应快,这点自不必说,聪明意味着学习能力.适应力强, ...
- Android面试必问!面试字节跳动Android研发岗,满满干货指导
一.自我介绍 应该算是起点比较高吧!985大学毕业后面一直在国外读研.之前准备面试微软但是可能经验不够,没有通过.经过朋友介绍我准备回国,积累一些开发经验.于是我面试了国内大厂BATJ,还有一些其他比 ...
- 大厂面试必问!java审批工作流实现
蚂蚁一面 ⼀⾯就做了⼀道算法题,要求两⼩时内完成,给了⻓度为N的有重复元素的数组,要求输出第10⼤的数.典型的TopK问题,快排算法搞定.算法题要注意的是合法性校验.边界条件以及异常的处理.另外,如果 ...
- Android面试必问的Activity,初阶,中高阶问法,你都掌握了吗?(要求熟读并背诵全文)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cXs1wGDx-1605843173409)(https://upload-images.jianshu.io/uplo ...
最新文章
- C#文件封装到Dll
- 了解一下爬虫技术方方面面
- ABAP 动态 SQL
- ELF文件和BIN文件
- python如何引发和处理异常_在python3.6中,如何捕捉异常并引发异常以便稍后处理?...
- Redis工作笔记-事务
- 关于fsockopen pfsockopen函数被禁用的解决方法
- python中的thread_深入理解Python中的ThreadLocal变量(上)
- 如何保持最佳 MacBook 温度?
- 双向链表基本实现简单贪吃蛇
- 【Kafka】01 生产者
- python语音转文字源码_python文字转语音实现过程解析
- Win10系统下如何安装鼠标指针主题包
- English--consonant_摩擦音
- 企业微信开发,嵌入自定义项目,及JS-SDK的引用
- 《博弈论》异或 博弈x^x第二手只能一定赢吗?
- 程序员年底失业,到底是该年前找工作好还是年后找工作好?
- 啥叫企业管理?王健林告诉你
- 树洞外链2.1,一款基于七牛的外链分享平台
- hbase 部署测试