一、JDK 和 JRE 有什么区别?
JRE( Java Runtime Environment) 是Java 运行时环境……它是运行编译后的Java程序所必需的一切包,包括Java虚拟机(JVM)、Java基础类库、Java 命令和其他基础设施。但是,它不能用于创建新程序。
**JDK ** 是Java 开发工具包……功能齐全的SDKforJava。它拥有JRE所拥有的一切,还包含了编译java源码的编译器javac,还包含了很多java程序调试和分析的工具:jconsole,jvisualvm等工具软件,还包含了java程序编写所需的文档和demo例子程序。它能够创建和编译程序,是提供给程序员使用的。
如果你需要运行java程序,只需安装JRE就可以了。如果你需要编写java程序,需要安装JDK。
有时,即使您不打算在计算机上进行任何Java开发,仍然需要安装JDK。例如,如果您使用JSP部署Web应用程序,技术上来说,您只是在应用程序服务器中运行Java程序。那么,为什么需要JDK呢?因为应用服务器将JSP转换为JavaServlet,因此需要使用JDK来编译servlet。
JRE 根据不同操作系统(如:windows,linux等)和不同JRE提供商(IBM,ORACLE等)有很多版本,最常用的是Oracle公司收购SUN公司的JRE版本。
JDK 主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心
JDK包含的基本组件包括:
javac – 编译器,将源程序转成字节码
jar – 打包工具,将相关的类文件打包成一个文件
javadoc – 文档生成器,从源码注释中提取文档
jdb – debugger,查错工具
java – 运行编译后的java程序(.class后缀的)
appletviewer:小程序浏览器,一种执行HTML文件上的Java小程序的Java浏览器。
Javah:产生可以调用Java过程的C过程,或建立能被Java程序调用的C过程的头文件。
Javap:Java反汇编器,显示编译类文件中的可访问功能和数据,同时显示字节代码含义。
Jconsole: Java进行系统调试和监控的工具。
二、== 和 equals 的区别是什么?
对于基本类型和引用类型==的作用效果是不同的:
· 基本类型:比较的是值是否相同;
· 引用类型:比较的是引用是否相同;
equals 默认情况下是引用比较,只是很多类重写了equals方法;比如String、Integer等把它改成了值比较,所以一般情况下equals比较的是值是否相等。
三、两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?
两个对象的hashCode相同,equals方法不一定需要为true。在Object的hashCode方法写了hashCode的几个约定,其中就有一条表示,equals方法返回false,不代表hashCode就不相等。言下之意,就是hashCode相等时,equals方法返回的可能是false。当然,要尽量为equals方法返回false的对象,返回不同的hashCode。
四、final 在 java 中有什么作用?
- 修饰类:表示该类不能被继承
- 使用final修饰类的目的简单明确: 表明这个类不能被继承
- 当程序中有永远不会被继承的类时, 可以使用final关键字修饰
- 被final修饰的类所有成员方法都将被隐式修饰为final方法
- 修饰方法:表示方法不能被重写(使用final修饰方法有两个作用)
- 首要作用是:锁定方法, 不让任何继承类对其进行修改
- 另外一个作用是:在编译器对方法进行内联, 提升效率. 但是现在已经很少这么使用了, 近代的Java版本已经把这部分的优化处理得很好了
- 方法内敛: 当调用一个方法时, 系统需要进行保存现场信息, 建立栈帧, 恢复线程等操作, 这些操作都是相对比较耗时的. 如果使用final修饰一个了一个方法a, 在其他调用方法a的类进行编译时, 方法a的代码会直接嵌入到调用a的代码块中.
- 修饰变量:表示变量只能一次赋值以后值不能被修改(常量)
- 当final修饰的是一个基本数据类型数据时, 这个数据的值在初始化后将不能被改变;
- 当final修饰的是一个引用类型数据时, 也就是修饰一个对象时, 引用在初始化后将永远指向一个内存地址, 不可修改. 但是该内存地址中保存的对象信息, 是可以进行修改的
五、java 中的 Math.round(-1.5) 等于多少?
Math 类中提供了三个与取整有关的方法:ceil , floor , **round ** 这些方法的作用与它们的英文名称的含义相对应。
**ceil ** 的英文意义是天花板,该方法就表示向上取整,math.ceil(-1.5) 的结果为-1
**floor ** 的英文是地板,该方法就表示向下取整,math.floor(-1.6) 的结果是-2
最难掌握的是round 方法,他表示“四舍五入”,算法为 math.floor(x+0.5), 即将原来的数字加上0.5后再向下取整,所以,math.round(-1.5)的结果是-1
六、String 属于基础的数据类型吗?
整数类型:
byte : 字节占用 1字节 8位,用来表达最小的数据单位,储存数据长度为 正负 127;
short : 字节占用 2字节 16位,储存数值长度为 -32768-32767
int : 字节占用 4字节 32位,最为常用的整数类型,储存长度为 -2^31-1~2^31 (21 亿)
**long ** :字节占用 8字节 64位,当到达int数值极限时使用,储存长度为
浮点数类型:
float : 单精度浮点型 32位 取值范围 3.4e-38~3.4e-38
double : 双精度浮点型 64位 ,java中默认的浮点类型 取值范围 1.7e-308~1.7e-308
字符类型:
char : 16位 ,java字符使用Unicode编码;
布尔类型:
boolean : true 真 和 false 假
引用数据类型:
类 class
接口 interface
数组
String不是基本的数据类型,是final修饰的java类,是引用类型
七、java 中操作字符串都有哪些类?它们之间有什么区别?
String、StringBuffer、StringBuilder
相同(StringBuffer 、StringBuilder ):
都是字符串的缓冲区、可变的字符序列;具有相同的构造和方法。
区别(String 、StringBuffer 、StringBuilder ):
内存
String 是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,
StringBuffer 、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String 。
出现版本:
StringBuffer 是 Jdk 1.1
StringBuilder 是 Jdk 1.5
线程安全:
StringBuffer 线程安全,同步锁(synchronized ),多线程仍可以保证数据安全
StringBuilder 线程不安全,多线程无法保证数据安全
效率:
StringBuilder > StringBuffer > String
总结:
不频繁增改字符,就用String , 否则用StringBuffer 或StringBuilder
八、String str="i"与 String str=new String(“i”)一样吗?
不一样
因为内存的分配方式不一样。String str="i"的方式,Java 虚拟机会将其分配到常量池中;而 String str=new String(“i”)方式,则会被分到堆内存中。
解释 :
- Java 虚拟机会将其分配到常量池中:常量池不会重复创建对象。在String str1="i" 中,把i值存在常量池,地址赋给str1。假设再写一个String str2="i",则会把i的地址赋给str2,但是i对象不会重新创建,他们引用的是同一个地址值,共享同一个i内存。
- 分到堆内存中:堆内存会创建新的对象。假设再写一个String str3=new String(“i”),则会创建一个新的i对象,然后将新对象的地址值赋给str3。虽然str3和str1的值相同但是地址值不同。
九、如何将字符串反转?
方法一:使用StringBuilder的reverse方法(最快)
String str1 = new String("123456789");
/**
* 使用StringBuilder的reverse方法
*/
String str2 = new StringBuilder(str1).reverse().toString();
System.out.println("原字符串:" + str1);
System.out.println("字符串反转后:" + str2);
方法二:转换成字符数组,再使用StringBuilder拼接
/**
* 转换成字符数组,后通过StringBuilder拼接
*/
char[] mychar=str1.toCharArray();
StringBuilder sb=new StringBuilder("");
for(int i=mychar.length-1;i>=0;i--){
sb.append(mychar[i]);
}
String str2=sb.toString();
System.out.println("原字符串:" + str1);
System.out.println("字符串反转后:" + str2);
方法三:使用charAt(),并用StringBuilder拼接
String str1 = new String("123456789");
StringBuilder sb=new StringBuilder("");
for(int i=str1.length()-1;i>=0;i--){
sb.append(str1.charAt(i));
}
String str2=sb.toString();
System.out.println("原字符串:" + str1);
System.out.println("字符串反转后:" + str2);
十、String 类的常用方法都有那些?
- 和长度有关:
- int length() 得到一个字符串的字符个数
- 和数组有关:
- byte[] getByte() ) 将一个字符串转换成字节数组
- char[] toCharArray() 将一个字符串转换成字符数组
- String split(String) 将一个字符串按照指定内容劈开
- 和判断有关:
- boolean equals() 判断两个字符串的内容是否一样
- boolean equalsIsIgnoreCase(String) 忽略太小写的比较两个字符串的内容是否一样
- boolean contains(String) 判断一个字符串里面是否包含指定的内容
- boolean startsWith(String) 判断一个字符串是否以指定的内容开头
- boolean endsWith(String) 判断一个字符串是否以指定的内容结尾
- 和改变内容有关:
- String toUpperCase() 将一个字符串全部转换成大写
- String toLowerCase() 将一个字符串全部转换成小写
- String replace(String,String) 将某个内容全部替换成指定内容
- String replaceAll(String,String) 将某个内容全部替换成指定内容,支持正则
- String repalceFirst(String,String) 将第一次出现的某个内容替换成指定的内容
- String substring(int) 从指定下标开始一直截取到字符串的最后
- String substring(int,int) 从下标x截取到下标y-1对应的元素
- String trim() 去除一个字符串的前后空格
- 和位置有关:
- char charAt(int) 得到指定下标位置对应的字符
- int indexOf(String) 得到指定内容第一次出现的下标
- int lastIndexOf(String) 得到指定内容最后一次出现的下标
十一、抽象类必须要有抽象方法吗?
抽象类不一定有抽象方法;但是包含一个抽象方法的类一定是抽象类。(有抽象方法就是抽象类,是抽象类可以没有抽象方法)
抽象方法:
java中的抽象方法就是以abstract修饰的方法,这种方法只声明返回的数据类型、方法名称和所需的参数,没有方法体,也就是说抽象方法只需要声明而不需要实现。
抽象方法与抽象类:
当一个方法为抽象方法时,意味着这个方法必须被子类的方法所重写,否则其子类的该方法仍然是abstract的,而这个子类也必须是抽象的,即声明为abstract。abstract抽象类不能用new实例化对象,abstract方法只允许声明不能实现。如果一个类中含有abstract方法,那么这个类必须用abstract来修饰,当然abstract类也可以没有abstract方法。 一个抽象类里面没有一个抽象方法可用来禁止产生这种类的对象。
Java中的抽象类:
abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。
在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在 interface中一般不定义数据成员),所有的成员方法都是abstract的。
十二、普通类和抽象类有哪些区别?
- 抽象类不能被实例化
- 抽象类可以有抽象方法,抽象方法只需申明,无需实现
- 含有抽象方法的类必须申明为抽象类
- 抽象的子类必须实现抽象类中所有抽象方法,否则这个子类也是抽象类
- 抽象方法不能被声明为静态
- 抽象方法不能用private修饰
- 抽象方法不能用final修饰
十三、抽象类能使用 final 修饰吗?
不能,抽象类是被用于继承的,而用final修饰的类,无法被继承。
十四、接口和抽象类有什么区别?
接口和抽象类的概念不一样。接口是对动作的抽象,抽象类是对根源的抽象。
抽象类是什么:
抽象类不能创建实例,它只能作为父类被继承。抽象类是从多个具体类中抽象出来的父类,它具有更高层次的抽象。从多个具有相同特征的类中抽象出一个抽象类,以这个抽象类作为其子类的模板,从而避免了子类的随意性。
- 抽象方法只作声明,而不包含实现,可以看成是没有实现体的虚方法
- 抽象类不能被实例化
- 抽象类可以但不是必须有抽象属性和抽象方法,但是一旦有了抽象方法,就一定要把这个类声明为抽象类
- 具体派生类必须覆盖基类的抽象方法
- 抽象派生类可以覆盖基类的抽象方法,也可以不覆盖。如果不覆盖,则其具体派生类必须覆盖它们
接口是什么:
- 接口不能被实例化
- 接口只能包含方法声明
- 接口的成员包括方法、属性、索引器、事件
- 接口中不能包含常量、字段(域)、构造函数、析构函数、静态成员
接口和抽象类的区别:
- 抽象类可以有构造方法,接口中不能有构造方法。
- 抽象类中可以有普通成员变量,接口中没有普通成员变量
- 抽象类中可以包含静态方法,接口中不能包含静态方法
- 一个类可以实现多个接口,但只能继承一个抽象类。
- 接口可以被多重实现,抽象类只能被单一继承
- 如果抽象类实现接口,则可以把接口中方法映射到抽象类中作为抽象方法而不必实现,而在抽象类的子类中实现接口中方法
接口和抽象类的相同点:
- 都可以被继承
- 都不能被实例化
- 都可以包含方法声明
- 派生类必须实现未实现的方法
十五、java 中 IO 流分为几种?
**按照流的流向分,可以分为输入流和输出流;
按照操作单元划分,可以划分为字节流和字符流;
按照流的角色划分为节点流和处理流。**
Java Io流共涉及40多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系, Java IO流的40多个类都是从如下4个抽象类基类中派生出来的。
**InputStream/Reader: ** 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
**OutputStream/Writer: ** 所有输出流的基类,前者是字节输出流,后者是字符输出流。
按操作方式分类结构图:
****编辑
按操作对象分类结构图:
****编辑
十六、BIO、NIO、AIO 有什么区别?
BIO (Blocking I/O): 同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。
NIO (New I/O): NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。NIO中的N可以理解为Non-blocking,不单纯是New。它支持面向缓冲的,基于通道的I/O操作方法。 NIO提供了与传统BIO模型中的 Socket 和 ServerSocket 相对应的 SocketChannel 和 ServerSocketChannel 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发
**AIO (Asynchronous I/O): ** AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。AIO 是异步IO的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO操作本身是同步的。查阅网上相关资料,我发现就目前来说 AIO 的应用还不是很广泛,Netty 之前也尝试使用过 AIO,不过又放弃了。
十七、Files的常用方法都有哪些?
- isExecutable:文件是否可以执行
- isSameFile:是否同一个文件或目录
- isReadable:是否可读
- isDirectory:是否为目录
- isHidden:是否隐藏
- isWritable:是否可写
- isRegularFile:是否为普通文件
- getPosixFilePermissions:获取POSIX文件权限,windows系统调用此方法会报错
- setPosixFilePermissions:设置POSIX文件权限
- getOwner:获取文件所属人
- setOwner:设置文件所属人
- createFile:创建文件
- newInputStream:打开新的输入流
- newOutputStream:打开新的输出流
- createDirectory:创建目录,当父目录不存在会报错
- createDirectories:创建目录,当父目录不存在会自动创建
- createTempFile:创建临时文件
- newBufferedReader:打开或创建一个带缓存的字符输入流
- probeContentType:探测文件的内容类型
- list:目录中的文件、文件夹列表
- find:查找文件
- size:文件字节数
- copy:文件复制
- lines:读出文件中的所有行
- move:移动文件位置
- exists:文件是否存在
- walk:遍历所有目录和文件
- write:向一个文件写入字节
- delete:删除文件
- getFileStore:返回文件存储区
- newByteChannel:打开或创建文件,返回一个字节通道来访问文件
- readAllLines:从一个文件读取所有行字符串
- setAttribute:设置文件属性的值
- getAttribute:获取文件属性的值
- newBufferedWriter:打开或创建一个带缓存的字符输出流
- readAllBytes:从一个文件中读取所有字节
- createTempDirectory:在特殊的目录中创建临时目录
- deleteIfExists:如果文件存在删除文件
- notExists:判断文件不存在
- getLastModifiedTime:获取文件最后修改时间属性
- setLastModifiedTime:更新文件最后修改时间属性
- newDirectoryStream:打开目录,返回可迭代该目录下的目录流
- walkFileTree:遍历文件树,可用来递归删除文件等操作
注:以上内容仅提供参考和交流,请勿用于商业用途,如有侵权联系本人删除!
注:此博客只是为了记忆相关知识点,大部分为网络上的文章,在此向各个文章的作者表示感谢!
标题:Java 常见的面试题(java基础)
作者:wangjing
地址:https://www.codedblogs.cn/articles/2024/04/12/1712888986804.html