- java基础
- 1.JDK 和 JRE 有什么区别?
- 2. == 和 equals 的区别是什么?解读
- 3. 两个对象的 hashCode() 相同, 那么 equals() 也一定为 true吗?equals 和 hashcode 的关系
- 4. final 在 Java 中有什么作用?
- 引申 final finally finalize()区别
- 5. Java 中的 Math. round(-1. 5) 等于多少?
- 6. String 属于基础的数据类型吗?
- 7. Java 中操作字符串都有哪些类?它们之间有什么区别?
- 8. String str="i"与 String str=new String("i")一样吗?
- 9. 如何将字符串反转?
- 10. String 类的常用方法都有那些?
- 11. 抽象类必须要有抽象方法吗?
- 12. 普通类和抽象类有哪些区别?
- 13. 抽象类能使用 final 修饰吗?
- 14. 接口和抽象类有什么区别?
- 15. Java 中 IO 流分为几种?
- 16. BIO、NIO、AIO 有什么区别?
- 17. Files的常用方法都有哪些?
今天开始要背面试题了,做个记录 java基础 1.JDK 和 JRE 有什么区别?
JRE (Java Runtime Environment) :是Java程序的运行时环境,包含 JVM(java虚拟机) 和运行时所需要的 核心 类库 。
JDK (Java Development Kit):是Java程序开发工具包,包含 JRE 和开发人员使用的工具。
我们想要运行一个已有的Java程序,那么只需安装 JRE 即可。
我们想要开发一个全新的Java程序,那么必须安装 JDK ,其内部包含 JRE 。
JDK包含了JRE,同时还包括java源码的编译器javac、监控工具jconsole、分析工具jvisualvm等。
1). JRE是个运行环境,JDK是个开发环境。因此,开发程序时,写的Java程序就是在JDK上,而运行Java程序的时候,就 需要JRE。
2).JDK包含了JRE,但是,JRE可以独立安装的。
3). JDK、JRE、JVM的关系
解读:对于基本类型和引用类型的作用效果是不同的;基本类型:比较的是值是否相同。引用类型:比较的是引用是否相同。
equals 解读:equals本质上就是==,不过String和lnteger等重写了equals 方法,把它变战了值比较
Java中 Object 有一个方法:
public native int hashcode();
hashcode()方法的作用
hashcode()方法主要配合基于散列的集合一起使用,比如HashSet、HashMap、HashTable。
当集合需要添加新的对象时,先调用这个对象的hashcode()方法,得到对应的hashcode值,实际上hashmap中会有一个table保存已经存进去的对象的hashcode值,如果table中没有改hashcode值,则直接存入;如果有,就调用equals方法与新元素进行比较,相同不存,不同就存入。
equals 和 hashcode 的关系
如果equals为true,hashcode一定相等;
如果equals为false,hashcode不一定不相等;
如果hashcode值相等,equals不一定相等;
如果hashcode值不等,equals一定不等;
重写equals方法时,一定要重写hashcode方法
总结
hashCode() 返回该对象的哈希码值;equals() 返回两个对象是否相等。
- 被 final 修饰的类,不能够被继承
- final 修饰的变量叫常量,被 final修饰的成员变量必须要初始化,赋初值后不能再重新赋值(可以调用对象方法修改属性值)。对基本类型来说是其值不可变;对引用变量来说其引用不可变,即不能再指向其他的对象
- 被 final 修饰的方法不能重写
final 表示最终的、不可改变的。用于修饰类、方法和变量。final 修饰的类不能被继承;final 方法也同样只能使用,不能重写,但能够重载;final 修饰的成员变量必须在声明时给定初值或者在构造方法内设置初始值,只能读取,不可修改;final 修饰的局部变量必须在声明时给定初值;final 修饰的变量是非基本类型,对象的引用地址不能变,但对象的属性值可以改变
finally 异常处理的一部分,它只能用在 try/catch 语句中,表示希望 finally 语句块中的代码最后一定被执行(存在一些情况导致 finally 语句块不会被执行,如 jvm 结束)
finalize() 是在 java.lang.Object 里定义的,Object 的 finalize() 方法什么都不做,对象被回收时 finalize() 方法会被调用。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要清理工作,在垃圾收集器删除对象之前被调用的。一般情况下,此方法由JVM调用。特殊情况下,可重写 finalize() 方法,当对象被回收的时候释放一些资源,须调用 super.finalize() 。
5. Java 中的 Math. round(-1. 5) 等于多少?JDK 中的 java.lang.Math 类
ceil() :向上取整,返回小数所在两整数间的较大值,返回类型是 double,如 -1.5 返回 -1.0
floor() :向下取整,返回小数所在两整数间的较小值,返回类型是 double,如 -1.5 返回 -2.0
round() :四舍五入,朝正无穷大方向返回参数最接近的整数,可以换算为 参数 + 0.5 向下取整,返回值是 int 或 long,如 -1.5 返回 -1
String不是基本的数据类型,是final修饰的java类,是引用类型。java中的基本类型一共有8个,它们分别为:
Java 中,常用的对字符串操作的类有 String、StringBuffer、StringBuilder
相同点:
都可以储存和操作字符串
都使用 final 修饰,不能被继承
提供的 API 相似
区别:
String 是只读字符串,String 对象内容是不能被改变的
StringBuffer 和 StringBuilder 的字符串对象可以对字符串内容进行修改,在修改后的内存地址不会发生改变
StringBuilder 线程不安全;StringBuffer 线程安全
String : final 修饰,String 类的方法都是返回 new String。即对 String 对象的任何改变都不影响到原对象,对字符串的修改操作都会生成新的对象。
StringBuffer : 对字符串的操作的方法都加了synchronized,保证线程安全。
StringBuilder : 不保证线程安全,在方法体内需要进行字符串的修改操作,可以 new StringBuilder 对象,调用 StringBuilder 对象的 append()、replace()、delete() 等方法修改字符串。
String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。
8. String str="i"与 String str=new String(“i”)一样吗?不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。
9. 如何将字符串反转?- 使用 StringBuilder 或 StringBuffer 的 reverse 方法,本质都调用了它们的父类
AbstractStringBuilder 的 reverse 方法实现。(JDK1.8) - 不考虑字符串中的字符是否是 Unicode 编码,自己实现。
- 递归
public class TestReverseString {
public static void main(String[] args) {
String str = "ABCDE";
System.out.println(reverseString(str));
System.out.println(reverseStringByStringBuilderApi(str));
System.out.println(reverseStringByRecursion(str));
}
public static String reverseString(String str) {
if (str != null && str.length() > 0) {
int len = str.length();
char[] chars = new char[len];
for (int i = len - 1; i >= 0; i--) {
chars[len - 1 - i] = str.charAt(i);
}
return new String(chars);
}
return str;
}
public static String reverseStringByStringBuilderApi(String str) {
if (str != null && str.length() > 0) {
return new StringBuilder(str).reverse().toString();
}
return str;
}
public static String reverseStringByRecursion(String str) {
if (str == null || str.length() <= 1) {
return str;
}
return reverseStringByRecursion(str.substring(1)) + str.charAt(0);
}
}
10. String 类的常用方法都有那些?
String 类的常用方法:
equals:字符串是否相同 equalsIgnoreCase:忽略大小写后字符串是否相同 compareTo:根据字符串中每个字符的Unicode编码进行比较 compareToIgnoreCase:根据字符串中每个字符的Unicode编码进行忽略大小写比较 indexOf:目标字符或字符串在源字符串中位置下标 lastIndexOf:目标字符或字符串在源字符串中最后一次出现的位置下标 valueOf:其他类型转字符串 charAt:获取指定下标位置的字符 codePointAt:指定下标的字符的Unicode编码 concat:追加字符串到当前字符串 isEmpty:字符串长度是否为0 contains:是否包含目标字符串 startsWith:是否以目标字符串开头 endsWith:是否以目标字符串结束 format:格式化字符串 getBytes:获取字符串的字节数组 getChars:获取字符串的指定长度字符数组 toCharArray:获取字符串的字符数组 join:以某字符串,连接某字符串数组 length:字符串字符数 matches:字符串是否匹配正则表达式 replace:字符串替换 replaceAll:带正则字符串替换 replaceFirst:替换第一个出现的目标字符串 split:以某正则表达式分割字符串 substring:截取字符串 toLowerCase:字符串转小写 toUpperCase:字符串转大写 trim:去字符串首尾空格11. 抽象类必须要有抽象方法吗?
不一定
public abstract class TestAbstractClass {
public static void notAbstractMethod() {
System.out.println("I am not a abstract method.");
}
}
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。
抽象类不能被实例化 抽象类可以有抽象方法,抽象方法只需申明,无需实现 含有抽象方法的类必须申明为抽象类 抽象类的子类必须实现抽象类中所有抽象方法,否则这个子类也是抽象类 抽象方法不能被声明为静态 抽象方法不能用 private 修饰 抽象方法不能用 final 修饰13. 抽象类能使用 final 修饰吗?
不能,抽象类是被用于继承的,final修饰代表不可修改、不可继承的。
14. 接口和抽象类有什么区别?实现:抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口。
构造函数:抽象类可以有构造函数;接口不能有。
main 方法:抽象类可以有 main 方法,并且我们能运行它;接口不能有 main 方法。
实现数量:类可以实现很多个接口;但是只能继承一个抽象类。
访问修饰符:接口中的方法默认使用 public 修饰;抽象类中的方法可以是任意访问修饰符。
抽象类可以有构造方法;接口中不能有构造方法。
抽象类中可以有普通成员变量;接口中没有普通成员变量。
抽象类中可以包含非抽象普通方法;JDK1.8 以前接口中的所有方法默认都是抽象的,JDK1.8 开始方法可以有 default 实现和 static 方法。
抽象类中的抽象方法的访问权限可以是 public、protected 和 default;接口中的抽象方法只能是 public 类型的,并且默认即为 public abstract 类型。
抽象类中可以包含静态方法;JDK1.8 前接口中不能包含静态方法,JDK1.8 及以后可以包含已实现的静态方法。
抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量可以是任意访问权限;接口中变量默认且只能是 public static final 类型。
一个类可以实现多个接口,用逗号隔开,但只能继承一个抽象类。
接口不可以实现接口,但可以继承接口,并且可以继承多个接口,用逗号隔开。
抽象类:
在项目中,一般类确实够用,但是现实中有些父类的方法根本不需要写,因为每个子类中的这个方法肯定有所不同。 写成抽象类,这样别人看到你的代码,或你看到别人的代码,你就会注意抽象方法,而知道这个方法是在子类中实现的,所以,有个提示作用。 抽象类是用来捕捉子类的通用特性的 。它不能被实例化,只能被用作子类的超类。抽象类是被用来创建继承层级里子类的模板。
接口:
接口是抽象方法的集合。如果一个类实现了某个接口,那么它就继承了这个接口的抽象方法。这就像契约模式,如果实现了这个接口,那么就必须确保使用这些方法。接口只是一种形式,接口自身不能做任何事情。
什么时候使用抽象类和接口:
如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类吧。 如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。 如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。 假如有一个接口,五个实现类,现在的需求可能要往接口加一个方法,这样就要改动五个实现类,但需求只需要改动其中两个实现类,可以再定义一个抽象类去实现这个接口,在抽象类中新增这个方法,然后其他两个实现类实现这个抽象类就好了,或者使用 Java 8 中的新特性,在接口中新增默认方法或者静态方法。15. Java 中 IO 流分为几种?
(1)按功能分类:
输入流
输出流
(2)按处理数据不同分类:
字节流:二进制,可以处理一切文件,包括:纯文本、doc、音频、视频等。
字符流:文本文件,只能处理纯文本。
(3)按功能不同分类:
节点流:包裹源头。
处理流:增强功能,提高性能。
BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
NIO:Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。
BIO是一个连接一个线程。
NIO是一个请求一个线程。
AIO是一个有效请求一个线程。
BIO:同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
NIO:同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
AIO:异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。
适用场景分析
BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
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:遍历文件树,可用来递归删除文件等操作



