目录
- 1、JDK和JRE有什么区别?
- 2、== 和 equals 的区别是什么?
- 3、两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?
- 4、final 在 java 中有什么作用?
- 5、java 中的 Math.round(1.5) 等于多少? Math.round(-1.5) 等于多少?
- 6、说出以下代码的输出结果。
- 7、Java中,基本的数据类型有哪些?
- 8、String 属于基础的数据类型吗?
- 9、switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上?
- 10、java 中操作字符串都有哪些类?它们之间有什么区别?
- 11、String str="i"与 String str=new String("i")一样吗?
- 13、如何将字符串反转?
- 14、String 类的常用方法都有那些?
- 15、HashMap中使用String做key有什么好处?
- 16、抽象类必须要有抽象方法吗?
- 17、普通类和抽象类有哪些区别?
- 18、抽象类能使用 final 修饰吗?
- 19、接口和抽象类有什么区别?
- 20、内部类有哪几种?详细说明一下。
- 21、内部类有哪些使用场景?你在哪些地方使用到了内部类?
- 22、Files的常用方法都有哪些?
- 23、Date类常用方法都有哪些?
- 24、java 中 IO 流分为几种?
- 25、BIO、NIO、AIO 有什么区别?
1、JDK和JRE有什么区别?
JDK就是Java Development Kit 。JDK是面向开发人员使用的SDK,它提供了Java的开发环境和运行环境。SDK是Software Development Kit 一般指软件开发包,可以包括函数库、编译程序等。
JRE是Java Runtime Enviroment是指Java的运行环境,是面向Java程序的使用者,而不是开发者。
2、== 和 equals 的区别是什么?
(1)== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。
(基本数据类型 == 比较的是值,引用数据类型 == 比较的是内存地址)
(2)equals() : 它的作用也是判断两个对象是否相等。
但它一般有两种使用情况:
情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。
3、两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?
如果两个对象相等,则hashcode一定也是相同的
两个对象相等,对两个对象分别调用equals方法都返回true
两个对象有相同的hashcode值,它们也不一定是相等的
因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
4、final 在 java 中有什么作用?
用于修饰类、属性和方法;
被final修饰的类不可以被继承
被final修饰的方法不可以被重写
被final修饰的变量不可以被改变,被final修饰不可变的是变量的引用,而不是引用指向的内容,引用指向的内容是可以改变的
5、java 中的 Math.round(1.5) 等于多少? Math.round(-1.5) 等于多少?
Math.round(1.5)等于2,Math.round(-1.5)等于-1,四舍五入是在原来的基础上加上0.5向下取整。
6、说出以下代码的输出结果。
public class A {
static{
System.out.println("static in class A");
}
public A(){
System.out.println("class A");
}
}
public class SubA extends A {
static {
System.out.println("static in class SubA");
}
public SubA() {
super();
System.out.println("class SubA");
}
public SubA(String sa) {
System.out.println("class SubA " + sa);
}
}
public class StaticTest {
public static void main(String[] args) {
SubA subA1 = new SubA("111111");
SubA subA2 = new SubA("222222");
SubA subA3 = new SubA("333333");
}
}
输出结果为:
static in class A
static in class SubA
class A
class SubA 111111
class A
class SubA 222222
class A
class SubA 333333
解释:
子类构造方法调用规则:
(1)如果子类的构造方法中没有通过 super 显式调用父类的有参构造方法,
也没有通过 this 显式调用自身的其他构造方法,则系统会默认先调用父类的无参构造方法。
这种情况下,写不写 super(); 语句,效果是一样的
(2)如果子类的构造方法中通过 super 显式调用父类的有参构造方法,
将执行父类相应的构造方法,不执行父类无参构造方法
(3)如果子类的构造方法中通过 this 显式调用自身的其他构造方法,将执行类中相应的构造方法
(4)如果存在多级继承关系,在创建一个子类对象时,以上规则会多次向更高一级父类应用,
一直到执行顶级父类 Object 类的无参构造方法为止
结论:
类的实例化方法调用顺序:
类加载器实例化时进行的操作步骤:加载 -> 连接 -> 初始化
(1)父类静态代变量
(2)父类静态代码块
(3)子类静态变量
(4)子类静态代码块
(5)父类非静态变量(父类实例成员变量)
(6)父类构造函数
(7)子类非静态变量(子类实例成员变量)
(8)子类构造函数
7、Java中,基本的数据类型有哪些?
基本数据类型有byte、short、int、long、float、double、char、boolean八种基本数据类型。
byte:1个字节,8位
short:2个字节,16位
int:4个字节,32位
long:8个字节,64位
float:4个字节,32位
double:8个字节,64位
boolean:逻辑上理解是占用 1位,但是实际中会考虑计算机高效存储因素
char:2个字节,16位
8、String 属于基础的数据类型吗?
不属于,Java中基本数据类型只有byte、short、int、long、float、double、char、boolean八种数据类型。
String在Java中属于对象,底层实现是char数组,使用final修饰。
9、switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上?
在Java5以前,switch(expr)中的expr只能是byte、char、short、int四种数据类型。从Java5以后引入了枚举,expr可以是enum类型,Java7开始,expr就可以支持String字符串了,但是目前还不能使用long类型的。
10、java 中操作字符串都有哪些类?它们之间有什么区别?
Java中操作字符串的类有String、StringBuffer、StringBuilder三个类。
三者的相同点:
(1)都可以存储和操作字符串;
(2)底层都使用了final修饰,不能被继承。
(3)提供了API相似。
三者的区别:
(1)String是不可变字符序列,String内容是不能被改变的;
(2)StringBuffer和StringBuilder是可变字符序列,他们都可以对字符串内容进行修改,
并且修改之后的内存地址不会发生改变;
(3)StringBuilder是JDK1.5的,效率高,但是它的线程不安全,
StringBuffer是JDK1.0的,效率低,但是它是线程安全的(方法加了Synchronized)。
对于三者使用的总结
如果要操作少量的数据用 = String
单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
多线程操作字符串缓冲区 下操作大量数据 = StringBuffer
11、String str="i"与 String str=new String(“i”)一样吗?
不一样,因为内存的分配方式不一样,String str = "i"的方式,Java虚拟机会将其分配到常量池中;而String str = new String(“i”) 则会被分配到堆内存中。
提问:String s = new String(“abc”)创建了几个对象呢?
答案是两个对象,一个是静态区的"abc",另外一个是用new创建在堆上的对象。
String str1 = "hello"; //str1指向静态区
String str2 = new String("hello"); //str2指向堆上的对象
String str3 = "hello";
String str4 = new String("hello");
System.out.println(str1.equals(str2)); //true
System.out.println(str2.equals(str4)); //true
System.out.println(str1 == str3); //true
System.out.println(str1 == str2); //false
System.out.println(str2 == str4); //false
System.out.println(str2 == "hello"); //false
str2 = str1;
System.out.println(str2 == "hello"); //true
13、如何将字符串反转?
使用StringBuffer或者StringBuilder中的reverse()方法。
// StringBuffer reverse
StringBuffer stringBuffer = new StringBuffer();
stringBuffer. append("abcdefg");
System. out. println(stringBuffer. reverse()); // gfedcba
// StringBuilder reverse
StringBuilder stringBuilder = new StringBuilder();
stringBuilder. append("abcdefg");
System. out. println(stringBuilder. reverse()); // gfedcba
14、String 类的常用方法都有那些?
(1)String 类的常用方法都有那些?
(2)indexOf():返回指定字符的索引。
(3)charAt():返回指定索引处的字符。
(4)replace():字符串替换。
(5)trim():去除字符串两端空白。
(6)split():分割字符串,返回一个分割后的字符串数组。
(7)getBytes():返回字符串的 byte 类型数组。
(8)length():返回字符串长度。
(9)toLowerCase():将字符串转成小写字母。
(10)toUpperCase():将字符串转成大写字符。
(11)substring():截取字符串。
(12)equals():字符串比较。
15、HashMap中使用String做key有什么好处?
HashMap内部实现是通过key的hashcode来确定value的存储位置,因为字符串是不可变的,并且使用字符串时会在字符串常量池中进行缓存,所以当创建字符串的时候,hashcode会被缓存下来,不需要再次计算,所以相比于其他对象来说快一些。
16、抽象类必须要有抽象方法吗?
抽象类不一定要有抽象方法,但是抽象方法的类必须是抽象类。
17、普通类和抽象类有哪些区别?
(1)抽象类不能被实例化;
(2)抽象类可以有抽象方法,但是普通类没有;
(3)含有抽象方法的类必须是抽象类;
(4)抽象方法不能被声明为静态;
(5)抽象方法不能被private;
(6)抽象方法不能被final修饰。
18、抽象类能使用 final 修饰吗?
不能,因为被final修饰的类不能被继承,而定义抽象类就是为了让其他类去继承的,如果使用final修饰了就矛盾了,因此不能被final修饰。
19、接口和抽象类有什么区别?
(1)实现:抽象类的子类使用extends来继承,而接口就必须使用implements来实现接口;
(2)构造函数:抽象类可以有构造函数,但是接口没有;
(3)实现数量:类可以实现很多个接口,但是只能继承一个抽象类;
(4)访问修饰符:接口的方法默认使用的是public修饰,而抽象类中的方法可以是任意访问修饰符;
20、内部类有哪几种?详细说明一下。
内部类的定义:可以将一个类的定义放在另外一个类的定义内部;
内部类的种类:成员内部类、局部内部类、匿名内部类、静态内部类。
(1)静态内部类:定义在类内部的静态类。
public class Outer {
private static int radius = 1;
static class StaticInner {
public void visit() {
System.out.println("visit outer static variable:" + radius);
}
}
}
静态内部类可以访问外部类所有的静态变量,而不可访问外部类的非静态变量;静态内部类的创建方式,new 外部类.静态内部类(),如下:
Outer.StaticInner inner = new Outer.StaticInner();
inner.visit();
(2)成员内部类:定义在类内部,成员位置上的非静态类。
public class Outer {
private static int radius = 1;
private int count =2;
class Inner {
public void visit() {
System.out.println("visit outer static variable:" + radius);
System.out.println("visit outer variable:" + count);
}
}
}
成员内部类可以访问外部类所有的变量和方法,包括静态和非静态,私有和公有。成员内部类依赖于外部类的实例,它的创建方式外部类实例.new 内部类(),如下:
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.visit();
(3)局部内部类:定义在方法的内部,就是局部内部类。
public class Outer {
private int out_a = 1;
private static int STATIC_b = 2;
public void testFunctionClass(){
int inner_c =3;
class Inner {
private void fun(){
System.out.println(out_a);
System.out.println(STATIC_b);
System.out.println(inner_c);
}
}
Inner inner = new Inner();
inner.fun();
}
public static void testStaticFunctionClass(){
int d =3;
class Inner {
private void fun(){
// System.out.println(out_a); 编译错误,定义在静态方法中的局部类不可以访问外部类的实例变量
System.out.println(STATIC_b);
System.out.println(d);
}
}
Inner inner = new Inner();
inner.fun();
}
}
定义在实例方法中的局部类可以访问外部类的所有变量和方法,定义在静态方法中的局部类只能访问外部类的静态变量和方法。局部内部类的创建方式,在对应方法内,new 内部类(),如下:
public static void testStaticFunctionClass(){
class Inner {
}
Inner inner = new Inner();
}
(4)匿名内部类:没有名字的内部类,日常开发中使用的比较多。
public class Outer {
private void test(final int i) {
new Service() {
public void method() {
for (int j = 0; j < i; j++) {
System.out.println("匿名内部类" );
}
}
}.method();
}
}
//匿名内部类必须继承或实现一个已有的接口
interface Service{
void method();
}
除了没有名字,匿名内部类还有以下特点:
A、匿名内部类必须继承一个抽象类或者实现一个接口。
B、匿名内部类不能定义任何静态成员和静态方法。
C、当所在的方法的形参需要被匿名内部类使用时,必须声明为 final。
D、匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
匿名内部类创建方式:
new 类/接口{
//匿名内部类实现部分
}
21、内部类有哪些使用场景?你在哪些地方使用到了内部类?
(1)在设计模式中使用静态内部类实现单例模式;
public class SingletonDemo03 {
private static class SingletonClassInstance{
private static final SingletonDemo03 instance = new SingletonDemo03();
}
public static SingletonDemo03 getInstance(){
return SingletonClassInstance.instance;
}
private SingletonDemo03(){}
}
(2)见以下代码,这种方式用到了匿名内部类。
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
});
thread.start();
其他的忘记了,,,等记得来的时候再补上0.0
22、Files的常用方法都有哪些?
(1)Files. exists():检测文件路径是否存在。
(2)Files. createFile():创建文件。
(3)Files. createDirectory():创建文件夹。
(4)Files. delete():删除一个文件或目录。
(5)Files. copy():复制文件。
(6)Files. move():移动文件。
(7)Files. size():查看文件个数。
(8)Files. read():读取文件。
(9)Files. write():写入文件。
23、Date类常用方法都有哪些?
-----日期类型如何格式化?
***************************************************************************************
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String s = sdf.format(new Date());//日期转字符串
***************************************************************************************
-----字符串如何转日期?
***************************************************************************************
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String s = "2019-10-31 22:53:10";
Date date = sdf.parse(s);
***************************************************************************************
-----如何取得当前年、月、日、时、分、秒、毫秒?
年:Calendar.getInstance().get(Calendar.YEAR);
或者Year.now();//JDK 1.8 java.time 包
还有LocalDate.now().getYear();//JDK 1.8 java.time 包
月:Calendar.getInstance().get(Calendar.MONTH)+1;
MonthDay.now().getMonthValue();//JDK 1.8 java.time 包
LocalDate.now().getMonthValue();//JDK 1.8 java.time 包
日:Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
MonthDay.now().getDayOfMonth();//JDK 1.8 java.time 包
LocalDate.now().getDayOfMonth();//JDK 1.8 java.time 包
时:Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
LocalTime.now().getHour();//JDK 1.8 java.time 包
分:Calendar.getInstance().get(Calendar.MINUTE);
LocalTime.now().getMinute();//JDK 1.8 java.time 包
秒:Calendar.getInstance().get(Calendar.SECOND);
LocalTime.now().getSecond();//JDK 1.8 java.time 包
毫秒:Calendar.getInstance().get(Calendar.MILLISECOND);
***************************************************************************************
--如何取得从1970年1月1日0时0分0秒到现在的毫秒数?
System.currentTimeMillis();
Calendar.getInstance().getTimeInMillis();
--如何格式化日期?
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
//JDK 1.8 java.time 包
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
24、java 中 IO 流分为几种?
(1)按照流向可以分为输入流和输出流;
(2)按照操作单元划分可以分为字节流和字符流;
(3)按照流的角色划分可分为节点流和处理流;
25、BIO、NIO、AIO 有什么区别?
简答:
BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
NIO:Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。
详细回答:
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操作本身是同步的。
以上是我之前面试的时候的一些问题+基础总结,答案参考了很多大佬的技术博客,说来惭愧,当时基础不太好,问到的好多都不太会,0.0